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