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