xref: /freebsd/sys/geom/geom_ccd.c (revision 3bc746be91c04a326969480c00af3c56d20c32aa)
13bc746beSSatoshi Asami /* $Id: ccd.c,v 1.5 1996/01/30 22:34:53 asami 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>
95a56bb8a5SSatoshi Asami #include <sys/proc.h>
96a56bb8a5SSatoshi Asami #include <sys/errno.h>
97a56bb8a5SSatoshi Asami #include <sys/dkstat.h>
98a56bb8a5SSatoshi Asami #include <sys/buf.h>
99a56bb8a5SSatoshi Asami #include <sys/malloc.h>
100a56bb8a5SSatoshi Asami #include <sys/namei.h>
101a56bb8a5SSatoshi Asami #include <sys/conf.h>
102a56bb8a5SSatoshi Asami #include <sys/stat.h>
103a56bb8a5SSatoshi Asami #include <sys/ioctl.h>
104a56bb8a5SSatoshi Asami #include <sys/disklabel.h>
105d8594dfbSSatoshi Asami #include <ufs/ffs/fs.h>
106d8594dfbSSatoshi Asami #include <sys/devconf.h>
107a56bb8a5SSatoshi Asami #include <sys/device.h>
108a56bb8a5SSatoshi Asami #include <sys/disk.h>
109a56bb8a5SSatoshi Asami #include <sys/syslog.h>
110a56bb8a5SSatoshi Asami #include <sys/fcntl.h>
111a56bb8a5SSatoshi Asami #include <sys/vnode.h>
112d8594dfbSSatoshi Asami #include <sys/dkbad.h>
113a56bb8a5SSatoshi Asami 
114d8594dfbSSatoshi Asami #include <sys/ccdvar.h>
115a56bb8a5SSatoshi Asami 
116a56bb8a5SSatoshi Asami #if defined(CCDDEBUG) && !defined(DEBUG)
117a56bb8a5SSatoshi Asami #define DEBUG
118a56bb8a5SSatoshi Asami #endif
119a56bb8a5SSatoshi Asami 
120a56bb8a5SSatoshi Asami #ifdef DEBUG
121a56bb8a5SSatoshi Asami #define CCDB_FOLLOW	0x01
122a56bb8a5SSatoshi Asami #define CCDB_INIT	0x02
123a56bb8a5SSatoshi Asami #define CCDB_IO		0x04
124a56bb8a5SSatoshi Asami #define CCDB_LABEL	0x08
125a56bb8a5SSatoshi Asami #define CCDB_VNODE	0x10
126d8594dfbSSatoshi Asami int ccddebug = CCDB_FOLLOW | CCDB_INIT | CCDB_IO | CCDB_LABEL | CCDB_VNODE;
127d8594dfbSSatoshi Asami #undef DEBUG
128a56bb8a5SSatoshi Asami #endif
129a56bb8a5SSatoshi Asami 
130d8594dfbSSatoshi Asami #define	ccdunit(x)	dkunit(x)
131d8594dfbSSatoshi Asami #define ccdpart(x)	dkpart(x)
132a56bb8a5SSatoshi Asami 
133a56bb8a5SSatoshi Asami struct ccdbuf {
134a56bb8a5SSatoshi Asami 	struct buf	cb_buf;		/* new I/O buf */
135a56bb8a5SSatoshi Asami 	struct buf	*cb_obp;	/* ptr. to original I/O buf */
136a56bb8a5SSatoshi Asami 	int		cb_unit;	/* target unit */
137a56bb8a5SSatoshi Asami 	int		cb_comp;	/* target component */
138a56bb8a5SSatoshi Asami };
139a56bb8a5SSatoshi Asami 
140a56bb8a5SSatoshi Asami #define	getccdbuf()		\
141a56bb8a5SSatoshi Asami 	((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK))
142a56bb8a5SSatoshi Asami #define putccdbuf(cbp)		\
143a56bb8a5SSatoshi Asami 	free((caddr_t)(cbp), M_DEVBUF)
144a56bb8a5SSatoshi Asami 
145a56bb8a5SSatoshi Asami #define CCDLABELDEV(dev)	\
146d8594dfbSSatoshi Asami 	(makedev(major((dev)), dkmakeminor(ccdunit((dev)), 0, RAW_PART)))
147a56bb8a5SSatoshi Asami 
148a56bb8a5SSatoshi Asami /* {b,c}devsw[] function prototypes */
149d8594dfbSSatoshi Asami d_open_t ccdopen ;
150d8594dfbSSatoshi Asami d_close_t ccdclose ;
151d8594dfbSSatoshi Asami d_strategy_t ccdstrategy ;
152d8594dfbSSatoshi Asami d_ioctl_t ccdioctl ;
153d8594dfbSSatoshi Asami d_read_t ccdread ;
154d8594dfbSSatoshi Asami d_write_t ccdwrite ;
155d8594dfbSSatoshi Asami 
156a56bb8a5SSatoshi Asami 
157a56bb8a5SSatoshi Asami /* called by main() at boot time */
158d8594dfbSSatoshi Asami int	ccdattach __P((struct isa_device *dp));
159d8594dfbSSatoshi Asami int	ccdprobe __P((struct isa_device *dp));
160a56bb8a5SSatoshi Asami 
161a56bb8a5SSatoshi Asami /* called by biodone() at interrupt time */
162a56bb8a5SSatoshi Asami void	ccdiodone __P((struct ccdbuf *cbp));
163a56bb8a5SSatoshi Asami 
164a56bb8a5SSatoshi Asami static	void ccdstart __P((struct ccd_softc *, struct buf *));
165a56bb8a5SSatoshi Asami static	void ccdinterleave __P((struct ccd_softc *, int));
166a56bb8a5SSatoshi Asami static	void ccdintr __P((struct ccd_softc *, struct buf *));
167a56bb8a5SSatoshi Asami static	int ccdinit __P((struct ccddevice *, char **, struct proc *));
168a56bb8a5SSatoshi Asami static	int ccdlookup __P((char *, struct proc *p, struct vnode **));
1693bc746beSSatoshi Asami static	void ccdbuffer __P((struct ccdbuf **ret, struct ccd_softc *,
1703bc746beSSatoshi Asami 		struct buf *, daddr_t, caddr_t, long));
171a56bb8a5SSatoshi Asami static	void ccdgetdisklabel __P((dev_t));
172a56bb8a5SSatoshi Asami static	void ccdmakedisklabel __P((struct ccd_softc *));
173a56bb8a5SSatoshi Asami static	int ccdlock __P((struct ccd_softc *));
174a56bb8a5SSatoshi Asami static	void ccdunlock __P((struct ccd_softc *));
175a56bb8a5SSatoshi Asami 
176d8594dfbSSatoshi Asami static	void loopdelay __P((void));
177d8594dfbSSatoshi Asami 
178a56bb8a5SSatoshi Asami #ifdef DEBUG
179a56bb8a5SSatoshi Asami static	void printiinfo __P((struct ccdiinfo *));
180a56bb8a5SSatoshi Asami #endif
181a56bb8a5SSatoshi Asami 
182a56bb8a5SSatoshi Asami /* Non-private for the benefit of libkvm. */
183a56bb8a5SSatoshi Asami struct	ccd_softc *ccd_softc;
184a56bb8a5SSatoshi Asami struct	ccddevice *ccddevs;
185a56bb8a5SSatoshi Asami int	numccd = 0;
186a56bb8a5SSatoshi Asami 
187d8594dfbSSatoshi Asami static struct kern_devconf kdc_ccd[NCCD] = { {
188d8594dfbSSatoshi Asami         0, 0, 0,                /* filled in by dev_attach */
189d8594dfbSSatoshi Asami         "ccd", 0, { MDDT_DISK, 0, "tty" },
190d8594dfbSSatoshi Asami         0, 0, 0, DISK_EXTERNALLEN,
191d8594dfbSSatoshi Asami         0,                      /* parent */
192d8594dfbSSatoshi Asami         0,                      /* parentdata */
193d8594dfbSSatoshi Asami         DC_UNKNOWN,             /* not supported */
194d8594dfbSSatoshi Asami         "Concatenated disk driver"
195d8594dfbSSatoshi Asami } };
196d8594dfbSSatoshi Asami 
197d8594dfbSSatoshi Asami struct isa_driver ccddriver = {
198d8594dfbSSatoshi Asami         ccdprobe, ccdattach, "ccd",
199d8594dfbSSatoshi Asami };
200d8594dfbSSatoshi Asami 
201d8594dfbSSatoshi Asami int
202d8594dfbSSatoshi Asami ccdprobe(dp)
203d8594dfbSSatoshi Asami 	struct isa_device *dp;
204d8594dfbSSatoshi Asami {
205d8594dfbSSatoshi Asami 	return -1;
206d8594dfbSSatoshi Asami }
207d8594dfbSSatoshi Asami 
208a56bb8a5SSatoshi Asami /*
209a56bb8a5SSatoshi Asami  * Called by main() during pseudo-device attachment.  All we need
210a56bb8a5SSatoshi Asami  * to do is allocate enough space for devices to be configured later.
211a56bb8a5SSatoshi Asami  */
212d8594dfbSSatoshi Asami int
213d8594dfbSSatoshi Asami ccdattach(dp)
214d8594dfbSSatoshi Asami 	struct isa_device *dp;
215a56bb8a5SSatoshi Asami {
216a56bb8a5SSatoshi Asami 	int i;
217d8594dfbSSatoshi Asami 	int num = dp->id_unit;
218a56bb8a5SSatoshi Asami 
219d8594dfbSSatoshi Asami 	if (num < 0) {
220a56bb8a5SSatoshi Asami #ifdef DIAGNOSTIC
221a56bb8a5SSatoshi Asami 		panic("ccdattach: count <= 0");
222a56bb8a5SSatoshi Asami #endif
223d8594dfbSSatoshi Asami 		return 0;
224a56bb8a5SSatoshi Asami 	}
225a56bb8a5SSatoshi Asami 
226d8594dfbSSatoshi Asami 	if (num == NCCD-1) {
227d8594dfbSSatoshi Asami 		if (num)
228d8594dfbSSatoshi Asami 			printf("ccd0-%d: Concatenated disk drivers\n", num);
229d8594dfbSSatoshi Asami 		else
230d8594dfbSSatoshi Asami 			printf("ccd0: Concatenated disk driver\n", num);
231d8594dfbSSatoshi Asami 	}
232d8594dfbSSatoshi Asami 
233d8594dfbSSatoshi Asami 	if (num > 0) {
234d8594dfbSSatoshi Asami 		/* only do initialization first time around */
235d8594dfbSSatoshi Asami 		return 0;
236d8594dfbSSatoshi Asami 	}
237d8594dfbSSatoshi Asami 	num = NCCD;
238a56bb8a5SSatoshi Asami 	ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
239a56bb8a5SSatoshi Asami 	    M_DEVBUF, M_NOWAIT);
240a56bb8a5SSatoshi Asami 	ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice),
241a56bb8a5SSatoshi Asami 	    M_DEVBUF, M_NOWAIT);
242a56bb8a5SSatoshi Asami 	if ((ccd_softc == NULL) || (ccddevs == NULL)) {
243a56bb8a5SSatoshi Asami 		printf("WARNING: no memory for concatenated disks\n");
244a56bb8a5SSatoshi Asami 		if (ccd_softc != NULL)
245a56bb8a5SSatoshi Asami 			free(ccd_softc, M_DEVBUF);
246a56bb8a5SSatoshi Asami 		if (ccddevs != NULL)
247a56bb8a5SSatoshi Asami 			free(ccddevs, M_DEVBUF);
248d8594dfbSSatoshi Asami 		return 0;
249a56bb8a5SSatoshi Asami 	}
250a56bb8a5SSatoshi Asami 	numccd = num;
251a56bb8a5SSatoshi Asami 	bzero(ccd_softc, num * sizeof(struct ccd_softc));
252a56bb8a5SSatoshi Asami 	bzero(ccddevs, num * sizeof(struct ccddevice));
253a56bb8a5SSatoshi Asami 
254a56bb8a5SSatoshi Asami 	/* XXX: is this necessary? */
255a56bb8a5SSatoshi Asami 	for (i = 0; i < numccd; ++i)
256a56bb8a5SSatoshi Asami 		ccddevs[i].ccd_dk = -1;
257d8594dfbSSatoshi Asami 
258d8594dfbSSatoshi Asami 	dev_attach(&kdc_ccd[dp->id_unit]);
259d8594dfbSSatoshi Asami 	return 1;
260a56bb8a5SSatoshi Asami }
261a56bb8a5SSatoshi Asami 
262a56bb8a5SSatoshi Asami static int
263a56bb8a5SSatoshi Asami ccdinit(ccd, cpaths, p)
264a56bb8a5SSatoshi Asami 	struct ccddevice *ccd;
265a56bb8a5SSatoshi Asami 	char **cpaths;
266a56bb8a5SSatoshi Asami 	struct proc *p;
267a56bb8a5SSatoshi Asami {
268a56bb8a5SSatoshi Asami 	register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit];
269a56bb8a5SSatoshi Asami 	register struct ccdcinfo *ci;
270a56bb8a5SSatoshi Asami 	register size_t size;
271a56bb8a5SSatoshi Asami 	register int ix;
272a56bb8a5SSatoshi Asami 	struct vnode *vp;
273a56bb8a5SSatoshi Asami 	struct vattr va;
274a56bb8a5SSatoshi Asami 	size_t minsize;
275a56bb8a5SSatoshi Asami 	int maxsecsize;
276a56bb8a5SSatoshi Asami 	struct partinfo dpart;
277a56bb8a5SSatoshi Asami 	struct ccdgeom *ccg = &cs->sc_geom;
278a56bb8a5SSatoshi Asami 	char tmppath[MAXPATHLEN];
279a56bb8a5SSatoshi Asami 	int error;
280a56bb8a5SSatoshi Asami 
281a56bb8a5SSatoshi Asami #ifdef DEBUG
282a56bb8a5SSatoshi Asami 	if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
283a56bb8a5SSatoshi Asami 		printf("ccdinit: unit %d\n", ccd->ccd_unit);
284a56bb8a5SSatoshi Asami #endif
285a56bb8a5SSatoshi Asami 
286a56bb8a5SSatoshi Asami #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
287a56bb8a5SSatoshi Asami 	cs->sc_dk = ccd->ccd_dk;
288a56bb8a5SSatoshi Asami #endif
289a56bb8a5SSatoshi Asami 	cs->sc_size = 0;
290a56bb8a5SSatoshi Asami 	cs->sc_ileave = ccd->ccd_interleave;
291a56bb8a5SSatoshi Asami 	cs->sc_nccdisks = ccd->ccd_ndev;
292a56bb8a5SSatoshi Asami 
293a56bb8a5SSatoshi Asami 	/* Allocate space for the component info. */
294a56bb8a5SSatoshi Asami 	cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
295a56bb8a5SSatoshi Asami 	    M_DEVBUF, M_WAITOK);
296a56bb8a5SSatoshi Asami 
297a56bb8a5SSatoshi Asami 	/*
298a56bb8a5SSatoshi Asami 	 * Verify that each component piece exists and record
299a56bb8a5SSatoshi Asami 	 * relevant information about it.
300a56bb8a5SSatoshi Asami 	 */
301a56bb8a5SSatoshi Asami 	maxsecsize = 0;
302a56bb8a5SSatoshi Asami 	minsize = 0;
303a56bb8a5SSatoshi Asami 	for (ix = 0; ix < cs->sc_nccdisks; ix++) {
304a56bb8a5SSatoshi Asami 		vp = ccd->ccd_vpp[ix];
305a56bb8a5SSatoshi Asami 		ci = &cs->sc_cinfo[ix];
306a56bb8a5SSatoshi Asami 		ci->ci_vp = vp;
307a56bb8a5SSatoshi Asami 
308a56bb8a5SSatoshi Asami 		/*
309a56bb8a5SSatoshi Asami 		 * Copy in the pathname of the component.
310a56bb8a5SSatoshi Asami 		 */
311a56bb8a5SSatoshi Asami 		bzero(tmppath, sizeof(tmppath));	/* sanity */
312a56bb8a5SSatoshi Asami 		if (error = copyinstr(cpaths[ix], tmppath,
313a56bb8a5SSatoshi Asami 		    MAXPATHLEN, &ci->ci_pathlen)) {
314a56bb8a5SSatoshi Asami #ifdef DEBUG
315a56bb8a5SSatoshi Asami 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
316a56bb8a5SSatoshi Asami 				printf("ccd%d: can't copy path, error = %d\n",
317a56bb8a5SSatoshi Asami 				    ccd->ccd_unit, error);
318a56bb8a5SSatoshi Asami #endif
319a56bb8a5SSatoshi Asami 			free(cs->sc_cinfo, M_DEVBUF);
320a56bb8a5SSatoshi Asami 			return (error);
321a56bb8a5SSatoshi Asami 		}
322a56bb8a5SSatoshi Asami 		ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
323a56bb8a5SSatoshi Asami 		bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
324a56bb8a5SSatoshi Asami 
325a56bb8a5SSatoshi Asami 		/*
326a56bb8a5SSatoshi Asami 		 * XXX: Cache the component's dev_t.
327a56bb8a5SSatoshi Asami 		 */
328a56bb8a5SSatoshi Asami 		if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) {
329a56bb8a5SSatoshi Asami #ifdef DEBUG
330a56bb8a5SSatoshi Asami 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
331a56bb8a5SSatoshi Asami 				printf("ccd%d: %s: getattr failed %s = %d\n",
332a56bb8a5SSatoshi Asami 				    ccd->ccd_unit, ci->ci_path,
333a56bb8a5SSatoshi Asami 				    "error", error);
334a56bb8a5SSatoshi Asami #endif
335a56bb8a5SSatoshi Asami 			free(ci->ci_path, M_DEVBUF);
336a56bb8a5SSatoshi Asami 			free(cs->sc_cinfo, M_DEVBUF);
337a56bb8a5SSatoshi Asami 			return (error);
338a56bb8a5SSatoshi Asami 		}
339a56bb8a5SSatoshi Asami 		ci->ci_dev = va.va_rdev;
340a56bb8a5SSatoshi Asami 
341a56bb8a5SSatoshi Asami 		/*
342a56bb8a5SSatoshi Asami 		 * Get partition information for the component.
343a56bb8a5SSatoshi Asami 		 */
344a56bb8a5SSatoshi Asami 		if (error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart,
345a56bb8a5SSatoshi Asami 		    FREAD, p->p_ucred, p)) {
346a56bb8a5SSatoshi Asami #ifdef DEBUG
347a56bb8a5SSatoshi Asami 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
348a56bb8a5SSatoshi Asami 				 printf("ccd%d: %s: ioctl failed, error = %d\n",
349a56bb8a5SSatoshi Asami 				     ccd->ccd_unit, ci->ci_path, error);
350a56bb8a5SSatoshi Asami #endif
351a56bb8a5SSatoshi Asami 			free(ci->ci_path, M_DEVBUF);
352a56bb8a5SSatoshi Asami 			free(cs->sc_cinfo, M_DEVBUF);
353a56bb8a5SSatoshi Asami 			return (error);
354a56bb8a5SSatoshi Asami 		}
355a56bb8a5SSatoshi Asami 		if (dpart.part->p_fstype == FS_BSDFFS) {
356a56bb8a5SSatoshi Asami 			maxsecsize =
357a56bb8a5SSatoshi Asami 			    ((dpart.disklab->d_secsize > maxsecsize) ?
358a56bb8a5SSatoshi Asami 			    dpart.disklab->d_secsize : maxsecsize);
359a56bb8a5SSatoshi Asami 			size = dpart.part->p_size;
360a56bb8a5SSatoshi Asami 		} else {
361a56bb8a5SSatoshi Asami #ifdef DEBUG
362a56bb8a5SSatoshi Asami 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
363a56bb8a5SSatoshi Asami 				printf("ccd%d: %s: incorrect partition type\n",
364a56bb8a5SSatoshi Asami 				    ccd->ccd_unit, ci->ci_path);
365a56bb8a5SSatoshi Asami #endif
366a56bb8a5SSatoshi Asami 			free(ci->ci_path, M_DEVBUF);
367a56bb8a5SSatoshi Asami 			free(cs->sc_cinfo, M_DEVBUF);
368a56bb8a5SSatoshi Asami 			return (EFTYPE);
369a56bb8a5SSatoshi Asami 		}
370a56bb8a5SSatoshi Asami 
371a56bb8a5SSatoshi Asami 		/*
372a56bb8a5SSatoshi Asami 		 * Calculate the size, truncating to an interleave
373a56bb8a5SSatoshi Asami 		 * boundary if necessary.
374a56bb8a5SSatoshi Asami 		 */
375a56bb8a5SSatoshi Asami 		if (size < 0)
376a56bb8a5SSatoshi Asami 			size = 0;
377a56bb8a5SSatoshi Asami 
378a56bb8a5SSatoshi Asami 		if (cs->sc_ileave > 1)
379a56bb8a5SSatoshi Asami 			size -= size % cs->sc_ileave;
380a56bb8a5SSatoshi Asami 
381a56bb8a5SSatoshi Asami 		if (size == 0) {
382a56bb8a5SSatoshi Asami #ifdef DEBUG
383a56bb8a5SSatoshi Asami 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
384a56bb8a5SSatoshi Asami 				printf("ccd%d: %s: size == 0\n",
385a56bb8a5SSatoshi Asami 				    ccd->ccd_unit, ci->ci_path);
386a56bb8a5SSatoshi Asami #endif
387a56bb8a5SSatoshi Asami 			free(ci->ci_path, M_DEVBUF);
388a56bb8a5SSatoshi Asami 			free(cs->sc_cinfo, M_DEVBUF);
389a56bb8a5SSatoshi Asami 			return (ENODEV);
390a56bb8a5SSatoshi Asami 		}
391a56bb8a5SSatoshi Asami 
392a56bb8a5SSatoshi Asami 		if (minsize == 0 || size < minsize)
393a56bb8a5SSatoshi Asami 			minsize = size;
394a56bb8a5SSatoshi Asami 		ci->ci_size = size;
395a56bb8a5SSatoshi Asami 		cs->sc_size += size;
396a56bb8a5SSatoshi Asami 	}
397a56bb8a5SSatoshi Asami 
398a56bb8a5SSatoshi Asami 	/*
399a56bb8a5SSatoshi Asami 	 * Don't allow the interleave to be smaller than
400a56bb8a5SSatoshi Asami 	 * the biggest component sector.
401a56bb8a5SSatoshi Asami 	 */
402a56bb8a5SSatoshi Asami 	if ((cs->sc_ileave > 0) &&
403a56bb8a5SSatoshi Asami 	    (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
404a56bb8a5SSatoshi Asami #ifdef DEBUG
405a56bb8a5SSatoshi Asami 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
406a56bb8a5SSatoshi Asami 			printf("ccd%d: interleave must be at least %d\n",
407a56bb8a5SSatoshi Asami 			    ccd->ccd_unit, (maxsecsize / DEV_BSIZE));
408a56bb8a5SSatoshi Asami #endif
409a56bb8a5SSatoshi Asami 		free(ci->ci_path, M_DEVBUF);
410a56bb8a5SSatoshi Asami 		free(cs->sc_cinfo, M_DEVBUF);
411a56bb8a5SSatoshi Asami 		return (EINVAL);
412a56bb8a5SSatoshi Asami 	}
413a56bb8a5SSatoshi Asami 
414a56bb8a5SSatoshi Asami 	/*
415a56bb8a5SSatoshi Asami 	 * If uniform interleave is desired set all sizes to that of
416a56bb8a5SSatoshi Asami 	 * the smallest component.
417a56bb8a5SSatoshi Asami 	 */
418a56bb8a5SSatoshi Asami 	if (ccd->ccd_flags & CCDF_UNIFORM) {
419a56bb8a5SSatoshi Asami 		for (ci = cs->sc_cinfo;
420a56bb8a5SSatoshi Asami 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
421a56bb8a5SSatoshi Asami 			ci->ci_size = minsize;
42209b59204SSatoshi Asami 		if (ccd->ccd_flags & CCDF_MIRROR) {
42309b59204SSatoshi Asami 			if (cs->sc_nccdisks % 2) {
42409b59204SSatoshi Asami 				cs->sc_nccdisks--;
42509b59204SSatoshi Asami 				printf("ccd%d: mirroring requires even number of disks; using %d\n",
42609b59204SSatoshi Asami 				       ccd->ccd_unit, cs->sc_nccdisks);
42709b59204SSatoshi Asami 			}
42809b59204SSatoshi Asami 			cs->sc_size = (cs->sc_nccdisks/2) * minsize;
42909b59204SSatoshi Asami 		}
43009b59204SSatoshi Asami 		else if (ccd->ccd_flags & CCDF_PARITY)
4317ecb65faSSatoshi Asami 			cs->sc_size = (cs->sc_nccdisks-1) * minsize;
4327ecb65faSSatoshi Asami 		else
433a56bb8a5SSatoshi Asami 			cs->sc_size = cs->sc_nccdisks * minsize;
434a56bb8a5SSatoshi Asami 	}
435a56bb8a5SSatoshi Asami 
436a56bb8a5SSatoshi Asami 	/*
437a56bb8a5SSatoshi Asami 	 * Construct the interleave table.
438a56bb8a5SSatoshi Asami 	 */
439a56bb8a5SSatoshi Asami 	ccdinterleave(cs, ccd->ccd_unit);
440a56bb8a5SSatoshi Asami 
441a56bb8a5SSatoshi Asami 	/*
442a56bb8a5SSatoshi Asami 	 * Create pseudo-geometry based on 1MB cylinders.  It's
443a56bb8a5SSatoshi Asami 	 * pretty close.
444a56bb8a5SSatoshi Asami 	 */
445a56bb8a5SSatoshi Asami 	ccg->ccg_secsize = DEV_BSIZE;
446a56bb8a5SSatoshi Asami 	ccg->ccg_ntracks = 1;
447a56bb8a5SSatoshi Asami 	ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
448a56bb8a5SSatoshi Asami 	ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
449a56bb8a5SSatoshi Asami 
450a56bb8a5SSatoshi Asami #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
451a56bb8a5SSatoshi Asami 	if (ccd->ccd_dk >= 0)
452a56bb8a5SSatoshi Asami 		dk_wpms[ccd->ccd_dk] = 32 * (60 * DEV_BSIZE / 2);     /* XXX */
453a56bb8a5SSatoshi Asami #endif
454a56bb8a5SSatoshi Asami 
455a56bb8a5SSatoshi Asami 	cs->sc_flags |= CCDF_INITED;
456a56bb8a5SSatoshi Asami 	cs->sc_cflags = ccd->ccd_flags;	/* So we can find out later... */
457a56bb8a5SSatoshi Asami 	cs->sc_unit = ccd->ccd_unit;
458a56bb8a5SSatoshi Asami 	return (0);
459a56bb8a5SSatoshi Asami }
460a56bb8a5SSatoshi Asami 
461a56bb8a5SSatoshi Asami static void
462a56bb8a5SSatoshi Asami ccdinterleave(cs, unit)
463a56bb8a5SSatoshi Asami 	register struct ccd_softc *cs;
464a56bb8a5SSatoshi Asami 	int unit;
465a56bb8a5SSatoshi Asami {
466a56bb8a5SSatoshi Asami 	register struct ccdcinfo *ci, *smallci;
467a56bb8a5SSatoshi Asami 	register struct ccdiinfo *ii;
468a56bb8a5SSatoshi Asami 	register daddr_t bn, lbn;
469a56bb8a5SSatoshi Asami 	register int ix;
470a56bb8a5SSatoshi Asami 	u_long size;
471a56bb8a5SSatoshi Asami 
472a56bb8a5SSatoshi Asami #ifdef DEBUG
473a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_INIT)
474a56bb8a5SSatoshi Asami 		printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
475a56bb8a5SSatoshi Asami #endif
476a56bb8a5SSatoshi Asami 	/*
477a56bb8a5SSatoshi Asami 	 * Allocate an interleave table.
478a56bb8a5SSatoshi Asami 	 * Chances are this is too big, but we don't care.
479a56bb8a5SSatoshi Asami 	 */
480a56bb8a5SSatoshi Asami 	size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
481a56bb8a5SSatoshi Asami 	cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
482a56bb8a5SSatoshi Asami 	bzero((caddr_t)cs->sc_itable, size);
483a56bb8a5SSatoshi Asami 
484a56bb8a5SSatoshi Asami 	/*
485a56bb8a5SSatoshi Asami 	 * Trivial case: no interleave (actually interleave of disk size).
486a56bb8a5SSatoshi Asami 	 * Each table entry represents a single component in its entirety.
487a56bb8a5SSatoshi Asami 	 */
488a56bb8a5SSatoshi Asami 	if (cs->sc_ileave == 0) {
489a56bb8a5SSatoshi Asami 		bn = 0;
490a56bb8a5SSatoshi Asami 		ii = cs->sc_itable;
491a56bb8a5SSatoshi Asami 
492a56bb8a5SSatoshi Asami 		for (ix = 0; ix < cs->sc_nccdisks; ix++) {
493a56bb8a5SSatoshi Asami 			/* Allocate space for ii_index. */
494a56bb8a5SSatoshi Asami 			ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
495a56bb8a5SSatoshi Asami 			ii->ii_ndisk = 1;
496a56bb8a5SSatoshi Asami 			ii->ii_startblk = bn;
497a56bb8a5SSatoshi Asami 			ii->ii_startoff = 0;
498a56bb8a5SSatoshi Asami 			ii->ii_index[0] = ix;
499a56bb8a5SSatoshi Asami 			bn += cs->sc_cinfo[ix].ci_size;
500a56bb8a5SSatoshi Asami 			ii++;
501a56bb8a5SSatoshi Asami 		}
502a56bb8a5SSatoshi Asami 		ii->ii_ndisk = 0;
503a56bb8a5SSatoshi Asami #ifdef DEBUG
504a56bb8a5SSatoshi Asami 		if (ccddebug & CCDB_INIT)
505a56bb8a5SSatoshi Asami 			printiinfo(cs->sc_itable);
506a56bb8a5SSatoshi Asami #endif
507a56bb8a5SSatoshi Asami 		return;
508a56bb8a5SSatoshi Asami 	}
509a56bb8a5SSatoshi Asami 
510a56bb8a5SSatoshi Asami 	/*
511a56bb8a5SSatoshi Asami 	 * The following isn't fast or pretty; it doesn't have to be.
512a56bb8a5SSatoshi Asami 	 */
513a56bb8a5SSatoshi Asami 	size = 0;
514a56bb8a5SSatoshi Asami 	bn = lbn = 0;
515a56bb8a5SSatoshi Asami 	for (ii = cs->sc_itable; ; ii++) {
516a56bb8a5SSatoshi Asami 		/* Allocate space for ii_index. */
517a56bb8a5SSatoshi Asami 		ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
518a56bb8a5SSatoshi Asami 		    M_DEVBUF, M_WAITOK);
519a56bb8a5SSatoshi Asami 
520a56bb8a5SSatoshi Asami 		/*
521a56bb8a5SSatoshi Asami 		 * Locate the smallest of the remaining components
522a56bb8a5SSatoshi Asami 		 */
523a56bb8a5SSatoshi Asami 		smallci = NULL;
524a56bb8a5SSatoshi Asami 		for (ci = cs->sc_cinfo;
525a56bb8a5SSatoshi Asami 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
526a56bb8a5SSatoshi Asami 			if (ci->ci_size > size &&
527a56bb8a5SSatoshi Asami 			    (smallci == NULL ||
528a56bb8a5SSatoshi Asami 			     ci->ci_size < smallci->ci_size))
529a56bb8a5SSatoshi Asami 				smallci = ci;
530a56bb8a5SSatoshi Asami 
531a56bb8a5SSatoshi Asami 		/*
532a56bb8a5SSatoshi Asami 		 * Nobody left, all done
533a56bb8a5SSatoshi Asami 		 */
534a56bb8a5SSatoshi Asami 		if (smallci == NULL) {
535a56bb8a5SSatoshi Asami 			ii->ii_ndisk = 0;
536a56bb8a5SSatoshi Asami 			break;
537a56bb8a5SSatoshi Asami 		}
538a56bb8a5SSatoshi Asami 
539a56bb8a5SSatoshi Asami 		/*
540a56bb8a5SSatoshi Asami 		 * Record starting logical block and component offset
541a56bb8a5SSatoshi Asami 		 */
542a56bb8a5SSatoshi Asami 		ii->ii_startblk = bn / cs->sc_ileave;
543a56bb8a5SSatoshi Asami 		ii->ii_startoff = lbn;
544a56bb8a5SSatoshi Asami 
545a56bb8a5SSatoshi Asami 		/*
546a56bb8a5SSatoshi Asami 		 * Determine how many disks take part in this interleave
547a56bb8a5SSatoshi Asami 		 * and record their indices.
548a56bb8a5SSatoshi Asami 		 */
549a56bb8a5SSatoshi Asami 		ix = 0;
550a56bb8a5SSatoshi Asami 		for (ci = cs->sc_cinfo;
551a56bb8a5SSatoshi Asami 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
552a56bb8a5SSatoshi Asami 			if (ci->ci_size >= smallci->ci_size)
553a56bb8a5SSatoshi Asami 				ii->ii_index[ix++] = ci - cs->sc_cinfo;
554a56bb8a5SSatoshi Asami 		ii->ii_ndisk = ix;
555a56bb8a5SSatoshi Asami 		bn += ix * (smallci->ci_size - size);
556a56bb8a5SSatoshi Asami 		lbn = smallci->ci_size / cs->sc_ileave;
557a56bb8a5SSatoshi Asami 		size = smallci->ci_size;
558a56bb8a5SSatoshi Asami 	}
559a56bb8a5SSatoshi Asami #ifdef DEBUG
560a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_INIT)
561a56bb8a5SSatoshi Asami 		printiinfo(cs->sc_itable);
562a56bb8a5SSatoshi Asami #endif
563a56bb8a5SSatoshi Asami }
564a56bb8a5SSatoshi Asami 
565a56bb8a5SSatoshi Asami /* ARGSUSED */
566a56bb8a5SSatoshi Asami int
567a56bb8a5SSatoshi Asami ccdopen(dev, flags, fmt, p)
568a56bb8a5SSatoshi Asami 	dev_t dev;
569a56bb8a5SSatoshi Asami 	int flags, fmt;
570a56bb8a5SSatoshi Asami 	struct proc *p;
571a56bb8a5SSatoshi Asami {
572a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
573a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
574a56bb8a5SSatoshi Asami 	struct disklabel *lp;
575a56bb8a5SSatoshi Asami 	int error = 0, part, pmask;
576a56bb8a5SSatoshi Asami 
577a56bb8a5SSatoshi Asami #ifdef DEBUG
578a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
579a56bb8a5SSatoshi Asami 		printf("ccdopen(%x, %x)\n", dev, flags);
580a56bb8a5SSatoshi Asami #endif
581a56bb8a5SSatoshi Asami 	if (unit >= numccd)
582a56bb8a5SSatoshi Asami 		return (ENXIO);
583a56bb8a5SSatoshi Asami 	cs = &ccd_softc[unit];
584a56bb8a5SSatoshi Asami 
585a56bb8a5SSatoshi Asami 	if (error = ccdlock(cs))
586a56bb8a5SSatoshi Asami 		return (error);
587a56bb8a5SSatoshi Asami 
588a56bb8a5SSatoshi Asami 	lp = &cs->sc_dkdev.dk_label;
589a56bb8a5SSatoshi Asami 
590d8594dfbSSatoshi Asami 	part = ccdpart(dev);
591a56bb8a5SSatoshi Asami 	pmask = (1 << part);
592a56bb8a5SSatoshi Asami 
593a56bb8a5SSatoshi Asami 	/*
594a56bb8a5SSatoshi Asami 	 * If we're initialized, check to see if there are any other
595a56bb8a5SSatoshi Asami 	 * open partitions.  If not, then it's safe to update
596a56bb8a5SSatoshi Asami 	 * the in-core disklabel.
597a56bb8a5SSatoshi Asami 	 */
598a56bb8a5SSatoshi Asami 	if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0))
599a56bb8a5SSatoshi Asami 		ccdgetdisklabel(dev);
600a56bb8a5SSatoshi Asami 
601a56bb8a5SSatoshi Asami 	/* Check that the partition exists. */
602a56bb8a5SSatoshi Asami 	if (part != RAW_PART && ((part > lp->d_npartitions) ||
603a56bb8a5SSatoshi Asami 	    (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
604a56bb8a5SSatoshi Asami 		error = ENXIO;
605a56bb8a5SSatoshi Asami 		goto done;
606a56bb8a5SSatoshi Asami 	}
607a56bb8a5SSatoshi Asami 
608a56bb8a5SSatoshi Asami 	/* Prevent our unit from being unconfigured while open. */
609a56bb8a5SSatoshi Asami 	switch (fmt) {
610a56bb8a5SSatoshi Asami 	case S_IFCHR:
611a56bb8a5SSatoshi Asami 		cs->sc_dkdev.dk_copenmask |= pmask;
612a56bb8a5SSatoshi Asami 		break;
613a56bb8a5SSatoshi Asami 
614a56bb8a5SSatoshi Asami 	case S_IFBLK:
615a56bb8a5SSatoshi Asami 		cs->sc_dkdev.dk_bopenmask |= pmask;
616a56bb8a5SSatoshi Asami 		break;
617a56bb8a5SSatoshi Asami 	}
618a56bb8a5SSatoshi Asami 	cs->sc_dkdev.dk_openmask =
619a56bb8a5SSatoshi Asami 	    cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
620a56bb8a5SSatoshi Asami 
621a56bb8a5SSatoshi Asami  done:
622a56bb8a5SSatoshi Asami 	ccdunlock(cs);
623a56bb8a5SSatoshi Asami 	return (0);
624a56bb8a5SSatoshi Asami }
625a56bb8a5SSatoshi Asami 
626a56bb8a5SSatoshi Asami /* ARGSUSED */
627a56bb8a5SSatoshi Asami int
628a56bb8a5SSatoshi Asami ccdclose(dev, flags, fmt, p)
629a56bb8a5SSatoshi Asami 	dev_t dev;
630a56bb8a5SSatoshi Asami 	int flags, fmt;
631a56bb8a5SSatoshi Asami 	struct proc *p;
632a56bb8a5SSatoshi Asami {
633a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
634a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
635a56bb8a5SSatoshi Asami 	int error = 0, part;
636a56bb8a5SSatoshi Asami 
637a56bb8a5SSatoshi Asami #ifdef DEBUG
638a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
639a56bb8a5SSatoshi Asami 		printf("ccdclose(%x, %x)\n", dev, flags);
640a56bb8a5SSatoshi Asami #endif
641a56bb8a5SSatoshi Asami 
642a56bb8a5SSatoshi Asami 	if (unit >= numccd)
643a56bb8a5SSatoshi Asami 		return (ENXIO);
644a56bb8a5SSatoshi Asami 	cs = &ccd_softc[unit];
645a56bb8a5SSatoshi Asami 
646a56bb8a5SSatoshi Asami 	if (error = ccdlock(cs))
647a56bb8a5SSatoshi Asami 		return (error);
648a56bb8a5SSatoshi Asami 
649d8594dfbSSatoshi Asami 	part = ccdpart(dev);
650a56bb8a5SSatoshi Asami 
651a56bb8a5SSatoshi Asami 	/* ...that much closer to allowing unconfiguration... */
652a56bb8a5SSatoshi Asami 	switch (fmt) {
653a56bb8a5SSatoshi Asami 	case S_IFCHR:
654a56bb8a5SSatoshi Asami 		cs->sc_dkdev.dk_copenmask &= ~(1 << part);
655a56bb8a5SSatoshi Asami 		break;
656a56bb8a5SSatoshi Asami 
657a56bb8a5SSatoshi Asami 	case S_IFBLK:
658a56bb8a5SSatoshi Asami 		cs->sc_dkdev.dk_bopenmask &= ~(1 << part);
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 	ccdunlock(cs);
665a56bb8a5SSatoshi Asami 	return (0);
666a56bb8a5SSatoshi Asami }
667a56bb8a5SSatoshi Asami 
668a56bb8a5SSatoshi Asami void
669a56bb8a5SSatoshi Asami ccdstrategy(bp)
670a56bb8a5SSatoshi Asami 	register struct buf *bp;
671a56bb8a5SSatoshi Asami {
672a56bb8a5SSatoshi Asami 	register int unit = ccdunit(bp->b_dev);
673a56bb8a5SSatoshi Asami 	register struct ccd_softc *cs = &ccd_softc[unit];
674a56bb8a5SSatoshi Asami 	register daddr_t bn;
675a56bb8a5SSatoshi Asami 	register int sz, s;
676a56bb8a5SSatoshi Asami 	int wlabel;
677a56bb8a5SSatoshi Asami 	struct disklabel *lp;
678a56bb8a5SSatoshi Asami 
679a56bb8a5SSatoshi Asami #ifdef DEBUG
680a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
681a56bb8a5SSatoshi Asami 		printf("ccdstrategy(%x): unit %d\n", bp, unit);
682a56bb8a5SSatoshi Asami #endif
683a56bb8a5SSatoshi Asami 	if ((cs->sc_flags & CCDF_INITED) == 0) {
684a56bb8a5SSatoshi Asami 		bp->b_error = ENXIO;
685a56bb8a5SSatoshi Asami 		bp->b_flags |= B_ERROR;
686a56bb8a5SSatoshi Asami 		goto done;
687a56bb8a5SSatoshi Asami 	}
688a56bb8a5SSatoshi Asami 
689a56bb8a5SSatoshi Asami 	/* If it's a nil transfer, wake up the top half now. */
690a56bb8a5SSatoshi Asami 	if (bp->b_bcount == 0)
691a56bb8a5SSatoshi Asami 		goto done;
692a56bb8a5SSatoshi Asami 
693a56bb8a5SSatoshi Asami 	lp = &cs->sc_dkdev.dk_label;
694a56bb8a5SSatoshi Asami 
695a56bb8a5SSatoshi Asami 	/*
696a56bb8a5SSatoshi Asami 	 * Do bounds checking and adjust transfer.  If there's an
697a56bb8a5SSatoshi Asami 	 * error, the bounds check will flag that for us.
698a56bb8a5SSatoshi Asami 	 */
699a56bb8a5SSatoshi Asami 	wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
700d8594dfbSSatoshi Asami 	if (ccdpart(bp->b_dev) != RAW_PART)
701a56bb8a5SSatoshi Asami 		if (bounds_check_with_label(bp, lp, wlabel) <= 0)
702a56bb8a5SSatoshi Asami 			goto done;
703a56bb8a5SSatoshi Asami 
7043bc746beSSatoshi Asami 	if (cs->sc_cflags & CCDF_MIRROR && (bp->b_flags & B_READ) == 0)
7053bc746beSSatoshi Asami 		bp->b_resid = bp->b_bcount*2;
7063bc746beSSatoshi Asami 	else
707a56bb8a5SSatoshi Asami 		bp->b_resid = bp->b_bcount;
708a56bb8a5SSatoshi Asami 
709a56bb8a5SSatoshi Asami 	/*
710a56bb8a5SSatoshi Asami 	 * "Start" the unit.
711a56bb8a5SSatoshi Asami 	 */
712a56bb8a5SSatoshi Asami 	s = splbio();
713a56bb8a5SSatoshi Asami 	ccdstart(cs, bp);
714a56bb8a5SSatoshi Asami 	splx(s);
715a56bb8a5SSatoshi Asami 	return;
716a56bb8a5SSatoshi Asami done:
717a56bb8a5SSatoshi Asami 	biodone(bp);
718a56bb8a5SSatoshi Asami }
719a56bb8a5SSatoshi Asami 
720a56bb8a5SSatoshi Asami static void
721a56bb8a5SSatoshi Asami ccdstart(cs, bp)
722a56bb8a5SSatoshi Asami 	register struct ccd_softc *cs;
723a56bb8a5SSatoshi Asami 	register struct buf *bp;
724a56bb8a5SSatoshi Asami {
725a56bb8a5SSatoshi Asami 	register long bcount, rcount;
7263bc746beSSatoshi Asami 	struct ccdbuf *cbp[4];
7273bc746beSSatoshi Asami 	/* XXX! : 2 reads and 2 writes for RAID 4/5 */
728a56bb8a5SSatoshi Asami 	caddr_t addr;
729a56bb8a5SSatoshi Asami 	daddr_t bn;
730a56bb8a5SSatoshi Asami 	struct partition *pp;
731a56bb8a5SSatoshi Asami 
732a56bb8a5SSatoshi Asami #ifdef DEBUG
733a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
734a56bb8a5SSatoshi Asami 		printf("ccdstart(%x, %x)\n", cs, bp);
735a56bb8a5SSatoshi Asami #endif
736a56bb8a5SSatoshi Asami 
737a56bb8a5SSatoshi Asami #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
738a56bb8a5SSatoshi Asami 	/*
739a56bb8a5SSatoshi Asami 	 * Instrumentation (not very meaningful)
740a56bb8a5SSatoshi Asami 	 */
741a56bb8a5SSatoshi Asami 	cs->sc_nactive++;
742a56bb8a5SSatoshi Asami 	if (cs->sc_dk >= 0) {
743a56bb8a5SSatoshi Asami 		dk_busy |= 1 << cs->sc_dk;
744a56bb8a5SSatoshi Asami 		dk_xfer[cs->sc_dk]++;
745a56bb8a5SSatoshi Asami 		dk_wds[cs->sc_dk] += bp->b_bcount >> 6;
746a56bb8a5SSatoshi Asami 	}
747a56bb8a5SSatoshi Asami #endif
748a56bb8a5SSatoshi Asami 
749a56bb8a5SSatoshi Asami 	/*
750a56bb8a5SSatoshi Asami 	 * Translate the partition-relative block number to an absolute.
751a56bb8a5SSatoshi Asami 	 */
752a56bb8a5SSatoshi Asami 	bn = bp->b_blkno;
753d8594dfbSSatoshi Asami 	if (ccdpart(bp->b_dev) != RAW_PART) {
754d8594dfbSSatoshi Asami 		pp = &cs->sc_dkdev.dk_label.d_partitions[ccdpart(bp->b_dev)];
755a56bb8a5SSatoshi Asami 		bn += pp->p_offset;
756a56bb8a5SSatoshi Asami 	}
757a56bb8a5SSatoshi Asami 
758a56bb8a5SSatoshi Asami 	/*
759a56bb8a5SSatoshi Asami 	 * Allocate component buffers and fire off the requests
760a56bb8a5SSatoshi Asami 	 */
761a56bb8a5SSatoshi Asami 	addr = bp->b_data;
762a56bb8a5SSatoshi Asami 	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
7633bc746beSSatoshi Asami 		ccdbuffer(cbp, cs, bp, bn, addr, bcount);
7643bc746beSSatoshi Asami 		rcount = cbp[0]->cb_buf.b_bcount;
7653bc746beSSatoshi Asami 		if ((cbp[0]->cb_buf.b_flags & B_READ) == 0)
7663bc746beSSatoshi Asami 			cbp[0]->cb_buf.b_vp->v_numoutput++;
7673bc746beSSatoshi Asami 		VOP_STRATEGY(&cbp[0]->cb_buf);
7683bc746beSSatoshi Asami 		if (cs->sc_cflags & CCDF_MIRROR &&
7693bc746beSSatoshi Asami 		    (cbp[0]->cb_buf.b_flags & B_READ) == 0) {
7703bc746beSSatoshi Asami 			/* mirror, start another write */
7713bc746beSSatoshi Asami 			cbp[1]->cb_buf.b_vp->v_numoutput++;
7723bc746beSSatoshi Asami 			VOP_STRATEGY(&cbp[1]->cb_buf);
7733bc746beSSatoshi Asami 		}
774a56bb8a5SSatoshi Asami 		bn += btodb(rcount);
775a56bb8a5SSatoshi Asami 		addr += rcount;
776a56bb8a5SSatoshi Asami 	}
777a56bb8a5SSatoshi Asami }
778a56bb8a5SSatoshi Asami 
779a56bb8a5SSatoshi Asami /*
780a56bb8a5SSatoshi Asami  * Build a component buffer header.
781a56bb8a5SSatoshi Asami  */
7823bc746beSSatoshi Asami void
7833bc746beSSatoshi Asami ccdbuffer(cb, cs, bp, bn, addr, bcount)
7843bc746beSSatoshi Asami 	register struct ccdbuf **cb;
785a56bb8a5SSatoshi Asami 	register struct ccd_softc *cs;
786a56bb8a5SSatoshi Asami 	struct buf *bp;
787a56bb8a5SSatoshi Asami 	daddr_t bn;
788a56bb8a5SSatoshi Asami 	caddr_t addr;
789a56bb8a5SSatoshi Asami 	long bcount;
790a56bb8a5SSatoshi Asami {
7913bc746beSSatoshi Asami 	register struct ccdcinfo *ci, *ci2;
792a56bb8a5SSatoshi Asami 	register struct ccdbuf *cbp;
793a56bb8a5SSatoshi Asami 	register daddr_t cbn, cboff;
794a56bb8a5SSatoshi Asami 
795a56bb8a5SSatoshi Asami #ifdef DEBUG
796a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_IO)
797a56bb8a5SSatoshi Asami 		printf("ccdbuffer(%x, %x, %d, %x, %d)\n",
798a56bb8a5SSatoshi Asami 		       cs, bp, bn, addr, bcount);
799a56bb8a5SSatoshi Asami #endif
800a56bb8a5SSatoshi Asami 	/*
801a56bb8a5SSatoshi Asami 	 * Determine which component bn falls in.
802a56bb8a5SSatoshi Asami 	 */
803a56bb8a5SSatoshi Asami 	cbn = bn;
804a56bb8a5SSatoshi Asami 	cboff = 0;
805a56bb8a5SSatoshi Asami 
806a56bb8a5SSatoshi Asami 	/*
807a56bb8a5SSatoshi Asami 	 * Serially concatenated
808a56bb8a5SSatoshi Asami 	 */
809a56bb8a5SSatoshi Asami 	if (cs->sc_ileave == 0) {
810a56bb8a5SSatoshi Asami 		register daddr_t sblk;
811a56bb8a5SSatoshi Asami 
812a56bb8a5SSatoshi Asami 		sblk = 0;
813a56bb8a5SSatoshi Asami 		for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
814a56bb8a5SSatoshi Asami 			sblk += ci->ci_size;
815a56bb8a5SSatoshi Asami 		cbn -= sblk;
816a56bb8a5SSatoshi Asami 	}
817a56bb8a5SSatoshi Asami 	/*
818a56bb8a5SSatoshi Asami 	 * Interleaved
819a56bb8a5SSatoshi Asami 	 */
820a56bb8a5SSatoshi Asami 	else {
821a56bb8a5SSatoshi Asami 		register struct ccdiinfo *ii;
822a56bb8a5SSatoshi Asami 		int ccdisk, off;
823a56bb8a5SSatoshi Asami 
824a56bb8a5SSatoshi Asami 		cboff = cbn % cs->sc_ileave;
825a56bb8a5SSatoshi Asami 		cbn /= cs->sc_ileave;
826a56bb8a5SSatoshi Asami 		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
827a56bb8a5SSatoshi Asami 			if (ii->ii_startblk > cbn)
828a56bb8a5SSatoshi Asami 				break;
829a56bb8a5SSatoshi Asami 		ii--;
830a56bb8a5SSatoshi Asami 		off = cbn - ii->ii_startblk;
831a56bb8a5SSatoshi Asami 		if (ii->ii_ndisk == 1) {
832a56bb8a5SSatoshi Asami 			ccdisk = ii->ii_index[0];
833a56bb8a5SSatoshi Asami 			cbn = ii->ii_startoff + off;
834a56bb8a5SSatoshi Asami 		} else {
83509b59204SSatoshi Asami 			if (cs->sc_cflags & CCDF_MIRROR) {
83609b59204SSatoshi Asami 				ccdisk = ii->ii_index[off % (ii->ii_ndisk/2)];
83709b59204SSatoshi Asami 				cbn = ii->ii_startoff + off / (ii->ii_ndisk/2);
8383bc746beSSatoshi Asami 				/* mirrored data */
8393bc746beSSatoshi Asami 				ci2 = &cs->sc_cinfo[ccdisk + ii->ii_ndisk/2];
84009b59204SSatoshi Asami 			}
84109b59204SSatoshi Asami 			else if (cs->sc_cflags & CCDF_PARITY) {
8427ecb65faSSatoshi Asami 				ccdisk = ii->ii_index[off % (ii->ii_ndisk-1)];
8437ecb65faSSatoshi Asami 				cbn = ii->ii_startoff + off / (ii->ii_ndisk-1);
8447ecb65faSSatoshi Asami 				if (cbn % ii->ii_ndisk <= ccdisk)
8457ecb65faSSatoshi Asami 					ccdisk++;
8467ecb65faSSatoshi Asami 			}
8477ecb65faSSatoshi Asami 			else {
848a56bb8a5SSatoshi Asami 				ccdisk = ii->ii_index[off % ii->ii_ndisk];
849a56bb8a5SSatoshi Asami 				cbn = ii->ii_startoff + off / ii->ii_ndisk;
850a56bb8a5SSatoshi Asami 			}
8517ecb65faSSatoshi Asami 		}
852a56bb8a5SSatoshi Asami 		cbn *= cs->sc_ileave;
853a56bb8a5SSatoshi Asami 		ci = &cs->sc_cinfo[ccdisk];
854a56bb8a5SSatoshi Asami 	}
855a56bb8a5SSatoshi Asami 
856a56bb8a5SSatoshi Asami 	/*
857a56bb8a5SSatoshi Asami 	 * Fill in the component buf structure.
858a56bb8a5SSatoshi Asami 	 */
859a56bb8a5SSatoshi Asami 	cbp = getccdbuf();
860a56bb8a5SSatoshi Asami 	cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
861a56bb8a5SSatoshi Asami 	cbp->cb_buf.b_iodone = (void (*)())ccdiodone;
862a56bb8a5SSatoshi Asami 	cbp->cb_buf.b_proc = bp->b_proc;
863a56bb8a5SSatoshi Asami 	cbp->cb_buf.b_dev = ci->ci_dev;		/* XXX */
864a56bb8a5SSatoshi Asami 	cbp->cb_buf.b_blkno = cbn + cboff;
865a56bb8a5SSatoshi Asami 	cbp->cb_buf.b_data = addr;
866a56bb8a5SSatoshi Asami 	cbp->cb_buf.b_vp = ci->ci_vp;
867a56bb8a5SSatoshi Asami 	if (cs->sc_ileave == 0)
868a56bb8a5SSatoshi Asami 		cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn);
869a56bb8a5SSatoshi Asami 	else
870a56bb8a5SSatoshi Asami 		cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff);
871a56bb8a5SSatoshi Asami 	if (cbp->cb_buf.b_bcount > bcount)
872a56bb8a5SSatoshi Asami 		cbp->cb_buf.b_bcount = bcount;
873a56bb8a5SSatoshi Asami 
874a56bb8a5SSatoshi Asami 	/*
875a56bb8a5SSatoshi Asami 	 * context for ccdiodone
876a56bb8a5SSatoshi Asami 	 */
877a56bb8a5SSatoshi Asami 	cbp->cb_obp = bp;
878a56bb8a5SSatoshi Asami 	cbp->cb_unit = cs - ccd_softc;
879a56bb8a5SSatoshi Asami 	cbp->cb_comp = ci - cs->sc_cinfo;
880a56bb8a5SSatoshi Asami 
881a56bb8a5SSatoshi Asami #ifdef DEBUG
882a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_IO)
883a56bb8a5SSatoshi Asami 		printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
884a56bb8a5SSatoshi Asami 		       ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
885a56bb8a5SSatoshi Asami 		       cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
886a56bb8a5SSatoshi Asami #endif
8873bc746beSSatoshi Asami 	cb[0] = cbp;
8883bc746beSSatoshi Asami 	if (cs->sc_cflags & CCDF_MIRROR &&
8893bc746beSSatoshi Asami 	    (cbp->cb_buf.b_flags & B_READ) == 0) {
8903bc746beSSatoshi Asami 		/* mirror, start one more write */
8913bc746beSSatoshi Asami 		cbp = getccdbuf();
8923bc746beSSatoshi Asami 		*cbp = *cb[0];
8933bc746beSSatoshi Asami 		cbp->cb_buf.b_dev = ci2->ci_dev;
8943bc746beSSatoshi Asami 		cbp->cb_buf.b_vp = ci2->ci_vp;
8953bc746beSSatoshi Asami 		cbp->cb_comp = ci2 - cs->sc_cinfo;
8963bc746beSSatoshi Asami 		cb[1] = cbp;
8973bc746beSSatoshi Asami 	}
898a56bb8a5SSatoshi Asami }
899a56bb8a5SSatoshi Asami 
900a56bb8a5SSatoshi Asami static void
901a56bb8a5SSatoshi Asami ccdintr(cs, bp)
902a56bb8a5SSatoshi Asami 	register struct ccd_softc *cs;
903a56bb8a5SSatoshi Asami 	register struct buf *bp;
904a56bb8a5SSatoshi Asami {
905a56bb8a5SSatoshi Asami 
906a56bb8a5SSatoshi Asami #ifdef DEBUG
907a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
908a56bb8a5SSatoshi Asami 		printf("ccdintr(%x, %x)\n", cs, bp);
909a56bb8a5SSatoshi Asami #endif
910a56bb8a5SSatoshi Asami 	/*
911a56bb8a5SSatoshi Asami 	 * Request is done for better or worse, wakeup the top half.
912a56bb8a5SSatoshi Asami 	 */
913a56bb8a5SSatoshi Asami #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
914a56bb8a5SSatoshi Asami 	--cs->sc_nactive;
915a56bb8a5SSatoshi Asami #ifdef DIAGNOSTIC
916a56bb8a5SSatoshi Asami 	if (cs->sc_nactive < 0)
917a56bb8a5SSatoshi Asami 		panic("ccdintr: ccd%d: sc_nactive < 0", cs->sc_unit);
918a56bb8a5SSatoshi Asami #endif
919a56bb8a5SSatoshi Asami 
920a56bb8a5SSatoshi Asami 	if (cs->sc_nactive == 0 && cs->sc_dk >= 0)
921a56bb8a5SSatoshi Asami 		dk_busy &= ~(1 << cs->sc_dk);
922a56bb8a5SSatoshi Asami #endif
923a56bb8a5SSatoshi Asami 	if (bp->b_flags & B_ERROR)
9243bc746beSSatoshi Asami 		if (cs->sc_cflags & CCDF_MIRROR && (bp->b_flags & B_READ) == 0)
9253bc746beSSatoshi Asami 			bp->b_resid = bp->b_bcount*2;
9263bc746beSSatoshi Asami 		else
927a56bb8a5SSatoshi Asami 			bp->b_resid = bp->b_bcount;
928a56bb8a5SSatoshi Asami 	biodone(bp);
929a56bb8a5SSatoshi Asami }
930a56bb8a5SSatoshi Asami 
931a56bb8a5SSatoshi Asami /*
932a56bb8a5SSatoshi Asami  * Called at interrupt time.
933a56bb8a5SSatoshi Asami  * Mark the component as done and if all components are done,
934a56bb8a5SSatoshi Asami  * take a ccd interrupt.
935a56bb8a5SSatoshi Asami  */
936a56bb8a5SSatoshi Asami void
937a56bb8a5SSatoshi Asami ccdiodone(cbp)
938a56bb8a5SSatoshi Asami 	struct ccdbuf *cbp;
939a56bb8a5SSatoshi Asami {
940a56bb8a5SSatoshi Asami 	register struct buf *bp = cbp->cb_obp;
941a56bb8a5SSatoshi Asami 	register int unit = cbp->cb_unit;
942a56bb8a5SSatoshi Asami 	int count, s;
943a56bb8a5SSatoshi Asami 
944a56bb8a5SSatoshi Asami 	s = splbio();
945a56bb8a5SSatoshi Asami #ifdef DEBUG
946a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
947a56bb8a5SSatoshi Asami 		printf("ccdiodone(%x)\n", cbp);
948a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_IO) {
949a56bb8a5SSatoshi Asami 		printf("ccdiodone: bp %x bcount %d resid %d\n",
950a56bb8a5SSatoshi Asami 		       bp, bp->b_bcount, bp->b_resid);
951a56bb8a5SSatoshi Asami 		printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
952a56bb8a5SSatoshi Asami 		       cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
953a56bb8a5SSatoshi Asami 		       cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
954a56bb8a5SSatoshi Asami 		       cbp->cb_buf.b_bcount);
955a56bb8a5SSatoshi Asami 	}
956a56bb8a5SSatoshi Asami #endif
957a56bb8a5SSatoshi Asami 
958a56bb8a5SSatoshi Asami 	if (cbp->cb_buf.b_flags & B_ERROR) {
959a56bb8a5SSatoshi Asami 		bp->b_flags |= B_ERROR;
960a56bb8a5SSatoshi Asami 		bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO;
961a56bb8a5SSatoshi Asami #ifdef DEBUG
962a56bb8a5SSatoshi Asami 		printf("ccd%d: error %d on component %d\n",
963a56bb8a5SSatoshi Asami 		       unit, bp->b_error, cbp->cb_comp);
964a56bb8a5SSatoshi Asami #endif
965a56bb8a5SSatoshi Asami 	}
966a56bb8a5SSatoshi Asami 	count = cbp->cb_buf.b_bcount;
967a56bb8a5SSatoshi Asami 	putccdbuf(cbp);
968a56bb8a5SSatoshi Asami 
969a56bb8a5SSatoshi Asami 	/*
970a56bb8a5SSatoshi Asami 	 * If all done, "interrupt".
971a56bb8a5SSatoshi Asami 	 */
972a56bb8a5SSatoshi Asami 	bp->b_resid -= count;
973a56bb8a5SSatoshi Asami 	if (bp->b_resid < 0)
974a56bb8a5SSatoshi Asami 		panic("ccdiodone: count");
975a56bb8a5SSatoshi Asami 	if (bp->b_resid == 0)
976a56bb8a5SSatoshi Asami 		ccdintr(&ccd_softc[unit], bp);
977a56bb8a5SSatoshi Asami 	splx(s);
978a56bb8a5SSatoshi Asami }
979a56bb8a5SSatoshi Asami 
980a56bb8a5SSatoshi Asami /* ARGSUSED */
981a56bb8a5SSatoshi Asami int
982a56bb8a5SSatoshi Asami ccdread(dev, uio, flags)
983a56bb8a5SSatoshi Asami 	dev_t dev;
984a56bb8a5SSatoshi Asami 	struct uio *uio;
985a56bb8a5SSatoshi Asami 	int flags;
986a56bb8a5SSatoshi Asami {
987a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
988a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
989a56bb8a5SSatoshi Asami 
990a56bb8a5SSatoshi Asami #ifdef DEBUG
991a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
992a56bb8a5SSatoshi Asami 		printf("ccdread(%x, %x)\n", dev, uio);
993a56bb8a5SSatoshi Asami #endif
994a56bb8a5SSatoshi Asami 	if (unit >= numccd)
995a56bb8a5SSatoshi Asami 		return (ENXIO);
996a56bb8a5SSatoshi Asami 	cs = &ccd_softc[unit];
997a56bb8a5SSatoshi Asami 
998a56bb8a5SSatoshi Asami 	if ((cs->sc_flags & CCDF_INITED) == 0)
999a56bb8a5SSatoshi Asami 		return (ENXIO);
1000a56bb8a5SSatoshi Asami 
1001a56bb8a5SSatoshi Asami 	/*
1002a56bb8a5SSatoshi Asami 	 * XXX: It's not clear that using minphys() is completely safe,
1003a56bb8a5SSatoshi Asami 	 * in particular, for raw I/O.  Underlying devices might have some
1004a56bb8a5SSatoshi Asami 	 * non-obvious limits, because of the copy to user-space.
1005a56bb8a5SSatoshi Asami 	 */
1006a56bb8a5SSatoshi Asami 	return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
1007a56bb8a5SSatoshi Asami }
1008a56bb8a5SSatoshi Asami 
1009a56bb8a5SSatoshi Asami /* ARGSUSED */
1010a56bb8a5SSatoshi Asami int
1011a56bb8a5SSatoshi Asami ccdwrite(dev, uio, flags)
1012a56bb8a5SSatoshi Asami 	dev_t dev;
1013a56bb8a5SSatoshi Asami 	struct uio *uio;
1014a56bb8a5SSatoshi Asami 	int flags;
1015a56bb8a5SSatoshi Asami {
1016a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
1017a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1018a56bb8a5SSatoshi Asami 
1019a56bb8a5SSatoshi Asami #ifdef DEBUG
1020a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_FOLLOW)
1021a56bb8a5SSatoshi Asami 		printf("ccdwrite(%x, %x)\n", dev, uio);
1022a56bb8a5SSatoshi Asami #endif
1023a56bb8a5SSatoshi Asami 	if (unit >= numccd)
1024a56bb8a5SSatoshi Asami 		return (ENXIO);
1025a56bb8a5SSatoshi Asami 	cs = &ccd_softc[unit];
1026a56bb8a5SSatoshi Asami 
1027a56bb8a5SSatoshi Asami 	if ((cs->sc_flags & CCDF_INITED) == 0)
1028a56bb8a5SSatoshi Asami 		return (ENXIO);
1029a56bb8a5SSatoshi Asami 
1030a56bb8a5SSatoshi Asami 	/*
1031a56bb8a5SSatoshi Asami 	 * XXX: It's not clear that using minphys() is completely safe,
1032a56bb8a5SSatoshi Asami 	 * in particular, for raw I/O.  Underlying devices might have some
1033a56bb8a5SSatoshi Asami 	 * non-obvious limits, because of the copy to user-space.
1034a56bb8a5SSatoshi Asami 	 */
1035a56bb8a5SSatoshi Asami 	return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
1036a56bb8a5SSatoshi Asami }
1037a56bb8a5SSatoshi Asami 
1038d8594dfbSSatoshi Asami static void
1039d8594dfbSSatoshi Asami loopdelay()
1040d8594dfbSSatoshi Asami {
1041d8594dfbSSatoshi Asami 	int i, j, k, l;
1042d8594dfbSSatoshi Asami 	printf("I'm now gonna wait for fifteen seconds\n");
1043d8594dfbSSatoshi Asami 	printf("Press Ctl-Alt-Esc NOW!\n");
1044d8594dfbSSatoshi Asami 	for (i = 0; i < 1000; i++)
1045d8594dfbSSatoshi Asami 		for (j = 0; j < 1000; j++)
1046d8594dfbSSatoshi Asami 			for (k = 0; k < 100; k++)
1047d8594dfbSSatoshi Asami 				l = i * j * k;
1048d8594dfbSSatoshi Asami }
1049d8594dfbSSatoshi Asami 
1050a56bb8a5SSatoshi Asami int
1051a56bb8a5SSatoshi Asami ccdioctl(dev, cmd, data, flag, p)
1052a56bb8a5SSatoshi Asami 	dev_t dev;
1053d8594dfbSSatoshi Asami 	int cmd;
1054a56bb8a5SSatoshi Asami 	caddr_t data;
1055a56bb8a5SSatoshi Asami 	int flag;
1056a56bb8a5SSatoshi Asami 	struct proc *p;
1057a56bb8a5SSatoshi Asami {
1058a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
1059a56bb8a5SSatoshi Asami 	int i, j, lookedup = 0, error = 0;
1060a56bb8a5SSatoshi Asami 	int part, pmask, s;
1061a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1062a56bb8a5SSatoshi Asami 	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
1063a56bb8a5SSatoshi Asami 	struct ccddevice ccd;
1064a56bb8a5SSatoshi Asami 	char **cpp;
1065a56bb8a5SSatoshi Asami 	struct vnode **vpp;
1066a56bb8a5SSatoshi Asami #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
1067a56bb8a5SSatoshi Asami 	extern int dkn;
1068a56bb8a5SSatoshi Asami #endif
1069a56bb8a5SSatoshi Asami 
1070a56bb8a5SSatoshi Asami 	if (unit >= numccd)
1071a56bb8a5SSatoshi Asami 		return (ENXIO);
1072a56bb8a5SSatoshi Asami 	cs = &ccd_softc[unit];
1073a56bb8a5SSatoshi Asami 
1074a56bb8a5SSatoshi Asami 	bzero(&ccd, sizeof(ccd));
1075a56bb8a5SSatoshi Asami 
1076a56bb8a5SSatoshi Asami 	switch (cmd) {
1077a56bb8a5SSatoshi Asami 	case CCDIOCSET:
1078a56bb8a5SSatoshi Asami 		if (cs->sc_flags & CCDF_INITED)
1079a56bb8a5SSatoshi Asami 			return (EBUSY);
1080a56bb8a5SSatoshi Asami 
1081a56bb8a5SSatoshi Asami 		if ((flag & FWRITE) == 0)
1082a56bb8a5SSatoshi Asami 			return (EBADF);
1083a56bb8a5SSatoshi Asami 
1084a56bb8a5SSatoshi Asami 		if (error = ccdlock(cs))
1085a56bb8a5SSatoshi Asami 			return (error);
1086a56bb8a5SSatoshi Asami 
1087a56bb8a5SSatoshi Asami 		/* Fill in some important bits. */
1088a56bb8a5SSatoshi Asami 		ccd.ccd_unit = unit;
1089a56bb8a5SSatoshi Asami 		ccd.ccd_interleave = ccio->ccio_ileave;
109009b59204SSatoshi Asami 		if ((ccio->ccio_flags & CCDF_MIRROR) &&
109109b59204SSatoshi Asami 		    (ccio->ccio_flags & CCDF_PARITY)) {
109209b59204SSatoshi Asami 			printf("ccd%d: can't specify both mirror and parity, using mirror\n", unit);
109309b59204SSatoshi Asami 			ccio->ccio_flags &= ~CCDF_PARITY;
109409b59204SSatoshi Asami 		}
109509b59204SSatoshi Asami 		if ((ccio->ccio_flags & (CCDF_MIRROR | CCDF_PARITY)) &&
10967ecb65faSSatoshi Asami 		    !(ccio->ccio_flags & CCDF_UNIFORM)) {
109709b59204SSatoshi Asami 			printf("ccd%d: mirror/parity forces uniform flag\n",
109809b59204SSatoshi Asami 			       unit);
10997ecb65faSSatoshi Asami 			ccio->ccio_flags |= CCDF_UNIFORM;
11007ecb65faSSatoshi Asami 		}
1101a56bb8a5SSatoshi Asami 		ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK;
1102a56bb8a5SSatoshi Asami 
1103a56bb8a5SSatoshi Asami 		/*
1104a56bb8a5SSatoshi Asami 		 * Allocate space for and copy in the array of
1105a56bb8a5SSatoshi Asami 		 * componet pathnames and device numbers.
1106a56bb8a5SSatoshi Asami 		 */
1107a56bb8a5SSatoshi Asami 		cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
1108a56bb8a5SSatoshi Asami 		    M_DEVBUF, M_WAITOK);
1109a56bb8a5SSatoshi Asami 		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
1110a56bb8a5SSatoshi Asami 		    M_DEVBUF, M_WAITOK);
1111a56bb8a5SSatoshi Asami 
1112a56bb8a5SSatoshi Asami 		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
1113a56bb8a5SSatoshi Asami 		    ccio->ccio_ndisks * sizeof(char **));
1114a56bb8a5SSatoshi Asami 		if (error) {
1115a56bb8a5SSatoshi Asami 			free(vpp, M_DEVBUF);
1116a56bb8a5SSatoshi Asami 			free(cpp, M_DEVBUF);
1117a56bb8a5SSatoshi Asami 			ccdunlock(cs);
1118a56bb8a5SSatoshi Asami 			return (error);
1119a56bb8a5SSatoshi Asami 		}
1120a56bb8a5SSatoshi Asami 
1121a56bb8a5SSatoshi Asami #ifdef DEBUG
1122a56bb8a5SSatoshi Asami 		if (ccddebug & CCDB_INIT)
1123a56bb8a5SSatoshi Asami 			for (i = 0; i < ccio->ccio_ndisks; ++i)
1124a56bb8a5SSatoshi Asami 				printf("ccdioctl: component %d: 0x%x\n",
1125a56bb8a5SSatoshi Asami 				    i, cpp[i]);
1126a56bb8a5SSatoshi Asami #endif
1127a56bb8a5SSatoshi Asami 
1128a56bb8a5SSatoshi Asami 		for (i = 0; i < ccio->ccio_ndisks; ++i) {
1129a56bb8a5SSatoshi Asami #ifdef DEBUG
1130a56bb8a5SSatoshi Asami 			if (ccddebug & CCDB_INIT)
1131a56bb8a5SSatoshi Asami 				printf("ccdioctl: lookedup = %d\n", lookedup);
1132a56bb8a5SSatoshi Asami #endif
1133a56bb8a5SSatoshi Asami 			if (error = ccdlookup(cpp[i], p, &vpp[i])) {
1134a56bb8a5SSatoshi Asami 				for (j = 0; j < lookedup; ++j)
1135a56bb8a5SSatoshi Asami 					(void)vn_close(vpp[j], FREAD|FWRITE,
1136a56bb8a5SSatoshi Asami 					    p->p_ucred, p);
1137a56bb8a5SSatoshi Asami 				free(vpp, M_DEVBUF);
1138a56bb8a5SSatoshi Asami 				free(cpp, M_DEVBUF);
1139a56bb8a5SSatoshi Asami 				ccdunlock(cs);
1140a56bb8a5SSatoshi Asami 				return (error);
1141a56bb8a5SSatoshi Asami 			}
1142a56bb8a5SSatoshi Asami 			++lookedup;
1143a56bb8a5SSatoshi Asami 		}
1144a56bb8a5SSatoshi Asami 		ccd.ccd_cpp = cpp;
1145a56bb8a5SSatoshi Asami 		ccd.ccd_vpp = vpp;
1146a56bb8a5SSatoshi Asami 		ccd.ccd_ndev = ccio->ccio_ndisks;
1147a56bb8a5SSatoshi Asami 
1148a56bb8a5SSatoshi Asami #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
1149a56bb8a5SSatoshi Asami 		/*
1150a56bb8a5SSatoshi Asami 		 * Assign disk index first so that init routine
1151a56bb8a5SSatoshi Asami 		 * can use it (saves having the driver drag around
1152a56bb8a5SSatoshi Asami 		 * the ccddevice pointer just to set up the dk_*
1153a56bb8a5SSatoshi Asami 		 * info in the open routine).
1154a56bb8a5SSatoshi Asami 		 */
1155a56bb8a5SSatoshi Asami 		if (dkn < DK_NDRIVE)
1156a56bb8a5SSatoshi Asami 			ccd.ccd_dk = dkn++;
1157a56bb8a5SSatoshi Asami 		else
1158a56bb8a5SSatoshi Asami 			ccd.ccd_dk = -1;
1159a56bb8a5SSatoshi Asami #endif
1160a56bb8a5SSatoshi Asami 
1161a56bb8a5SSatoshi Asami 		/*
1162a56bb8a5SSatoshi Asami 		 * Initialize the ccd.  Fills in the softc for us.
1163a56bb8a5SSatoshi Asami 		 */
1164a56bb8a5SSatoshi Asami 		if (error = ccdinit(&ccd, cpp, p)) {
1165a56bb8a5SSatoshi Asami #ifdef WORKING_DISK_STATISTICS		/* XXX !! */
1166a56bb8a5SSatoshi Asami 			if (ccd.ccd_dk >= 0)
1167a56bb8a5SSatoshi Asami 				--dkn;
1168a56bb8a5SSatoshi Asami #endif
1169a56bb8a5SSatoshi Asami 			for (j = 0; j < lookedup; ++j)
1170a56bb8a5SSatoshi Asami 				(void)vn_close(vpp[j], FREAD|FWRITE,
1171a56bb8a5SSatoshi Asami 				    p->p_ucred, p);
1172a56bb8a5SSatoshi Asami 			bzero(&ccd_softc[unit], sizeof(struct ccd_softc));
1173a56bb8a5SSatoshi Asami 			free(vpp, M_DEVBUF);
1174a56bb8a5SSatoshi Asami 			free(cpp, M_DEVBUF);
1175a56bb8a5SSatoshi Asami 			ccdunlock(cs);
1176a56bb8a5SSatoshi Asami 			return (error);
1177a56bb8a5SSatoshi Asami 		}
1178a56bb8a5SSatoshi Asami 
1179a56bb8a5SSatoshi Asami 		/*
1180a56bb8a5SSatoshi Asami 		 * The ccd has been successfully initialized, so
1181a56bb8a5SSatoshi Asami 		 * we can place it into the array and read the disklabel.
1182a56bb8a5SSatoshi Asami 		 */
1183a56bb8a5SSatoshi Asami 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1184a56bb8a5SSatoshi Asami 		ccio->ccio_unit = unit;
1185a56bb8a5SSatoshi Asami 		ccio->ccio_size = cs->sc_size;
1186a56bb8a5SSatoshi Asami 		ccdgetdisklabel(dev);
1187a56bb8a5SSatoshi Asami 
1188a56bb8a5SSatoshi Asami 		ccdunlock(cs);
1189a56bb8a5SSatoshi Asami 
1190a56bb8a5SSatoshi Asami 		break;
1191a56bb8a5SSatoshi Asami 
1192a56bb8a5SSatoshi Asami 	case CCDIOCCLR:
1193a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1194a56bb8a5SSatoshi Asami 			return (ENXIO);
1195a56bb8a5SSatoshi Asami 
1196a56bb8a5SSatoshi Asami 		if ((flag & FWRITE) == 0)
1197a56bb8a5SSatoshi Asami 			return (EBADF);
1198a56bb8a5SSatoshi Asami 
1199a56bb8a5SSatoshi Asami 		if (error = ccdlock(cs))
1200a56bb8a5SSatoshi Asami 			return (error);
1201a56bb8a5SSatoshi Asami 
1202a56bb8a5SSatoshi Asami 		/*
1203a56bb8a5SSatoshi Asami 		 * Don't unconfigure if any other partitions are open
1204a56bb8a5SSatoshi Asami 		 * or if both the character and block flavors of this
1205a56bb8a5SSatoshi Asami 		 * partition are open.
1206a56bb8a5SSatoshi Asami 		 */
1207d8594dfbSSatoshi Asami 		part = ccdpart(dev);
1208a56bb8a5SSatoshi Asami 		pmask = (1 << part);
1209a56bb8a5SSatoshi Asami 		if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
1210a56bb8a5SSatoshi Asami 		    ((cs->sc_dkdev.dk_bopenmask & pmask) &&
1211a56bb8a5SSatoshi Asami 		    (cs->sc_dkdev.dk_copenmask & pmask))) {
1212a56bb8a5SSatoshi Asami 			ccdunlock(cs);
1213a56bb8a5SSatoshi Asami 			return (EBUSY);
1214a56bb8a5SSatoshi Asami 		}
1215a56bb8a5SSatoshi Asami 
1216a56bb8a5SSatoshi Asami 		/*
1217a56bb8a5SSatoshi Asami 		 * Free ccd_softc information and clear entry.
1218a56bb8a5SSatoshi Asami 		 */
1219a56bb8a5SSatoshi Asami 
1220a56bb8a5SSatoshi Asami 		/* Close the components and free their pathnames. */
1221a56bb8a5SSatoshi Asami 		for (i = 0; i < cs->sc_nccdisks; ++i) {
1222a56bb8a5SSatoshi Asami 			/*
1223a56bb8a5SSatoshi Asami 			 * XXX: this close could potentially fail and
1224a56bb8a5SSatoshi Asami 			 * cause Bad Things.  Maybe we need to force
1225a56bb8a5SSatoshi Asami 			 * the close to happen?
1226a56bb8a5SSatoshi Asami 			 */
1227a56bb8a5SSatoshi Asami #ifdef DEBUG
1228a56bb8a5SSatoshi Asami 			if (ccddebug & CCDB_VNODE)
1229a56bb8a5SSatoshi Asami 				vprint("CCDIOCCLR: vnode info",
1230a56bb8a5SSatoshi Asami 				    cs->sc_cinfo[i].ci_vp);
1231a56bb8a5SSatoshi Asami #endif
1232a56bb8a5SSatoshi Asami 			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
1233a56bb8a5SSatoshi Asami 			    p->p_ucred, p);
1234a56bb8a5SSatoshi Asami 			free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
1235a56bb8a5SSatoshi Asami 		}
1236a56bb8a5SSatoshi Asami 
1237a56bb8a5SSatoshi Asami 		/* Free interleave index. */
1238a56bb8a5SSatoshi Asami 		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
1239a56bb8a5SSatoshi Asami 			free(cs->sc_itable[i].ii_index, M_DEVBUF);
1240a56bb8a5SSatoshi Asami 
1241a56bb8a5SSatoshi Asami 		/* Free component info and interleave table. */
1242a56bb8a5SSatoshi Asami 		free(cs->sc_cinfo, M_DEVBUF);
1243a56bb8a5SSatoshi Asami 		free(cs->sc_itable, M_DEVBUF);
1244a56bb8a5SSatoshi Asami 		cs->sc_flags &= ~CCDF_INITED;
1245a56bb8a5SSatoshi Asami 
1246a56bb8a5SSatoshi Asami 		/*
1247a56bb8a5SSatoshi Asami 		 * Free ccddevice information and clear entry.
1248a56bb8a5SSatoshi Asami 		 */
1249a56bb8a5SSatoshi Asami 		free(ccddevs[unit].ccd_cpp, M_DEVBUF);
1250a56bb8a5SSatoshi Asami 		free(ccddevs[unit].ccd_vpp, M_DEVBUF);
1251a56bb8a5SSatoshi Asami 		ccd.ccd_dk = -1;
1252a56bb8a5SSatoshi Asami 		bcopy(&ccd, &ccddevs[unit], sizeof(ccd));
1253a56bb8a5SSatoshi Asami 
1254a56bb8a5SSatoshi Asami 		/* This must be atomic. */
1255a56bb8a5SSatoshi Asami 		s = splhigh();
1256a56bb8a5SSatoshi Asami 		ccdunlock(cs);
1257a56bb8a5SSatoshi Asami 		bzero(cs, sizeof(struct ccd_softc));
1258a56bb8a5SSatoshi Asami 		splx(s);
1259a56bb8a5SSatoshi Asami 
1260a56bb8a5SSatoshi Asami 		break;
1261a56bb8a5SSatoshi Asami 
1262a56bb8a5SSatoshi Asami 	case DIOCGDINFO:
1263a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1264a56bb8a5SSatoshi Asami 			return (ENXIO);
1265a56bb8a5SSatoshi Asami 
1266a56bb8a5SSatoshi Asami 		*(struct disklabel *)data = cs->sc_dkdev.dk_label;
1267a56bb8a5SSatoshi Asami 		break;
1268a56bb8a5SSatoshi Asami 
1269a56bb8a5SSatoshi Asami 	case DIOCGPART:
1270a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1271a56bb8a5SSatoshi Asami 			return (ENXIO);
1272a56bb8a5SSatoshi Asami 
1273a56bb8a5SSatoshi Asami 		((struct partinfo *)data)->disklab = &cs->sc_dkdev.dk_label;
1274a56bb8a5SSatoshi Asami 		((struct partinfo *)data)->part =
1275d8594dfbSSatoshi Asami 		    &cs->sc_dkdev.dk_label.d_partitions[ccdpart(dev)];
1276a56bb8a5SSatoshi Asami 		break;
1277a56bb8a5SSatoshi Asami 
1278a56bb8a5SSatoshi Asami 	case DIOCWDINFO:
1279a56bb8a5SSatoshi Asami 	case DIOCSDINFO:
1280a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1281a56bb8a5SSatoshi Asami 			return (ENXIO);
1282a56bb8a5SSatoshi Asami 
1283a56bb8a5SSatoshi Asami 		if ((flag & FWRITE) == 0)
1284a56bb8a5SSatoshi Asami 			return (EBADF);
1285a56bb8a5SSatoshi Asami 
1286a56bb8a5SSatoshi Asami 		if (error = ccdlock(cs))
1287a56bb8a5SSatoshi Asami 			return (error);
1288a56bb8a5SSatoshi Asami 
1289a56bb8a5SSatoshi Asami 		cs->sc_flags |= CCDF_LABELLING;
1290a56bb8a5SSatoshi Asami 
1291a56bb8a5SSatoshi Asami 		error = setdisklabel(&cs->sc_dkdev.dk_label,
1292d8594dfbSSatoshi Asami 		    (struct disklabel *)data, 0);
1293d8594dfbSSatoshi Asami 				/*, &cs->sc_dkdev.dk_cpulabel); */
1294a56bb8a5SSatoshi Asami 		if (error == 0) {
1295a56bb8a5SSatoshi Asami 			if (cmd == DIOCWDINFO)
1296d8594dfbSSatoshi Asami 				error = correct_writedisklabel(CCDLABELDEV(dev),
1297d8594dfbSSatoshi Asami 				    ccdstrategy, &cs->sc_dkdev.dk_label);
1298d8594dfbSSatoshi Asami 				/*
1299d8594dfbSSatoshi Asami 				    &cs->sc_dkdev.dk_cpulabel); */
1300a56bb8a5SSatoshi Asami 		}
1301a56bb8a5SSatoshi Asami 
1302a56bb8a5SSatoshi Asami 		cs->sc_flags &= ~CCDF_LABELLING;
1303a56bb8a5SSatoshi Asami 
1304a56bb8a5SSatoshi Asami 		ccdunlock(cs);
1305a56bb8a5SSatoshi Asami 
1306a56bb8a5SSatoshi Asami 		if (error)
1307a56bb8a5SSatoshi Asami 			return (error);
1308a56bb8a5SSatoshi Asami 		break;
1309a56bb8a5SSatoshi Asami 
1310a56bb8a5SSatoshi Asami 	case DIOCWLABEL:
1311a56bb8a5SSatoshi Asami 		if ((cs->sc_flags & CCDF_INITED) == 0)
1312a56bb8a5SSatoshi Asami 			return (ENXIO);
1313a56bb8a5SSatoshi Asami 
1314a56bb8a5SSatoshi Asami 		if ((flag & FWRITE) == 0)
1315a56bb8a5SSatoshi Asami 			return (EBADF);
1316a56bb8a5SSatoshi Asami 		if (*(int *)data != 0)
1317a56bb8a5SSatoshi Asami 			cs->sc_flags |= CCDF_WLABEL;
1318a56bb8a5SSatoshi Asami 		else
1319a56bb8a5SSatoshi Asami 			cs->sc_flags &= ~CCDF_WLABEL;
1320a56bb8a5SSatoshi Asami 		break;
1321a56bb8a5SSatoshi Asami 
1322a56bb8a5SSatoshi Asami 	default:
1323a56bb8a5SSatoshi Asami 		return (ENOTTY);
1324a56bb8a5SSatoshi Asami 	}
1325a56bb8a5SSatoshi Asami 
1326a56bb8a5SSatoshi Asami 	return (0);
1327a56bb8a5SSatoshi Asami }
1328a56bb8a5SSatoshi Asami 
1329a56bb8a5SSatoshi Asami int
1330a56bb8a5SSatoshi Asami ccdsize(dev)
1331a56bb8a5SSatoshi Asami 	dev_t dev;
1332a56bb8a5SSatoshi Asami {
1333a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1334a56bb8a5SSatoshi Asami 	int part, size;
1335a56bb8a5SSatoshi Asami 
1336a56bb8a5SSatoshi Asami 	if (ccdopen(dev, 0, S_IFBLK, curproc))
1337a56bb8a5SSatoshi Asami 		return (-1);
1338a56bb8a5SSatoshi Asami 
1339a56bb8a5SSatoshi Asami 	cs = &ccd_softc[ccdunit(dev)];
1340d8594dfbSSatoshi Asami 	part = ccdpart(dev);
1341a56bb8a5SSatoshi Asami 
1342a56bb8a5SSatoshi Asami 	if ((cs->sc_flags & CCDF_INITED) == 0)
1343a56bb8a5SSatoshi Asami 		return (-1);
1344a56bb8a5SSatoshi Asami 
1345a56bb8a5SSatoshi Asami 	if (cs->sc_dkdev.dk_label.d_partitions[part].p_fstype != FS_SWAP)
1346a56bb8a5SSatoshi Asami 		size = -1;
1347a56bb8a5SSatoshi Asami 	else
1348a56bb8a5SSatoshi Asami 		size = cs->sc_dkdev.dk_label.d_partitions[part].p_size;
1349a56bb8a5SSatoshi Asami 
1350a56bb8a5SSatoshi Asami 	if (ccdclose(dev, 0, S_IFBLK, curproc))
1351a56bb8a5SSatoshi Asami 		return (-1);
1352a56bb8a5SSatoshi Asami 
1353a56bb8a5SSatoshi Asami 	return (size);
1354a56bb8a5SSatoshi Asami }
1355a56bb8a5SSatoshi Asami 
1356a56bb8a5SSatoshi Asami int
1357a56bb8a5SSatoshi Asami ccddump(dev, blkno, va, size)
1358a56bb8a5SSatoshi Asami 	dev_t dev;
1359a56bb8a5SSatoshi Asami 	daddr_t blkno;
1360a56bb8a5SSatoshi Asami 	caddr_t va;
1361a56bb8a5SSatoshi Asami 	size_t size;
1362a56bb8a5SSatoshi Asami {
1363a56bb8a5SSatoshi Asami 
1364a56bb8a5SSatoshi Asami 	/* Not implemented. */
1365a56bb8a5SSatoshi Asami 	return ENXIO;
1366a56bb8a5SSatoshi Asami }
1367a56bb8a5SSatoshi Asami 
1368a56bb8a5SSatoshi Asami /*
1369a56bb8a5SSatoshi Asami  * Lookup the provided name in the filesystem.  If the file exists,
1370a56bb8a5SSatoshi Asami  * is a valid block device, and isn't being used by anyone else,
1371a56bb8a5SSatoshi Asami  * set *vpp to the file's vnode.
1372a56bb8a5SSatoshi Asami  */
1373a56bb8a5SSatoshi Asami static int
1374a56bb8a5SSatoshi Asami ccdlookup(path, p, vpp)
1375a56bb8a5SSatoshi Asami 	char *path;
1376a56bb8a5SSatoshi Asami 	struct proc *p;
1377a56bb8a5SSatoshi Asami 	struct vnode **vpp;	/* result */
1378a56bb8a5SSatoshi Asami {
1379a56bb8a5SSatoshi Asami 	struct nameidata nd;
1380a56bb8a5SSatoshi Asami 	struct vnode *vp;
1381a56bb8a5SSatoshi Asami 	struct vattr va;
1382a56bb8a5SSatoshi Asami 	int error;
1383a56bb8a5SSatoshi Asami 
1384a56bb8a5SSatoshi Asami 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1385a56bb8a5SSatoshi Asami 	if (error = vn_open(&nd, FREAD|FWRITE, 0)) {
1386a56bb8a5SSatoshi Asami #ifdef DEBUG
1387a56bb8a5SSatoshi Asami 		if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1388a56bb8a5SSatoshi Asami 			printf("ccdlookup: vn_open error = %d\n", error);
1389a56bb8a5SSatoshi Asami #endif
1390a56bb8a5SSatoshi Asami 		return (error);
1391a56bb8a5SSatoshi Asami 	}
1392a56bb8a5SSatoshi Asami 	vp = nd.ni_vp;
1393a56bb8a5SSatoshi Asami 
1394a56bb8a5SSatoshi Asami 	if (vp->v_usecount > 1) {
1395a56bb8a5SSatoshi Asami 		VOP_UNLOCK(vp);
1396a56bb8a5SSatoshi Asami 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1397a56bb8a5SSatoshi Asami 		return (EBUSY);
1398a56bb8a5SSatoshi Asami 	}
1399a56bb8a5SSatoshi Asami 
1400a56bb8a5SSatoshi Asami 	if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) {
1401a56bb8a5SSatoshi Asami #ifdef DEBUG
1402a56bb8a5SSatoshi Asami 		if (ccddebug & CCDB_FOLLOW|CCDB_INIT)
1403a56bb8a5SSatoshi Asami 			printf("ccdlookup: getattr error = %d\n", error);
1404a56bb8a5SSatoshi Asami #endif
1405a56bb8a5SSatoshi Asami 		VOP_UNLOCK(vp);
1406a56bb8a5SSatoshi Asami 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1407a56bb8a5SSatoshi Asami 		return (error);
1408a56bb8a5SSatoshi Asami 	}
1409a56bb8a5SSatoshi Asami 
1410a56bb8a5SSatoshi Asami 	/* XXX: eventually we should handle VREG, too. */
1411a56bb8a5SSatoshi Asami 	if (va.va_type != VBLK) {
1412a56bb8a5SSatoshi Asami 		VOP_UNLOCK(vp);
1413a56bb8a5SSatoshi Asami 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
1414a56bb8a5SSatoshi Asami 		return (ENOTBLK);
1415a56bb8a5SSatoshi Asami 	}
1416a56bb8a5SSatoshi Asami 
1417a56bb8a5SSatoshi Asami #ifdef DEBUG
1418a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_VNODE)
1419a56bb8a5SSatoshi Asami 		vprint("ccdlookup: vnode info", vp);
1420a56bb8a5SSatoshi Asami #endif
1421a56bb8a5SSatoshi Asami 
1422a56bb8a5SSatoshi Asami 	VOP_UNLOCK(vp);
1423a56bb8a5SSatoshi Asami 	*vpp = vp;
1424a56bb8a5SSatoshi Asami 	return (0);
1425a56bb8a5SSatoshi Asami }
1426a56bb8a5SSatoshi Asami 
1427a56bb8a5SSatoshi Asami /*
1428a56bb8a5SSatoshi Asami  * Read the disklabel from the ccd.  If one is not present, fake one
1429a56bb8a5SSatoshi Asami  * up.
1430a56bb8a5SSatoshi Asami  */
1431a56bb8a5SSatoshi Asami static void
1432a56bb8a5SSatoshi Asami ccdgetdisklabel(dev)
1433a56bb8a5SSatoshi Asami 	dev_t dev;
1434a56bb8a5SSatoshi Asami {
1435a56bb8a5SSatoshi Asami 	int unit = ccdunit(dev);
1436a56bb8a5SSatoshi Asami 	struct ccd_softc *cs = &ccd_softc[unit];
1437a56bb8a5SSatoshi Asami 	char *errstring;
1438a56bb8a5SSatoshi Asami 	struct disklabel *lp = &cs->sc_dkdev.dk_label;
1439d8594dfbSSatoshi Asami /*	struct cpu_disklabel *clp = &cs->sc_dkdev.dk_cpulabel; */
1440a56bb8a5SSatoshi Asami 	struct ccdgeom *ccg = &cs->sc_geom;
1441a56bb8a5SSatoshi Asami 
1442d8594dfbSSatoshi Asami 	struct dos_partition dos_partdummy;
1443d8594dfbSSatoshi Asami 	struct dkbad dkbaddummy;
1444d8594dfbSSatoshi Asami 
1445a56bb8a5SSatoshi Asami 	bzero(lp, sizeof(*lp));
1446d8594dfbSSatoshi Asami /*	bzero(clp, sizeof(*clp)); */
1447a56bb8a5SSatoshi Asami 
1448a56bb8a5SSatoshi Asami 	lp->d_secperunit = cs->sc_size;
1449a56bb8a5SSatoshi Asami 	lp->d_secsize = ccg->ccg_secsize;
1450a56bb8a5SSatoshi Asami 	lp->d_nsectors = ccg->ccg_nsectors;
1451a56bb8a5SSatoshi Asami 	lp->d_ntracks = ccg->ccg_ntracks;
1452a56bb8a5SSatoshi Asami 	lp->d_ncylinders = ccg->ccg_ncylinders;
1453a56bb8a5SSatoshi Asami 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1454a56bb8a5SSatoshi Asami 
1455a56bb8a5SSatoshi Asami 	strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
1456a56bb8a5SSatoshi Asami 	lp->d_type = DTYPE_CCD;
1457a56bb8a5SSatoshi Asami 	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1458a56bb8a5SSatoshi Asami 	lp->d_rpm = 3600;
1459a56bb8a5SSatoshi Asami 	lp->d_interleave = 1;
1460a56bb8a5SSatoshi Asami 	lp->d_flags = 0;
1461a56bb8a5SSatoshi Asami 
1462a56bb8a5SSatoshi Asami 	lp->d_partitions[RAW_PART].p_offset = 0;
1463a56bb8a5SSatoshi Asami 	lp->d_partitions[RAW_PART].p_size = cs->sc_size;
1464a56bb8a5SSatoshi Asami 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1465a56bb8a5SSatoshi Asami 	lp->d_npartitions = RAW_PART + 1;
1466a56bb8a5SSatoshi Asami 
1467d8594dfbSSatoshi Asami 	lp->d_bbsize = BBSIZE;				/* XXX */
1468d8594dfbSSatoshi Asami 	lp->d_sbsize = SBSIZE;				/* XXX */
1469d8594dfbSSatoshi Asami 
1470a56bb8a5SSatoshi Asami 	lp->d_magic = DISKMAGIC;
1471a56bb8a5SSatoshi Asami 	lp->d_magic2 = DISKMAGIC;
1472a56bb8a5SSatoshi Asami 	lp->d_checksum = dkcksum(&cs->sc_dkdev.dk_label);
1473a56bb8a5SSatoshi Asami 
1474a56bb8a5SSatoshi Asami 	/*
1475a56bb8a5SSatoshi Asami 	 * Call the generic disklabel extraction routine.
1476a56bb8a5SSatoshi Asami 	 */
1477d8594dfbSSatoshi Asami 	if (errstring = correct_readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1478d8594dfbSSatoshi Asami 	    &cs->sc_dkdev.dk_label/*, &dos_partdummy, &dkbaddummy*/))
1479d8594dfbSSatoshi Asami 		/*, &cs->sc_dkdev.dk_cpulabel)) */
1480a56bb8a5SSatoshi Asami 		ccdmakedisklabel(cs);
1481a56bb8a5SSatoshi Asami 
1482a56bb8a5SSatoshi Asami #ifdef DEBUG
1483a56bb8a5SSatoshi Asami 	/* It's actually extremely common to have unlabeled ccds. */
1484a56bb8a5SSatoshi Asami 	if (ccddebug & CCDB_LABEL)
1485a56bb8a5SSatoshi Asami 		if (errstring != NULL)
1486a56bb8a5SSatoshi Asami 			printf("ccd%d: %s\n", unit, errstring);
1487a56bb8a5SSatoshi Asami #endif
1488a56bb8a5SSatoshi Asami }
1489a56bb8a5SSatoshi Asami 
1490a56bb8a5SSatoshi Asami /*
1491a56bb8a5SSatoshi Asami  * Take care of things one might want to take care of in the event
1492a56bb8a5SSatoshi Asami  * that a disklabel isn't present.
1493a56bb8a5SSatoshi Asami  */
1494a56bb8a5SSatoshi Asami static void
1495a56bb8a5SSatoshi Asami ccdmakedisklabel(cs)
1496a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1497a56bb8a5SSatoshi Asami {
1498a56bb8a5SSatoshi Asami 	struct disklabel *lp = &cs->sc_dkdev.dk_label;
1499a56bb8a5SSatoshi Asami 
1500a56bb8a5SSatoshi Asami 	/*
1501a56bb8a5SSatoshi Asami 	 * For historical reasons, if there's no disklabel present
1502a56bb8a5SSatoshi Asami 	 * the raw partition must be marked FS_BSDFFS.
1503a56bb8a5SSatoshi Asami 	 */
1504a56bb8a5SSatoshi Asami 	lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
1505a56bb8a5SSatoshi Asami 
1506a56bb8a5SSatoshi Asami 	strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1507a56bb8a5SSatoshi Asami }
1508a56bb8a5SSatoshi Asami 
1509a56bb8a5SSatoshi Asami /*
1510a56bb8a5SSatoshi Asami  * Wait interruptibly for an exclusive lock.
1511a56bb8a5SSatoshi Asami  *
1512a56bb8a5SSatoshi Asami  * XXX
1513a56bb8a5SSatoshi Asami  * Several drivers do this; it should be abstracted and made MP-safe.
1514a56bb8a5SSatoshi Asami  */
1515a56bb8a5SSatoshi Asami static int
1516a56bb8a5SSatoshi Asami ccdlock(cs)
1517a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1518a56bb8a5SSatoshi Asami {
1519a56bb8a5SSatoshi Asami 	int error;
1520a56bb8a5SSatoshi Asami 
1521a56bb8a5SSatoshi Asami 	while ((cs->sc_flags & CCDF_LOCKED) != 0) {
1522a56bb8a5SSatoshi Asami 		cs->sc_flags |= CCDF_WANTED;
1523a56bb8a5SSatoshi Asami 		if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0)
1524a56bb8a5SSatoshi Asami 			return (error);
1525a56bb8a5SSatoshi Asami 	}
1526a56bb8a5SSatoshi Asami 	cs->sc_flags |= CCDF_LOCKED;
1527a56bb8a5SSatoshi Asami 	return (0);
1528a56bb8a5SSatoshi Asami }
1529a56bb8a5SSatoshi Asami 
1530a56bb8a5SSatoshi Asami /*
1531a56bb8a5SSatoshi Asami  * Unlock and wake up any waiters.
1532a56bb8a5SSatoshi Asami  */
1533a56bb8a5SSatoshi Asami static void
1534a56bb8a5SSatoshi Asami ccdunlock(cs)
1535a56bb8a5SSatoshi Asami 	struct ccd_softc *cs;
1536a56bb8a5SSatoshi Asami {
1537a56bb8a5SSatoshi Asami 
1538a56bb8a5SSatoshi Asami 	cs->sc_flags &= ~CCDF_LOCKED;
1539a56bb8a5SSatoshi Asami 	if ((cs->sc_flags & CCDF_WANTED) != 0) {
1540a56bb8a5SSatoshi Asami 		cs->sc_flags &= ~CCDF_WANTED;
1541a56bb8a5SSatoshi Asami 		wakeup(cs);
1542a56bb8a5SSatoshi Asami 	}
1543a56bb8a5SSatoshi Asami }
1544a56bb8a5SSatoshi Asami 
1545a56bb8a5SSatoshi Asami #ifdef DEBUG
1546a56bb8a5SSatoshi Asami static void
1547a56bb8a5SSatoshi Asami printiinfo(ii)
1548a56bb8a5SSatoshi Asami 	struct ccdiinfo *ii;
1549a56bb8a5SSatoshi Asami {
1550a56bb8a5SSatoshi Asami 	register int ix, i;
1551a56bb8a5SSatoshi Asami 
1552a56bb8a5SSatoshi Asami 	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
1553a56bb8a5SSatoshi Asami 		printf(" itab[%d]: #dk %d sblk %d soff %d",
1554a56bb8a5SSatoshi Asami 		       ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
1555a56bb8a5SSatoshi Asami 		for (i = 0; i < ii->ii_ndisk; i++)
1556a56bb8a5SSatoshi Asami 			printf(" %d", ii->ii_index[i]);
1557a56bb8a5SSatoshi Asami 		printf("\n");
1558a56bb8a5SSatoshi Asami 	}
1559a56bb8a5SSatoshi Asami }
1560a56bb8a5SSatoshi Asami #endif
1561d8594dfbSSatoshi Asami 
1562d8594dfbSSatoshi Asami #endif /* NCCD > 0 */
1563d8594dfbSSatoshi Asami 
1564d8594dfbSSatoshi Asami /* Local Variables: */
1565d8594dfbSSatoshi Asami /* c-argdecl-indent: 8 */
156609b59204SSatoshi Asami /* c-continued-statement-offset: 8 */
1567d8594dfbSSatoshi Asami /* c-indent-level: 8 */
1568d8594dfbSSatoshi Asami /* End: */
1569