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