Home | History | Annotate | Line # | Download | only in dev
ccd.c revision 1.40
      1 /*	$NetBSD: ccd.c,v 1.40 1997/06/23 23:59:53 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
     30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * Copyright (c) 1988 University of Utah.
     41  * Copyright (c) 1990, 1993
     42  *	The Regents of the University of California.  All rights reserved.
     43  *
     44  * This code is derived from software contributed to Berkeley by
     45  * the Systems Programming Group of the University of Utah Computer
     46  * Science Department.
     47  *
     48  * Redistribution and use in source and binary forms, with or without
     49  * modification, are permitted provided that the following conditions
     50  * are met:
     51  * 1. Redistributions of source code must retain the above copyright
     52  *    notice, this list of conditions and the following disclaimer.
     53  * 2. Redistributions in binary form must reproduce the above copyright
     54  *    notice, this list of conditions and the following disclaimer in the
     55  *    documentation and/or other materials provided with the distribution.
     56  * 3. All advertising materials mentioning features or use of this software
     57  *    must display the following acknowledgement:
     58  *	This product includes software developed by the University of
     59  *	California, Berkeley and its contributors.
     60  * 4. Neither the name of the University nor the names of its contributors
     61  *    may be used to endorse or promote products derived from this software
     62  *    without specific prior written permission.
     63  *
     64  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     65  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     66  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     67  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     68  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     69  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     70  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     71  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     72  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     73  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     74  * SUCH DAMAGE.
     75  *
     76  * from: Utah $Hdr: cd.c 1.6 90/11/28$
     77  *
     78  *	@(#)cd.c	8.2 (Berkeley) 11/16/93
     79  */
     80 
     81 /*
     82  * "Concatenated" disk driver.
     83  *
     84  * Dynamic configuration and disklabel support by:
     85  *	Jason R. Thorpe <thorpej (at) nas.nasa.gov>
     86  *	Numerical Aerodynamic Simulation Facility
     87  *	Mail Stop 258-6
     88  *	NASA Ames Research Center
     89  *	Moffett Field, CA 94035
     90  *
     91  * Mirroring support based on code written by Satoshi Asami
     92  * and Nisha Talagala.
     93  */
     94 
     95 #include <sys/param.h>
     96 #include <sys/systm.h>
     97 #include <sys/proc.h>
     98 #include <sys/errno.h>
     99 #include <sys/buf.h>
    100 #include <sys/malloc.h>
    101 #include <sys/namei.h>
    102 #include <sys/stat.h>
    103 #include <sys/ioctl.h>
    104 #include <sys/disklabel.h>
    105 #include <sys/device.h>
    106 #include <sys/disk.h>
    107 #include <sys/syslog.h>
    108 #include <sys/fcntl.h>
    109 #include <sys/vnode.h>
    110 #include <sys/conf.h>
    111 
    112 #include <dev/ccdvar.h>
    113 
    114 #if defined(CCDDEBUG) && !defined(DEBUG)
    115 #define DEBUG
    116 #endif
    117 
    118 #ifdef DEBUG
    119 #define CCDB_FOLLOW	0x01
    120 #define CCDB_INIT	0x02
    121 #define CCDB_IO		0x04
    122 #define CCDB_LABEL	0x08
    123 #define CCDB_VNODE	0x10
    124 int ccddebug = 0x00;
    125 #endif
    126 
    127 #define	ccdunit(x)	DISKUNIT(x)
    128 
    129 struct ccdbuf {
    130 	struct buf	cb_buf;		/* new I/O buf */
    131 	struct buf	*cb_obp;	/* ptr. to original I/O buf */
    132 	int		cb_unit;	/* target unit */
    133 	int		cb_comp;	/* target component */
    134 	int		cb_flags;	/* misc. flags */
    135 	LIST_ENTRY(ccdbuf) cb_list;	/* entry on freelist */
    136 };
    137 
    138 /* cb_flags */
    139 #define CBF_MIRROR	0x01		/* we're for a mirror component */
    140 
    141 /*
    142  * Number of freelist buffers per component.  Overridable in kernel
    143  * config file and patchable.
    144  */
    145 #ifndef CCDNBUF
    146 #define	CCDNBUF		8
    147 #endif
    148 int	ccdnbuf = CCDNBUF;
    149 
    150 /*
    151  * XXX Is it OK to wait here?
    152  * XXX maybe set up a timeout when we hit some lowater?
    153  * XXX    --thorpej
    154  */
    155 #define	CCDGETBUF(cs, cbp)	do {					\
    156 		(cs)->sc_ngetbuf++;					\
    157 		if (((cbp) = (cs)->sc_freelist.lh_first) != NULL) {	\
    158 			LIST_REMOVE((cbp), cb_list);			\
    159 			(cs)->sc_freecount--;				\
    160 		} else {						\
    161 			(cs)->sc_nmisses++;				\
    162 			MALLOC((cbp), struct ccdbuf *,			\
    163 			    sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK);	\
    164 		}							\
    165 	} while (0)
    166 
    167 #define	CCDPUTBUF(cs, cbp)	do {					\
    168 		if ((cs)->sc_freecount == (cs)->sc_hiwat) {		\
    169 			FREE((cbp), M_DEVBUF);				\
    170 		} else {						\
    171 			LIST_INSERT_HEAD(&(cs)->sc_freelist, (cbp), cb_list); \
    172 			(cs)->sc_freecount++;				\
    173 		}							\
    174 	} while (0)
    175 
    176 #define CCDLABELDEV(dev)	\
    177 	(MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART))
    178 
    179 /* called by main() at boot time */
    180 void	ccdattach __P((int));
    181 
    182 /* called by biodone() at interrupt time */
    183 void	ccdiodone __P((struct buf *));
    184 int	ccdsize __P((dev_t));
    185 
    186 static	void ccdstart __P((struct ccd_softc *, struct buf *));
    187 static	void ccdinterleave __P((struct ccd_softc *, int));
    188 static	void ccdintr __P((struct ccd_softc *, struct buf *));
    189 static	int ccdinit __P((struct ccddevice *, char **, struct proc *));
    190 static	int ccdlookup __P((char *, struct proc *p, struct vnode **));
    191 static	void ccdbuffer __P((struct ccd_softc *, struct buf *,
    192 		daddr_t, caddr_t, long, struct ccdbuf **));
    193 static	void ccdgetdisklabel __P((dev_t));
    194 static	void ccdmakedisklabel __P((struct ccd_softc *));
    195 static	int ccdlock __P((struct ccd_softc *));
    196 static	void ccdunlock __P((struct ccd_softc *));
    197 
    198 #ifdef DEBUG
    199 static	void printiinfo __P((struct ccdiinfo *));
    200 #endif
    201 
    202 /* Non-private for the benefit of libkvm. */
    203 struct	ccd_softc *ccd_softc;
    204 struct	ccddevice *ccddevs;
    205 int	numccd = 0;
    206 
    207 /*
    208  * Called by main() during pseudo-device attachment.  All we need
    209  * to do is allocate enough space for devices to be configured later.
    210  */
    211 void
    212 ccdattach(num)
    213 	int num;
    214 {
    215 	if (num <= 0) {
    216 #ifdef DIAGNOSTIC
    217 		panic("ccdattach: count <= 0");
    218 #endif
    219 		return;
    220 	}
    221 
    222 	ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
    223 	    M_DEVBUF, M_NOWAIT);
    224 	ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice),
    225 	    M_DEVBUF, M_NOWAIT);
    226 	if ((ccd_softc == NULL) || (ccddevs == NULL)) {
    227 		printf("WARNING: no memory for concatenated disks\n");
    228 		if (ccd_softc != NULL)
    229 			free(ccd_softc, M_DEVBUF);
    230 		if (ccddevs != NULL)
    231 			free(ccddevs, M_DEVBUF);
    232 		return;
    233 	}
    234 	numccd = num;
    235 	bzero(ccd_softc, num * sizeof(struct ccd_softc));
    236 	bzero(ccddevs, num * sizeof(struct ccddevice));
    237 }
    238 
    239 static int
    240 ccdinit(ccd, cpaths, p)
    241 	struct ccddevice *ccd;
    242 	char **cpaths;
    243 	struct proc *p;
    244 {
    245 	register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
    246 	register struct ccdcinfo *ci = NULL;
    247 	register size_t size;
    248 	register int ix;
    249 	struct vnode *vp;
    250 	struct vattr va;
    251 	size_t minsize;
    252 	int maxsecsize;
    253 	struct partinfo dpart;
    254 	struct ccdgeom *ccg = &cs->sc_geom;
    255 	char tmppath[MAXPATHLEN];
    256 	struct ccdbuf *cbp;
    257 	int error;
    258 
    259 #ifdef DEBUG
    260 	if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
    261 		printf("ccdinit: unit %d\n", ccd->ccd_unit);
    262 #endif
    263 
    264 	cs->sc_size = 0;
    265 	cs->sc_ileave = ccd->ccd_interleave;
    266 	cs->sc_nccdisks = ccd->ccd_ndev;
    267 	sprintf(cs->sc_xname, "ccd%d", ccd->ccd_unit);	/* XXX */
    268 
    269 	/* Allocate space for the component info. */
    270 	cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
    271 	    M_DEVBUF, M_WAITOK);
    272 
    273 	/*
    274 	 * Verify that each component piece exists and record
    275 	 * relevant information about it.
    276 	 */
    277 	maxsecsize = 0;
    278 	minsize = 0;
    279 	for (ix = 0; ix < cs->sc_nccdisks; ix++) {
    280 		vp = ccd->ccd_vpp[ix];
    281 		ci = &cs->sc_cinfo[ix];
    282 		ci->ci_vp = vp;
    283 
    284 		/*
    285 		 * Copy in the pathname of the component.
    286 		 */
    287 		bzero(tmppath, sizeof(tmppath));	/* sanity */
    288 		error = copyinstr(cpaths[ix], tmppath,
    289 		    MAXPATHLEN, &ci->ci_pathlen);
    290 		if (error) {
    291 #ifdef DEBUG
    292 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
    293 				printf("%s: can't copy path, error = %d\n",
    294 				    cs->sc_xname, error);
    295 #endif
    296 			free(cs->sc_cinfo, M_DEVBUF);
    297 			return (error);
    298 		}
    299 		ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
    300 		bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
    301 
    302 		/*
    303 		 * XXX: Cache the component's dev_t.
    304 		 */
    305 		if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
    306 #ifdef DEBUG
    307 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
    308 				printf("%s: %s: getattr failed %s = %d\n",
    309 				    cs->sc_xname, ci->ci_path,
    310 				    "error", error);
    311 #endif
    312 			free(ci->ci_path, M_DEVBUF);
    313 			free(cs->sc_cinfo, M_DEVBUF);
    314 			return (error);
    315 		}
    316 		ci->ci_dev = va.va_rdev;
    317 
    318 		/*
    319 		 * Get partition information for the component.
    320 		 */
    321 		error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
    322 		    FREAD, p->p_ucred, p);
    323 		if (error) {
    324 #ifdef DEBUG
    325 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
    326 				 printf("%s: %s: ioctl failed, error = %d\n",
    327 				     cs->sc_xname, ci->ci_path, error);
    328 #endif
    329 			free(ci->ci_path, M_DEVBUF);
    330 			free(cs->sc_cinfo, M_DEVBUF);
    331 			return (error);
    332 		}
    333 		if (dpart.part->p_fstype == FS_BSDFFS) {
    334 			maxsecsize =
    335 			    ((dpart.disklab->d_secsize > maxsecsize) ?
    336 			    dpart.disklab->d_secsize : maxsecsize);
    337 			size = dpart.part->p_size;
    338 		} else {
    339 #ifdef DEBUG
    340 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
    341 				printf("%s: %s: incorrect partition type\n",
    342 				    cs->sc_xname, ci->ci_path);
    343 #endif
    344 			free(ci->ci_path, M_DEVBUF);
    345 			free(cs->sc_cinfo, M_DEVBUF);
    346 			return (EFTYPE);
    347 		}
    348 
    349 		/*
    350 		 * Calculate the size, truncating to an interleave
    351 		 * boundary if necessary.
    352 		 */
    353 		if (cs->sc_ileave > 1)
    354 			size -= size % cs->sc_ileave;
    355 
    356 		if (size == 0) {
    357 #ifdef DEBUG
    358 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
    359 				printf("%s: %s: size == 0\n",
    360 				    cs->sc_xname, ci->ci_path);
    361 #endif
    362 			free(ci->ci_path, M_DEVBUF);
    363 			free(cs->sc_cinfo, M_DEVBUF);
    364 			return (ENODEV);
    365 		}
    366 
    367 		if (minsize == 0 || size < minsize)
    368 			minsize = size;
    369 		ci->ci_size = size;
    370 		cs->sc_size += size;
    371 	}
    372 
    373 	/*
    374 	 * Don't allow the interleave to be smaller than
    375 	 * the biggest component sector.
    376 	 */
    377 	if ((cs->sc_ileave > 0) &&
    378 	    (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
    379 #ifdef DEBUG
    380 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
    381 			printf("%s: interleave must be at least %d\n",
    382 			    cs->sc_xname, (maxsecsize / DEV_BSIZE));
    383 #endif
    384 		free(ci->ci_path, M_DEVBUF);
    385 		free(cs->sc_cinfo, M_DEVBUF);
    386 		return (EINVAL);
    387 	}
    388 
    389 	/*
    390 	 * Mirroring support requires uniform interleave and
    391 	 * and even number of components.
    392 	 */
    393 	if (ccd->ccd_flags & CCDF_MIRROR) {
    394 		ccd->ccd_flags |= CCDF_UNIFORM;
    395 		if (cs->sc_ileave == 0) {
    396 #ifdef DEBUG
    397 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
    398 			printf("%s: mirroring requires interleave\n",
    399 			    cs->sc_xname);
    400 #endif
    401 			free(ci->ci_path, M_DEVBUF);
    402 			free(cs->sc_cinfo, M_DEVBUF);
    403 			return (EINVAL);
    404 		}
    405 		if (cs->sc_nccdisks % 2) {
    406 #ifdef DEBUG
    407 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
    408 			printf("%s: mirroring requires even # of components\n",
    409 			    cs->sc_xname);
    410 #endif
    411 			free(ci->ci_path, M_DEVBUF);
    412 			free(cs->sc_cinfo, M_DEVBUF);
    413 			return (EINVAL);
    414 		}
    415 	}
    416 
    417 	/*
    418 	 * If uniform interleave is desired set all sizes to that of
    419 	 * the smallest component.
    420 	 */
    421 	if (ccd->ccd_flags & CCDF_UNIFORM) {
    422 		for (ci = cs->sc_cinfo;
    423 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
    424 			ci->ci_size = minsize;
    425 
    426 		if (ccd->ccd_flags & CCDF_MIRROR)
    427 			cs->sc_size = (cs->sc_nccdisks / 2) * minsize;
    428 		else
    429 			cs->sc_size = cs->sc_nccdisks * minsize;
    430 	}
    431 
    432 	/*
    433 	 * Construct the interleave table.
    434 	 */
    435 	ccdinterleave(cs, ccd->ccd_unit);
    436 
    437 	/*
    438 	 * Create pseudo-geometry based on 1MB cylinders.  It's
    439 	 * pretty close.
    440 	 */
    441 	ccg->ccg_secsize = DEV_BSIZE;
    442 	ccg->ccg_ntracks = 1;
    443 	ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
    444 	ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
    445 
    446 	/*
    447 	 * Allocate the component buffer header freelist.  We allocate
    448 	 * ccdnbuf buffers per component.
    449 	 */
    450 	LIST_INIT(&cs->sc_freelist);
    451 	cs->sc_hiwat = cs->sc_nccdisks * ccdnbuf;
    452 	cs->sc_freecount = cs->sc_hiwat;
    453 	for (ix = 0; ix < cs->sc_hiwat; ix++) {
    454 		MALLOC(cbp, struct ccdbuf *, sizeof(struct ccdbuf),
    455 		    M_DEVBUF, M_WAITOK);
    456 		LIST_INSERT_HEAD(&cs->sc_freelist, cbp, cb_list);
    457 	}
    458 
    459 	/* Reset statistics. */
    460 	cs->sc_nmisses = 0;
    461 	cs->sc_ngetbuf = 0;
    462 
    463 	cs->sc_flags |= CCDF_INITED;
    464 	cs->sc_cflags = ccd->ccd_flags;	/* So we can find out later... */
    465 	cs->sc_unit = ccd->ccd_unit;
    466 
    467 	return (0);
    468 }
    469 
    470 static void
    471 ccdinterleave(cs, unit)
    472 	register struct ccd_softc *cs;
    473 	int unit;
    474 {
    475 	register struct ccdcinfo *ci, *smallci;
    476 	register struct ccdiinfo *ii;
    477 	register daddr_t bn, lbn;
    478 	register int ix;
    479 	u_long size;
    480 
    481 #ifdef DEBUG
    482 	if (ccddebug & CCDB_INIT)
    483 		printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave);
    484 #endif
    485 	/*
    486 	 * Allocate an interleave table.
    487 	 * Chances are this is too big, but we don't care.
    488 	 */
    489 	size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
    490 	cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
    491 	bzero((caddr_t)cs->sc_itable, size);
    492 
    493 	/*
    494 	 * Trivial case: no interleave (actually interleave of disk size).
    495 	 * Each table entry represents a single component in its entirety.
    496 	 */
    497 	if (cs->sc_ileave == 0) {
    498 		bn = 0;
    499 		ii = cs->sc_itable;
    500 
    501 		for (ix = 0; ix < cs->sc_nccdisks; ix++) {
    502 			/* Allocate space for ii_index. */
    503 			ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
    504 			ii->ii_ndisk = 1;
    505 			ii->ii_startblk = bn;
    506 			ii->ii_startoff = 0;
    507 			ii->ii_index[0] = ix;
    508 			bn += cs->sc_cinfo[ix].ci_size;
    509 			ii++;
    510 		}
    511 		ii->ii_ndisk = 0;
    512 #ifdef DEBUG
    513 		if (ccddebug & CCDB_INIT)
    514 			printiinfo(cs->sc_itable);
    515 #endif
    516 		return;
    517 	}
    518 
    519 	/*
    520 	 * The following isn't fast or pretty; it doesn't have to be.
    521 	 */
    522 	size = 0;
    523 	bn = lbn = 0;
    524 	for (ii = cs->sc_itable; ; ii++) {
    525 		/* Allocate space for ii_index. */
    526 		ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
    527 		    M_DEVBUF, M_WAITOK);
    528 
    529 		/*
    530 		 * Locate the smallest of the remaining components
    531 		 */
    532 		smallci = NULL;
    533 		for (ci = cs->sc_cinfo;
    534 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
    535 			if (ci->ci_size > size &&
    536 			    (smallci == NULL ||
    537 			     ci->ci_size < smallci->ci_size))
    538 				smallci = ci;
    539 
    540 		/*
    541 		 * Nobody left, all done
    542 		 */
    543 		if (smallci == NULL) {
    544 			ii->ii_ndisk = 0;
    545 			break;
    546 		}
    547 
    548 		/*
    549 		 * Record starting logical block and component offset
    550 		 */
    551 		ii->ii_startblk = bn / cs->sc_ileave;
    552 		ii->ii_startoff = lbn;
    553 
    554 		/*
    555 		 * Determine how many disks take part in this interleave
    556 		 * and record their indices.
    557 		 */
    558 		ix = 0;
    559 		for (ci = cs->sc_cinfo;
    560 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
    561 			if (ci->ci_size >= smallci->ci_size)
    562 				ii->ii_index[ix++] = ci - cs->sc_cinfo;
    563 		ii->ii_ndisk = ix;
    564 		bn += ix * (smallci->ci_size - size);
    565 		lbn = smallci->ci_size / cs->sc_ileave;
    566 		size = smallci->ci_size;
    567 	}
    568 #ifdef DEBUG
    569 	if (ccddebug & CCDB_INIT)
    570 		printiinfo(cs->sc_itable);
    571 #endif
    572 }
    573 
    574 /* ARGSUSED */
    575 int
    576 ccdopen(dev, flags, fmt, p)
    577 	dev_t dev;
    578 	int flags, fmt;
    579 	struct proc *p;
    580 {
    581 	int unit = ccdunit(dev);
    582 	struct ccd_softc *cs;
    583 	struct disklabel *lp;
    584 	int error = 0, part, pmask;
    585 
    586 #ifdef DEBUG
    587 	if (ccddebug & CCDB_FOLLOW)
    588 		printf("ccdopen(%x, %x)\n", dev, flags);
    589 #endif
    590 	if (unit >= numccd)
    591 		return (ENXIO);
    592 	cs = &ccd_softc[unit];
    593 
    594 	if ((error = ccdlock(cs)) != 0)
    595 		return (error);
    596 
    597 	lp = cs->sc_dkdev.dk_label;
    598 
    599 	part = DISKPART(dev);
    600 	pmask = (1 << part);
    601 
    602 	/*
    603 	 * If we're initialized, check to see if there are any other
    604 	 * open partitions.  If not, then it's safe to update
    605 	 * the in-core disklabel.
    606 	 */
    607 	if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0))
    608 		ccdgetdisklabel(dev);
    609 
    610 	/* Check that the partition exists. */
    611 	if (part != RAW_PART) {
    612 		if (((cs->sc_flags & CCDF_INITED) == 0) ||
    613 		    ((part >= lp->d_npartitions) ||
    614 		     (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
    615 			error = ENXIO;
    616 			goto done;
    617 		}
    618 	}
    619 
    620 	/* Prevent our unit from being unconfigured while open. */
    621 	switch (fmt) {
    622 	case S_IFCHR:
    623 		cs->sc_dkdev.dk_copenmask |= pmask;
    624 		break;
    625 
    626 	case S_IFBLK:
    627 		cs->sc_dkdev.dk_bopenmask |= pmask;
    628 		break;
    629 	}
    630 	cs->sc_dkdev.dk_openmask =
    631 	    cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
    632 
    633  done:
    634 	ccdunlock(cs);
    635 	return (error);
    636 }
    637 
    638 /* ARGSUSED */
    639 int
    640 ccdclose(dev, flags, fmt, p)
    641 	dev_t dev;
    642 	int flags, fmt;
    643 	struct proc *p;
    644 {
    645 	int unit = ccdunit(dev);
    646 	struct ccd_softc *cs;
    647 	int error = 0, part;
    648 
    649 #ifdef DEBUG
    650 	if (ccddebug & CCDB_FOLLOW)
    651 		printf("ccdclose(%x, %x)\n", dev, flags);
    652 #endif
    653 
    654 	if (unit >= numccd)
    655 		return (ENXIO);
    656 	cs = &ccd_softc[unit];
    657 
    658 	if ((error = ccdlock(cs)) != 0)
    659 		return (error);
    660 
    661 	part = DISKPART(dev);
    662 
    663 	/* ...that much closer to allowing unconfiguration... */
    664 	switch (fmt) {
    665 	case S_IFCHR:
    666 		cs->sc_dkdev.dk_copenmask &= ~(1 << part);
    667 		break;
    668 
    669 	case S_IFBLK:
    670 		cs->sc_dkdev.dk_bopenmask &= ~(1 << part);
    671 		break;
    672 	}
    673 	cs->sc_dkdev.dk_openmask =
    674 	    cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
    675 
    676 	ccdunlock(cs);
    677 	return (0);
    678 }
    679 
    680 void
    681 ccdstrategy(bp)
    682 	register struct buf *bp;
    683 {
    684 	register int unit = ccdunit(bp->b_dev);
    685 	register struct ccd_softc *cs = &ccd_softc[unit];
    686 	register int s;
    687 	int wlabel;
    688 	struct disklabel *lp;
    689 
    690 #ifdef DEBUG
    691 	if (ccddebug & CCDB_FOLLOW)
    692 		printf("ccdstrategy(%p): unit %d\n", bp, unit);
    693 #endif
    694 	if ((cs->sc_flags & CCDF_INITED) == 0) {
    695 		bp->b_error = ENXIO;
    696 		bp->b_flags |= B_ERROR;
    697 		goto done;
    698 	}
    699 
    700 	/* If it's a nil transfer, wake up the top half now. */
    701 	if (bp->b_bcount == 0)
    702 		goto done;
    703 
    704 	lp = cs->sc_dkdev.dk_label;
    705 
    706 	/*
    707 	 * Do bounds checking and adjust transfer.  If there's an
    708 	 * error, the bounds check will flag that for us.
    709 	 */
    710 	wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
    711 	if (DISKPART(bp->b_dev) != RAW_PART)
    712 		if (bounds_check_with_label(bp, lp, wlabel) <= 0)
    713 			goto done;
    714 
    715 	bp->b_resid = bp->b_bcount;
    716 
    717 	/*
    718 	 * "Start" the unit.
    719 	 */
    720 	s = splbio();
    721 	ccdstart(cs, bp);
    722 	splx(s);
    723 	return;
    724 done:
    725 	biodone(bp);
    726 }
    727 
    728 static void
    729 ccdstart(cs, bp)
    730 	register struct ccd_softc *cs;
    731 	register struct buf *bp;
    732 {
    733 	register long bcount, rcount;
    734 	struct ccdbuf *cbp[4];
    735 	caddr_t addr;
    736 	daddr_t bn;
    737 	struct partition *pp;
    738 
    739 #ifdef DEBUG
    740 	if (ccddebug & CCDB_FOLLOW)
    741 		printf("ccdstart(%p, %p)\n", cs, bp);
    742 #endif
    743 
    744 	/* Instrumentation. */
    745 	disk_busy(&cs->sc_dkdev);
    746 
    747 	/*
    748 	 * Translate the partition-relative block number to an absolute.
    749 	 */
    750 	bn = bp->b_blkno;
    751 	if (DISKPART(bp->b_dev) != RAW_PART) {
    752 		pp = &cs->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
    753 		bn += pp->p_offset;
    754 	}
    755 
    756 	/*
    757 	 * Allocate component buffers and fire off the requests
    758 	 */
    759 	addr = bp->b_data;
    760 	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
    761 		ccdbuffer(cs, bp, bn, addr, bcount, cbp);
    762 		rcount = cbp[0]->cb_buf.b_bcount;
    763 		if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
    764 			cbp[0]->cb_buf.b_vp->v_numoutput++;
    765 		VOP_STRATEGY(&cbp[0]->cb_buf);
    766 
    767 		/*
    768 		 * Mirror requires additional write.
    769 		 */
    770 		if ((cs->sc_cflags & CCDF_MIRROR) &&
    771 		    ((cbp[0]->cb_buf.b_flags & B_READ) == 0)) {
    772 			cbp[1]->cb_buf.b_vp->v_numoutput++;
    773 			VOP_STRATEGY(&cbp[1]->cb_buf);
    774 		}
    775 
    776 		bn += btodb(rcount);
    777 		addr += rcount;
    778 	}
    779 }
    780 
    781 /*
    782  * Build a component buffer header.
    783  */
    784 static void
    785 ccdbuffer(cs, bp, bn, addr, bcount, cbpp)
    786 	register struct ccd_softc *cs;
    787 	struct buf *bp;
    788 	daddr_t bn;
    789 	caddr_t addr;
    790 	long bcount;
    791 	struct ccdbuf **cbpp;
    792 {
    793 	register struct ccdcinfo *ci, *ci2 = NULL;
    794 	register struct ccdbuf *cbp;
    795 	register daddr_t cbn, cboff;
    796 	int ccdisk;
    797 
    798 #ifdef DEBUG
    799 	if (ccddebug & CCDB_IO)
    800 		printf("ccdbuffer(%p, %p, %d, %p, %ld)\n",
    801 		       cs, bp, bn, addr, bcount);
    802 #endif
    803 	/*
    804 	 * Determine which component bn falls in.
    805 	 */
    806 	cbn = bn;
    807 	cboff = 0;
    808 
    809 	/*
    810 	 * Serially concatenated
    811 	 */
    812 	if (cs->sc_ileave == 0) {
    813 		register daddr_t sblk;
    814 
    815 		sblk = 0;
    816 		for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk];
    817 		    cbn >= sblk + ci->ci_size;
    818 		    ccdisk++, ci = &cs->sc_cinfo[ccdisk])
    819 			sblk += ci->ci_size;
    820 		cbn -= sblk;
    821 	}
    822 	/*
    823 	 * Interleaved
    824 	 */
    825 	else {
    826 		register struct ccdiinfo *ii;
    827 		int off;
    828 
    829 		cboff = cbn % cs->sc_ileave;
    830 		cbn /= cs->sc_ileave;
    831 		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
    832 			if (ii->ii_startblk > cbn)
    833 				break;
    834 		ii--;
    835 		off = cbn - ii->ii_startblk;
    836 		if (ii->ii_ndisk == 1) {
    837 			ccdisk = ii->ii_index[0];
    838 			cbn = ii->ii_startoff + off;
    839 		} else {
    840 			if (cs->sc_cflags & CCDF_MIRROR) {
    841 				ccdisk =
    842 				    ii->ii_index[off % (ii->ii_ndisk / 2)];
    843 				cbn = ii->ii_startoff +
    844 				    (off / (ii->ii_ndisk / 2));
    845 				/* Mirrored data */
    846 				ci2 =
    847 				    &cs->sc_cinfo[ccdisk + (ii->ii_ndisk / 2)];
    848 			} else {
    849 				/* Normal case. */
    850 				ccdisk = ii->ii_index[off % ii->ii_ndisk];
    851 				cbn = ii->ii_startoff + off / ii->ii_ndisk;
    852 			}
    853 		}
    854 		cbn *= cs->sc_ileave;
    855 		ci = &cs->sc_cinfo[ccdisk];
    856 	}
    857 
    858 	/*
    859 	 * Fill in the component buf structure.
    860 	 */
    861 	CCDGETBUF(cs, cbp);
    862 	cbp->cb_flags = 0;
    863 	cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
    864 	cbp->cb_buf.b_iodone = ccdiodone;
    865 	cbp->cb_buf.b_proc = bp->b_proc;
    866 	cbp->cb_buf.b_dev = ci->ci_dev;		/* XXX */
    867 	cbp->cb_buf.b_blkno = cbn + cboff;
    868 	cbp->cb_buf.b_data = addr;
    869 	cbp->cb_buf.b_vp = ci->ci_vp;
    870 	if (cs->sc_ileave == 0)
    871 		cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn);
    872 	else
    873 		cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff);
    874 	if (cbp->cb_buf.b_bcount > bcount)
    875 		cbp->cb_buf.b_bcount = bcount;
    876 
    877 	/*
    878 	 * context for ccdiodone
    879 	 */
    880 	cbp->cb_obp = bp;
    881 	cbp->cb_unit = cs->sc_unit;
    882 	cbp->cb_comp = ccdisk;
    883 
    884 	/* First buffer is dealt with. */
    885 	cbpp[0] = cbp;
    886 
    887 #ifdef DEBUG
    888 	if (ccddebug & CCDB_IO)
    889 		printf(" dev %x(u%d): cbp %p bn %d addr %p bcnt %ld\n",
    890 		    ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
    891 		    cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
    892 #endif
    893 
    894 	/*
    895 	 * Mirrors have an additional write operation that is nearly
    896 	 * identical to the first.
    897 	 */
    898 	if ((cs->sc_cflags & CCDF_MIRROR) &&
    899 	    ((cbp->cb_buf.b_flags & B_READ) == 0)) {
    900 		CCDGETBUF(cs, cbp);
    901 		*cbp = *cbpp[0];
    902 		cbp->cb_flags = CBF_MIRROR;
    903 		cbp->cb_buf.b_dev = ci2->ci_dev;	/* XXX */
    904 		cbp->cb_buf.b_vp = ci2->ci_vp;
    905 		cbp->cb_comp = ci2 - cs->sc_cinfo;
    906 		cbpp[1] = cbp;
    907 	}
    908 }
    909 
    910 static void
    911 ccdintr(cs, bp)
    912 	register struct ccd_softc *cs;
    913 	register struct buf *bp;
    914 {
    915 
    916 #ifdef DEBUG
    917 	if (ccddebug & CCDB_FOLLOW)
    918 		printf("ccdintr(%p, %p)\n", cs, bp);
    919 #endif
    920 	/*
    921 	 * Request is done for better or worse, wakeup the top half.
    922 	 */
    923 	if (bp->b_flags & B_ERROR)
    924 		bp->b_resid = bp->b_bcount;
    925 	disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid));
    926 	biodone(bp);
    927 }
    928 
    929 /*
    930  * Called at interrupt time.
    931  * Mark the component as done and if all components are done,
    932  * take a ccd interrupt.
    933  */
    934 void
    935 ccdiodone(vbp)
    936 	struct buf *vbp;
    937 {
    938 	struct ccdbuf *cbp = (struct ccdbuf *) vbp;
    939 	register struct buf *bp = cbp->cb_obp;
    940 	register int unit = cbp->cb_unit;
    941 	struct ccd_softc *cs = &ccd_softc[unit];
    942 	int count, cbflags, s;
    943 	char *comptype;
    944 
    945 	s = splbio();
    946 #ifdef DEBUG
    947 	if (ccddebug & CCDB_FOLLOW)
    948 		printf("ccdiodone(%p)\n", cbp);
    949 	if (ccddebug & CCDB_IO) {
    950 		if (cbp->cb_flags & CBF_MIRROR)
    951 			printf("ccdiodone: mirror component\n");
    952 		else
    953 			printf("ccdiodone: bp %p bcount %ld resid %ld\n",
    954 			       bp, bp->b_bcount, bp->b_resid);
    955 		printf(" dev %x(u%d), cbp %p bn %d addr %p bcnt %ld\n",
    956 		       cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
    957 		       cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
    958 		       cbp->cb_buf.b_bcount);
    959 	}
    960 #endif
    961 
    962 	if (cbp->cb_buf.b_flags & B_ERROR) {
    963 		if (cbp->cb_flags & CBF_MIRROR)
    964 			comptype = " (mirror)";
    965 		else {
    966 			bp->b_flags |= B_ERROR;
    967 			bp->b_error = cbp->cb_buf.b_error ?
    968 			    cbp->cb_buf.b_error : EIO;
    969 			comptype = "";
    970 		}
    971 
    972 		printf("%s: error %d on component %d%s\n",
    973 		       cs->sc_xname, bp->b_error, cbp->cb_comp, comptype);
    974 	}
    975 	count = cbp->cb_buf.b_bcount;
    976 	cbflags = cbp->cb_flags;
    977 	CCDPUTBUF(cs, cbp);
    978 
    979 	/*
    980 	 * If all done, "interrupt".
    981 	 *
    982 	 * Note that mirror component buffers aren't counted against
    983 	 * the original I/O buffer.
    984 	 */
    985 	if ((cbflags & CBF_MIRROR) == 0) {
    986 		bp->b_resid -= count;
    987 		if (bp->b_resid < 0)
    988 			panic("ccdiodone: count");
    989 		if (bp->b_resid == 0)
    990 			ccdintr(&ccd_softc[unit], bp);
    991 	}
    992 	splx(s);
    993 }
    994 
    995 /* ARGSUSED */
    996 int
    997 ccdread(dev, uio, flags)
    998 	dev_t dev;
    999 	struct uio *uio;
   1000 	int flags;
   1001 {
   1002 	int unit = ccdunit(dev);
   1003 	struct ccd_softc *cs;
   1004 
   1005 #ifdef DEBUG
   1006 	if (ccddebug & CCDB_FOLLOW)
   1007 		printf("ccdread(%x, %p)\n", dev, uio);
   1008 #endif
   1009 	if (unit >= numccd)
   1010 		return (ENXIO);
   1011 	cs = &ccd_softc[unit];
   1012 
   1013 	if ((cs->sc_flags & CCDF_INITED) == 0)
   1014 		return (ENXIO);
   1015 
   1016 	/*
   1017 	 * XXX: It's not clear that using minphys() is completely safe,
   1018 	 * in particular, for raw I/O.  Underlying devices might have some
   1019 	 * non-obvious limits, because of the copy to user-space.
   1020 	 */
   1021 	return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
   1022 }
   1023 
   1024 /* ARGSUSED */
   1025 int
   1026 ccdwrite(dev, uio, flags)
   1027 	dev_t dev;
   1028 	struct uio *uio;
   1029 	int flags;
   1030 {
   1031 	int unit = ccdunit(dev);
   1032 	struct ccd_softc *cs;
   1033 
   1034 #ifdef DEBUG
   1035 	if (ccddebug & CCDB_FOLLOW)
   1036 		printf("ccdwrite(%x, %p)\n", dev, uio);
   1037 #endif
   1038 	if (unit >= numccd)
   1039 		return (ENXIO);
   1040 	cs = &ccd_softc[unit];
   1041 
   1042 	if ((cs->sc_flags & CCDF_INITED) == 0)
   1043 		return (ENXIO);
   1044 
   1045 	/*
   1046 	 * XXX: It's not clear that using minphys() is completely safe,
   1047 	 * in particular, for raw I/O.  Underlying devices might have some
   1048 	 * non-obvious limits, because of the copy to user-space.
   1049 	 */
   1050 	return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
   1051 }
   1052 
   1053 int
   1054 ccdioctl(dev, cmd, data, flag, p)
   1055 	dev_t dev;
   1056 	u_long cmd;
   1057 	caddr_t data;
   1058 	int flag;
   1059 	struct proc *p;
   1060 {
   1061 	int unit = ccdunit(dev);
   1062 	int i, j, lookedup = 0, error = 0;
   1063 	int part, pmask;
   1064 	struct ccd_softc *cs;
   1065 	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
   1066 	struct ccddevice ccd;
   1067 	struct ccdbuf *cbp;
   1068 	char **cpp;
   1069 	struct vnode **vpp;
   1070 
   1071 	if (unit >= numccd)
   1072 		return (ENXIO);
   1073 	cs = &ccd_softc[unit];
   1074 
   1075 	bzero(&ccd, sizeof(ccd));
   1076 
   1077 	switch (cmd) {
   1078 	case CCDIOCSET:
   1079 		if (cs->sc_flags & CCDF_INITED)
   1080 			return (EBUSY);
   1081 
   1082 		if ((flag & FWRITE) == 0)
   1083 			return (EBADF);
   1084 
   1085 		if ((error = ccdlock(cs)) != 0)
   1086 			return (error);
   1087 
   1088 		/* Fill in some important bits. */
   1089 		ccd.ccd_unit = unit;
   1090 		ccd.ccd_interleave = ccio->ccio_ileave;
   1091 		ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
   1092 
   1093 		/*
   1094 		 * Allocate space for and copy in the array of
   1095 		 * componet pathnames and device numbers.
   1096 		 */
   1097 		cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
   1098 		    M_DEVBUF, M_WAITOK);
   1099 		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
   1100 		    M_DEVBUF, M_WAITOK);
   1101 
   1102 		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
   1103 		    ccio->ccio_ndisks * sizeof(char **));
   1104 		if (error) {
   1105 			free(vpp, M_DEVBUF);
   1106 			free(cpp, M_DEVBUF);
   1107 			ccdunlock(cs);
   1108 			return (error);
   1109 		}
   1110 
   1111 #ifdef DEBUG
   1112 		if (ccddebug & CCDB_INIT)
   1113 			for (i = 0; i < ccio->ccio_ndisks; ++i)
   1114 				printf("ccdioctl: component %d: 0x%p\n",
   1115 				    i, cpp[i]);
   1116 #endif
   1117 
   1118 		for (i = 0; i < ccio->ccio_ndisks; ++i) {
   1119 #ifdef DEBUG
   1120 			if (ccddebug & CCDB_INIT)
   1121 				printf("ccdioctl: lookedup = %d\n", lookedup);
   1122 #endif
   1123 			if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
   1124 				for (j = 0; j < lookedup; ++j)
   1125 					(void)vn_close(vpp[j], FREAD|FWRITE,
   1126 					    p->p_ucred, p);
   1127 				free(vpp, M_DEVBUF);
   1128 				free(cpp, M_DEVBUF);
   1129 				ccdunlock(cs);
   1130 				return (error);
   1131 			}
   1132 			++lookedup;
   1133 		}
   1134 		ccd.ccd_cpp = cpp;
   1135 		ccd.ccd_vpp = vpp;
   1136 		ccd.ccd_ndev = ccio->ccio_ndisks;
   1137 
   1138 		/*
   1139 		 * Initialize the ccd.  Fills in the softc for us.
   1140 		 */
   1141 		if ((error = ccdinit(&ccd, cpp, p)) != 0) {
   1142 			for (j = 0; j < lookedup; ++j)
   1143 				(void)vn_close(vpp[j], FREAD|FWRITE,
   1144 				    p->p_ucred, p);
   1145 			bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
   1146 			free(vpp, M_DEVBUF);
   1147 			free(cpp, M_DEVBUF);
   1148 			ccdunlock(cs);
   1149 			return (error);
   1150 		}
   1151 
   1152 		/*
   1153 		 * The ccd has been successfully initialized, so
   1154 		 * we can place it into the array.  Don't try to
   1155 		 * read the disklabel until the disk has been attached,
   1156 		 * because space for the disklabel is allocated
   1157 		 * in disk_attach();
   1158 		 */
   1159 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
   1160 		ccio->ccio_unit = unit;
   1161 		ccio->ccio_size = cs->sc_size;
   1162 
   1163 		/* Attach the disk. */
   1164 		cs->sc_dkdev.dk_name = cs->sc_xname;
   1165 		disk_attach(&cs->sc_dkdev);
   1166 
   1167 		/* Try and read the disklabel. */
   1168 		ccdgetdisklabel(dev);
   1169 
   1170 		ccdunlock(cs);
   1171 
   1172 		break;
   1173 
   1174 	case CCDIOCCLR:
   1175 		if ((cs->sc_flags & CCDF_INITED) == 0)
   1176 			return (ENXIO);
   1177 
   1178 		if ((flag & FWRITE) == 0)
   1179 			return (EBADF);
   1180 
   1181 		if ((error = ccdlock(cs)) != 0)
   1182 			return (error);
   1183 
   1184 		/*
   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.
   1188 		 */
   1189 		part = DISKPART(dev);
   1190 		pmask = (1 << part);
   1191 		if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
   1192 		    ((cs->sc_dkdev.dk_bopenmask & pmask) &&
   1193 		    (cs->sc_dkdev.dk_copenmask & pmask))) {
   1194 			ccdunlock(cs);
   1195 			return (EBUSY);
   1196 		}
   1197 
   1198 		/*
   1199 		 * Free ccd_softc information and clear entry.
   1200 		 */
   1201 
   1202 		/* Close the components and free their pathnames. */
   1203 		for (i = 0; i < cs->sc_nccdisks; ++i) {
   1204 			/*
   1205 			 * XXX: this close could potentially fail and
   1206 			 * cause Bad Things.  Maybe we need to force
   1207 			 * the close to happen?
   1208 			 */
   1209 #ifdef DEBUG
   1210 			if (ccddebug & CCDB_VNODE)
   1211 				vprint("CCDIOCCLR: vnode info",
   1212 				    cs->sc_cinfo[i].ci_vp);
   1213 #endif
   1214 			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
   1215 			    p->p_ucred, p);
   1216 			free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
   1217 		}
   1218 
   1219 		/* Free component buffer freelist. */
   1220 		while ((cbp = cs->sc_freelist.lh_first) != NULL) {
   1221 			LIST_REMOVE(cbp, cb_list);
   1222 			FREE(cbp, M_DEVBUF);
   1223 		}
   1224 
   1225 		/* Free interleave index. */
   1226 		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
   1227 			free(cs->sc_itable[i].ii_index, M_DEVBUF);
   1228 
   1229 		/* Free component info and interleave table. */
   1230 		free(cs->sc_cinfo, M_DEVBUF);
   1231 		free(cs->sc_itable, M_DEVBUF);
   1232 		cs->sc_flags &= ~CCDF_INITED;
   1233 
   1234 		/*
   1235 		 * Free ccddevice information and clear entry.
   1236 		 */
   1237 		free(ccddevs[unit].ccd_cpp, M_DEVBUF);
   1238 		free(ccddevs[unit].ccd_vpp, M_DEVBUF);
   1239 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
   1240 
   1241 		/* Detatch the disk. */
   1242 		disk_detach(&cs->sc_dkdev);
   1243 
   1244 		ccdunlock(cs);
   1245 
   1246 		break;
   1247 
   1248 	case DIOCGDINFO:
   1249 		if ((cs->sc_flags & CCDF_INITED) == 0)
   1250 			return (ENXIO);
   1251 
   1252 		*(struct disklabel *)data = *(cs->sc_dkdev.dk_label);
   1253 		break;
   1254 
   1255 	case DIOCGPART:
   1256 		if ((cs->sc_flags & CCDF_INITED) == 0)
   1257 			return (ENXIO);
   1258 
   1259 		((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label;
   1260 		((struct partinfo *)data)->part =
   1261 		    &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
   1262 		break;
   1263 
   1264 	case DIOCWDINFO:
   1265 	case DIOCSDINFO:
   1266 		if ((cs->sc_flags & CCDF_INITED) == 0)
   1267 			return (ENXIO);
   1268 
   1269 		if ((flag & FWRITE) == 0)
   1270 			return (EBADF);
   1271 
   1272 		if ((error = ccdlock(cs)) != 0)
   1273 			return (error);
   1274 
   1275 		cs->sc_flags |= CCDF_LABELLING;
   1276 
   1277 		error = setdisklabel(cs->sc_dkdev.dk_label,
   1278 		    (struct disklabel *)data, 0, cs->sc_dkdev.dk_cpulabel);
   1279 		if (error == 0) {
   1280 			if (cmd == DIOCWDINFO)
   1281 				error = writedisklabel(CCDLABELDEV(dev),
   1282 				    ccdstrategy, cs->sc_dkdev.dk_label,
   1283 				    cs->sc_dkdev.dk_cpulabel);
   1284 		}
   1285 
   1286 		cs->sc_flags &= ~CCDF_LABELLING;
   1287 
   1288 		ccdunlock(cs);
   1289 
   1290 		if (error)
   1291 			return (error);
   1292 		break;
   1293 
   1294 	case DIOCWLABEL:
   1295 		if ((cs->sc_flags & CCDF_INITED) == 0)
   1296 			return (ENXIO);
   1297 
   1298 		if ((flag & FWRITE) == 0)
   1299 			return (EBADF);
   1300 		if (*(int *)data != 0)
   1301 			cs->sc_flags |= CCDF_WLABEL;
   1302 		else
   1303 			cs->sc_flags &= ~CCDF_WLABEL;
   1304 		break;
   1305 
   1306 	default:
   1307 		return (ENOTTY);
   1308 	}
   1309 
   1310 	return (0);
   1311 }
   1312 
   1313 int
   1314 ccdsize(dev)
   1315 	dev_t dev;
   1316 {
   1317 	struct ccd_softc *cs;
   1318 	struct disklabel *lp;
   1319 	int part, unit, omask, size;
   1320 
   1321 	unit = ccdunit(dev);
   1322 	if (unit >= numccd)
   1323 		return (-1);
   1324 	cs = &ccd_softc[unit];
   1325 
   1326 	if ((cs->sc_flags & CCDF_INITED) == 0)
   1327 		return (-1);
   1328 
   1329 	part = DISKPART(dev);
   1330 	omask = cs->sc_dkdev.dk_openmask & (1 << part);
   1331 	lp = cs->sc_dkdev.dk_label;
   1332 
   1333 	if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curproc))
   1334 		return (-1);
   1335 
   1336 	if (lp->d_partitions[part].p_fstype != FS_SWAP)
   1337 		size = -1;
   1338 	else
   1339 		size = lp->d_partitions[part].p_size *
   1340 		    (lp->d_secsize / DEV_BSIZE);
   1341 
   1342 	if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curproc))
   1343 		return (-1);
   1344 
   1345 	return (size);
   1346 }
   1347 
   1348 int
   1349 ccddump(dev, blkno, va, size)
   1350 	dev_t dev;
   1351 	daddr_t blkno;
   1352 	caddr_t va;
   1353 	size_t size;
   1354 {
   1355 
   1356 	/* Not implemented. */
   1357 	return ENXIO;
   1358 }
   1359 
   1360 /*
   1361  * Lookup the provided name in the filesystem.  If the file exists,
   1362  * is a valid block device, and isn't being used by anyone else,
   1363  * set *vpp to the file's vnode.
   1364  */
   1365 static int
   1366 ccdlookup(path, p, vpp)
   1367 	char *path;
   1368 	struct proc *p;
   1369 	struct vnode **vpp;	/* result */
   1370 {
   1371 	struct nameidata nd;
   1372 	struct vnode *vp;
   1373 	struct vattr va;
   1374 	int error;
   1375 
   1376 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
   1377 	if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
   1378 #ifdef DEBUG
   1379 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
   1380 			printf("ccdlookup: vn_open error = %d\n", error);
   1381 #endif
   1382 		return (error);
   1383 	}
   1384 	vp = nd.ni_vp;
   1385 
   1386 	if (vp->v_usecount > 1) {
   1387 		VOP_UNLOCK(vp);
   1388 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
   1389 		return (EBUSY);
   1390 	}
   1391 
   1392 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
   1393 #ifdef DEBUG
   1394 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
   1395 			printf("ccdlookup: getattr error = %d\n", error);
   1396 #endif
   1397 		VOP_UNLOCK(vp);
   1398 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
   1399 		return (error);
   1400 	}
   1401 
   1402 	/* XXX: eventually we should handle VREG, too. */
   1403 	if (va.va_type != VBLK) {
   1404 		VOP_UNLOCK(vp);
   1405 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
   1406 		return (ENOTBLK);
   1407 	}
   1408 
   1409 #ifdef DEBUG
   1410 	if (ccddebug & CCDB_VNODE)
   1411 		vprint("ccdlookup: vnode info", vp);
   1412 #endif
   1413 
   1414 	VOP_UNLOCK(vp);
   1415 	*vpp = vp;
   1416 	return (0);
   1417 }
   1418 
   1419 /*
   1420  * Read the disklabel from the ccd.  If one is not present, fake one
   1421  * up.
   1422  */
   1423 static void
   1424 ccdgetdisklabel(dev)
   1425 	dev_t dev;
   1426 {
   1427 	int unit = ccdunit(dev);
   1428 	struct ccd_softc *cs = &ccd_softc[unit];
   1429 	char *errstring;
   1430 	struct disklabel *lp = cs->sc_dkdev.dk_label;
   1431 	struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel;
   1432 	struct ccdgeom *ccg = &cs->sc_geom;
   1433 
   1434 	bzero(lp, sizeof(*lp));
   1435 	bzero(clp, sizeof(*clp));
   1436 
   1437 	lp->d_secperunit = cs->sc_size;
   1438 	lp->d_secsize = ccg->ccg_secsize;
   1439 	lp->d_nsectors = ccg->ccg_nsectors;
   1440 	lp->d_ntracks = ccg->ccg_ntracks;
   1441 	lp->d_ncylinders = ccg->ccg_ncylinders;
   1442 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
   1443 
   1444 	strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
   1445 	lp->d_type = DTYPE_CCD;
   1446 	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
   1447 	lp->d_rpm = 3600;
   1448 	lp->d_interleave = 1;
   1449 	lp->d_flags = 0;
   1450 
   1451 	lp->d_partitions[RAW_PART].p_offset = 0;
   1452 	lp->d_partitions[RAW_PART].p_size = cs->sc_size;
   1453 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
   1454 	lp->d_npartitions = RAW_PART + 1;
   1455 
   1456 	lp->d_magic = DISKMAGIC;
   1457 	lp->d_magic2 = DISKMAGIC;
   1458 	lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label);
   1459 
   1460 	/*
   1461 	 * Call the generic disklabel extraction routine.
   1462 	 */
   1463 	errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
   1464 	    cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel);
   1465 	if (errstring)
   1466 		ccdmakedisklabel(cs);
   1467 
   1468 #ifdef DEBUG
   1469 	/* It's actually extremely common to have unlabeled ccds. */
   1470 	if (ccddebug & CCDB_LABEL)
   1471 		if (errstring != NULL)
   1472 			printf("%s: %s\n", cs->sc_xname, errstring);
   1473 #endif
   1474 }
   1475 
   1476 /*
   1477  * Take care of things one might want to take care of in the event
   1478  * that a disklabel isn't present.
   1479  */
   1480 static void
   1481 ccdmakedisklabel(cs)
   1482 	struct ccd_softc *cs;
   1483 {
   1484 	struct disklabel *lp = cs->sc_dkdev.dk_label;
   1485 
   1486 	/*
   1487 	 * For historical reasons, if there's no disklabel present
   1488 	 * the raw partition must be marked FS_BSDFFS.
   1489 	 */
   1490 	lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
   1491 
   1492 	strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
   1493 }
   1494 
   1495 /*
   1496  * Wait interruptibly for an exclusive lock.
   1497  *
   1498  * XXX
   1499  * Several drivers do this; it should be abstracted and made MP-safe.
   1500  */
   1501 static int
   1502 ccdlock(cs)
   1503 	struct ccd_softc *cs;
   1504 {
   1505 	int error;
   1506 
   1507 	while ((cs->sc_flags & CCDF_LOCKED) != 0) {
   1508 		cs->sc_flags |= CCDF_WANTED;
   1509 		if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
   1510 			return (error);
   1511 	}
   1512 	cs->sc_flags |= CCDF_LOCKED;
   1513 	return (0);
   1514 }
   1515 
   1516 /*
   1517  * Unlock and wake up any waiters.
   1518  */
   1519 static void
   1520 ccdunlock(cs)
   1521 	struct ccd_softc *cs;
   1522 {
   1523 
   1524 	cs->sc_flags &= ~CCDF_LOCKED;
   1525 	if ((cs->sc_flags & CCDF_WANTED) != 0) {
   1526 		cs->sc_flags &= ~CCDF_WANTED;
   1527 		wakeup(cs);
   1528 	}
   1529 }
   1530 
   1531 #ifdef DEBUG
   1532 static void
   1533 printiinfo(ii)
   1534 	struct ccdiinfo *ii;
   1535 {
   1536 	register int ix, i;
   1537 
   1538 	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
   1539 		printf(" itab[%d]: #dk %d sblk %d soff %d",
   1540 		    ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
   1541 		for (i = 0; i < ii->ii_ndisk; i++)
   1542 			printf(" %d", ii->ii_index[i]);
   1543 		printf("\n");
   1544 	}
   1545 }
   1546 #endif
   1547