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