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