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