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