xref: /netbsd-src/sys/dev/ccd.c (revision f5d3fbbc6ff4a77159fb268d247bd94cb7d7e332)
1 /*	$NetBSD: ccd.c,v 1.45 1997/10/09 08:11:07 jtc Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 1997 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 		if (dpart.part->p_fstype == FS_BSDFFS) {
335 			maxsecsize =
336 			    ((dpart.disklab->d_secsize > maxsecsize) ?
337 			    dpart.disklab->d_secsize : maxsecsize);
338 			size = dpart.part->p_size;
339 		} else {
340 #ifdef DEBUG
341 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
342 				printf("%s: %s: incorrect partition type\n",
343 				    cs->sc_xname, ci->ci_path);
344 #endif
345 			free(ci->ci_path, M_DEVBUF);
346 			free(cs->sc_cinfo, M_DEVBUF);
347 			return (EFTYPE);
348 		}
349 
350 		/*
351 		 * Calculate the size, truncating to an interleave
352 		 * boundary if necessary.
353 		 */
354 		if (cs->sc_ileave > 1)
355 			size -= size % cs->sc_ileave;
356 
357 		if (size == 0) {
358 #ifdef DEBUG
359 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
360 				printf("%s: %s: size == 0\n",
361 				    cs->sc_xname, ci->ci_path);
362 #endif
363 			free(ci->ci_path, M_DEVBUF);
364 			free(cs->sc_cinfo, M_DEVBUF);
365 			return (ENODEV);
366 		}
367 
368 		if (minsize == 0 || size < minsize)
369 			minsize = size;
370 		ci->ci_size = size;
371 		cs->sc_size += size;
372 	}
373 
374 	/*
375 	 * Don't allow the interleave to be smaller than
376 	 * the biggest component sector.
377 	 */
378 	if ((cs->sc_ileave > 0) &&
379 	    (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
380 #ifdef DEBUG
381 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
382 			printf("%s: interleave must be at least %d\n",
383 			    cs->sc_xname, (maxsecsize / DEV_BSIZE));
384 #endif
385 		free(ci->ci_path, M_DEVBUF);
386 		free(cs->sc_cinfo, M_DEVBUF);
387 		return (EINVAL);
388 	}
389 
390 	/*
391 	 * Mirroring support requires uniform interleave and
392 	 * and even number of components.
393 	 */
394 	if (ccd->ccd_flags & CCDF_MIRROR) {
395 		ccd->ccd_flags |= CCDF_UNIFORM;
396 		if (cs->sc_ileave == 0) {
397 #ifdef DEBUG
398 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
399 			printf("%s: mirroring requires interleave\n",
400 			    cs->sc_xname);
401 #endif
402 			free(ci->ci_path, M_DEVBUF);
403 			free(cs->sc_cinfo, M_DEVBUF);
404 			return (EINVAL);
405 		}
406 		if (cs->sc_nccdisks % 2) {
407 #ifdef DEBUG
408 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
409 			printf("%s: mirroring requires even # of components\n",
410 			    cs->sc_xname);
411 #endif
412 			free(ci->ci_path, M_DEVBUF);
413 			free(cs->sc_cinfo, M_DEVBUF);
414 			return (EINVAL);
415 		}
416 	}
417 
418 	/*
419 	 * If uniform interleave is desired set all sizes to that of
420 	 * the smallest component.
421 	 */
422 	if (ccd->ccd_flags & CCDF_UNIFORM) {
423 		for (ci = cs->sc_cinfo;
424 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
425 			ci->ci_size = minsize;
426 
427 		if (ccd->ccd_flags & CCDF_MIRROR)
428 			cs->sc_size = (cs->sc_nccdisks / 2) * minsize;
429 		else
430 			cs->sc_size = cs->sc_nccdisks * minsize;
431 	}
432 
433 	/*
434 	 * Construct the interleave table.
435 	 */
436 	ccdinterleave(cs, ccd->ccd_unit);
437 
438 	/*
439 	 * Create pseudo-geometry based on 1MB cylinders.  It's
440 	 * pretty close.
441 	 */
442 	ccg->ccg_secsize = DEV_BSIZE;
443 	ccg->ccg_ntracks = 1;
444 	ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
445 	ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
446 
447 	/*
448 	 * Allocate the component buffer header freelist.  We allocate
449 	 * ccdnbuf buffers per component.
450 	 */
451 	LIST_INIT(&cs->sc_freelist);
452 	cs->sc_hiwat = cs->sc_nccdisks * ccdnbuf;
453 	cs->sc_freecount = cs->sc_hiwat;
454 	for (ix = 0; ix < cs->sc_hiwat; ix++) {
455 		MALLOC(cbp, struct ccdbuf *, sizeof(struct ccdbuf),
456 		    M_DEVBUF, M_WAITOK);
457 		LIST_INSERT_HEAD(&cs->sc_freelist, cbp, cb_list);
458 	}
459 
460 	/* Reset statistics. */
461 	cs->sc_nmisses = 0;
462 	cs->sc_ngetbuf = 0;
463 
464 	cs->sc_flags |= CCDF_INITED;
465 	cs->sc_cflags = ccd->ccd_flags;	/* So we can find out later... */
466 	cs->sc_unit = ccd->ccd_unit;
467 
468 	return (0);
469 }
470 
471 static void
472 ccdinterleave(cs, unit)
473 	register struct ccd_softc *cs;
474 	int unit;
475 {
476 	register struct ccdcinfo *ci, *smallci;
477 	register struct ccdiinfo *ii;
478 	register daddr_t bn, lbn;
479 	register int ix;
480 	u_long size;
481 
482 #ifdef DEBUG
483 	if (ccddebug & CCDB_INIT)
484 		printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave);
485 #endif
486 	/*
487 	 * Allocate an interleave table.
488 	 * Chances are this is too big, but we don't care.
489 	 */
490 	size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
491 	cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
492 	bzero((caddr_t)cs->sc_itable, size);
493 
494 	/*
495 	 * Trivial case: no interleave (actually interleave of disk size).
496 	 * Each table entry represents a single component in its entirety.
497 	 */
498 	if (cs->sc_ileave == 0) {
499 		bn = 0;
500 		ii = cs->sc_itable;
501 
502 		for (ix = 0; ix < cs->sc_nccdisks; ix++) {
503 			/* Allocate space for ii_index. */
504 			ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
505 			ii->ii_ndisk = 1;
506 			ii->ii_startblk = bn;
507 			ii->ii_startoff = 0;
508 			ii->ii_index[0] = ix;
509 			bn += cs->sc_cinfo[ix].ci_size;
510 			ii++;
511 		}
512 		ii->ii_ndisk = 0;
513 #ifdef DEBUG
514 		if (ccddebug & CCDB_INIT)
515 			printiinfo(cs->sc_itable);
516 #endif
517 		return;
518 	}
519 
520 	/*
521 	 * The following isn't fast or pretty; it doesn't have to be.
522 	 */
523 	size = 0;
524 	bn = lbn = 0;
525 	for (ii = cs->sc_itable; ; ii++) {
526 		/* Allocate space for ii_index. */
527 		ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
528 		    M_DEVBUF, M_WAITOK);
529 
530 		/*
531 		 * Locate the smallest of the remaining components
532 		 */
533 		smallci = NULL;
534 		for (ci = cs->sc_cinfo;
535 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
536 			if (ci->ci_size > size &&
537 			    (smallci == NULL ||
538 			     ci->ci_size < smallci->ci_size))
539 				smallci = ci;
540 
541 		/*
542 		 * Nobody left, all done
543 		 */
544 		if (smallci == NULL) {
545 			ii->ii_ndisk = 0;
546 			break;
547 		}
548 
549 		/*
550 		 * Record starting logical block and component offset
551 		 */
552 		ii->ii_startblk = bn / cs->sc_ileave;
553 		ii->ii_startoff = lbn;
554 
555 		/*
556 		 * Determine how many disks take part in this interleave
557 		 * and record their indices.
558 		 */
559 		ix = 0;
560 		for (ci = cs->sc_cinfo;
561 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
562 			if (ci->ci_size >= smallci->ci_size)
563 				ii->ii_index[ix++] = ci - cs->sc_cinfo;
564 		ii->ii_ndisk = ix;
565 		bn += ix * (smallci->ci_size - size);
566 		lbn = smallci->ci_size / cs->sc_ileave;
567 		size = smallci->ci_size;
568 	}
569 #ifdef DEBUG
570 	if (ccddebug & CCDB_INIT)
571 		printiinfo(cs->sc_itable);
572 #endif
573 }
574 
575 /* ARGSUSED */
576 int
577 ccdopen(dev, flags, fmt, p)
578 	dev_t dev;
579 	int flags, fmt;
580 	struct proc *p;
581 {
582 	int unit = ccdunit(dev);
583 	struct ccd_softc *cs;
584 	struct disklabel *lp;
585 	int error = 0, part, pmask;
586 
587 #ifdef DEBUG
588 	if (ccddebug & CCDB_FOLLOW)
589 		printf("ccdopen(0x%x, 0x%x)\n", dev, flags);
590 #endif
591 	if (unit >= numccd)
592 		return (ENXIO);
593 	cs = &ccd_softc[unit];
594 
595 	if ((error = ccdlock(cs)) != 0)
596 		return (error);
597 
598 	lp = cs->sc_dkdev.dk_label;
599 
600 	part = DISKPART(dev);
601 	pmask = (1 << part);
602 
603 	/*
604 	 * If we're initialized, check to see if there are any other
605 	 * open partitions.  If not, then it's safe to update
606 	 * the in-core disklabel.
607 	 */
608 	if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0))
609 		ccdgetdisklabel(dev);
610 
611 	/* Check that the partition exists. */
612 	if (part != RAW_PART) {
613 		if (((cs->sc_flags & CCDF_INITED) == 0) ||
614 		    ((part >= lp->d_npartitions) ||
615 		     (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
616 			error = ENXIO;
617 			goto done;
618 		}
619 	}
620 
621 	/* Prevent our unit from being unconfigured while open. */
622 	switch (fmt) {
623 	case S_IFCHR:
624 		cs->sc_dkdev.dk_copenmask |= pmask;
625 		break;
626 
627 	case S_IFBLK:
628 		cs->sc_dkdev.dk_bopenmask |= pmask;
629 		break;
630 	}
631 	cs->sc_dkdev.dk_openmask =
632 	    cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
633 
634  done:
635 	ccdunlock(cs);
636 	return (error);
637 }
638 
639 /* ARGSUSED */
640 int
641 ccdclose(dev, flags, fmt, p)
642 	dev_t dev;
643 	int flags, fmt;
644 	struct proc *p;
645 {
646 	int unit = ccdunit(dev);
647 	struct ccd_softc *cs;
648 	int error = 0, part;
649 
650 #ifdef DEBUG
651 	if (ccddebug & CCDB_FOLLOW)
652 		printf("ccdclose(0x%x, 0x%x)\n", dev, flags);
653 #endif
654 
655 	if (unit >= numccd)
656 		return (ENXIO);
657 	cs = &ccd_softc[unit];
658 
659 	if ((error = ccdlock(cs)) != 0)
660 		return (error);
661 
662 	part = DISKPART(dev);
663 
664 	/* ...that much closer to allowing unconfiguration... */
665 	switch (fmt) {
666 	case S_IFCHR:
667 		cs->sc_dkdev.dk_copenmask &= ~(1 << part);
668 		break;
669 
670 	case S_IFBLK:
671 		cs->sc_dkdev.dk_bopenmask &= ~(1 << part);
672 		break;
673 	}
674 	cs->sc_dkdev.dk_openmask =
675 	    cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
676 
677 	ccdunlock(cs);
678 	return (0);
679 }
680 
681 void
682 ccdstrategy(bp)
683 	register struct buf *bp;
684 {
685 	register int unit = ccdunit(bp->b_dev);
686 	register struct ccd_softc *cs = &ccd_softc[unit];
687 	register int s;
688 	int wlabel;
689 	struct disklabel *lp;
690 
691 #ifdef DEBUG
692 	if (ccddebug & CCDB_FOLLOW)
693 		printf("ccdstrategy(%p): unit %d\n", bp, unit);
694 #endif
695 	if ((cs->sc_flags & CCDF_INITED) == 0) {
696 		bp->b_error = ENXIO;
697 		bp->b_flags |= B_ERROR;
698 		goto done;
699 	}
700 
701 	/* If it's a nil transfer, wake up the top half now. */
702 	if (bp->b_bcount == 0)
703 		goto done;
704 
705 	lp = cs->sc_dkdev.dk_label;
706 
707 	/*
708 	 * Do bounds checking and adjust transfer.  If there's an
709 	 * error, the bounds check will flag that for us.
710 	 */
711 	wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
712 	if (DISKPART(bp->b_dev) != RAW_PART)
713 		if (bounds_check_with_label(bp, lp, wlabel) <= 0)
714 			goto done;
715 
716 	bp->b_resid = bp->b_bcount;
717 
718 	/*
719 	 * "Start" the unit.
720 	 */
721 	s = splbio();
722 	ccdstart(cs, bp);
723 	splx(s);
724 	return;
725 done:
726 	biodone(bp);
727 }
728 
729 static void
730 ccdstart(cs, bp)
731 	register struct ccd_softc *cs;
732 	register struct buf *bp;
733 {
734 	register long bcount, rcount;
735 	struct ccdbuf *cbp[4];
736 	caddr_t addr;
737 	daddr_t bn;
738 	struct partition *pp;
739 
740 #ifdef DEBUG
741 	if (ccddebug & CCDB_FOLLOW)
742 		printf("ccdstart(%p, %p)\n", cs, bp);
743 #endif
744 
745 	/* Instrumentation. */
746 	disk_busy(&cs->sc_dkdev);
747 
748 	/*
749 	 * Translate the partition-relative block number to an absolute.
750 	 */
751 	bn = bp->b_blkno;
752 	if (DISKPART(bp->b_dev) != RAW_PART) {
753 		pp = &cs->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
754 		bn += pp->p_offset;
755 	}
756 
757 	/*
758 	 * Allocate component buffers and fire off the requests
759 	 */
760 	addr = bp->b_data;
761 	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
762 		ccdbuffer(cs, bp, bn, addr, bcount, cbp);
763 		rcount = cbp[0]->cb_buf.b_bcount;
764 		if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
765 			cbp[0]->cb_buf.b_vp->v_numoutput++;
766 		VOP_STRATEGY(&cbp[0]->cb_buf);
767 
768 		/*
769 		 * Mirror requires additional write.
770 		 */
771 		if ((cs->sc_cflags & CCDF_MIRROR) &&
772 		    ((cbp[0]->cb_buf.b_flags & B_READ) == 0)) {
773 			cbp[1]->cb_buf.b_vp->v_numoutput++;
774 			VOP_STRATEGY(&cbp[1]->cb_buf);
775 		}
776 
777 		bn += btodb(rcount);
778 		addr += rcount;
779 	}
780 }
781 
782 /*
783  * Build a component buffer header.
784  */
785 static void
786 ccdbuffer(cs, bp, bn, addr, bcount, cbpp)
787 	register struct ccd_softc *cs;
788 	struct buf *bp;
789 	daddr_t bn;
790 	caddr_t addr;
791 	long bcount;
792 	struct ccdbuf **cbpp;
793 {
794 	register struct ccdcinfo *ci, *ci2 = NULL;
795 	register struct ccdbuf *cbp;
796 	register daddr_t cbn, cboff;
797 	int ccdisk;
798 
799 #ifdef DEBUG
800 	if (ccddebug & CCDB_IO)
801 		printf("ccdbuffer(%p, %p, %d, %p, %ld)\n",
802 		       cs, bp, bn, addr, bcount);
803 #endif
804 	/*
805 	 * Determine which component bn falls in.
806 	 */
807 	cbn = bn;
808 	cboff = 0;
809 
810 	/*
811 	 * Serially concatenated
812 	 */
813 	if (cs->sc_ileave == 0) {
814 		register daddr_t sblk;
815 
816 		sblk = 0;
817 		for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk];
818 		    cbn >= sblk + ci->ci_size;
819 		    ccdisk++, ci = &cs->sc_cinfo[ccdisk])
820 			sblk += ci->ci_size;
821 		cbn -= sblk;
822 	}
823 	/*
824 	 * Interleaved
825 	 */
826 	else {
827 		register struct ccdiinfo *ii;
828 		int off;
829 
830 		cboff = cbn % cs->sc_ileave;
831 		cbn /= cs->sc_ileave;
832 		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
833 			if (ii->ii_startblk > cbn)
834 				break;
835 		ii--;
836 		off = cbn - ii->ii_startblk;
837 		if (ii->ii_ndisk == 1) {
838 			ccdisk = ii->ii_index[0];
839 			cbn = ii->ii_startoff + off;
840 		} else {
841 			if (cs->sc_cflags & CCDF_MIRROR) {
842 				ccdisk =
843 				    ii->ii_index[off % (ii->ii_ndisk / 2)];
844 				cbn = ii->ii_startoff +
845 				    (off / (ii->ii_ndisk / 2));
846 				/* Mirrored data */
847 				ci2 =
848 				    &cs->sc_cinfo[ccdisk + (ii->ii_ndisk / 2)];
849 			} else {
850 				/* Normal case. */
851 				ccdisk = ii->ii_index[off % ii->ii_ndisk];
852 				cbn = ii->ii_startoff + off / ii->ii_ndisk;
853 			}
854 		}
855 		cbn *= cs->sc_ileave;
856 		ci = &cs->sc_cinfo[ccdisk];
857 	}
858 
859 	/*
860 	 * Fill in the component buf structure.
861 	 */
862 	CCDGETBUF(cs, cbp);
863 	cbp->cb_flags = 0;
864 	cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
865 	cbp->cb_buf.b_iodone = ccdiodone;
866 	cbp->cb_buf.b_proc = bp->b_proc;
867 	cbp->cb_buf.b_dev = ci->ci_dev;		/* XXX */
868 	cbp->cb_buf.b_blkno = cbn + cboff;
869 	cbp->cb_buf.b_data = addr;
870 	cbp->cb_buf.b_vp = ci->ci_vp;
871 	if (cs->sc_ileave == 0)
872 		cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn);
873 	else
874 		cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff);
875 	if (cbp->cb_buf.b_bcount > bcount)
876 		cbp->cb_buf.b_bcount = bcount;
877 
878 	/*
879 	 * context for ccdiodone
880 	 */
881 	cbp->cb_obp = bp;
882 	cbp->cb_unit = cs->sc_unit;
883 	cbp->cb_comp = ccdisk;
884 
885 	/* First buffer is dealt with. */
886 	cbpp[0] = cbp;
887 
888 #ifdef DEBUG
889 	if (ccddebug & CCDB_IO)
890 		printf(" dev 0x%x(u%d): cbp %p bn %d addr %p bcnt %ld\n",
891 		    ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
892 		    cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
893 #endif
894 
895 	/*
896 	 * Mirrors have an additional write operation that is nearly
897 	 * identical to the first.
898 	 */
899 	if ((cs->sc_cflags & CCDF_MIRROR) &&
900 	    ((cbp->cb_buf.b_flags & B_READ) == 0)) {
901 		CCDGETBUF(cs, cbp);
902 		*cbp = *cbpp[0];
903 		cbp->cb_flags = CBF_MIRROR;
904 		cbp->cb_buf.b_dev = ci2->ci_dev;	/* XXX */
905 		cbp->cb_buf.b_vp = ci2->ci_vp;
906 		cbp->cb_comp = ci2 - cs->sc_cinfo;
907 		cbpp[1] = cbp;
908 	}
909 }
910 
911 static void
912 ccdintr(cs, bp)
913 	register struct ccd_softc *cs;
914 	register struct buf *bp;
915 {
916 
917 #ifdef DEBUG
918 	if (ccddebug & CCDB_FOLLOW)
919 		printf("ccdintr(%p, %p)\n", cs, bp);
920 #endif
921 	/*
922 	 * Request is done for better or worse, wakeup the top half.
923 	 */
924 	if (bp->b_flags & B_ERROR)
925 		bp->b_resid = bp->b_bcount;
926 	disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid));
927 	biodone(bp);
928 }
929 
930 /*
931  * Called at interrupt time.
932  * Mark the component as done and if all components are done,
933  * take a ccd interrupt.
934  */
935 void
936 ccdiodone(vbp)
937 	struct buf *vbp;
938 {
939 	struct ccdbuf *cbp = (struct ccdbuf *) vbp;
940 	register struct buf *bp = cbp->cb_obp;
941 	register int unit = cbp->cb_unit;
942 	struct ccd_softc *cs = &ccd_softc[unit];
943 	int count, cbflags, s;
944 	char *comptype;
945 
946 	s = splbio();
947 #ifdef DEBUG
948 	if (ccddebug & CCDB_FOLLOW)
949 		printf("ccdiodone(%p)\n", cbp);
950 	if (ccddebug & CCDB_IO) {
951 		if (cbp->cb_flags & CBF_MIRROR)
952 			printf("ccdiodone: mirror component\n");
953 		else
954 			printf("ccdiodone: bp %p bcount %ld resid %ld\n",
955 			       bp, bp->b_bcount, bp->b_resid);
956 		printf(" dev 0x%x(u%d), cbp %p bn %d addr %p bcnt %ld\n",
957 		       cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
958 		       cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
959 		       cbp->cb_buf.b_bcount);
960 	}
961 #endif
962 
963 	if (cbp->cb_buf.b_flags & B_ERROR) {
964 		if (cbp->cb_flags & CBF_MIRROR)
965 			comptype = " (mirror)";
966 		else {
967 			bp->b_flags |= B_ERROR;
968 			bp->b_error = cbp->cb_buf.b_error ?
969 			    cbp->cb_buf.b_error : EIO;
970 			comptype = "";
971 		}
972 
973 		printf("%s: error %d on component %d%s\n",
974 		       cs->sc_xname, bp->b_error, cbp->cb_comp, comptype);
975 	}
976 	count = cbp->cb_buf.b_bcount;
977 	cbflags = cbp->cb_flags;
978 	CCDPUTBUF(cs, cbp);
979 
980 	/*
981 	 * If all done, "interrupt".
982 	 *
983 	 * Note that mirror component buffers aren't counted against
984 	 * the original I/O buffer.
985 	 */
986 	if ((cbflags & CBF_MIRROR) == 0) {
987 		bp->b_resid -= count;
988 		if (bp->b_resid < 0)
989 			panic("ccdiodone: count");
990 		if (bp->b_resid == 0)
991 			ccdintr(&ccd_softc[unit], bp);
992 	}
993 	splx(s);
994 }
995 
996 /* ARGSUSED */
997 int
998 ccdread(dev, uio, flags)
999 	dev_t dev;
1000 	struct uio *uio;
1001 	int flags;
1002 {
1003 	int unit = ccdunit(dev);
1004 	struct ccd_softc *cs;
1005 
1006 #ifdef DEBUG
1007 	if (ccddebug & CCDB_FOLLOW)
1008 		printf("ccdread(0x%x, %p)\n", dev, uio);
1009 #endif
1010 	if (unit >= numccd)
1011 		return (ENXIO);
1012 	cs = &ccd_softc[unit];
1013 
1014 	if ((cs->sc_flags & CCDF_INITED) == 0)
1015 		return (ENXIO);
1016 
1017 	/*
1018 	 * XXX: It's not clear that using minphys() is completely safe,
1019 	 * in particular, for raw I/O.  Underlying devices might have some
1020 	 * non-obvious limits, because of the copy to user-space.
1021 	 */
1022 	return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
1023 }
1024 
1025 /* ARGSUSED */
1026 int
1027 ccdwrite(dev, uio, flags)
1028 	dev_t dev;
1029 	struct uio *uio;
1030 	int flags;
1031 {
1032 	int unit = ccdunit(dev);
1033 	struct ccd_softc *cs;
1034 
1035 #ifdef DEBUG
1036 	if (ccddebug & CCDB_FOLLOW)
1037 		printf("ccdwrite(0x%x, %p)\n", dev, uio);
1038 #endif
1039 	if (unit >= numccd)
1040 		return (ENXIO);
1041 	cs = &ccd_softc[unit];
1042 
1043 	if ((cs->sc_flags & CCDF_INITED) == 0)
1044 		return (ENXIO);
1045 
1046 	/*
1047 	 * XXX: It's not clear that using minphys() is completely safe,
1048 	 * in particular, for raw I/O.  Underlying devices might have some
1049 	 * non-obvious limits, because of the copy to user-space.
1050 	 */
1051 	return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
1052 }
1053 
1054 int
1055 ccdioctl(dev, cmd, data, flag, p)
1056 	dev_t dev;
1057 	u_long cmd;
1058 	caddr_t data;
1059 	int flag;
1060 	struct proc *p;
1061 {
1062 	int unit = ccdunit(dev);
1063 	int i, j, lookedup = 0, error = 0;
1064 	int part, pmask;
1065 	struct ccd_softc *cs;
1066 	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1067 	struct ccddevice ccd;
1068 	struct ccdbuf *cbp;
1069 	char **cpp;
1070 	struct vnode **vpp;
1071 
1072 	if (unit >= numccd)
1073 		return (ENXIO);
1074 	cs = &ccd_softc[unit];
1075 
1076 	bzero(&ccd, sizeof(ccd));
1077 
1078 	/* Must be open for writes for these commands... */
1079 	switch (cmd) {
1080 	case CCDIOCSET:
1081 	case CCDIOCCLR:
1082 	case DIOCSDINFO:
1083 	case DIOCWDINFO:
1084 	case DIOCWLABEL:
1085 		if ((flag & FWRITE) == 0)
1086 			return (EBADF);
1087 	}
1088 
1089 	/* Must be initialized for these... */
1090 	switch (cmd) {
1091 	case CCDIOCCLR:
1092 	case DIOCGDINFO:
1093 	case DIOCSDINFO:
1094 	case DIOCWDINFO:
1095 	case DIOCGPART:
1096 	case DIOCWLABEL:
1097 	case DIOCGDEFLABEL:
1098 		if ((cs->sc_flags & CCDF_INITED) == 0)
1099 			return (ENXIO);
1100 	}
1101 
1102 	switch (cmd) {
1103 	case CCDIOCSET:
1104 		if (cs->sc_flags & CCDF_INITED)
1105 			return (EBUSY);
1106 
1107 		if ((error = ccdlock(cs)) != 0)
1108 			return (error);
1109 
1110 		/* Fill in some important bits. */
1111 		ccd.ccd_unit = unit;
1112 		ccd.ccd_interleave = ccio->ccio_ileave;
1113 		ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1114 
1115 		/*
1116 		 * Allocate space for and copy in the array of
1117 		 * componet pathnames and device numbers.
1118 		 */
1119 		cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1120 		    M_DEVBUF, M_WAITOK);
1121 		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1122 		    M_DEVBUF, M_WAITOK);
1123 
1124 		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1125 		    ccio->ccio_ndisks * sizeof(char **));
1126 		if (error) {
1127 			free(vpp, M_DEVBUF);
1128 			free(cpp, M_DEVBUF);
1129 			ccdunlock(cs);
1130 			return (error);
1131 		}
1132 
1133 #ifdef DEBUG
1134 		if (ccddebug & CCDB_INIT)
1135 			for (i = 0; i < ccio->ccio_ndisks; ++i)
1136 				printf("ccdioctl: component %d: 0x%p\n",
1137 				    i, cpp[i]);
1138 #endif
1139 
1140 		for (i = 0; i < ccio->ccio_ndisks; ++i) {
1141 #ifdef DEBUG
1142 			if (ccddebug & CCDB_INIT)
1143 				printf("ccdioctl: lookedup = %d\n", lookedup);
1144 #endif
1145 			if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1146 				for (j = 0; j < lookedup; ++j)
1147 					(void)vn_close(vpp[j], FREAD|FWRITE,
1148 					    p->p_ucred, p);
1149 				free(vpp, M_DEVBUF);
1150 				free(cpp, M_DEVBUF);
1151 				ccdunlock(cs);
1152 				return (error);
1153 			}
1154 			++lookedup;
1155 		}
1156 		ccd.ccd_cpp = cpp;
1157 		ccd.ccd_vpp = vpp;
1158 		ccd.ccd_ndev = ccio->ccio_ndisks;
1159 
1160 		/*
1161 		 * Initialize the ccd.  Fills in the softc for us.
1162 		 */
1163 		if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1164 			for (j = 0; j < lookedup; ++j)
1165 				(void)vn_close(vpp[j], FREAD|FWRITE,
1166 				    p->p_ucred, p);
1167 			bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1168 			free(vpp, M_DEVBUF);
1169 			free(cpp, M_DEVBUF);
1170 			ccdunlock(cs);
1171 			return (error);
1172 		}
1173 
1174 		/*
1175 		 * The ccd has been successfully initialized, so
1176 		 * we can place it into the array.  Don't try to
1177 		 * read the disklabel until the disk has been attached,
1178 		 * because space for the disklabel is allocated
1179 		 * in disk_attach();
1180 		 */
1181 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1182 		ccio->ccio_unit = unit;
1183 		ccio->ccio_size = cs->sc_size;
1184 
1185 		/* Attach the disk. */
1186 		cs->sc_dkdev.dk_name = cs->sc_xname;
1187 		disk_attach(&cs->sc_dkdev);
1188 
1189 		/* Try and read the disklabel. */
1190 		ccdgetdisklabel(dev);
1191 
1192 		ccdunlock(cs);
1193 
1194 		break;
1195 
1196 	case CCDIOCCLR:
1197 		if ((error = ccdlock(cs)) != 0)
1198 			return (error);
1199 
1200 		/*
1201 		 * Don't unconfigure if any other partitions are open
1202 		 * or if both the character and block flavors of this
1203 		 * partition are open.
1204 		 */
1205 		part = DISKPART(dev);
1206 		pmask = (1 << part);
1207 		if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
1208 		    ((cs->sc_dkdev.dk_bopenmask & pmask) &&
1209 		    (cs->sc_dkdev.dk_copenmask & pmask))) {
1210 			ccdunlock(cs);
1211 			return (EBUSY);
1212 		}
1213 
1214 		/*
1215 		 * Free ccd_softc information and clear entry.
1216 		 */
1217 
1218 		/* Close the components and free their pathnames. */
1219 		for (i = 0; i < cs->sc_nccdisks; ++i) {
1220 			/*
1221 			 * XXX: this close could potentially fail and
1222 			 * cause Bad Things.  Maybe we need to force
1223 			 * the close to happen?
1224 			 */
1225 #ifdef DEBUG
1226 			if (ccddebug & CCDB_VNODE)
1227 				vprint("CCDIOCCLR: vnode info",
1228 				    cs->sc_cinfo[i].ci_vp);
1229 #endif
1230 			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1231 			    p->p_ucred, p);
1232 			free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1233 		}
1234 
1235 		/* Free component buffer freelist. */
1236 		while ((cbp = cs->sc_freelist.lh_first) != NULL) {
1237 			LIST_REMOVE(cbp, cb_list);
1238 			FREE(cbp, M_DEVBUF);
1239 		}
1240 
1241 		/* Free interleave index. */
1242 		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1243 			free(cs->sc_itable[i].ii_index, M_DEVBUF);
1244 
1245 		/* Free component info and interleave table. */
1246 		free(cs->sc_cinfo, M_DEVBUF);
1247 		free(cs->sc_itable, M_DEVBUF);
1248 		cs->sc_flags &= ~CCDF_INITED;
1249 
1250 		/*
1251 		 * Free ccddevice information and clear entry.
1252 		 */
1253 		free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1254 		free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1255 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1256 
1257 		/* Detatch the disk. */
1258 		disk_detach(&cs->sc_dkdev);
1259 
1260 		ccdunlock(cs);
1261 
1262 		break;
1263 
1264 	case DIOCGDINFO:
1265 		*(struct disklabel *)data = *(cs->sc_dkdev.dk_label);
1266 		break;
1267 
1268 	case DIOCGPART:
1269 		((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label;
1270 		((struct partinfo *)data)->part =
1271 		    &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
1272 		break;
1273 
1274 	case DIOCWDINFO:
1275 	case DIOCSDINFO:
1276 		if ((error = ccdlock(cs)) != 0)
1277 			return (error);
1278 
1279 		cs->sc_flags |= CCDF_LABELLING;
1280 
1281 		error = setdisklabel(cs->sc_dkdev.dk_label,
1282 		    (struct disklabel *)data, 0, cs->sc_dkdev.dk_cpulabel);
1283 		if (error == 0) {
1284 			if (cmd == DIOCWDINFO)
1285 				error = writedisklabel(CCDLABELDEV(dev),
1286 				    ccdstrategy, cs->sc_dkdev.dk_label,
1287 				    cs->sc_dkdev.dk_cpulabel);
1288 		}
1289 
1290 		cs->sc_flags &= ~CCDF_LABELLING;
1291 
1292 		ccdunlock(cs);
1293 
1294 		if (error)
1295 			return (error);
1296 		break;
1297 
1298 	case DIOCWLABEL:
1299 		if (*(int *)data != 0)
1300 			cs->sc_flags |= CCDF_WLABEL;
1301 		else
1302 			cs->sc_flags &= ~CCDF_WLABEL;
1303 		break;
1304 
1305 	case DIOCGDEFLABEL:
1306 		ccdgetdefaultlabel(cs, (struct disklabel *)data);
1307 		break;
1308 
1309 	default:
1310 		return (ENOTTY);
1311 	}
1312 
1313 	return (0);
1314 }
1315 
1316 int
1317 ccdsize(dev)
1318 	dev_t dev;
1319 {
1320 	struct ccd_softc *cs;
1321 	struct disklabel *lp;
1322 	int part, unit, omask, size;
1323 
1324 	unit = ccdunit(dev);
1325 	if (unit >= numccd)
1326 		return (-1);
1327 	cs = &ccd_softc[unit];
1328 
1329 	if ((cs->sc_flags & CCDF_INITED) == 0)
1330 		return (-1);
1331 
1332 	part = DISKPART(dev);
1333 	omask = cs->sc_dkdev.dk_openmask & (1 << part);
1334 	lp = cs->sc_dkdev.dk_label;
1335 
1336 	if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curproc))
1337 		return (-1);
1338 
1339 	if (lp->d_partitions[part].p_fstype != FS_SWAP)
1340 		size = -1;
1341 	else
1342 		size = lp->d_partitions[part].p_size *
1343 		    (lp->d_secsize / DEV_BSIZE);
1344 
1345 	if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curproc))
1346 		return (-1);
1347 
1348 	return (size);
1349 }
1350 
1351 int
1352 ccddump(dev, blkno, va, size)
1353 	dev_t dev;
1354 	daddr_t blkno;
1355 	caddr_t va;
1356 	size_t size;
1357 {
1358 
1359 	/* Not implemented. */
1360 	return ENXIO;
1361 }
1362 
1363 /*
1364  * Lookup the provided name in the filesystem.  If the file exists,
1365  * is a valid block device, and isn't being used by anyone else,
1366  * set *vpp to the file's vnode.
1367  */
1368 static int
1369 ccdlookup(path, p, vpp)
1370 	char *path;
1371 	struct proc *p;
1372 	struct vnode **vpp;	/* result */
1373 {
1374 	struct nameidata nd;
1375 	struct vnode *vp;
1376 	struct vattr va;
1377 	int error;
1378 
1379 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1380 	if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1381 #ifdef DEBUG
1382 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1383 			printf("ccdlookup: vn_open error = %d\n", error);
1384 #endif
1385 		return (error);
1386 	}
1387 	vp = nd.ni_vp;
1388 
1389 	if (vp->v_usecount > 1) {
1390 		VOP_UNLOCK(vp);
1391 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1392 		return (EBUSY);
1393 	}
1394 
1395 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
1396 #ifdef DEBUG
1397 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
1398 			printf("ccdlookup: getattr error = %d\n", error);
1399 #endif
1400 		VOP_UNLOCK(vp);
1401 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1402 		return (error);
1403 	}
1404 
1405 	/* XXX: eventually we should handle VREG, too. */
1406 	if (va.va_type != VBLK) {
1407 		VOP_UNLOCK(vp);
1408 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1409 		return (ENOTBLK);
1410 	}
1411 
1412 #ifdef DEBUG
1413 	if (ccddebug & CCDB_VNODE)
1414 		vprint("ccdlookup: vnode info", vp);
1415 #endif
1416 
1417 	VOP_UNLOCK(vp);
1418 	*vpp = vp;
1419 	return (0);
1420 }
1421 
1422 static void
1423 ccdgetdefaultlabel(cs, lp)
1424 	struct ccd_softc *cs;
1425 	struct disklabel *lp;
1426 {
1427 	struct ccdgeom *ccg = &cs->sc_geom;
1428 
1429 	bzero(lp, sizeof(*lp));
1430 
1431 	lp->d_secperunit = cs->sc_size;
1432 	lp->d_secsize = ccg->ccg_secsize;
1433 	lp->d_nsectors = ccg->ccg_nsectors;
1434 	lp->d_ntracks = ccg->ccg_ntracks;
1435 	lp->d_ncylinders = ccg->ccg_ncylinders;
1436 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1437 
1438 	strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1439 	lp->d_type = DTYPE_CCD;
1440 	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1441 	lp->d_rpm = 3600;
1442 	lp->d_interleave = 1;
1443 	lp->d_flags = 0;
1444 
1445 	lp->d_partitions[RAW_PART].p_offset = 0;
1446 	lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1447 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1448 	lp->d_npartitions = RAW_PART + 1;
1449 
1450 	lp->d_magic = DISKMAGIC;
1451 	lp->d_magic2 = DISKMAGIC;
1452 	lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label);
1453 }
1454 
1455 /*
1456  * Read the disklabel from the ccd.  If one is not present, fake one
1457  * up.
1458  */
1459 static void
1460 ccdgetdisklabel(dev)
1461 	dev_t dev;
1462 {
1463 	int unit = ccdunit(dev);
1464 	struct ccd_softc *cs = &ccd_softc[unit];
1465 	char *errstring;
1466 	struct disklabel *lp = cs->sc_dkdev.dk_label;
1467 	struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel;
1468 
1469 	bzero(clp, sizeof(*clp));
1470 
1471 	ccdgetdefaultlabel(cs, lp);
1472 
1473 	/*
1474 	 * Call the generic disklabel extraction routine.
1475 	 */
1476 	errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1477 	    cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel);
1478 	if (errstring)
1479 		ccdmakedisklabel(cs);
1480 
1481 #ifdef DEBUG
1482 	/* It's actually extremely common to have unlabeled ccds. */
1483 	if (ccddebug & CCDB_LABEL)
1484 		if (errstring != NULL)
1485 			printf("%s: %s\n", cs->sc_xname, errstring);
1486 #endif
1487 }
1488 
1489 /*
1490  * Take care of things one might want to take care of in the event
1491  * that a disklabel isn't present.
1492  */
1493 static void
1494 ccdmakedisklabel(cs)
1495 	struct ccd_softc *cs;
1496 {
1497 	struct disklabel *lp = cs->sc_dkdev.dk_label;
1498 
1499 	/*
1500 	 * For historical reasons, if there's no disklabel present
1501 	 * the raw partition must be marked FS_BSDFFS.
1502 	 */
1503 	lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1504 
1505 	strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1506 
1507 	lp->d_checksum = dkcksum(lp);
1508 }
1509 
1510 /*
1511  * Wait interruptibly for an exclusive lock.
1512  *
1513  * XXX
1514  * Several drivers do this; it should be abstracted and made MP-safe.
1515  */
1516 static int
1517 ccdlock(cs)
1518 	struct ccd_softc *cs;
1519 {
1520 	int error;
1521 
1522 	while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1523 		cs->sc_flags |= CCDF_WANTED;
1524 		if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1525 			return (error);
1526 	}
1527 	cs->sc_flags |= CCDF_LOCKED;
1528 	return (0);
1529 }
1530 
1531 /*
1532  * Unlock and wake up any waiters.
1533  */
1534 static void
1535 ccdunlock(cs)
1536 	struct ccd_softc *cs;
1537 {
1538 
1539 	cs->sc_flags &= ~CCDF_LOCKED;
1540 	if ((cs->sc_flags & CCDF_WANTED) != 0) {
1541 		cs->sc_flags &= ~CCDF_WANTED;
1542 		wakeup(cs);
1543 	}
1544 }
1545 
1546 #ifdef DEBUG
1547 static void
1548 printiinfo(ii)
1549 	struct ccdiinfo *ii;
1550 {
1551 	register int ix, i;
1552 
1553 	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1554 		printf(" itab[%d]: #dk %d sblk %d soff %d",
1555 		    ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1556 		for (i = 0; i < ii->ii_ndisk; i++)
1557 			printf(" %d", ii->ii_index[i]);
1558 		printf("\n");
1559 	}
1560 }
1561 #endif
1562