xref: /csrg-svn/sys/dev/cd.c (revision 49302)
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  *
12*49302Shibler  * from: Utah $Hdr: cd.c 1.6 90/11/28$
1341480Smckusick  *
14*49302Shibler  *	@(#)cd.c	7.4 (Berkeley) 05/07/91
1541480Smckusick  */
1641480Smckusick 
1741480Smckusick /*
1841480Smckusick  * "Concatenated" disk driver.
1941480Smckusick  */
2041480Smckusick #include "cd.h"
2141480Smckusick #if NCD > 0
2241480Smckusick 
2345788Sbostic #include "sys/param.h"
2445788Sbostic #include "sys/systm.h"
2545788Sbostic #include "sys/errno.h"
2645788Sbostic #include "sys/dkstat.h"
2745788Sbostic #include "sys/buf.h"
2845788Sbostic #include "sys/malloc.h"
2945788Sbostic #include "sys/conf.h"
3041480Smckusick 
3141480Smckusick #include "cdvar.h"
3241480Smckusick 
3341480Smckusick #ifdef DEBUG
3441480Smckusick int cddebug = 0x00;
3541480Smckusick #define CDB_FOLLOW	0x01
3641480Smckusick #define CDB_INIT	0x02
3741480Smckusick #define CDB_IO		0x04
3841480Smckusick #endif
3941480Smckusick 
4041480Smckusick struct	buf cdbuf[NCD];
4141480Smckusick struct	buf *cdbuffer();
42*49302Shibler char	*cddevtostr();
4341480Smckusick int	cdiodone();
4441480Smckusick 
4541480Smckusick #define	cdunit(x)	((minor(x) >> 3) & 0x7)	/* for consistency */
4641480Smckusick 
4741480Smckusick #define	getcbuf()	\
4841480Smckusick 	((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK))
4941480Smckusick #define putcbuf(bp)	\
5041480Smckusick 	free((caddr_t)(bp), M_DEVBUF)
5141480Smckusick 
5241480Smckusick struct cd_softc {
5341480Smckusick 	int		 sc_flags;		/* flags */
5441480Smckusick 	size_t		 sc_size;		/* size of cd */
5541480Smckusick 	int		 sc_ileave;		/* interleave */
5641480Smckusick 	int		 sc_ncdisks;		/* number of components */
5741480Smckusick 	struct cdcinfo	 sc_cinfo[NCDISKS];	/* component info */
5841480Smckusick 	struct cdiinfo	 *sc_itable;		/* interleave table */
5941480Smckusick 	int		 sc_usecnt;		/* number of requests active */
6041480Smckusick 	struct buf	 *sc_bp;		/* "current" request */
6141480Smckusick 	int		 sc_dk;			/* disk index */
6241480Smckusick } cd_softc[NCD];
6341480Smckusick 
6441480Smckusick /* sc_flags */
6541480Smckusick #define	CDF_ALIVE	0x01
6641480Smckusick #define CDF_INITED	0x02
6741480Smckusick 
6841480Smckusick cdinit(cd)
6941480Smckusick 	struct cddevice *cd;
7041480Smckusick {
7141480Smckusick 	register struct cd_softc *cs = &cd_softc[cd->cd_unit];
7241480Smckusick 	register struct cdcinfo *ci;
7341480Smckusick 	register size_t size;
7441480Smckusick 	register int ix;
7541480Smckusick 	size_t minsize;
7641480Smckusick 	dev_t dev;
7741480Smckusick 
7841480Smckusick #ifdef DEBUG
7941480Smckusick 	if (cddebug & (CDB_FOLLOW|CDB_INIT))
8041480Smckusick 		printf("cdinit: unit %d\n", cd->cd_unit);
8141480Smckusick #endif
8241480Smckusick 	cs->sc_dk = cd->cd_dk;
8341480Smckusick 	cs->sc_size = 0;
8441480Smckusick 	cs->sc_ileave = cd->cd_interleave;
8541480Smckusick 	cs->sc_ncdisks = 0;
8641480Smckusick 	/*
8741480Smckusick 	 * Verify that each component piece exists and record
8841480Smckusick 	 * relevant information about it.
8941480Smckusick 	 */
9041480Smckusick 	minsize = 0;
9141480Smckusick 	for (ix = 0; ix < NCDISKS; ix++) {
9241480Smckusick 		if ((dev = cd->cd_dev[ix]) == NODEV)
9341480Smckusick 			break;
9441480Smckusick 		ci = &cs->sc_cinfo[ix];
9541480Smckusick 		ci->ci_dev = dev;
9641480Smckusick 		/*
9741480Smckusick 		 * Calculate size (truncated to interleave boundary
9841480Smckusick 		 * if necessary.
9941480Smckusick 		 */
10041480Smckusick 		if (bdevsw[major(dev)].d_psize) {
101*49302Shibler 			size = (size_t) (*bdevsw[major(dev)].d_psize)(dev);
102*49302Shibler 			if ((int)size < 0)
10341480Smckusick 				size = 0;
10441480Smckusick 		} else
10541480Smckusick 			size = 0;
10641480Smckusick 		if (cs->sc_ileave > 1)
10741480Smckusick 			size -= size % cs->sc_ileave;
108*49302Shibler 		if (size == 0) {
109*49302Shibler 			printf("cd%d: not configured (component %s missing)\n",
110*49302Shibler 			       cd->cd_unit, cddevtostr(ci->ci_dev));
11141480Smckusick 			return(0);
112*49302Shibler 		}
11341480Smckusick 		if (minsize == 0 || size < minsize)
11441480Smckusick 			minsize = size;
11541480Smckusick 		ci->ci_size = size;
11641480Smckusick 		cs->sc_size += size;
11741480Smckusick 		cs->sc_ncdisks++;
11841480Smckusick 	}
11941480Smckusick 	/*
12041480Smckusick 	 * If uniform interleave is desired set all sizes to that of
12141480Smckusick 	 * the smallest component.
12241480Smckusick 	 */
12341480Smckusick 	if (cd->cd_flags & CDF_UNIFORM) {
12441480Smckusick 		for (ci = cs->sc_cinfo;
12541480Smckusick 		     ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
12641480Smckusick 			ci->ci_size = minsize;
12741480Smckusick 		cs->sc_size = cs->sc_ncdisks * minsize;
12841480Smckusick 	}
12941480Smckusick 	/*
13041480Smckusick 	 * Construct the interleave table
13141480Smckusick 	 */
13241480Smckusick 	if (!cdinterleave(cs))
13341480Smckusick 		return(0);
13441480Smckusick 	if (cd->cd_dk >= 0)
13541480Smckusick 		dk_wpms[cd->cd_dk] = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
136*49302Shibler 	printf("cd%d: %d components ", cd->cd_unit, cs->sc_ncdisks);
137*49302Shibler 	for (ix = 0; ix < cs->sc_ncdisks; ix++)
138*49302Shibler 		printf("%c%s%c",
139*49302Shibler 		       ix == 0 ? '(' : ' ',
140*49302Shibler 		       cddevtostr(cs->sc_cinfo[ix].ci_dev),
141*49302Shibler 		       ix == cs->sc_ncdisks - 1 ? ')' : ',');
142*49302Shibler 	printf(", %d blocks ", cs->sc_size);
14341480Smckusick 	if (cs->sc_ileave)
144*49302Shibler 		printf("interleaved at %d blocks\n", cs->sc_ileave);
14541480Smckusick 	else
146*49302Shibler 		printf("concatenated\n");
14741480Smckusick 	cs->sc_flags = CDF_ALIVE | CDF_INITED;
14841480Smckusick 	return(1);
14941480Smckusick }
15041480Smckusick 
151*49302Shibler /*
152*49302Shibler  * XXX not really cd specific.
153*49302Shibler  */
154*49302Shibler char *
155*49302Shibler cddevtostr(dev)
156*49302Shibler 	dev_t dev;
157*49302Shibler {
158*49302Shibler 	static char dbuf[5];
159*49302Shibler 
160*49302Shibler 	dbuf[1] = 'd';
161*49302Shibler 	switch (major(dev)) {
162*49302Shibler 	case 2:
163*49302Shibler 		dbuf[0] = 'r';
164*49302Shibler 		break;
165*49302Shibler 	case 4:
166*49302Shibler 		dbuf[0] = 's';
167*49302Shibler 		break;
168*49302Shibler 	case 5:
169*49302Shibler 		dbuf[0] = 'c';
170*49302Shibler 		break;
171*49302Shibler 	default:
172*49302Shibler 		dbuf[0] = dbuf[1] = '?';
173*49302Shibler 		break;
174*49302Shibler 	}
175*49302Shibler 	dbuf[2] = (minor(dev) >> 3) + '0';
176*49302Shibler 	dbuf[3] = (minor(dev) & 7) + 'a';
177*49302Shibler 	dbuf[4] = '\0';
178*49302Shibler 	return (dbuf);
179*49302Shibler }
180*49302Shibler 
18141480Smckusick cdinterleave(cs)
18241480Smckusick 	register struct cd_softc *cs;
18341480Smckusick {
18441480Smckusick 	register struct cdcinfo *ci, *smallci;
18541480Smckusick 	register struct cdiinfo *ii;
18641480Smckusick 	register daddr_t bn, lbn;
18741480Smckusick 	register int ix;
18841480Smckusick 	u_long size;
18941480Smckusick 
19041480Smckusick #ifdef DEBUG
19141480Smckusick 	if (cddebug & CDB_INIT)
19241480Smckusick 		printf("cdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
19341480Smckusick #endif
19441480Smckusick 	/*
19541480Smckusick 	 * Allocate an interleave table.
19641480Smckusick 	 * Chances are this is too big, but we don't care.
19741480Smckusick 	 */
19841480Smckusick 	size = (cs->sc_ncdisks + 1) * sizeof(struct cdiinfo);
19941480Smckusick 	cs->sc_itable = (struct cdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
20041480Smckusick 	bzero((caddr_t)cs->sc_itable, size);
20141480Smckusick 	/*
20241480Smckusick 	 * Trivial case: no interleave (actually interleave of disk size).
20341480Smckusick 	 * Each table entry represent a single component in its entirety.
20441480Smckusick 	 */
20541480Smckusick 	if (cs->sc_ileave == 0) {
20641480Smckusick 		bn = 0;
20741480Smckusick 		ii = cs->sc_itable;
20841480Smckusick 		for (ix = 0; ix < cs->sc_ncdisks; ix++) {
20941480Smckusick 			ii->ii_ndisk = 1;
21041480Smckusick 			ii->ii_startblk = bn;
21141480Smckusick 			ii->ii_startoff = 0;
21241480Smckusick 			ii->ii_index[0] = ix;
21341480Smckusick 			bn += cs->sc_cinfo[ix].ci_size;
21441480Smckusick 			ii++;
21541480Smckusick 		}
21641480Smckusick 		ii->ii_ndisk = 0;
21741480Smckusick #ifdef DEBUG
21841480Smckusick 		if (cddebug & CDB_INIT)
21941480Smckusick 			printiinfo(cs->sc_itable);
22041480Smckusick #endif
22141480Smckusick 		return(1);
22241480Smckusick 	}
22341480Smckusick 	/*
22441480Smckusick 	 * The following isn't fast or pretty; it doesn't have to be.
22541480Smckusick 	 */
22641480Smckusick 	size = 0;
22741480Smckusick 	bn = lbn = 0;
22841480Smckusick 	for (ii = cs->sc_itable; ; ii++) {
22941480Smckusick 		/*
23041480Smckusick 		 * Locate the smallest of the remaining components
23141480Smckusick 		 */
23241480Smckusick 		smallci = NULL;
23341480Smckusick 		for (ci = cs->sc_cinfo;
23441480Smckusick 		     ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
23541480Smckusick 			if (ci->ci_size > size &&
23641480Smckusick 			    (smallci == NULL ||
23741480Smckusick 			     ci->ci_size < smallci->ci_size))
23841480Smckusick 				smallci = ci;
23941480Smckusick 		/*
24041480Smckusick 		 * Nobody left, all done
24141480Smckusick 		 */
24241480Smckusick 		if (smallci == NULL) {
24341480Smckusick 			ii->ii_ndisk = 0;
24441480Smckusick 			break;
24541480Smckusick 		}
24641480Smckusick 		/*
24741480Smckusick 		 * Record starting logical block and component offset
24841480Smckusick 		 */
24941480Smckusick 		ii->ii_startblk = bn / cs->sc_ileave;
25041480Smckusick 		ii->ii_startoff = lbn;
25141480Smckusick 		/*
25241480Smckusick 		 * Determine how many disks take part in this interleave
25341480Smckusick 		 * and record their indices.
25441480Smckusick 		 */
25541480Smckusick 		ix = 0;
25641480Smckusick 		for (ci = cs->sc_cinfo;
25741480Smckusick 		     ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
25841480Smckusick 			if (ci->ci_size >= smallci->ci_size)
25941480Smckusick 				ii->ii_index[ix++] = ci - cs->sc_cinfo;
26041480Smckusick 		ii->ii_ndisk = ix;
26141480Smckusick 		bn += ix * (smallci->ci_size - size);
26241480Smckusick 		lbn = smallci->ci_size / cs->sc_ileave;
26341480Smckusick 		size = smallci->ci_size;
26441480Smckusick 	}
26541480Smckusick #ifdef DEBUG
26641480Smckusick 	if (cddebug & CDB_INIT)
26741480Smckusick 		printiinfo(cs->sc_itable);
26841480Smckusick #endif
26941480Smckusick 	return(1);
27041480Smckusick }
27141480Smckusick 
27241480Smckusick #ifdef DEBUG
27341480Smckusick printiinfo(ii)
27441480Smckusick 	struct cdiinfo *ii;
27541480Smckusick {
27641480Smckusick 	register int ix, i;
27741480Smckusick 
27841480Smckusick 	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
27941480Smckusick 		printf(" itab[%d]: #dk %d sblk %d soff %d",
28041480Smckusick 		       ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
28141480Smckusick 		for (i = 0; i < ii->ii_ndisk; i++)
28241480Smckusick 			printf(" %d", ii->ii_index[i]);
28341480Smckusick 		printf("\n");
28441480Smckusick 	}
28541480Smckusick }
28641480Smckusick #endif
28741480Smckusick 
28841480Smckusick cdopen(dev, flags)
28941480Smckusick 	dev_t dev;
29041480Smckusick {
29141480Smckusick 	int unit = cdunit(dev);
29241480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
29341480Smckusick 
29441480Smckusick #ifdef DEBUG
29541480Smckusick 	if (cddebug & CDB_FOLLOW)
29641480Smckusick 		printf("cdopen(%x, %x)\n", dev, flags);
29741480Smckusick #endif
29841480Smckusick 	if (unit >= NCD || (cs->sc_flags & CDF_ALIVE) == 0)
29941480Smckusick 		return(ENXIO);
30041480Smckusick 	return(0);
30141480Smckusick }
30241480Smckusick 
30341480Smckusick cdstrategy(bp)
30441480Smckusick 	register struct buf *bp;
30541480Smckusick {
30641480Smckusick 	register int unit = cdunit(bp->b_dev);
30741480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
30845480Smckusick 	register daddr_t bn;
30945480Smckusick 	register int sz, s;
31041480Smckusick 
31141480Smckusick #ifdef DEBUG
31241480Smckusick 	if (cddebug & CDB_FOLLOW)
31341480Smckusick 		printf("cdstrategy(%x): unit %d\n", bp, unit);
31441480Smckusick #endif
31541480Smckusick 	if ((cs->sc_flags & CDF_INITED) == 0) {
31641480Smckusick 		bp->b_error = ENXIO;
31745480Smckusick 		bp->b_flags |= B_ERROR;
31845480Smckusick 		goto done;
31941480Smckusick 	}
32041480Smckusick 	bn = bp->b_blkno;
32145480Smckusick 	sz = howmany(bp->b_bcount, DEV_BSIZE);
32241480Smckusick 	if (bn < 0 || bn + sz > cs->sc_size) {
32345480Smckusick 		sz = cs->sc_size - bn;
32445480Smckusick 		if (sz == 0) {
32545480Smckusick 			bp->b_resid = bp->b_bcount;
32641480Smckusick 			goto done;
32745480Smckusick 		}
32845480Smckusick 		if (sz < 0) {
32945480Smckusick 			bp->b_error = EINVAL;
33045480Smckusick 			bp->b_flags |= B_ERROR;
33145480Smckusick 			goto done;
33245480Smckusick 		}
33345480Smckusick 		bp->b_bcount = dbtob(sz);
33441480Smckusick 	}
33545480Smckusick 	bp->b_resid = bp->b_bcount;
33641480Smckusick 	/*
33741480Smckusick 	 * "Start" the unit.
33841480Smckusick 	 * XXX: the use of sc_bp is just to retain the "traditional"
33941480Smckusick 	 * interface to the start routine.
34041480Smckusick 	 */
34141480Smckusick 	s = splbio();
34241480Smckusick 	cs->sc_bp = bp;
34341480Smckusick 	cdstart(unit);
34441480Smckusick 	splx(s);
34541480Smckusick 	return;
34641480Smckusick done:
34745480Smckusick 	biodone(bp);
34841480Smckusick }
34941480Smckusick 
35041480Smckusick cdstart(unit)
35141480Smckusick 	int unit;
35241480Smckusick {
35341480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
35441480Smckusick 	register struct buf *bp = cs->sc_bp;
35541480Smckusick 	register long bcount, rcount;
35641480Smckusick 	struct buf *cbp;
35741480Smckusick 	caddr_t addr;
35841480Smckusick 	daddr_t bn;
35941480Smckusick 
36041480Smckusick #ifdef DEBUG
36141480Smckusick 	if (cddebug & CDB_FOLLOW)
36241480Smckusick 		printf("cdstart(%d)\n", unit);
36341480Smckusick #endif
36441480Smckusick 	/*
36541480Smckusick 	 * Instumentation (not real meaningful)
36641480Smckusick 	 */
36741480Smckusick 	cs->sc_usecnt++;
36841480Smckusick 	if (cs->sc_dk >= 0) {
36941480Smckusick 		dk_busy |= 1 << cs->sc_dk;
37041480Smckusick 		dk_xfer[cs->sc_dk]++;
37141480Smckusick 		dk_wds[cs->sc_dk] += bp->b_bcount >> 6;
37241480Smckusick 	}
37341480Smckusick 	/*
37441480Smckusick 	 * Allocate component buffers and fire off the requests
37541480Smckusick 	 */
37641480Smckusick 	bn = bp->b_blkno;
37741480Smckusick 	addr = bp->b_un.b_addr;
37841480Smckusick 	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
37941480Smckusick 		cbp = cdbuffer(cs, bp, bn, addr, bcount);
38041480Smckusick 		rcount = cbp->b_bcount;
38141480Smckusick 		(*bdevsw[major(cbp->b_dev)].d_strategy)(cbp);
38241480Smckusick 		bn += btodb(rcount);
38341480Smckusick 		addr += rcount;
38441480Smckusick 	}
38541480Smckusick }
38641480Smckusick 
38741480Smckusick /*
38841480Smckusick  * Build a component buffer header.
38941480Smckusick  */
39041480Smckusick struct buf *
39141480Smckusick cdbuffer(cs, bp, bn, addr, bcount)
39241480Smckusick 	register struct cd_softc *cs;
39341480Smckusick 	struct buf *bp;
39441480Smckusick 	daddr_t bn;
39541480Smckusick 	caddr_t addr;
39641480Smckusick 	long bcount;
39741480Smckusick {
39841480Smckusick 	register struct cdcinfo *ci;
39941480Smckusick 	register struct buf *cbp;
40041480Smckusick 	register daddr_t cbn, cboff;
40141480Smckusick 
40241480Smckusick #ifdef DEBUG
40341480Smckusick 	if (cddebug & CDB_IO)
40441480Smckusick 		printf("cdbuffer(%x, %x, %d, %x, %d)\n",
40541480Smckusick 		       cs, bp, bn, addr, bcount);
40641480Smckusick #endif
40741480Smckusick 	/*
40841480Smckusick 	 * Determine which component bn falls in.
40941480Smckusick 	 */
41041480Smckusick 	cbn = bn;
41141480Smckusick 	cboff = 0;
41241480Smckusick 	/*
41341480Smckusick 	 * Serially concatenated
41441480Smckusick 	 */
41541480Smckusick 	if (cs->sc_ileave == 0) {
41641480Smckusick 		register daddr_t sblk;
41741480Smckusick 
41841480Smckusick 		sblk = 0;
41941480Smckusick 		for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
42041480Smckusick 			sblk += ci->ci_size;
42141480Smckusick 		cbn -= sblk;
42241480Smckusick 	}
42341480Smckusick 	/*
42441480Smckusick 	 * Interleaved
42541480Smckusick 	 */
42641480Smckusick 	else {
42741480Smckusick 		register struct cdiinfo *ii;
42841480Smckusick 		int cdisk, off;
42941480Smckusick 
43041480Smckusick 		cboff = cbn % cs->sc_ileave;
43141480Smckusick 		cbn /= cs->sc_ileave;
43241480Smckusick 		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
43341480Smckusick 			if (ii->ii_startblk > cbn)
43441480Smckusick 				break;
43541480Smckusick 		ii--;
43641480Smckusick 		off = cbn - ii->ii_startblk;
43741480Smckusick 		if (ii->ii_ndisk == 1) {
43841480Smckusick 			cdisk = ii->ii_index[0];
43941480Smckusick 			cbn = ii->ii_startoff + off;
44041480Smckusick 		} else {
44141480Smckusick 			cdisk = ii->ii_index[off % ii->ii_ndisk];
44241480Smckusick 			cbn = ii->ii_startoff + off / ii->ii_ndisk;
44341480Smckusick 		}
44441480Smckusick 		cbn *= cs->sc_ileave;
44541480Smckusick 		ci = &cs->sc_cinfo[cdisk];
44641480Smckusick 	}
44741480Smckusick 	/*
44841480Smckusick 	 * Fill in the component buf structure.
44941480Smckusick 	 */
45041480Smckusick 	cbp = getcbuf();
45141480Smckusick 	cbp->b_flags = bp->b_flags | B_CALL;
45241480Smckusick 	cbp->b_iodone = cdiodone;
45341480Smckusick 	cbp->b_proc = bp->b_proc;
45441480Smckusick 	cbp->b_dev = ci->ci_dev;
45541480Smckusick 	cbp->b_blkno = cbn + cboff;
45641480Smckusick 	cbp->b_un.b_addr = addr;
45745480Smckusick 	cbp->b_vp = 0;
45841480Smckusick 	if (cs->sc_ileave == 0)
45941480Smckusick 		cbp->b_bcount = dbtob(ci->ci_size - cbn);
46041480Smckusick 	else
46141480Smckusick 		cbp->b_bcount = dbtob(cs->sc_ileave - cboff);
46241480Smckusick 	if (cbp->b_bcount > bcount)
46341480Smckusick 		cbp->b_bcount = bcount;
46441480Smckusick 	/*
46541480Smckusick 	 * XXX: context for cdiodone
46641480Smckusick 	 */
46745480Smckusick 	cbp->b_saveaddr = (caddr_t)bp;
46841480Smckusick 	cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo);
46941480Smckusick #ifdef DEBUG
47041480Smckusick 	if (cddebug & CDB_IO)
47141480Smckusick 		printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
47241480Smckusick 		       ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno,
47341480Smckusick 		       cbp->b_un.b_addr, cbp->b_bcount);
47441480Smckusick #endif
47541480Smckusick 	return(cbp);
47641480Smckusick }
47741480Smckusick 
47841480Smckusick cdintr(unit)
47941480Smckusick 	int unit;
48041480Smckusick {
48141480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
48241480Smckusick 	register struct buf *bp = cs->sc_bp;
48341480Smckusick 
48441480Smckusick #ifdef DEBUG
48541480Smckusick 	if (cddebug & CDB_FOLLOW)
48645480Smckusick 		printf("cdintr(%d): bp %x\n", unit, bp);
48741480Smckusick #endif
48841480Smckusick 	/*
48941480Smckusick 	 * Request is done for better or worse, wakeup the top half.
49041480Smckusick 	 */
49141480Smckusick 	if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0)
49241480Smckusick 		dk_busy &= ~(1 << cs->sc_dk);
49341480Smckusick 	if (bp->b_flags & B_ERROR)
49441480Smckusick 		bp->b_resid = bp->b_bcount;
49545480Smckusick 	biodone(bp);
49641480Smckusick }
49741480Smckusick 
49841480Smckusick /*
49945480Smckusick  * Called by biodone at interrupt time.
50041480Smckusick  * Mark the component as done and if all components are done,
50141480Smckusick  * take a cd interrupt.
50241480Smckusick  */
50341480Smckusick cdiodone(cbp)
50441480Smckusick 	register struct buf *cbp;
50541480Smckusick {
50645480Smckusick 	register struct buf *bp = (struct buf *)cbp->b_saveaddr;/* XXX */
50741480Smckusick 	register int unit = (cbp->b_pfcent >> 16) & 0xFFFF;	/* XXX */
50841480Smckusick 	int count, s;
50941480Smckusick 
51041480Smckusick 	s = splbio();
51141480Smckusick #ifdef DEBUG
51241480Smckusick 	if (cddebug & CDB_FOLLOW)
51341480Smckusick 		printf("cdiodone(%x)\n", cbp);
51441480Smckusick 	if (cddebug & CDB_IO) {
51541480Smckusick 		printf("cdiodone: bp %x bcount %d resid %d\n",
51641480Smckusick 		       bp, bp->b_bcount, bp->b_resid);
51741480Smckusick 		printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
51841480Smckusick 		       cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp,
51941480Smckusick 		       cbp->b_blkno, cbp->b_un.b_addr, cbp->b_bcount);
52041480Smckusick 	}
52141480Smckusick #endif
52241480Smckusick 
52341480Smckusick 	if (cbp->b_flags & B_ERROR) {
52441480Smckusick 		bp->b_flags |= B_ERROR;
52545480Smckusick 		bp->b_error = biowait(cbp);
52641480Smckusick #ifdef DEBUG
52741480Smckusick 		printf("cd%d: error %d on component %d\n",
52841480Smckusick 		       unit, bp->b_error, cbp->b_pfcent & 0xFFFF);
52941480Smckusick #endif
53041480Smckusick 	}
53141480Smckusick 	count = cbp->b_bcount;
53241480Smckusick 	putcbuf(cbp);
53341480Smckusick 
53441480Smckusick 	/*
53541480Smckusick 	 * If all done, "interrupt".
53641480Smckusick 	 * Again, sc_bp is only used to preserve the traditional interface.
53741480Smckusick 	 */
53841480Smckusick 	bp->b_resid -= count;
53941480Smckusick 	if (bp->b_resid < 0)
54041480Smckusick 		panic("cdiodone: count");
54141480Smckusick 	if (bp->b_resid == 0) {
54241480Smckusick 		cd_softc[unit].sc_bp = bp;
54341480Smckusick 		cdintr(unit);
54441480Smckusick 	}
54541480Smckusick 	splx(s);
54641480Smckusick }
54741480Smckusick 
54841480Smckusick cdread(dev, uio)
54941480Smckusick 	dev_t dev;
55041480Smckusick 	struct uio *uio;
55141480Smckusick {
55241480Smckusick 	register int unit = cdunit(dev);
55341480Smckusick 
55441480Smckusick #ifdef DEBUG
55541480Smckusick 	if (cddebug & CDB_FOLLOW)
55641480Smckusick 		printf("cdread(%x, %x)\n", dev, uio);
55741480Smckusick #endif
55841480Smckusick 	return(physio(cdstrategy, &cdbuf[unit], dev, B_READ, minphys, uio));
55941480Smckusick }
56041480Smckusick 
56141480Smckusick cdwrite(dev, uio)
56241480Smckusick 	dev_t dev;
56341480Smckusick 	struct uio *uio;
56441480Smckusick {
56541480Smckusick 	register int unit = cdunit(dev);
56641480Smckusick 
56741480Smckusick #ifdef DEBUG
56841480Smckusick 	if (cddebug & CDB_FOLLOW)
56941480Smckusick 		printf("cdwrite(%x, %x)\n", dev, uio);
57041480Smckusick #endif
57141480Smckusick 	return(physio(cdstrategy, &cdbuf[unit], dev, B_WRITE, minphys, uio));
57241480Smckusick }
57341480Smckusick 
57441480Smckusick cdioctl(dev, cmd, data, flag)
57541480Smckusick 	dev_t dev;
57641480Smckusick 	int cmd;
57741480Smckusick 	caddr_t data;
57841480Smckusick 	int flag;
57941480Smckusick {
58041480Smckusick 	return(EINVAL);
58141480Smckusick }
58241480Smckusick 
58341480Smckusick cdsize(dev)
58441480Smckusick 	dev_t dev;
58541480Smckusick {
58641480Smckusick 	int unit = cdunit(dev);
58741480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
58841480Smckusick 
58941480Smckusick 	if (unit >= NCD || (cs->sc_flags & CDF_INITED) == 0)
59041480Smckusick 		return(-1);
59141480Smckusick 	return(cs->sc_size);
59241480Smckusick }
59341480Smckusick 
59441480Smckusick cddump(dev)
59541480Smckusick {
59641480Smckusick 	return(ENXIO);
59741480Smckusick }
59841480Smckusick #endif
599