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