Home | History | Annotate | Line # | Download | only in ata
      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