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