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