diff options
Diffstat (limited to 'sys/dev/ccd/ccd.c')
| -rw-r--r-- | sys/dev/ccd/ccd.c | 1428 | 
1 files changed, 0 insertions, 1428 deletions
| diff --git a/sys/dev/ccd/ccd.c b/sys/dev/ccd/ccd.c deleted file mode 100644 index c8d33a4b867eb..0000000000000 --- a/sys/dev/ccd/ccd.c +++ /dev/null @@ -1,1428 +0,0 @@ -/*	$NetBSD: ccd.c,v 1.22 1995/12/08 19:13:26 thorpej Exp $	*/ - -/* - * Copyright (c) 1995 Jason R. Thorpe. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - *    notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - *    notice, this list of conditions and the following disclaimer in the - *    documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - *    must display the following acknowledgement: - *	This product includes software developed for the NetBSD Project - *	by Jason R. Thorpe. - * 4. The name of the author may not be used to endorse or promote products - *    derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 1988 University of Utah. - * Copyright (c) 1990, 1993 - *	The Regents of the University of California.  All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Systems Programming Group of the University of Utah Computer - * Science Department. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - *    notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - *    notice, this list of conditions and the following disclaimer in the - *    documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - *    must display the following acknowledgement: - *	This product includes software developed by the University of - *	California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - *    may be used to endorse or promote products derived from this software - *    without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * from: Utah $Hdr: cd.c 1.6 90/11/28$ - * - *	@(#)cd.c	8.2 (Berkeley) 11/16/93 - */ - -/* - * "Concatenated" disk driver. - * - * Dynamic configuration and disklabel support by: - *	Jason R. Thorpe <thorpej@nas.nasa.gov> - *	Numerical Aerodynamic Simulation Facility - *	Mail Stop 258-6 - *	NASA Ames Research Center - *	Moffett Field, CA 94035 - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/errno.h> -#include <sys/dkstat.h> -#include <sys/buf.h> -#include <sys/malloc.h> -#include <sys/namei.h> -#include <sys/conf.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/disklabel.h> -#include <sys/device.h> -#include <sys/disk.h> -#include <sys/syslog.h> -#include <sys/fcntl.h> -#include <sys/vnode.h> - -#include <dev/ccdvar.h> - -#if defined(CCDDEBUG) && !defined(DEBUG) -#define DEBUG -#endif - -#ifdef DEBUG -int ccddebug = 0x00; -#define CCDB_FOLLOW	0x01 -#define CCDB_INIT	0x02 -#define CCDB_IO		0x04 -#define CCDB_LABEL	0x08 -#define CCDB_VNODE	0x10 -#endif - -#define	ccdunit(x)	DISKUNIT(x) - -struct ccdbuf { -	struct buf	cb_buf;		/* new I/O buf */ -	struct buf	*cb_obp;	/* ptr. to original I/O buf */ -	int		cb_unit;	/* target unit */ -	int		cb_comp;	/* target component */ -}; - -#define	getccdbuf()		\ -	((struct ccdbuf *)malloc(sizeof(struct ccdbuf), M_DEVBUF, M_WAITOK)) -#define putccdbuf(cbp)		\ -	free((caddr_t)(cbp), M_DEVBUF) - -#define CCDLABELDEV(dev)	\ -	(MAKEDISKDEV(major((dev)), ccdunit((dev)), RAW_PART)) - -/* {b,c}devsw[] function prototypes */ -dev_type_open(ccdopen); -dev_type_close(ccdclose); -dev_type_strategy(ccdstrategy); -dev_type_ioctl(ccdioctl); -dev_type_read(ccdread); -dev_type_write(ccdwrite); - -/* called by main() at boot time */ -void	ccdattach __P((int)); - -/* called by biodone() at interrupt time */ -void	ccdiodone __P((struct ccdbuf *cbp)); - -static	void ccdstart __P((struct ccd_softc *, struct buf *)); -static	void ccdinterleave __P((struct ccd_softc *, int)); -static	void ccdintr __P((struct ccd_softc *, struct buf *)); -static	int ccdinit __P((struct ccddevice *, char **, struct proc *)); -static	int ccdlookup __P((char *, struct proc *p, struct vnode **)); -static	struct ccdbuf *ccdbuffer __P((struct ccd_softc *, struct buf *, -		daddr_t, caddr_t, long)); -static	void ccdgetdisklabel __P((dev_t)); -static	void ccdmakedisklabel __P((struct ccd_softc *)); -static	int ccdlock __P((struct ccd_softc *)); -static	void ccdunlock __P((struct ccd_softc *)); - -#ifdef DEBUG -static	void printiinfo __P((struct ccdiinfo *)); -#endif - -/* Non-private for the benefit of libkvm. */ -struct	ccd_softc *ccd_softc; -struct	ccddevice *ccddevs; -int	numccd = 0; - -/* - * Called by main() during pseudo-device attachment.  All we need - * to do is allocate enough space for devices to be configured later. - */ -void -ccdattach(num) -	int num; -{ -	int i; - -	if (num <= 0) { -#ifdef DIAGNOSTIC -		panic("ccdattach: count <= 0"); -#endif -		return; -	} - -	ccd_softc = (struct ccd_softc *)malloc(num * sizeof(struct ccd_softc), -	    M_DEVBUF, M_NOWAIT); -	ccddevs = (struct ccddevice *)malloc(num * sizeof(struct ccddevice), -	    M_DEVBUF, M_NOWAIT); -	if ((ccd_softc == NULL) || (ccddevs == NULL)) { -		printf("WARNING: no memory for concatenated disks\n"); -		if (ccd_softc != NULL) -			free(ccd_softc, M_DEVBUF); -		if (ccddevs != NULL) -			free(ccddevs, M_DEVBUF); -		return; -	} -	numccd = num; -	bzero(ccd_softc, num * sizeof(struct ccd_softc)); -	bzero(ccddevs, num * sizeof(struct ccddevice)); - -	/* XXX: is this necessary? */ -	for (i = 0; i < numccd; ++i) -		ccddevs[i].ccd_dk = -1; -} - -static int -ccdinit(ccd, cpaths, p) -	struct ccddevice *ccd; -	char **cpaths; -	struct proc *p; -{ -	register struct ccd_softc *cs = &ccd_softc[ccd->ccd_unit]; -	register struct ccdcinfo *ci; -	register size_t size; -	register int ix; -	struct vnode *vp; -	struct vattr va; -	size_t minsize; -	int maxsecsize; -	struct partinfo dpart; -	struct ccdgeom *ccg = &cs->sc_geom; -	char tmppath[MAXPATHLEN]; -	int error; - -#ifdef DEBUG -	if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) -		printf("ccdinit: unit %d\n", ccd->ccd_unit); -#endif - -#ifdef WORKING_DISK_STATISTICS		/* XXX !! */ -	cs->sc_dk = ccd->ccd_dk; -#endif -	cs->sc_size = 0; -	cs->sc_ileave = ccd->ccd_interleave; -	cs->sc_nccdisks = ccd->ccd_ndev; - -	/* Allocate space for the component info. */ -	cs->sc_cinfo = malloc(cs->sc_nccdisks * sizeof(struct ccdcinfo), -	    M_DEVBUF, M_WAITOK); - -	/* -	 * Verify that each component piece exists and record -	 * relevant information about it. -	 */ -	maxsecsize = 0; -	minsize = 0; -	for (ix = 0; ix < cs->sc_nccdisks; ix++) { -		vp = ccd->ccd_vpp[ix]; -		ci = &cs->sc_cinfo[ix]; -		ci->ci_vp = vp; - -		/* -		 * Copy in the pathname of the component. -		 */ -		bzero(tmppath, sizeof(tmppath));	/* sanity */ -		if (error = copyinstr(cpaths[ix], tmppath, -		    MAXPATHLEN, &ci->ci_pathlen)) { -#ifdef DEBUG -			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) -				printf("ccd%d: can't copy path, error = %d\n", -				    ccd->ccd_unit, error); -#endif -			free(cs->sc_cinfo, M_DEVBUF); -			return (error); -		} -		ci->ci_path = malloc(ci->ci_pathlen, M_DEVBUF, M_WAITOK); -		bcopy(tmppath, ci->ci_path, ci->ci_pathlen); - -		/* -		 * XXX: Cache the component's dev_t. -		 */ -		if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) { -#ifdef DEBUG -			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) -				printf("ccd%d: %s: getattr failed %s = %d\n", -				    ccd->ccd_unit, ci->ci_path, -				    "error", error); -#endif -			free(ci->ci_path, M_DEVBUF); -			free(cs->sc_cinfo, M_DEVBUF); -			return (error); -		} -		ci->ci_dev = va.va_rdev; - -		/* -		 * Get partition information for the component. -		 */ -		if (error = VOP_IOCTL(vp, DIOCGPART, (caddr_t)&dpart, -		    FREAD, p->p_ucred, p)) { -#ifdef DEBUG -			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) -				 printf("ccd%d: %s: ioctl failed, error = %d\n", -				     ccd->ccd_unit, ci->ci_path, error); -#endif -			free(ci->ci_path, M_DEVBUF); -			free(cs->sc_cinfo, M_DEVBUF); -			return (error); -		} -		if (dpart.part->p_fstype == FS_BSDFFS) { -			maxsecsize = -			    ((dpart.disklab->d_secsize > maxsecsize) ? -			    dpart.disklab->d_secsize : maxsecsize); -			size = dpart.part->p_size; -		} else { -#ifdef DEBUG -			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) -				printf("ccd%d: %s: incorrect partition type\n", -				    ccd->ccd_unit, ci->ci_path); -#endif -			free(ci->ci_path, M_DEVBUF); -			free(cs->sc_cinfo, M_DEVBUF); -			return (EFTYPE); -		} - -		/* -		 * Calculate the size, truncating to an interleave -		 * boundary if necessary. -		 */ -		if (size < 0) -			size = 0; - -		if (cs->sc_ileave > 1) -			size -= size % cs->sc_ileave; - -		if (size == 0) { -#ifdef DEBUG -			if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) -				printf("ccd%d: %s: size == 0\n", -				    ccd->ccd_unit, ci->ci_path); -#endif -			free(ci->ci_path, M_DEVBUF); -			free(cs->sc_cinfo, M_DEVBUF); -			return (ENODEV); -		} - -		if (minsize == 0 || size < minsize) -			minsize = size; -		ci->ci_size = size; -		cs->sc_size += size; -	} - -	/* -	 * Don't allow the interleave to be smaller than -	 * the biggest component sector. -	 */ -	if ((cs->sc_ileave > 0) && -	    (cs->sc_ileave < (maxsecsize / DEV_BSIZE))) { -#ifdef DEBUG -		if (ccddebug & (CCDB_FOLLOW|CCDB_INIT)) -			printf("ccd%d: interleave must be at least %d\n", -			    ccd->ccd_unit, (maxsecsize / DEV_BSIZE)); -#endif -		free(ci->ci_path, M_DEVBUF); -		free(cs->sc_cinfo, M_DEVBUF); -		return (EINVAL); -	} - -	/* -	 * If uniform interleave is desired set all sizes to that of -	 * the smallest component. -	 */ -	if (ccd->ccd_flags & CCDF_UNIFORM) { -		for (ci = cs->sc_cinfo; -		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) -			ci->ci_size = minsize; -		cs->sc_size = cs->sc_nccdisks * minsize; -	} - -	/* -	 * Construct the interleave table. -	 */ -	ccdinterleave(cs, ccd->ccd_unit); - -	/* -	 * Create pseudo-geometry based on 1MB cylinders.  It's -	 * pretty close. -	 */ -	ccg->ccg_secsize = DEV_BSIZE; -	ccg->ccg_ntracks = 1; -	ccg->ccg_nsectors = 1024 * (1024 / ccg->ccg_secsize); -	ccg->ccg_ncylinders = cs->sc_size / ccg->ccg_nsectors; - -#ifdef WORKING_DISK_STATISTICS		/* XXX !! */ -	if (ccd->ccd_dk >= 0) -		dk_wpms[ccd->ccd_dk] = 32 * (60 * DEV_BSIZE / 2);     /* XXX */ -#endif - -	cs->sc_flags |= CCDF_INITED; -	cs->sc_cflags = ccd->ccd_flags;	/* So we can find out later... */ -	cs->sc_unit = ccd->ccd_unit; -	return (0); -} - -static void -ccdinterleave(cs, unit) -	register struct ccd_softc *cs; -	int unit; -{ -	register struct ccdcinfo *ci, *smallci; -	register struct ccdiinfo *ii; -	register daddr_t bn, lbn; -	register int ix; -	u_long size; - -#ifdef DEBUG -	if (ccddebug & CCDB_INIT) -		printf("ccdinterleave(%x): ileave %d\n", cs, cs->sc_ileave); -#endif -	/* -	 * Allocate an interleave table. -	 * Chances are this is too big, but we don't care. -	 */ -	size = (cs->sc_nccdisks + 1) * sizeof(struct ccdiinfo); -	cs->sc_itable = (struct ccdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); -	bzero((caddr_t)cs->sc_itable, size); - -	/* -	 * Trivial case: no interleave (actually interleave of disk size). -	 * Each table entry represents a single component in its entirety. -	 */ -	if (cs->sc_ileave == 0) { -		bn = 0; -		ii = cs->sc_itable; - -		for (ix = 0; ix < cs->sc_nccdisks; ix++) { -			/* Allocate space for ii_index. */ -			ii->ii_index = malloc(sizeof(int), M_DEVBUF, M_WAITOK); -			ii->ii_ndisk = 1; -			ii->ii_startblk = bn; -			ii->ii_startoff = 0; -			ii->ii_index[0] = ix; -			bn += cs->sc_cinfo[ix].ci_size; -			ii++; -		} -		ii->ii_ndisk = 0; -#ifdef DEBUG -		if (ccddebug & CCDB_INIT) -			printiinfo(cs->sc_itable); -#endif -		return; -	} - -	/* -	 * The following isn't fast or pretty; it doesn't have to be. -	 */ -	size = 0; -	bn = lbn = 0; -	for (ii = cs->sc_itable; ; ii++) { -		/* Allocate space for ii_index. */ -		ii->ii_index = malloc((sizeof(int) * cs->sc_nccdisks), -		    M_DEVBUF, M_WAITOK); - -		/* -		 * Locate the smallest of the remaining components -		 */ -		smallci = NULL; -		for (ci = cs->sc_cinfo; -		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) -			if (ci->ci_size > size && -			    (smallci == NULL || -			     ci->ci_size < smallci->ci_size)) -				smallci = ci; - -		/* -		 * Nobody left, all done -		 */ -		if (smallci == NULL) { -			ii->ii_ndisk = 0; -			break; -		} - -		/* -		 * Record starting logical block and component offset -		 */ -		ii->ii_startblk = bn / cs->sc_ileave; -		ii->ii_startoff = lbn; - -		/* -		 * Determine how many disks take part in this interleave -		 * and record their indices. -		 */ -		ix = 0; -		for (ci = cs->sc_cinfo; -		     ci < &cs->sc_cinfo[cs->sc_nccdisks]; ci++) -			if (ci->ci_size >= smallci->ci_size) -				ii->ii_index[ix++] = ci - cs->sc_cinfo; -		ii->ii_ndisk = ix; -		bn += ix * (smallci->ci_size - size); -		lbn = smallci->ci_size / cs->sc_ileave; -		size = smallci->ci_size; -	} -#ifdef DEBUG -	if (ccddebug & CCDB_INIT) -		printiinfo(cs->sc_itable); -#endif -} - -/* ARGSUSED */ -int -ccdopen(dev, flags, fmt, p) -	dev_t dev; -	int flags, fmt; -	struct proc *p; -{ -	int unit = ccdunit(dev); -	struct ccd_softc *cs; -	struct disklabel *lp; -	int error = 0, part, pmask; - -#ifdef DEBUG -	if (ccddebug & CCDB_FOLLOW) -		printf("ccdopen(%x, %x)\n", dev, flags); -#endif -	if (unit >= numccd) -		return (ENXIO); -	cs = &ccd_softc[unit]; - -	if (error = ccdlock(cs)) -		return (error); - -	lp = &cs->sc_dkdev.dk_label; - -	part = DISKPART(dev); -	pmask = (1 << part); - -	/* -	 * If we're initialized, check to see if there are any other -	 * open partitions.  If not, then it's safe to update -	 * the in-core disklabel. -	 */ -	if ((cs->sc_flags & CCDF_INITED) && (cs->sc_dkdev.dk_openmask == 0)) -		ccdgetdisklabel(dev); - -	/* Check that the partition exists. */ -	if (part != RAW_PART && ((part > lp->d_npartitions) || -	    (lp->d_partitions[part].p_fstype == FS_UNUSED))) { -		error = ENXIO; -		goto done; -	} - -	/* Prevent our unit from being unconfigured while open. */ -	switch (fmt) { -	case S_IFCHR: -		cs->sc_dkdev.dk_copenmask |= pmask; -		break; - -	case S_IFBLK: -		cs->sc_dkdev.dk_bopenmask |= pmask; -		break; -	} -	cs->sc_dkdev.dk_openmask = -	    cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; - - done: -	ccdunlock(cs); -	return (0); -} - -/* ARGSUSED */ -int -ccdclose(dev, flags, fmt, p) -	dev_t dev; -	int flags, fmt; -	struct proc *p; -{ -	int unit = ccdunit(dev); -	struct ccd_softc *cs; -	int error = 0, part; - -#ifdef DEBUG -	if (ccddebug & CCDB_FOLLOW) -		printf("ccdclose(%x, %x)\n", dev, flags); -#endif - -	if (unit >= numccd) -		return (ENXIO); -	cs = &ccd_softc[unit]; - -	if (error = ccdlock(cs)) -		return (error); - -	part = DISKPART(dev); - -	/* ...that much closer to allowing unconfiguration... */ -	switch (fmt) { -	case S_IFCHR: -		cs->sc_dkdev.dk_copenmask &= ~(1 << part); -		break; - -	case S_IFBLK: -		cs->sc_dkdev.dk_bopenmask &= ~(1 << part); -		break; -	} -	cs->sc_dkdev.dk_openmask = -	    cs->sc_dkdev.dk_copenmask | cs->sc_dkdev.dk_bopenmask; - -	ccdunlock(cs); -	return (0); -} - -void -ccdstrategy(bp) -	register struct buf *bp; -{ -	register int unit = ccdunit(bp->b_dev); -	register struct ccd_softc *cs = &ccd_softc[unit]; -	register daddr_t bn; -	register int sz, s; -	int wlabel; -	struct disklabel *lp; - -#ifdef DEBUG -	if (ccddebug & CCDB_FOLLOW) -		printf("ccdstrategy(%x): unit %d\n", bp, unit); -#endif -	if ((cs->sc_flags & CCDF_INITED) == 0) { -		bp->b_error = ENXIO; -		bp->b_flags |= B_ERROR; -		goto done; -	} - -	/* If it's a nil transfer, wake up the top half now. */ -	if (bp->b_bcount == 0) -		goto done; - -	lp = &cs->sc_dkdev.dk_label; - -	/* -	 * Do bounds checking and adjust transfer.  If there's an -	 * error, the bounds check will flag that for us. -	 */ -	wlabel = cs->sc_flags & (CCDF_WLABEL|CCDF_LABELLING); -	if (DISKPART(bp->b_dev) != RAW_PART) -		if (bounds_check_with_label(bp, lp, wlabel) <= 0) -			goto done; - -	bp->b_resid = bp->b_bcount; - -	/* -	 * "Start" the unit. -	 */ -	s = splbio(); -	ccdstart(cs, bp); -	splx(s); -	return; -done: -	biodone(bp); -} - -static void -ccdstart(cs, bp) -	register struct ccd_softc *cs; -	register struct buf *bp; -{ -	register long bcount, rcount; -	struct ccdbuf *cbp; -	caddr_t addr; -	daddr_t bn; -	struct partition *pp; - -#ifdef DEBUG -	if (ccddebug & CCDB_FOLLOW) -		printf("ccdstart(%x, %x)\n", cs, bp); -#endif - -#ifdef WORKING_DISK_STATISTICS		/* XXX !! */ -	/* -	 * Instrumentation (not very meaningful) -	 */ -	cs->sc_nactive++; -	if (cs->sc_dk >= 0) { -		dk_busy |= 1 << cs->sc_dk; -		dk_xfer[cs->sc_dk]++; -		dk_wds[cs->sc_dk] += bp->b_bcount >> 6; -	} -#endif - -	/* -	 * Translate the partition-relative block number to an absolute. -	 */ -	bn = bp->b_blkno; -	if (DISKPART(bp->b_dev) != RAW_PART) { -		pp = &cs->sc_dkdev.dk_label.d_partitions[DISKPART(bp->b_dev)]; -		bn += pp->p_offset; -	} - -	/* -	 * Allocate component buffers and fire off the requests -	 */ -	addr = bp->b_data; -	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { -		cbp = ccdbuffer(cs, bp, bn, addr, bcount); -		rcount = cbp->cb_buf.b_bcount; -		if ((cbp->cb_buf.b_flags & B_READ) == 0) -			cbp->cb_buf.b_vp->v_numoutput++; -		VOP_STRATEGY(&cbp->cb_buf); -		bn += btodb(rcount); -		addr += rcount; -	} -} - -/* - * Build a component buffer header. - */ -static struct ccdbuf * -ccdbuffer(cs, bp, bn, addr, bcount) -	register struct ccd_softc *cs; -	struct buf *bp; -	daddr_t bn; -	caddr_t addr; -	long bcount; -{ -	register struct ccdcinfo *ci; -	register struct ccdbuf *cbp; -	register daddr_t cbn, cboff; - -#ifdef DEBUG -	if (ccddebug & CCDB_IO) -		printf("ccdbuffer(%x, %x, %d, %x, %d)\n", -		       cs, bp, bn, addr, bcount); -#endif -	/* -	 * Determine which component bn falls in. -	 */ -	cbn = bn; -	cboff = 0; - -	/* -	 * Serially concatenated -	 */ -	if (cs->sc_ileave == 0) { -		register daddr_t sblk; - -		sblk = 0; -		for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) -			sblk += ci->ci_size; -		cbn -= sblk; -	} -	/* -	 * Interleaved -	 */ -	else { -		register struct ccdiinfo *ii; -		int ccdisk, off; - -		cboff = cbn % cs->sc_ileave; -		cbn /= cs->sc_ileave; -		for (ii = cs->sc_itable; ii->ii_ndisk; ii++) -			if (ii->ii_startblk > cbn) -				break; -		ii--; -		off = cbn - ii->ii_startblk; -		if (ii->ii_ndisk == 1) { -			ccdisk = ii->ii_index[0]; -			cbn = ii->ii_startoff + off; -		} else { -			ccdisk = ii->ii_index[off % ii->ii_ndisk]; -			cbn = ii->ii_startoff + off / ii->ii_ndisk; -		} -		cbn *= cs->sc_ileave; -		ci = &cs->sc_cinfo[ccdisk]; -	} - -	/* -	 * Fill in the component buf structure. -	 */ -	cbp = getccdbuf(); -	cbp->cb_buf.b_flags = bp->b_flags | B_CALL; -	cbp->cb_buf.b_iodone = (void (*)())ccdiodone; -	cbp->cb_buf.b_proc = bp->b_proc; -	cbp->cb_buf.b_dev = ci->ci_dev;		/* XXX */ -	cbp->cb_buf.b_blkno = cbn + cboff; -	cbp->cb_buf.b_data = addr; -	cbp->cb_buf.b_vp = ci->ci_vp; -	if (cs->sc_ileave == 0) -		cbp->cb_buf.b_bcount = dbtob(ci->ci_size - cbn); -	else -		cbp->cb_buf.b_bcount = dbtob(cs->sc_ileave - cboff); -	if (cbp->cb_buf.b_bcount > bcount) -		cbp->cb_buf.b_bcount = bcount; - -	/* -	 * context for ccdiodone -	 */ -	cbp->cb_obp = bp; -	cbp->cb_unit = cs - ccd_softc; -	cbp->cb_comp = ci - cs->sc_cinfo; - -#ifdef DEBUG -	if (ccddebug & CCDB_IO) -		printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", -		       ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->cb_buf.b_blkno, -		       cbp->cb_buf.b_data, cbp->cb_buf.b_bcount); -#endif -	return (cbp); -} - -static void -ccdintr(cs, bp) -	register struct ccd_softc *cs; -	register struct buf *bp; -{ - -#ifdef DEBUG -	if (ccddebug & CCDB_FOLLOW) -		printf("ccdintr(%x, %x)\n", cs, bp); -#endif -	/* -	 * Request is done for better or worse, wakeup the top half. -	 */ -#ifdef WORKING_DISK_STATISTICS		/* XXX !! */ -	--cs->sc_nactive; -#ifdef DIAGNOSTIC -	if (cs->sc_nactive < 0) -		panic("ccdintr: ccd%d: sc_nactive < 0", cs->sc_unit); -#endif - -	if (cs->sc_nactive == 0 && cs->sc_dk >= 0) -		dk_busy &= ~(1 << cs->sc_dk); -#endif -	if (bp->b_flags & B_ERROR) -		bp->b_resid = bp->b_bcount; -	biodone(bp); -} - -/* - * Called at interrupt time. - * Mark the component as done and if all components are done, - * take a ccd interrupt. - */ -void -ccdiodone(cbp) -	struct ccdbuf *cbp; -{ -	register struct buf *bp = cbp->cb_obp; -	register int unit = cbp->cb_unit; -	int count, s; - -	s = splbio(); -#ifdef DEBUG -	if (ccddebug & CCDB_FOLLOW) -		printf("ccdiodone(%x)\n", cbp); -	if (ccddebug & CCDB_IO) { -		printf("ccdiodone: bp %x bcount %d resid %d\n", -		       bp, bp->b_bcount, bp->b_resid); -		printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", -		       cbp->cb_buf.b_dev, cbp->cb_comp, cbp, -		       cbp->cb_buf.b_blkno, cbp->cb_buf.b_data, -		       cbp->cb_buf.b_bcount); -	} -#endif - -	if (cbp->cb_buf.b_flags & B_ERROR) { -		bp->b_flags |= B_ERROR; -		bp->b_error = cbp->cb_buf.b_error ? cbp->cb_buf.b_error : EIO; -#ifdef DEBUG -		printf("ccd%d: error %d on component %d\n", -		       unit, bp->b_error, cbp->cb_comp); -#endif -	} -	count = cbp->cb_buf.b_bcount; -	putccdbuf(cbp); - -	/* -	 * If all done, "interrupt". -	 */ -	bp->b_resid -= count; -	if (bp->b_resid < 0) -		panic("ccdiodone: count"); -	if (bp->b_resid == 0) -		ccdintr(&ccd_softc[unit], bp); -	splx(s); -} - -/* ARGSUSED */ -int -ccdread(dev, uio, flags) -	dev_t dev; -	struct uio *uio; -	int flags; -{ -	int unit = ccdunit(dev); -	struct ccd_softc *cs; - -#ifdef DEBUG -	if (ccddebug & CCDB_FOLLOW) -		printf("ccdread(%x, %x)\n", dev, uio); -#endif -	if (unit >= numccd) -		return (ENXIO); -	cs = &ccd_softc[unit]; - -	if ((cs->sc_flags & CCDF_INITED) == 0) -		return (ENXIO); - -	/* -	 * XXX: It's not clear that using minphys() is completely safe, -	 * in particular, for raw I/O.  Underlying devices might have some -	 * non-obvious limits, because of the copy to user-space. -	 */ -	return (physio(ccdstrategy, NULL, dev, B_READ, minphys, uio)); -} - -/* ARGSUSED */ -int -ccdwrite(dev, uio, flags) -	dev_t dev; -	struct uio *uio; -	int flags; -{ -	int unit = ccdunit(dev); -	struct ccd_softc *cs; - -#ifdef DEBUG -	if (ccddebug & CCDB_FOLLOW) -		printf("ccdwrite(%x, %x)\n", dev, uio); -#endif -	if (unit >= numccd) -		return (ENXIO); -	cs = &ccd_softc[unit]; - -	if ((cs->sc_flags & CCDF_INITED) == 0) -		return (ENXIO); - -	/* -	 * XXX: It's not clear that using minphys() is completely safe, -	 * in particular, for raw I/O.  Underlying devices might have some -	 * non-obvious limits, because of the copy to user-space. -	 */ -	return (physio(ccdstrategy, NULL, dev, B_WRITE, minphys, uio)); -} - -int -ccdioctl(dev, cmd, data, flag, p) -	dev_t dev; -	u_long cmd; -	caddr_t data; -	int flag; -	struct proc *p; -{ -	int unit = ccdunit(dev); -	int i, j, lookedup = 0, error = 0; -	int part, pmask, s; -	struct ccd_softc *cs; -	struct ccd_ioctl *ccio = (struct ccd_ioctl *)data; -	struct ccddevice ccd; -	char **cpp; -	struct vnode **vpp; -#ifdef WORKING_DISK_STATISTICS		/* XXX !! */ -	extern int dkn; -#endif - -	if (unit >= numccd) -		return (ENXIO); -	cs = &ccd_softc[unit]; - -	bzero(&ccd, sizeof(ccd)); - -	switch (cmd) { -	case CCDIOCSET: -		if (cs->sc_flags & CCDF_INITED) -			return (EBUSY); - -		if ((flag & FWRITE) == 0) -			return (EBADF); - -		if (error = ccdlock(cs)) -			return (error); - -		/* Fill in some important bits. */ -		ccd.ccd_unit = unit; -		ccd.ccd_interleave = ccio->ccio_ileave; -		ccd.ccd_flags = ccio->ccio_flags & CCDF_USERMASK; - -		/* -		 * Allocate space for and copy in the array of -		 * componet pathnames and device numbers. -		 */ -		cpp = malloc(ccio->ccio_ndisks * sizeof(char *), -		    M_DEVBUF, M_WAITOK); -		vpp = malloc(ccio->ccio_ndisks * sizeof(struct vnode *), -		    M_DEVBUF, M_WAITOK); - -		error = copyin((caddr_t)ccio->ccio_disks, (caddr_t)cpp, -		    ccio->ccio_ndisks * sizeof(char **)); -		if (error) { -			free(vpp, M_DEVBUF); -			free(cpp, M_DEVBUF); -			ccdunlock(cs); -			return (error); -		} - -#ifdef DEBUG -		if (ccddebug & CCDB_INIT) -			for (i = 0; i < ccio->ccio_ndisks; ++i) -				printf("ccdioctl: component %d: 0x%x\n", -				    i, cpp[i]); -#endif - -		for (i = 0; i < ccio->ccio_ndisks; ++i) { -#ifdef DEBUG -			if (ccddebug & CCDB_INIT) -				printf("ccdioctl: lookedup = %d\n", lookedup); -#endif -			if (error = ccdlookup(cpp[i], p, &vpp[i])) { -				for (j = 0; j < lookedup; ++j) -					(void)vn_close(vpp[j], FREAD|FWRITE, -					    p->p_ucred, p); -				free(vpp, M_DEVBUF); -				free(cpp, M_DEVBUF); -				ccdunlock(cs); -				return (error); -			} -			++lookedup; -		} -		ccd.ccd_cpp = cpp; -		ccd.ccd_vpp = vpp; -		ccd.ccd_ndev = ccio->ccio_ndisks; - -#ifdef WORKING_DISK_STATISTICS		/* XXX !! */ -		/* -		 * Assign disk index first so that init routine -		 * can use it (saves having the driver drag around -		 * the ccddevice pointer just to set up the dk_* -		 * info in the open routine). -		 */ -		if (dkn < DK_NDRIVE) -			ccd.ccd_dk = dkn++; -		else -			ccd.ccd_dk = -1; -#endif - -		/* -		 * Initialize the ccd.  Fills in the softc for us. -		 */ -		if (error = ccdinit(&ccd, cpp, p)) { -#ifdef WORKING_DISK_STATISTICS		/* XXX !! */ -			if (ccd.ccd_dk >= 0) -				--dkn; -#endif -			for (j = 0; j < lookedup; ++j) -				(void)vn_close(vpp[j], FREAD|FWRITE, -				    p->p_ucred, p); -			bzero(&ccd_softc[unit], sizeof(struct ccd_softc)); -			free(vpp, M_DEVBUF); -			free(cpp, M_DEVBUF); -			ccdunlock(cs); -			return (error); -		} - -		/* -		 * The ccd has been successfully initialized, so -		 * we can place it into the array and read the disklabel. -		 */ -		bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); -		ccio->ccio_unit = unit; -		ccio->ccio_size = cs->sc_size; -		ccdgetdisklabel(dev); - -		ccdunlock(cs); - -		break; - -	case CCDIOCCLR: -		if ((cs->sc_flags & CCDF_INITED) == 0) -			return (ENXIO); - -		if ((flag & FWRITE) == 0) -			return (EBADF); - -		if (error = ccdlock(cs)) -			return (error); - -		/* -		 * Don't unconfigure if any other partitions are open -		 * or if both the character and block flavors of this -		 * partition are open. -		 */ -		part = DISKPART(dev); -		pmask = (1 << part); -		if ((cs->sc_dkdev.dk_openmask & ~pmask) || -		    ((cs->sc_dkdev.dk_bopenmask & pmask) && -		    (cs->sc_dkdev.dk_copenmask & pmask))) { -			ccdunlock(cs); -			return (EBUSY); -		} - -		/* -		 * Free ccd_softc information and clear entry. -		 */ - -		/* Close the components and free their pathnames. */ -		for (i = 0; i < cs->sc_nccdisks; ++i) { -			/* -			 * XXX: this close could potentially fail and -			 * cause Bad Things.  Maybe we need to force -			 * the close to happen? -			 */ -#ifdef DEBUG -			if (ccddebug & CCDB_VNODE) -				vprint("CCDIOCCLR: vnode info", -				    cs->sc_cinfo[i].ci_vp); -#endif -			(void)vn_close(cs->sc_cinfo[i].ci_vp, FREAD|FWRITE, -			    p->p_ucred, p); -			free(cs->sc_cinfo[i].ci_path, M_DEVBUF); -		} - -		/* Free interleave index. */ -		for (i = 0; cs->sc_itable[i].ii_ndisk; ++i) -			free(cs->sc_itable[i].ii_index, M_DEVBUF); - -		/* Free component info and interleave table. */ -		free(cs->sc_cinfo, M_DEVBUF); -		free(cs->sc_itable, M_DEVBUF); -		cs->sc_flags &= ~CCDF_INITED; - -		/* -		 * Free ccddevice information and clear entry. -		 */ -		free(ccddevs[unit].ccd_cpp, M_DEVBUF); -		free(ccddevs[unit].ccd_vpp, M_DEVBUF); -		ccd.ccd_dk = -1; -		bcopy(&ccd, &ccddevs[unit], sizeof(ccd)); - -		/* This must be atomic. */ -		s = splhigh(); -		ccdunlock(cs); -		bzero(cs, sizeof(struct ccd_softc)); -		splx(s); - -		break; - -	case DIOCGDINFO: -		if ((cs->sc_flags & CCDF_INITED) == 0) -			return (ENXIO); - -		*(struct disklabel *)data = cs->sc_dkdev.dk_label; -		break; - -	case DIOCGPART: -		if ((cs->sc_flags & CCDF_INITED) == 0) -			return (ENXIO); - -		((struct partinfo *)data)->disklab = &cs->sc_dkdev.dk_label; -		((struct partinfo *)data)->part = -		    &cs->sc_dkdev.dk_label.d_partitions[DISKPART(dev)]; -		break; - -	case DIOCWDINFO: -	case DIOCSDINFO: -		if ((cs->sc_flags & CCDF_INITED) == 0) -			return (ENXIO); - -		if ((flag & FWRITE) == 0) -			return (EBADF); - -		if (error = ccdlock(cs)) -			return (error); - -		cs->sc_flags |= CCDF_LABELLING; - -		error = setdisklabel(&cs->sc_dkdev.dk_label, -		    (struct disklabel *)data, 0, &cs->sc_dkdev.dk_cpulabel); -		if (error == 0) { -			if (cmd == DIOCWDINFO) -				error = writedisklabel(CCDLABELDEV(dev), -				    ccdstrategy, &cs->sc_dkdev.dk_label, -				    &cs->sc_dkdev.dk_cpulabel); -		} - -		cs->sc_flags &= ~CCDF_LABELLING; - -		ccdunlock(cs); - -		if (error) -			return (error); -		break; - -	case DIOCWLABEL: -		if ((cs->sc_flags & CCDF_INITED) == 0) -			return (ENXIO); - -		if ((flag & FWRITE) == 0) -			return (EBADF); -		if (*(int *)data != 0) -			cs->sc_flags |= CCDF_WLABEL; -		else -			cs->sc_flags &= ~CCDF_WLABEL; -		break; - -	default: -		return (ENOTTY); -	} - -	return (0); -} - -int -ccdsize(dev) -	dev_t dev; -{ -	struct ccd_softc *cs; -	int part, size; - -	if (ccdopen(dev, 0, S_IFBLK, curproc)) -		return (-1); - -	cs = &ccd_softc[ccdunit(dev)]; -	part = DISKPART(dev); - -	if ((cs->sc_flags & CCDF_INITED) == 0) -		return (-1); - -	if (cs->sc_dkdev.dk_label.d_partitions[part].p_fstype != FS_SWAP) -		size = -1; -	else -		size = cs->sc_dkdev.dk_label.d_partitions[part].p_size; - -	if (ccdclose(dev, 0, S_IFBLK, curproc)) -		return (-1); - -	return (size); -} - -int -ccddump(dev, blkno, va, size) -	dev_t dev; -	daddr_t blkno; -	caddr_t va; -	size_t size; -{ - -	/* Not implemented. */ -	return ENXIO; -} - -/* - * Lookup the provided name in the filesystem.  If the file exists, - * is a valid block device, and isn't being used by anyone else, - * set *vpp to the file's vnode. - */ -static int -ccdlookup(path, p, vpp) -	char *path; -	struct proc *p; -	struct vnode **vpp;	/* result */ -{ -	struct nameidata nd; -	struct vnode *vp; -	struct vattr va; -	int error; - -	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, path, p); -	if (error = vn_open(&nd, FREAD|FWRITE, 0)) { -#ifdef DEBUG -		if (ccddebug & CCDB_FOLLOW|CCDB_INIT) -			printf("ccdlookup: vn_open error = %d\n", error); -#endif -		return (error); -	} -	vp = nd.ni_vp; - -	if (vp->v_usecount > 1) { -		VOP_UNLOCK(vp); -		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); -		return (EBUSY); -	} - -	if (error = VOP_GETATTR(vp, &va, p->p_ucred, p)) { -#ifdef DEBUG -		if (ccddebug & CCDB_FOLLOW|CCDB_INIT) -			printf("ccdlookup: getattr error = %d\n", error); -#endif -		VOP_UNLOCK(vp); -		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); -		return (error); -	} - -	/* XXX: eventually we should handle VREG, too. */ -	if (va.va_type != VBLK) { -		VOP_UNLOCK(vp); -		(void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); -		return (ENOTBLK); -	} - -#ifdef DEBUG -	if (ccddebug & CCDB_VNODE) -		vprint("ccdlookup: vnode info", vp); -#endif - -	VOP_UNLOCK(vp); -	*vpp = vp; -	return (0); -} - -/* - * Read the disklabel from the ccd.  If one is not present, fake one - * up. - */ -static void -ccdgetdisklabel(dev) -	dev_t dev; -{ -	int unit = ccdunit(dev); -	struct ccd_softc *cs = &ccd_softc[unit]; -	char *errstring; -	struct disklabel *lp = &cs->sc_dkdev.dk_label; -	struct cpu_disklabel *clp = &cs->sc_dkdev.dk_cpulabel; -	struct ccdgeom *ccg = &cs->sc_geom; - -	bzero(lp, sizeof(*lp)); -	bzero(clp, sizeof(*clp)); - -	lp->d_secperunit = cs->sc_size; -	lp->d_secsize = ccg->ccg_secsize; -	lp->d_nsectors = ccg->ccg_nsectors; -	lp->d_ntracks = ccg->ccg_ntracks; -	lp->d_ncylinders = ccg->ccg_ncylinders; -	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; - -	strncpy(lp->d_typename, "ccd", sizeof(lp->d_typename)); -	lp->d_type = DTYPE_CCD; -	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); -	lp->d_rpm = 3600; -	lp->d_interleave = 1; -	lp->d_flags = 0; - -	lp->d_partitions[RAW_PART].p_offset = 0; -	lp->d_partitions[RAW_PART].p_size = cs->sc_size; -	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; -	lp->d_npartitions = RAW_PART + 1; - -	lp->d_magic = DISKMAGIC; -	lp->d_magic2 = DISKMAGIC; -	lp->d_checksum = dkcksum(&cs->sc_dkdev.dk_label); - -	/* -	 * Call the generic disklabel extraction routine. -	 */ -	if (errstring = readdisklabel(CCDLABELDEV(dev), ccdstrategy, -	    &cs->sc_dkdev.dk_label, &cs->sc_dkdev.dk_cpulabel)) -		ccdmakedisklabel(cs); - -#ifdef DEBUG -	/* It's actually extremely common to have unlabeled ccds. */ -	if (ccddebug & CCDB_LABEL) -		if (errstring != NULL) -			printf("ccd%d: %s\n", unit, errstring); -#endif -} - -/* - * Take care of things one might want to take care of in the event - * that a disklabel isn't present. - */ -static void -ccdmakedisklabel(cs) -	struct ccd_softc *cs; -{ -	struct disklabel *lp = &cs->sc_dkdev.dk_label; - -	/* -	 * For historical reasons, if there's no disklabel present -	 * the raw partition must be marked FS_BSDFFS. -	 */ -	lp->d_partitions[RAW_PART].p_fstype = FS_BSDFFS; - -	strncpy(lp->d_packname, "default label", sizeof(lp->d_packname)); -} - -/* - * Wait interruptibly for an exclusive lock. - * - * XXX - * Several drivers do this; it should be abstracted and made MP-safe. - */ -static int -ccdlock(cs) -	struct ccd_softc *cs; -{ -	int error; - -	while ((cs->sc_flags & CCDF_LOCKED) != 0) { -		cs->sc_flags |= CCDF_WANTED; -		if ((error = tsleep(cs, PRIBIO | PCATCH, "ccdlck", 0)) != 0) -			return (error); -	} -	cs->sc_flags |= CCDF_LOCKED; -	return (0); -} - -/* - * Unlock and wake up any waiters. - */ -static void -ccdunlock(cs) -	struct ccd_softc *cs; -{ - -	cs->sc_flags &= ~CCDF_LOCKED; -	if ((cs->sc_flags & CCDF_WANTED) != 0) { -		cs->sc_flags &= ~CCDF_WANTED; -		wakeup(cs); -	} -} - -#ifdef DEBUG -static void -printiinfo(ii) -	struct ccdiinfo *ii; -{ -	register int ix, i; - -	for (ix = 0; ii->ii_ndisk; ix++, ii++) { -		printf(" itab[%d]: #dk %d sblk %d soff %d", -		       ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); -		for (i = 0; i < ii->ii_ndisk; i++) -			printf(" %d", ii->ii_index[i]); -		printf("\n"); -	} -} -#endif | 
