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