xref: /netbsd-src/sys/dev/ccd.c (revision c6aa25bfa17d5f5e19cbe5ad5810ac2a32f2600c)
1*c6aa25bfSthorpej /*	$NetBSD: ccd.c,v 1.59 1999/01/21 00:35:15 thorpej Exp $	*/
277d85de2Sthorpej 
3ee8a2c00Sthorpej /*-
4*c6aa25bfSthorpej  * Copyright (c) 1996, 1997, 1998, 1999 The NetBSD Foundation, Inc.
577d85de2Sthorpej  * All rights reserved.
677d85de2Sthorpej  *
7ee8a2c00Sthorpej  * This code is derived from software contributed to The NetBSD Foundation
8ee8a2c00Sthorpej  * by Jason R. Thorpe.
9ee8a2c00Sthorpej  *
1077d85de2Sthorpej  * Redistribution and use in source and binary forms, with or without
1177d85de2Sthorpej  * modification, are permitted provided that the following conditions
1277d85de2Sthorpej  * are met:
1377d85de2Sthorpej  * 1. Redistributions of source code must retain the above copyright
1477d85de2Sthorpej  *    notice, this list of conditions and the following disclaimer.
1577d85de2Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
1677d85de2Sthorpej  *    notice, this list of conditions and the following disclaimer in the
1777d85de2Sthorpej  *    documentation and/or other materials provided with the distribution.
1877d85de2Sthorpej  * 3. All advertising materials mentioning features or use of this software
1977d85de2Sthorpej  *    must display the following acknowledgement:
20ee8a2c00Sthorpej  *        This product includes software developed by the NetBSD
21ee8a2c00Sthorpej  *        Foundation, Inc. and its contributors.
22ee8a2c00Sthorpej  * 4. Neither the name of The NetBSD Foundation nor the names of its
23ee8a2c00Sthorpej  *    contributors may be used to endorse or promote products derived
24ee8a2c00Sthorpej  *    from this software without specific prior written permission.
2577d85de2Sthorpej  *
26ee8a2c00Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27ee8a2c00Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28ee8a2c00Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29d6ae2cd7Sjtc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30d6ae2cd7Sjtc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31ee8a2c00Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32ee8a2c00Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33ee8a2c00Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34ee8a2c00Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35ee8a2c00Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36ee8a2c00Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
3777d85de2Sthorpej  */
38cf92afd6Scgd 
396f9db1eeShpeyerl /*
406f9db1eeShpeyerl  * Copyright (c) 1988 University of Utah.
413214723fShpeyerl  * Copyright (c) 1990, 1993
423214723fShpeyerl  *	The Regents of the University of California.  All rights reserved.
436f9db1eeShpeyerl  *
446f9db1eeShpeyerl  * This code is derived from software contributed to Berkeley by
456f9db1eeShpeyerl  * the Systems Programming Group of the University of Utah Computer
466f9db1eeShpeyerl  * Science Department.
476f9db1eeShpeyerl  *
486f9db1eeShpeyerl  * Redistribution and use in source and binary forms, with or without
496f9db1eeShpeyerl  * modification, are permitted provided that the following conditions
506f9db1eeShpeyerl  * are met:
516f9db1eeShpeyerl  * 1. Redistributions of source code must retain the above copyright
526f9db1eeShpeyerl  *    notice, this list of conditions and the following disclaimer.
536f9db1eeShpeyerl  * 2. Redistributions in binary form must reproduce the above copyright
546f9db1eeShpeyerl  *    notice, this list of conditions and the following disclaimer in the
556f9db1eeShpeyerl  *    documentation and/or other materials provided with the distribution.
566f9db1eeShpeyerl  * 3. All advertising materials mentioning features or use of this software
576f9db1eeShpeyerl  *    must display the following acknowledgement:
586f9db1eeShpeyerl  *	This product includes software developed by the University of
596f9db1eeShpeyerl  *	California, Berkeley and its contributors.
606f9db1eeShpeyerl  * 4. Neither the name of the University nor the names of its contributors
616f9db1eeShpeyerl  *    may be used to endorse or promote products derived from this software
626f9db1eeShpeyerl  *    without specific prior written permission.
636f9db1eeShpeyerl  *
646f9db1eeShpeyerl  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
656f9db1eeShpeyerl  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
666f9db1eeShpeyerl  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
676f9db1eeShpeyerl  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
686f9db1eeShpeyerl  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
696f9db1eeShpeyerl  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
706f9db1eeShpeyerl  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
716f9db1eeShpeyerl  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
726f9db1eeShpeyerl  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
736f9db1eeShpeyerl  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
746f9db1eeShpeyerl  * SUCH DAMAGE.
756f9db1eeShpeyerl  *
76cf92afd6Scgd  * from: Utah $Hdr: cd.c 1.6 90/11/28$
77cf92afd6Scgd  *
783214723fShpeyerl  *	@(#)cd.c	8.2 (Berkeley) 11/16/93
796f9db1eeShpeyerl  */
806f9db1eeShpeyerl 
816f9db1eeShpeyerl /*
826f9db1eeShpeyerl  * "Concatenated" disk driver.
8377d85de2Sthorpej  *
8477d85de2Sthorpej  * Dynamic configuration and disklabel support by:
8577d85de2Sthorpej  *	Jason R. Thorpe <thorpej@nas.nasa.gov>
8677d85de2Sthorpej  *	Numerical Aerodynamic Simulation Facility
8777d85de2Sthorpej  *	Mail Stop 258-6
8877d85de2Sthorpej  *	NASA Ames Research Center
8977d85de2Sthorpej  *	Moffett Field, CA 94035
906f9db1eeShpeyerl  */
916f9db1eeShpeyerl 
926f9db1eeShpeyerl #include <sys/param.h>
936f9db1eeShpeyerl #include <sys/systm.h>
943214723fShpeyerl #include <sys/proc.h>
956f9db1eeShpeyerl #include <sys/errno.h>
966f9db1eeShpeyerl #include <sys/buf.h>
976f9db1eeShpeyerl #include <sys/malloc.h>
9877d85de2Sthorpej #include <sys/namei.h>
993214723fShpeyerl #include <sys/stat.h>
1003214723fShpeyerl #include <sys/ioctl.h>
1013214723fShpeyerl #include <sys/disklabel.h>
10277d85de2Sthorpej #include <sys/device.h>
10377d85de2Sthorpej #include <sys/disk.h>
10477d85de2Sthorpej #include <sys/syslog.h>
1053214723fShpeyerl #include <sys/fcntl.h>
10677d85de2Sthorpej #include <sys/vnode.h>
107e1930da2Schristos #include <sys/conf.h>
1080272b2abSthorpej #include <sys/lock.h>
109d272bb00Sthorpej #include <sys/queue.h>
1106f9db1eeShpeyerl 
1116f9db1eeShpeyerl #include <dev/ccdvar.h>
1126f9db1eeShpeyerl 
11377d85de2Sthorpej #if defined(CCDDEBUG) && !defined(DEBUG)
11477d85de2Sthorpej #define DEBUG
11577d85de2Sthorpej #endif
11677d85de2Sthorpej 
1176f9db1eeShpeyerl #ifdef DEBUG
1183214723fShpeyerl #define CCDB_FOLLOW	0x01
1193214723fShpeyerl #define CCDB_INIT	0x02
1203214723fShpeyerl #define CCDB_IO		0x04
12177d85de2Sthorpej #define CCDB_LABEL	0x08
12277d85de2Sthorpej #define CCDB_VNODE	0x10
123732dd94aSthorpej int ccddebug = 0x00;
1246f9db1eeShpeyerl #endif
1256f9db1eeShpeyerl 
126f694af67Scgd #define	ccdunit(x)	DISKUNIT(x)
1276f9db1eeShpeyerl 
128f694af67Scgd struct ccdbuf {
129f694af67Scgd 	struct buf	cb_buf;		/* new I/O buf */
130f694af67Scgd 	struct buf	*cb_obp;	/* ptr. to original I/O buf */
131*c6aa25bfSthorpej 	struct ccd_softc *cb_sc;	/* pointer to ccd softc */
132f694af67Scgd 	int		cb_comp;	/* target component */
133d272bb00Sthorpej 	SIMPLEQ_ENTRY(ccdbuf) cb_q;	/* fifo of component buffers */
134f694af67Scgd };
1356f9db1eeShpeyerl 
136b6ac7c9bSthorpej #define	CCD_GETBUF(cs)		pool_get(&(cs)->sc_cbufpool, PR_NOWAIT)
13743561361Sthorpej #define	CCD_PUTBUF(cs, cbp)	pool_put(&(cs)->sc_cbufpool, cbp)
1386f9db1eeShpeyerl 
13977d85de2Sthorpej #define CCDLABELDEV(dev)	\
14077d85de2Sthorpej 	(MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART))
1416f9db1eeShpeyerl 
14277d85de2Sthorpej /* called by main() at boot time */
14377d85de2Sthorpej void	ccdattach __P((int));
14477d85de2Sthorpej 
14577d85de2Sthorpej /* called by biodone() at interrupt time */
146d318abdbSchristos void	ccdiodone __P((struct buf *));
147d318abdbSchristos int	ccdsize __P((dev_t));
148f694af67Scgd 
14977d85de2Sthorpej static	void ccdstart __P((struct ccd_softc *, struct buf *));
1500272b2abSthorpej static	void ccdinterleave __P((struct ccd_softc *));
15177d85de2Sthorpej static	void ccdintr __P((struct ccd_softc *, struct buf *));
1520272b2abSthorpej static	int ccdinit __P((struct ccd_softc *, char **, struct vnode **,
1530272b2abSthorpej 	    struct proc *));
15477d85de2Sthorpej static	int ccdlookup __P((char *, struct proc *p, struct vnode **));
155092c2019Sthorpej static	struct ccdbuf *ccdbuffer __P((struct ccd_softc *, struct buf *,
156092c2019Sthorpej 		daddr_t, caddr_t, long));
157939e074dSthorpej static	void ccdgetdefaultlabel __P((struct ccd_softc *, struct disklabel *));
15877d85de2Sthorpej static	void ccdgetdisklabel __P((dev_t));
15977d85de2Sthorpej static	void ccdmakedisklabel __P((struct ccd_softc *));
1603214723fShpeyerl 
16177d85de2Sthorpej #ifdef DEBUG
16277d85de2Sthorpej static	void printiinfo __P((struct ccdiinfo *));
16377d85de2Sthorpej #endif
16477d85de2Sthorpej 
16577d85de2Sthorpej /* Non-private for the benefit of libkvm. */
1663214723fShpeyerl struct	ccd_softc *ccd_softc;
16777d85de2Sthorpej int	numccd = 0;
1686f9db1eeShpeyerl 
1696f9db1eeShpeyerl /*
17077d85de2Sthorpej  * Called by main() during pseudo-device attachment.  All we need
17177d85de2Sthorpej  * to do is allocate enough space for devices to be configured later.
1726f9db1eeShpeyerl  */
1736f9db1eeShpeyerl void
1743214723fShpeyerl ccdattach(num)
1753214723fShpeyerl 	int num;
1766f9db1eeShpeyerl {
1770272b2abSthorpej 	struct ccd_softc *cs;
1780272b2abSthorpej 	int i;
1790272b2abSthorpej 
18077d85de2Sthorpej 	if (num <= 0) {
18177d85de2Sthorpej #ifdef DIAGNOSTIC
18277d85de2Sthorpej 		panic("ccdattach: count <= 0");
18377d85de2Sthorpej #endif
1843214723fShpeyerl 		return;
1853214723fShpeyerl 	}
18677d85de2Sthorpej 
18777d85de2Sthorpej 	ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc),
18877d85de2Sthorpej 	    M_DEVBUF, M_NOWAIT);
1890272b2abSthorpej 	if (ccd_softc == NULL) {
19086373f8cSchristos 		printf("WARNING: no memory for concatenated disks\n");
19177d85de2Sthorpej 		if (ccd_softc != NULL)
19277d85de2Sthorpej 			free(ccd_softc, M_DEVBUF);
19377d85de2Sthorpej 		return;
19477d85de2Sthorpej 	}
1953214723fShpeyerl 	numccd = num;
19677d85de2Sthorpej 	bzero(ccd_softc, num * sizeof(struct ccd_softc));
1970272b2abSthorpej 
1980272b2abSthorpej 	/* Initialize per-softc structures. */
1990272b2abSthorpej 	for (i = 0; i < num; i++) {
2000272b2abSthorpej 		cs = &ccd_softc[i];
2010272b2abSthorpej 		sprintf(cs->sc_xname, "ccd%d", i);	/* XXX */
2020272b2abSthorpej 		cs->sc_dkdev.dk_name = cs->sc_xname;	/* XXX */
2030272b2abSthorpej 		lockinit(&cs->sc_lock, PRIBIO, "ccdlk", 0, 0);
2040272b2abSthorpej 	}
2056f9db1eeShpeyerl }
2066f9db1eeShpeyerl 
20777d85de2Sthorpej static int
2080272b2abSthorpej ccdinit(cs, cpaths, vpp, p)
2090272b2abSthorpej 	struct ccd_softc *cs;
21077d85de2Sthorpej 	char **cpaths;
2110272b2abSthorpej 	struct vnode **vpp;
21277d85de2Sthorpej 	struct proc *p;
2136f9db1eeShpeyerl {
214d318abdbSchristos 	register struct ccdcinfo *ci = NULL;
2156f9db1eeShpeyerl 	register size_t size;
2166f9db1eeShpeyerl 	register int ix;
21777d85de2Sthorpej 	struct vattr va;
2186f9db1eeShpeyerl 	size_t minsize;
21977d85de2Sthorpej 	int maxsecsize;
220a44a2765Scgd 	struct partinfo dpart;
22177d85de2Sthorpej 	struct ccdgeom *ccg = &cs->sc_geom;
22277d85de2Sthorpej 	char tmppath[MAXPATHLEN];
22377d85de2Sthorpej 	int error;
2246f9db1eeShpeyerl 
2256f9db1eeShpeyerl #ifdef DEBUG
2263214723fShpeyerl 	if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
227*c6aa25bfSthorpej 		printf("%s: ccdinit\n", cs->sc_xname);
2286f9db1eeShpeyerl #endif
22977d85de2Sthorpej 
23077d85de2Sthorpej 	/* Allocate space for the component info. */
23177d85de2Sthorpej 	cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo),
23277d85de2Sthorpej 	    M_DEVBUF, M_WAITOK);
23377d85de2Sthorpej 
2340272b2abSthorpej 	cs->sc_size = 0;
2350272b2abSthorpej 
2366f9db1eeShpeyerl 	/*
2376f9db1eeShpeyerl 	 * Verify that each component piece exists and record
2386f9db1eeShpeyerl 	 * relevant information about it.
2396f9db1eeShpeyerl 	 */
24077d85de2Sthorpej 	maxsecsize = 0;
2416f9db1eeShpeyerl 	minsize = 0;
24277d85de2Sthorpej 	for (ix = 0; ix < cs->sc_nccdisks; ix++) {
2436f9db1eeShpeyerl 		ci = &cs->sc_cinfo[ix];
2440272b2abSthorpej 		ci->ci_vp = vpp[ix];
245a44a2765Scgd 
24677d85de2Sthorpej 		/*
24777d85de2Sthorpej 		 * Copy in the pathname of the component.
24877d85de2Sthorpej 		 */
24977d85de2Sthorpej 		bzero(tmppath, sizeof(tmppath));	/* sanity */
250d318abdbSchristos 		error = copyinstr(cpaths[ix], tmppath,
251d318abdbSchristos 		    MAXPATHLEN, &ci->ci_pathlen);
252d318abdbSchristos 		if (error) {
25377d85de2Sthorpej #ifdef DEBUG
25477d85de2Sthorpej 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
25586373f8cSchristos 				printf("%s: can't copy path, error = %d\n",
2565b39541eSthorpej 				    cs->sc_xname, error);
25777d85de2Sthorpej #endif
25877d85de2Sthorpej 			free(cs->sc_cinfo, M_DEVBUF);
25977d85de2Sthorpej 			return (error);
26077d85de2Sthorpej 		}
26177d85de2Sthorpej 		ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK);
26277d85de2Sthorpej 		bcopy(tmppath, ci->ci_path, ci->ci_pathlen);
26377d85de2Sthorpej 
26477d85de2Sthorpej 		/*
26577d85de2Sthorpej 		 * XXX: Cache the component's dev_t.
26677d85de2Sthorpej 		 */
2670272b2abSthorpej 		if ((error = VOP_GETATTR(vpp[ix], &va, p->p_ucred, p)) != 0) {
26877d85de2Sthorpej #ifdef DEBUG
26977d85de2Sthorpej 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
27086373f8cSchristos 				printf("%s: %s: getattr failed %s = %d\n",
2715b39541eSthorpej 				    cs->sc_xname, ci->ci_path,
27277d85de2Sthorpej 				    "error", error);
27377d85de2Sthorpej #endif
27477d85de2Sthorpej 			free(ci->ci_path, M_DEVBUF);
27577d85de2Sthorpej 			free(cs->sc_cinfo, M_DEVBUF);
27677d85de2Sthorpej 			return (error);
27777d85de2Sthorpej 		}
27877d85de2Sthorpej 		ci->ci_dev = va.va_rdev;
27977d85de2Sthorpej 
28077d85de2Sthorpej 		/*
28177d85de2Sthorpej 		 * Get partition information for the component.
28277d85de2Sthorpej 		 */
2830272b2abSthorpej 		error = VOP_IOCTL(vpp[ix], DIOCGPART, (caddr_t)&dpart,
284d318abdbSchristos 		    FREAD, p->p_ucred, p);
285d318abdbSchristos 		if (error) {
28677d85de2Sthorpej #ifdef DEBUG
28777d85de2Sthorpej 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
28886373f8cSchristos 				 printf("%s: %s: ioctl failed, error = %d\n",
2895b39541eSthorpej 				     cs->sc_xname, ci->ci_path, error);
29077d85de2Sthorpej #endif
29177d85de2Sthorpej 			free(ci->ci_path, M_DEVBUF);
29277d85de2Sthorpej 			free(cs->sc_cinfo, M_DEVBUF);
29377d85de2Sthorpej 			return (error);
29477d85de2Sthorpej 		}
29577d85de2Sthorpej 
29677d85de2Sthorpej 		/*
29777d85de2Sthorpej 		 * Calculate the size, truncating to an interleave
29877d85de2Sthorpej 		 * boundary if necessary.
29977d85de2Sthorpej 		 */
300fd01cb62Sthorpej 		maxsecsize =
301fd01cb62Sthorpej 		    ((dpart.disklab->d_secsize > maxsecsize) ?
302fd01cb62Sthorpej 		    dpart.disklab->d_secsize : maxsecsize);
303fd01cb62Sthorpej 		size = dpart.part->p_size;
3046f9db1eeShpeyerl 		if (cs->sc_ileave > 1)
3056f9db1eeShpeyerl 			size -= size % cs->sc_ileave;
3063214723fShpeyerl 
30777d85de2Sthorpej 		if (size == 0) {
30877d85de2Sthorpej #ifdef DEBUG
30977d85de2Sthorpej 			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
31086373f8cSchristos 				printf("%s: %s: size == 0\n",
3115b39541eSthorpej 				    cs->sc_xname, ci->ci_path);
3123214723fShpeyerl #endif
31377d85de2Sthorpej 			free(ci->ci_path, M_DEVBUF);
31477d85de2Sthorpej 			free(cs->sc_cinfo, M_DEVBUF);
31577d85de2Sthorpej 			return (ENODEV);
31677d85de2Sthorpej 		}
31777d85de2Sthorpej 
3186f9db1eeShpeyerl 		if (minsize == 0 || size < minsize)
3196f9db1eeShpeyerl 			minsize = size;
3206f9db1eeShpeyerl 		ci->ci_size = size;
3216f9db1eeShpeyerl 		cs->sc_size += size;
3226f9db1eeShpeyerl 	}
32377d85de2Sthorpej 
32477d85de2Sthorpej 	/*
32577d85de2Sthorpej 	 * Don't allow the interleave to be smaller than
32677d85de2Sthorpej 	 * the biggest component sector.
32777d85de2Sthorpej 	 */
32877d85de2Sthorpej 	if ((cs->sc_ileave > 0) &&
32977d85de2Sthorpej 	    (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) {
33077d85de2Sthorpej #ifdef DEBUG
33177d85de2Sthorpej 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
33286373f8cSchristos 			printf("%s: interleave must be at least %d\n",
3335b39541eSthorpej 			    cs->sc_xname, (maxsecsize / DEV_BSIZE));
33477d85de2Sthorpej #endif
33577d85de2Sthorpej 		free(ci->ci_path, M_DEVBUF);
33677d85de2Sthorpej 		free(cs->sc_cinfo, M_DEVBUF);
33777d85de2Sthorpej 		return (EINVAL);
33877d85de2Sthorpej 	}
33977d85de2Sthorpej 
3406f9db1eeShpeyerl 	/*
3416f9db1eeShpeyerl 	 * If uniform interleave is desired set all sizes to that of
3426f9db1eeShpeyerl 	 * the smallest component.
3436f9db1eeShpeyerl 	 */
3440272b2abSthorpej 	if (cs->sc_flags & CCDF_UNIFORM) {
3456f9db1eeShpeyerl 		for (ci = cs->sc_cinfo;
3466f9db1eeShpeyerl 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
3476f9db1eeShpeyerl 			ci->ci_size = minsize;
348732dd94aSthorpej 
3496f9db1eeShpeyerl 		cs->sc_size = cs->sc_nccdisks * minsize;
3506f9db1eeShpeyerl 	}
35177d85de2Sthorpej 
3526f9db1eeShpeyerl 	/*
35377d85de2Sthorpej 	 * Construct the interleave table.
3546f9db1eeShpeyerl 	 */
3550272b2abSthorpej 	ccdinterleave(cs);
35677d85de2Sthorpej 
35777d85de2Sthorpej 	/*
35877d85de2Sthorpej 	 * Create pseudo-geometry based on 1MB cylinders.  It's
35977d85de2Sthorpej 	 * pretty close.
36077d85de2Sthorpej 	 */
36177d85de2Sthorpej 	ccg->ccg_secsize = DEV_BSIZE;
36289d4987eSthorpej 	ccg->ccg_ntracks = 1;
36377d85de2Sthorpej 	ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize);
36477d85de2Sthorpej 	ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors;
36577d85de2Sthorpej 
36677d85de2Sthorpej 	cs->sc_flags |= CCDF_INITED;
3675b39541eSthorpej 
36877d85de2Sthorpej 	return (0);
3696f9db1eeShpeyerl }
3706f9db1eeShpeyerl 
37177d85de2Sthorpej static void
3720272b2abSthorpej ccdinterleave(cs)
3736f9db1eeShpeyerl 	register struct ccd_softc *cs;
3746f9db1eeShpeyerl {
3756f9db1eeShpeyerl 	register struct ccdcinfo *ci, *smallci;
3766f9db1eeShpeyerl 	register struct ccdiinfo *ii;
3776f9db1eeShpeyerl 	register daddr_t bn, lbn;
3786f9db1eeShpeyerl 	register int ix;
3796f9db1eeShpeyerl 	u_long size;
3806f9db1eeShpeyerl 
3816f9db1eeShpeyerl #ifdef DEBUG
3823214723fShpeyerl 	if (ccddebug & CCDB_INIT)
38386373f8cSchristos 		printf("ccdinterleave(%p): ileave %d\n", cs, cs->sc_ileave);
3846f9db1eeShpeyerl #endif
3856f9db1eeShpeyerl 	/*
3866f9db1eeShpeyerl 	 * Allocate an interleave table.
3876f9db1eeShpeyerl 	 * Chances are this is too big, but we don't care.
3886f9db1eeShpeyerl 	 */
3896f9db1eeShpeyerl 	size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo);
3906f9db1eeShpeyerl 	cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
3916f9db1eeShpeyerl 	bzero((caddr_t)cs->sc_itable, size);
39277d85de2Sthorpej 
3936f9db1eeShpeyerl 	/*
3946f9db1eeShpeyerl 	 * Trivial case: no interleave (actually interleave of disk size).
39577d85de2Sthorpej 	 * Each table entry represents a single component in its entirety.
3966f9db1eeShpeyerl 	 */
3976f9db1eeShpeyerl 	if (cs->sc_ileave == 0) {
3986f9db1eeShpeyerl 		bn = 0;
3996f9db1eeShpeyerl 		ii = cs->sc_itable;
40077d85de2Sthorpej 
4016f9db1eeShpeyerl 		for (ix = 0; ix < cs->sc_nccdisks; ix++) {
40289d4987eSthorpej 			/* Allocate space for ii_index. */
40389d4987eSthorpej 			ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK);
4046f9db1eeShpeyerl 			ii->ii_ndisk = 1;
4056f9db1eeShpeyerl 			ii->ii_startblk = bn;
4066f9db1eeShpeyerl 			ii->ii_startoff = 0;
4076f9db1eeShpeyerl 			ii->ii_index[0] = ix;
4086f9db1eeShpeyerl 			bn += cs->sc_cinfo[ix].ci_size;
4096f9db1eeShpeyerl 			ii++;
4106f9db1eeShpeyerl 		}
4116f9db1eeShpeyerl 		ii->ii_ndisk = 0;
4126f9db1eeShpeyerl #ifdef DEBUG
4133214723fShpeyerl 		if (ccddebug & CCDB_INIT)
4146f9db1eeShpeyerl 			printiinfo(cs->sc_itable);
4156f9db1eeShpeyerl #endif
41677d85de2Sthorpej 		return;
4176f9db1eeShpeyerl 	}
41877d85de2Sthorpej 
4196f9db1eeShpeyerl 	/*
4206f9db1eeShpeyerl 	 * The following isn't fast or pretty; it doesn't have to be.
4216f9db1eeShpeyerl 	 */
4226f9db1eeShpeyerl 	size = 0;
4236f9db1eeShpeyerl 	bn = lbn = 0;
4246f9db1eeShpeyerl 	for (ii = cs->sc_itable; ; ii++) {
42577d85de2Sthorpej 		/* Allocate space for ii_index. */
42689d4987eSthorpej 		ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks),
42789d4987eSthorpej 		    M_DEVBUF, M_WAITOK);
42877d85de2Sthorpej 
4296f9db1eeShpeyerl 		/*
4306f9db1eeShpeyerl 		 * Locate the smallest of the remaining components
4316f9db1eeShpeyerl 		 */
4326f9db1eeShpeyerl 		smallci = NULL;
4336f9db1eeShpeyerl 		for (ci = cs->sc_cinfo;
4346f9db1eeShpeyerl 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
4356f9db1eeShpeyerl 			if (ci->ci_size > size &&
4366f9db1eeShpeyerl 			    (smallci == NULL ||
4376f9db1eeShpeyerl 			     ci->ci_size < smallci->ci_size))
4386f9db1eeShpeyerl 				smallci = ci;
43977d85de2Sthorpej 
4406f9db1eeShpeyerl 		/*
4416f9db1eeShpeyerl 		 * Nobody left, all done
4426f9db1eeShpeyerl 		 */
4436f9db1eeShpeyerl 		if (smallci == NULL) {
4446f9db1eeShpeyerl 			ii->ii_ndisk = 0;
4456f9db1eeShpeyerl 			break;
4466f9db1eeShpeyerl 		}
44777d85de2Sthorpej 
4486f9db1eeShpeyerl 		/*
4496f9db1eeShpeyerl 		 * Record starting logical block and component offset
4506f9db1eeShpeyerl 		 */
4516f9db1eeShpeyerl 		ii->ii_startblk = bn / cs->sc_ileave;
4526f9db1eeShpeyerl 		ii->ii_startoff = lbn;
45377d85de2Sthorpej 
4546f9db1eeShpeyerl 		/*
4556f9db1eeShpeyerl 		 * Determine how many disks take part in this interleave
4566f9db1eeShpeyerl 		 * and record their indices.
4576f9db1eeShpeyerl 		 */
4586f9db1eeShpeyerl 		ix = 0;
4596f9db1eeShpeyerl 		for (ci = cs->sc_cinfo;
4606f9db1eeShpeyerl 		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++)
4616f9db1eeShpeyerl 			if (ci->ci_size >= smallci->ci_size)
4626f9db1eeShpeyerl 				ii->ii_index[ix++] = ci - cs->sc_cinfo;
4636f9db1eeShpeyerl 		ii->ii_ndisk = ix;
4646f9db1eeShpeyerl 		bn += ix * (smallci->ci_size - size);
4656f9db1eeShpeyerl 		lbn = smallci->ci_size / cs->sc_ileave;
4666f9db1eeShpeyerl 		size = smallci->ci_size;
4676f9db1eeShpeyerl 	}
4686f9db1eeShpeyerl #ifdef DEBUG
4693214723fShpeyerl 	if (ccddebug & CCDB_INIT)
4706f9db1eeShpeyerl 		printiinfo(cs->sc_itable);
4716f9db1eeShpeyerl #endif
4726f9db1eeShpeyerl }
4736f9db1eeShpeyerl 
47477d85de2Sthorpej /* ARGSUSED */
47577d85de2Sthorpej int
47677d85de2Sthorpej ccdopen(dev, flags, fmt, p)
4776f9db1eeShpeyerl 	dev_t dev;
47877d85de2Sthorpej 	int flags, fmt;
47977d85de2Sthorpej 	struct proc *p;
4806f9db1eeShpeyerl {
4816f9db1eeShpeyerl 	int unit = ccdunit(dev);
48277d85de2Sthorpej 	struct ccd_softc *cs;
48377d85de2Sthorpej 	struct disklabel *lp;
484b8dcfbd3Sthorpej 	int error = 0, part, pmask;
4856f9db1eeShpeyerl 
4866f9db1eeShpeyerl #ifdef DEBUG
4873214723fShpeyerl 	if (ccddebug & CCDB_FOLLOW)
488c27c2868Sfair 		printf("ccdopen(0x%x, 0x%x)\n", dev, flags);
4896f9db1eeShpeyerl #endif
49077d85de2Sthorpej 	if (unit >= numccd)
4916f9db1eeShpeyerl 		return (ENXIO);
49277d85de2Sthorpej 	cs = &ccd_softc[unit];
49377d85de2Sthorpej 
4940272b2abSthorpej 	if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
495b8dcfbd3Sthorpej 		return (error);
496b8dcfbd3Sthorpej 
4975b39541eSthorpej 	lp = cs->sc_dkdev.dk_label;
49877d85de2Sthorpej 
49977d85de2Sthorpej 	part = DISKPART(dev);
50077d85de2Sthorpej 	pmask = (1 << part);
50177d85de2Sthorpej 
502b8dcfbd3Sthorpej 	/*
503b8dcfbd3Sthorpej 	 * If we're initialized, check to see if there are any other
504b8dcfbd3Sthorpej 	 * open partitions.  If not, then it's safe to update
505b8dcfbd3Sthorpej 	 * the in-core disklabel.
506b8dcfbd3Sthorpej 	 */
507b8dcfbd3Sthorpej 	if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0))
508b8dcfbd3Sthorpej 		ccdgetdisklabel(dev);
509b8dcfbd3Sthorpej 
51077d85de2Sthorpej 	/* Check that the partition exists. */
51191bd533cSthorpej 	if (part != RAW_PART) {
51291bd533cSthorpej 		if (((cs->sc_flags & CCDF_INITED) == 0) ||
513bb608224Sthorpej 		    ((part >= lp->d_npartitions) ||
514b8dcfbd3Sthorpej 		     (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
515b8dcfbd3Sthorpej 			error = ENXIO;
516b8dcfbd3Sthorpej 			goto done;
517b8dcfbd3Sthorpej 		}
51891bd533cSthorpej 	}
51977d85de2Sthorpej 
52077d85de2Sthorpej 	/* Prevent our unit from being unconfigured while open. */
52177d85de2Sthorpej 	switch (fmt) {
52277d85de2Sthorpej 	case S_IFCHR:
52377d85de2Sthorpej 		cs->sc_dkdev.dk_copenmask |= pmask;
52477d85de2Sthorpej 		break;
52577d85de2Sthorpej 
52677d85de2Sthorpej 	case S_IFBLK:
52777d85de2Sthorpej 		cs->sc_dkdev.dk_bopenmask |= pmask;
52877d85de2Sthorpej 		break;
52977d85de2Sthorpej 	}
53077d85de2Sthorpej 	cs->sc_dkdev.dk_openmask =
53177d85de2Sthorpej 	    cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
53277d85de2Sthorpej 
533b8dcfbd3Sthorpej  done:
5340272b2abSthorpej 	(void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL);
53549c5d29eSthorpej 	return (error);
5366f9db1eeShpeyerl }
5376f9db1eeShpeyerl 
53877d85de2Sthorpej /* ARGSUSED */
53977d85de2Sthorpej int
54077d85de2Sthorpej ccdclose(dev, flags, fmt, p)
541a44a2765Scgd 	dev_t dev;
54277d85de2Sthorpej 	int flags, fmt;
54377d85de2Sthorpej 	struct proc *p;
544a44a2765Scgd {
54577d85de2Sthorpej 	int unit = ccdunit(dev);
54677d85de2Sthorpej 	struct ccd_softc *cs;
547b8dcfbd3Sthorpej 	int error = 0, part;
54877d85de2Sthorpej 
549a44a2765Scgd #ifdef DEBUG
550a44a2765Scgd 	if (ccddebug & CCDB_FOLLOW)
551c27c2868Sfair 		printf("ccdclose(0x%x, 0x%x)\n", dev, flags);
552a44a2765Scgd #endif
55377d85de2Sthorpej 
55477d85de2Sthorpej 	if (unit >= numccd)
55577d85de2Sthorpej 		return (ENXIO);
55677d85de2Sthorpej 	cs = &ccd_softc[unit];
557b8dcfbd3Sthorpej 
5580272b2abSthorpej 	if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
559b8dcfbd3Sthorpej 		return (error);
560b8dcfbd3Sthorpej 
56177d85de2Sthorpej 	part = DISKPART(dev);
56277d85de2Sthorpej 
56377d85de2Sthorpej 	/* ...that much closer to allowing unconfiguration... */
56477d85de2Sthorpej 	switch (fmt) {
56577d85de2Sthorpej 	case S_IFCHR:
56677d85de2Sthorpej 		cs->sc_dkdev.dk_copenmask &= ~(1 << part);
56777d85de2Sthorpej 		break;
56877d85de2Sthorpej 
56977d85de2Sthorpej 	case S_IFBLK:
57077d85de2Sthorpej 		cs->sc_dkdev.dk_bopenmask &= ~(1 << part);
57177d85de2Sthorpej 		break;
57277d85de2Sthorpej 	}
57377d85de2Sthorpej 	cs->sc_dkdev.dk_openmask =
57477d85de2Sthorpej 	    cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask;
57577d85de2Sthorpej 
5760272b2abSthorpej 	(void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL);
577a44a2765Scgd 	return (0);
578a44a2765Scgd }
579a44a2765Scgd 
58077d85de2Sthorpej void
5816f9db1eeShpeyerl ccdstrategy(bp)
5826f9db1eeShpeyerl 	register struct buf *bp;
5836f9db1eeShpeyerl {
5846f9db1eeShpeyerl 	register int unit = ccdunit(bp->b_dev);
5856f9db1eeShpeyerl 	register struct ccd_softc *cs = &ccd_softc[unit];
586d318abdbSchristos 	register int s;
58777d85de2Sthorpej 	int wlabel;
588b8dcfbd3Sthorpej 	struct disklabel *lp;
5896f9db1eeShpeyerl 
5906f9db1eeShpeyerl #ifdef DEBUG
5913214723fShpeyerl 	if (ccddebug & CCDB_FOLLOW)
59286373f8cSchristos 		printf("ccdstrategy(%p): unit %d\n", bp, unit);
5936f9db1eeShpeyerl #endif
5943214723fShpeyerl 	if ((cs->sc_flags & CCDF_INITED) == 0) {
595*c6aa25bfSthorpej #ifdef DEBUG
596*c6aa25bfSthorpej 		if (ccddebug & CCDB_FOLLOW)
597*c6aa25bfSthorpej 			printf("ccdstrategy: unit %d: not inited\n", unit);
598*c6aa25bfSthorpej #endif
5996f9db1eeShpeyerl 		bp->b_error = ENXIO;
6006f9db1eeShpeyerl 		bp->b_flags |= B_ERROR;
6016f9db1eeShpeyerl 		goto done;
6026f9db1eeShpeyerl 	}
60377d85de2Sthorpej 
60477d85de2Sthorpej 	/* If it's a nil transfer, wake up the top half now. */
60577d85de2Sthorpej 	if (bp->b_bcount == 0)
6066f9db1eeShpeyerl 		goto done;
60777d85de2Sthorpej 
6085b39541eSthorpej 	lp = cs->sc_dkdev.dk_label;
609b8dcfbd3Sthorpej 
61077d85de2Sthorpej 	/*
611ab0109adSthorpej 	 * Do bounds checking and adjust transfer.  If there's an
61277d85de2Sthorpej 	 * error, the bounds check will flag that for us.
61377d85de2Sthorpej 	 */
61477d85de2Sthorpej 	wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING);
6154e3112d3Sthorpej 	if (DISKPART(bp->b_dev) != RAW_PART)
616b8dcfbd3Sthorpej 		if (bounds_check_with_label(bp, lp, wlabel) <= 0)
6176f9db1eeShpeyerl 			goto done;
61877d85de2Sthorpej 
6196f9db1eeShpeyerl 	bp->b_resid = bp->b_bcount;
62077d85de2Sthorpej 
6216f9db1eeShpeyerl 	/*
6226f9db1eeShpeyerl 	 * "Start" the unit.
6236f9db1eeShpeyerl 	 */
6246f9db1eeShpeyerl 	s = splbio();
6253214723fShpeyerl 	ccdstart(cs, bp);
6266f9db1eeShpeyerl 	splx(s);
627d272bb00Sthorpej 	if (bp->b_flags & B_ERROR)
628d272bb00Sthorpej 		goto done;
6296f9db1eeShpeyerl 	return;
6306f9db1eeShpeyerl done:
6316f9db1eeShpeyerl 	biodone(bp);
6326f9db1eeShpeyerl }
6336f9db1eeShpeyerl 
63477d85de2Sthorpej static void
6353214723fShpeyerl ccdstart(cs, bp)
6363214723fShpeyerl 	register struct ccd_softc *cs;
6373214723fShpeyerl 	register struct buf *bp;
6386f9db1eeShpeyerl {
6396f9db1eeShpeyerl 	register long bcount, rcount;
640092c2019Sthorpej 	struct ccdbuf *cbp;
6416f9db1eeShpeyerl 	caddr_t addr;
6426f9db1eeShpeyerl 	daddr_t bn;
643f85819bcSthorpej 	struct partition *pp;
644d272bb00Sthorpej 	SIMPLEQ_HEAD(, ccdbuf) cbufq;
6456f9db1eeShpeyerl 
6466f9db1eeShpeyerl #ifdef DEBUG
6473214723fShpeyerl 	if (ccddebug & CCDB_FOLLOW)
64886373f8cSchristos 		printf("ccdstart(%p, %p)\n", cs, bp);
6496f9db1eeShpeyerl #endif
65077d85de2Sthorpej 
6515b39541eSthorpej 	/* Instrumentation. */
6525b39541eSthorpej 	disk_busy(&cs->sc_dkdev);
65377d85de2Sthorpej 
6546f9db1eeShpeyerl 	/*
655ab0109adSthorpej 	 * Translate the partition-relative block number to an absolute.
6566f9db1eeShpeyerl 	 */
657f85819bcSthorpej 	bn = bp->b_blkno;
658f85819bcSthorpej 	if (DISKPART(bp->b_dev) != RAW_PART) {
6595b39541eSthorpej 		pp = &cs->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
660f85819bcSthorpej 		bn += pp->p_offset;
661f85819bcSthorpej 	}
662ab0109adSthorpej 
663ab0109adSthorpej 	/*
664d272bb00Sthorpej 	 * Allocate the component buffers.
665ab0109adSthorpej 	 */
666d272bb00Sthorpej 	SIMPLEQ_INIT(&cbufq);
6673214723fShpeyerl 	addr = bp->b_data;
6686f9db1eeShpeyerl 	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
669092c2019Sthorpej 		cbp = ccdbuffer(cs, bp, bn, addr, bcount);
670d272bb00Sthorpej 		if (cbp == NULL) {
671d272bb00Sthorpej 			/* Free the already allocated component buffers. */
672d272bb00Sthorpej 			while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
673d272bb00Sthorpej 				SIMPLEQ_REMOVE_HEAD(&cbufq, cbp, cb_q);
674d272bb00Sthorpej 				CCD_PUTBUF(cs, cbp);
675d272bb00Sthorpej 			}
676d272bb00Sthorpej 
677d272bb00Sthorpej 			/* Notify the upper layer we are out of memory. */
678d272bb00Sthorpej 			bp->b_error = ENOMEM;
679d272bb00Sthorpej 			bp->b_flags |= B_ERROR;
680*c6aa25bfSthorpej 			disk_unbusy(&cs->sc_dkdev, 0);
681d272bb00Sthorpej 			return;
682d272bb00Sthorpej 		}
683d272bb00Sthorpej 		SIMPLEQ_INSERT_TAIL(&cbufq, cbp, cb_q);
684092c2019Sthorpej 		rcount = cbp->cb_buf.b_bcount;
685d272bb00Sthorpej 		bn += btodb(rcount);
686d272bb00Sthorpej 		addr += rcount;
687d272bb00Sthorpej 	}
688d272bb00Sthorpej 
689d272bb00Sthorpej 	/* Now fire off the requests. */
690d272bb00Sthorpej 	while ((cbp = SIMPLEQ_FIRST(&cbufq)) != NULL) {
691d272bb00Sthorpej 		SIMPLEQ_REMOVE_HEAD(&cbufq, cbp, cb_q);
692092c2019Sthorpej 		if ((cbp->cb_buf.b_flags & B_READ) == 0)
693092c2019Sthorpej 			cbp->cb_buf.b_vp->v_numoutput++;
694092c2019Sthorpej 		VOP_STRATEGY(&cbp->cb_buf);
6956f9db1eeShpeyerl 	}
6966f9db1eeShpeyerl }
6976f9db1eeShpeyerl 
6986f9db1eeShpeyerl /*
6996f9db1eeShpeyerl  * Build a component buffer header.
7006f9db1eeShpeyerl  */
701092c2019Sthorpej static struct ccdbuf *
702092c2019Sthorpej ccdbuffer(cs, bp, bn, addr, bcount)
7036f9db1eeShpeyerl 	register struct ccd_softc *cs;
7046f9db1eeShpeyerl 	struct buf *bp;
7056f9db1eeShpeyerl 	daddr_t bn;
7066f9db1eeShpeyerl 	caddr_t addr;
7076f9db1eeShpeyerl 	long bcount;
7086f9db1eeShpeyerl {
70900172c10Sthorpej 	register struct ccdcinfo *ci;
710f694af67Scgd 	register struct ccdbuf *cbp;
7116f9db1eeShpeyerl 	register daddr_t cbn, cboff;
712902855d6Sthorpej 	register u_int64_t cbc;
7137770d7c4Sthorpej 	int ccdisk;
7146f9db1eeShpeyerl 
7156f9db1eeShpeyerl #ifdef DEBUG
7163214723fShpeyerl 	if (ccddebug & CCDB_IO)
71786373f8cSchristos 		printf("ccdbuffer(%p, %p, %d, %p, %ld)\n",
7186f9db1eeShpeyerl 		       cs, bp, bn, addr, bcount);
7196f9db1eeShpeyerl #endif
7206f9db1eeShpeyerl 	/*
7216f9db1eeShpeyerl 	 * Determine which component bn falls in.
7226f9db1eeShpeyerl 	 */
7236f9db1eeShpeyerl 	cbn = bn;
7246f9db1eeShpeyerl 	cboff = 0;
72577d85de2Sthorpej 
7266f9db1eeShpeyerl 	/*
7276f9db1eeShpeyerl 	 * Serially concatenated
7286f9db1eeShpeyerl 	 */
7296f9db1eeShpeyerl 	if (cs->sc_ileave == 0) {
7306f9db1eeShpeyerl 		register daddr_t sblk;
7316f9db1eeShpeyerl 
7326f9db1eeShpeyerl 		sblk = 0;
7337770d7c4Sthorpej 		for (ccdisk = 0, ci = &cs->sc_cinfo[ccdisk];
7347770d7c4Sthorpej 		    cbn >= sblk + ci->ci_size;
7357770d7c4Sthorpej 		    ccdisk++, ci = &cs->sc_cinfo[ccdisk])
7366f9db1eeShpeyerl 			sblk += ci->ci_size;
7376f9db1eeShpeyerl 		cbn -= sblk;
7386f9db1eeShpeyerl 	}
7396f9db1eeShpeyerl 	/*
7406f9db1eeShpeyerl 	 * Interleaved
7416f9db1eeShpeyerl 	 */
7426f9db1eeShpeyerl 	else {
7436f9db1eeShpeyerl 		register struct ccdiinfo *ii;
7447770d7c4Sthorpej 		int off;
7456f9db1eeShpeyerl 
7466f9db1eeShpeyerl 		cboff = cbn % cs->sc_ileave;
7476f9db1eeShpeyerl 		cbn /= cs->sc_ileave;
7486f9db1eeShpeyerl 		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
7496f9db1eeShpeyerl 			if (ii->ii_startblk > cbn)
7506f9db1eeShpeyerl 				break;
7516f9db1eeShpeyerl 		ii--;
7526f9db1eeShpeyerl 		off = cbn - ii->ii_startblk;
7536f9db1eeShpeyerl 		if (ii->ii_ndisk == 1) {
7546f9db1eeShpeyerl 			ccdisk = ii->ii_index[0];
7556f9db1eeShpeyerl 			cbn = ii->ii_startoff + off;
7566f9db1eeShpeyerl 		} else {
7576f9db1eeShpeyerl 			ccdisk = ii->ii_index[off % ii->ii_ndisk];
7586f9db1eeShpeyerl 			cbn = ii->ii_startoff + off / ii->ii_ndisk;
7596f9db1eeShpeyerl 		}
7606f9db1eeShpeyerl 		cbn *= cs->sc_ileave;
7616f9db1eeShpeyerl 		ci = &cs->sc_cinfo[ccdisk];
7626f9db1eeShpeyerl 	}
76377d85de2Sthorpej 
7646f9db1eeShpeyerl 	/*
7656f9db1eeShpeyerl 	 * Fill in the component buf structure.
7666f9db1eeShpeyerl 	 */
76743561361Sthorpej 	cbp = CCD_GETBUF(cs);
768092c2019Sthorpej 	if (cbp == NULL)
769092c2019Sthorpej 		return (NULL);
770f694af67Scgd 	cbp->cb_buf.b_flags = bp->b_flags | B_CALL;
771d318abdbSchristos 	cbp->cb_buf.b_iodone = ccdiodone;
772f694af67Scgd 	cbp->cb_buf.b_proc = bp->b_proc;
77377d85de2Sthorpej 	cbp->cb_buf.b_dev = ci->ci_dev;		/* XXX */
774f694af67Scgd 	cbp->cb_buf.b_blkno = cbn + cboff;
775f694af67Scgd 	cbp->cb_buf.b_data = addr;
77677d85de2Sthorpej 	cbp->cb_buf.b_vp = ci->ci_vp;
7776f9db1eeShpeyerl 	if (cs->sc_ileave == 0)
778902855d6Sthorpej 		cbc = dbtob((u_int64_t)(ci->ci_size - cbn));
7796f9db1eeShpeyerl 	else
780902855d6Sthorpej 		cbc = dbtob((u_int64_t)(cs->sc_ileave - cboff));
781902855d6Sthorpej 	cbp->cb_buf.b_bcount = cbc < bcount ? cbc : bcount;
782f694af67Scgd 
7836f9db1eeShpeyerl 	/*
784f694af67Scgd 	 * context for ccdiodone
7856f9db1eeShpeyerl 	 */
786f694af67Scgd 	cbp->cb_obp = bp;
787*c6aa25bfSthorpej 	cbp->cb_sc = cs;
7887770d7c4Sthorpej 	cbp->cb_comp = ccdisk;
789f694af67Scgd 
7906f9db1eeShpeyerl #ifdef DEBUG
7913214723fShpeyerl 	if (ccddebug & CCDB_IO)
792c27c2868Sfair 		printf(" dev 0x%x(u%d): cbp %p bn %d addr %p bcnt %ld\n",
793f694af67Scgd 		    ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno,
794f694af67Scgd 		    cbp->cb_buf.b_data, cbp->cb_buf.b_bcount);
7956f9db1eeShpeyerl #endif
796092c2019Sthorpej 
797092c2019Sthorpej 	return (cbp);
7986f9db1eeShpeyerl }
7996f9db1eeShpeyerl 
80077d85de2Sthorpej static void
8013214723fShpeyerl ccdintr(cs, bp)
8023214723fShpeyerl 	register struct ccd_softc *cs;
8033214723fShpeyerl 	register struct buf *bp;
8046f9db1eeShpeyerl {
8056f9db1eeShpeyerl 
8066f9db1eeShpeyerl #ifdef DEBUG
8073214723fShpeyerl 	if (ccddebug & CCDB_FOLLOW)
80886373f8cSchristos 		printf("ccdintr(%p, %p)\n", cs, bp);
8096f9db1eeShpeyerl #endif
8106f9db1eeShpeyerl 	/*
8116f9db1eeShpeyerl 	 * Request is done for better or worse, wakeup the top half.
8126f9db1eeShpeyerl 	 */
8136f9db1eeShpeyerl 	if (bp->b_flags & B_ERROR)
8146f9db1eeShpeyerl 		bp->b_resid = bp->b_bcount;
8155b39541eSthorpej 	disk_unbusy(&cs->sc_dkdev, (bp->b_bcount - bp->b_resid));
8166f9db1eeShpeyerl 	biodone(bp);
8176f9db1eeShpeyerl }
8186f9db1eeShpeyerl 
8196f9db1eeShpeyerl /*
82077d85de2Sthorpej  * Called at interrupt time.
8216f9db1eeShpeyerl  * Mark the component as done and if all components are done,
8226f9db1eeShpeyerl  * take a ccd interrupt.
8236f9db1eeShpeyerl  */
8243214723fShpeyerl void
825d318abdbSchristos ccdiodone(vbp)
826d318abdbSchristos 	struct buf *vbp;
8276f9db1eeShpeyerl {
828d318abdbSchristos 	struct ccdbuf *cbp = (struct ccdbuf *) vbp;
829*c6aa25bfSthorpej 	struct buf *bp = cbp->cb_obp;
830*c6aa25bfSthorpej 	struct ccd_softc *cs = cbp->cb_sc;
83100172c10Sthorpej 	int count, s;
8326f9db1eeShpeyerl 
8336f9db1eeShpeyerl 	s = splbio();
8346f9db1eeShpeyerl #ifdef DEBUG
8353214723fShpeyerl 	if (ccddebug & CCDB_FOLLOW)
83686373f8cSchristos 		printf("ccdiodone(%p)\n", cbp);
8373214723fShpeyerl 	if (ccddebug & CCDB_IO) {
83886373f8cSchristos 		printf("ccdiodone: bp %p bcount %ld resid %ld\n",
8396f9db1eeShpeyerl 		       bp, bp->b_bcount, bp->b_resid);
840c27c2868Sfair 		printf(" dev 0x%x(u%d), cbp %p bn %d addr %p bcnt %ld\n",
841f694af67Scgd 		       cbp->cb_buf.b_dev, cbp->cb_comp, cbp,
842f694af67Scgd 		       cbp->cb_buf.b_blkno, cbp->cb_buf.b_data,
843f694af67Scgd 		       cbp->cb_buf.b_bcount);
8446f9db1eeShpeyerl 	}
8456f9db1eeShpeyerl #endif
8466f9db1eeShpeyerl 
847f694af67Scgd 	if (cbp->cb_buf.b_flags & B_ERROR) {
8486f9db1eeShpeyerl 		bp->b_flags |= B_ERROR;
849732dd94aSthorpej 		bp->b_error = cbp->cb_buf.b_error ?
850732dd94aSthorpej 		    cbp->cb_buf.b_error : EIO;
851732dd94aSthorpej 
85200172c10Sthorpej 		printf("%s: error %d on component %d\n",
85300172c10Sthorpej 		       cs->sc_xname, bp->b_error, cbp->cb_comp);
8546f9db1eeShpeyerl 	}
855f694af67Scgd 	count = cbp->cb_buf.b_bcount;
85643561361Sthorpej 	CCD_PUTBUF(cs, cbp);
8576f9db1eeShpeyerl 
8586f9db1eeShpeyerl 	/*
8596f9db1eeShpeyerl 	 * If all done, "interrupt".
8606f9db1eeShpeyerl 	 */
8616f9db1eeShpeyerl 	bp->b_resid -= count;
8626f9db1eeShpeyerl 	if (bp->b_resid < 0)
8636f9db1eeShpeyerl 		panic("ccdiodone: count");
8643214723fShpeyerl 	if (bp->b_resid == 0)
865*c6aa25bfSthorpej 		ccdintr(cs, bp);
8666f9db1eeShpeyerl 	splx(s);
8676f9db1eeShpeyerl }
8686f9db1eeShpeyerl 
86977d85de2Sthorpej /* ARGSUSED */
8707263209cSmycroft int
87177d85de2Sthorpej ccdread(dev, uio, flags)
8723214723fShpeyerl 	dev_t dev;
8733214723fShpeyerl 	struct uio *uio;
87477d85de2Sthorpej 	int flags;
8753214723fShpeyerl {
87677d85de2Sthorpej 	int unit = ccdunit(dev);
87777d85de2Sthorpej 	struct ccd_softc *cs;
8783214723fShpeyerl 
8793214723fShpeyerl #ifdef DEBUG
8803214723fShpeyerl 	if (ccddebug & CCDB_FOLLOW)
881c27c2868Sfair 		printf("ccdread(0x%x, %p)\n", dev, uio);
8823214723fShpeyerl #endif
88377d85de2Sthorpej 	if (unit >= numccd)
88477d85de2Sthorpej 		return (ENXIO);
88577d85de2Sthorpej 	cs = &ccd_softc[unit];
88677d85de2Sthorpej 
88777d85de2Sthorpej 	if ((cs->sc_flags & CCDF_INITED) == 0)
88877d85de2Sthorpej 		return (ENXIO);
88977d85de2Sthorpej 
89077d85de2Sthorpej 	/*
89177d85de2Sthorpej 	 * XXX: It's not clear that using minphys() is completely safe,
89277d85de2Sthorpej 	 * in particular, for raw I/O.  Underlying devices might have some
89377d85de2Sthorpej 	 * non-obvious limits, because of the copy to user-space.
89477d85de2Sthorpej 	 */
8953214723fShpeyerl 	return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio));
8963214723fShpeyerl }
8973214723fShpeyerl 
89877d85de2Sthorpej /* ARGSUSED */
8997263209cSmycroft int
90077d85de2Sthorpej ccdwrite(dev, uio, flags)
9013214723fShpeyerl 	dev_t dev;
9023214723fShpeyerl 	struct uio *uio;
90377d85de2Sthorpej 	int flags;
9043214723fShpeyerl {
90577d85de2Sthorpej 	int unit = ccdunit(dev);
90677d85de2Sthorpej 	struct ccd_softc *cs;
9073214723fShpeyerl 
9083214723fShpeyerl #ifdef DEBUG
9093214723fShpeyerl 	if (ccddebug & CCDB_FOLLOW)
910c27c2868Sfair 		printf("ccdwrite(0x%x, %p)\n", dev, uio);
9113214723fShpeyerl #endif
91277d85de2Sthorpej 	if (unit >= numccd)
91377d85de2Sthorpej 		return (ENXIO);
91477d85de2Sthorpej 	cs = &ccd_softc[unit];
91577d85de2Sthorpej 
91677d85de2Sthorpej 	if ((cs->sc_flags & CCDF_INITED) == 0)
91777d85de2Sthorpej 		return (ENXIO);
91877d85de2Sthorpej 
91977d85de2Sthorpej 	/*
92077d85de2Sthorpej 	 * XXX: It's not clear that using minphys() is completely safe,
92177d85de2Sthorpej 	 * in particular, for raw I/O.  Underlying devices might have some
92277d85de2Sthorpej 	 * non-obvious limits, because of the copy to user-space.
92377d85de2Sthorpej 	 */
9243214723fShpeyerl 	return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio));
9253214723fShpeyerl }
9263214723fShpeyerl 
92777d85de2Sthorpej int
92877d85de2Sthorpej ccdioctl(dev, cmd, data, flag, p)
9296f9db1eeShpeyerl 	dev_t dev;
9306ac2bbfcScgd 	u_long cmd;
9316f9db1eeShpeyerl 	caddr_t data;
9326f9db1eeShpeyerl 	int flag;
93377d85de2Sthorpej 	struct proc *p;
9346f9db1eeShpeyerl {
93577d85de2Sthorpej 	int unit = ccdunit(dev);
9360272b2abSthorpej 	int i, j, lookedup = 0, error;
9378f8b0d91Smycroft 	int part, pmask;
93877d85de2Sthorpej 	struct ccd_softc *cs;
93977d85de2Sthorpej 	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data;
94077d85de2Sthorpej 	char **cpp;
94177d85de2Sthorpej 	struct vnode **vpp;
94277d85de2Sthorpej 
94377d85de2Sthorpej 	if (unit >= numccd)
94477d85de2Sthorpej 		return (ENXIO);
94577d85de2Sthorpej 	cs = &ccd_softc[unit];
94677d85de2Sthorpej 
9474cea35ebSthorpej 	/* Must be open for writes for these commands... */
9484cea35ebSthorpej 	switch (cmd) {
9494cea35ebSthorpej 	case CCDIOCSET:
9504cea35ebSthorpej 	case CCDIOCCLR:
9514cea35ebSthorpej 	case DIOCSDINFO:
9524cea35ebSthorpej 	case DIOCWDINFO:
9534cea35ebSthorpej 	case DIOCWLABEL:
9544cea35ebSthorpej 		if ((flag & FWRITE) == 0)
9554cea35ebSthorpej 			return (EBADF);
9564cea35ebSthorpej 	}
9574cea35ebSthorpej 
9580272b2abSthorpej 	if ((error = lockmgr(&cs->sc_lock, LK_EXCLUSIVE, NULL)) != 0)
9590272b2abSthorpej 		return (error);
9600272b2abSthorpej 
9614cea35ebSthorpej 	/* Must be initialized for these... */
9624cea35ebSthorpej 	switch (cmd) {
9634cea35ebSthorpej 	case CCDIOCCLR:
964d72a3b2dSkleink 	case DIOCGDINFO:
9654cea35ebSthorpej 	case DIOCSDINFO:
9664cea35ebSthorpej 	case DIOCWDINFO:
9674cea35ebSthorpej 	case DIOCGPART:
9684cea35ebSthorpej 	case DIOCWLABEL:
969939e074dSthorpej 	case DIOCGDEFLABEL:
9700272b2abSthorpej 		if ((cs->sc_flags & CCDF_INITED) == 0) {
9710272b2abSthorpej 			error = ENXIO;
9720272b2abSthorpej 			goto out;
9730272b2abSthorpej 		}
9744cea35ebSthorpej 	}
9754cea35ebSthorpej 
97677d85de2Sthorpej 	switch (cmd) {
97777d85de2Sthorpej 	case CCDIOCSET:
9780272b2abSthorpej 		if (cs->sc_flags & CCDF_INITED) {
9790272b2abSthorpej 			error = EBUSY;
9800272b2abSthorpej 			goto out;
9810272b2abSthorpej 		}
982b8dcfbd3Sthorpej 
983ab27c3f8Sthorpej 		/* Validate the flags. */
9840272b2abSthorpej 		if ((ccio->ccio_flags & CCDF_USERMASK) != ccio->ccio_flags) {
9850272b2abSthorpej 			error = EINVAL;
9860272b2abSthorpej 			goto out;
9870272b2abSthorpej 		}
988ab27c3f8Sthorpej 
98977d85de2Sthorpej 		/* Fill in some important bits. */
9900272b2abSthorpej 		cs->sc_ileave = ccio->ccio_ileave;
9910272b2abSthorpej 		cs->sc_nccdisks = ccio->ccio_ndisks;
9920272b2abSthorpej 		cs->sc_flags = ccio->ccio_flags & CCDF_USERMASK;
99377d85de2Sthorpej 
99477d85de2Sthorpej 		/*
99577d85de2Sthorpej 		 * Allocate space for and copy in the array of
99677d85de2Sthorpej 		 * componet pathnames and device numbers.
99777d85de2Sthorpej 		 */
99877d85de2Sthorpej 		cpp = malloc(ccio->ccio_ndisks * sizeof(char *),
99977d85de2Sthorpej 		    M_DEVBUF, M_WAITOK);
100077d85de2Sthorpej 		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *),
100177d85de2Sthorpej 		    M_DEVBUF, M_WAITOK);
100277d85de2Sthorpej 
100377d85de2Sthorpej 		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp,
100477d85de2Sthorpej 		    ccio->ccio_ndisks * sizeof(char **));
100577d85de2Sthorpej 		if (error) {
100677d85de2Sthorpej 			free(vpp, M_DEVBUF);
100777d85de2Sthorpej 			free(cpp, M_DEVBUF);
10080272b2abSthorpej 			goto out;
10096f9db1eeShpeyerl 		}
10106f9db1eeShpeyerl 
101177d85de2Sthorpej #ifdef DEBUG
101277d85de2Sthorpej 		if (ccddebug & CCDB_INIT)
101377d85de2Sthorpej 			for (i = 0; i < ccio->ccio_ndisks; ++i)
101486373f8cSchristos 				printf("ccdioctl: component %d: 0x%p\n",
101577d85de2Sthorpej 				    i, cpp[i]);
101677d85de2Sthorpej #endif
101777d85de2Sthorpej 
101877d85de2Sthorpej 		for (i = 0; i < ccio->ccio_ndisks; ++i) {
101977d85de2Sthorpej #ifdef DEBUG
102077d85de2Sthorpej 			if (ccddebug & CCDB_INIT)
102186373f8cSchristos 				printf("ccdioctl: lookedup = %d\n", lookedup);
102277d85de2Sthorpej #endif
1023d318abdbSchristos 			if ((error = ccdlookup(cpp[i], p, &vpp[i])) != 0) {
102477d85de2Sthorpej 				for (j = 0; j < lookedup; ++j)
1025a2db2c18Sthorpej 					(void)vn_close(vpp[j], FREAD|FWRITE,
102677d85de2Sthorpej 					    p->p_ucred, p);
102777d85de2Sthorpej 				free(vpp, M_DEVBUF);
102877d85de2Sthorpej 				free(cpp, M_DEVBUF);
10290272b2abSthorpej 				goto out;
103077d85de2Sthorpej 			}
103177d85de2Sthorpej 			++lookedup;
103277d85de2Sthorpej 		}
103377d85de2Sthorpej 
103477d85de2Sthorpej 		/*
103577d85de2Sthorpej 		 * Initialize the ccd.  Fills in the softc for us.
103677d85de2Sthorpej 		 */
10370272b2abSthorpej 		if ((error = ccdinit(cs, cpp, vpp, p)) != 0) {
103877d85de2Sthorpej 			for (j = 0; j < lookedup; ++j)
1039a1bc3740Sthorpej 				(void)vn_close(vpp[j], FREAD|FWRITE,
104077d85de2Sthorpej 				    p->p_ucred, p);
104177d85de2Sthorpej 			free(vpp, M_DEVBUF);
104277d85de2Sthorpej 			free(cpp, M_DEVBUF);
10430272b2abSthorpej 			goto out;
104477d85de2Sthorpej 		}
104577d85de2Sthorpej 
10460272b2abSthorpej 		/* We can free the temporary variables now. */
10470272b2abSthorpej 		free(vpp, M_DEVBUF);
10480272b2abSthorpej 		free(cpp, M_DEVBUF);
10490272b2abSthorpej 
105077d85de2Sthorpej 		/*
105177d85de2Sthorpej 		 * The ccd has been successfully initialized, so
10525b39541eSthorpej 		 * we can place it into the array.  Don't try to
10535b39541eSthorpej 		 * read the disklabel until the disk has been attached,
10545b39541eSthorpej 		 * because space for the disklabel is allocated
10555b39541eSthorpej 		 * in disk_attach();
105677d85de2Sthorpej 		 */
105777d85de2Sthorpej 		ccio->ccio_unit = unit;
105877d85de2Sthorpej 		ccio->ccio_size = cs->sc_size;
10595b39541eSthorpej 
10605b39541eSthorpej 		/* Attach the disk. */
10615b39541eSthorpej 		disk_attach(&cs->sc_dkdev);
10625b39541eSthorpej 
106343561361Sthorpej 		/* Initialize the component buffer pool. */
106443561361Sthorpej 		pool_init(&cs->sc_cbufpool, sizeof(struct ccdbuf), 0,
106543561361Sthorpej 		    0, 0, "ccdpl", 0, NULL, NULL, M_DEVBUF);
106643561361Sthorpej 
10675b39541eSthorpej 		/* Try and read the disklabel. */
106877d85de2Sthorpej 		ccdgetdisklabel(dev);
106977d85de2Sthorpej 		break;
107077d85de2Sthorpej 
107177d85de2Sthorpej 	case CCDIOCCLR:
107277d85de2Sthorpej 		/*
107377d85de2Sthorpej 		 * Don't unconfigure if any other partitions are open
107477d85de2Sthorpej 		 * or if both the character and block flavors of this
107577d85de2Sthorpej 		 * partition are open.
107677d85de2Sthorpej 		 */
107777d85de2Sthorpej 		part = DISKPART(dev);
107877d85de2Sthorpej 		pmask = (1 << part);
107977d85de2Sthorpej 		if ((cs->sc_dkdev.dk_openmask & ~pmask) ||
108077d85de2Sthorpej 		    ((cs->sc_dkdev.dk_bopenmask & pmask) &&
1081b8dcfbd3Sthorpej 		    (cs->sc_dkdev.dk_copenmask & pmask))) {
10820272b2abSthorpej 			error = EBUSY;
10830272b2abSthorpej 			goto out;
1084b8dcfbd3Sthorpej 		}
108577d85de2Sthorpej 
108677d85de2Sthorpej 		/*
108777d85de2Sthorpej 		 * Free ccd_softc information and clear entry.
108877d85de2Sthorpej 		 */
10897268bf55Sthorpej 
10907268bf55Sthorpej 		/* Close the components and free their pathnames. */
109177d85de2Sthorpej 		for (i = 0; i < cs->sc_nccdisks; ++i) {
109277d85de2Sthorpej 			/*
109377d85de2Sthorpej 			 * XXX: this close could potentially fail and
109477d85de2Sthorpej 			 * cause Bad Things.  Maybe we need to force
109577d85de2Sthorpej 			 * the close to happen?
109677d85de2Sthorpej 			 */
109777d85de2Sthorpej #ifdef DEBUG
109877d85de2Sthorpej 			if (ccddebug & CCDB_VNODE)
109977d85de2Sthorpej 				vprint("CCDIOCCLR: vnode info",
110077d85de2Sthorpej 				    cs->sc_cinfo[i].ci_vp);
110177d85de2Sthorpej #endif
110277d85de2Sthorpej 			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE,
110377d85de2Sthorpej 			    p->p_ucred, p);
110477d85de2Sthorpej 			free(cs->sc_cinfo[i].ci_path, M_DEVBUF);
110577d85de2Sthorpej 		}
11067268bf55Sthorpej 
11077268bf55Sthorpej 		/* Free interleave index. */
11087268bf55Sthorpej 		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i)
11097268bf55Sthorpej 			free(cs->sc_itable[i].ii_index, M_DEVBUF);
11107268bf55Sthorpej 
11117268bf55Sthorpej 		/* Free component info and interleave table. */
111277d85de2Sthorpej 		free(cs->sc_cinfo, M_DEVBUF);
111377d85de2Sthorpej 		free(cs->sc_itable, M_DEVBUF);
1114664cb046Sthorpej 		cs->sc_flags &= ~CCDF_INITED;
111577d85de2Sthorpej 
111643561361Sthorpej 		/* Free the component buffer pool. */
111743561361Sthorpej 		pool_destroy(&cs->sc_cbufpool);
111843561361Sthorpej 
11195b39541eSthorpej 		/* Detatch the disk. */
1120fb815819Shpeyerl 		disk_detach(&cs->sc_dkdev);
112177d85de2Sthorpej 		break;
112277d85de2Sthorpej 
112377d85de2Sthorpej 	case DIOCGDINFO:
11245b39541eSthorpej 		*(struct disklabel *)data = *(cs->sc_dkdev.dk_label);
112577d85de2Sthorpej 		break;
112677d85de2Sthorpej 
112777d85de2Sthorpej 	case DIOCGPART:
11285b39541eSthorpej 		((struct partinfo *)data)->disklab = cs->sc_dkdev.dk_label;
112977d85de2Sthorpej 		((struct partinfo *)data)->part =
11305b39541eSthorpej 		    &cs->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
113177d85de2Sthorpej 		break;
113277d85de2Sthorpej 
113377d85de2Sthorpej 	case DIOCWDINFO:
113477d85de2Sthorpej 	case DIOCSDINFO:
113577d85de2Sthorpej 		cs->sc_flags |= CCDF_LABELLING;
113677d85de2Sthorpej 
11375b39541eSthorpej 		error = setdisklabel(cs->sc_dkdev.dk_label,
11385b39541eSthorpej 		    (struct disklabel *)data, 0, cs->sc_dkdev.dk_cpulabel);
113977d85de2Sthorpej 		if (error == 0) {
114077d85de2Sthorpej 			if (cmd == DIOCWDINFO)
114177d85de2Sthorpej 				error = writedisklabel(CCDLABELDEV(dev),
11425b39541eSthorpej 				    ccdstrategy, cs->sc_dkdev.dk_label,
11435b39541eSthorpej 				    cs->sc_dkdev.dk_cpulabel);
114477d85de2Sthorpej 		}
114577d85de2Sthorpej 
114677d85de2Sthorpej 		cs->sc_flags &= ~CCDF_LABELLING;
114777d85de2Sthorpej 		break;
114877d85de2Sthorpej 
114977d85de2Sthorpej 	case DIOCWLABEL:
115077d85de2Sthorpej 		if (*(int *)data != 0)
115177d85de2Sthorpej 			cs->sc_flags |= CCDF_WLABEL;
115277d85de2Sthorpej 		else
115377d85de2Sthorpej 			cs->sc_flags &= ~CCDF_WLABEL;
115477d85de2Sthorpej 		break;
115577d85de2Sthorpej 
1156939e074dSthorpej 	case DIOCGDEFLABEL:
1157939e074dSthorpej 		ccdgetdefaultlabel(cs, (struct disklabel *)data);
1158939e074dSthorpej 		break;
1159939e074dSthorpej 
116077d85de2Sthorpej 	default:
11610272b2abSthorpej 		error = ENOTTY;
116277d85de2Sthorpej 	}
116377d85de2Sthorpej 
11640272b2abSthorpej  out:
11650272b2abSthorpej 	(void) lockmgr(&cs->sc_lock, LK_RELEASE, NULL);
11660272b2abSthorpej 	return (error);
116777d85de2Sthorpej }
116877d85de2Sthorpej 
116977d85de2Sthorpej int
11706f9db1eeShpeyerl ccdsize(dev)
11716f9db1eeShpeyerl 	dev_t dev;
11726f9db1eeShpeyerl {
117377d85de2Sthorpej 	struct ccd_softc *cs;
1174e06bb29bSthorpej 	struct disklabel *lp;
1175e06bb29bSthorpej 	int part, unit, omask, size;
11766f9db1eeShpeyerl 
1177e06bb29bSthorpej 	unit = ccdunit(dev);
1178e06bb29bSthorpej 	if (unit >= numccd)
11796f9db1eeShpeyerl 		return (-1);
1180e06bb29bSthorpej 	cs = &ccd_softc[unit];
118177d85de2Sthorpej 
118277d85de2Sthorpej 	if ((cs->sc_flags & CCDF_INITED) == 0)
118377d85de2Sthorpej 		return (-1);
118477d85de2Sthorpej 
1185e06bb29bSthorpej 	part = DISKPART(dev);
1186e06bb29bSthorpej 	omask = cs->sc_dkdev.dk_openmask & (1 << part);
1187e06bb29bSthorpej 	lp = cs->sc_dkdev.dk_label;
1188e06bb29bSthorpej 
1189e06bb29bSthorpej 	if (omask == 0 && ccdopen(dev, 0, S_IFBLK, curproc))
1190e06bb29bSthorpej 		return (-1);
1191e06bb29bSthorpej 
1192e06bb29bSthorpej 	if (lp->d_partitions[part].p_fstype != FS_SWAP)
119377d85de2Sthorpej 		size = -1;
119477d85de2Sthorpej 	else
1195e06bb29bSthorpej 		size = lp->d_partitions[part].p_size *
1196e06bb29bSthorpej 		    (lp->d_secsize / DEV_BSIZE);
119777d85de2Sthorpej 
1198e06bb29bSthorpej 	if (omask == 0 && ccdclose(dev, 0, S_IFBLK, curproc))
119977d85de2Sthorpej 		return (-1);
120077d85de2Sthorpej 
120177d85de2Sthorpej 	return (size);
12026f9db1eeShpeyerl }
12036f9db1eeShpeyerl 
1204bc9de323Scgd int
1205bc9de323Scgd ccddump(dev, blkno, va, size)
1206bc9de323Scgd 	dev_t dev;
1207bc9de323Scgd 	daddr_t blkno;
1208bc9de323Scgd 	caddr_t va;
1209bc9de323Scgd 	size_t size;
12106f9db1eeShpeyerl {
1211bc9de323Scgd 
1212bc9de323Scgd 	/* Not implemented. */
1213bc9de323Scgd 	return ENXIO;
12146f9db1eeShpeyerl }
121577d85de2Sthorpej 
121677d85de2Sthorpej /*
121777d85de2Sthorpej  * Lookup the provided name in the filesystem.  If the file exists,
121877d85de2Sthorpej  * is a valid block device, and isn't being used by anyone else,
121977d85de2Sthorpej  * set *vpp to the file's vnode.
122077d85de2Sthorpej  */
122177d85de2Sthorpej static int
122277d85de2Sthorpej ccdlookup(path, p, vpp)
122377d85de2Sthorpej 	char *path;
122477d85de2Sthorpej 	struct proc *p;
122577d85de2Sthorpej 	struct vnode **vpp;	/* result */
122677d85de2Sthorpej {
122777d85de2Sthorpej 	struct nameidata nd;
122877d85de2Sthorpej 	struct vnode *vp;
122977d85de2Sthorpej 	struct vattr va;
123077d85de2Sthorpej 	int error;
123177d85de2Sthorpej 
123277d85de2Sthorpej 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p);
1233d318abdbSchristos 	if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
123477d85de2Sthorpej #ifdef DEBUG
1235d318abdbSchristos 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
123686373f8cSchristos 			printf("ccdlookup: vn_open error = %d\n", error);
123777d85de2Sthorpej #endif
123877d85de2Sthorpej 		return (error);
123977d85de2Sthorpej 	}
124077d85de2Sthorpej 	vp = nd.ni_vp;
124177d85de2Sthorpej 
124277d85de2Sthorpej 	if (vp->v_usecount > 1) {
1243331fee62Sross 		VOP_UNLOCK(vp, 0);
124477d85de2Sthorpej 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
124577d85de2Sthorpej 		return (EBUSY);
124677d85de2Sthorpej 	}
124777d85de2Sthorpej 
1248d318abdbSchristos 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) {
124977d85de2Sthorpej #ifdef DEBUG
1250d318abdbSchristos 		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT))
125186373f8cSchristos 			printf("ccdlookup: getattr error = %d\n", error);
125277d85de2Sthorpej #endif
1253331fee62Sross 		VOP_UNLOCK(vp, 0);
125477d85de2Sthorpej 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
125577d85de2Sthorpej 		return (error);
125677d85de2Sthorpej 	}
125777d85de2Sthorpej 
125877d85de2Sthorpej 	/* XXX: eventually we should handle VREG, too. */
125977d85de2Sthorpej 	if (va.va_type != VBLK) {
1260331fee62Sross 		VOP_UNLOCK(vp, 0);
126177d85de2Sthorpej 		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
126277d85de2Sthorpej 		return (ENOTBLK);
126377d85de2Sthorpej 	}
126477d85de2Sthorpej 
126577d85de2Sthorpej #ifdef DEBUG
126677d85de2Sthorpej 	if (ccddebug & CCDB_VNODE)
126777d85de2Sthorpej 		vprint("ccdlookup: vnode info", vp);
126877d85de2Sthorpej #endif
126977d85de2Sthorpej 
1270331fee62Sross 	VOP_UNLOCK(vp, 0);
127177d85de2Sthorpej 	*vpp = vp;
127277d85de2Sthorpej 	return (0);
127377d85de2Sthorpej }
127477d85de2Sthorpej 
127577d85de2Sthorpej static void
1276939e074dSthorpej ccdgetdefaultlabel(cs, lp)
1277939e074dSthorpej 	struct ccd_softc *cs;
1278939e074dSthorpej 	struct disklabel *lp;
127977d85de2Sthorpej {
128077d85de2Sthorpej 	struct ccdgeom *ccg = &cs->sc_geom;
128177d85de2Sthorpej 
128277d85de2Sthorpej 	bzero(lp, sizeof(*lp));
128377d85de2Sthorpej 
128477d85de2Sthorpej 	lp->d_secperunit = cs->sc_size;
128577d85de2Sthorpej 	lp->d_secsize = ccg->ccg_secsize;
128677d85de2Sthorpej 	lp->d_nsectors = ccg->ccg_nsectors;
128777d85de2Sthorpej 	lp->d_ntracks = ccg->ccg_ntracks;
128877d85de2Sthorpej 	lp->d_ncylinders = ccg->ccg_ncylinders;
128989d4987eSthorpej 	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
129077d85de2Sthorpej 
129177d85de2Sthorpej 	strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename));
129277d85de2Sthorpej 	lp->d_type = DTYPE_CCD;
129377d85de2Sthorpej 	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
129477d85de2Sthorpej 	lp->d_rpm = 3600;
129577d85de2Sthorpej 	lp->d_interleave = 1;
129677d85de2Sthorpej 	lp->d_flags = 0;
129777d85de2Sthorpej 
129877d85de2Sthorpej 	lp->d_partitions[RAW_PART].p_offset = 0;
129977d85de2Sthorpej 	lp->d_partitions[RAW_PART].p_size = cs->sc_size;
130077d85de2Sthorpej 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
130177d85de2Sthorpej 	lp->d_npartitions = RAW_PART + 1;
130277d85de2Sthorpej 
130377d85de2Sthorpej 	lp->d_magic = DISKMAGIC;
130477d85de2Sthorpej 	lp->d_magic2 = DISKMAGIC;
13055b39541eSthorpej 	lp->d_checksum = dkcksum(cs->sc_dkdev.dk_label);
1306939e074dSthorpej }
1307939e074dSthorpej 
1308939e074dSthorpej /*
1309939e074dSthorpej  * Read the disklabel from the ccd.  If one is not present, fake one
1310939e074dSthorpej  * up.
1311939e074dSthorpej  */
1312939e074dSthorpej static void
1313939e074dSthorpej ccdgetdisklabel(dev)
1314939e074dSthorpej 	dev_t dev;
1315939e074dSthorpej {
1316939e074dSthorpej 	int unit = ccdunit(dev);
1317939e074dSthorpej 	struct ccd_softc *cs = &ccd_softc[unit];
1318939e074dSthorpej 	char *errstring;
1319939e074dSthorpej 	struct disklabel *lp = cs->sc_dkdev.dk_label;
1320939e074dSthorpej 	struct cpu_disklabel *clp = cs->sc_dkdev.dk_cpulabel;
1321939e074dSthorpej 
1322939e074dSthorpej 	bzero(clp, sizeof(*clp));
1323939e074dSthorpej 
1324939e074dSthorpej 	ccdgetdefaultlabel(cs, lp);
132577d85de2Sthorpej 
132677d85de2Sthorpej 	/*
132777d85de2Sthorpej 	 * Call the generic disklabel extraction routine.
132877d85de2Sthorpej 	 */
1329d318abdbSchristos 	errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy,
1330d318abdbSchristos 	    cs->sc_dkdev.dk_label, cs->sc_dkdev.dk_cpulabel);
1331d318abdbSchristos 	if (errstring)
133277d85de2Sthorpej 		ccdmakedisklabel(cs);
1333512a0186Senami 	else {
1334512a0186Senami 		int i;
1335512a0186Senami 		struct partition *pp;
1336512a0186Senami 
1337512a0186Senami 		/*
1338512a0186Senami 		 * Sanity check whether the found disklabel is valid.
1339512a0186Senami 		 *
1340512a0186Senami 		 * This is necessary since total size of ccd may vary
1341512a0186Senami 		 * when an interleave is changed even though exactly
1342512a0186Senami 		 * same componets are used, and old disklabel may used
1343512a0186Senami 		 * if that is found.
1344512a0186Senami 		 */
1345512a0186Senami 		if (lp->d_secperunit != cs->sc_size)
1346512a0186Senami 			printf("WARNING: %s: "
1347512a0186Senami 			    "total sector size in disklabel (%d) != "
1348512a0186Senami 			    "the size of ccd (%d)\n", cs->sc_xname,
1349512a0186Senami 			    lp->d_secperunit, cs->sc_size);
1350512a0186Senami 		for (i = 0; i < lp->d_npartitions; i++) {
1351512a0186Senami 			pp = &lp->d_partitions[i];
1352512a0186Senami 			if (pp->p_offset + pp->p_size > cs->sc_size)
13539b770726Senami 				printf("WARNING: %s: end of partition `%c' "
13549b770726Senami 				    "exceeds the size of ccd (%d)\n",
13559b770726Senami 				    cs->sc_xname, 'a' + i, cs->sc_size);
1356512a0186Senami 		}
1357512a0186Senami 	}
135877d85de2Sthorpej 
135977d85de2Sthorpej #ifdef DEBUG
136077d85de2Sthorpej 	/* It's actually extremely common to have unlabeled ccds. */
136177d85de2Sthorpej 	if (ccddebug & CCDB_LABEL)
136277d85de2Sthorpej 		if (errstring != NULL)
136386373f8cSchristos 			printf("%s: %s\n", cs->sc_xname, errstring);
136477d85de2Sthorpej #endif
136577d85de2Sthorpej }
136677d85de2Sthorpej 
136777d85de2Sthorpej /*
136877d85de2Sthorpej  * Take care of things one might want to take care of in the event
136977d85de2Sthorpej  * that a disklabel isn't present.
137077d85de2Sthorpej  */
137177d85de2Sthorpej static void
137277d85de2Sthorpej ccdmakedisklabel(cs)
137377d85de2Sthorpej 	struct ccd_softc *cs;
137477d85de2Sthorpej {
13755b39541eSthorpej 	struct disklabel *lp = cs->sc_dkdev.dk_label;
137677d85de2Sthorpej 
137777d85de2Sthorpej 	/*
137877d85de2Sthorpej 	 * For historical reasons, if there's no disklabel present
137977d85de2Sthorpej 	 * the raw partition must be marked FS_BSDFFS.
138077d85de2Sthorpej 	 */
138177d85de2Sthorpej 	lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS;
138277d85de2Sthorpej 
138377d85de2Sthorpej 	strncpy(lp->d_packname, "default label", sizeof(lp->d_packname));
1384939e074dSthorpej 
1385939e074dSthorpej 	lp->d_checksum = dkcksum(lp);
138677d85de2Sthorpej }
138777d85de2Sthorpej 
138877d85de2Sthorpej #ifdef DEBUG
138977d85de2Sthorpej static void
139077d85de2Sthorpej printiinfo(ii)
139177d85de2Sthorpej 	struct ccdiinfo *ii;
139277d85de2Sthorpej {
139377d85de2Sthorpej 	register int ix, i;
139477d85de2Sthorpej 
139577d85de2Sthorpej 	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
139686373f8cSchristos 		printf(" itab[%d]: #dk %d sblk %d soff %d",
139777d85de2Sthorpej 		    ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
139877d85de2Sthorpej 		for (i = 0; i < ii->ii_ndisk; i++)
139986373f8cSchristos 			printf(" %d", ii->ii_index[i]);
140086373f8cSchristos 		printf("\n");
140177d85de2Sthorpej 	}
140277d85de2Sthorpej }
14036f9db1eeShpeyerl #endif
1404