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