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