xref: /csrg-svn/sys/dev/cd.c (revision 68158)
141480Smckusick /*
241480Smckusick  * Copyright (c) 1988 University of Utah.
363144Sbostic  * Copyright (c) 1990, 1993
463144Sbostic  *	The Regents of the University of California.  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*68158Scgd  *	@(#)cd.c	8.3 (Berkeley) 01/09/95
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>
2559851Shibler #include <sys/proc.h>
2656503Sbostic #include <sys/errno.h>
2756503Sbostic #include <sys/dkstat.h>
2856503Sbostic #include <sys/buf.h>
2956503Sbostic #include <sys/malloc.h>
3056503Sbostic #include <sys/conf.h>
3158051Shibler #include <sys/stat.h>
3258051Shibler #ifdef COMPAT_NOLABEL
3358051Shibler #include <sys/ioctl.h>
3458051Shibler #include <sys/disklabel.h>
3558051Shibler #include <sys/fcntl.h>
3658051Shibler #endif
3741480Smckusick 
3856503Sbostic #include <dev/cdvar.h>
3941480Smckusick 
4041480Smckusick #ifdef DEBUG
4141480Smckusick int cddebug = 0x00;
4241480Smckusick #define CDB_FOLLOW	0x01
4341480Smckusick #define CDB_INIT	0x02
4441480Smckusick #define CDB_IO		0x04
4541480Smckusick #endif
4641480Smckusick 
4741480Smckusick struct	buf *cdbuffer();
4849302Shibler char	*cddevtostr();
4959851Shibler void	cdiodone();
5041480Smckusick 
5159851Shibler #define	cdunit(x)	((minor(x) >> 3) & 0xf)	/* 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 	int		 sc_dk;			/* disk index */
6759851Shibler };
6841480Smckusick 
6941480Smckusick /* sc_flags */
7041480Smckusick #define	CDF_ALIVE	0x01
7141480Smckusick #define CDF_INITED	0x02
7241480Smckusick 
7359851Shibler struct cd_softc *cd_softc;
7459851Shibler int numcd;
7559851Shibler 
7659851Shibler /*
7759851Shibler  * Since this is called after auto-configuration of devices,
7859851Shibler  * we can handle the initialization here.
7959851Shibler  *
8059851Shibler  * XXX this will not work if you want to use a cd as your primary
8159851Shibler  * swap device since swapconf() has been called before now.
8259851Shibler  */
8359851Shibler void
cdattach(num)8459851Shibler cdattach(num)
8559851Shibler 	int num;
8659851Shibler {
8759851Shibler 	char *mem;
8859851Shibler 	register u_long size;
8959851Shibler 	register struct cddevice *cd;
9059851Shibler 	extern int dkn;
9159851Shibler 
9259851Shibler 	if (num <= 0)
9359851Shibler 		return;
9459851Shibler 	size = num * sizeof(struct cd_softc);
9559851Shibler 	mem = malloc(size, M_DEVBUF, M_NOWAIT);
9659851Shibler 	if (mem == NULL) {
9759851Shibler 		printf("WARNING: no memory for concatonated disks\n");
9859851Shibler 		return;
9959851Shibler 	}
10059851Shibler 	bzero(mem, size);
10159851Shibler 	cd_softc = (struct cd_softc *)mem;
10259851Shibler 	numcd = num;
10359851Shibler 	for (cd = cddevice; cd->cd_unit >= 0; cd++) {
10459851Shibler 		/*
10559851Shibler 		 * XXX
10659851Shibler 		 * Assign disk index first so that init routine
10759851Shibler 		 * can use it (saves having the driver drag around
10859851Shibler 		 * the cddevice pointer just to set up the dk_*
10959851Shibler 		 * info in the open routine).
11059851Shibler 		 */
11159851Shibler 		if (dkn < DK_NDRIVE)
11259851Shibler 			cd->cd_dk = dkn++;
11359851Shibler 		else
11459851Shibler 			cd->cd_dk = -1;
11559851Shibler 		if (cdinit(cd))
11659851Shibler 			printf("cd%d configured\n", cd->cd_unit);
11759851Shibler 		else if (cd->cd_dk >= 0) {
11859851Shibler 			cd->cd_dk = -1;
11959851Shibler 			dkn--;
12059851Shibler 		}
12159851Shibler 	}
12259851Shibler }
12359851Shibler 
12441480Smckusick cdinit(cd)
12541480Smckusick 	struct cddevice *cd;
12641480Smckusick {
12741480Smckusick 	register struct cd_softc *cs = &cd_softc[cd->cd_unit];
12841480Smckusick 	register struct cdcinfo *ci;
12941480Smckusick 	register size_t size;
13041480Smckusick 	register int ix;
13141480Smckusick 	size_t minsize;
13241480Smckusick 	dev_t dev;
13358051Shibler 	struct bdevsw *bsw;
13458051Shibler 	int error;
13559851Shibler 	struct proc *p = curproc; /* XXX */
13641480Smckusick 
13741480Smckusick #ifdef DEBUG
13841480Smckusick 	if (cddebug & (CDB_FOLLOW|CDB_INIT))
13941480Smckusick 		printf("cdinit: unit %d\n", cd->cd_unit);
14041480Smckusick #endif
14141480Smckusick 	cs->sc_dk = cd->cd_dk;
14241480Smckusick 	cs->sc_size = 0;
14341480Smckusick 	cs->sc_ileave = cd->cd_interleave;
14441480Smckusick 	cs->sc_ncdisks = 0;
14541480Smckusick 	/*
14641480Smckusick 	 * Verify that each component piece exists and record
14741480Smckusick 	 * relevant information about it.
14841480Smckusick 	 */
14941480Smckusick 	minsize = 0;
15041480Smckusick 	for (ix = 0; ix < NCDISKS; ix++) {
15141480Smckusick 		if ((dev = cd->cd_dev[ix]) == NODEV)
15241480Smckusick 			break;
15341480Smckusick 		ci = &cs->sc_cinfo[ix];
15441480Smckusick 		ci->ci_dev = dev;
15558051Shibler 		bsw = &bdevsw[major(dev)];
15641480Smckusick 		/*
15758051Shibler 		 * Open the partition
15858051Shibler 		 */
15959851Shibler 		if (bsw->d_open &&
16059851Shibler 		    (error = (*bsw->d_open)(dev, 0, S_IFBLK, p))) {
16158051Shibler 			printf("cd%d: component %s open failed, error = %d\n",
16258051Shibler 			       cd->cd_unit, cddevtostr(dev), error);
16358051Shibler 			return(0);
16458051Shibler 		}
16558051Shibler 		/*
16641480Smckusick 		 * Calculate size (truncated to interleave boundary
16741480Smckusick 		 * if necessary.
16841480Smckusick 		 */
16958051Shibler 		if (bsw->d_psize) {
17058051Shibler 			size = (size_t) (*bsw->d_psize)(dev);
17149302Shibler 			if ((int)size < 0)
17241480Smckusick 				size = 0;
17341480Smckusick 		} else
17441480Smckusick 			size = 0;
17541480Smckusick 		if (cs->sc_ileave > 1)
17641480Smckusick 			size -= size % cs->sc_ileave;
17749302Shibler 		if (size == 0) {
17849302Shibler 			printf("cd%d: not configured (component %s missing)\n",
17958051Shibler 			       cd->cd_unit, cddevtostr(dev));
18041480Smckusick 			return(0);
18149302Shibler 		}
18258051Shibler #ifdef COMPAT_NOLABEL
18358051Shibler 		/*
18458051Shibler 		 * XXX if this is a 'c' partition then we need to mark the
18558051Shibler 		 * label area writeable since there cannot be a label.
18658051Shibler 		 */
18758051Shibler 		if ((minor(dev) & 7) == 2 && bsw->d_open) {
18858051Shibler 			int i, flag;
18958051Shibler 
19058051Shibler 			for (i = 0; i < nchrdev; i++)
19158051Shibler 				if (cdevsw[i].d_open == bsw->d_open)
19258051Shibler 					break;
19358051Shibler 			if (i != nchrdev && cdevsw[i].d_ioctl) {
19458051Shibler 				flag = 1;
19558051Shibler 				(void)(*cdevsw[i].d_ioctl)(dev, DIOCWLABEL,
19659851Shibler 					(caddr_t)&flag, FWRITE, p);
19758051Shibler 			}
19858051Shibler 		}
19958051Shibler #endif
20041480Smckusick 		if (minsize == 0 || size < minsize)
20141480Smckusick 			minsize = size;
20241480Smckusick 		ci->ci_size = size;
20341480Smckusick 		cs->sc_size += size;
20441480Smckusick 		cs->sc_ncdisks++;
20541480Smckusick 	}
20641480Smckusick 	/*
20741480Smckusick 	 * If uniform interleave is desired set all sizes to that of
20841480Smckusick 	 * the smallest component.
20941480Smckusick 	 */
21041480Smckusick 	if (cd->cd_flags & CDF_UNIFORM) {
21141480Smckusick 		for (ci = cs->sc_cinfo;
21241480Smckusick 		     ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
21341480Smckusick 			ci->ci_size = minsize;
21441480Smckusick 		cs->sc_size = cs->sc_ncdisks * minsize;
21541480Smckusick 	}
21641480Smckusick 	/*
21741480Smckusick 	 * Construct the interleave table
21841480Smckusick 	 */
21941480Smckusick 	if (!cdinterleave(cs))
22041480Smckusick 		return(0);
22141480Smckusick 	if (cd->cd_dk >= 0)
22241480Smckusick 		dk_wpms[cd->cd_dk] = 32 * (60 * DEV_BSIZE / 2);	/* XXX */
22349302Shibler 	printf("cd%d: %d components ", cd->cd_unit, cs->sc_ncdisks);
22449302Shibler 	for (ix = 0; ix < cs->sc_ncdisks; ix++)
22549302Shibler 		printf("%c%s%c",
22649302Shibler 		       ix == 0 ? '(' : ' ',
22749302Shibler 		       cddevtostr(cs->sc_cinfo[ix].ci_dev),
22849302Shibler 		       ix == cs->sc_ncdisks - 1 ? ')' : ',');
22949302Shibler 	printf(", %d blocks ", cs->sc_size);
23041480Smckusick 	if (cs->sc_ileave)
23149302Shibler 		printf("interleaved at %d blocks\n", cs->sc_ileave);
23241480Smckusick 	else
23349302Shibler 		printf("concatenated\n");
23441480Smckusick 	cs->sc_flags = CDF_ALIVE | CDF_INITED;
23541480Smckusick 	return(1);
23641480Smckusick }
23741480Smckusick 
23849302Shibler /*
23949302Shibler  * XXX not really cd specific.
24059851Shibler  * Could be called something like bdevtostr in machine/conf.c.
24149302Shibler  */
24249302Shibler char *
cddevtostr(dev)24349302Shibler cddevtostr(dev)
24449302Shibler 	dev_t dev;
24549302Shibler {
24649302Shibler 	static char dbuf[5];
24749302Shibler 
24849302Shibler 	switch (major(dev)) {
24959851Shibler #ifdef hp300
25049302Shibler 	case 2:
25159851Shibler 		dbuf[0] = 'r'; dbuf[1] = 'd';
25249302Shibler 		break;
25349302Shibler 	case 4:
25459851Shibler 		dbuf[0] = 's'; dbuf[1] = 'd';
25549302Shibler 		break;
25649302Shibler 	case 5:
25759851Shibler 		dbuf[0] = 'c'; dbuf[1] = 'd';
25849302Shibler 		break;
25959851Shibler 	case 6:
26059851Shibler 		dbuf[0] = 'v'; dbuf[1] = 'n';
26159851Shibler 		break;
26259851Shibler #endif
26349302Shibler 	default:
26449302Shibler 		dbuf[0] = dbuf[1] = '?';
26549302Shibler 		break;
26649302Shibler 	}
26749302Shibler 	dbuf[2] = (minor(dev) >> 3) + '0';
26849302Shibler 	dbuf[3] = (minor(dev) & 7) + 'a';
26949302Shibler 	dbuf[4] = '\0';
27049302Shibler 	return (dbuf);
27149302Shibler }
27249302Shibler 
cdinterleave(cs)27341480Smckusick cdinterleave(cs)
27441480Smckusick 	register struct cd_softc *cs;
27541480Smckusick {
27641480Smckusick 	register struct cdcinfo *ci, *smallci;
27741480Smckusick 	register struct cdiinfo *ii;
27841480Smckusick 	register daddr_t bn, lbn;
27941480Smckusick 	register int ix;
28041480Smckusick 	u_long size;
28141480Smckusick 
28241480Smckusick #ifdef DEBUG
28341480Smckusick 	if (cddebug & CDB_INIT)
28441480Smckusick 		printf("cdinterleave(%x): ileave %d\n", cs, cs->sc_ileave);
28541480Smckusick #endif
28641480Smckusick 	/*
28741480Smckusick 	 * Allocate an interleave table.
28841480Smckusick 	 * Chances are this is too big, but we don't care.
28941480Smckusick 	 */
29041480Smckusick 	size = (cs->sc_ncdisks + 1) * sizeof(struct cdiinfo);
29141480Smckusick 	cs->sc_itable = (struct cdiinfo *)malloc(size, M_DEVBUF, M_WAITOK);
29241480Smckusick 	bzero((caddr_t)cs->sc_itable, size);
29341480Smckusick 	/*
29441480Smckusick 	 * Trivial case: no interleave (actually interleave of disk size).
29541480Smckusick 	 * Each table entry represent a single component in its entirety.
29641480Smckusick 	 */
29741480Smckusick 	if (cs->sc_ileave == 0) {
29841480Smckusick 		bn = 0;
29941480Smckusick 		ii = cs->sc_itable;
30041480Smckusick 		for (ix = 0; ix < cs->sc_ncdisks; ix++) {
30141480Smckusick 			ii->ii_ndisk = 1;
30241480Smckusick 			ii->ii_startblk = bn;
30341480Smckusick 			ii->ii_startoff = 0;
30441480Smckusick 			ii->ii_index[0] = ix;
30541480Smckusick 			bn += cs->sc_cinfo[ix].ci_size;
30641480Smckusick 			ii++;
30741480Smckusick 		}
30841480Smckusick 		ii->ii_ndisk = 0;
30941480Smckusick #ifdef DEBUG
31041480Smckusick 		if (cddebug & CDB_INIT)
31141480Smckusick 			printiinfo(cs->sc_itable);
31241480Smckusick #endif
31341480Smckusick 		return(1);
31441480Smckusick 	}
31541480Smckusick 	/*
31641480Smckusick 	 * The following isn't fast or pretty; it doesn't have to be.
31741480Smckusick 	 */
31841480Smckusick 	size = 0;
31941480Smckusick 	bn = lbn = 0;
32041480Smckusick 	for (ii = cs->sc_itable; ; ii++) {
32141480Smckusick 		/*
32241480Smckusick 		 * Locate the smallest of the remaining components
32341480Smckusick 		 */
32441480Smckusick 		smallci = NULL;
32541480Smckusick 		for (ci = cs->sc_cinfo;
32641480Smckusick 		     ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
32741480Smckusick 			if (ci->ci_size > size &&
32841480Smckusick 			    (smallci == NULL ||
32941480Smckusick 			     ci->ci_size < smallci->ci_size))
33041480Smckusick 				smallci = ci;
33141480Smckusick 		/*
33241480Smckusick 		 * Nobody left, all done
33341480Smckusick 		 */
33441480Smckusick 		if (smallci == NULL) {
33541480Smckusick 			ii->ii_ndisk = 0;
33641480Smckusick 			break;
33741480Smckusick 		}
33841480Smckusick 		/*
33941480Smckusick 		 * Record starting logical block and component offset
34041480Smckusick 		 */
34141480Smckusick 		ii->ii_startblk = bn / cs->sc_ileave;
34241480Smckusick 		ii->ii_startoff = lbn;
34341480Smckusick 		/*
34441480Smckusick 		 * Determine how many disks take part in this interleave
34541480Smckusick 		 * and record their indices.
34641480Smckusick 		 */
34741480Smckusick 		ix = 0;
34841480Smckusick 		for (ci = cs->sc_cinfo;
34941480Smckusick 		     ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++)
35041480Smckusick 			if (ci->ci_size >= smallci->ci_size)
35141480Smckusick 				ii->ii_index[ix++] = ci - cs->sc_cinfo;
35241480Smckusick 		ii->ii_ndisk = ix;
35341480Smckusick 		bn += ix * (smallci->ci_size - size);
35441480Smckusick 		lbn = smallci->ci_size / cs->sc_ileave;
35541480Smckusick 		size = smallci->ci_size;
35641480Smckusick 	}
35741480Smckusick #ifdef DEBUG
35841480Smckusick 	if (cddebug & CDB_INIT)
35941480Smckusick 		printiinfo(cs->sc_itable);
36041480Smckusick #endif
36141480Smckusick 	return(1);
36241480Smckusick }
36341480Smckusick 
36441480Smckusick #ifdef DEBUG
36541480Smckusick printiinfo(ii)
36641480Smckusick 	struct cdiinfo *ii;
36741480Smckusick {
36841480Smckusick 	register int ix, i;
36941480Smckusick 
37041480Smckusick 	for (ix = 0; ii->ii_ndisk; ix++, ii++) {
37141480Smckusick 		printf(" itab[%d]: #dk %d sblk %d soff %d",
37241480Smckusick 		       ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff);
37341480Smckusick 		for (i = 0; i < ii->ii_ndisk; i++)
37441480Smckusick 			printf(" %d", ii->ii_index[i]);
37541480Smckusick 		printf("\n");
37641480Smckusick 	}
37741480Smckusick }
37841480Smckusick #endif
37941480Smckusick 
cdopen(dev,flags)38041480Smckusick cdopen(dev, flags)
38141480Smckusick 	dev_t dev;
38241480Smckusick {
38341480Smckusick 	int unit = cdunit(dev);
38441480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
38541480Smckusick 
38641480Smckusick #ifdef DEBUG
38741480Smckusick 	if (cddebug & CDB_FOLLOW)
38841480Smckusick 		printf("cdopen(%x, %x)\n", dev, flags);
38941480Smckusick #endif
39059851Shibler 	if (unit >= numcd || (cs->sc_flags & CDF_ALIVE) == 0)
39141480Smckusick 		return(ENXIO);
39241480Smckusick 	return(0);
39341480Smckusick }
39441480Smckusick 
395*68158Scgd void
cdstrategy(bp)39641480Smckusick cdstrategy(bp)
39741480Smckusick 	register struct buf *bp;
39841480Smckusick {
39941480Smckusick 	register int unit = cdunit(bp->b_dev);
40041480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
40145480Smckusick 	register daddr_t bn;
40245480Smckusick 	register int sz, s;
40341480Smckusick 
40441480Smckusick #ifdef DEBUG
40541480Smckusick 	if (cddebug & CDB_FOLLOW)
40641480Smckusick 		printf("cdstrategy(%x): unit %d\n", bp, unit);
40741480Smckusick #endif
40841480Smckusick 	if ((cs->sc_flags & CDF_INITED) == 0) {
40941480Smckusick 		bp->b_error = ENXIO;
41045480Smckusick 		bp->b_flags |= B_ERROR;
41145480Smckusick 		goto done;
41241480Smckusick 	}
41341480Smckusick 	bn = bp->b_blkno;
41445480Smckusick 	sz = howmany(bp->b_bcount, DEV_BSIZE);
41541480Smckusick 	if (bn < 0 || bn + sz > cs->sc_size) {
41645480Smckusick 		sz = cs->sc_size - bn;
41745480Smckusick 		if (sz == 0) {
41845480Smckusick 			bp->b_resid = bp->b_bcount;
41941480Smckusick 			goto done;
42045480Smckusick 		}
42145480Smckusick 		if (sz < 0) {
42245480Smckusick 			bp->b_error = EINVAL;
42345480Smckusick 			bp->b_flags |= B_ERROR;
42445480Smckusick 			goto done;
42545480Smckusick 		}
42645480Smckusick 		bp->b_bcount = dbtob(sz);
42741480Smckusick 	}
42845480Smckusick 	bp->b_resid = bp->b_bcount;
42941480Smckusick 	/*
43041480Smckusick 	 * "Start" the unit.
43141480Smckusick 	 */
43241480Smckusick 	s = splbio();
43359851Shibler 	cdstart(cs, bp);
43441480Smckusick 	splx(s);
43541480Smckusick 	return;
43641480Smckusick done:
43745480Smckusick 	biodone(bp);
43841480Smckusick }
43941480Smckusick 
cdstart(cs,bp)44059851Shibler cdstart(cs, bp)
44159851Shibler 	register struct cd_softc *cs;
44259851Shibler 	register struct buf *bp;
44341480Smckusick {
44441480Smckusick 	register long bcount, rcount;
44541480Smckusick 	struct buf *cbp;
44641480Smckusick 	caddr_t addr;
44741480Smckusick 	daddr_t bn;
44841480Smckusick 
44941480Smckusick #ifdef DEBUG
45041480Smckusick 	if (cddebug & CDB_FOLLOW)
45159851Shibler 		printf("cdstart(%x, %x)\n", cs, bp);
45241480Smckusick #endif
45341480Smckusick 	/*
45441480Smckusick 	 * Instumentation (not real meaningful)
45541480Smckusick 	 */
45641480Smckusick 	cs->sc_usecnt++;
45741480Smckusick 	if (cs->sc_dk >= 0) {
45841480Smckusick 		dk_busy |= 1 << cs->sc_dk;
45941480Smckusick 		dk_xfer[cs->sc_dk]++;
46041480Smckusick 		dk_wds[cs->sc_dk] += bp->b_bcount >> 6;
46141480Smckusick 	}
46241480Smckusick 	/*
46341480Smckusick 	 * Allocate component buffers and fire off the requests
46441480Smckusick 	 */
46541480Smckusick 	bn = bp->b_blkno;
46664902Shibler 	addr = bp->b_data;
46741480Smckusick 	for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) {
46841480Smckusick 		cbp = cdbuffer(cs, bp, bn, addr, bcount);
46941480Smckusick 		rcount = cbp->b_bcount;
47041480Smckusick 		(*bdevsw[major(cbp->b_dev)].d_strategy)(cbp);
47141480Smckusick 		bn += btodb(rcount);
47241480Smckusick 		addr += rcount;
47341480Smckusick 	}
47441480Smckusick }
47541480Smckusick 
47641480Smckusick /*
47741480Smckusick  * Build a component buffer header.
47841480Smckusick  */
47941480Smckusick struct buf *
cdbuffer(cs,bp,bn,addr,bcount)48041480Smckusick cdbuffer(cs, bp, bn, addr, bcount)
48141480Smckusick 	register struct cd_softc *cs;
48241480Smckusick 	struct buf *bp;
48341480Smckusick 	daddr_t bn;
48441480Smckusick 	caddr_t addr;
48541480Smckusick 	long bcount;
48641480Smckusick {
48741480Smckusick 	register struct cdcinfo *ci;
48841480Smckusick 	register struct buf *cbp;
48941480Smckusick 	register daddr_t cbn, cboff;
49041480Smckusick 
49141480Smckusick #ifdef DEBUG
49241480Smckusick 	if (cddebug & CDB_IO)
49341480Smckusick 		printf("cdbuffer(%x, %x, %d, %x, %d)\n",
49441480Smckusick 		       cs, bp, bn, addr, bcount);
49541480Smckusick #endif
49641480Smckusick 	/*
49741480Smckusick 	 * Determine which component bn falls in.
49841480Smckusick 	 */
49941480Smckusick 	cbn = bn;
50041480Smckusick 	cboff = 0;
50141480Smckusick 	/*
50241480Smckusick 	 * Serially concatenated
50341480Smckusick 	 */
50441480Smckusick 	if (cs->sc_ileave == 0) {
50541480Smckusick 		register daddr_t sblk;
50641480Smckusick 
50741480Smckusick 		sblk = 0;
50841480Smckusick 		for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++)
50941480Smckusick 			sblk += ci->ci_size;
51041480Smckusick 		cbn -= sblk;
51141480Smckusick 	}
51241480Smckusick 	/*
51341480Smckusick 	 * Interleaved
51441480Smckusick 	 */
51541480Smckusick 	else {
51641480Smckusick 		register struct cdiinfo *ii;
51741480Smckusick 		int cdisk, off;
51841480Smckusick 
51941480Smckusick 		cboff = cbn % cs->sc_ileave;
52041480Smckusick 		cbn /= cs->sc_ileave;
52141480Smckusick 		for (ii = cs->sc_itable; ii->ii_ndisk; ii++)
52241480Smckusick 			if (ii->ii_startblk > cbn)
52341480Smckusick 				break;
52441480Smckusick 		ii--;
52541480Smckusick 		off = cbn - ii->ii_startblk;
52641480Smckusick 		if (ii->ii_ndisk == 1) {
52741480Smckusick 			cdisk = ii->ii_index[0];
52841480Smckusick 			cbn = ii->ii_startoff + off;
52941480Smckusick 		} else {
53041480Smckusick 			cdisk = ii->ii_index[off % ii->ii_ndisk];
53141480Smckusick 			cbn = ii->ii_startoff + off / ii->ii_ndisk;
53241480Smckusick 		}
53341480Smckusick 		cbn *= cs->sc_ileave;
53441480Smckusick 		ci = &cs->sc_cinfo[cdisk];
53541480Smckusick 	}
53641480Smckusick 	/*
53741480Smckusick 	 * Fill in the component buf structure.
53841480Smckusick 	 */
53941480Smckusick 	cbp = getcbuf();
54041480Smckusick 	cbp->b_flags = bp->b_flags | B_CALL;
54141480Smckusick 	cbp->b_iodone = cdiodone;
54241480Smckusick 	cbp->b_proc = bp->b_proc;
54341480Smckusick 	cbp->b_dev = ci->ci_dev;
54441480Smckusick 	cbp->b_blkno = cbn + cboff;
54564902Shibler 	cbp->b_data = addr;
54645480Smckusick 	cbp->b_vp = 0;
54741480Smckusick 	if (cs->sc_ileave == 0)
54841480Smckusick 		cbp->b_bcount = dbtob(ci->ci_size - cbn);
54941480Smckusick 	else
55041480Smckusick 		cbp->b_bcount = dbtob(cs->sc_ileave - cboff);
55141480Smckusick 	if (cbp->b_bcount > bcount)
55241480Smckusick 		cbp->b_bcount = bcount;
55341480Smckusick 	/*
55459851Shibler 	 * XXX context for cdiodone
55541480Smckusick 	 */
55645480Smckusick 	cbp->b_saveaddr = (caddr_t)bp;
55741480Smckusick 	cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo);
55841480Smckusick #ifdef DEBUG
55941480Smckusick 	if (cddebug & CDB_IO)
56041480Smckusick 		printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n",
56141480Smckusick 		       ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno,
56264902Shibler 		       cbp->b_data, cbp->b_bcount);
56341480Smckusick #endif
56441480Smckusick 	return(cbp);
56541480Smckusick }
56641480Smckusick 
cdintr(cs,bp)56759851Shibler cdintr(cs, bp)
56859851Shibler 	register struct cd_softc *cs;
56959851Shibler 	register struct buf *bp;
57041480Smckusick {
57141480Smckusick 
57241480Smckusick #ifdef DEBUG
57341480Smckusick 	if (cddebug & CDB_FOLLOW)
57459851Shibler 		printf("cdintr(%x, %x)\n", cs, bp);
57541480Smckusick #endif
57641480Smckusick 	/*
57741480Smckusick 	 * Request is done for better or worse, wakeup the top half.
57841480Smckusick 	 */
57941480Smckusick 	if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0)
58041480Smckusick 		dk_busy &= ~(1 << cs->sc_dk);
58141480Smckusick 	if (bp->b_flags & B_ERROR)
58241480Smckusick 		bp->b_resid = bp->b_bcount;
58345480Smckusick 	biodone(bp);
58441480Smckusick }
58541480Smckusick 
58641480Smckusick /*
58745480Smckusick  * Called by biodone at interrupt time.
58841480Smckusick  * Mark the component as done and if all components are done,
58941480Smckusick  * take a cd interrupt.
59041480Smckusick  */
59159851Shibler void
cdiodone(cbp)59241480Smckusick cdiodone(cbp)
59341480Smckusick 	register struct buf *cbp;
59441480Smckusick {
59545480Smckusick 	register struct buf *bp = (struct buf *)cbp->b_saveaddr;/* XXX */
59641480Smckusick 	register int unit = (cbp->b_pfcent >> 16) & 0xFFFF;	/* XXX */
59741480Smckusick 	int count, s;
59841480Smckusick 
59941480Smckusick 	s = splbio();
60041480Smckusick #ifdef DEBUG
60141480Smckusick 	if (cddebug & CDB_FOLLOW)
60241480Smckusick 		printf("cdiodone(%x)\n", cbp);
60341480Smckusick 	if (cddebug & CDB_IO) {
60441480Smckusick 		printf("cdiodone: bp %x bcount %d resid %d\n",
60541480Smckusick 		       bp, bp->b_bcount, bp->b_resid);
60641480Smckusick 		printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n",
60741480Smckusick 		       cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp,
60864902Shibler 		       cbp->b_blkno, cbp->b_data, cbp->b_bcount);
60941480Smckusick 	}
61041480Smckusick #endif
61141480Smckusick 
61241480Smckusick 	if (cbp->b_flags & B_ERROR) {
61341480Smckusick 		bp->b_flags |= B_ERROR;
61445480Smckusick 		bp->b_error = biowait(cbp);
61541480Smckusick #ifdef DEBUG
61641480Smckusick 		printf("cd%d: error %d on component %d\n",
61741480Smckusick 		       unit, bp->b_error, cbp->b_pfcent & 0xFFFF);
61841480Smckusick #endif
61941480Smckusick 	}
62041480Smckusick 	count = cbp->b_bcount;
62141480Smckusick 	putcbuf(cbp);
62241480Smckusick 
62341480Smckusick 	/*
62441480Smckusick 	 * If all done, "interrupt".
62541480Smckusick 	 */
62641480Smckusick 	bp->b_resid -= count;
62741480Smckusick 	if (bp->b_resid < 0)
62841480Smckusick 		panic("cdiodone: count");
62959851Shibler 	if (bp->b_resid == 0)
63059851Shibler 		cdintr(&cd_softc[unit], bp);
63141480Smckusick 	splx(s);
63241480Smckusick }
63341480Smckusick 
cdread(dev,uio)63441480Smckusick cdread(dev, uio)
63541480Smckusick 	dev_t dev;
63641480Smckusick 	struct uio *uio;
63741480Smckusick {
63841480Smckusick 	register int unit = cdunit(dev);
63941480Smckusick 
64041480Smckusick #ifdef DEBUG
64141480Smckusick 	if (cddebug & CDB_FOLLOW)
64241480Smckusick 		printf("cdread(%x, %x)\n", dev, uio);
64341480Smckusick #endif
64459851Shibler 	return(physio(cdstrategy, NULL, dev, B_READ, minphys, uio));
64541480Smckusick }
64641480Smckusick 
cdwrite(dev,uio)64741480Smckusick cdwrite(dev, uio)
64841480Smckusick 	dev_t dev;
64941480Smckusick 	struct uio *uio;
65041480Smckusick {
65141480Smckusick 	register int unit = cdunit(dev);
65241480Smckusick 
65341480Smckusick #ifdef DEBUG
65441480Smckusick 	if (cddebug & CDB_FOLLOW)
65541480Smckusick 		printf("cdwrite(%x, %x)\n", dev, uio);
65641480Smckusick #endif
65759851Shibler 	return(physio(cdstrategy, NULL, dev, B_WRITE, minphys, uio));
65841480Smckusick }
65941480Smckusick 
cdioctl(dev,cmd,data,flag)66041480Smckusick cdioctl(dev, cmd, data, flag)
66141480Smckusick 	dev_t dev;
662*68158Scgd 	u_long cmd;
66341480Smckusick 	caddr_t data;
66441480Smckusick 	int flag;
66541480Smckusick {
66641480Smckusick 	return(EINVAL);
66741480Smckusick }
66841480Smckusick 
cdsize(dev)66941480Smckusick cdsize(dev)
67041480Smckusick 	dev_t dev;
67141480Smckusick {
67241480Smckusick 	int unit = cdunit(dev);
67341480Smckusick 	register struct cd_softc *cs = &cd_softc[unit];
67441480Smckusick 
67559851Shibler 	if (unit >= numcd || (cs->sc_flags & CDF_INITED) == 0)
67641480Smckusick 		return(-1);
67741480Smckusick 	return(cs->sc_size);
67841480Smckusick }
67941480Smckusick 
cddump(dev)68041480Smckusick cddump(dev)
68141480Smckusick {
68241480Smckusick 	return(ENXIO);
68341480Smckusick }
68441480Smckusick #endif
685