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