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