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