1 /* $Id: ccd.c,v 1.48 1999/05/30 16:51:18 phk Exp $ */
3 /* $NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $ */
6 * Copyright (c) 1995 Jason R. Thorpe.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
21 * 4. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * Copyright (c) 1988 University of Utah.
39 * Copyright (c) 1990, 1993
40 * The Regents of the University of California. All rights reserved.
42 * This code is derived from software contributed to Berkeley by
43 * the Systems Programming Group of the University of Utah Computer
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 * 3. All advertising materials mentioning features or use of this software
55 * must display the following acknowledgement:
56 * This product includes software developed by the University of
57 * California, Berkeley and its contributors.
58 * 4. Neither the name of the University nor the names of its contributors
59 * may be used to endorse or promote products derived from this software
60 * without specific prior written permission.
62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 * from: Utah $Hdr: cd.c 1.6 90/11/28$
76 * @(#)cd.c 8.2 (Berkeley) 11/16/93
80 * "Concatenated" disk driver.
82 * Dynamic configuration and disklabel support by:
83 * Jason R. Thorpe <thorpej@nas.nasa.gov>
84 * Numerical Aerodynamic Simulation Facility
86 * NASA Ames Research Center
87 * Moffett Field, CA 94035
93 #include <sys/param.h>
94 #include <sys/systm.h>
95 #include <sys/kernel.h>
96 #include <sys/module.h>
99 #include <sys/malloc.h>
100 #include <sys/namei.h>
101 #include <sys/conf.h>
102 #include <sys/stat.h>
103 #include <sys/sysctl.h>
104 #include <sys/disklabel.h>
105 #include <ufs/ffs/fs.h>
106 #include <sys/device.h>
107 #include <sys/devicestat.h>
108 #include <sys/fcntl.h>
109 #include <sys/vnode.h>
111 #include <sys/ccdvar.h>
113 #if defined(CCDDEBUG) && !defined(DEBUG)
118 #define CCDB_FOLLOW 0x01
119 #define CCDB_INIT 0x02
121 #define CCDB_LABEL 0x08
122 #define CCDB_VNODE 0x10
123 static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL |
125 SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, "");
129 #define ccdunit(x) dkunit(x)
130 #define ccdpart(x) dkpart(x)
133 This is how mirroring works (only writes are special):
135 When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s
136 linked together by the cb_mirror field. "cb_pflags &
137 CCDPF_MIRROR_DONE" is set to 0 on both of them.
139 When a component returns to ccdiodone(), it checks if "cb_pflags &
140 CCDPF_MIRROR_DONE" is set or not. If not, it sets the partner's
141 flag and returns. If it is, it means its partner has already
142 returned, so it will go to the regular cleanup.
147 struct buf cb_buf; /* new I/O buf */
148 struct buf *cb_obp; /* ptr. to original I/O buf */
149 int cb_unit; /* target unit */
150 int cb_comp; /* target component */
151 int cb_pflags; /* mirror/parity status flag */
152 struct ccdbuf *cb_mirror; /* mirror counterpart */
155 /* bits in cb_pflags */
156 #define CCDPF_MIRROR_DONE 1 /* if set, mirror counterpart is done */
158 #define getccdbuf() \
159 ((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK))
160 #define putccdbuf(cbp) \
161 free((caddr_t)(cbp), M_DEVBUF)
163 #define CCDLABELDEV(dev) \
164 (makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
166 static d_open_t ccdopen;
167 static d_close_t ccdclose;
168 static d_strategy_t ccdstrategy;
169 static d_ioctl_t ccdioctl;
170 static d_dump_t ccddump;
171 static d_psize_t ccdsize;
173 #define CDEV_MAJOR 74
174 #define BDEV_MAJOR 21
176 static struct cdevsw ccd_cdevsw = {
178 /* close */ ccdclose,
180 /* write */ physwrite,
181 /* ioctl */ ccdioctl,
184 /* devtotty */ nodevtotty,
187 /* strategy */ ccdstrategy,
190 /* maj */ CDEV_MAJOR,
195 /* bmaj */ BDEV_MAJOR
198 /* called during module initialization */
199 static void ccdattach __P((void));
200 static int ccd_modevent __P((module_t, int, void *));
202 /* called by biodone() at interrupt time */
203 static void ccdiodone __P((struct ccdbuf *cbp));
205 static void ccdstart __P((struct ccd_softc *, struct buf *));
206 static void ccdinterleave __P((struct ccd_softc *, int));
207 static void ccdintr __P((struct ccd_softc *, struct buf *));
208 static int ccdinit __P((struct ccddevice *, char **, struct proc *));
209 static int ccdlookup __P((char *, struct proc *p, struct vnode **));
210 static void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *,
211 struct buf *, daddr_t, caddr_t, long));
212 static void ccdgetdisklabel __P((dev_t));
213 static void ccdmakedisklabel __P((struct ccd_softc *));
214 static int ccdlock __P((struct ccd_softc *));
215 static void ccdunlock __P((struct ccd_softc *));
218 static void printiinfo __P((struct ccdiinfo *));
221 /* Non-private for the benefit of libkvm. */
222 struct ccd_softc *ccd_softc;
223 struct ccddevice *ccddevs;
224 static int numccd = 0;
227 * Number of blocks to untouched in front of a component partition.
228 * This is to avoid violating its disklabel area when it starts at the
229 * beginning of the slice.
231 #if !defined(CCD_OFFSET)
232 #define CCD_OFFSET 16
236 * Called by main() during pseudo-device attachment. All we need
237 * to do is allocate enough space for devices to be configured later, and
247 printf("ccd0-%d: Concatenated disk drivers\n", num-1);
249 printf("ccd0: Concatenated disk driver\n");
251 ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
253 ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice),
255 if ((ccd_softc == NULL) || (ccddevs == NULL)) {
256 printf("WARNING: no memory for concatenated disks\n");
257 if (ccd_softc != NULL)
258 free(ccd_softc, M_DEVBUF);
260 free(ccddevs, M_DEVBUF);
264 bzero(ccd_softc, num * sizeof(struct ccd_softc));
265 bzero(ccddevs, num * sizeof(struct ccddevice));
267 /* XXX: is this necessary? */
268 for (i = 0; i < numccd; ++i)
269 ccddevs[i].ccd_dk = -1;
273 ccd_modevent(mod, type, data)
286 printf("ccd0: Unload not supported!\n");
290 default: /* MOD_SHUTDOWN etc */
296 DEV_MODULE(ccd, CDEV_MAJOR, BDEV_MAJOR, ccd_cdevsw, ccd_modevent, NULL);
299 ccdinit(ccd, cpaths, p)
300 struct ccddevice *ccd;
304 register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
305 register struct ccdcinfo *ci = NULL; /* XXX */
306 register size_t size;
312 struct partinfo dpart;
313 struct ccdgeom *ccg = &cs->sc_geom;
314 char tmppath[MAXPATHLEN];
318 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
319 printf("ccdinit: unit %d\n", ccd->ccd_unit);
323 cs->sc_ileave = ccd->ccd_interleave;
324 cs->sc_nccdisks = ccd->ccd_ndev;
326 /* Allocate space for the component info. */
327 cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
331 * Verify that each component piece exists and record
332 * relevant information about it.
336 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
337 vp = ccd->ccd_vpp[ix];
338 ci = &cs->sc_cinfo[ix];
342 * Copy in the pathname of the component.
344 bzero(tmppath, sizeof(tmppath)); /* sanity */
345 if ((error = copyinstr(cpaths[ix], tmppath,
346 MAXPATHLEN, &ci->ci_pathlen)) != 0) {
348 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
349 printf("ccd%d: can't copy path, error = %d\n",
350 ccd->ccd_unit, error);
352 while (ci > cs->sc_cinfo) {
354 free(ci->ci_path, M_DEVBUF);
356 free(cs->sc_cinfo, M_DEVBUF);
359 ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
360 bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
363 * XXX: Cache the component's dev_t.
365 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
367 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
368 printf("ccd%d: %s: getattr failed %s = %d\n",
369 ccd->ccd_unit, ci->ci_path,
372 while (ci >= cs->sc_cinfo) {
373 free(ci->ci_path, M_DEVBUF);
376 free(cs->sc_cinfo, M_DEVBUF);
379 ci->ci_dev = udev2dev(va.va_rdev, 2);
382 * Get partition information for the component.
384 if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
385 FREAD, p->p_ucred, p)) != 0) {
387 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
388 printf("ccd%d: %s: ioctl failed, error = %d\n",
389 ccd->ccd_unit, ci->ci_path, error);
391 while (ci >= cs->sc_cinfo) {
392 free(ci->ci_path, M_DEVBUF);
395 free(cs->sc_cinfo, M_DEVBUF);
398 if (dpart.part->p_fstype == FS_BSDFFS) {
400 ((dpart.disklab->d_secsize > maxsecsize) ?
401 dpart.disklab->d_secsize : maxsecsize);
402 size = dpart.part->p_size - CCD_OFFSET;
405 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
406 printf("ccd%d: %s: incorrect partition type\n",
407 ccd->ccd_unit, ci->ci_path);
409 while (ci >= cs->sc_cinfo) {
410 free(ci->ci_path, M_DEVBUF);
413 free(cs->sc_cinfo, M_DEVBUF);
418 * Calculate the size, truncating to an interleave
419 * boundary if necessary.
422 if (cs->sc_ileave > 1)
423 size -= size % cs->sc_ileave;
427 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
428 printf("ccd%d: %s: size == 0\n",
429 ccd->ccd_unit, ci->ci_path);
431 while (ci >= cs->sc_cinfo) {
432 free(ci->ci_path, M_DEVBUF);
435 free(cs->sc_cinfo, M_DEVBUF);
439 if (minsize == 0 || size < minsize)
446 * Don't allow the interleave to be smaller than
447 * the biggest component sector.
449 if ((cs->sc_ileave > 0) &&
450 (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
452 if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
453 printf("ccd%d: interleave must be at least %d\n",
454 ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
456 while (ci >= cs->sc_cinfo) {
457 free(ci->ci_path, M_DEVBUF);
460 free(cs->sc_cinfo, M_DEVBUF);
465 * If uniform interleave is desired set all sizes to that of
466 * the smallest component.
468 if (ccd->ccd_flags & CCDF_UNIFORM) {
469 for (ci = cs->sc_cinfo;
470 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
471 ci->ci_size = minsize;
472 if (ccd->ccd_flags & CCDF_MIRROR) {
474 * Check to see if an even number of components
475 * have been specified.
477 if (cs->sc_nccdisks % 2) {
478 printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
479 while (ci > cs->sc_cinfo) {
481 free(ci->ci_path, M_DEVBUF);
483 free(cs->sc_cinfo, M_DEVBUF);
486 cs->sc_size = (cs->sc_nccdisks/2) * minsize;
488 else if (ccd->ccd_flags & CCDF_PARITY)
489 cs->sc_size = (cs->sc_nccdisks-1) * minsize;
491 cs->sc_size = cs->sc_nccdisks * minsize;
495 * Construct the interleave table.
497 ccdinterleave(cs, ccd->ccd_unit);
500 * Create pseudo-geometry based on 1MB cylinders. It's
503 ccg->ccg_secsize = maxsecsize;
504 ccg->ccg_ntracks = 1;
505 ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
506 ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
509 * Add an devstat entry for this device.
511 devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
512 ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
513 DEVSTAT_TYPE_ASC0 |DEVSTAT_TYPE_IF_OTHER,
514 DEVSTAT_PRIORITY_CCD);
516 cs->sc_flags |= CCDF_INITED;
517 cs->sc_cflags = ccd->ccd_flags; /* So we can find out later... */
518 cs->sc_unit = ccd->ccd_unit;
523 ccdinterleave(cs, unit)
524 register struct ccd_softc *cs;
527 register struct ccdcinfo *ci, *smallci;
528 register struct ccdiinfo *ii;
529 register daddr_t bn, lbn;
534 if (ccddebug & CCDB_INIT)
535 printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
538 * Allocate an interleave table.
539 * Chances are this is too big, but we don't care.
541 size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
542 cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
543 bzero((caddr_t)cs->sc_itable, size);
546 * Trivial case: no interleave (actually interleave of disk size).
547 * Each table entry represents a single component in its entirety.
549 if (cs->sc_ileave == 0) {
553 for (ix = 0; ix < cs->sc_nccdisks; ix++) {
554 /* Allocate space for ii_index. */
555 ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
557 ii->ii_startblk = bn;
559 ii->ii_index[0] = ix;
560 bn += cs->sc_cinfo[ix].ci_size;
565 if (ccddebug & CCDB_INIT)
566 printiinfo(cs->sc_itable);
572 * The following isn't fast or pretty; it doesn't have to be.
576 for (ii = cs->sc_itable; ; ii++) {
577 /* Allocate space for ii_index. */
578 ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
582 * Locate the smallest of the remaining components
585 for (ci = cs->sc_cinfo;
586 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
587 if (ci->ci_size > size &&
589 ci->ci_size < smallci->ci_size))
593 * Nobody left, all done
595 if (smallci == NULL) {
601 * Record starting logical block and component offset
603 ii->ii_startblk = bn / cs->sc_ileave;
604 ii->ii_startoff = lbn;
607 * Determine how many disks take part in this interleave
608 * and record their indices.
611 for (ci = cs->sc_cinfo;
612 ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
613 if (ci->ci_size >= smallci->ci_size)
614 ii->ii_index[ix++] = ci - cs->sc_cinfo;
616 bn += ix * (smallci->ci_size - size);
617 lbn = smallci->ci_size / cs->sc_ileave;
618 size = smallci->ci_size;
621 if (ccddebug & CCDB_INIT)
622 printiinfo(cs->sc_itable);
628 ccdopen(dev, flags, fmt, p)
633 int unit = ccdunit(dev);
634 struct ccd_softc *cs;
635 struct disklabel *lp;
636 int error = 0, part, pmask;
639 if (ccddebug & CCDB_FOLLOW)
640 printf("ccdopen(%x, %x)\n", dev, flags);
644 cs = &ccd_softc[unit];
646 if ((error = ccdlock(cs)) != 0)
655 * If we're initialized, check to see if there are any other
656 * open partitions. If not, then it's safe to update
657 * the in-core disklabel.
659 if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
660 ccdgetdisklabel(dev);
662 /* Check that the partition exists. */
663 if (part != RAW_PART && ((part >= lp->d_npartitions) ||
664 (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
669 /* Prevent our unit from being unconfigured while open. */
672 cs->sc_copenmask |= pmask;
676 cs->sc_bopenmask |= pmask;
680 cs->sc_copenmask | cs->sc_bopenmask;
689 ccdclose(dev, flags, fmt, p)
694 int unit = ccdunit(dev);
695 struct ccd_softc *cs;
699 if (ccddebug & CCDB_FOLLOW)
700 printf("ccdclose(%x, %x)\n", dev, flags);
705 cs = &ccd_softc[unit];
707 if ((error = ccdlock(cs)) != 0)
712 /* ...that much closer to allowing unconfiguration... */
715 cs->sc_copenmask &= ~(1 << part);
719 cs->sc_bopenmask &= ~(1 << part);
723 cs->sc_copenmask | cs->sc_bopenmask;
731 register struct buf *bp;
733 register int unit = ccdunit(bp->b_dev);
734 register struct ccd_softc *cs = &ccd_softc[unit];
737 struct disklabel *lp;
740 if (ccddebug & CCDB_FOLLOW)
741 printf("ccdstrategy(%x): unit %d\n", bp, unit);
743 if ((cs->sc_flags & CCDF_INITED) == 0) {
745 bp->b_flags |= B_ERROR;
749 /* If it's a nil transfer, wake up the top half now. */
750 if (bp->b_bcount == 0)
756 * Do bounds checking and adjust transfer. If there's an
757 * error, the bounds check will flag that for us.
759 wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
760 if (ccdpart(bp->b_dev) != RAW_PART)
761 if (bounds_check_with_label(bp, lp, wlabel) <= 0)
764 bp->b_resid = bp->b_bcount;
779 register struct ccd_softc *cs;
780 register struct buf *bp;
782 register long bcount, rcount;
783 struct ccdbuf *cbp[4];
784 /* XXX! : 2 reads and 2 writes for RAID 4/5 */
787 struct partition *pp;
790 if (ccddebug & CCDB_FOLLOW)
791 printf("ccdstart(%x, %x)\n", cs, bp);
794 /* Record the transaction start */
795 devstat_start_transaction(&cs->device_stats);
798 * Translate the partition-relative block number to an absolute.
801 if (ccdpart(bp->b_dev) != RAW_PART) {
802 pp = &cs->sc_label.d_partitions[ccdpart(bp->b_dev)];
807 * Allocate component buffers and fire off the requests
810 for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
811 ccdbuffer(cbp, cs, bp, bn, addr, bcount);
812 rcount = cbp[0]->cb_buf.b_bcount;
813 if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
814 cbp[0]->cb_buf.b_vp->v_numoutput++;
815 VOP_STRATEGY(cbp[0]->cb_buf.b_vp, &cbp[0]->cb_buf);
816 if (cs->sc_cflags & CCDF_MIRROR &&
817 (cbp[0]->cb_buf.b_flags & B_READ) == 0) {
818 /* mirror, start another write */
819 cbp[1]->cb_buf.b_vp->v_numoutput++;
820 VOP_STRATEGY(cbp[1]->cb_buf.b_vp, &cbp[1]->cb_buf);
828 * Build a component buffer header.
831 ccdbuffer(cb, cs, bp, bn, addr, bcount)
832 register struct ccdbuf **cb;
833 register struct ccd_softc *cs;
839 register struct ccdcinfo *ci, *ci2 = NULL; /* XXX */
840 register struct ccdbuf *cbp;
841 register daddr_t cbn, cboff;
845 if (ccddebug & CCDB_IO)
846 printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
847 cs, bp, bn, addr, bcount);
850 * Determine which component bn falls in.
856 * Serially concatenated
858 if (cs->sc_ileave == 0) {
859 register daddr_t sblk;
862 for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
870 register struct ccdiinfo *ii;
873 cboff = cbn % cs->sc_ileave;
874 cbn /= cs->sc_ileave;
875 for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
876 if (ii->ii_startblk > cbn)
879 off = cbn - ii->ii_startblk;
880 if (ii->ii_ndisk == 1) {
881 ccdisk = ii->ii_index[0];
882 cbn = ii->ii_startoff + off;
884 if (cs->sc_cflags & CCDF_MIRROR) {
885 ccdisk = ii->ii_index[off % (ii->ii_ndisk/2)];
886 cbn = ii->ii_startoff + off / (ii->ii_ndisk/2);
888 ci2 = &cs->sc_cinfo[ccdisk + ii->ii_ndisk/2];
890 else if (cs->sc_cflags & CCDF_PARITY) {
891 ccdisk = ii->ii_index[off % (ii->ii_ndisk-1)];
892 cbn = ii->ii_startoff + off / (ii->ii_ndisk-1);
893 if (cbn % ii->ii_ndisk <= ccdisk)
897 ccdisk = ii->ii_index[off % ii->ii_ndisk];
898 cbn = ii->ii_startoff + off / ii->ii_ndisk;
901 cbn *= cs->sc_ileave;
902 ci = &cs->sc_cinfo[ccdisk];
906 * Fill in the component buf structure.
909 bzero(cbp, sizeof (struct ccdbuf));
910 cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
911 cbp->cb_buf.b_iodone = (void (*)(struct buf *))ccdiodone;
912 cbp->cb_buf.b_dev = ci->ci_dev; /* XXX */
913 cbp->cb_buf.b_blkno = cbn + cboff + CCD_OFFSET;
914 cbp->cb_buf.b_offset = dbtob(cbn + cboff + CCD_OFFSET);
915 cbp->cb_buf.b_data = addr;
916 cbp->cb_buf.b_vp = ci->ci_vp;
917 LIST_INIT(&cbp->cb_buf.b_dep);
918 BUF_LOCKINIT(&cbp->cb_buf);
919 BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
920 cbp->cb_buf.b_resid = 0;
921 if (cs->sc_ileave == 0)
922 cbc = dbtob((off_t)(ci->ci_size - cbn));
924 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
925 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
926 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
929 * context for ccdiodone
932 cbp->cb_unit = cs - ccd_softc;
933 cbp->cb_comp = ci - cs->sc_cinfo;
936 if (ccddebug & CCDB_IO)
937 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
938 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
939 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
942 if (cs->sc_cflags & CCDF_MIRROR &&
943 (cbp->cb_buf.b_flags & B_READ) == 0) {
944 /* mirror, start one more write */
946 bzero(cbp, sizeof (struct ccdbuf));
948 cbp->cb_buf.b_dev = ci2->ci_dev;
949 cbp->cb_buf.b_vp = ci2->ci_vp;
950 LIST_INIT(&cbp->cb_buf.b_dep);
951 BUF_LOCKINIT(&cbp->cb_buf);
952 BUF_LOCK(&cbp->cb_buf, LK_EXCLUSIVE);
953 cbp->cb_comp = ci2 - cs->sc_cinfo;
955 /* link together the ccdbuf's and clear "mirror done" flag */
956 cb[0]->cb_mirror = cb[1];
957 cb[1]->cb_mirror = cb[0];
958 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
959 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
965 register struct ccd_softc *cs;
966 register struct buf *bp;
969 if (ccddebug & CCDB_FOLLOW)
970 printf("ccdintr(%x, %x)\n", cs, bp);
973 * Request is done for better or worse, wakeup the top half.
975 /* Record device statistics */
976 devstat_end_transaction(&cs->device_stats,
977 bp->b_bcount - bp->b_resid,
978 (bp->b_flags & B_ORDERED) ?
979 DEVSTAT_TAG_ORDERED : DEVSTAT_TAG_SIMPLE,
980 (bp->b_flags & B_READ) ? DEVSTAT_READ :
983 if (bp->b_flags & B_ERROR)
984 bp->b_resid = bp->b_bcount;
989 * Called at interrupt time.
990 * Mark the component as done and if all components are done,
991 * take a ccd interrupt.
997 register struct buf *bp = cbp->cb_obp;
998 register int unit = cbp->cb_unit;
1003 if (ccddebug & CCDB_FOLLOW)
1004 printf("ccdiodone(%x)\n", cbp);
1005 if (ccddebug & CCDB_IO) {
1006 printf("ccdiodone: bp %x bcount %d resid %d\n",
1007 bp, bp->b_bcount, bp->b_resid);
1008 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
1009 cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1010 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
1011 cbp->cb_buf.b_bcount);
1015 if (cbp->cb_buf.b_flags & B_ERROR) {
1016 bp->b_flags |= B_ERROR;
1017 bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;
1019 printf("ccd%d: error %d on component %d\n",
1020 unit, bp->b_error, cbp->cb_comp);
1024 if (ccd_softc[unit].sc_cflags & CCDF_MIRROR &&
1025 (cbp->cb_buf.b_flags & B_READ) == 0)
1026 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1027 /* I'm done before my counterpart, so just set
1028 partner's flag and return */
1029 cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1035 count = cbp->cb_buf.b_bcount;
1039 * If all done, "interrupt".
1041 bp->b_resid -= count;
1042 if (bp->b_resid < 0)
1043 panic("ccdiodone: count");
1044 if (bp->b_resid == 0)
1045 ccdintr(&ccd_softc[unit], bp);
1050 ccdioctl(dev, cmd, data, flag, p)
1057 int unit = ccdunit(dev);
1058 int i, j, lookedup = 0, error = 0;
1060 struct ccd_softc *cs;
1061 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1062 struct ccddevice ccd;
1068 cs = &ccd_softc[unit];
1070 bzero(&ccd, sizeof(ccd));
1074 if (cs->sc_flags & CCDF_INITED)
1077 if ((flag & FWRITE) == 0)
1080 if ((error = ccdlock(cs)) != 0)
1083 /* Fill in some important bits. */
1084 ccd.ccd_unit = unit;
1085 ccd.ccd_interleave = ccio->ccio_ileave;
1086 if (ccd.ccd_interleave == 0 &&
1087 ((ccio->ccio_flags & CCDF_MIRROR) ||
1088 (ccio->ccio_flags & CCDF_PARITY))) {
1089 printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1090 ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1092 if ((ccio->ccio_flags & CCDF_MIRROR) &&
1093 (ccio->ccio_flags & CCDF_PARITY)) {
1094 printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1095 ccio->ccio_flags &= ~CCDF_PARITY;
1097 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1098 !(ccio->ccio_flags & CCDF_UNIFORM)) {
1099 printf("ccd%d: mirror/parity forces uniform flag\n",
1101 ccio->ccio_flags |= CCDF_UNIFORM;
1103 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1106 * Allocate space for and copy in the array of
1107 * componet pathnames and device numbers.
1109 cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1110 M_DEVBUF, M_WAITOK);
1111 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1112 M_DEVBUF, M_WAITOK);
1114 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1115 ccio->ccio_ndisks * sizeof(char **));
1117 free(vpp, M_DEVBUF);
1118 free(cpp, M_DEVBUF);
1124 if (ccddebug & CCDB_INIT)
1125 for (i = 0; i < ccio->ccio_ndisks; ++i)
1126 printf("ccdioctl: component %d: 0x%x\n",
1130 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1132 if (ccddebug & CCDB_INIT)
1133 printf("ccdioctl: lookedup = %d\n", lookedup);
1135 if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1136 for (j = 0; j < lookedup; ++j)
1137 (void)vn_close(vpp[j], FREAD|FWRITE,
1139 free(vpp, M_DEVBUF);
1140 free(cpp, M_DEVBUF);
1148 ccd.ccd_ndev = ccio->ccio_ndisks;
1151 * Initialize the ccd. Fills in the softc for us.
1153 if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1154 for (j = 0; j < lookedup; ++j)
1155 (void)vn_close(vpp[j], FREAD|FWRITE,
1157 bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1158 free(vpp, M_DEVBUF);
1159 free(cpp, M_DEVBUF);
1165 * The ccd has been successfully initialized, so
1166 * we can place it into the array and read the disklabel.
1168 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1169 ccio->ccio_unit = unit;
1170 ccio->ccio_size = cs->sc_size;
1171 ccdgetdisklabel(dev);
1178 if ((cs->sc_flags & CCDF_INITED) == 0)
1181 if ((flag & FWRITE) == 0)
1184 if ((error = ccdlock(cs)) != 0)
1188 * Don't unconfigure if any other partitions are open
1189 * or if both the character and block flavors of this
1190 * partition are open.
1192 part = ccdpart(dev);
1193 pmask = (1 << part);
1194 if ((cs->sc_openmask & ~pmask) ||
1195 ((cs->sc_bopenmask & pmask) &&
1196 (cs->sc_copenmask & pmask))) {
1202 * Free ccd_softc information and clear entry.
1205 /* Close the components and free their pathnames. */
1206 for (i = 0; i < cs->sc_nccdisks; ++i) {
1208 * XXX: this close could potentially fail and
1209 * cause Bad Things. Maybe we need to force
1210 * the close to happen?
1213 if (ccddebug & CCDB_VNODE)
1214 vprint("CCDIOCCLR: vnode info",
1215 cs->sc_cinfo[i].ci_vp);
1217 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1219 free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1222 /* Free interleave index. */
1223 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1224 free(cs->sc_itable[i].ii_index, M_DEVBUF);
1226 /* Free component info and interleave table. */
1227 free(cs->sc_cinfo, M_DEVBUF);
1228 free(cs->sc_itable, M_DEVBUF);
1229 cs->sc_flags &= ~CCDF_INITED;
1232 * Free ccddevice information and clear entry.
1234 free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1235 free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1237 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1240 * And remove the devstat entry.
1242 devstat_remove_entry(&cs->device_stats);
1244 /* This must be atomic. */
1247 bzero(cs, sizeof(struct ccd_softc));
1253 if ((cs->sc_flags & CCDF_INITED) == 0)
1256 *(struct disklabel *)data = cs->sc_label;
1260 if ((cs->sc_flags & CCDF_INITED) == 0)
1263 ((struct partinfo *)data)->disklab = &cs->sc_label;
1264 ((struct partinfo *)data)->part =
1265 &cs->sc_label.d_partitions[ccdpart(dev)];
1270 if ((cs->sc_flags & CCDF_INITED) == 0)
1273 if ((flag & FWRITE) == 0)
1276 if ((error = ccdlock(cs)) != 0)
1279 cs->sc_flags |= CCDF_LABELLING;
1281 error = setdisklabel(&cs->sc_label,
1282 (struct disklabel *)data, 0);
1284 if (cmd == DIOCWDINFO)
1285 error = writedisklabel(CCDLABELDEV(dev),
1286 ccdstrategy, &cs->sc_label);
1289 cs->sc_flags &= ~CCDF_LABELLING;
1298 if ((cs->sc_flags & CCDF_INITED) == 0)
1301 if ((flag & FWRITE) == 0)
1303 if (*(int *)data != 0)
1304 cs->sc_flags |= CCDF_WLABEL;
1306 cs->sc_flags &= ~CCDF_WLABEL;
1320 struct ccd_softc *cs;
1323 if (ccdopen(dev, 0, S_IFBLK, curproc))
1326 cs = &ccd_softc[ccdunit(dev)];
1327 part = ccdpart(dev);
1329 if ((cs->sc_flags & CCDF_INITED) == 0)
1332 if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1335 size = cs->sc_label.d_partitions[part].p_size;
1337 if (ccdclose(dev, 0, S_IFBLK, curproc))
1348 /* Not implemented. */
1353 * Lookup the provided name in the filesystem. If the file exists,
1354 * is a valid block device, and isn't being used by anyone else,
1355 * set *vpp to the file's vnode.
1358 ccdlookup(path, p, vpp)
1361 struct vnode **vpp; /* result */
1363 struct nameidata nd;
1368 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1369 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1371 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1372 printf("ccdlookup: vn_open error = %d\n", error);
1378 if (vp->v_usecount > 1) {
1379 VOP_UNLOCK(vp, 0, p);
1380 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1384 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1386 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1387 printf("ccdlookup: getattr error = %d\n", error);
1389 VOP_UNLOCK(vp, 0, p);
1390 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1394 /* XXX: eventually we should handle VREG, too. */
1395 if (va.va_type != VBLK) {
1396 VOP_UNLOCK(vp, 0, p);
1397 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1402 if (ccddebug & CCDB_VNODE)
1403 vprint("ccdlookup: vnode info", vp);
1406 VOP_UNLOCK(vp, 0, p);
1412 * Read the disklabel from the ccd. If one is not present, fake one
1416 ccdgetdisklabel(dev)
1419 int unit = ccdunit(dev);
1420 struct ccd_softc *cs = &ccd_softc[unit];
1422 struct disklabel *lp = &cs->sc_label;
1423 struct ccdgeom *ccg = &cs->sc_geom;
1425 bzero(lp, sizeof(*lp));
1427 lp->d_secperunit = cs->sc_size;
1428 lp->d_secsize = ccg->ccg_secsize;
1429 lp->d_nsectors = ccg->ccg_nsectors;
1430 lp->d_ntracks = ccg->ccg_ntracks;
1431 lp->d_ncylinders = ccg->ccg_ncylinders;
1432 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1434 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1435 lp->d_type = DTYPE_CCD;
1436 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1438 lp->d_interleave = 1;
1441 lp->d_partitions[RAW_PART].p_offset = 0;
1442 lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1443 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1444 lp->d_npartitions = RAW_PART + 1;
1446 lp->d_bbsize = BBSIZE; /* XXX */
1447 lp->d_sbsize = SBSIZE; /* XXX */
1449 lp->d_magic = DISKMAGIC;
1450 lp->d_magic2 = DISKMAGIC;
1451 lp->d_checksum = dkcksum(&cs->sc_label);
1454 * Call the generic disklabel extraction routine.
1456 if ((errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1457 &cs->sc_label)) != NULL)
1458 ccdmakedisklabel(cs);
1461 /* It's actually extremely common to have unlabeled ccds. */
1462 if (ccddebug & CCDB_LABEL)
1463 if (errstring != NULL)
1464 printf("ccd%d: %s\n", unit, errstring);
1469 * Take care of things one might want to take care of in the event
1470 * that a disklabel isn't present.
1473 ccdmakedisklabel(cs)
1474 struct ccd_softc *cs;
1476 struct disklabel *lp = &cs->sc_label;
1479 * For historical reasons, if there's no disklabel present
1480 * the raw partition must be marked FS_BSDFFS.
1482 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1484 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1488 * Wait interruptibly for an exclusive lock.
1491 * Several drivers do this; it should be abstracted and made MP-safe.
1495 struct ccd_softc *cs;
1499 while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1500 cs->sc_flags |= CCDF_WANTED;
1501 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1504 cs->sc_flags |= CCDF_LOCKED;
1509 * Unlock and wake up any waiters.
1513 struct ccd_softc *cs;
1516 cs->sc_flags &= ~CCDF_LOCKED;
1517 if ((cs->sc_flags & CCDF_WANTED) != 0) {
1518 cs->sc_flags &= ~CCDF_WANTED;
1526 struct ccdiinfo *ii;
1530 for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1531 printf(" itab[%d]: #dk %d sblk %d soff %d",
1532 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1533 for (i = 0; i < ii->ii_ndisk; i++)
1534 printf(" %d", ii->ii_index[i]);
1540 #endif /* NCCD > 0 */
1542 /* Local Variables: */
1543 /* c-argdecl-indent: 8 */
1544 /* c-continued-statement-offset: 8 */
1545 /* c-indent-level: 8 */