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