xref: /freebsd/sys/geom/geom_ccd.c (revision 4a0f765fbf09711e612e86fce8bb09ec43f482d9)
1 /* $Id$ */
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  	cbp->cb_buf.b_bufsize = cbp->cb_buf.b_bcount;
914 
915 	/*
916 	 * context for ccdiodone
917 	 */
918 	cbp->cb_obp = bp;
919 	cbp->cb_unit = cs - ccd_softc;
920 	cbp->cb_comp = ci - cs->sc_cinfo;
921 
922 #ifdef DEBUG
923 	if (ccddebug & CCDB_IO)
924 		printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
925 		       ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
926 		       cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
927 #endif
928 	cb[0] = cbp;
929 	if (cs->sc_cflags & CCDF_MIRROR &&
930 	    (cbp->cb_buf.b_flags & B_READ) == 0) {
931 		/* mirror, start one more write */
932 		cbp = getccdbuf();
933 		*cbp = *cb[0];
934 		cbp->cb_buf.b_dev = ci2->ci_dev;
935 		cbp->cb_buf.b_vp = ci2->ci_vp;
936 		cbp->cb_comp = ci2 - cs->sc_cinfo;
937 		cb[1] = cbp;
938 		/* link together the ccdbuf's and clear "mirror done" flag */
939 		cb[0]->cb_mirror = cb[1];
940 		cb[1]->cb_mirror = cb[0];
941 		cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
942 		cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
943 	}
944 }
945 
946 static void
947 ccdintr(cs, bp)
948 	register struct ccd_softc *cs;
949 	register struct buf *bp;
950 {
951 
952 #ifdef DEBUG
953 	if (ccddebug & CCDB_FOLLOW)
954 		printf("ccdintr(%x, %x)\n", cs, bp);
955 #endif
956 	/*
957 	 * Request is done for better or worse, wakeup the top half.
958 	 */
959 #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
960 	--cs->sc_nactive;
961 #ifdef DIAGNOSTIC
962 	if (cs->sc_nactive < 0)
963 		panic("ccdintr: ccd%d: sc_nactive < 0", cs->sc_unit);
964 #endif
965 
966 	if (cs->sc_nactive == 0 && cs->sc_dk >= 0)
967 		dk_busy &= ~(1 << cs->sc_dk);
968 #endif
969 	if (bp->b_flags & B_ERROR)
970 		bp->b_resid = bp->b_bcount;
971 	biodone(bp);
972 }
973 
974 /*
975  * Called at interrupt time.
976  * Mark the component as done and if all components are done,
977  * take a ccd interrupt.
978  */
979 void
980 ccdiodone(cbp)
981 	struct ccdbuf *cbp;
982 {
983 	register struct buf *bp = cbp->cb_obp;
984 	register int unit = cbp->cb_unit;
985 	int count, s;
986 
987 	s = splbio();
988 #ifdef DEBUG
989 	if (ccddebug & CCDB_FOLLOW)
990 		printf("ccdiodone(%x)\n", cbp);
991 	if (ccddebug & CCDB_IO) {
992 		printf("ccdiodone: bp %x bcount %d resid %d\n",
993 		       bp, bp->b_bcount, bp->b_resid);
994 		printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
995 		       cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
996 		       cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
997 		       cbp->cb_buf.b_bcount);
998 	}
999 #endif
1000 
1001 	if (cbp->cb_buf.b_flags & B_ERROR) {
1002 		bp->b_flags |= B_ERROR;
1003 		bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;
1004 #ifdef DEBUG
1005 		printf("ccd%d: error %d on component %d\n",
1006 		       unit, bp->b_error, cbp->cb_comp);
1007 #endif
1008 	}
1009 
1010 	if (ccd_softc[unit].sc_cflags & CCDF_MIRROR &&
1011 	    (cbp->cb_buf.b_flags & B_READ) == 0)
1012 		if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1013 			/* I'm done before my counterpart, so just set
1014 			   partner's flag and return */
1015 			cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1016 			putccdbuf(cbp);
1017 			splx(s);
1018 			return;
1019 		}
1020 
1021 	count = cbp->cb_buf.b_bcount;
1022 	putccdbuf(cbp);
1023 
1024 	/*
1025 	 * If all done, "interrupt".
1026 	 */
1027 	bp->b_resid -= count;
1028 	if (bp->b_resid < 0)
1029 		panic("ccdiodone: count");
1030 	if (bp->b_resid == 0)
1031 		ccdintr(&ccd_softc[unit], bp);
1032 	splx(s);
1033 }
1034 
1035 int
1036 ccdioctl(dev, cmd, data, flag, p)
1037 	dev_t dev;
1038 	int cmd;
1039 	caddr_t data;
1040 	int flag;
1041 	struct proc *p;
1042 {
1043 	int unit = ccdunit(dev);
1044 	int i, j, lookedup = 0, error = 0;
1045 	int part, pmask, s;
1046 	struct ccd_softc *cs;
1047 	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1048 	struct ccddevice ccd;
1049 	char **cpp;
1050 	struct vnode **vpp;
1051 #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
1052 	extern int dkn;
1053 #endif
1054 
1055 	if (unit >= numccd)
1056 		return (ENXIO);
1057 	cs = &ccd_softc[unit];
1058 
1059 	bzero(&ccd, sizeof(ccd));
1060 
1061 	switch (cmd) {
1062 	case CCDIOCSET:
1063 		if (cs->sc_flags & CCDF_INITED)
1064 			return (EBUSY);
1065 
1066 		if ((flag & FWRITE) == 0)
1067 			return (EBADF);
1068 
1069 		if (error = ccdlock(cs))
1070 			return (error);
1071 
1072 		/* Fill in some important bits. */
1073 		ccd.ccd_unit = unit;
1074 		ccd.ccd_interleave = ccio->ccio_ileave;
1075 		if (ccd.ccd_interleave == 0 &&
1076 		    ((ccio->ccio_flags & CCDF_MIRROR) ||
1077 		     (ccio->ccio_flags & CCDF_PARITY))) {
1078 			printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1079 			ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1080 		}
1081 		if ((ccio->ccio_flags & CCDF_MIRROR) &&
1082 		    (ccio->ccio_flags & CCDF_PARITY)) {
1083 			printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
1084 			ccio->ccio_flags &= ~CCDF_PARITY;
1085 		}
1086 		if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
1087 		    !(ccio->ccio_flags & CCDF_UNIFORM)) {
1088 			printf("ccd%d: mirror/parity forces uniform flag\n",
1089 			       unit);
1090 			ccio->ccio_flags |= CCDF_UNIFORM;
1091 		}
1092 		ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1093 
1094 		/*
1095 		 * Allocate space for and copy in the array of
1096 		 * componet pathnames and device numbers.
1097 		 */
1098 		cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1099 		    M_DEVBUF, M_WAITOK);
1100 		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1101 		    M_DEVBUF, M_WAITOK);
1102 
1103 		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1104 		    ccio->ccio_ndisks * sizeof(char **));
1105 		if (error) {
1106 			free(vpp, M_DEVBUF);
1107 			free(cpp, M_DEVBUF);
1108 			ccdunlock(cs);
1109 			return (error);
1110 		}
1111 
1112 #ifdef DEBUG
1113 		if (ccddebug & CCDB_INIT)
1114 			for (i = 0; i < ccio->ccio_ndisks; ++i)
1115 				printf("ccdioctl: component %d: 0x%x\n",
1116 				    i, cpp[i]);
1117 #endif
1118 
1119 		for (i = 0; i < ccio->ccio_ndisks; ++i) {
1120 #ifdef DEBUG
1121 			if (ccddebug & CCDB_INIT)
1122 				printf("ccdioctl: lookedup = %d\n", lookedup);
1123 #endif
1124 			if (error = ccdlookup(cpp[i], p, &vpp[i])) {
1125 				for (j = 0; j < lookedup; ++j)
1126 					(void)vn_close(vpp[j], FREAD|FWRITE,
1127 					    p->p_ucred, p);
1128 				free(vpp, M_DEVBUF);
1129 				free(cpp, M_DEVBUF);
1130 				ccdunlock(cs);
1131 				return (error);
1132 			}
1133 			++lookedup;
1134 		}
1135 		ccd.ccd_cpp = cpp;
1136 		ccd.ccd_vpp = vpp;
1137 		ccd.ccd_ndev = ccio->ccio_ndisks;
1138 
1139 #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
1140 		/*
1141 		 * Assign disk index first so that init routine
1142 		 * can use it (saves having the driver drag around
1143 		 * the ccddevice pointer just to set up the dk_*
1144 		 * info in the open routine).
1145 		 */
1146 		if (dkn < DK_NDRIVE)
1147 			ccd.ccd_dk = dkn++;
1148 		else
1149 			ccd.ccd_dk = -1;
1150 #endif
1151 
1152 		/*
1153 		 * Initialize the ccd.  Fills in the softc for us.
1154 		 */
1155 		if (error = ccdinit(&ccd, cpp, p)) {
1156 #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
1157 			if (ccd.ccd_dk >= 0)
1158 				--dkn;
1159 #endif
1160 			for (j = 0; j < lookedup; ++j)
1161 				(void)vn_close(vpp[j], FREAD|FWRITE,
1162 				    p->p_ucred, p);
1163 			bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1164 			free(vpp, M_DEVBUF);
1165 			free(cpp, M_DEVBUF);
1166 			ccdunlock(cs);
1167 			return (error);
1168 		}
1169 
1170 		/*
1171 		 * The ccd has been successfully initialized, so
1172 		 * we can place it into the array and read the disklabel.
1173 		 */
1174 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1175 		ccio->ccio_unit = unit;
1176 		ccio->ccio_size = cs->sc_size;
1177 		ccdgetdisklabel(dev);
1178 
1179 		ccdunlock(cs);
1180 
1181 		break;
1182 
1183 	case CCDIOCCLR:
1184 		if ((cs->sc_flags & CCDF_INITED) == 0)
1185 			return (ENXIO);
1186 
1187 		if ((flag & FWRITE) == 0)
1188 			return (EBADF);
1189 
1190 		if (error = ccdlock(cs))
1191 			return (error);
1192 
1193 		/*
1194 		 * Don't unconfigure if any other partitions are open
1195 		 * or if both the character and block flavors of this
1196 		 * partition are open.
1197 		 */
1198 		part = ccdpart(dev);
1199 		pmask = (1 << part);
1200 		if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
1201 		    ((cs->sc_dkdev.dk_bopenmask & pmask) &&
1202 		    (cs->sc_dkdev.dk_copenmask & pmask))) {
1203 			ccdunlock(cs);
1204 			return (EBUSY);
1205 		}
1206 
1207 		/*
1208 		 * Free ccd_softc information and clear entry.
1209 		 */
1210 
1211 		/* Close the components and free their pathnames. */
1212 		for (i = 0; i < cs->sc_nccdisks; ++i) {
1213 			/*
1214 			 * XXX: this close could potentially fail and
1215 			 * cause Bad Things.  Maybe we need to force
1216 			 * the close to happen?
1217 			 */
1218 #ifdef DEBUG
1219 			if (ccddebug & CCDB_VNODE)
1220 				vprint("CCDIOCCLR: vnode info",
1221 				    cs->sc_cinfo[i].ci_vp);
1222 #endif
1223 			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1224 			    p->p_ucred, p);
1225 			free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1226 		}
1227 
1228 		/* Free interleave index. */
1229 		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1230 			free(cs->sc_itable[i].ii_index, M_DEVBUF);
1231 
1232 		/* Free component info and interleave table. */
1233 		free(cs->sc_cinfo, M_DEVBUF);
1234 		free(cs->sc_itable, M_DEVBUF);
1235 		cs->sc_flags &= ~CCDF_INITED;
1236 
1237 		/*
1238 		 * Free ccddevice information and clear entry.
1239 		 */
1240 		free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1241 		free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1242 		ccd.ccd_dk = -1;
1243 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1244 
1245 		/* This must be atomic. */
1246 		s = splhigh();
1247 		ccdunlock(cs);
1248 		bzero(cs, sizeof(struct ccd_softc));
1249 		splx(s);
1250 
1251 		break;
1252 
1253 	case DIOCGDINFO:
1254 		if ((cs->sc_flags & CCDF_INITED) == 0)
1255 			return (ENXIO);
1256 
1257 		*(struct disklabel *)data = cs->sc_dkdev.dk_label;
1258 		break;
1259 
1260 	case DIOCGPART:
1261 		if ((cs->sc_flags & CCDF_INITED) == 0)
1262 			return (ENXIO);
1263 
1264 		((struct partinfo *)data)->disklab = &cs->sc_dkdev.dk_label;
1265 		((struct partinfo *)data)->part =
1266 		    &cs->sc_dkdev.dk_label.d_partitions[ccdpart(dev)];
1267 		break;
1268 
1269 	case DIOCWDINFO:
1270 	case DIOCSDINFO:
1271 		if ((cs->sc_flags & CCDF_INITED) == 0)
1272 			return (ENXIO);
1273 
1274 		if ((flag & FWRITE) == 0)
1275 			return (EBADF);
1276 
1277 		if (error = ccdlock(cs))
1278 			return (error);
1279 
1280 		cs->sc_flags |= CCDF_LABELLING;
1281 
1282 		error = setdisklabel(&cs->sc_dkdev.dk_label,
1283 		    (struct disklabel *)data, 0);
1284 				/*, &cs->sc_dkdev.dk_cpulabel); */
1285 		if (error == 0) {
1286 			if (cmd == DIOCWDINFO)
1287 				error = writedisklabel(CCDLABELDEV(dev),
1288 				    ccdstrategy, &cs->sc_dkdev.dk_label);
1289 				/*
1290 				    &cs->sc_dkdev.dk_cpulabel); */
1291 		}
1292 
1293 		cs->sc_flags &= ~CCDF_LABELLING;
1294 
1295 		ccdunlock(cs);
1296 
1297 		if (error)
1298 			return (error);
1299 		break;
1300 
1301 	case DIOCWLABEL:
1302 		if ((cs->sc_flags & CCDF_INITED) == 0)
1303 			return (ENXIO);
1304 
1305 		if ((flag & FWRITE) == 0)
1306 			return (EBADF);
1307 		if (*(int *)data != 0)
1308 			cs->sc_flags |= CCDF_WLABEL;
1309 		else
1310 			cs->sc_flags &= ~CCDF_WLABEL;
1311 		break;
1312 
1313 	default:
1314 		return (ENOTTY);
1315 	}
1316 
1317 	return (0);
1318 }
1319 
1320 int
1321 ccdsize(dev)
1322 	dev_t dev;
1323 {
1324 	struct ccd_softc *cs;
1325 	int part, size;
1326 
1327 	if (ccdopen(dev, 0, S_IFBLK, curproc))
1328 		return (-1);
1329 
1330 	cs = &ccd_softc[ccdunit(dev)];
1331 	part = ccdpart(dev);
1332 
1333 	if ((cs->sc_flags & CCDF_INITED) == 0)
1334 		return (-1);
1335 
1336 	if (cs->sc_dkdev.dk_label.d_partitions[part].p_fstype != FS_SWAP)
1337 		size = -1;
1338 	else
1339 		size = cs->sc_dkdev.dk_label.d_partitions[part].p_size;
1340 
1341 	if (ccdclose(dev, 0, S_IFBLK, curproc))
1342 		return (-1);
1343 
1344 	return (size);
1345 }
1346 
1347 int
1348 ccddump(dev)
1349 	dev_t dev;
1350 {
1351 
1352 	/* Not implemented. */
1353 	return ENXIO;
1354 }
1355 
1356 /*
1357  * Lookup the provided name in the filesystem.  If the file exists,
1358  * is a valid block device, and isn't being used by anyone else,
1359  * set *vpp to the file's vnode.
1360  */
1361 static int
1362 ccdlookup(path, p, vpp)
1363 	char *path;
1364 	struct proc *p;
1365 	struct vnode **vpp;	/* result */
1366 {
1367 	struct nameidata nd;
1368 	struct vnode *vp;
1369 	struct vattr va;
1370 	int error;
1371 
1372 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1373 	if (error = vn_open(&nd, FREAD|FWRITE, 0)) {
1374 #ifdef DEBUG
1375 		if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1376 			printf("ccdlookup: vn_open error = %d\n", error);
1377 #endif
1378 		return (error);
1379 	}
1380 	vp = nd.ni_vp;
1381 
1382 	if (vp->v_usecount > 1) {
1383 		VOP_UNLOCK(vp, 0, p);
1384 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1385 		return (EBUSY);
1386 	}
1387 
1388 	if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) {
1389 #ifdef DEBUG
1390 		if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1391 			printf("ccdlookup: getattr error = %d\n", error);
1392 #endif
1393 		VOP_UNLOCK(vp, 0, p);
1394 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1395 		return (error);
1396 	}
1397 
1398 	/* XXX: eventually we should handle VREG, too. */
1399 	if (va.va_type != VBLK) {
1400 		VOP_UNLOCK(vp, 0, p);
1401 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1402 		return (ENOTBLK);
1403 	}
1404 
1405 #ifdef DEBUG
1406 	if (ccddebug & CCDB_VNODE)
1407 		vprint("ccdlookup: vnode info", vp);
1408 #endif
1409 
1410 	VOP_UNLOCK(vp, 0, p);
1411 	*vpp = vp;
1412 	return (0);
1413 }
1414 
1415 /*
1416  * Read the disklabel from the ccd.  If one is not present, fake one
1417  * up.
1418  */
1419 static void
1420 ccdgetdisklabel(dev)
1421 	dev_t dev;
1422 {
1423 	int unit = ccdunit(dev);
1424 	struct ccd_softc *cs = &ccd_softc[unit];
1425 	char *errstring;
1426 	struct disklabel *lp = &cs->sc_dkdev.dk_label;
1427 	struct ccdgeom *ccg = &cs->sc_geom;
1428 
1429 	bzero(lp, sizeof(*lp));
1430 
1431 	lp->d_secperunit = cs->sc_size;
1432 	lp->d_secsize = ccg->ccg_secsize;
1433 	lp->d_nsectors = ccg->ccg_nsectors;
1434 	lp->d_ntracks = ccg->ccg_ntracks;
1435 	lp->d_ncylinders = ccg->ccg_ncylinders;
1436 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1437 
1438 	strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1439 	lp->d_type = DTYPE_CCD;
1440 	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1441 	lp->d_rpm = 3600;
1442 	lp->d_interleave = 1;
1443 	lp->d_flags = 0;
1444 
1445 	lp->d_partitions[RAW_PART].p_offset = 0;
1446 	lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1447 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1448 	lp->d_npartitions = RAW_PART + 1;
1449 
1450 	lp->d_bbsize = BBSIZE;				/* XXX */
1451 	lp->d_sbsize = SBSIZE;				/* XXX */
1452 
1453 	lp->d_magic = DISKMAGIC;
1454 	lp->d_magic2 = DISKMAGIC;
1455 	lp->d_checksum = dkcksum(&cs->sc_dkdev.dk_label);
1456 
1457 	/*
1458 	 * Call the generic disklabel extraction routine.
1459 	 */
1460 	if (errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1461 	    &cs->sc_dkdev.dk_label))
1462 		ccdmakedisklabel(cs);
1463 
1464 #ifdef DEBUG
1465 	/* It's actually extremely common to have unlabeled ccds. */
1466 	if (ccddebug & CCDB_LABEL)
1467 		if (errstring != NULL)
1468 			printf("ccd%d: %s\n", unit, errstring);
1469 #endif
1470 }
1471 
1472 /*
1473  * Take care of things one might want to take care of in the event
1474  * that a disklabel isn't present.
1475  */
1476 static void
1477 ccdmakedisklabel(cs)
1478 	struct ccd_softc *cs;
1479 {
1480 	struct disklabel *lp = &cs->sc_dkdev.dk_label;
1481 
1482 	/*
1483 	 * For historical reasons, if there's no disklabel present
1484 	 * the raw partition must be marked FS_BSDFFS.
1485 	 */
1486 	lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1487 
1488 	strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1489 }
1490 
1491 /*
1492  * Wait interruptibly for an exclusive lock.
1493  *
1494  * XXX
1495  * Several drivers do this; it should be abstracted and made MP-safe.
1496  */
1497 static int
1498 ccdlock(cs)
1499 	struct ccd_softc *cs;
1500 {
1501 	int error;
1502 
1503 	while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1504 		cs->sc_flags |= CCDF_WANTED;
1505 		if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1506 			return (error);
1507 	}
1508 	cs->sc_flags |= CCDF_LOCKED;
1509 	return (0);
1510 }
1511 
1512 /*
1513  * Unlock and wake up any waiters.
1514  */
1515 static void
1516 ccdunlock(cs)
1517 	struct ccd_softc *cs;
1518 {
1519 
1520 	cs->sc_flags &= ~CCDF_LOCKED;
1521 	if ((cs->sc_flags & CCDF_WANTED) != 0) {
1522 		cs->sc_flags &= ~CCDF_WANTED;
1523 		wakeup(cs);
1524 	}
1525 }
1526 
1527 #ifdef DEBUG
1528 static void
1529 printiinfo(ii)
1530 	struct ccdiinfo *ii;
1531 {
1532 	register int ix, i;
1533 
1534 	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1535 		printf(" itab[%d]: #dk %d sblk %d soff %d",
1536 		       ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1537 		for (i = 0; i < ii->ii_ndisk; i++)
1538 			printf(" %d", ii->ii_index[i]);
1539 		printf("\n");
1540 	}
1541 }
1542 #endif
1543 
1544 #endif /* NCCD > 0 */
1545 
1546 /* Local Variables: */
1547 /* c-argdecl-indent: 8 */
1548 /* c-continued-statement-offset: 8 */
1549 /* c-indent-level: 8 */
1550 /* End: */
1551