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