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