xref: /freebsd/sys/geom/geom_ccd.c (revision 9d7f73695d650ca78c0e87909888e1930512df1a)
1c3aac50fSPeter Wemm /* $FreeBSD$ */
2aa8bdaecSSatoshi Asami 
3a56bb8a5SSatoshi Asami /*	$NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $	*/
4a56bb8a5SSatoshi Asami 
5a56bb8a5SSatoshi Asami /*
6a56bb8a5SSatoshi Asami  * Copyright (c) 1995 Jason R. Thorpe.
7a56bb8a5SSatoshi Asami  * All rights reserved.
8a56bb8a5SSatoshi Asami  *
9a56bb8a5SSatoshi Asami  * Redistribution and use in source and binary forms, with or without
10a56bb8a5SSatoshi Asami  * modification, are permitted provided that the following conditions
11a56bb8a5SSatoshi Asami  * are met:
12a56bb8a5SSatoshi Asami  * 1. Redistributions of source code must retain the above copyright
13a56bb8a5SSatoshi Asami  *    notice, this list of conditions and the following disclaimer.
14a56bb8a5SSatoshi Asami  * 2. Redistributions in binary form must reproduce the above copyright
15a56bb8a5SSatoshi Asami  *    notice, this list of conditions and the following disclaimer in the
16a56bb8a5SSatoshi Asami  *    documentation and/or other materials provided with the distribution.
17a56bb8a5SSatoshi Asami  * 3. All advertising materials mentioning features or use of this software
18a56bb8a5SSatoshi Asami  *    must display the following acknowledgement:
19a56bb8a5SSatoshi Asami  *	This product includes software developed for the NetBSD Project
20a56bb8a5SSatoshi Asami  *	by Jason R. Thorpe.
21a56bb8a5SSatoshi Asami  * 4. The name of the author may not be used to endorse or promote products
22a56bb8a5SSatoshi Asami  *    derived from this software without specific prior written permission.
23a56bb8a5SSatoshi Asami  *
24a56bb8a5SSatoshi Asami  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25a56bb8a5SSatoshi Asami  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26a56bb8a5SSatoshi Asami  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27a56bb8a5SSatoshi Asami  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28a56bb8a5SSatoshi Asami  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29a56bb8a5SSatoshi Asami  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30a56bb8a5SSatoshi Asami  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31a56bb8a5SSatoshi Asami  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32a56bb8a5SSatoshi Asami  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33a56bb8a5SSatoshi Asami  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34a56bb8a5SSatoshi Asami  * SUCH DAMAGE.
35a56bb8a5SSatoshi Asami  */
36a56bb8a5SSatoshi Asami 
37a56bb8a5SSatoshi Asami /*
38a56bb8a5SSatoshi Asami  * Copyright (c) 1988 University of Utah.
39a56bb8a5SSatoshi Asami  * Copyright (c) 1990, 1993
40a56bb8a5SSatoshi Asami  *	The Regents of the University of California.  All rights reserved.
41a56bb8a5SSatoshi Asami  *
42a56bb8a5SSatoshi Asami  * This code is derived from software contributed to Berkeley by
43a56bb8a5SSatoshi Asami  * the Systems Programming Group of the University of Utah Computer
44a56bb8a5SSatoshi Asami  * Science Department.
45a56bb8a5SSatoshi Asami  *
46a56bb8a5SSatoshi Asami  * Redistribution and use in source and binary forms, with or without
47a56bb8a5SSatoshi Asami  * modification, are permitted provided that the following conditions
48a56bb8a5SSatoshi Asami  * are met:
49a56bb8a5SSatoshi Asami  * 1. Redistributions of source code must retain the above copyright
50a56bb8a5SSatoshi Asami  *    notice, this list of conditions and the following disclaimer.
51a56bb8a5SSatoshi Asami  * 2. Redistributions in binary form must reproduce the above copyright
52a56bb8a5SSatoshi Asami  *    notice, this list of conditions and the following disclaimer in the
53a56bb8a5SSatoshi Asami  *    documentation and/or other materials provided with the distribution.
54a56bb8a5SSatoshi Asami  * 3. All advertising materials mentioning features or use of this software
55a56bb8a5SSatoshi Asami  *    must display the following acknowledgement:
56a56bb8a5SSatoshi Asami  *	This product includes software developed by the University of
57a56bb8a5SSatoshi Asami  *	California, Berkeley and its contributors.
58a56bb8a5SSatoshi Asami  * 4. Neither the name of the University nor the names of its contributors
59a56bb8a5SSatoshi Asami  *    may be used to endorse or promote products derived from this software
60a56bb8a5SSatoshi Asami  *    without specific prior written permission.
61a56bb8a5SSatoshi Asami  *
62a56bb8a5SSatoshi Asami  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63a56bb8a5SSatoshi Asami  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64a56bb8a5SSatoshi Asami  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65a56bb8a5SSatoshi Asami  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66a56bb8a5SSatoshi Asami  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67a56bb8a5SSatoshi Asami  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68a56bb8a5SSatoshi Asami  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69a56bb8a5SSatoshi Asami  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70a56bb8a5SSatoshi Asami  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71a56bb8a5SSatoshi Asami  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72a56bb8a5SSatoshi Asami  * SUCH DAMAGE.
73a56bb8a5SSatoshi Asami  *
74a56bb8a5SSatoshi Asami  * from: Utah $Hdr: cd.c 1.6 90/11/28$
75a56bb8a5SSatoshi Asami  *
76a56bb8a5SSatoshi Asami  *	@(#)cd.c	8.2 (Berkeley) 11/16/93
77a56bb8a5SSatoshi Asami  */
78a56bb8a5SSatoshi Asami 
79a56bb8a5SSatoshi Asami /*
80a56bb8a5SSatoshi Asami  * "Concatenated" disk driver.
81a56bb8a5SSatoshi Asami  *
82a56bb8a5SSatoshi Asami  * Dynamic configuration and disklabel support by:
83a56bb8a5SSatoshi Asami  *	Jason R. Thorpe <thorpej@nas.nasa.gov>
84a56bb8a5SSatoshi Asami  *	Numerical Aerodynamic Simulation Facility
85a56bb8a5SSatoshi Asami  *	Mail Stop 258-6
86a56bb8a5SSatoshi Asami  *	NASA Ames Research Center
87a56bb8a5SSatoshi Asami  *	Moffett Field, CA 94035
88a56bb8a5SSatoshi Asami  */
89a56bb8a5SSatoshi Asami 
90d8594dfbSSatoshi Asami #include "ccd.h"
91d8594dfbSSatoshi Asami 
92a56bb8a5SSatoshi Asami #include <sys/param.h>
93a56bb8a5SSatoshi Asami #include <sys/systm.h>
94e2a13e8cSSatoshi Asami #include <sys/kernel.h>
95b7b98418SPeter Wemm #include <sys/module.h>
96a56bb8a5SSatoshi Asami #include <sys/proc.h>
97a56bb8a5SSatoshi Asami #include <sys/buf.h>
98a56bb8a5SSatoshi Asami #include <sys/malloc.h>
99a56bb8a5SSatoshi Asami #include <sys/namei.h>
100a56bb8a5SSatoshi Asami #include <sys/conf.h>
101a56bb8a5SSatoshi Asami #include <sys/stat.h>
102e2738b4fSPoul-Henning Kamp #include <sys/sysctl.h>
103a56bb8a5SSatoshi Asami #include <sys/disklabel.h>
104d8594dfbSSatoshi Asami #include <ufs/ffs/fs.h>
105b2dfb1f9SJustin T. Gibbs #include <sys/devicestat.h>
106a56bb8a5SSatoshi Asami #include <sys/fcntl.h>
107a56bb8a5SSatoshi Asami #include <sys/vnode.h>
108a56bb8a5SSatoshi Asami 
109d8594dfbSSatoshi Asami #include <sys/ccdvar.h>
110a56bb8a5SSatoshi Asami 
111762e6b85SEivind Eklund 
112a56bb8a5SSatoshi Asami #if defined(CCDDEBUG) && !defined(DEBUG)
113a56bb8a5SSatoshi Asami #define DEBUG
114a56bb8a5SSatoshi Asami #endif
115a56bb8a5SSatoshi Asami 
116a56bb8a5SSatoshi Asami #ifdef DEBUG
117a56bb8a5SSatoshi Asami #define CCDB_FOLLOW	0x01
118a56bb8a5SSatoshi Asami #define CCDB_INIT	0x02
119a56bb8a5SSatoshi Asami #define CCDB_IO		0x04
120a56bb8a5SSatoshi Asami #define CCDB_LABEL	0x08
121a56bb8a5SSatoshi Asami #define CCDB_VNODE	0x10
122e2738b4fSPoul-Henning Kamp static int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL |
123e2738b4fSPoul-Henning Kamp     CCDB_VNODE;
124e2738b4fSPoul-Henning Kamp SYSCTL_INT(_debug, OID_AUTO, ccddebug, CTLFLAG_RW, &ccddebug, 0, "");
125d8594dfbSSatoshi Asami #undef DEBUG
126a56bb8a5SSatoshi Asami #endif
127a56bb8a5SSatoshi Asami 
128d8594dfbSSatoshi Asami #define	ccdunit(x)	dkunit(x)
129d8594dfbSSatoshi Asami #define ccdpart(x)	dkpart(x)
130a56bb8a5SSatoshi Asami 
131e7322872SSatoshi Asami /*
132e7322872SSatoshi Asami    This is how mirroring works (only writes are special):
133e7322872SSatoshi Asami 
134e7322872SSatoshi Asami    When initiating a write, ccdbuffer() returns two "struct ccdbuf *"s
135e7322872SSatoshi Asami    linked together by the cb_mirror field.  "cb_pflags &
136e7322872SSatoshi Asami    CCDPF_MIRROR_DONE" is set to 0 on both of them.
137e7322872SSatoshi Asami 
138e7322872SSatoshi Asami    When a component returns to ccdiodone(), it checks if "cb_pflags &
139e7322872SSatoshi Asami    CCDPF_MIRROR_DONE" is set or not.  If not, it sets the partner's
140e7322872SSatoshi Asami    flag and returns.  If it is, it means its partner has already
141e7322872SSatoshi Asami    returned, so it will go to the regular cleanup.
142e7322872SSatoshi Asami 
143e7322872SSatoshi Asami  */
144e7322872SSatoshi Asami 
145a56bb8a5SSatoshi Asami struct ccdbuf {
1469d7f7369SPoul-Henning Kamp 	struct bio	cb_buf;		/* new I/O buf */
1479d7f7369SPoul-Henning Kamp 	struct bio	*cb_obp;	/* ptr. to original I/O buf */
1481464240eSMatthew Dillon 	struct ccdbuf	*cb_freenext;	/* free list link */
149a56bb8a5SSatoshi Asami 	int		cb_unit;	/* target unit */
150a56bb8a5SSatoshi Asami 	int		cb_comp;	/* target component */
151e7322872SSatoshi Asami 	int		cb_pflags;	/* mirror/parity status flag */
152e7322872SSatoshi Asami 	struct ccdbuf	*cb_mirror;	/* mirror counterpart */
153a56bb8a5SSatoshi Asami };
154a56bb8a5SSatoshi Asami 
155e7322872SSatoshi Asami /* bits in cb_pflags */
156e7322872SSatoshi Asami #define CCDPF_MIRROR_DONE 1	/* if set, mirror counterpart is done */
157e7322872SSatoshi Asami 
158a56bb8a5SSatoshi Asami #define CCDLABELDEV(dev)	\
159d8594dfbSSatoshi Asami 	(makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
160a56bb8a5SSatoshi Asami 
161e2738b4fSPoul-Henning Kamp static d_open_t ccdopen;
162e2738b4fSPoul-Henning Kamp static d_close_t ccdclose;
163e2738b4fSPoul-Henning Kamp static d_strategy_t ccdstrategy;
164e2738b4fSPoul-Henning Kamp static d_ioctl_t ccdioctl;
165e2738b4fSPoul-Henning Kamp static d_dump_t ccddump;
166e2738b4fSPoul-Henning Kamp static d_psize_t ccdsize;
167d8594dfbSSatoshi Asami 
1681464240eSMatthew Dillon #define NCCDFREEHIWAT	16
1691464240eSMatthew Dillon 
170e2a13e8cSSatoshi Asami #define CDEV_MAJOR 74
171e2a13e8cSSatoshi Asami #define BDEV_MAJOR 21
172a56bb8a5SSatoshi Asami 
173f7ea2f55SJulian Elischer static struct cdevsw ccd_cdevsw = {
1744e2f199eSPoul-Henning Kamp 	/* open */	ccdopen,
1754e2f199eSPoul-Henning Kamp 	/* close */	ccdclose,
1764e2f199eSPoul-Henning Kamp 	/* read */	physread,
1774e2f199eSPoul-Henning Kamp 	/* write */	physwrite,
1784e2f199eSPoul-Henning Kamp 	/* ioctl */	ccdioctl,
1794e2f199eSPoul-Henning Kamp 	/* poll */	nopoll,
1804e2f199eSPoul-Henning Kamp 	/* mmap */	nommap,
1814e2f199eSPoul-Henning Kamp 	/* strategy */	ccdstrategy,
1824e2f199eSPoul-Henning Kamp 	/* name */	"ccd",
1834e2f199eSPoul-Henning Kamp 	/* maj */	CDEV_MAJOR,
1844e2f199eSPoul-Henning Kamp 	/* dump */	ccddump,
1854e2f199eSPoul-Henning Kamp 	/* psize */	ccdsize,
1864e2f199eSPoul-Henning Kamp 	/* flags */	D_DISK,
1874e2f199eSPoul-Henning Kamp 	/* bmaj */	BDEV_MAJOR
1884e2f199eSPoul-Henning Kamp };
189e2a13e8cSSatoshi Asami 
190b7b98418SPeter Wemm /* called during module initialization */
191b7b98418SPeter Wemm static	void ccdattach __P((void));
192b7b98418SPeter Wemm static	int ccd_modevent __P((module_t, int, void *));
193a56bb8a5SSatoshi Asami 
194a56bb8a5SSatoshi Asami /* called by biodone() at interrupt time */
1959d7f7369SPoul-Henning Kamp static	void ccdiodone __P((struct bio *bp));
196a56bb8a5SSatoshi Asami 
1979d7f7369SPoul-Henning Kamp static	void ccdstart __P((struct ccd_softc *, struct bio *));
198a56bb8a5SSatoshi Asami static	void ccdinterleave __P((struct ccd_softc *, int));
1999d7f7369SPoul-Henning Kamp static	void ccdintr __P((struct ccd_softc *, struct bio *));
200a56bb8a5SSatoshi Asami static	int ccdinit __P((struct ccddevice *, char **, struct proc *));
201a56bb8a5SSatoshi Asami static	int ccdlookup __P((char *, struct proc *p, struct vnode **));
2023bc746beSSatoshi Asami static	void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *,
2039d7f7369SPoul-Henning Kamp 		struct bio *, daddr_t, caddr_t, long));
204a56bb8a5SSatoshi Asami static	void ccdgetdisklabel __P((dev_t));
205a56bb8a5SSatoshi Asami static	void ccdmakedisklabel __P((struct ccd_softc *));
206a56bb8a5SSatoshi Asami static	int ccdlock __P((struct ccd_softc *));
207a56bb8a5SSatoshi Asami static	void ccdunlock __P((struct ccd_softc *));
208a56bb8a5SSatoshi Asami 
209a56bb8a5SSatoshi Asami #ifdef DEBUG
210a56bb8a5SSatoshi Asami static	void printiinfo __P((struct ccdiinfo *));
211a56bb8a5SSatoshi Asami #endif
212a56bb8a5SSatoshi Asami 
213a56bb8a5SSatoshi Asami /* Non-private for the benefit of libkvm. */
214a56bb8a5SSatoshi Asami struct	ccd_softc *ccd_softc;
215a56bb8a5SSatoshi Asami struct	ccddevice *ccddevs;
2161464240eSMatthew Dillon struct	ccdbuf *ccdfreebufs;
2171464240eSMatthew Dillon static	int numccdfreebufs;
218e2738b4fSPoul-Henning Kamp static	int numccd = 0;
219a56bb8a5SSatoshi Asami 
220a56bb8a5SSatoshi Asami /*
2211464240eSMatthew Dillon  * getccdbuf() -	Allocate and zero a ccd buffer.
2221464240eSMatthew Dillon  *
2231464240eSMatthew Dillon  *	This routine is called at splbio().
2241464240eSMatthew Dillon  */
2251464240eSMatthew Dillon 
2261464240eSMatthew Dillon static __inline
2271464240eSMatthew Dillon struct ccdbuf *
2281464240eSMatthew Dillon getccdbuf(struct ccdbuf *cpy)
2291464240eSMatthew Dillon {
2301464240eSMatthew Dillon 	struct ccdbuf *cbp;
2311464240eSMatthew Dillon 
2321464240eSMatthew Dillon 	/*
2331464240eSMatthew Dillon 	 * Allocate from freelist or malloc as necessary
2341464240eSMatthew Dillon 	 */
2351464240eSMatthew Dillon 	if ((cbp = ccdfreebufs) != NULL) {
2361464240eSMatthew Dillon 		ccdfreebufs = cbp->cb_freenext;
2371464240eSMatthew Dillon 		--numccdfreebufs;
2381464240eSMatthew Dillon 	} else {
2391464240eSMatthew Dillon 		cbp = malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK);
2401464240eSMatthew Dillon 	}
2411464240eSMatthew Dillon 
2421464240eSMatthew Dillon 	/*
2431464240eSMatthew Dillon 	 * Used by mirroring code
2441464240eSMatthew Dillon 	 */
2451464240eSMatthew Dillon 	if (cpy)
2461464240eSMatthew Dillon 		bcopy(cpy, cbp, sizeof(struct ccdbuf));
2471464240eSMatthew Dillon 	else
2481464240eSMatthew Dillon 		bzero(cbp, sizeof(struct ccdbuf));
2491464240eSMatthew Dillon 
2501464240eSMatthew Dillon 	/*
2519d7f7369SPoul-Henning Kamp 	 * independant struct bio initialization
2521464240eSMatthew Dillon 	 */
2531464240eSMatthew Dillon 
2541464240eSMatthew Dillon 	return(cbp);
2551464240eSMatthew Dillon }
2561464240eSMatthew Dillon 
2571464240eSMatthew Dillon /*
2581441456fSGreg Lehey  * putccdbuf() -	Free a ccd buffer.
2591464240eSMatthew Dillon  *
2601464240eSMatthew Dillon  *	This routine is called at splbio().
2611464240eSMatthew Dillon  */
2621464240eSMatthew Dillon 
2631464240eSMatthew Dillon static __inline
2641464240eSMatthew Dillon void
2651464240eSMatthew Dillon putccdbuf(struct ccdbuf *cbp)
2661464240eSMatthew Dillon {
26774427f90SMatthew Dillon 
2681464240eSMatthew Dillon 	if (numccdfreebufs < NCCDFREEHIWAT) {
2691464240eSMatthew Dillon 		cbp->cb_freenext = ccdfreebufs;
2701464240eSMatthew Dillon 		ccdfreebufs = cbp;
2711464240eSMatthew Dillon 		++numccdfreebufs;
2721464240eSMatthew Dillon 	} else {
2731464240eSMatthew Dillon 		free((caddr_t)cbp, M_DEVBUF);
2741464240eSMatthew Dillon 	}
2751464240eSMatthew Dillon }
2761464240eSMatthew Dillon 
2771464240eSMatthew Dillon 
2781464240eSMatthew Dillon /*
2790d88ef07SSatoshi Asami  * Number of blocks to untouched in front of a component partition.
2800d88ef07SSatoshi Asami  * This is to avoid violating its disklabel area when it starts at the
2810d88ef07SSatoshi Asami  * beginning of the slice.
2820d88ef07SSatoshi Asami  */
2831af0e025SSatoshi Asami #if !defined(CCD_OFFSET)
2840d88ef07SSatoshi Asami #define CCD_OFFSET 16
2851af0e025SSatoshi Asami #endif
2860d88ef07SSatoshi Asami 
2870d88ef07SSatoshi Asami /*
288a56bb8a5SSatoshi Asami  * Called by main() during pseudo-device attachment.  All we need
289e2a13e8cSSatoshi Asami  * to do is allocate enough space for devices to be configured later, and
290e2a13e8cSSatoshi Asami  * add devsw entries.
291a56bb8a5SSatoshi Asami  */
292e2738b4fSPoul-Henning Kamp static void
293b7b98418SPeter Wemm ccdattach()
294a56bb8a5SSatoshi Asami {
295a56bb8a5SSatoshi Asami 	int i;
296e2a13e8cSSatoshi Asami 	int num = NCCD;
297a56bb8a5SSatoshi Asami 
298e2a13e8cSSatoshi Asami 	if (num > 1)
299e2a13e8cSSatoshi Asami 		printf("ccd0-%d: Concatenated disk drivers\n", num-1);
300d8594dfbSSatoshi Asami 	else
301e2a13e8cSSatoshi Asami 		printf("ccd0: Concatenated disk driver\n");
302d8594dfbSSatoshi Asami 
303a56bb8a5SSatoshi Asami 	ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
304a56bb8a5SSatoshi Asami 	    M_DEVBUF, M_NOWAIT);
305a56bb8a5SSatoshi Asami 	ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice),
306a56bb8a5SSatoshi Asami 	    M_DEVBUF, M_NOWAIT);
307a56bb8a5SSatoshi Asami 	if ((ccd_softc == NULL) || (ccddevs == NULL)) {
308a56bb8a5SSatoshi Asami 		printf("WARNING: no memory for concatenated disks\n");
309a56bb8a5SSatoshi Asami 		if (ccd_softc != NULL)
310a56bb8a5SSatoshi Asami 			free(ccd_softc, M_DEVBUF);
311a56bb8a5SSatoshi Asami 		if (ccddevs != NULL)
312a56bb8a5SSatoshi Asami 			free(ccddevs, M_DEVBUF);
313e2a13e8cSSatoshi Asami 		return;
314a56bb8a5SSatoshi Asami 	}
315a56bb8a5SSatoshi Asami 	numccd = num;
316a56bb8a5SSatoshi Asami 	bzero(ccd_softc, num * sizeof(struct ccd_softc));
317a56bb8a5SSatoshi Asami 	bzero(ccddevs, num * sizeof(struct ccddevice));
318a56bb8a5SSatoshi Asami 
319d53dedeeSPoul-Henning Kamp 	cdevsw_add(&ccd_cdevsw);
320a56bb8a5SSatoshi Asami 	/* XXX: is this necessary? */
321a56bb8a5SSatoshi Asami 	for (i = 0; i < numccd; ++i)
322a56bb8a5SSatoshi Asami 		ccddevs[i].ccd_dk = -1;
323b7b98418SPeter Wemm }
324d8594dfbSSatoshi Asami 
325b7b98418SPeter Wemm static int
326b7b98418SPeter Wemm ccd_modevent(mod, type, data)
327b7b98418SPeter Wemm 	module_t mod;
328b7b98418SPeter Wemm 	int type;
329b7b98418SPeter Wemm 	void *data;
330b7b98418SPeter Wemm {
331b7b98418SPeter Wemm 	int error = 0;
332b7b98418SPeter Wemm 
333b7b98418SPeter Wemm 	switch (type) {
334b7b98418SPeter Wemm 	case MOD_LOAD:
335b7b98418SPeter Wemm 		ccdattach();
336b7b98418SPeter Wemm 		break;
337b7b98418SPeter Wemm 
338b7b98418SPeter Wemm 	case MOD_UNLOAD:
339b7b98418SPeter Wemm 		printf("ccd0: Unload not supported!\n");
340b7b98418SPeter Wemm 		error = EOPNOTSUPP;
341b7b98418SPeter Wemm 		break;
342b7b98418SPeter Wemm 
343b7b98418SPeter Wemm 	default:	/* MOD_SHUTDOWN etc */
344b7b98418SPeter Wemm 		break;
345e2a13e8cSSatoshi Asami 	}
346b7b98418SPeter Wemm 	return (error);
347e2a13e8cSSatoshi Asami }
348b7b98418SPeter Wemm 
349d53dedeeSPoul-Henning Kamp DEV_MODULE(ccd, ccd_modevent, NULL);
350a56bb8a5SSatoshi Asami 
351a56bb8a5SSatoshi Asami static int
352a56bb8a5SSatoshi Asami ccdinit(ccd, cpaths, p)
353a56bb8a5SSatoshi Asami 	struct ccddevice *ccd;
354a56bb8a5SSatoshi Asami 	char **cpaths;
355a56bb8a5SSatoshi Asami 	struct proc *p;
356a56bb8a5SSatoshi Asami {
3571464240eSMatthew Dillon 	struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
3581464240eSMatthew Dillon 	struct ccdcinfo *ci = NULL;	/* XXX */
3591464240eSMatthew Dillon 	size_t size;
3601464240eSMatthew Dillon 	int ix;
361a56bb8a5SSatoshi Asami 	struct vnode *vp;
362a56bb8a5SSatoshi Asami 	size_t minsize;
363a56bb8a5SSatoshi Asami 	int maxsecsize;
364a56bb8a5SSatoshi Asami 	struct partinfo dpart;
365a56bb8a5SSatoshi Asami 	struct ccdgeom *ccg = &cs->sc_geom;
366a56bb8a5SSatoshi Asami 	char tmppath[MAXPATHLEN];
3671464240eSMatthew Dillon 	int error = 0;
368a56bb8a5SSatoshi Asami 
369a56bb8a5SSatoshi Asami #ifdef DEBUG
370a56bb8a5SSatoshi Asami 	if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
371a56bb8a5SSatoshi Asami 		printf("ccdinit: unit %d\n", ccd->ccd_unit);
372a56bb8a5SSatoshi Asami #endif
373a56bb8a5SSatoshi Asami 
374a56bb8a5SSatoshi Asami 	cs->sc_size = 0;
375a56bb8a5SSatoshi Asami 	cs->sc_ileave = ccd->ccd_interleave;
376a56bb8a5SSatoshi Asami 	cs->sc_nccdisks = ccd->ccd_ndev;
377a56bb8a5SSatoshi Asami 
378a56bb8a5SSatoshi Asami 	/* Allocate space for the component info. */
379a56bb8a5SSatoshi Asami 	cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
380a56bb8a5SSatoshi Asami 	    M_DEVBUF, M_WAITOK);
381a56bb8a5SSatoshi Asami 
382a56bb8a5SSatoshi Asami 	/*
383a56bb8a5SSatoshi Asami 	 * Verify that each component piece exists and record
384a56bb8a5SSatoshi Asami 	 * relevant information about it.
385a56bb8a5SSatoshi Asami 	 */
386a56bb8a5SSatoshi Asami 	maxsecsize = 0;
387a56bb8a5SSatoshi Asami 	minsize = 0;
388a56bb8a5SSatoshi Asami 	for (ix = 0; ix < cs->sc_nccdisks; ix++) {
389a56bb8a5SSatoshi Asami 		vp = ccd->ccd_vpp[ix];
390a56bb8a5SSatoshi Asami 		ci = &cs->sc_cinfo[ix];
391a56bb8a5SSatoshi Asami 		ci->ci_vp = vp;
392a56bb8a5SSatoshi Asami 
393a56bb8a5SSatoshi Asami 		/*
394a56bb8a5SSatoshi Asami 		 * Copy in the pathname of the component.
395a56bb8a5SSatoshi Asami 		 */
396a56bb8a5SSatoshi Asami 		bzero(tmppath, sizeof(tmppath));	/* sanity */
397b4e36adfSMatthew Dillon 		if ((error = copyinstr(cpaths[ix], tmppath,
398b4e36adfSMatthew Dillon 		    MAXPATHLEN, &ci->ci_pathlen)) != 0) {
399a56bb8a5SSatoshi Asami #ifdef DEBUG
400a56bb8a5SSatoshi Asami 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
401a56bb8a5SSatoshi Asami 				printf("ccd%d: can't copy path, error = %d\n",
402a56bb8a5SSatoshi Asami 				    ccd->ccd_unit, error);
403a56bb8a5SSatoshi Asami #endif
4041464240eSMatthew Dillon 			goto fail;
405a56bb8a5SSatoshi Asami 		}
406a56bb8a5SSatoshi Asami 		ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
407a56bb8a5SSatoshi Asami 		bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
408a56bb8a5SSatoshi Asami 
409684adedeSPoul-Henning Kamp 		ci->ci_dev = vn_todev(vp);
410a56bb8a5SSatoshi Asami 
411a56bb8a5SSatoshi Asami 		/*
412a56bb8a5SSatoshi Asami 		 * Get partition information for the component.
413a56bb8a5SSatoshi Asami 		 */
414b4e36adfSMatthew Dillon 		if ((error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
415b4e36adfSMatthew Dillon 		    FREAD, p->p_ucred, p)) != 0) {
416a56bb8a5SSatoshi Asami #ifdef DEBUG
417a56bb8a5SSatoshi Asami 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
418a56bb8a5SSatoshi Asami 				 printf("ccd%d: %s: ioctl failed, error = %d\n",
419a56bb8a5SSatoshi Asami 				     ccd->ccd_unit, ci->ci_path, error);
420a56bb8a5SSatoshi Asami #endif
4211464240eSMatthew Dillon 			goto fail;
422a56bb8a5SSatoshi Asami 		}
423a56bb8a5SSatoshi Asami 		if (dpart.part->p_fstype == FS_BSDFFS) {
424a56bb8a5SSatoshi Asami 			maxsecsize =
425a56bb8a5SSatoshi Asami 			    ((dpart.disklab->d_secsize > maxsecsize) ?
426a56bb8a5SSatoshi Asami 			    dpart.disklab->d_secsize : maxsecsize);
4270d88ef07SSatoshi Asami 			size = dpart.part->p_size - CCD_OFFSET;
428a56bb8a5SSatoshi Asami 		} else {
429a56bb8a5SSatoshi Asami #ifdef DEBUG
430a56bb8a5SSatoshi Asami 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
431a56bb8a5SSatoshi Asami 				printf("ccd%d: %s: incorrect partition type\n",
432a56bb8a5SSatoshi Asami 				    ccd->ccd_unit, ci->ci_path);
433a56bb8a5SSatoshi Asami #endif
4341464240eSMatthew Dillon 			error = EFTYPE;
4351464240eSMatthew Dillon 			goto fail;
436a56bb8a5SSatoshi Asami 		}
437a56bb8a5SSatoshi Asami 
438a56bb8a5SSatoshi Asami 		/*
439a56bb8a5SSatoshi Asami 		 * Calculate the size, truncating to an interleave
440a56bb8a5SSatoshi Asami 		 * boundary if necessary.
441a56bb8a5SSatoshi Asami 		 */
442a56bb8a5SSatoshi Asami 
443a56bb8a5SSatoshi Asami 		if (cs->sc_ileave > 1)
444a56bb8a5SSatoshi Asami 			size -= size % cs->sc_ileave;
445a56bb8a5SSatoshi Asami 
446a56bb8a5SSatoshi Asami 		if (size == 0) {
447a56bb8a5SSatoshi Asami #ifdef DEBUG
448a56bb8a5SSatoshi Asami 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
449a56bb8a5SSatoshi Asami 				printf("ccd%d: %s: size == 0\n",
450a56bb8a5SSatoshi Asami 				    ccd->ccd_unit, ci->ci_path);
451a56bb8a5SSatoshi Asami #endif
4521464240eSMatthew Dillon 			error = ENODEV;
4531464240eSMatthew Dillon 			goto fail;
454a56bb8a5SSatoshi Asami 		}
455a56bb8a5SSatoshi Asami 
456a56bb8a5SSatoshi Asami 		if (minsize == 0 || size < minsize)
457a56bb8a5SSatoshi Asami 			minsize = size;
458a56bb8a5SSatoshi Asami 		ci->ci_size = size;
459a56bb8a5SSatoshi Asami 		cs->sc_size += size;
460a56bb8a5SSatoshi Asami 	}
461a56bb8a5SSatoshi Asami 
462a56bb8a5SSatoshi Asami 	/*
463a56bb8a5SSatoshi Asami 	 * Don't allow the interleave to be smaller than
464a56bb8a5SSatoshi Asami 	 * the biggest component sector.
465a56bb8a5SSatoshi Asami 	 */
466a56bb8a5SSatoshi Asami 	if ((cs->sc_ileave > 0) &&
467a56bb8a5SSatoshi Asami 	    (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
468a56bb8a5SSatoshi Asami #ifdef DEBUG
469a56bb8a5SSatoshi Asami 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
470a56bb8a5SSatoshi Asami 			printf("ccd%d: interleave must be at least %d\n",
471a56bb8a5SSatoshi Asami 			    ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
472a56bb8a5SSatoshi Asami #endif
4731464240eSMatthew Dillon 		error = EINVAL;
4741464240eSMatthew Dillon 		goto fail;
475a56bb8a5SSatoshi Asami 	}
476a56bb8a5SSatoshi Asami 
477a56bb8a5SSatoshi Asami 	/*
478a56bb8a5SSatoshi Asami 	 * If uniform interleave is desired set all sizes to that of
4791464240eSMatthew Dillon 	 * the smallest component.  This will guarentee that a single
4801464240eSMatthew Dillon 	 * interleave table is generated.
4811464240eSMatthew Dillon 	 *
4821464240eSMatthew Dillon 	 * Lost space must be taken into account when calculating the
4831464240eSMatthew Dillon 	 * overall size.  Half the space is lost when CCDF_MIRROR is
4841464240eSMatthew Dillon 	 * specified.  One disk is lost when CCDF_PARITY is specified.
485a56bb8a5SSatoshi Asami 	 */
486a56bb8a5SSatoshi Asami 	if (ccd->ccd_flags & CCDF_UNIFORM) {
487a56bb8a5SSatoshi Asami 		for (ci = cs->sc_cinfo;
4881464240eSMatthew Dillon 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
489a56bb8a5SSatoshi Asami 			ci->ci_size = minsize;
4901464240eSMatthew Dillon 		}
49109b59204SSatoshi Asami 		if (ccd->ccd_flags & CCDF_MIRROR) {
49234f35216SSatoshi Asami 			/*
49334f35216SSatoshi Asami 			 * Check to see if an even number of components
4941464240eSMatthew Dillon 			 * have been specified.  The interleave must also
4951464240eSMatthew Dillon 			 * be non-zero in order for us to be able to
4961464240eSMatthew Dillon 			 * guarentee the topology.
49734f35216SSatoshi Asami 			 */
49809b59204SSatoshi Asami 			if (cs->sc_nccdisks % 2) {
49934f35216SSatoshi Asami 				printf("ccd%d: mirroring requires an even number of disks\n", ccd->ccd_unit );
5001464240eSMatthew Dillon 				error = EINVAL;
5011464240eSMatthew Dillon 				goto fail;
50234f35216SSatoshi Asami 			}
5031464240eSMatthew Dillon 			if (cs->sc_ileave == 0) {
5041464240eSMatthew Dillon 				printf("ccd%d: an interleave must be specified when mirroring\n", ccd->ccd_unit);
5051464240eSMatthew Dillon 				error = EINVAL;
5061464240eSMatthew Dillon 				goto fail;
50709b59204SSatoshi Asami 			}
50809b59204SSatoshi Asami 			cs->sc_size = (cs->sc_nccdisks/2) * minsize;
5091464240eSMatthew Dillon 		} else if (ccd->ccd_flags & CCDF_PARITY) {
5107ecb65faSSatoshi Asami 			cs->sc_size = (cs->sc_nccdisks-1) * minsize;
5111464240eSMatthew Dillon 		} else {
5121464240eSMatthew Dillon 			if (cs->sc_ileave == 0) {
5131464240eSMatthew Dillon 				printf("ccd%d: an interleave must be specified when using parity\n", ccd->ccd_unit);
5141464240eSMatthew Dillon 				error = EINVAL;
5151464240eSMatthew Dillon 				goto fail;
5161464240eSMatthew Dillon 			}
517a56bb8a5SSatoshi Asami 			cs->sc_size = cs->sc_nccdisks * minsize;
518a56bb8a5SSatoshi Asami 		}
5191464240eSMatthew Dillon 	}
520a56bb8a5SSatoshi Asami 
521a56bb8a5SSatoshi Asami 	/*
522a56bb8a5SSatoshi Asami 	 * Construct the interleave table.
523a56bb8a5SSatoshi Asami 	 */
524a56bb8a5SSatoshi Asami 	ccdinterleave(cs, ccd->ccd_unit);
525a56bb8a5SSatoshi Asami 
526a56bb8a5SSatoshi Asami 	/*
527a56bb8a5SSatoshi Asami 	 * Create pseudo-geometry based on 1MB cylinders.  It's
528a56bb8a5SSatoshi Asami 	 * pretty close.
529a56bb8a5SSatoshi Asami 	 */
530e59f3105SSøren Schmidt 	ccg->ccg_secsize = maxsecsize;
531a56bb8a5SSatoshi Asami 	ccg->ccg_ntracks = 1;
532e322ec4cSMatthew Dillon 	ccg->ccg_nsectors = 1024 * 1024 / ccg->ccg_secsize;
533a56bb8a5SSatoshi Asami 	ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
534a56bb8a5SSatoshi Asami 
535b2dfb1f9SJustin T. Gibbs 	/*
536b2dfb1f9SJustin T. Gibbs 	 * Add an devstat entry for this device.
537b2dfb1f9SJustin T. Gibbs 	 */
538b2dfb1f9SJustin T. Gibbs 	devstat_add_entry(&cs->device_stats, "ccd", ccd->ccd_unit,
539b2dfb1f9SJustin T. Gibbs 			  ccg->ccg_secsize, DEVSTAT_ALL_SUPPORTED,
54086b2c846SKenneth D. Merry 			  DEVSTAT_TYPE_STORARRAY |DEVSTAT_TYPE_IF_OTHER,
54186b2c846SKenneth D. Merry 			  DEVSTAT_PRIORITY_ARRAY);
542a56bb8a5SSatoshi Asami 
543a56bb8a5SSatoshi Asami 	cs->sc_flags |= CCDF_INITED;
544a56bb8a5SSatoshi Asami 	cs->sc_cflags = ccd->ccd_flags;	/* So we can find out later... */
545a56bb8a5SSatoshi Asami 	cs->sc_unit = ccd->ccd_unit;
546a56bb8a5SSatoshi Asami 	return (0);
5471464240eSMatthew Dillon fail:
5481464240eSMatthew Dillon 	while (ci > cs->sc_cinfo) {
5491464240eSMatthew Dillon 		ci--;
5501464240eSMatthew Dillon 		free(ci->ci_path, M_DEVBUF);
5511464240eSMatthew Dillon 	}
5521464240eSMatthew Dillon 	free(cs->sc_cinfo, M_DEVBUF);
5531464240eSMatthew Dillon 	return (error);
554a56bb8a5SSatoshi Asami }
555a56bb8a5SSatoshi Asami 
556a56bb8a5SSatoshi Asami static void
557a56bb8a5SSatoshi Asami ccdinterleave(cs, unit)
5581464240eSMatthew Dillon 	struct ccd_softc *cs;
559a56bb8a5SSatoshi Asami 	int unit;
560a56bb8a5SSatoshi Asami {
5611464240eSMatthew Dillon 	struct ccdcinfo *ci, *smallci;
5621464240eSMatthew Dillon 	struct ccdiinfo *ii;
5631464240eSMatthew Dillon 	daddr_t bn, lbn;
5641464240eSMatthew Dillon 	int ix;
565a56bb8a5SSatoshi Asami 	u_long size;
566a56bb8a5SSatoshi Asami 
567a56bb8a5SSatoshi Asami #ifdef DEBUG
568a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_INIT)
569a56bb8a5SSatoshi Asami 		printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
570a56bb8a5SSatoshi Asami #endif
5711464240eSMatthew Dillon 
572a56bb8a5SSatoshi Asami 	/*
5731464240eSMatthew Dillon 	 * Allocate an interleave table.  The worst case occurs when each
5741464240eSMatthew Dillon 	 * of N disks is of a different size, resulting in N interleave
5751464240eSMatthew Dillon 	 * tables.
5761464240eSMatthew Dillon 	 *
577a56bb8a5SSatoshi Asami 	 * Chances are this is too big, but we don't care.
578a56bb8a5SSatoshi Asami 	 */
579a56bb8a5SSatoshi Asami 	size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
580a56bb8a5SSatoshi Asami 	cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
581a56bb8a5SSatoshi Asami 	bzero((caddr_t)cs->sc_itable, size);
582a56bb8a5SSatoshi Asami 
583a56bb8a5SSatoshi Asami 	/*
584a56bb8a5SSatoshi Asami 	 * Trivial case: no interleave (actually interleave of disk size).
585a56bb8a5SSatoshi Asami 	 * Each table entry represents a single component in its entirety.
5861464240eSMatthew Dillon 	 *
5871464240eSMatthew Dillon 	 * An interleave of 0 may not be used with a mirror or parity setup.
588a56bb8a5SSatoshi Asami 	 */
589a56bb8a5SSatoshi Asami 	if (cs->sc_ileave == 0) {
590a56bb8a5SSatoshi Asami 		bn = 0;
591a56bb8a5SSatoshi Asami 		ii = cs->sc_itable;
592a56bb8a5SSatoshi Asami 
593a56bb8a5SSatoshi Asami 		for (ix = 0; ix < cs->sc_nccdisks; ix++) {
594a56bb8a5SSatoshi Asami 			/* Allocate space for ii_index. */
595a56bb8a5SSatoshi Asami 			ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
596a56bb8a5SSatoshi Asami 			ii->ii_ndisk = 1;
597a56bb8a5SSatoshi Asami 			ii->ii_startblk = bn;
598a56bb8a5SSatoshi Asami 			ii->ii_startoff = 0;
599a56bb8a5SSatoshi Asami 			ii->ii_index[0] = ix;
600a56bb8a5SSatoshi Asami 			bn += cs->sc_cinfo[ix].ci_size;
601a56bb8a5SSatoshi Asami 			ii++;
602a56bb8a5SSatoshi Asami 		}
603a56bb8a5SSatoshi Asami 		ii->ii_ndisk = 0;
604a56bb8a5SSatoshi Asami #ifdef DEBUG
605a56bb8a5SSatoshi Asami 		if (ccddebug & CCDB_INIT)
606a56bb8a5SSatoshi Asami 			printiinfo(cs->sc_itable);
607a56bb8a5SSatoshi Asami #endif
608a56bb8a5SSatoshi Asami 		return;
609a56bb8a5SSatoshi Asami 	}
610a56bb8a5SSatoshi Asami 
611a56bb8a5SSatoshi Asami 	/*
612a56bb8a5SSatoshi Asami 	 * The following isn't fast or pretty; it doesn't have to be.
613a56bb8a5SSatoshi Asami 	 */
614a56bb8a5SSatoshi Asami 	size = 0;
615a56bb8a5SSatoshi Asami 	bn = lbn = 0;
616a56bb8a5SSatoshi Asami 	for (ii = cs->sc_itable; ; ii++) {
6171464240eSMatthew Dillon 		/*
6181464240eSMatthew Dillon 		 * Allocate space for ii_index.  We might allocate more then
6191464240eSMatthew Dillon 		 * we use.
6201464240eSMatthew Dillon 		 */
621a56bb8a5SSatoshi Asami 		ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
622a56bb8a5SSatoshi Asami 		    M_DEVBUF, M_WAITOK);
623a56bb8a5SSatoshi Asami 
624a56bb8a5SSatoshi Asami 		/*
625a56bb8a5SSatoshi Asami 		 * Locate the smallest of the remaining components
626a56bb8a5SSatoshi Asami 		 */
627a56bb8a5SSatoshi Asami 		smallci = NULL;
6281464240eSMatthew Dillon 		for (ci = cs->sc_cinfo; ci < &cs->sc_cinfo[cs->sc_nccdisks];
6291464240eSMatthew Dillon 		    ci++) {
630a56bb8a5SSatoshi Asami 			if (ci->ci_size > size &&
631a56bb8a5SSatoshi Asami 			    (smallci == NULL ||
6321464240eSMatthew Dillon 			     ci->ci_size < smallci->ci_size)) {
633a56bb8a5SSatoshi Asami 				smallci = ci;
6341464240eSMatthew Dillon 			}
6351464240eSMatthew Dillon 		}
636a56bb8a5SSatoshi Asami 
637a56bb8a5SSatoshi Asami 		/*
638a56bb8a5SSatoshi Asami 		 * Nobody left, all done
639a56bb8a5SSatoshi Asami 		 */
640a56bb8a5SSatoshi Asami 		if (smallci == NULL) {
641a56bb8a5SSatoshi Asami 			ii->ii_ndisk = 0;
642a56bb8a5SSatoshi Asami 			break;
643a56bb8a5SSatoshi Asami 		}
644a56bb8a5SSatoshi Asami 
645a56bb8a5SSatoshi Asami 		/*
6461464240eSMatthew Dillon 		 * Record starting logical block using an sc_ileave blocksize.
647a56bb8a5SSatoshi Asami 		 */
648a56bb8a5SSatoshi Asami 		ii->ii_startblk = bn / cs->sc_ileave;
6491464240eSMatthew Dillon 
6501464240eSMatthew Dillon 		/*
6511464240eSMatthew Dillon 		 * Record starting comopnent block using an sc_ileave
6521464240eSMatthew Dillon 		 * blocksize.  This value is relative to the beginning of
6531464240eSMatthew Dillon 		 * a component disk.
6541464240eSMatthew Dillon 		 */
655a56bb8a5SSatoshi Asami 		ii->ii_startoff = lbn;
656a56bb8a5SSatoshi Asami 
657a56bb8a5SSatoshi Asami 		/*
658a56bb8a5SSatoshi Asami 		 * Determine how many disks take part in this interleave
659a56bb8a5SSatoshi Asami 		 * and record their indices.
660a56bb8a5SSatoshi Asami 		 */
661a56bb8a5SSatoshi Asami 		ix = 0;
662a56bb8a5SSatoshi Asami 		for (ci = cs->sc_cinfo;
6631464240eSMatthew Dillon 		    ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) {
6641464240eSMatthew Dillon 			if (ci->ci_size >= smallci->ci_size) {
665a56bb8a5SSatoshi Asami 				ii->ii_index[ix++] = ci - cs->sc_cinfo;
6661464240eSMatthew Dillon 			}
6671464240eSMatthew Dillon 		}
668a56bb8a5SSatoshi Asami 		ii->ii_ndisk = ix;
669a56bb8a5SSatoshi Asami 		bn += ix * (smallci->ci_size - size);
670a56bb8a5SSatoshi Asami 		lbn = smallci->ci_size / cs->sc_ileave;
671a56bb8a5SSatoshi Asami 		size = smallci->ci_size;
672a56bb8a5SSatoshi Asami 	}
673a56bb8a5SSatoshi Asami #ifdef DEBUG
674a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_INIT)
675a56bb8a5SSatoshi Asami 		printiinfo(cs->sc_itable);
676a56bb8a5SSatoshi Asami #endif
677a56bb8a5SSatoshi Asami }
678a56bb8a5SSatoshi Asami 
679a56bb8a5SSatoshi Asami /* ARGSUSED */
680e2738b4fSPoul-Henning Kamp static int
681a56bb8a5SSatoshi Asami ccdopen(dev, flags, fmt, p)
682a56bb8a5SSatoshi Asami 	dev_t dev;
683a56bb8a5SSatoshi Asami 	int flags, fmt;
684a56bb8a5SSatoshi Asami 	struct proc *p;
685a56bb8a5SSatoshi Asami {
686a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
687a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
688a56bb8a5SSatoshi Asami 	struct disklabel *lp;
689a56bb8a5SSatoshi Asami 	int error = 0, part, pmask;
690a56bb8a5SSatoshi Asami 
691a56bb8a5SSatoshi Asami #ifdef DEBUG
692a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
693a56bb8a5SSatoshi Asami 		printf("ccdopen(%x, %x)\n", dev, flags);
694a56bb8a5SSatoshi Asami #endif
695a56bb8a5SSatoshi Asami 	if (unit >= numccd)
696a56bb8a5SSatoshi Asami 		return (ENXIO);
697a56bb8a5SSatoshi Asami 	cs = &ccd_softc[unit];
698a56bb8a5SSatoshi Asami 
699b4e36adfSMatthew Dillon 	if ((error = ccdlock(cs)) != 0)
700a56bb8a5SSatoshi Asami 		return (error);
701a56bb8a5SSatoshi Asami 
7026cc5a722SPoul-Henning Kamp 	lp = &cs->sc_label;
703a56bb8a5SSatoshi Asami 
704d8594dfbSSatoshi Asami 	part = ccdpart(dev);
705a56bb8a5SSatoshi Asami 	pmask = (1 << part);
706a56bb8a5SSatoshi Asami 
707a56bb8a5SSatoshi Asami 	/*
708a56bb8a5SSatoshi Asami 	 * If we're initialized, check to see if there are any other
709a56bb8a5SSatoshi Asami 	 * open partitions.  If not, then it's safe to update
710a56bb8a5SSatoshi Asami 	 * the in-core disklabel.
711a56bb8a5SSatoshi Asami 	 */
7126cc5a722SPoul-Henning Kamp 	if ((cs->sc_flags & CCDF_INITED) && (cs->sc_openmask == 0))
713a56bb8a5SSatoshi Asami 		ccdgetdisklabel(dev);
714a56bb8a5SSatoshi Asami 
715a56bb8a5SSatoshi Asami 	/* Check that the partition exists. */
7167d15435cSJordan K. Hubbard 	if (part != RAW_PART && ((part >= lp->d_npartitions) ||
717a56bb8a5SSatoshi Asami 	    (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
718a56bb8a5SSatoshi Asami 		error = ENXIO;
719a56bb8a5SSatoshi Asami 		goto done;
720a56bb8a5SSatoshi Asami 	}
721a56bb8a5SSatoshi Asami 
722af8862e4SPoul-Henning Kamp 	cs->sc_openmask |= pmask;
723a56bb8a5SSatoshi Asami  done:
724a56bb8a5SSatoshi Asami 	ccdunlock(cs);
725a56bb8a5SSatoshi Asami 	return (0);
726a56bb8a5SSatoshi Asami }
727a56bb8a5SSatoshi Asami 
728a56bb8a5SSatoshi Asami /* ARGSUSED */
729e2738b4fSPoul-Henning Kamp static int
730a56bb8a5SSatoshi Asami ccdclose(dev, flags, fmt, p)
731a56bb8a5SSatoshi Asami 	dev_t dev;
732a56bb8a5SSatoshi Asami 	int flags, fmt;
733a56bb8a5SSatoshi Asami 	struct proc *p;
734a56bb8a5SSatoshi Asami {
735a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
736a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
737a56bb8a5SSatoshi Asami 	int error = 0, part;
738a56bb8a5SSatoshi Asami 
739a56bb8a5SSatoshi Asami #ifdef DEBUG
740a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
741a56bb8a5SSatoshi Asami 		printf("ccdclose(%x, %x)\n", dev, flags);
742a56bb8a5SSatoshi Asami #endif
743a56bb8a5SSatoshi Asami 
744a56bb8a5SSatoshi Asami 	if (unit >= numccd)
745a56bb8a5SSatoshi Asami 		return (ENXIO);
746a56bb8a5SSatoshi Asami 	cs = &ccd_softc[unit];
747a56bb8a5SSatoshi Asami 
748b4e36adfSMatthew Dillon 	if ((error = ccdlock(cs)) != 0)
749a56bb8a5SSatoshi Asami 		return (error);
750a56bb8a5SSatoshi Asami 
751d8594dfbSSatoshi Asami 	part = ccdpart(dev);
752a56bb8a5SSatoshi Asami 
753a56bb8a5SSatoshi Asami 	/* ...that much closer to allowing unconfiguration... */
754af8862e4SPoul-Henning Kamp 	cs->sc_openmask &= ~(1 << part);
755a56bb8a5SSatoshi Asami 	ccdunlock(cs);
756a56bb8a5SSatoshi Asami 	return (0);
757a56bb8a5SSatoshi Asami }
758a56bb8a5SSatoshi Asami 
759e2738b4fSPoul-Henning Kamp static void
7609d7f7369SPoul-Henning Kamp ccdstrategy(bp)
7619d7f7369SPoul-Henning Kamp 	struct bio *bp;
762a56bb8a5SSatoshi Asami {
7639d7f7369SPoul-Henning Kamp 	int unit = ccdunit(bp->bio_dev);
7641464240eSMatthew Dillon 	struct ccd_softc *cs = &ccd_softc[unit];
7651464240eSMatthew Dillon 	int s;
766a56bb8a5SSatoshi Asami 	int wlabel;
767a56bb8a5SSatoshi Asami 	struct disklabel *lp;
768a56bb8a5SSatoshi Asami 
769a56bb8a5SSatoshi Asami #ifdef DEBUG
770a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
771a56bb8a5SSatoshi Asami 		printf("ccdstrategy(%x): unit %d\n", bp, unit);
772a56bb8a5SSatoshi Asami #endif
773a56bb8a5SSatoshi Asami 	if ((cs->sc_flags & CCDF_INITED) == 0) {
7749d7f7369SPoul-Henning Kamp 		bp->bio_error = ENXIO;
7759d7f7369SPoul-Henning Kamp 		bp->bio_flags |= BIO_ERROR;
776a56bb8a5SSatoshi Asami 		goto done;
777a56bb8a5SSatoshi Asami 	}
778a56bb8a5SSatoshi Asami 
779a56bb8a5SSatoshi Asami 	/* If it's a nil transfer, wake up the top half now. */
7809d7f7369SPoul-Henning Kamp 	if (bp->bio_bcount == 0)
781a56bb8a5SSatoshi Asami 		goto done;
782a56bb8a5SSatoshi Asami 
7836cc5a722SPoul-Henning Kamp 	lp = &cs->sc_label;
784a56bb8a5SSatoshi Asami 
785a56bb8a5SSatoshi Asami 	/*
786a56bb8a5SSatoshi Asami 	 * Do bounds checking and adjust transfer.  If there's an
787a56bb8a5SSatoshi Asami 	 * error, the bounds check will flag that for us.
788a56bb8a5SSatoshi Asami 	 */
789a56bb8a5SSatoshi Asami 	wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
7909d7f7369SPoul-Henning Kamp 	if (ccdpart(bp->bio_dev) != RAW_PART) {
7919d7f7369SPoul-Henning Kamp 		if (bounds_check_with_label(bp, lp, wlabel) <= 0)
792a56bb8a5SSatoshi Asami 			goto done;
79374427f90SMatthew Dillon 	} else {
79474427f90SMatthew Dillon 		int pbn;        /* in sc_secsize chunks */
79574427f90SMatthew Dillon 		long sz;        /* in sc_secsize chunks */
79674427f90SMatthew Dillon 
7979d7f7369SPoul-Henning Kamp 		pbn = bp->bio_blkno / (cs->sc_geom.ccg_secsize / DEV_BSIZE);
7989d7f7369SPoul-Henning Kamp 		sz = howmany(bp->bio_bcount, cs->sc_geom.ccg_secsize);
79974427f90SMatthew Dillon 
80074427f90SMatthew Dillon 		/*
80174427f90SMatthew Dillon 		 * If out of bounds return an error. If at the EOF point,
80274427f90SMatthew Dillon 		 * simply read or write less.
80374427f90SMatthew Dillon 		 */
80474427f90SMatthew Dillon 
80574427f90SMatthew Dillon 		if (pbn < 0 || pbn >= cs->sc_size) {
8069d7f7369SPoul-Henning Kamp 			bp->bio_resid = bp->bio_bcount;
80774427f90SMatthew Dillon 			if (pbn != cs->sc_size) {
8089d7f7369SPoul-Henning Kamp 				bp->bio_error = EINVAL;
8099d7f7369SPoul-Henning Kamp 				bp->bio_flags |= BIO_ERROR;
81074427f90SMatthew Dillon 			}
81174427f90SMatthew Dillon 			goto done;
81274427f90SMatthew Dillon 		}
81374427f90SMatthew Dillon 
81474427f90SMatthew Dillon 		/*
81574427f90SMatthew Dillon 		 * If the request crosses EOF, truncate the request.
81674427f90SMatthew Dillon 		 */
81774427f90SMatthew Dillon 		if (pbn + sz > cs->sc_size) {
8189d7f7369SPoul-Henning Kamp 			bp->bio_bcount = (cs->sc_size - pbn) *
81974427f90SMatthew Dillon 			    cs->sc_geom.ccg_secsize;
82074427f90SMatthew Dillon 		}
82174427f90SMatthew Dillon 	}
822a56bb8a5SSatoshi Asami 
8239d7f7369SPoul-Henning Kamp 	bp->bio_resid = bp->bio_bcount;
824a56bb8a5SSatoshi Asami 
825a56bb8a5SSatoshi Asami 	/*
826a56bb8a5SSatoshi Asami 	 * "Start" the unit.
827a56bb8a5SSatoshi Asami 	 */
828a56bb8a5SSatoshi Asami 	s = splbio();
829a56bb8a5SSatoshi Asami 	ccdstart(cs, bp);
830a56bb8a5SSatoshi Asami 	splx(s);
831a56bb8a5SSatoshi Asami 	return;
832a56bb8a5SSatoshi Asami done:
8339d7f7369SPoul-Henning Kamp 	biodone(bp);
834a56bb8a5SSatoshi Asami }
835a56bb8a5SSatoshi Asami 
836a56bb8a5SSatoshi Asami static void
837a56bb8a5SSatoshi Asami ccdstart(cs, bp)
8381464240eSMatthew Dillon 	struct ccd_softc *cs;
8399d7f7369SPoul-Henning Kamp 	struct bio *bp;
840a56bb8a5SSatoshi Asami {
8411464240eSMatthew Dillon 	long bcount, rcount;
8423bc746beSSatoshi Asami 	struct ccdbuf *cbp[4];
8433bc746beSSatoshi Asami 	/* XXX! : 2 reads and 2 writes for RAID 4/5 */
844a56bb8a5SSatoshi Asami 	caddr_t addr;
845a56bb8a5SSatoshi Asami 	daddr_t bn;
846a56bb8a5SSatoshi Asami 	struct partition *pp;
847a56bb8a5SSatoshi Asami 
848a56bb8a5SSatoshi Asami #ifdef DEBUG
849a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
850a56bb8a5SSatoshi Asami 		printf("ccdstart(%x, %x)\n", cs, bp);
851a56bb8a5SSatoshi Asami #endif
852a56bb8a5SSatoshi Asami 
853b2dfb1f9SJustin T. Gibbs 	/* Record the transaction start  */
854b2dfb1f9SJustin T. Gibbs 	devstat_start_transaction(&cs->device_stats);
855a56bb8a5SSatoshi Asami 
856a56bb8a5SSatoshi Asami 	/*
857a56bb8a5SSatoshi Asami 	 * Translate the partition-relative block number to an absolute.
858a56bb8a5SSatoshi Asami 	 */
8599d7f7369SPoul-Henning Kamp 	bn = bp->bio_blkno;
8609d7f7369SPoul-Henning Kamp 	if (ccdpart(bp->bio_dev) != RAW_PART) {
8619d7f7369SPoul-Henning Kamp 		pp = &cs->sc_label.d_partitions[ccdpart(bp->bio_dev)];
862a56bb8a5SSatoshi Asami 		bn += pp->p_offset;
863a56bb8a5SSatoshi Asami 	}
864a56bb8a5SSatoshi Asami 
865a56bb8a5SSatoshi Asami 	/*
866a56bb8a5SSatoshi Asami 	 * Allocate component buffers and fire off the requests
867a56bb8a5SSatoshi Asami 	 */
8689d7f7369SPoul-Henning Kamp 	addr = bp->bio_data;
8699d7f7369SPoul-Henning Kamp 	for (bcount = bp->bio_bcount; bcount > 0; bcount -= rcount) {
8703bc746beSSatoshi Asami 		ccdbuffer(cbp, cs, bp, bn, addr, bcount);
8719d7f7369SPoul-Henning Kamp 		rcount = cbp[0]->cb_buf.bio_bcount;
8721464240eSMatthew Dillon 
8731464240eSMatthew Dillon 		if (cs->sc_cflags & CCDF_MIRROR) {
8741464240eSMatthew Dillon 			/*
8751464240eSMatthew Dillon 			 * Mirroring.  Writes go to both disks, reads are
8761464240eSMatthew Dillon 			 * taken from whichever disk seems most appropriate.
8771464240eSMatthew Dillon 			 *
8781464240eSMatthew Dillon 			 * We attempt to localize reads to the disk whos arm
8791464240eSMatthew Dillon 			 * is nearest the read request.  We ignore seeks due
8801464240eSMatthew Dillon 			 * to writes when making this determination and we
8811464240eSMatthew Dillon 			 * also try to avoid hogging.
8821464240eSMatthew Dillon 			 */
8839d7f7369SPoul-Henning Kamp 			if (cbp[0]->cb_buf.bio_cmd == BIO_WRITE) {
8849d7f7369SPoul-Henning Kamp 				BIO_STRATEGY(&cbp[0]->cb_buf, 0);
8859d7f7369SPoul-Henning Kamp 				BIO_STRATEGY(&cbp[1]->cb_buf, 0);
8861464240eSMatthew Dillon 			} else {
8871464240eSMatthew Dillon 				int pick = cs->sc_pick;
8881464240eSMatthew Dillon 				daddr_t range = cs->sc_size / 16;
8891464240eSMatthew Dillon 
8901464240eSMatthew Dillon 				if (bn < cs->sc_blk[pick] - range ||
8911464240eSMatthew Dillon 				    bn > cs->sc_blk[pick] + range
8921464240eSMatthew Dillon 				) {
8931464240eSMatthew Dillon 					cs->sc_pick = pick = 1 - pick;
8941464240eSMatthew Dillon 				}
8951464240eSMatthew Dillon 				cs->sc_blk[pick] = bn + btodb(rcount);
8969d7f7369SPoul-Henning Kamp 				BIO_STRATEGY(&cbp[pick]->cb_buf, 0);
8971464240eSMatthew Dillon 			}
8981464240eSMatthew Dillon 		} else {
8991464240eSMatthew Dillon 			/*
9001464240eSMatthew Dillon 			 * Not mirroring
9011464240eSMatthew Dillon 			 */
9029d7f7369SPoul-Henning Kamp 			BIO_STRATEGY(&cbp[0]->cb_buf, 0);
9033bc746beSSatoshi Asami 		}
904a56bb8a5SSatoshi Asami 		bn += btodb(rcount);
905a56bb8a5SSatoshi Asami 		addr += rcount;
906a56bb8a5SSatoshi Asami 	}
907a56bb8a5SSatoshi Asami }
908a56bb8a5SSatoshi Asami 
909a56bb8a5SSatoshi Asami /*
910a56bb8a5SSatoshi Asami  * Build a component buffer header.
911a56bb8a5SSatoshi Asami  */
912e2738b4fSPoul-Henning Kamp static void
9133bc746beSSatoshi Asami ccdbuffer(cb, cs, bp, bn, addr, bcount)
9141464240eSMatthew Dillon 	struct ccdbuf **cb;
9151464240eSMatthew Dillon 	struct ccd_softc *cs;
9169d7f7369SPoul-Henning Kamp 	struct bio *bp;
917a56bb8a5SSatoshi Asami 	daddr_t bn;
918a56bb8a5SSatoshi Asami 	caddr_t addr;
919a56bb8a5SSatoshi Asami 	long bcount;
920a56bb8a5SSatoshi Asami {
9211464240eSMatthew Dillon 	struct ccdcinfo *ci, *ci2 = NULL;	/* XXX */
9221464240eSMatthew Dillon 	struct ccdbuf *cbp;
9231464240eSMatthew Dillon 	daddr_t cbn, cboff;
9241464240eSMatthew Dillon 	off_t cbc;
925a56bb8a5SSatoshi Asami 
926a56bb8a5SSatoshi Asami #ifdef DEBUG
927a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_IO)
928a56bb8a5SSatoshi Asami 		printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
929a56bb8a5SSatoshi Asami 		       cs, bp, bn, addr, bcount);
930a56bb8a5SSatoshi Asami #endif
931a56bb8a5SSatoshi Asami 	/*
932a56bb8a5SSatoshi Asami 	 * Determine which component bn falls in.
933a56bb8a5SSatoshi Asami 	 */
934a56bb8a5SSatoshi Asami 	cbn = bn;
935a56bb8a5SSatoshi Asami 	cboff = 0;
936a56bb8a5SSatoshi Asami 
937a56bb8a5SSatoshi Asami 	if (cs->sc_ileave == 0) {
9381464240eSMatthew Dillon 		/*
9391464240eSMatthew Dillon 		 * Serially concatenated and neither a mirror nor a parity
9401464240eSMatthew Dillon 		 * config.  This is a special case.
9411464240eSMatthew Dillon 		 */
9421464240eSMatthew Dillon 		daddr_t sblk;
943a56bb8a5SSatoshi Asami 
944a56bb8a5SSatoshi Asami 		sblk = 0;
945a56bb8a5SSatoshi Asami 		for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
946a56bb8a5SSatoshi Asami 			sblk += ci->ci_size;
947a56bb8a5SSatoshi Asami 		cbn -= sblk;
9481464240eSMatthew Dillon 	} else {
9491464240eSMatthew Dillon 		struct ccdiinfo *ii;
950a56bb8a5SSatoshi Asami 		int ccdisk, off;
951a56bb8a5SSatoshi Asami 
9521464240eSMatthew Dillon 		/*
9531464240eSMatthew Dillon 		 * Calculate cbn, the logical superblock (sc_ileave chunks),
9541464240eSMatthew Dillon 		 * and cboff, a normal block offset (DEV_BSIZE chunks) relative
9551464240eSMatthew Dillon 		 * to cbn.
9561464240eSMatthew Dillon 		 */
9571464240eSMatthew Dillon 		cboff = cbn % cs->sc_ileave;	/* DEV_BSIZE gran */
9581464240eSMatthew Dillon 		cbn = cbn / cs->sc_ileave;	/* DEV_BSIZE * ileave gran */
9591464240eSMatthew Dillon 
9601464240eSMatthew Dillon 		/*
9611464240eSMatthew Dillon 		 * Figure out which interleave table to use.
9621464240eSMatthew Dillon 		 */
9631464240eSMatthew Dillon 		for (ii = cs->sc_itable; ii->ii_ndisk; ii++) {
964a56bb8a5SSatoshi Asami 			if (ii->ii_startblk > cbn)
965a56bb8a5SSatoshi Asami 				break;
9661464240eSMatthew Dillon 		}
967a56bb8a5SSatoshi Asami 		ii--;
9681464240eSMatthew Dillon 
9691464240eSMatthew Dillon 		/*
9701464240eSMatthew Dillon 		 * off is the logical superblock relative to the beginning
9711464240eSMatthew Dillon 		 * of this interleave block.
9721464240eSMatthew Dillon 		 */
973a56bb8a5SSatoshi Asami 		off = cbn - ii->ii_startblk;
9741464240eSMatthew Dillon 
9751464240eSMatthew Dillon 		/*
9761464240eSMatthew Dillon 		 * We must calculate which disk component to use (ccdisk),
9771464240eSMatthew Dillon 		 * and recalculate cbn to be the superblock relative to
9781464240eSMatthew Dillon 		 * the beginning of the component.  This is typically done by
9791464240eSMatthew Dillon 		 * adding 'off' and ii->ii_startoff together.  However, 'off'
9801464240eSMatthew Dillon 		 * must typically be divided by the number of components in
9811464240eSMatthew Dillon 		 * this interleave array to be properly convert it from a
9821464240eSMatthew Dillon 		 * CCD-relative logical superblock number to a
9831464240eSMatthew Dillon 		 * component-relative superblock number.
9841464240eSMatthew Dillon 		 */
985a56bb8a5SSatoshi Asami 		if (ii->ii_ndisk == 1) {
9861464240eSMatthew Dillon 			/*
9871464240eSMatthew Dillon 			 * When we have just one disk, it can't be a mirror
9881464240eSMatthew Dillon 			 * or a parity config.
9891464240eSMatthew Dillon 			 */
990a56bb8a5SSatoshi Asami 			ccdisk = ii->ii_index[0];
991a56bb8a5SSatoshi Asami 			cbn = ii->ii_startoff + off;
992a56bb8a5SSatoshi Asami 		} else {
99309b59204SSatoshi Asami 			if (cs->sc_cflags & CCDF_MIRROR) {
9941464240eSMatthew Dillon 				/*
9951464240eSMatthew Dillon 				 * We have forced a uniform mapping, resulting
9961464240eSMatthew Dillon 				 * in a single interleave array.  We double
9971464240eSMatthew Dillon 				 * up on the first half of the available
9981464240eSMatthew Dillon 				 * components and our mirror is in the second
9991464240eSMatthew Dillon 				 * half.  This only works with a single
10001464240eSMatthew Dillon 				 * interleave array because doubling up
10011464240eSMatthew Dillon 				 * doubles the number of sectors, so there
10021464240eSMatthew Dillon 				 * cannot be another interleave array because
10031464240eSMatthew Dillon 				 * the next interleave array's calculations
10041464240eSMatthew Dillon 				 * would be off.
10051464240eSMatthew Dillon 				 */
10061464240eSMatthew Dillon 				int ndisk2 = ii->ii_ndisk / 2;
10071464240eSMatthew Dillon 				ccdisk = ii->ii_index[off % ndisk2];
10081464240eSMatthew Dillon 				cbn = ii->ii_startoff + off / ndisk2;
10091464240eSMatthew Dillon 				ci2 = &cs->sc_cinfo[ccdisk + ndisk2];
10101464240eSMatthew Dillon 			} else if (cs->sc_cflags & CCDF_PARITY) {
10111464240eSMatthew Dillon 				/*
10121464240eSMatthew Dillon 				 * XXX not implemented yet
10131464240eSMatthew Dillon 				 */
10141464240eSMatthew Dillon 				int ndisk2 = ii->ii_ndisk - 1;
10151464240eSMatthew Dillon 				ccdisk = ii->ii_index[off % ndisk2];
10161464240eSMatthew Dillon 				cbn = ii->ii_startoff + off / ndisk2;
10177ecb65faSSatoshi Asami 				if (cbn % ii->ii_ndisk <= ccdisk)
10187ecb65faSSatoshi Asami 					ccdisk++;
10191464240eSMatthew Dillon 			} else {
1020a56bb8a5SSatoshi Asami 				ccdisk = ii->ii_index[off % ii->ii_ndisk];
1021a56bb8a5SSatoshi Asami 				cbn = ii->ii_startoff + off / ii->ii_ndisk;
1022a56bb8a5SSatoshi Asami 			}
10237ecb65faSSatoshi Asami 		}
10241464240eSMatthew Dillon 
1025a56bb8a5SSatoshi Asami 		ci = &cs->sc_cinfo[ccdisk];
10261464240eSMatthew Dillon 
10271464240eSMatthew Dillon 		/*
10281464240eSMatthew Dillon 		 * Convert cbn from a superblock to a normal block so it
10291464240eSMatthew Dillon 		 * can be used to calculate (along with cboff) the normal
10301464240eSMatthew Dillon 		 * block index into this particular disk.
10311464240eSMatthew Dillon 		 */
10321464240eSMatthew Dillon 		cbn *= cs->sc_ileave;
1033a56bb8a5SSatoshi Asami 	}
1034a56bb8a5SSatoshi Asami 
1035a56bb8a5SSatoshi Asami 	/*
1036a56bb8a5SSatoshi Asami 	 * Fill in the component buf structure.
1037a56bb8a5SSatoshi Asami 	 */
10381464240eSMatthew Dillon 	cbp = getccdbuf(NULL);
10399d7f7369SPoul-Henning Kamp 	cbp->cb_buf.bio_cmd = bp->bio_cmd;
10409d7f7369SPoul-Henning Kamp 	cbp->cb_buf.bio_done = ccdiodone;
10419d7f7369SPoul-Henning Kamp 	cbp->cb_buf.bio_dev = ci->ci_dev;		/* XXX */
10429d7f7369SPoul-Henning Kamp 	cbp->cb_buf.bio_blkno = cbn + cboff + CCD_OFFSET;
10439d7f7369SPoul-Henning Kamp 	cbp->cb_buf.bio_offset = dbtob(cbn + cboff + CCD_OFFSET);
10449d7f7369SPoul-Henning Kamp 	cbp->cb_buf.bio_data = addr;
1045a56bb8a5SSatoshi Asami 	if (cs->sc_ileave == 0)
104640969e38SDavid Greenman               cbc = dbtob((off_t)(ci->ci_size - cbn));
1047a56bb8a5SSatoshi Asami 	else
104840969e38SDavid Greenman               cbc = dbtob((off_t)(cs->sc_ileave - cboff));
10499d7f7369SPoul-Henning Kamp 	cbp->cb_buf.bio_bcount = (cbc < bcount) ? cbc : bcount;
10509d7f7369SPoul-Henning Kamp  	cbp->cb_buf.bio_caller1 = (void*)cbp->cb_buf.bio_bcount;
1051c0b89506SJohn Dyson 
1052a56bb8a5SSatoshi Asami 	/*
1053a56bb8a5SSatoshi Asami 	 * context for ccdiodone
1054a56bb8a5SSatoshi Asami 	 */
1055a56bb8a5SSatoshi Asami 	cbp->cb_obp = bp;
1056a56bb8a5SSatoshi Asami 	cbp->cb_unit = cs - ccd_softc;
1057a56bb8a5SSatoshi Asami 	cbp->cb_comp = ci - cs->sc_cinfo;
1058a56bb8a5SSatoshi Asami 
1059a56bb8a5SSatoshi Asami #ifdef DEBUG
1060a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_IO)
1061a56bb8a5SSatoshi Asami 		printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
10629d7f7369SPoul-Henning Kamp 		       ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.bio_blkno,
10639d7f7369SPoul-Henning Kamp 		       cbp->cb_buf.bio_data, cbp->cb_buf.bio_bcount);
1064a56bb8a5SSatoshi Asami #endif
10653bc746beSSatoshi Asami 	cb[0] = cbp;
10661464240eSMatthew Dillon 
10671464240eSMatthew Dillon 	/*
10681464240eSMatthew Dillon 	 * Note: both I/O's setup when reading from mirror, but only one
10691464240eSMatthew Dillon 	 * will be executed.
10701464240eSMatthew Dillon 	 */
10711464240eSMatthew Dillon 	if (cs->sc_cflags & CCDF_MIRROR) {
10721464240eSMatthew Dillon 		/* mirror, setup second I/O */
10731464240eSMatthew Dillon 		cbp = getccdbuf(cb[0]);
10749d7f7369SPoul-Henning Kamp 		cbp->cb_buf.bio_dev = ci2->ci_dev;
10753bc746beSSatoshi Asami 		cbp->cb_comp = ci2 - cs->sc_cinfo;
10763bc746beSSatoshi Asami 		cb[1] = cbp;
1077e7322872SSatoshi Asami 		/* link together the ccdbuf's and clear "mirror done" flag */
1078e7322872SSatoshi Asami 		cb[0]->cb_mirror = cb[1];
1079e7322872SSatoshi Asami 		cb[1]->cb_mirror = cb[0];
1080e7322872SSatoshi Asami 		cb[0]->cb_pflags &= ~CCDPF_MIRROR_DONE;
1081e7322872SSatoshi Asami 		cb[1]->cb_pflags &= ~CCDPF_MIRROR_DONE;
10823bc746beSSatoshi Asami 	}
1083a56bb8a5SSatoshi Asami }
1084a56bb8a5SSatoshi Asami 
1085a56bb8a5SSatoshi Asami static void
1086a56bb8a5SSatoshi Asami ccdintr(cs, bp)
10871464240eSMatthew Dillon 	struct ccd_softc *cs;
10889d7f7369SPoul-Henning Kamp 	struct bio *bp;
1089a56bb8a5SSatoshi Asami {
1090a56bb8a5SSatoshi Asami #ifdef DEBUG
1091a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
1092a56bb8a5SSatoshi Asami 		printf("ccdintr(%x, %x)\n", cs, bp);
1093a56bb8a5SSatoshi Asami #endif
1094a56bb8a5SSatoshi Asami 	/*
1095a56bb8a5SSatoshi Asami 	 * Request is done for better or worse, wakeup the top half.
1096a56bb8a5SSatoshi Asami 	 */
10979d7f7369SPoul-Henning Kamp 	if (bp->bio_flags & BIO_ERROR)
10989d7f7369SPoul-Henning Kamp 		bp->bio_resid = bp->bio_bcount;
10999d7f7369SPoul-Henning Kamp 	devstat_end_transaction_bio(&cs->device_stats, bp);
11009d7f7369SPoul-Henning Kamp 	biodone(bp);
1101a56bb8a5SSatoshi Asami }
1102a56bb8a5SSatoshi Asami 
1103a56bb8a5SSatoshi Asami /*
1104a56bb8a5SSatoshi Asami  * Called at interrupt time.
1105a56bb8a5SSatoshi Asami  * Mark the component as done and if all components are done,
1106a56bb8a5SSatoshi Asami  * take a ccd interrupt.
1107a56bb8a5SSatoshi Asami  */
1108e2738b4fSPoul-Henning Kamp static void
110921144e3bSPoul-Henning Kamp ccdiodone(ibp)
11109d7f7369SPoul-Henning Kamp 	struct bio *ibp;
1111a56bb8a5SSatoshi Asami {
111221144e3bSPoul-Henning Kamp 	struct ccdbuf *cbp = (struct ccdbuf *)ibp;
11139d7f7369SPoul-Henning Kamp 	struct bio *bp = cbp->cb_obp;
11141464240eSMatthew Dillon 	int unit = cbp->cb_unit;
1115a56bb8a5SSatoshi Asami 	int count, s;
1116a56bb8a5SSatoshi Asami 
1117a56bb8a5SSatoshi Asami 	s = splbio();
1118a56bb8a5SSatoshi Asami #ifdef DEBUG
1119a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
1120a56bb8a5SSatoshi Asami 		printf("ccdiodone(%x)\n", cbp);
1121a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_IO) {
1122a56bb8a5SSatoshi Asami 		printf("ccdiodone: bp %x bcount %d resid %d\n",
11239d7f7369SPoul-Henning Kamp 		       bp, bp->bio_bcount, bp->bio_resid);
1124a56bb8a5SSatoshi Asami 		printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
11259d7f7369SPoul-Henning Kamp 		       cbp->cb_buf.bio_dev, cbp->cb_comp, cbp,
11269d7f7369SPoul-Henning Kamp 		       cbp->cb_buf.bio_blkno, cbp->cb_buf.bio_data,
11279d7f7369SPoul-Henning Kamp 		       cbp->cb_buf.bio_bcount);
1128a56bb8a5SSatoshi Asami 	}
1129a56bb8a5SSatoshi Asami #endif
11301464240eSMatthew Dillon 	/*
11311464240eSMatthew Dillon 	 * If an error occured, report it.  If this is a mirrored
11321464240eSMatthew Dillon 	 * configuration and the first of two possible reads, do not
11331464240eSMatthew Dillon 	 * set the error in the bp yet because the second read may
11341464240eSMatthew Dillon 	 * succeed.
11351464240eSMatthew Dillon 	 */
1136a56bb8a5SSatoshi Asami 
11379d7f7369SPoul-Henning Kamp 	if (cbp->cb_buf.bio_flags & BIO_ERROR) {
11381464240eSMatthew Dillon 		const char *msg = "";
11391464240eSMatthew Dillon 
11401464240eSMatthew Dillon 		if ((ccd_softc[unit].sc_cflags & CCDF_MIRROR) &&
11419d7f7369SPoul-Henning Kamp 		    (cbp->cb_buf.bio_cmd == BIO_READ) &&
11421464240eSMatthew Dillon 		    (cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
11431464240eSMatthew Dillon 			/*
11441464240eSMatthew Dillon 			 * We will try our read on the other disk down
11451464240eSMatthew Dillon 			 * below, also reverse the default pick so if we
11461464240eSMatthew Dillon 			 * are doing a scan we do not keep hitting the
11471464240eSMatthew Dillon 			 * bad disk first.
11481464240eSMatthew Dillon 			 */
11491464240eSMatthew Dillon 			struct ccd_softc *cs = &ccd_softc[unit];
11501464240eSMatthew Dillon 
11511464240eSMatthew Dillon 			msg = ", trying other disk";
11521464240eSMatthew Dillon 			cs->sc_pick = 1 - cs->sc_pick;
11539d7f7369SPoul-Henning Kamp 			cs->sc_blk[cs->sc_pick] = bp->bio_blkno;
11541464240eSMatthew Dillon 		} else {
11559d7f7369SPoul-Henning Kamp 			bp->bio_flags |= BIO_ERROR;
11569d7f7369SPoul-Henning Kamp 			bp->bio_error = cbp->cb_buf.bio_error ?
11579d7f7369SPoul-Henning Kamp 			    cbp->cb_buf.bio_error : EIO;
11581464240eSMatthew Dillon 		}
11591464240eSMatthew Dillon 		printf("ccd%d: error %d on component %d block %d (ccd block %d)%s\n",
11609d7f7369SPoul-Henning Kamp 		       unit, bp->bio_error, cbp->cb_comp,
11619d7f7369SPoul-Henning Kamp 		       (int)cbp->cb_buf.bio_blkno, bp->bio_blkno, msg);
1162a56bb8a5SSatoshi Asami 	}
1163e7322872SSatoshi Asami 
11641464240eSMatthew Dillon 	/*
11651464240eSMatthew Dillon 	 * Process mirror.  If we are writing, I/O has been initiated on both
11661464240eSMatthew Dillon 	 * buffers and we fall through only after both are finished.
11671464240eSMatthew Dillon 	 *
11681464240eSMatthew Dillon 	 * If we are reading only one I/O is initiated at a time.  If an
11691464240eSMatthew Dillon 	 * error occurs we initiate the second I/O and return, otherwise
11701464240eSMatthew Dillon 	 * we free the second I/O without initiating it.
11711464240eSMatthew Dillon 	 */
11721464240eSMatthew Dillon 
11731464240eSMatthew Dillon 	if (ccd_softc[unit].sc_cflags & CCDF_MIRROR) {
11749d7f7369SPoul-Henning Kamp 		if (cbp->cb_buf.bio_cmd == BIO_WRITE) {
11751464240eSMatthew Dillon 			/*
11761464240eSMatthew Dillon 			 * When writing, handshake with the second buffer
11771464240eSMatthew Dillon 			 * to determine when both are done.  If both are not
11781464240eSMatthew Dillon 			 * done, return here.
11791464240eSMatthew Dillon 			 */
1180e7322872SSatoshi Asami 			if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
1181e7322872SSatoshi Asami 				cbp->cb_mirror->cb_pflags |= CCDPF_MIRROR_DONE;
1182e7322872SSatoshi Asami 				putccdbuf(cbp);
1183e7322872SSatoshi Asami 				splx(s);
1184e7322872SSatoshi Asami 				return;
1185e7322872SSatoshi Asami 			}
11861464240eSMatthew Dillon 		} else {
11871464240eSMatthew Dillon 			/*
11881464240eSMatthew Dillon 			 * When reading, either dispose of the second buffer
11891464240eSMatthew Dillon 			 * or initiate I/O on the second buffer if an error
11901464240eSMatthew Dillon 			 * occured with this one.
11911464240eSMatthew Dillon 			 */
11921464240eSMatthew Dillon 			if ((cbp->cb_pflags & CCDPF_MIRROR_DONE) == 0) {
11939d7f7369SPoul-Henning Kamp 				if (cbp->cb_buf.bio_flags & BIO_ERROR) {
11941464240eSMatthew Dillon 					cbp->cb_mirror->cb_pflags |=
11951464240eSMatthew Dillon 					    CCDPF_MIRROR_DONE;
11969d7f7369SPoul-Henning Kamp 					BIO_STRATEGY(&cbp->cb_mirror->cb_buf, 0);
11971464240eSMatthew Dillon 					putccdbuf(cbp);
11981464240eSMatthew Dillon 					splx(s);
11991464240eSMatthew Dillon 					return;
12001464240eSMatthew Dillon 				} else {
12011464240eSMatthew Dillon 					putccdbuf(cbp->cb_mirror);
12021464240eSMatthew Dillon 					/* fall through */
12031464240eSMatthew Dillon 				}
12041464240eSMatthew Dillon 			}
12051464240eSMatthew Dillon 		}
12061464240eSMatthew Dillon 	}
1207e7322872SSatoshi Asami 
120825d1a00bSMatthew Dillon 	/*
12099d7f7369SPoul-Henning Kamp 	 * use bio_caller1 to determine how big the original request was rather
12109d7f7369SPoul-Henning Kamp 	 * then bio_bcount, because bio_bcount may have been truncated for EOF.
121125d1a00bSMatthew Dillon 	 *
121225d1a00bSMatthew Dillon 	 * XXX We check for an error, but we do not test the resid for an
121325d1a00bSMatthew Dillon 	 * aligned EOF condition.  This may result in character & block
121425d1a00bSMatthew Dillon 	 * device access not recognizing EOF properly when read or written
121525d1a00bSMatthew Dillon 	 * sequentially, but will not effect filesystems.
121625d1a00bSMatthew Dillon 	 */
12179d7f7369SPoul-Henning Kamp 	count = (long)cbp->cb_buf.bio_caller1;
1218a56bb8a5SSatoshi Asami 	putccdbuf(cbp);
1219a56bb8a5SSatoshi Asami 
1220a56bb8a5SSatoshi Asami 	/*
1221a56bb8a5SSatoshi Asami 	 * If all done, "interrupt".
1222a56bb8a5SSatoshi Asami 	 */
12239d7f7369SPoul-Henning Kamp 	bp->bio_resid -= count;
12249d7f7369SPoul-Henning Kamp 	if (bp->bio_resid < 0)
1225a56bb8a5SSatoshi Asami 		panic("ccdiodone: count");
12269d7f7369SPoul-Henning Kamp 	if (bp->bio_resid == 0)
1227a56bb8a5SSatoshi Asami 		ccdintr(&ccd_softc[unit], bp);
1228a56bb8a5SSatoshi Asami 	splx(s);
1229a56bb8a5SSatoshi Asami }
1230a56bb8a5SSatoshi Asami 
1231e2738b4fSPoul-Henning Kamp static int
1232a56bb8a5SSatoshi Asami ccdioctl(dev, cmd, data, flag, p)
1233a56bb8a5SSatoshi Asami 	dev_t dev;
1234ecbb00a2SDoug Rabson 	u_long cmd;
1235a56bb8a5SSatoshi Asami 	caddr_t data;
1236a56bb8a5SSatoshi Asami 	int flag;
1237a56bb8a5SSatoshi Asami 	struct proc *p;
1238a56bb8a5SSatoshi Asami {
1239a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
1240a56bb8a5SSatoshi Asami 	int i, j, lookedup = 0, error = 0;
1241a56bb8a5SSatoshi Asami 	int part, pmask, s;
1242a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1243a56bb8a5SSatoshi Asami 	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1244a56bb8a5SSatoshi Asami 	struct ccddevice ccd;
1245a56bb8a5SSatoshi Asami 	char **cpp;
1246a56bb8a5SSatoshi Asami 	struct vnode **vpp;
1247a56bb8a5SSatoshi Asami 
1248a56bb8a5SSatoshi Asami 	if (unit >= numccd)
1249a56bb8a5SSatoshi Asami 		return (ENXIO);
1250a56bb8a5SSatoshi Asami 	cs = &ccd_softc[unit];
1251a56bb8a5SSatoshi Asami 
1252a56bb8a5SSatoshi Asami 	bzero(&ccd, sizeof(ccd));
1253a56bb8a5SSatoshi Asami 
1254a56bb8a5SSatoshi Asami 	switch (cmd) {
1255a56bb8a5SSatoshi Asami 	case CCDIOCSET:
1256a56bb8a5SSatoshi Asami 		if (cs->sc_flags & CCDF_INITED)
1257a56bb8a5SSatoshi Asami 			return (EBUSY);
1258a56bb8a5SSatoshi Asami 
1259a56bb8a5SSatoshi Asami 		if ((flag & FWRITE) == 0)
1260a56bb8a5SSatoshi Asami 			return (EBADF);
1261a56bb8a5SSatoshi Asami 
1262b4e36adfSMatthew Dillon 		if ((error = ccdlock(cs)) != 0)
1263a56bb8a5SSatoshi Asami 			return (error);
1264a56bb8a5SSatoshi Asami 
1265a56bb8a5SSatoshi Asami 		/* Fill in some important bits. */
1266a56bb8a5SSatoshi Asami 		ccd.ccd_unit = unit;
1267a56bb8a5SSatoshi Asami 		ccd.ccd_interleave = ccio->ccio_ileave;
1268b8e29b55SSatoshi Asami 		if (ccd.ccd_interleave == 0 &&
1269b8e29b55SSatoshi Asami 		    ((ccio->ccio_flags & CCDF_MIRROR) ||
1270b8e29b55SSatoshi Asami 		     (ccio->ccio_flags & CCDF_PARITY))) {
1271b8e29b55SSatoshi Asami 			printf("ccd%d: disabling mirror/parity, interleave is 0\n", unit);
1272b8e29b55SSatoshi Asami 			ccio->ccio_flags &= ~(CCDF_MIRROR | CCDF_PARITY);
1273b8e29b55SSatoshi Asami 		}
127409b59204SSatoshi Asami 		if ((ccio->ccio_flags & CCDF_MIRROR) &&
127509b59204SSatoshi Asami 		    (ccio->ccio_flags & CCDF_PARITY)) {
127609b59204SSatoshi Asami 			printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
127709b59204SSatoshi Asami 			ccio->ccio_flags &= ~CCDF_PARITY;
127809b59204SSatoshi Asami 		}
127909b59204SSatoshi Asami 		if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
12807ecb65faSSatoshi Asami 		    !(ccio->ccio_flags & CCDF_UNIFORM)) {
128109b59204SSatoshi Asami 			printf("ccd%d: mirror/parity forces uniform flag\n",
128209b59204SSatoshi Asami 			       unit);
12837ecb65faSSatoshi Asami 			ccio->ccio_flags |= CCDF_UNIFORM;
12847ecb65faSSatoshi Asami 		}
1285a56bb8a5SSatoshi Asami 		ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1286a56bb8a5SSatoshi Asami 
1287a56bb8a5SSatoshi Asami 		/*
1288a56bb8a5SSatoshi Asami 		 * Allocate space for and copy in the array of
1289a56bb8a5SSatoshi Asami 		 * componet pathnames and device numbers.
1290a56bb8a5SSatoshi Asami 		 */
1291a56bb8a5SSatoshi Asami 		cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1292a56bb8a5SSatoshi Asami 		    M_DEVBUF, M_WAITOK);
1293a56bb8a5SSatoshi Asami 		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1294a56bb8a5SSatoshi Asami 		    M_DEVBUF, M_WAITOK);
1295a56bb8a5SSatoshi Asami 
1296a56bb8a5SSatoshi Asami 		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1297a56bb8a5SSatoshi Asami 		    ccio->ccio_ndisks * sizeof(char **));
1298a56bb8a5SSatoshi Asami 		if (error) {
1299a56bb8a5SSatoshi Asami 			free(vpp, M_DEVBUF);
1300a56bb8a5SSatoshi Asami 			free(cpp, M_DEVBUF);
1301a56bb8a5SSatoshi Asami 			ccdunlock(cs);
1302a56bb8a5SSatoshi Asami 			return (error);
1303a56bb8a5SSatoshi Asami 		}
1304a56bb8a5SSatoshi Asami 
1305a56bb8a5SSatoshi Asami #ifdef DEBUG
1306a56bb8a5SSatoshi Asami 		if (ccddebug & CCDB_INIT)
1307a56bb8a5SSatoshi Asami 			for (i = 0; i < ccio->ccio_ndisks; ++i)
1308a56bb8a5SSatoshi Asami 				printf("ccdioctl: component %d: 0x%x\n",
1309a56bb8a5SSatoshi Asami 				    i, cpp[i]);
1310a56bb8a5SSatoshi Asami #endif
1311a56bb8a5SSatoshi Asami 
1312a56bb8a5SSatoshi Asami 		for (i = 0; i < ccio->ccio_ndisks; ++i) {
1313a56bb8a5SSatoshi Asami #ifdef DEBUG
1314a56bb8a5SSatoshi Asami 			if (ccddebug & CCDB_INIT)
1315a56bb8a5SSatoshi Asami 				printf("ccdioctl: lookedup = %d\n", lookedup);
1316a56bb8a5SSatoshi Asami #endif
1317b4e36adfSMatthew Dillon 			if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
1318a56bb8a5SSatoshi Asami 				for (j = 0; j < lookedup; ++j)
1319a56bb8a5SSatoshi Asami 					(void)vn_close(vpp[j], FREAD|FWRITE,
1320a56bb8a5SSatoshi Asami 					    p->p_ucred, p);
1321a56bb8a5SSatoshi Asami 				free(vpp, M_DEVBUF);
1322a56bb8a5SSatoshi Asami 				free(cpp, M_DEVBUF);
1323a56bb8a5SSatoshi Asami 				ccdunlock(cs);
1324a56bb8a5SSatoshi Asami 				return (error);
1325a56bb8a5SSatoshi Asami 			}
1326a56bb8a5SSatoshi Asami 			++lookedup;
1327a56bb8a5SSatoshi Asami 		}
1328a56bb8a5SSatoshi Asami 		ccd.ccd_cpp = cpp;
1329a56bb8a5SSatoshi Asami 		ccd.ccd_vpp = vpp;
1330a56bb8a5SSatoshi Asami 		ccd.ccd_ndev = ccio->ccio_ndisks;
1331a56bb8a5SSatoshi Asami 
1332a56bb8a5SSatoshi Asami 		/*
1333a56bb8a5SSatoshi Asami 		 * Initialize the ccd.  Fills in the softc for us.
1334a56bb8a5SSatoshi Asami 		 */
1335b4e36adfSMatthew Dillon 		if ((error = ccdinit(&ccd, cpp, p)) != 0) {
1336a56bb8a5SSatoshi Asami 			for (j = 0; j < lookedup; ++j)
1337a56bb8a5SSatoshi Asami 				(void)vn_close(vpp[j], FREAD|FWRITE,
1338a56bb8a5SSatoshi Asami 				    p->p_ucred, p);
1339a56bb8a5SSatoshi Asami 			bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1340a56bb8a5SSatoshi Asami 			free(vpp, M_DEVBUF);
1341a56bb8a5SSatoshi Asami 			free(cpp, M_DEVBUF);
1342a56bb8a5SSatoshi Asami 			ccdunlock(cs);
1343a56bb8a5SSatoshi Asami 			return (error);
1344a56bb8a5SSatoshi Asami 		}
1345a56bb8a5SSatoshi Asami 
1346a56bb8a5SSatoshi Asami 		/*
1347a56bb8a5SSatoshi Asami 		 * The ccd has been successfully initialized, so
1348a56bb8a5SSatoshi Asami 		 * we can place it into the array and read the disklabel.
1349a56bb8a5SSatoshi Asami 		 */
1350a56bb8a5SSatoshi Asami 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1351a56bb8a5SSatoshi Asami 		ccio->ccio_unit = unit;
1352a56bb8a5SSatoshi Asami 		ccio->ccio_size = cs->sc_size;
1353a56bb8a5SSatoshi Asami 		ccdgetdisklabel(dev);
1354a56bb8a5SSatoshi Asami 
1355a56bb8a5SSatoshi Asami 		ccdunlock(cs);
1356a56bb8a5SSatoshi Asami 
1357a56bb8a5SSatoshi Asami 		break;
1358a56bb8a5SSatoshi Asami 
1359a56bb8a5SSatoshi Asami 	case CCDIOCCLR:
1360a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1361a56bb8a5SSatoshi Asami 			return (ENXIO);
1362a56bb8a5SSatoshi Asami 
1363a56bb8a5SSatoshi Asami 		if ((flag & FWRITE) == 0)
1364a56bb8a5SSatoshi Asami 			return (EBADF);
1365a56bb8a5SSatoshi Asami 
1366b4e36adfSMatthew Dillon 		if ((error = ccdlock(cs)) != 0)
1367a56bb8a5SSatoshi Asami 			return (error);
1368a56bb8a5SSatoshi Asami 
1369af8862e4SPoul-Henning Kamp 		/* Don't unconfigure if any other partitions are open */
1370d8594dfbSSatoshi Asami 		part = ccdpart(dev);
1371a56bb8a5SSatoshi Asami 		pmask = (1 << part);
1372af8862e4SPoul-Henning Kamp 		if ((cs->sc_openmask & ~pmask)) {
1373a56bb8a5SSatoshi Asami 			ccdunlock(cs);
1374a56bb8a5SSatoshi Asami 			return (EBUSY);
1375a56bb8a5SSatoshi Asami 		}
1376a56bb8a5SSatoshi Asami 
1377a56bb8a5SSatoshi Asami 		/*
1378a56bb8a5SSatoshi Asami 		 * Free ccd_softc information and clear entry.
1379a56bb8a5SSatoshi Asami 		 */
1380a56bb8a5SSatoshi Asami 
1381a56bb8a5SSatoshi Asami 		/* Close the components and free their pathnames. */
1382a56bb8a5SSatoshi Asami 		for (i = 0; i < cs->sc_nccdisks; ++i) {
1383a56bb8a5SSatoshi Asami 			/*
1384a56bb8a5SSatoshi Asami 			 * XXX: this close could potentially fail and
1385a56bb8a5SSatoshi Asami 			 * cause Bad Things.  Maybe we need to force
1386a56bb8a5SSatoshi Asami 			 * the close to happen?
1387a56bb8a5SSatoshi Asami 			 */
1388a56bb8a5SSatoshi Asami #ifdef DEBUG
1389a56bb8a5SSatoshi Asami 			if (ccddebug & CCDB_VNODE)
1390a56bb8a5SSatoshi Asami 				vprint("CCDIOCCLR: vnode info",
1391a56bb8a5SSatoshi Asami 				    cs->sc_cinfo[i].ci_vp);
1392a56bb8a5SSatoshi Asami #endif
1393a56bb8a5SSatoshi Asami 			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1394a56bb8a5SSatoshi Asami 			    p->p_ucred, p);
1395a56bb8a5SSatoshi Asami 			free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1396a56bb8a5SSatoshi Asami 		}
1397a56bb8a5SSatoshi Asami 
1398a56bb8a5SSatoshi Asami 		/* Free interleave index. */
1399a56bb8a5SSatoshi Asami 		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1400a56bb8a5SSatoshi Asami 			free(cs->sc_itable[i].ii_index, M_DEVBUF);
1401a56bb8a5SSatoshi Asami 
1402a56bb8a5SSatoshi Asami 		/* Free component info and interleave table. */
1403a56bb8a5SSatoshi Asami 		free(cs->sc_cinfo, M_DEVBUF);
1404a56bb8a5SSatoshi Asami 		free(cs->sc_itable, M_DEVBUF);
1405a56bb8a5SSatoshi Asami 		cs->sc_flags &= ~CCDF_INITED;
1406a56bb8a5SSatoshi Asami 
1407a56bb8a5SSatoshi Asami 		/*
1408a56bb8a5SSatoshi Asami 		 * Free ccddevice information and clear entry.
1409a56bb8a5SSatoshi Asami 		 */
1410a56bb8a5SSatoshi Asami 		free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1411a56bb8a5SSatoshi Asami 		free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1412a56bb8a5SSatoshi Asami 		ccd.ccd_dk = -1;
1413a56bb8a5SSatoshi Asami 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1414a56bb8a5SSatoshi Asami 
141521c3b31eSMatt Jacob 		/*
141621c3b31eSMatt Jacob 		 * And remove the devstat entry.
141721c3b31eSMatt Jacob 		 */
141821c3b31eSMatt Jacob 		devstat_remove_entry(&cs->device_stats);
141921c3b31eSMatt Jacob 
1420a56bb8a5SSatoshi Asami 		/* This must be atomic. */
1421a56bb8a5SSatoshi Asami 		s = splhigh();
1422a56bb8a5SSatoshi Asami 		ccdunlock(cs);
1423a56bb8a5SSatoshi Asami 		bzero(cs, sizeof(struct ccd_softc));
1424a56bb8a5SSatoshi Asami 		splx(s);
1425a56bb8a5SSatoshi Asami 
1426a56bb8a5SSatoshi Asami 		break;
1427a56bb8a5SSatoshi Asami 
1428a56bb8a5SSatoshi Asami 	case DIOCGDINFO:
1429a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1430a56bb8a5SSatoshi Asami 			return (ENXIO);
1431a56bb8a5SSatoshi Asami 
14326cc5a722SPoul-Henning Kamp 		*(struct disklabel *)data = cs->sc_label;
1433a56bb8a5SSatoshi Asami 		break;
1434a56bb8a5SSatoshi Asami 
1435a56bb8a5SSatoshi Asami 	case DIOCGPART:
1436a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1437a56bb8a5SSatoshi Asami 			return (ENXIO);
1438a56bb8a5SSatoshi Asami 
14396cc5a722SPoul-Henning Kamp 		((struct partinfo *)data)->disklab = &cs->sc_label;
1440a56bb8a5SSatoshi Asami 		((struct partinfo *)data)->part =
14416cc5a722SPoul-Henning Kamp 		    &cs->sc_label.d_partitions[ccdpart(dev)];
1442a56bb8a5SSatoshi Asami 		break;
1443a56bb8a5SSatoshi Asami 
1444a56bb8a5SSatoshi Asami 	case DIOCWDINFO:
1445a56bb8a5SSatoshi Asami 	case DIOCSDINFO:
1446a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1447a56bb8a5SSatoshi Asami 			return (ENXIO);
1448a56bb8a5SSatoshi Asami 
1449a56bb8a5SSatoshi Asami 		if ((flag & FWRITE) == 0)
1450a56bb8a5SSatoshi Asami 			return (EBADF);
1451a56bb8a5SSatoshi Asami 
1452b4e36adfSMatthew Dillon 		if ((error = ccdlock(cs)) != 0)
1453a56bb8a5SSatoshi Asami 			return (error);
1454a56bb8a5SSatoshi Asami 
1455a56bb8a5SSatoshi Asami 		cs->sc_flags |= CCDF_LABELLING;
1456a56bb8a5SSatoshi Asami 
14576cc5a722SPoul-Henning Kamp 		error = setdisklabel(&cs->sc_label,
1458d8594dfbSSatoshi Asami 		    (struct disklabel *)data, 0);
1459a56bb8a5SSatoshi Asami 		if (error == 0) {
1460a56bb8a5SSatoshi Asami 			if (cmd == DIOCWDINFO)
1461e2a13e8cSSatoshi Asami 				error = writedisklabel(CCDLABELDEV(dev),
146249ff4debSPoul-Henning Kamp 				    &cs->sc_label);
1463a56bb8a5SSatoshi Asami 		}
1464a56bb8a5SSatoshi Asami 
1465a56bb8a5SSatoshi Asami 		cs->sc_flags &= ~CCDF_LABELLING;
1466a56bb8a5SSatoshi Asami 
1467a56bb8a5SSatoshi Asami 		ccdunlock(cs);
1468a56bb8a5SSatoshi Asami 
1469a56bb8a5SSatoshi Asami 		if (error)
1470a56bb8a5SSatoshi Asami 			return (error);
1471a56bb8a5SSatoshi Asami 		break;
1472a56bb8a5SSatoshi Asami 
1473a56bb8a5SSatoshi Asami 	case DIOCWLABEL:
1474a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1475a56bb8a5SSatoshi Asami 			return (ENXIO);
1476a56bb8a5SSatoshi Asami 
1477a56bb8a5SSatoshi Asami 		if ((flag & FWRITE) == 0)
1478a56bb8a5SSatoshi Asami 			return (EBADF);
1479a56bb8a5SSatoshi Asami 		if (*(int *)data != 0)
1480a56bb8a5SSatoshi Asami 			cs->sc_flags |= CCDF_WLABEL;
1481a56bb8a5SSatoshi Asami 		else
1482a56bb8a5SSatoshi Asami 			cs->sc_flags &= ~CCDF_WLABEL;
1483a56bb8a5SSatoshi Asami 		break;
1484a56bb8a5SSatoshi Asami 
1485a56bb8a5SSatoshi Asami 	default:
1486a56bb8a5SSatoshi Asami 		return (ENOTTY);
1487a56bb8a5SSatoshi Asami 	}
1488a56bb8a5SSatoshi Asami 
1489a56bb8a5SSatoshi Asami 	return (0);
1490a56bb8a5SSatoshi Asami }
1491a56bb8a5SSatoshi Asami 
1492e2738b4fSPoul-Henning Kamp static int
1493a56bb8a5SSatoshi Asami ccdsize(dev)
1494a56bb8a5SSatoshi Asami 	dev_t dev;
1495a56bb8a5SSatoshi Asami {
1496a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1497a56bb8a5SSatoshi Asami 	int part, size;
1498a56bb8a5SSatoshi Asami 
1499af8862e4SPoul-Henning Kamp 	if (ccdopen(dev, 0, S_IFCHR, curproc))
1500a56bb8a5SSatoshi Asami 		return (-1);
1501a56bb8a5SSatoshi Asami 
1502a56bb8a5SSatoshi Asami 	cs = &ccd_softc[ccdunit(dev)];
1503d8594dfbSSatoshi Asami 	part = ccdpart(dev);
1504a56bb8a5SSatoshi Asami 
1505a56bb8a5SSatoshi Asami 	if ((cs->sc_flags & CCDF_INITED) == 0)
1506a56bb8a5SSatoshi Asami 		return (-1);
1507a56bb8a5SSatoshi Asami 
15086cc5a722SPoul-Henning Kamp 	if (cs->sc_label.d_partitions[part].p_fstype != FS_SWAP)
1509a56bb8a5SSatoshi Asami 		size = -1;
1510a56bb8a5SSatoshi Asami 	else
15116cc5a722SPoul-Henning Kamp 		size = cs->sc_label.d_partitions[part].p_size;
1512a56bb8a5SSatoshi Asami 
1513af8862e4SPoul-Henning Kamp 	if (ccdclose(dev, 0, S_IFCHR, curproc))
1514a56bb8a5SSatoshi Asami 		return (-1);
1515a56bb8a5SSatoshi Asami 
1516a56bb8a5SSatoshi Asami 	return (size);
1517a56bb8a5SSatoshi Asami }
1518a56bb8a5SSatoshi Asami 
1519e2738b4fSPoul-Henning Kamp static int
1520e2a13e8cSSatoshi Asami ccddump(dev)
1521a56bb8a5SSatoshi Asami 	dev_t dev;
1522a56bb8a5SSatoshi Asami {
1523a56bb8a5SSatoshi Asami 
1524a56bb8a5SSatoshi Asami 	/* Not implemented. */
1525a56bb8a5SSatoshi Asami 	return ENXIO;
1526a56bb8a5SSatoshi Asami }
1527a56bb8a5SSatoshi Asami 
1528a56bb8a5SSatoshi Asami /*
1529a56bb8a5SSatoshi Asami  * Lookup the provided name in the filesystem.  If the file exists,
1530a56bb8a5SSatoshi Asami  * is a valid block device, and isn't being used by anyone else,
1531a56bb8a5SSatoshi Asami  * set *vpp to the file's vnode.
1532a56bb8a5SSatoshi Asami  */
1533a56bb8a5SSatoshi Asami static int
1534a56bb8a5SSatoshi Asami ccdlookup(path, p, vpp)
1535a56bb8a5SSatoshi Asami 	char *path;
1536a56bb8a5SSatoshi Asami 	struct proc *p;
1537a56bb8a5SSatoshi Asami 	struct vnode **vpp;	/* result */
1538a56bb8a5SSatoshi Asami {
1539a56bb8a5SSatoshi Asami 	struct nameidata nd;
1540a56bb8a5SSatoshi Asami 	struct vnode *vp;
1541a56bb8a5SSatoshi Asami 	int error;
1542a56bb8a5SSatoshi Asami 
1543a56bb8a5SSatoshi Asami 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1544b4e36adfSMatthew Dillon 	if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
1545a56bb8a5SSatoshi Asami #ifdef DEBUG
1546a56bb8a5SSatoshi Asami 		if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1547a56bb8a5SSatoshi Asami 			printf("ccdlookup: vn_open error = %d\n", error);
1548a56bb8a5SSatoshi Asami #endif
1549a56bb8a5SSatoshi Asami 		return (error);
1550a56bb8a5SSatoshi Asami 	}
1551a56bb8a5SSatoshi Asami 	vp = nd.ni_vp;
1552a56bb8a5SSatoshi Asami 
1553a56bb8a5SSatoshi Asami 	if (vp->v_usecount > 1) {
1554762e6b85SEivind Eklund 		error = EBUSY;
1555762e6b85SEivind Eklund 		goto bad;
1556a56bb8a5SSatoshi Asami 	}
1557a56bb8a5SSatoshi Asami 
1558ba4ad1fcSPoul-Henning Kamp 	if (!vn_isdisk(vp, &error))
1559762e6b85SEivind Eklund 		goto bad;
1560a56bb8a5SSatoshi Asami 
1561a56bb8a5SSatoshi Asami #ifdef DEBUG
1562a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_VNODE)
1563a56bb8a5SSatoshi Asami 		vprint("ccdlookup: vnode info", vp);
1564a56bb8a5SSatoshi Asami #endif
1565a56bb8a5SSatoshi Asami 
156606bcc9e5SMike Pritchard 	VOP_UNLOCK(vp, 0, p);
1567762e6b85SEivind Eklund 	NDFREE(&nd, NDF_ONLY_PNBUF);
1568a56bb8a5SSatoshi Asami 	*vpp = vp;
1569a56bb8a5SSatoshi Asami 	return (0);
1570762e6b85SEivind Eklund bad:
1571762e6b85SEivind Eklund 	VOP_UNLOCK(vp, 0, p);
1572762e6b85SEivind Eklund 	NDFREE(&nd, NDF_ONLY_PNBUF);
1573762e6b85SEivind Eklund 	/* vn_close does vrele() for vp */
1574762e6b85SEivind Eklund 	(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1575762e6b85SEivind Eklund 	return (error);
1576a56bb8a5SSatoshi Asami }
1577a56bb8a5SSatoshi Asami 
1578a56bb8a5SSatoshi Asami /*
1579a56bb8a5SSatoshi Asami  * Read the disklabel from the ccd.  If one is not present, fake one
1580a56bb8a5SSatoshi Asami  * up.
1581a56bb8a5SSatoshi Asami  */
1582a56bb8a5SSatoshi Asami static void
1583a56bb8a5SSatoshi Asami ccdgetdisklabel(dev)
1584a56bb8a5SSatoshi Asami 	dev_t dev;
1585a56bb8a5SSatoshi Asami {
1586a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
1587a56bb8a5SSatoshi Asami 	struct ccd_softc *cs = &ccd_softc[unit];
1588a56bb8a5SSatoshi Asami 	char *errstring;
15896cc5a722SPoul-Henning Kamp 	struct disklabel *lp = &cs->sc_label;
1590a56bb8a5SSatoshi Asami 	struct ccdgeom *ccg = &cs->sc_geom;
1591a56bb8a5SSatoshi Asami 
1592a56bb8a5SSatoshi Asami 	bzero(lp, sizeof(*lp));
1593a56bb8a5SSatoshi Asami 
1594a56bb8a5SSatoshi Asami 	lp->d_secperunit = cs->sc_size;
1595a56bb8a5SSatoshi Asami 	lp->d_secsize = ccg->ccg_secsize;
1596a56bb8a5SSatoshi Asami 	lp->d_nsectors = ccg->ccg_nsectors;
1597a56bb8a5SSatoshi Asami 	lp->d_ntracks = ccg->ccg_ntracks;
1598a56bb8a5SSatoshi Asami 	lp->d_ncylinders = ccg->ccg_ncylinders;
1599a56bb8a5SSatoshi Asami 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1600a56bb8a5SSatoshi Asami 
1601a56bb8a5SSatoshi Asami 	strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1602a56bb8a5SSatoshi Asami 	lp->d_type = DTYPE_CCD;
1603a56bb8a5SSatoshi Asami 	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1604a56bb8a5SSatoshi Asami 	lp->d_rpm = 3600;
1605a56bb8a5SSatoshi Asami 	lp->d_interleave = 1;
1606a56bb8a5SSatoshi Asami 	lp->d_flags = 0;
1607a56bb8a5SSatoshi Asami 
1608a56bb8a5SSatoshi Asami 	lp->d_partitions[RAW_PART].p_offset = 0;
1609a56bb8a5SSatoshi Asami 	lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1610a56bb8a5SSatoshi Asami 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1611a56bb8a5SSatoshi Asami 	lp->d_npartitions = RAW_PART + 1;
1612a56bb8a5SSatoshi Asami 
1613d8594dfbSSatoshi Asami 	lp->d_bbsize = BBSIZE;				/* XXX */
1614d8594dfbSSatoshi Asami 	lp->d_sbsize = SBSIZE;				/* XXX */
1615d8594dfbSSatoshi Asami 
1616a56bb8a5SSatoshi Asami 	lp->d_magic = DISKMAGIC;
1617a56bb8a5SSatoshi Asami 	lp->d_magic2 = DISKMAGIC;
16186cc5a722SPoul-Henning Kamp 	lp->d_checksum = dkcksum(&cs->sc_label);
1619a56bb8a5SSatoshi Asami 
1620a56bb8a5SSatoshi Asami 	/*
1621a56bb8a5SSatoshi Asami 	 * Call the generic disklabel extraction routine.
1622a56bb8a5SSatoshi Asami 	 */
162349ff4debSPoul-Henning Kamp 	errstring = readdisklabel(CCDLABELDEV(dev), &cs->sc_label);
162449ff4debSPoul-Henning Kamp 	if (errstring != NULL)
1625a56bb8a5SSatoshi Asami 		ccdmakedisklabel(cs);
1626a56bb8a5SSatoshi Asami 
1627a56bb8a5SSatoshi Asami #ifdef DEBUG
1628a56bb8a5SSatoshi Asami 	/* It's actually extremely common to have unlabeled ccds. */
1629a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_LABEL)
1630a56bb8a5SSatoshi Asami 		if (errstring != NULL)
1631a56bb8a5SSatoshi Asami 			printf("ccd%d: %s\n", unit, errstring);
1632a56bb8a5SSatoshi Asami #endif
1633a56bb8a5SSatoshi Asami }
1634a56bb8a5SSatoshi Asami 
1635a56bb8a5SSatoshi Asami /*
1636a56bb8a5SSatoshi Asami  * Take care of things one might want to take care of in the event
1637a56bb8a5SSatoshi Asami  * that a disklabel isn't present.
1638a56bb8a5SSatoshi Asami  */
1639a56bb8a5SSatoshi Asami static void
1640a56bb8a5SSatoshi Asami ccdmakedisklabel(cs)
1641a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1642a56bb8a5SSatoshi Asami {
16436cc5a722SPoul-Henning Kamp 	struct disklabel *lp = &cs->sc_label;
1644a56bb8a5SSatoshi Asami 
1645a56bb8a5SSatoshi Asami 	/*
1646a56bb8a5SSatoshi Asami 	 * For historical reasons, if there's no disklabel present
1647a56bb8a5SSatoshi Asami 	 * the raw partition must be marked FS_BSDFFS.
1648a56bb8a5SSatoshi Asami 	 */
1649a56bb8a5SSatoshi Asami 	lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1650a56bb8a5SSatoshi Asami 
1651a56bb8a5SSatoshi Asami 	strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1652a56bb8a5SSatoshi Asami }
1653a56bb8a5SSatoshi Asami 
1654a56bb8a5SSatoshi Asami /*
1655a56bb8a5SSatoshi Asami  * Wait interruptibly for an exclusive lock.
1656a56bb8a5SSatoshi Asami  *
1657a56bb8a5SSatoshi Asami  * XXX
1658a56bb8a5SSatoshi Asami  * Several drivers do this; it should be abstracted and made MP-safe.
1659a56bb8a5SSatoshi Asami  */
1660a56bb8a5SSatoshi Asami static int
1661a56bb8a5SSatoshi Asami ccdlock(cs)
1662a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1663a56bb8a5SSatoshi Asami {
1664a56bb8a5SSatoshi Asami 	int error;
1665a56bb8a5SSatoshi Asami 
1666a56bb8a5SSatoshi Asami 	while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1667a56bb8a5SSatoshi Asami 		cs->sc_flags |= CCDF_WANTED;
1668a56bb8a5SSatoshi Asami 		if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1669a56bb8a5SSatoshi Asami 			return (error);
1670a56bb8a5SSatoshi Asami 	}
1671a56bb8a5SSatoshi Asami 	cs->sc_flags |= CCDF_LOCKED;
1672a56bb8a5SSatoshi Asami 	return (0);
1673a56bb8a5SSatoshi Asami }
1674a56bb8a5SSatoshi Asami 
1675a56bb8a5SSatoshi Asami /*
1676a56bb8a5SSatoshi Asami  * Unlock and wake up any waiters.
1677a56bb8a5SSatoshi Asami  */
1678a56bb8a5SSatoshi Asami static void
1679a56bb8a5SSatoshi Asami ccdunlock(cs)
1680a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1681a56bb8a5SSatoshi Asami {
1682a56bb8a5SSatoshi Asami 
1683a56bb8a5SSatoshi Asami 	cs->sc_flags &= ~CCDF_LOCKED;
1684a56bb8a5SSatoshi Asami 	if ((cs->sc_flags & CCDF_WANTED) != 0) {
1685a56bb8a5SSatoshi Asami 		cs->sc_flags &= ~CCDF_WANTED;
1686a56bb8a5SSatoshi Asami 		wakeup(cs);
1687a56bb8a5SSatoshi Asami 	}
1688a56bb8a5SSatoshi Asami }
1689a56bb8a5SSatoshi Asami 
1690a56bb8a5SSatoshi Asami #ifdef DEBUG
1691a56bb8a5SSatoshi Asami static void
1692a56bb8a5SSatoshi Asami printiinfo(ii)
1693a56bb8a5SSatoshi Asami 	struct ccdiinfo *ii;
1694a56bb8a5SSatoshi Asami {
16951464240eSMatthew Dillon 	int ix, i;
1696a56bb8a5SSatoshi Asami 
1697a56bb8a5SSatoshi Asami 	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1698a56bb8a5SSatoshi Asami 		printf(" itab[%d]: #dk %d sblk %d soff %d",
1699a56bb8a5SSatoshi Asami 		       ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1700a56bb8a5SSatoshi Asami 		for (i = 0; i < ii->ii_ndisk; i++)
1701a56bb8a5SSatoshi Asami 			printf(" %d", ii->ii_index[i]);
1702a56bb8a5SSatoshi Asami 		printf("\n");
1703a56bb8a5SSatoshi Asami 	}
1704a56bb8a5SSatoshi Asami }
1705a56bb8a5SSatoshi Asami #endif
1706d8594dfbSSatoshi Asami 
1707d8594dfbSSatoshi Asami 
1708d8594dfbSSatoshi Asami /* Local Variables: */
1709d8594dfbSSatoshi Asami /* c-argdecl-indent: 8 */
171009b59204SSatoshi Asami /* c-continued-statement-offset: 8 */
1711d8594dfbSSatoshi Asami /* c-indent-level: 8 */
1712d8594dfbSSatoshi Asami /* End: */
1713