xref: /csrg-svn/sys/dev/cd.c (revision 58051)
141480Smckusick /*
241480Smckusick  * Copyright (c) 1988 University of Utah.
341480Smckusick  * Copyright (c) 1990 The Regents of the University of California.
441480Smckusick  * All rights reserved.
541480Smckusick  *
641480Smckusick  * This code is derived from software contributed to Berkeley by
741480Smckusick  * the Systems Programming Group of the University of Utah Computer
841480Smckusick  * Science Department.
941480Smckusick  *
1041480Smckusick  * %sccs.include.redist.c%
1141480Smckusick  *
1249302Shibler  * from: Utah $Hdr: cd.c 1.6 90/11/28$
1341480Smckusick  *
14*58051Shibler  *	@(#)cd.c	7.6 (Berkeley) 02/18/93
1541480Smckusick  */
1641480Smckusick 
1741480Smckusick /*
1841480Smckusick  * "Concatenated" disk driver.
1941480Smckusick  */
2041480Smckusick #include "cd.h"
2141480Smckusick #if NCD > 0
2241480Smckusick 
2356503Sbostic #include <sys/param.h>
2456503Sbostic #include <sys/systm.h>
2556503Sbostic #include <sys/errno.h>
2656503Sbostic #include <sys/dkstat.h>
2756503Sbostic #include <sys/buf.h>
2856503Sbostic #include <sys/malloc.h>
2956503Sbostic #include <sys/conf.h>
30*58051Shibler #include <sys/stat.h>
31*58051Shibler #ifdef COMPAT_NOLABEL
32*58051Shibler #include <sys/ioctl.h>
33*58051Shibler #include <sys/disklabel.h>
34*58051Shibler #include <sys/fcntl.h>
35*58051Shibler #endif
3641480Smckusick 
3756503Sbostic #include <dev/cdvar.h>
3841480Smckusick 
3941480Smckusick #ifdef DEBUG
4041480Smckusick int cddebug = 0x00;
4141480Smckusick #define CDB_FOLLOW	0x01
4241480Smckusick #define CDB_INIT	0x02
4341480Smckusick #define CDB_IO		0x04
4441480Smckusick #endif
4541480Smckusick 
4641480Smckusick struct	buf cdbuf[NCD];
4741480Smckusick struct	buf *cdbuffer();
4849302Shibler char	*cddevtostr();
4941480Smckusick int	cdiodone();
5041480Smckusick 
5141480Smckusick #define	cdunit(x)	((minor(x) >> 3) & 0x7)	/* for consistency */
5241480Smckusick 
5341480Smckusick #define	getcbuf()	\
5441480Smckusick 	((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))
5541480Smckusick #define putcbuf(bp)	\
5641480Smckusick 	free((caddr_t)(bp), M_DEVBUF)
5741480Smckusick 
5841480Smckusick struct cd_softc {
5941480Smckusick 	int		 sc_flags;		/* flags */
6041480Smckusick 	size_t		 sc_size;		/* size of cd */
6141480Smckusick 	int		 sc_ileave;		/* interleave */
6241480Smckusick 	int		 sc_ncdisks;		/* number of components */
6341480Smckusick 	struct cdcinfo	 sc_cinfo[NCDISKS];	/* component info */
6441480Smckusick 	struct cdiinfo	 *sc_itable;		/* interleave table */
6541480Smckusick 	int		 sc_usecnt;		/* number of requests active */
6641480Smckusick 	struct buf	 *sc_bp;		/* "current" request */
6741480Smckusick 	int		 sc_dk;			/* disk index */
6841480Smckusick } cd_softc[NCD];
6941480Smckusick 
7041480Smckusick /* sc_flags */
7141480Smckusick #define	CDF_ALIVE	0x01
7241480Smckusick #define CDF_INITED	0x02
7341480Smckusick 
7441480Smckusick cdinit(cd)
7541480Smckusick 	struct cddevice *cd;
7641480Smckusick {
7741480Smckusick 	register struct cd_softc *cs = &cd_softc[cd->cd_unit];
7841480Smckusick 	register struct cdcinfo *ci;
7941480Smckusick 	register size_t size;
8041480Smckusick 	register int ix;
8141480Smckusick 	size_t minsize;
8241480Smckusick 	dev_t dev;
83*58051Shibler 	struct bdevsw *bsw;
84*58051Shibler 	int error;
8541480Smckusick 
8641480Smckusick #ifdef DEBUG
8741480Smckusick 	if (cddebug & (CDB_FOLLOW|CDB_INIT))
8841480Smckusick 		printf("cdinit: unit %d\n", cd->cd_unit);
8941480Smckusick #endif
9041480Smckusick 	cs->sc_dk = cd->cd_dk;
9141480Smckusick 	cs->sc_size = 0;
9241480Smckusick 	cs->sc_ileave = cd->cd_interleave;
9341480Smckusick 	cs->sc_ncdisks = 0;
9441480Smckusick 	/*
9541480Smckusick 	 * Verify that each component piece exists and record
9641480Smckusick 	 * relevant information about it.
9741480Smckusick 	 */
9841480Smckusick 	minsize = 0;
9941480Smckusick 	for (ix = 0; ix < NCDISKS; ix++) {
10041480Smckusick 		if ((dev = cd->cd_dev[ix]) == NODEV)
10141480Smckusick 			break;
10241480Smckusick 		ci = &cs->sc_cinfo[ix];
10341480Smckusick 		ci->ci_dev = dev;
104*58051Shibler 		bsw = &bdevsw[major(dev)];
10541480Smckusick 		/*
106*58051Shibler 		 * Open the partition
107*58051Shibler 		 */
108*58051Shibler 		if (bsw->d_open && (error = (*bsw->d_open)(dev, 0, S_IFBLK))) {
109*58051Shibler 			printf("cd%d: component %s open failed, error = %d\n",
110*58051Shibler 			       cd->cd_unit, cddevtostr(dev), error);
111*58051Shibler 			return(0);
112*58051Shibler 		}
113*58051Shibler 		/*
11441480Smckusick 		 * Calculate size (truncated to interleave boundary
11541480Smckusick 		 * if necessary.
11641480Smckusick 		 */
117*58051Shibler 		if (bsw->d_psize) {
118*58051Shibler 			size = (size_t) (*bsw->d_psize)(dev);
11949302Shibler 			if ((int)size < 0)
12041480Smckusick 				size = 0;
12141480Smckusick 		} else
12241480Smckusick 			size = 0;
12341480Smckusick 		if (cs->sc_ileave > 1)
12441480Smckusick 			size -= size % cs->sc_ileave;
12549302Shibler 		if (size == 0) {
12649302Shibler 			printf("cd%d: not configured (component %s missing)\n",
127*58051Shibler 			       cd->cd_unit, cddevtostr(dev));
12841480Smckusick 			return(0);
12949302Shibler 		}
130*58051Shibler #ifdef COMPAT_NOLABEL
131*58051Shibler 		/*
132*58051Shibler 		 * XXX if this is a 'c' partition then we need to mark the
133*58051Shibler 		 * label area writeable since there cannot be a label.
134*58051Shibler 		 */
135*58051Shibler 		if ((minor(dev) & 7) == 2 && bsw->d_open) {
136*58051Shibler 			int i, flag;
137*58051Shibler 
138*58051Shibler 			for (i = 0; i < nchrdev; i++)
139*58051Shibler 				if (cdevsw[i].d_open == bsw->d_open)
140*58051Shibler 					break;
141*58051Shibler 			if (i != nchrdev && cdevsw[i].d_ioctl) {
142*58051Shibler 				flag = 1;
143*58051Shibler 				(void)(*cdevsw[i].d_ioctl)(dev, DIOCWLABEL,
144*58051Shibler 							   &flag, FWRITE);
145*58051Shibler 			}
146*58051Shibler 		}
147*58051Shibler #endif
14841480Smckusick 		if (minsize == 0 || size < minsize)
14941480Smckusick 			minsize = size;
15041480Smckusick 		ci->ci_size = size;
15141480Smckusick 		cs->sc_size += size;
15241480Smckusick 		cs->sc_ncdisks++;
15341480Smckusick 	}
15441480Smckusick 	/*
15541480Smckusick 	 * If uniform interleave is desired set all sizes to that of
15641480Smckusick 	 * the smallest component.
15741480Smckusick 	 */
15841480Smckusick 	if (cd->cd_flags & CDF_UNIFORM) {
15941480Smckusick 		for (ci = cs->sc_cinfo;
16041480Smckusick 		     ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
16141480Smckusick 			ci->ci_size = minsize;
16241480Smckusick 		cs->sc_size = cs->sc_ncdisks * minsize;
16341480Smckusick 	}
16441480Smckusick 	/*
16541480Smckusick 	 * Construct the interleave table
16641480Smckusick 	 */
16741480Smckusick 	if (!cdinterleave(cs))
16841480Smckusick 		return(0);
16941480Smckusick 	if (cd->cd_dk >= 0)
17041480Smckusick 		dk_wpms[cd->cd_dk] = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
17149302Shibler 	printf("cd%d: %d components ", cd->cd_unit, cs->sc_ncdisks);
17249302Shibler 	for (ix = 0; ix < cs->sc_ncdisks; ix++)
17349302Shibler 		printf("%c%s%c",
17449302Shibler 		       ix == 0 ? '(' : ' ',
17549302Shibler 		       cddevtostr(cs->sc_cinfo[ix].ci_dev),
17649302Shibler 		       ix == cs->sc_ncdisks - 1 ? ')' : ',');
17749302Shibler 	printf(", %d blocks ", cs->sc_size);
17841480Smckusick 	if (cs->sc_ileave)
17949302Shibler 		printf("interleaved at %d blocks\n", cs->sc_ileave);
18041480Smckusick 	else
18149302Shibler 		printf("concatenated\n");
18241480Smckusick 	cs->sc_flags = CDF_ALIVE | CDF_INITED;
18341480Smckusick 	return(1);
18441480Smckusick }
18541480Smckusick 
18649302Shibler /*
18749302Shibler  * XXX not really cd specific.
18849302Shibler  */
18949302Shibler char *
19049302Shibler cddevtostr(dev)
19149302Shibler 	dev_t dev;
19249302Shibler {
19349302Shibler 	static char dbuf[5];
19449302Shibler 
19549302Shibler 	dbuf[1] = 'd';
19649302Shibler 	switch (major(dev)) {
19749302Shibler 	case 2:
19849302Shibler 		dbuf[0] = 'r';
19949302Shibler 		break;
20049302Shibler 	case 4:
20149302Shibler 		dbuf[0] = 's';
20249302Shibler 		break;
20349302Shibler 	case 5:
20449302Shibler 		dbuf[0] = 'c';
20549302Shibler 		break;
20649302Shibler 	default:
20749302Shibler 		dbuf[0] = dbuf[1] = '?';
20849302Shibler 		break;
20949302Shibler 	}
21049302Shibler 	dbuf[2] = (minor(dev) >> 3) + '0';
21149302Shibler 	dbuf[3] = (minor(dev) & 7) + 'a';
21249302Shibler 	dbuf[4] = '\0';
21349302Shibler 	return (dbuf);
21449302Shibler }
21549302Shibler 
21641480Smckusick cdinterleave(cs)
21741480Smckusick 	register struct cd_softc *cs;
21841480Smckusick {
21941480Smckusick 	register struct cdcinfo *ci, *smallci;
22041480Smckusick 	register struct cdiinfo *ii;
22141480Smckusick 	register daddr_t bn, lbn;
22241480Smckusick 	register int ix;
22341480Smckusick 	u_long size;
22441480Smckusick 
22541480Smckusick #ifdef DEBUG
22641480Smckusick 	if (cddebug & CDB_INIT)
22741480Smckusick 		printf("cdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
22841480Smckusick #endif
22941480Smckusick 	/*
23041480Smckusick 	 * Allocate an interleave table.
23141480Smckusick 	 * Chances are this is too big, but we don't care.
23241480Smckusick 	 */
23341480Smckusick 	size = (cs->sc_ncdisks + 1) * sizeof(struct cdiinfo);
23441480Smckusick 	cs->sc_itable = (struct cdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
23541480Smckusick 	bzero((caddr_t)cs->sc_itable, size);
23641480Smckusick 	/*
23741480Smckusick 	 * Trivial case: no interleave (actually interleave of disk size).
23841480Smckusick 	 * Each table entry represent a single component in its entirety.
23941480Smckusick 	 */
24041480Smckusick 	if (cs->sc_ileave == 0) {
24141480Smckusick 		bn = 0;
24241480Smckusick 		ii = cs->sc_itable;
24341480Smckusick 		for (ix = 0; ix < cs->sc_ncdisks; ix++) {
24441480Smckusick 			ii->ii_ndisk = 1;
24541480Smckusick 			ii->ii_startblk = bn;
24641480Smckusick 			ii->ii_startoff = 0;
24741480Smckusick 			ii->ii_index[0] = ix;
24841480Smckusick 			bn += cs->sc_cinfo[ix].ci_size;
24941480Smckusick 			ii++;
25041480Smckusick 		}
25141480Smckusick 		ii->ii_ndisk = 0;
25241480Smckusick #ifdef DEBUG
25341480Smckusick 		if (cddebug & CDB_INIT)
25441480Smckusick 			printiinfo(cs->sc_itable);
25541480Smckusick #endif
25641480Smckusick 		return(1);
25741480Smckusick 	}
25841480Smckusick 	/*
25941480Smckusick 	 * The following isn't fast or pretty; it doesn't have to be.
26041480Smckusick 	 */
26141480Smckusick 	size = 0;
26241480Smckusick 	bn = lbn = 0;
26341480Smckusick 	for (ii = cs->sc_itable; ; ii++) {
26441480Smckusick 		/*
26541480Smckusick 		 * Locate the smallest of the remaining components
26641480Smckusick 		 */
26741480Smckusick 		smallci = NULL;
26841480Smckusick 		for (ci = cs->sc_cinfo;
26941480Smckusick 		     ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
27041480Smckusick 			if (ci->ci_size > size &&
27141480Smckusick 			    (smallci == NULL ||
27241480Smckusick 			     ci->ci_size < smallci->ci_size))
27341480Smckusick 				smallci = ci;
27441480Smckusick 		/*
27541480Smckusick 		 * Nobody left, all done
27641480Smckusick 		 */
27741480Smckusick 		if (smallci == NULL) {
27841480Smckusick 			ii->ii_ndisk = 0;
27941480Smckusick 			break;
28041480Smckusick 		}
28141480Smckusick 		/*
28241480Smckusick 		 * Record starting logical block and component offset
28341480Smckusick 		 */
28441480Smckusick 		ii->ii_startblk = bn / cs->sc_ileave;
28541480Smckusick 		ii->ii_startoff = lbn;
28641480Smckusick 		/*
28741480Smckusick 		 * Determine how many disks take part in this interleave
28841480Smckusick 		 * and record their indices.
28941480Smckusick 		 */
29041480Smckusick 		ix = 0;
29141480Smckusick 		for (ci = cs->sc_cinfo;
29241480Smckusick 		     ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
29341480Smckusick 			if (ci->ci_size >= smallci->ci_size)
29441480Smckusick 				ii->ii_index[ix++] = ci - cs->sc_cinfo;
29541480Smckusick 		ii->ii_ndisk = ix;
29641480Smckusick 		bn += ix * (smallci->ci_size - size);
29741480Smckusick 		lbn = smallci->ci_size / cs->sc_ileave;
29841480Smckusick 		size = smallci->ci_size;
29941480Smckusick 	}
30041480Smckusick #ifdef DEBUG
30141480Smckusick 	if (cddebug & CDB_INIT)
30241480Smckusick 		printiinfo(cs->sc_itable);
30341480Smckusick #endif
30441480Smckusick 	return(1);
30541480Smckusick }
30641480Smckusick 
30741480Smckusick #ifdef DEBUG
30841480Smckusick printiinfo(ii)
30941480Smckusick 	struct cdiinfo *ii;
31041480Smckusick {
31141480Smckusick 	register int ix, i;
31241480Smckusick 
31341480Smckusick 	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
31441480Smckusick 		printf(" itab[%d]: #dk %d sblk %d soff %d",
31541480Smckusick 		       ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
31641480Smckusick 		for (i = 0; i < ii->ii_ndisk; i++)
31741480Smckusick 			printf(" %d", ii->ii_index[i]);
31841480Smckusick 		printf("\n");
31941480Smckusick 	}
32041480Smckusick }
32141480Smckusick #endif
32241480Smckusick 
32341480Smckusick cdopen(dev, flags)
32441480Smckusick 	dev_t dev;
32541480Smckusick {
32641480Smckusick 	int unit = cdunit(dev);
32741480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
32841480Smckusick 
32941480Smckusick #ifdef DEBUG
33041480Smckusick 	if (cddebug & CDB_FOLLOW)
33141480Smckusick 		printf("cdopen(%x, %x)\n", dev, flags);
33241480Smckusick #endif
33341480Smckusick 	if (unit >= NCD || (cs->sc_flags & CDF_ALIVE) == 0)
33441480Smckusick 		return(ENXIO);
33541480Smckusick 	return(0);
33641480Smckusick }
33741480Smckusick 
33841480Smckusick cdstrategy(bp)
33941480Smckusick 	register struct buf *bp;
34041480Smckusick {
34141480Smckusick 	register int unit = cdunit(bp->b_dev);
34241480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
34345480Smckusick 	register daddr_t bn;
34445480Smckusick 	register int sz, s;
34541480Smckusick 
34641480Smckusick #ifdef DEBUG
34741480Smckusick 	if (cddebug & CDB_FOLLOW)
34841480Smckusick 		printf("cdstrategy(%x): unit %d\n", bp, unit);
34941480Smckusick #endif
35041480Smckusick 	if ((cs->sc_flags & CDF_INITED) == 0) {
35141480Smckusick 		bp->b_error = ENXIO;
35245480Smckusick 		bp->b_flags |= B_ERROR;
35345480Smckusick 		goto done;
35441480Smckusick 	}
35541480Smckusick 	bn = bp->b_blkno;
35645480Smckusick 	sz = howmany(bp->b_bcount, DEV_BSIZE);
35741480Smckusick 	if (bn < 0 || bn + sz > cs->sc_size) {
35845480Smckusick 		sz = cs->sc_size - bn;
35945480Smckusick 		if (sz == 0) {
36045480Smckusick 			bp->b_resid = bp->b_bcount;
36141480Smckusick 			goto done;
36245480Smckusick 		}
36345480Smckusick 		if (sz < 0) {
36445480Smckusick 			bp->b_error = EINVAL;
36545480Smckusick 			bp->b_flags |= B_ERROR;
36645480Smckusick 			goto done;
36745480Smckusick 		}
36845480Smckusick 		bp->b_bcount = dbtob(sz);
36941480Smckusick 	}
37045480Smckusick 	bp->b_resid = bp->b_bcount;
37141480Smckusick 	/*
37241480Smckusick 	 * "Start" the unit.
37341480Smckusick 	 * XXX: the use of sc_bp is just to retain the "traditional"
37441480Smckusick 	 * interface to the start routine.
37541480Smckusick 	 */
37641480Smckusick 	s = splbio();
37741480Smckusick 	cs->sc_bp = bp;
37841480Smckusick 	cdstart(unit);
37941480Smckusick 	splx(s);
38041480Smckusick 	return;
38141480Smckusick done:
38245480Smckusick 	biodone(bp);
38341480Smckusick }
38441480Smckusick 
38541480Smckusick cdstart(unit)
38641480Smckusick 	int unit;
38741480Smckusick {
38841480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
38941480Smckusick 	register struct buf *bp = cs->sc_bp;
39041480Smckusick 	register long bcount, rcount;
39141480Smckusick 	struct buf *cbp;
39241480Smckusick 	caddr_t addr;
39341480Smckusick 	daddr_t bn;
39441480Smckusick 
39541480Smckusick #ifdef DEBUG
39641480Smckusick 	if (cddebug & CDB_FOLLOW)
39741480Smckusick 		printf("cdstart(%d)\n", unit);
39841480Smckusick #endif
39941480Smckusick 	/*
40041480Smckusick 	 * Instumentation (not real meaningful)
40141480Smckusick 	 */
40241480Smckusick 	cs->sc_usecnt++;
40341480Smckusick 	if (cs->sc_dk >= 0) {
40441480Smckusick 		dk_busy |= 1 << cs->sc_dk;
40541480Smckusick 		dk_xfer[cs->sc_dk]++;
40641480Smckusick 		dk_wds[cs->sc_dk] += bp->b_bcount >> 6;
40741480Smckusick 	}
40841480Smckusick 	/*
40941480Smckusick 	 * Allocate component buffers and fire off the requests
41041480Smckusick 	 */
41141480Smckusick 	bn = bp->b_blkno;
41241480Smckusick 	addr = bp->b_un.b_addr;
41341480Smckusick 	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
41441480Smckusick 		cbp = cdbuffer(cs, bp, bn, addr, bcount);
41541480Smckusick 		rcount = cbp->b_bcount;
41641480Smckusick 		(*bdevsw[major(cbp->b_dev)].d_strategy)(cbp);
41741480Smckusick 		bn += btodb(rcount);
41841480Smckusick 		addr += rcount;
41941480Smckusick 	}
42041480Smckusick }
42141480Smckusick 
42241480Smckusick /*
42341480Smckusick  * Build a component buffer header.
42441480Smckusick  */
42541480Smckusick struct buf *
42641480Smckusick cdbuffer(cs, bp, bn, addr, bcount)
42741480Smckusick 	register struct cd_softc *cs;
42841480Smckusick 	struct buf *bp;
42941480Smckusick 	daddr_t bn;
43041480Smckusick 	caddr_t addr;
43141480Smckusick 	long bcount;
43241480Smckusick {
43341480Smckusick 	register struct cdcinfo *ci;
43441480Smckusick 	register struct buf *cbp;
43541480Smckusick 	register daddr_t cbn, cboff;
43641480Smckusick 
43741480Smckusick #ifdef DEBUG
43841480Smckusick 	if (cddebug & CDB_IO)
43941480Smckusick 		printf("cdbuffer(%x, %x, %d, %x, %d)\n",
44041480Smckusick 		       cs, bp, bn, addr, bcount);
44141480Smckusick #endif
44241480Smckusick 	/*
44341480Smckusick 	 * Determine which component bn falls in.
44441480Smckusick 	 */
44541480Smckusick 	cbn = bn;
44641480Smckusick 	cboff = 0;
44741480Smckusick 	/*
44841480Smckusick 	 * Serially concatenated
44941480Smckusick 	 */
45041480Smckusick 	if (cs->sc_ileave == 0) {
45141480Smckusick 		register daddr_t sblk;
45241480Smckusick 
45341480Smckusick 		sblk = 0;
45441480Smckusick 		for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
45541480Smckusick 			sblk += ci->ci_size;
45641480Smckusick 		cbn -= sblk;
45741480Smckusick 	}
45841480Smckusick 	/*
45941480Smckusick 	 * Interleaved
46041480Smckusick 	 */
46141480Smckusick 	else {
46241480Smckusick 		register struct cdiinfo *ii;
46341480Smckusick 		int cdisk, off;
46441480Smckusick 
46541480Smckusick 		cboff = cbn % cs->sc_ileave;
46641480Smckusick 		cbn /= cs->sc_ileave;
46741480Smckusick 		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
46841480Smckusick 			if (ii->ii_startblk > cbn)
46941480Smckusick 				break;
47041480Smckusick 		ii--;
47141480Smckusick 		off = cbn - ii->ii_startblk;
47241480Smckusick 		if (ii->ii_ndisk == 1) {
47341480Smckusick 			cdisk = ii->ii_index[0];
47441480Smckusick 			cbn = ii->ii_startoff + off;
47541480Smckusick 		} else {
47641480Smckusick 			cdisk = ii->ii_index[off % ii->ii_ndisk];
47741480Smckusick 			cbn = ii->ii_startoff + off / ii->ii_ndisk;
47841480Smckusick 		}
47941480Smckusick 		cbn *= cs->sc_ileave;
48041480Smckusick 		ci = &cs->sc_cinfo[cdisk];
48141480Smckusick 	}
48241480Smckusick 	/*
48341480Smckusick 	 * Fill in the component buf structure.
48441480Smckusick 	 */
48541480Smckusick 	cbp = getcbuf();
48641480Smckusick 	cbp->b_flags = bp->b_flags | B_CALL;
48741480Smckusick 	cbp->b_iodone = cdiodone;
48841480Smckusick 	cbp->b_proc = bp->b_proc;
48941480Smckusick 	cbp->b_dev = ci->ci_dev;
49041480Smckusick 	cbp->b_blkno = cbn + cboff;
49141480Smckusick 	cbp->b_un.b_addr = addr;
49245480Smckusick 	cbp->b_vp = 0;
49341480Smckusick 	if (cs->sc_ileave == 0)
49441480Smckusick 		cbp->b_bcount = dbtob(ci->ci_size - cbn);
49541480Smckusick 	else
49641480Smckusick 		cbp->b_bcount = dbtob(cs->sc_ileave - cboff);
49741480Smckusick 	if (cbp->b_bcount > bcount)
49841480Smckusick 		cbp->b_bcount = bcount;
49941480Smckusick 	/*
50041480Smckusick 	 * XXX: context for cdiodone
50141480Smckusick 	 */
50245480Smckusick 	cbp->b_saveaddr = (caddr_t)bp;
50341480Smckusick 	cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo);
50441480Smckusick #ifdef DEBUG
50541480Smckusick 	if (cddebug & CDB_IO)
50641480Smckusick 		printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
50741480Smckusick 		       ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno,
50841480Smckusick 		       cbp->b_un.b_addr, cbp->b_bcount);
50941480Smckusick #endif
51041480Smckusick 	return(cbp);
51141480Smckusick }
51241480Smckusick 
51341480Smckusick cdintr(unit)
51441480Smckusick 	int unit;
51541480Smckusick {
51641480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
51741480Smckusick 	register struct buf *bp = cs->sc_bp;
51841480Smckusick 
51941480Smckusick #ifdef DEBUG
52041480Smckusick 	if (cddebug & CDB_FOLLOW)
52145480Smckusick 		printf("cdintr(%d): bp %x\n", unit, bp);
52241480Smckusick #endif
52341480Smckusick 	/*
52441480Smckusick 	 * Request is done for better or worse, wakeup the top half.
52541480Smckusick 	 */
52641480Smckusick 	if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0)
52741480Smckusick 		dk_busy &= ~(1 << cs->sc_dk);
52841480Smckusick 	if (bp->b_flags & B_ERROR)
52941480Smckusick 		bp->b_resid = bp->b_bcount;
53045480Smckusick 	biodone(bp);
53141480Smckusick }
53241480Smckusick 
53341480Smckusick /*
53445480Smckusick  * Called by biodone at interrupt time.
53541480Smckusick  * Mark the component as done and if all components are done,
53641480Smckusick  * take a cd interrupt.
53741480Smckusick  */
53841480Smckusick cdiodone(cbp)
53941480Smckusick 	register struct buf *cbp;
54041480Smckusick {
54145480Smckusick 	register struct buf *bp = (struct buf *)cbp->b_saveaddr;/* XXX */
54241480Smckusick 	register int unit = (cbp->b_pfcent >> 16) & 0xFFFF;	/* XXX */
54341480Smckusick 	int count, s;
54441480Smckusick 
54541480Smckusick 	s = splbio();
54641480Smckusick #ifdef DEBUG
54741480Smckusick 	if (cddebug & CDB_FOLLOW)
54841480Smckusick 		printf("cdiodone(%x)\n", cbp);
54941480Smckusick 	if (cddebug & CDB_IO) {
55041480Smckusick 		printf("cdiodone: bp %x bcount %d resid %d\n",
55141480Smckusick 		       bp, bp->b_bcount, bp->b_resid);
55241480Smckusick 		printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
55341480Smckusick 		       cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp,
55441480Smckusick 		       cbp->b_blkno, cbp->b_un.b_addr, cbp->b_bcount);
55541480Smckusick 	}
55641480Smckusick #endif
55741480Smckusick 
55841480Smckusick 	if (cbp->b_flags & B_ERROR) {
55941480Smckusick 		bp->b_flags |= B_ERROR;
56045480Smckusick 		bp->b_error = biowait(cbp);
56141480Smckusick #ifdef DEBUG
56241480Smckusick 		printf("cd%d: error %d on component %d\n",
56341480Smckusick 		       unit, bp->b_error, cbp->b_pfcent & 0xFFFF);
56441480Smckusick #endif
56541480Smckusick 	}
56641480Smckusick 	count = cbp->b_bcount;
56741480Smckusick 	putcbuf(cbp);
56841480Smckusick 
56941480Smckusick 	/*
57041480Smckusick 	 * If all done, "interrupt".
57141480Smckusick 	 * Again, sc_bp is only used to preserve the traditional interface.
57241480Smckusick 	 */
57341480Smckusick 	bp->b_resid -= count;
57441480Smckusick 	if (bp->b_resid < 0)
57541480Smckusick 		panic("cdiodone: count");
57641480Smckusick 	if (bp->b_resid == 0) {
57741480Smckusick 		cd_softc[unit].sc_bp = bp;
57841480Smckusick 		cdintr(unit);
57941480Smckusick 	}
58041480Smckusick 	splx(s);
58141480Smckusick }
58241480Smckusick 
58341480Smckusick cdread(dev, uio)
58441480Smckusick 	dev_t dev;
58541480Smckusick 	struct uio *uio;
58641480Smckusick {
58741480Smckusick 	register int unit = cdunit(dev);
58841480Smckusick 
58941480Smckusick #ifdef DEBUG
59041480Smckusick 	if (cddebug & CDB_FOLLOW)
59141480Smckusick 		printf("cdread(%x, %x)\n", dev, uio);
59241480Smckusick #endif
59341480Smckusick 	return(physio(cdstrategy, &cdbuf[unit], dev, B_READ, minphys, uio));
59441480Smckusick }
59541480Smckusick 
59641480Smckusick cdwrite(dev, uio)
59741480Smckusick 	dev_t dev;
59841480Smckusick 	struct uio *uio;
59941480Smckusick {
60041480Smckusick 	register int unit = cdunit(dev);
60141480Smckusick 
60241480Smckusick #ifdef DEBUG
60341480Smckusick 	if (cddebug & CDB_FOLLOW)
60441480Smckusick 		printf("cdwrite(%x, %x)\n", dev, uio);
60541480Smckusick #endif
60641480Smckusick 	return(physio(cdstrategy, &cdbuf[unit], dev, B_WRITE, minphys, uio));
60741480Smckusick }
60841480Smckusick 
60941480Smckusick cdioctl(dev, cmd, data, flag)
61041480Smckusick 	dev_t dev;
61141480Smckusick 	int cmd;
61241480Smckusick 	caddr_t data;
61341480Smckusick 	int flag;
61441480Smckusick {
61541480Smckusick 	return(EINVAL);
61641480Smckusick }
61741480Smckusick 
61841480Smckusick cdsize(dev)
61941480Smckusick 	dev_t dev;
62041480Smckusick {
62141480Smckusick 	int unit = cdunit(dev);
62241480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
62341480Smckusick 
62441480Smckusick 	if (unit >= NCD || (cs->sc_flags & CDF_INITED) == 0)
62541480Smckusick 		return(-1);
62641480Smckusick 	return(cs->sc_size);
62741480Smckusick }
62841480Smckusick 
62941480Smckusick cddump(dev)
63041480Smckusick {
63141480Smckusick 	return(ENXIO);
63241480Smckusick }
63341480Smckusick #endif
634