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