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