1 /* $Id: ccd.c,v 1.47 1999/05/11 19:54:00 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 cbp->cb_buf.b_resid = 0;
919 if (cs->sc_ileave == 0)
920 cbc = dbtob((off_t)(ci->ci_size - cbn));
922 cbc = dbtob((off_t)(cs->sc_ileave - cboff));
923 cbp->cb_buf.b_bcount = (cbc < bcount) ? cbc : bcount;
925 cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
928 * context for ccdiodone
931 cbp->cb_unit = cs - ccd_softc;
932 cbp->cb_comp = ci - cs->sc_cinfo;
935 if (ccddebug & CCDB_IO)
936 printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
937 ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
938 cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
941 if (cs->sc_cflags & CCDF_MIRROR &&
942 (cbp->cb_buf.b_flags & B_READ) == 0) {
943 /* mirror, start one more write */
945 bzero(cbp, sizeof (struct ccdbuf));
947 cbp->cb_buf.b_dev = ci2->ci_dev;
948 cbp->cb_buf.b_vp = ci2->ci_vp;
949 LIST_INIT(&cbp->cb_buf.b_dep);
950 cbp->cb_comp = ci2 - cs->sc_cinfo;
952 /* link together the ccdbuf's and clear "mirror done" flag */
953 cb[0]->cb_mirror = cb[1];
954 cb[1]->cb_mirror = cb[0];
955 cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
956 cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
962 register struct ccd_softc *cs;
963 register struct buf *bp;
966 if (ccddebug & CCDB_FOLLOW)
967 printf("ccdintr(%x, %x)\n", cs, bp);
970 * Request is done for better or worse, wakeup the top half.
972 /* Record device statistics */
973 devstat_end_transaction(&cs->device_stats,
974 bp->b_bcount - bp->b_resid,
975 (bp->b_flags & B_ORDERED) ?
976 DEVSTAT_TAG_ORDERED : DEVSTAT_TAG_SIMPLE,
977 (bp->b_flags & B_READ) ? DEVSTAT_READ :
980 if (bp->b_flags & B_ERROR)
981 bp->b_resid = bp->b_bcount;
986 * Called at interrupt time.
987 * Mark the component as done and if all components are done,
988 * take a ccd interrupt.
994 register struct buf *bp = cbp->cb_obp;
995 register int unit = cbp->cb_unit;
1000 if (ccddebug & CCDB_FOLLOW)
1001 printf("ccdiodone(%x)\n", cbp);
1002 if (ccddebug & CCDB_IO) {
1003 printf("ccdiodone: bp %x bcount %d resid %d\n",
1004 bp, bp->b_bcount, bp->b_resid);
1005 printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
1006 cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
1007 cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
1008 cbp->cb_buf.b_bcount);
1012 if (cbp->cb_buf.b_flags & B_ERROR) {
1013 bp->b_flags |= B_ERROR;
1014 bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;
1016 printf("ccd%d: error %d on component %d\n",
1017 unit, bp->b_error, cbp->cb_comp);
1021 if (ccd_softc[unit].sc_cflags & CCDF_MIRROR &&
1022 (cbp->cb_buf.b_flags & B_READ) == 0)
1023 if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1024 /* I'm done before my counterpart, so just set
1025 partner's flag and return */
1026 cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1032 count = cbp->cb_buf.b_bcount;
1036 * If all done, "interrupt".
1038 bp->b_resid -= count;
1039 if (bp->b_resid < 0)
1040 panic("ccdiodone: count");
1041 if (bp->b_resid == 0)
1042 ccdintr(&ccd_softc[unit], bp);
1047 ccdioctl(dev, cmd, data, flag, p)
1054 int unit = ccdunit(dev);
1055 int i, j, lookedup = 0, error = 0;
1057 struct ccd_softc *cs;
1058 struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1059 struct ccddevice ccd;
1065 cs = &ccd_softc[unit];
1067 bzero(&ccd, sizeof(ccd));
1071 if (cs->sc_flags & CCDF_INITED)
1074 if ((flag & FWRITE) == 0)
1077 if ((error = ccdlock(cs)) != 0)
1080 /* Fill in some important bits. */
1081 ccd.ccd_unit = unit;
1082 ccd.ccd_interleave = ccio->ccio_ileave;
1083 if (ccd.ccd_interleave == 0 &&
1084 ((ccio->ccio_flags & CCDF_MIRROR) ||
1085 (ccio->ccio_flags & CCDF_PARITY))) {
1086 printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1087 ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1089 if ((ccio->ccio_flags & CCDF_MIRROR) &&
1090 (ccio->ccio_flags & CCDF_PARITY)) {
1091 printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1092 ccio->ccio_flags &= ~CCDF_PARITY;
1094 if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1095 !(ccio->ccio_flags & CCDF_UNIFORM)) {
1096 printf("ccd%d: mirror/parity forces uniform flag\n",
1098 ccio->ccio_flags |= CCDF_UNIFORM;
1100 ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1103 * Allocate space for and copy in the array of
1104 * componet pathnames and device numbers.
1106 cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1107 M_DEVBUF, M_WAITOK);
1108 vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1109 M_DEVBUF, M_WAITOK);
1111 error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1112 ccio->ccio_ndisks * sizeof(char **));
1114 free(vpp, M_DEVBUF);
1115 free(cpp, M_DEVBUF);
1121 if (ccddebug & CCDB_INIT)
1122 for (i = 0; i < ccio->ccio_ndisks; ++i)
1123 printf("ccdioctl: component %d: 0x%x\n",
1127 for (i = 0; i < ccio->ccio_ndisks; ++i) {
1129 if (ccddebug & CCDB_INIT)
1130 printf("ccdioctl: lookedup = %d\n", lookedup);
1132 if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1133 for (j = 0; j < lookedup; ++j)
1134 (void)vn_close(vpp[j], FREAD|FWRITE,
1136 free(vpp, M_DEVBUF);
1137 free(cpp, M_DEVBUF);
1145 ccd.ccd_ndev = ccio->ccio_ndisks;
1148 * Initialize the ccd. Fills in the softc for us.
1150 if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1151 for (j = 0; j < lookedup; ++j)
1152 (void)vn_close(vpp[j], FREAD|FWRITE,
1154 bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1155 free(vpp, M_DEVBUF);
1156 free(cpp, M_DEVBUF);
1162 * The ccd has been successfully initialized, so
1163 * we can place it into the array and read the disklabel.
1165 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1166 ccio->ccio_unit = unit;
1167 ccio->ccio_size = cs->sc_size;
1168 ccdgetdisklabel(dev);
1175 if ((cs->sc_flags & CCDF_INITED) == 0)
1178 if ((flag & FWRITE) == 0)
1181 if ((error = ccdlock(cs)) != 0)
1185 * Don't unconfigure if any other partitions are open
1186 * or if both the character and block flavors of this
1187 * partition are open.
1189 part = ccdpart(dev);
1190 pmask = (1 << part);
1191 if ((cs->sc_openmask & ~pmask) ||
1192 ((cs->sc_bopenmask & pmask) &&
1193 (cs->sc_copenmask & pmask))) {
1199 * Free ccd_softc information and clear entry.
1202 /* Close the components and free their pathnames. */
1203 for (i = 0; i < cs->sc_nccdisks; ++i) {
1205 * XXX: this close could potentially fail and
1206 * cause Bad Things. Maybe we need to force
1207 * the close to happen?
1210 if (ccddebug & CCDB_VNODE)
1211 vprint("CCDIOCCLR: vnode info",
1212 cs->sc_cinfo[i].ci_vp);
1214 (void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1216 free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1219 /* Free interleave index. */
1220 for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1221 free(cs->sc_itable[i].ii_index, M_DEVBUF);
1223 /* Free component info and interleave table. */
1224 free(cs->sc_cinfo, M_DEVBUF);
1225 free(cs->sc_itable, M_DEVBUF);
1226 cs->sc_flags &= ~CCDF_INITED;
1229 * Free ccddevice information and clear entry.
1231 free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1232 free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1234 bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1237 * And remove the devstat entry.
1239 devstat_remove_entry(&cs->device_stats);
1241 /* This must be atomic. */
1244 bzero(cs, sizeof(struct ccd_softc));
1250 if ((cs->sc_flags & CCDF_INITED) == 0)
1253 *(struct disklabel *)data = cs->sc_label;
1257 if ((cs->sc_flags & CCDF_INITED) == 0)
1260 ((struct partinfo *)data)->disklab = &cs->sc_label;
1261 ((struct partinfo *)data)->part =
1262 &cs->sc_label.d_partitions[ccdpart(dev)];
1267 if ((cs->sc_flags & CCDF_INITED) == 0)
1270 if ((flag & FWRITE) == 0)
1273 if ((error = ccdlock(cs)) != 0)
1276 cs->sc_flags |= CCDF_LABELLING;
1278 error = setdisklabel(&cs->sc_label,
1279 (struct disklabel *)data, 0);
1281 if (cmd == DIOCWDINFO)
1282 error = writedisklabel(CCDLABELDEV(dev),
1283 ccdstrategy, &cs->sc_label);
1286 cs->sc_flags &= ~CCDF_LABELLING;
1295 if ((cs->sc_flags & CCDF_INITED) == 0)
1298 if ((flag & FWRITE) == 0)
1300 if (*(int *)data != 0)
1301 cs->sc_flags |= CCDF_WLABEL;
1303 cs->sc_flags &= ~CCDF_WLABEL;
1317 struct ccd_softc *cs;
1320 if (ccdopen(dev, 0, S_IFBLK, curproc))
1323 cs = &ccd_softc[ccdunit(dev)];
1324 part = ccdpart(dev);
1326 if ((cs->sc_flags & CCDF_INITED) == 0)
1329 if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1332 size = cs->sc_label.d_partitions[part].p_size;
1334 if (ccdclose(dev, 0, S_IFBLK, curproc))
1345 /* Not implemented. */
1350 * Lookup the provided name in the filesystem. If the file exists,
1351 * is a valid block device, and isn't being used by anyone else,
1352 * set *vpp to the file's vnode.
1355 ccdlookup(path, p, vpp)
1358 struct vnode **vpp; /* result */
1360 struct nameidata nd;
1365 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1366 if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1368 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1369 printf("ccdlookup: vn_open error = %d\n", error);
1375 if (vp->v_usecount > 1) {
1376 VOP_UNLOCK(vp, 0, p);
1377 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1381 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1383 if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1384 printf("ccdlookup: getattr error = %d\n", error);
1386 VOP_UNLOCK(vp, 0, p);
1387 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1391 /* XXX: eventually we should handle VREG, too. */
1392 if (va.va_type != VBLK) {
1393 VOP_UNLOCK(vp, 0, p);
1394 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1399 if (ccddebug & CCDB_VNODE)
1400 vprint("ccdlookup: vnode info", vp);
1403 VOP_UNLOCK(vp, 0, p);
1409 * Read the disklabel from the ccd. If one is not present, fake one
1413 ccdgetdisklabel(dev)
1416 int unit = ccdunit(dev);
1417 struct ccd_softc *cs = &ccd_softc[unit];
1419 struct disklabel *lp = &cs->sc_label;
1420 struct ccdgeom *ccg = &cs->sc_geom;
1422 bzero(lp, sizeof(*lp));
1424 lp->d_secperunit = cs->sc_size;
1425 lp->d_secsize = ccg->ccg_secsize;
1426 lp->d_nsectors = ccg->ccg_nsectors;
1427 lp->d_ntracks = ccg->ccg_ntracks;
1428 lp->d_ncylinders = ccg->ccg_ncylinders;
1429 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1431 strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1432 lp->d_type = DTYPE_CCD;
1433 strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1435 lp->d_interleave = 1;
1438 lp->d_partitions[RAW_PART].p_offset = 0;
1439 lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1440 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1441 lp->d_npartitions = RAW_PART + 1;
1443 lp->d_bbsize = BBSIZE; /* XXX */
1444 lp->d_sbsize = SBSIZE; /* XXX */
1446 lp->d_magic = DISKMAGIC;
1447 lp->d_magic2 = DISKMAGIC;
1448 lp->d_checksum = dkcksum(&cs->sc_label);
1451 * Call the generic disklabel extraction routine.
1453 if ((errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1454 &cs->sc_label)) != NULL)
1455 ccdmakedisklabel(cs);
1458 /* It's actually extremely common to have unlabeled ccds. */
1459 if (ccddebug & CCDB_LABEL)
1460 if (errstring != NULL)
1461 printf("ccd%d: %s\n", unit, errstring);
1466 * Take care of things one might want to take care of in the event
1467 * that a disklabel isn't present.
1470 ccdmakedisklabel(cs)
1471 struct ccd_softc *cs;
1473 struct disklabel *lp = &cs->sc_label;
1476 * For historical reasons, if there's no disklabel present
1477 * the raw partition must be marked FS_BSDFFS.
1479 lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1481 strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1485 * Wait interruptibly for an exclusive lock.
1488 * Several drivers do this; it should be abstracted and made MP-safe.
1492 struct ccd_softc *cs;
1496 while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1497 cs->sc_flags |= CCDF_WANTED;
1498 if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1501 cs->sc_flags |= CCDF_LOCKED;
1506 * Unlock and wake up any waiters.
1510 struct ccd_softc *cs;
1513 cs->sc_flags &= ~CCDF_LOCKED;
1514 if ((cs->sc_flags & CCDF_WANTED) != 0) {
1515 cs->sc_flags &= ~CCDF_WANTED;
1523 struct ccdiinfo *ii;
1527 for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1528 printf(" itab[%d]: #dk %d sblk %d soff %d",
1529 ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1530 for (i = 0; i < ii->ii_ndisk; i++)
1531 printf(" %d", ii->ii_index[i]);
1537 #endif /* NCCD > 0 */
1539 /* Local Variables: */
1540 /* c-argdecl-indent: 8 */
1541 /* c-continued-statement-offset: 8 */
1542 /* c-indent-level: 8 */