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