1 /* $NetBSD: ld_ataraid.c,v 1.37 2010/07/06 18:09:04 bsh Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Support for ATA RAID logical disks. 40 * 41 * Note that all the RAID happens in software here; the ATA RAID 42 * controllers we're dealing with (Promise, etc.) only support 43 * configuration data on the component disks, with the BIOS supporting 44 * booting from the RAID volumes. 45 * 46 * bio(4) support was written by Juan Romero Pardines <xtraeme@gmail.com>. 47 */ 48 49 #include <sys/cdefs.h> 50 __KERNEL_RCSID(0, "$NetBSD: ld_ataraid.c,v 1.37 2010/07/06 18:09:04 bsh Exp $"); 51 52 #include "bio.h" 53 #include "rnd.h" 54 55 #include <sys/param.h> 56 #include <sys/systm.h> 57 #include <sys/conf.h> 58 #include <sys/kernel.h> 59 #include <sys/device.h> 60 #include <sys/buf.h> 61 #include <sys/bufq.h> 62 #include <sys/dkio.h> 63 #include <sys/disk.h> 64 #include <sys/disklabel.h> 65 #include <sys/fcntl.h> 66 #include <sys/malloc.h> 67 #include <sys/vnode.h> 68 #include <sys/kauth.h> 69 #if NRND > 0 70 #include <sys/rnd.h> 71 #endif 72 #if NBIO > 0 73 #include <dev/ata/atavar.h> 74 #include <dev/ata/atareg.h> 75 #include <dev/ata/wdvar.h> 76 #include <dev/biovar.h> 77 #include <dev/scsipi/scsipiconf.h> /* for scsipi_strvis() */ 78 #endif 79 80 #include <miscfs/specfs/specdev.h> 81 82 #include <dev/ldvar.h> 83 84 #include <dev/ata/ata_raidvar.h> 85 86 struct ld_ataraid_softc { 87 struct ld_softc sc_ld; 88 89 struct ataraid_array_info *sc_aai; 90 struct vnode *sc_vnodes[ATA_RAID_MAX_DISKS]; 91 92 void (*sc_iodone)(struct buf *); 93 94 pool_cache_t sc_cbufpool; 95 96 SIMPLEQ_HEAD(, cbuf) sc_cbufq; 97 98 void *sc_sih_cookie; 99 }; 100 101 static int ld_ataraid_match(device_t, cfdata_t, void *); 102 static void ld_ataraid_attach(device_t, device_t, void *); 103 104 static int ld_ataraid_dump(struct ld_softc *, void *, int, int); 105 106 static int cbufpool_ctor(void *, void *, int); 107 static void cbufpool_dtor(void *, void *); 108 109 static void ld_ataraid_start_vstrategy(void *); 110 static int ld_ataraid_start_span(struct ld_softc *, struct buf *); 111 112 static int ld_ataraid_start_raid0(struct ld_softc *, struct buf *); 113 static void ld_ataraid_iodone_raid0(struct buf *); 114 115 #if NBIO > 0 116 static int ld_ataraid_bioctl(device_t, u_long, void *); 117 static int ld_ataraid_bioinq(struct ld_ataraid_softc *, struct bioc_inq *); 118 static int ld_ataraid_biovol(struct ld_ataraid_softc *, struct bioc_vol *); 119 static int ld_ataraid_biodisk(struct ld_ataraid_softc *, 120 struct bioc_disk *); 121 #endif 122 123 CFATTACH_DECL_NEW(ld_ataraid, sizeof(struct ld_ataraid_softc), 124 ld_ataraid_match, ld_ataraid_attach, NULL, NULL); 125 126 struct cbuf { 127 struct buf cb_buf; /* new I/O buf */ 128 struct buf *cb_obp; /* ptr. to original I/O buf */ 129 struct ld_ataraid_softc *cb_sc; /* pointer to ld softc */ 130 u_int cb_comp; /* target component */ 131 SIMPLEQ_ENTRY(cbuf) cb_q; /* fifo of component buffers */ 132 struct cbuf *cb_other; /* other cbuf in case of mirror */ 133 int cb_flags; 134 #define CBUF_IODONE 0x00000001 /* I/O is already successfully done */ 135 }; 136 137 #define CBUF_GET() pool_cache_get(sc->sc_cbufpool, PR_NOWAIT); 138 #define CBUF_PUT(cbp) pool_cache_put(sc->sc_cbufpool, (cbp)) 139 140 static int 141 ld_ataraid_match(device_t parent, cfdata_t match, void *aux) 142 { 143 144 return (1); 145 } 146 147 static void 148 ld_ataraid_attach(device_t parent, device_t self, void *aux) 149 { 150 struct ld_ataraid_softc *sc = device_private(self); 151 struct ld_softc *ld = &sc->sc_ld; 152 struct ataraid_array_info *aai = aux; 153 struct ataraid_disk_info *adi = NULL; 154 const char *level; 155 struct vnode *vp; 156 char unklev[32]; 157 u_int i; 158 159 ld->sc_dv = self; 160 161 sc->sc_cbufpool = pool_cache_init(sizeof(struct cbuf), 0, 162 0, 0, "ldcbuf", NULL, IPL_BIO, cbufpool_ctor, cbufpool_dtor, sc); 163 sc->sc_sih_cookie = softint_establish(SOFTINT_BIO, 164 ld_ataraid_start_vstrategy, sc); 165 166 sc->sc_aai = aai; /* this data persists */ 167 168 ld->sc_maxxfer = MAXPHYS * aai->aai_width; /* XXX */ 169 ld->sc_secperunit = aai->aai_capacity; 170 ld->sc_secsize = 512; /* XXX */ 171 ld->sc_maxqueuecnt = 128; /* XXX */ 172 ld->sc_dump = ld_ataraid_dump; 173 174 switch (aai->aai_level) { 175 case AAI_L_SPAN: 176 level = "SPAN"; 177 ld->sc_start = ld_ataraid_start_span; 178 sc->sc_iodone = ld_ataraid_iodone_raid0; 179 break; 180 181 case AAI_L_RAID0: 182 level = "RAID-0"; 183 ld->sc_start = ld_ataraid_start_raid0; 184 sc->sc_iodone = ld_ataraid_iodone_raid0; 185 break; 186 187 case AAI_L_RAID1: 188 level = "RAID-1"; 189 ld->sc_start = ld_ataraid_start_raid0; 190 sc->sc_iodone = ld_ataraid_iodone_raid0; 191 break; 192 193 case AAI_L_RAID0 | AAI_L_RAID1: 194 level = "RAID-10"; 195 ld->sc_start = ld_ataraid_start_raid0; 196 sc->sc_iodone = ld_ataraid_iodone_raid0; 197 break; 198 199 default: 200 snprintf(unklev, sizeof(unklev), "<unknown level 0x%x>", 201 aai->aai_level); 202 level = unklev; 203 } 204 205 aprint_naive(": ATA %s array\n", level); 206 aprint_normal(": %s ATA %s array\n", 207 ata_raid_type_name(aai->aai_type), level); 208 209 if (ld->sc_start == NULL) { 210 aprint_error_dev(ld->sc_dv, "unsupported array type\n"); 211 return; 212 } 213 214 /* 215 * We get a geometry from the device; use it. 216 */ 217 ld->sc_nheads = aai->aai_heads; 218 ld->sc_nsectors = aai->aai_sectors; 219 ld->sc_ncylinders = aai->aai_cylinders; 220 221 /* 222 * Configure all the component disks. 223 */ 224 for (i = 0; i < aai->aai_ndisks; i++) { 225 adi = &aai->aai_disks[i]; 226 vp = ata_raid_disk_vnode_find(adi); 227 if (vp == NULL) { 228 /* 229 * XXX This is bogus. We should just mark the 230 * XXX component as FAILED, and write-back new 231 * XXX config blocks. 232 */ 233 break; 234 } 235 sc->sc_vnodes[i] = vp; 236 } 237 if (i == aai->aai_ndisks) { 238 ld->sc_flags = LDF_ENABLED; 239 goto finish; 240 } 241 242 for (i = 0; i < aai->aai_ndisks; i++) { 243 vp = sc->sc_vnodes[i]; 244 sc->sc_vnodes[i] = NULL; 245 if (vp != NULL) 246 (void) vn_close(vp, FREAD|FWRITE, NOCRED); 247 } 248 249 finish: 250 #if NBIO > 0 251 if (bio_register(self, ld_ataraid_bioctl) != 0) 252 panic("%s: bioctl registration failed\n", 253 device_xname(ld->sc_dv)); 254 #endif 255 SIMPLEQ_INIT(&sc->sc_cbufq); 256 ldattach(ld); 257 } 258 259 static int 260 cbufpool_ctor(void *arg, void *obj, int flags) 261 { 262 struct ld_ataraid_softc *sc = arg; 263 struct ld_softc *ld = &sc->sc_ld; 264 struct cbuf *cbp = obj; 265 266 /* We release/reacquire the spinlock before calling buf_init() */ 267 mutex_exit(&ld->sc_mutex); 268 buf_init(&cbp->cb_buf); 269 mutex_enter(&ld->sc_mutex); 270 271 return 0; 272 } 273 274 static void 275 cbufpool_dtor(void *arg, void *obj) 276 { 277 struct cbuf *cbp = obj; 278 279 buf_destroy(&cbp->cb_buf); 280 } 281 282 static struct cbuf * 283 ld_ataraid_make_cbuf(struct ld_ataraid_softc *sc, struct buf *bp, 284 u_int comp, daddr_t bn, void *addr, long bcount) 285 { 286 struct cbuf *cbp; 287 288 cbp = CBUF_GET(); 289 if (cbp == NULL) 290 return NULL; 291 cbp->cb_buf.b_flags = bp->b_flags; 292 cbp->cb_buf.b_oflags = bp->b_oflags; 293 cbp->cb_buf.b_cflags = bp->b_cflags; 294 cbp->cb_buf.b_iodone = sc->sc_iodone; 295 cbp->cb_buf.b_proc = bp->b_proc; 296 cbp->cb_buf.b_vp = sc->sc_vnodes[comp]; 297 cbp->cb_buf.b_objlock = &sc->sc_vnodes[comp]->v_interlock; 298 cbp->cb_buf.b_blkno = bn + sc->sc_aai->aai_offset; 299 cbp->cb_buf.b_data = addr; 300 cbp->cb_buf.b_bcount = bcount; 301 302 /* Context for iodone */ 303 cbp->cb_obp = bp; 304 cbp->cb_sc = sc; 305 cbp->cb_comp = comp; 306 cbp->cb_other = NULL; 307 cbp->cb_flags = 0; 308 309 return cbp; 310 } 311 312 static void 313 ld_ataraid_start_vstrategy(void *arg) 314 { 315 struct ld_ataraid_softc *sc = arg; 316 struct cbuf *cbp; 317 318 while ((cbp = SIMPLEQ_FIRST(&sc->sc_cbufq)) != NULL) { 319 SIMPLEQ_REMOVE_HEAD(&sc->sc_cbufq, cb_q); 320 if ((cbp->cb_buf.b_flags & B_READ) == 0) { 321 mutex_enter(&cbp->cb_buf.b_vp->v_interlock); 322 cbp->cb_buf.b_vp->v_numoutput++; 323 mutex_exit(&cbp->cb_buf.b_vp->v_interlock); 324 } 325 VOP_STRATEGY(cbp->cb_buf.b_vp, &cbp->cb_buf); 326 } 327 } 328 329 static int 330 ld_ataraid_start_span(struct ld_softc *ld, struct buf *bp) 331 { 332 struct ld_ataraid_softc *sc = (void *) ld; 333 struct ataraid_array_info *aai = sc->sc_aai; 334 struct ataraid_disk_info *adi; 335 struct cbuf *cbp; 336 char *addr; 337 daddr_t bn; 338 long bcount, rcount; 339 u_int comp; 340 341 /* Allocate component buffers. */ 342 addr = bp->b_data; 343 344 /* Find the first component. */ 345 comp = 0; 346 adi = &aai->aai_disks[comp]; 347 bn = bp->b_rawblkno; 348 while (bn >= adi->adi_compsize) { 349 bn -= adi->adi_compsize; 350 adi = &aai->aai_disks[++comp]; 351 } 352 353 bp->b_resid = bp->b_bcount; 354 355 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 356 rcount = bp->b_bcount; 357 if ((adi->adi_compsize - bn) < btodb(rcount)) 358 rcount = dbtob(adi->adi_compsize - bn); 359 360 cbp = ld_ataraid_make_cbuf(sc, bp, comp, bn, addr, rcount); 361 if (cbp == NULL) { 362 /* Free the already allocated component buffers. */ 363 while ((cbp = SIMPLEQ_FIRST(&sc->sc_cbufq)) != NULL) { 364 SIMPLEQ_REMOVE_HEAD(&sc->sc_cbufq, cb_q); 365 CBUF_PUT(cbp); 366 } 367 return EAGAIN; 368 } 369 370 /* 371 * For a span, we always know we advance to the next disk, 372 * and always start at offset 0 on that disk. 373 */ 374 adi = &aai->aai_disks[++comp]; 375 bn = 0; 376 377 SIMPLEQ_INSERT_TAIL(&sc->sc_cbufq, cbp, cb_q); 378 addr += rcount; 379 } 380 381 /* Now fire off the requests. */ 382 softint_schedule(sc->sc_sih_cookie); 383 384 return 0; 385 } 386 387 static int 388 ld_ataraid_start_raid0(struct ld_softc *ld, struct buf *bp) 389 { 390 struct ld_ataraid_softc *sc = (void *)ld; 391 struct ataraid_array_info *aai = sc->sc_aai; 392 struct ataraid_disk_info *adi; 393 struct cbuf *cbp, *other_cbp; 394 char *addr; 395 daddr_t bn, cbn, tbn, off; 396 long bcount, rcount; 397 u_int comp; 398 const int read = bp->b_flags & B_READ; 399 const int mirror = aai->aai_level & AAI_L_RAID1; 400 int error = 0; 401 402 /* Allocate component buffers. */ 403 addr = bp->b_data; 404 bn = bp->b_rawblkno; 405 406 bp->b_resid = bp->b_bcount; 407 408 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 409 tbn = bn / aai->aai_interleave; 410 off = bn % aai->aai_interleave; 411 412 if (__predict_false(tbn == aai->aai_capacity / 413 aai->aai_interleave)) { 414 /* Last stripe. */ 415 daddr_t sz = (aai->aai_capacity - 416 (tbn * aai->aai_interleave)) / 417 aai->aai_width; 418 comp = off / sz; 419 cbn = ((tbn / aai->aai_width) * aai->aai_interleave) + 420 (off % sz); 421 rcount = min(bcount, dbtob(sz)); 422 } else { 423 comp = tbn % aai->aai_width; 424 cbn = ((tbn / aai->aai_width) * aai->aai_interleave) + 425 off; 426 rcount = min(bcount, dbtob(aai->aai_interleave - off)); 427 } 428 429 /* 430 * See if a component is valid. 431 */ 432 try_mirror: 433 adi = &aai->aai_disks[comp]; 434 if ((adi->adi_status & ADI_S_ONLINE) == 0) { 435 if (mirror && comp < aai->aai_width) { 436 comp += aai->aai_width; 437 goto try_mirror; 438 } 439 440 /* 441 * No component available. 442 */ 443 error = EIO; 444 goto free_and_exit; 445 } 446 447 cbp = ld_ataraid_make_cbuf(sc, bp, comp, cbn, addr, rcount); 448 if (cbp == NULL) { 449 resource_shortage: 450 error = EAGAIN; 451 free_and_exit: 452 /* Free the already allocated component buffers. */ 453 while ((cbp = SIMPLEQ_FIRST(&sc->sc_cbufq)) != NULL) { 454 SIMPLEQ_REMOVE_HEAD(&sc->sc_cbufq, cb_q); 455 CBUF_PUT(cbp); 456 } 457 return error; 458 } 459 SIMPLEQ_INSERT_TAIL(&sc->sc_cbufq, cbp, cb_q); 460 if (mirror && !read && comp < aai->aai_width) { 461 comp += aai->aai_width; 462 adi = &aai->aai_disks[comp]; 463 if (adi->adi_status & ADI_S_ONLINE) { 464 other_cbp = ld_ataraid_make_cbuf(sc, bp, 465 comp, cbn, addr, rcount); 466 if (other_cbp == NULL) 467 goto resource_shortage; 468 SIMPLEQ_INSERT_TAIL(&sc->sc_cbufq, 469 other_cbp, cb_q); 470 other_cbp->cb_other = cbp; 471 cbp->cb_other = other_cbp; 472 } 473 } 474 bn += btodb(rcount); 475 addr += rcount; 476 } 477 478 /* Now fire off the requests. */ 479 softint_schedule(sc->sc_sih_cookie); 480 481 return error; 482 } 483 484 /* 485 * Called at interrupt time. Mark the component as done and if all 486 * components are done, take an "interrupt". 487 */ 488 static void 489 ld_ataraid_iodone_raid0(struct buf *vbp) 490 { 491 struct cbuf *cbp = (struct cbuf *) vbp, *other_cbp; 492 struct buf *bp = cbp->cb_obp; 493 struct ld_ataraid_softc *sc = cbp->cb_sc; 494 struct ataraid_array_info *aai = sc->sc_aai; 495 struct ataraid_disk_info *adi; 496 long count; 497 int s, iodone; 498 499 s = splbio(); 500 501 iodone = cbp->cb_flags & CBUF_IODONE; 502 other_cbp = cbp->cb_other; 503 if (other_cbp != NULL) 504 /* You are alone */ 505 other_cbp->cb_other = NULL; 506 507 if (cbp->cb_buf.b_error != 0) { 508 /* 509 * Mark this component broken. 510 */ 511 adi = &aai->aai_disks[cbp->cb_comp]; 512 adi->adi_status &= ~ADI_S_ONLINE; 513 514 printf("%s: error %d on component %d (%s)\n", 515 device_xname(sc->sc_ld.sc_dv), bp->b_error, cbp->cb_comp, 516 device_xname(adi->adi_dev)); 517 518 /* 519 * If we didn't see an error yet and we are reading 520 * RAID1 disk, try another component. 521 */ 522 if (bp->b_error == 0 && 523 (cbp->cb_buf.b_flags & B_READ) != 0 && 524 (aai->aai_level & AAI_L_RAID1) != 0 && 525 cbp->cb_comp < aai->aai_width) { 526 cbp->cb_comp += aai->aai_width; 527 adi = &aai->aai_disks[cbp->cb_comp]; 528 if (adi->adi_status & ADI_S_ONLINE) { 529 cbp->cb_buf.b_error = 0; 530 VOP_STRATEGY(cbp->cb_buf.b_vp, &cbp->cb_buf); 531 goto out; 532 } 533 } 534 535 if (iodone || other_cbp != NULL) 536 /* 537 * If I/O on other component successfully done 538 * or the I/O is still in progress, no need 539 * to tell an error to upper layer. 540 */ 541 ; 542 else { 543 bp->b_error = cbp->cb_buf.b_error ? 544 cbp->cb_buf.b_error : EIO; 545 } 546 547 /* XXX Update component config blocks. */ 548 549 } else { 550 /* 551 * If other I/O is still in progress, tell it that 552 * our I/O is successfully done. 553 */ 554 if (other_cbp != NULL) 555 other_cbp->cb_flags |= CBUF_IODONE; 556 } 557 count = cbp->cb_buf.b_bcount; 558 CBUF_PUT(cbp); 559 560 if (other_cbp != NULL) 561 goto out; 562 563 /* If all done, "interrupt". */ 564 bp->b_resid -= count; 565 if (bp->b_resid < 0) 566 panic("ld_ataraid_iodone_raid0: count"); 567 if (bp->b_resid == 0) 568 lddone(&sc->sc_ld, bp); 569 570 out: 571 splx(s); 572 } 573 574 static int 575 ld_ataraid_dump(struct ld_softc *sc, void *data, 576 int blkno, int blkcnt) 577 { 578 579 return (EIO); 580 } 581 582 #if NBIO > 0 583 static int 584 ld_ataraid_bioctl(device_t self, u_long cmd, void *addr) 585 { 586 struct ld_ataraid_softc *sc = device_private(self); 587 int error = 0; 588 589 switch (cmd) { 590 case BIOCINQ: 591 error = ld_ataraid_bioinq(sc, (struct bioc_inq *)addr); 592 break; 593 case BIOCVOL: 594 error = ld_ataraid_biovol(sc, (struct bioc_vol *)addr); 595 break; 596 case BIOCDISK: 597 error = ld_ataraid_biodisk(sc, (struct bioc_disk *)addr); 598 break; 599 default: 600 error = ENOTTY; 601 break; 602 } 603 604 return error; 605 } 606 607 static int 608 ld_ataraid_bioinq(struct ld_ataraid_softc *sc, struct bioc_inq *bi) 609 { 610 struct ataraid_array_info *aai = sc->sc_aai; 611 612 /* there's always one volume per ld device */ 613 bi->bi_novol = 1; 614 bi->bi_nodisk = aai->aai_ndisks; 615 616 return 0; 617 } 618 619 static int 620 ld_ataraid_biovol(struct ld_ataraid_softc *sc, struct bioc_vol *bv) 621 { 622 struct ataraid_array_info *aai = sc->sc_aai; 623 struct ld_softc *ld = &sc->sc_ld; 624 #define to_kibytes(ld,s) (ld->sc_secsize*(s)/1024) 625 626 /* Fill in data for _this_ volume */ 627 bv->bv_percent = -1; 628 bv->bv_seconds = 0; 629 630 switch (aai->aai_status) { 631 case AAI_S_READY: 632 bv->bv_status = BIOC_SVONLINE; 633 break; 634 case AAI_S_DEGRADED: 635 bv->bv_status = BIOC_SVDEGRADED; 636 break; 637 } 638 639 bv->bv_size = ld->sc_secsize * ld->sc_secperunit; 640 641 switch (aai->aai_level) { 642 case AAI_L_SPAN: 643 case AAI_L_RAID0: 644 bv->bv_stripe_size = to_kibytes(ld, aai->aai_interleave); 645 bv->bv_level = 0; 646 break; 647 case AAI_L_RAID1: 648 bv->bv_stripe_size = 0; 649 bv->bv_level = 1; 650 break; 651 case AAI_L_RAID5: 652 bv->bv_stripe_size = to_kibytes(ld, aai->aai_interleave); 653 bv->bv_level = 5; 654 break; 655 } 656 657 bv->bv_nodisk = aai->aai_ndisks; 658 strlcpy(bv->bv_dev, device_xname(ld->sc_dv), sizeof(bv->bv_dev)); 659 if (aai->aai_name[0] != '\0') 660 strlcpy(bv->bv_vendor, aai->aai_name, sizeof(bv->bv_vendor)); 661 662 return 0; 663 } 664 665 static int 666 ld_ataraid_biodisk(struct ld_ataraid_softc *sc, struct bioc_disk *bd) 667 { 668 struct ataraid_array_info *aai = sc->sc_aai; 669 struct ataraid_disk_info *adi; 670 struct ld_softc *ld = &sc->sc_ld; 671 struct atabus_softc *atabus; 672 struct wd_softc *wd; 673 char model[81], serial[41], rev[17]; 674 675 /* sanity check */ 676 if (bd->bd_diskid > aai->aai_ndisks) 677 return EINVAL; 678 679 adi = &aai->aai_disks[bd->bd_diskid]; 680 atabus = device_private(device_parent(adi->adi_dev)); 681 wd = device_private(adi->adi_dev); 682 683 /* fill in data for _this_ disk */ 684 switch (adi->adi_status) { 685 case ADI_S_ONLINE | ADI_S_ASSIGNED: 686 bd->bd_status = BIOC_SDONLINE; 687 break; 688 case ADI_S_SPARE: 689 bd->bd_status = BIOC_SDHOTSPARE; 690 break; 691 default: 692 bd->bd_status = BIOC_SDOFFLINE; 693 break; 694 } 695 696 bd->bd_channel = 0; 697 bd->bd_target = atabus->sc_chan->ch_channel; 698 bd->bd_lun = 0; 699 bd->bd_size = (wd->sc_capacity * ld->sc_secsize) - aai->aai_reserved; 700 701 strlcpy(bd->bd_procdev, device_xname(adi->adi_dev), 702 sizeof(bd->bd_procdev)); 703 704 scsipi_strvis(serial, sizeof(serial), wd->sc_params.atap_serial, 705 sizeof(wd->sc_params.atap_serial)); 706 scsipi_strvis(model, sizeof(model), wd->sc_params.atap_model, 707 sizeof(wd->sc_params.atap_model)); 708 scsipi_strvis(rev, sizeof(rev), wd->sc_params.atap_revision, 709 sizeof(wd->sc_params.atap_revision)); 710 711 snprintf(bd->bd_vendor, sizeof(bd->bd_vendor), "%s %s", model, rev); 712 strlcpy(bd->bd_serial, serial, sizeof(bd->bd_serial)); 713 714 return 0; 715 } 716 #endif /* NBIO > 0 */ 717