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
87struct 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
102static int ld_ataraid_match(device_t, cfdata_t, void *);
103static void ld_ataraid_attach(device_t, device_t, void *);
104
105static int ld_ataraid_dump(struct ld_softc *, void *, int, int);
106
107static int cbufpool_ctor(void *, void *, int);
108static void cbufpool_dtor(void *, void *);
109
110static void ld_ataraid_start_vstrategy(void *);
111static int ld_ataraid_start_span(struct ld_softc *, struct buf *);
112
113static int ld_ataraid_start_raid0(struct ld_softc *, struct buf *);
114static void ld_ataraid_iodone_raid0(struct buf *);
115
116#if NBIO > 0
117static int ld_ataraid_bioctl(device_t, u_long, void *);
118static int ld_ataraid_bioinq(struct ld_ataraid_softc *, struct bioc_inq *);
119static int ld_ataraid_biovol(struct ld_ataraid_softc *, struct bioc_vol *);
120static int ld_ataraid_biodisk(struct ld_ataraid_softc *,
121 struct bioc_disk *);
122#endif
123
124CFATTACH_DECL_NEW(ld_ataraid, sizeof(struct ld_ataraid_softc),
125 ld_ataraid_match, ld_ataraid_attach, NULL, NULL);
126
127struct 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
141static int
142ld_ataraid_match(device_t parent, cfdata_t match, void *aux)
143{
144
145 return (1);
146}
147
148static void
149ld_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
260static int
261cbufpool_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
275static void
276cbufpool_dtor(void *arg, void *obj)
277{
278 struct cbuf *cbp = obj;
279
280 buf_destroy(&cbp->cb_buf);
281}
282
283static struct cbuf *
284ld_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
313static void
314ld_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
330static int
331ld_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
388static int
389ld_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 */
433try_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) {
450resource_shortage:
451 error = EAGAIN;
452free_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 */
489static void
490ld_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
571out:
572 splx(s);
573}
574
575static int
576ld_ataraid_dump(struct ld_softc *sc, void *data,
577 int blkno, int blkcnt)
578{
579
580 return (EIO);
581}
582
583#if NBIO > 0
584static int
585ld_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
608static int
609ld_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
620static int
621ld_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
666static int
667ld_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
719MODULE(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
731static int
732ld_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