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