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