141480Smckusick /* 241480Smckusick * Copyright (c) 1988 University of Utah. 3*63144Sbostic * Copyright (c) 1990, 1993 4*63144Sbostic * 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*63144Sbostic * @(#)cd.c 8.1 (Berkeley) 06/10/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> 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 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 * 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 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 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 39541480Smckusick cdstrategy(bp) 39641480Smckusick register struct buf *bp; 39741480Smckusick { 39841480Smckusick register int unit = cdunit(bp->b_dev); 39941480Smckusick register struct cd_softc *cs = &cd_softc[unit]; 40045480Smckusick register daddr_t bn; 40145480Smckusick register int sz, s; 40241480Smckusick 40341480Smckusick #ifdef DEBUG 40441480Smckusick if (cddebug & CDB_FOLLOW) 40541480Smckusick printf("cdstrategy(%x): unit %d\n", bp, unit); 40641480Smckusick #endif 40741480Smckusick if ((cs->sc_flags & CDF_INITED) == 0) { 40841480Smckusick bp->b_error = ENXIO; 40945480Smckusick bp->b_flags |= B_ERROR; 41045480Smckusick goto done; 41141480Smckusick } 41241480Smckusick bn = bp->b_blkno; 41345480Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 41441480Smckusick if (bn < 0 || bn + sz > cs->sc_size) { 41545480Smckusick sz = cs->sc_size - bn; 41645480Smckusick if (sz == 0) { 41745480Smckusick bp->b_resid = bp->b_bcount; 41841480Smckusick goto done; 41945480Smckusick } 42045480Smckusick if (sz < 0) { 42145480Smckusick bp->b_error = EINVAL; 42245480Smckusick bp->b_flags |= B_ERROR; 42345480Smckusick goto done; 42445480Smckusick } 42545480Smckusick bp->b_bcount = dbtob(sz); 42641480Smckusick } 42745480Smckusick bp->b_resid = bp->b_bcount; 42841480Smckusick /* 42941480Smckusick * "Start" the unit. 43041480Smckusick */ 43141480Smckusick s = splbio(); 43259851Shibler cdstart(cs, bp); 43341480Smckusick splx(s); 43441480Smckusick return; 43541480Smckusick done: 43645480Smckusick biodone(bp); 43741480Smckusick } 43841480Smckusick 43959851Shibler cdstart(cs, bp) 44059851Shibler register struct cd_softc *cs; 44159851Shibler register struct buf *bp; 44241480Smckusick { 44341480Smckusick register long bcount, rcount; 44441480Smckusick struct buf *cbp; 44541480Smckusick caddr_t addr; 44641480Smckusick daddr_t bn; 44741480Smckusick 44841480Smckusick #ifdef DEBUG 44941480Smckusick if (cddebug & CDB_FOLLOW) 45059851Shibler printf("cdstart(%x, %x)\n", cs, bp); 45141480Smckusick #endif 45241480Smckusick /* 45341480Smckusick * Instumentation (not real meaningful) 45441480Smckusick */ 45541480Smckusick cs->sc_usecnt++; 45641480Smckusick if (cs->sc_dk >= 0) { 45741480Smckusick dk_busy |= 1 << cs->sc_dk; 45841480Smckusick dk_xfer[cs->sc_dk]++; 45941480Smckusick dk_wds[cs->sc_dk] += bp->b_bcount >> 6; 46041480Smckusick } 46141480Smckusick /* 46241480Smckusick * Allocate component buffers and fire off the requests 46341480Smckusick */ 46441480Smckusick bn = bp->b_blkno; 46541480Smckusick addr = bp->b_un.b_addr; 46641480Smckusick for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 46741480Smckusick cbp = cdbuffer(cs, bp, bn, addr, bcount); 46841480Smckusick rcount = cbp->b_bcount; 46941480Smckusick (*bdevsw[major(cbp->b_dev)].d_strategy)(cbp); 47041480Smckusick bn += btodb(rcount); 47141480Smckusick addr += rcount; 47241480Smckusick } 47341480Smckusick } 47441480Smckusick 47541480Smckusick /* 47641480Smckusick * Build a component buffer header. 47741480Smckusick */ 47841480Smckusick struct buf * 47941480Smckusick cdbuffer(cs, bp, bn, addr, bcount) 48041480Smckusick register struct cd_softc *cs; 48141480Smckusick struct buf *bp; 48241480Smckusick daddr_t bn; 48341480Smckusick caddr_t addr; 48441480Smckusick long bcount; 48541480Smckusick { 48641480Smckusick register struct cdcinfo *ci; 48741480Smckusick register struct buf *cbp; 48841480Smckusick register daddr_t cbn, cboff; 48941480Smckusick 49041480Smckusick #ifdef DEBUG 49141480Smckusick if (cddebug & CDB_IO) 49241480Smckusick printf("cdbuffer(%x, %x, %d, %x, %d)\n", 49341480Smckusick cs, bp, bn, addr, bcount); 49441480Smckusick #endif 49541480Smckusick /* 49641480Smckusick * Determine which component bn falls in. 49741480Smckusick */ 49841480Smckusick cbn = bn; 49941480Smckusick cboff = 0; 50041480Smckusick /* 50141480Smckusick * Serially concatenated 50241480Smckusick */ 50341480Smckusick if (cs->sc_ileave == 0) { 50441480Smckusick register daddr_t sblk; 50541480Smckusick 50641480Smckusick sblk = 0; 50741480Smckusick for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 50841480Smckusick sblk += ci->ci_size; 50941480Smckusick cbn -= sblk; 51041480Smckusick } 51141480Smckusick /* 51241480Smckusick * Interleaved 51341480Smckusick */ 51441480Smckusick else { 51541480Smckusick register struct cdiinfo *ii; 51641480Smckusick int cdisk, off; 51741480Smckusick 51841480Smckusick cboff = cbn % cs->sc_ileave; 51941480Smckusick cbn /= cs->sc_ileave; 52041480Smckusick for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 52141480Smckusick if (ii->ii_startblk > cbn) 52241480Smckusick break; 52341480Smckusick ii--; 52441480Smckusick off = cbn - ii->ii_startblk; 52541480Smckusick if (ii->ii_ndisk == 1) { 52641480Smckusick cdisk = ii->ii_index[0]; 52741480Smckusick cbn = ii->ii_startoff + off; 52841480Smckusick } else { 52941480Smckusick cdisk = ii->ii_index[off % ii->ii_ndisk]; 53041480Smckusick cbn = ii->ii_startoff + off / ii->ii_ndisk; 53141480Smckusick } 53241480Smckusick cbn *= cs->sc_ileave; 53341480Smckusick ci = &cs->sc_cinfo[cdisk]; 53441480Smckusick } 53541480Smckusick /* 53641480Smckusick * Fill in the component buf structure. 53741480Smckusick */ 53841480Smckusick cbp = getcbuf(); 53941480Smckusick cbp->b_flags = bp->b_flags | B_CALL; 54041480Smckusick cbp->b_iodone = cdiodone; 54141480Smckusick cbp->b_proc = bp->b_proc; 54241480Smckusick cbp->b_dev = ci->ci_dev; 54341480Smckusick cbp->b_blkno = cbn + cboff; 54441480Smckusick cbp->b_un.b_addr = addr; 54545480Smckusick cbp->b_vp = 0; 54641480Smckusick if (cs->sc_ileave == 0) 54741480Smckusick cbp->b_bcount = dbtob(ci->ci_size - cbn); 54841480Smckusick else 54941480Smckusick cbp->b_bcount = dbtob(cs->sc_ileave - cboff); 55041480Smckusick if (cbp->b_bcount > bcount) 55141480Smckusick cbp->b_bcount = bcount; 55241480Smckusick /* 55359851Shibler * XXX context for cdiodone 55441480Smckusick */ 55545480Smckusick cbp->b_saveaddr = (caddr_t)bp; 55641480Smckusick cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo); 55741480Smckusick #ifdef DEBUG 55841480Smckusick if (cddebug & CDB_IO) 55941480Smckusick printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 56041480Smckusick ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno, 56141480Smckusick cbp->b_un.b_addr, cbp->b_bcount); 56241480Smckusick #endif 56341480Smckusick return(cbp); 56441480Smckusick } 56541480Smckusick 56659851Shibler cdintr(cs, bp) 56759851Shibler register struct cd_softc *cs; 56859851Shibler register struct buf *bp; 56941480Smckusick { 57041480Smckusick 57141480Smckusick #ifdef DEBUG 57241480Smckusick if (cddebug & CDB_FOLLOW) 57359851Shibler printf("cdintr(%x, %x)\n", cs, bp); 57441480Smckusick #endif 57541480Smckusick /* 57641480Smckusick * Request is done for better or worse, wakeup the top half. 57741480Smckusick */ 57841480Smckusick if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0) 57941480Smckusick dk_busy &= ~(1 << cs->sc_dk); 58041480Smckusick if (bp->b_flags & B_ERROR) 58141480Smckusick bp->b_resid = bp->b_bcount; 58245480Smckusick biodone(bp); 58341480Smckusick } 58441480Smckusick 58541480Smckusick /* 58645480Smckusick * Called by biodone at interrupt time. 58741480Smckusick * Mark the component as done and if all components are done, 58841480Smckusick * take a cd interrupt. 58941480Smckusick */ 59059851Shibler void 59141480Smckusick cdiodone(cbp) 59241480Smckusick register struct buf *cbp; 59341480Smckusick { 59445480Smckusick register struct buf *bp = (struct buf *)cbp->b_saveaddr;/* XXX */ 59541480Smckusick register int unit = (cbp->b_pfcent >> 16) & 0xFFFF; /* XXX */ 59641480Smckusick int count, s; 59741480Smckusick 59841480Smckusick s = splbio(); 59941480Smckusick #ifdef DEBUG 60041480Smckusick if (cddebug & CDB_FOLLOW) 60141480Smckusick printf("cdiodone(%x)\n", cbp); 60241480Smckusick if (cddebug & CDB_IO) { 60341480Smckusick printf("cdiodone: bp %x bcount %d resid %d\n", 60441480Smckusick bp, bp->b_bcount, bp->b_resid); 60541480Smckusick printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", 60641480Smckusick cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp, 60741480Smckusick cbp->b_blkno, cbp->b_un.b_addr, cbp->b_bcount); 60841480Smckusick } 60941480Smckusick #endif 61041480Smckusick 61141480Smckusick if (cbp->b_flags & B_ERROR) { 61241480Smckusick bp->b_flags |= B_ERROR; 61345480Smckusick bp->b_error = biowait(cbp); 61441480Smckusick #ifdef DEBUG 61541480Smckusick printf("cd%d: error %d on component %d\n", 61641480Smckusick unit, bp->b_error, cbp->b_pfcent & 0xFFFF); 61741480Smckusick #endif 61841480Smckusick } 61941480Smckusick count = cbp->b_bcount; 62041480Smckusick putcbuf(cbp); 62141480Smckusick 62241480Smckusick /* 62341480Smckusick * If all done, "interrupt". 62441480Smckusick */ 62541480Smckusick bp->b_resid -= count; 62641480Smckusick if (bp->b_resid < 0) 62741480Smckusick panic("cdiodone: count"); 62859851Shibler if (bp->b_resid == 0) 62959851Shibler cdintr(&cd_softc[unit], bp); 63041480Smckusick splx(s); 63141480Smckusick } 63241480Smckusick 63341480Smckusick cdread(dev, uio) 63441480Smckusick dev_t dev; 63541480Smckusick struct uio *uio; 63641480Smckusick { 63741480Smckusick register int unit = cdunit(dev); 63841480Smckusick 63941480Smckusick #ifdef DEBUG 64041480Smckusick if (cddebug & CDB_FOLLOW) 64141480Smckusick printf("cdread(%x, %x)\n", dev, uio); 64241480Smckusick #endif 64359851Shibler return(physio(cdstrategy, NULL, dev, B_READ, minphys, uio)); 64441480Smckusick } 64541480Smckusick 64641480Smckusick cdwrite(dev, uio) 64741480Smckusick dev_t dev; 64841480Smckusick struct uio *uio; 64941480Smckusick { 65041480Smckusick register int unit = cdunit(dev); 65141480Smckusick 65241480Smckusick #ifdef DEBUG 65341480Smckusick if (cddebug & CDB_FOLLOW) 65441480Smckusick printf("cdwrite(%x, %x)\n", dev, uio); 65541480Smckusick #endif 65659851Shibler return(physio(cdstrategy, NULL, dev, B_WRITE, minphys, uio)); 65741480Smckusick } 65841480Smckusick 65941480Smckusick cdioctl(dev, cmd, data, flag) 66041480Smckusick dev_t dev; 66141480Smckusick int cmd; 66241480Smckusick caddr_t data; 66341480Smckusick int flag; 66441480Smckusick { 66541480Smckusick return(EINVAL); 66641480Smckusick } 66741480Smckusick 66841480Smckusick cdsize(dev) 66941480Smckusick dev_t dev; 67041480Smckusick { 67141480Smckusick int unit = cdunit(dev); 67241480Smckusick register struct cd_softc *cs = &cd_softc[unit]; 67341480Smckusick 67459851Shibler if (unit >= numcd || (cs->sc_flags & CDF_INITED) == 0) 67541480Smckusick return(-1); 67641480Smckusick return(cs->sc_size); 67741480Smckusick } 67841480Smckusick 67941480Smckusick cddump(dev) 68041480Smckusick { 68141480Smckusick return(ENXIO); 68241480Smckusick } 68341480Smckusick #endif 684