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