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 * 1245480Smckusick * from: Utah $Hdr: cd.c 1.1 90/07/09$ 1341480Smckusick * 14*45788Sbostic * @(#)cd.c 7.3 (Berkeley) 12/16/90 1541480Smckusick */ 1641480Smckusick 1741480Smckusick /* 1841480Smckusick * "Concatenated" disk driver. 1941480Smckusick */ 2041480Smckusick #include "cd.h" 2141480Smckusick #if NCD > 0 2241480Smckusick 23*45788Sbostic #include "sys/param.h" 24*45788Sbostic #include "sys/systm.h" 25*45788Sbostic #include "sys/errno.h" 26*45788Sbostic #include "sys/dkstat.h" 27*45788Sbostic #include "sys/buf.h" 28*45788Sbostic #include "sys/malloc.h" 29*45788Sbostic #include "sys/conf.h" 3041480Smckusick 3141480Smckusick #include "cdvar.h" 3241480Smckusick 3341480Smckusick #ifdef DEBUG 3441480Smckusick int cddebug = 0x00; 3541480Smckusick #define CDB_FOLLOW 0x01 3641480Smckusick #define CDB_INIT 0x02 3741480Smckusick #define CDB_IO 0x04 3841480Smckusick #endif 3941480Smckusick 4041480Smckusick struct buf cdbuf[NCD]; 4141480Smckusick struct buf *cdbuffer(); 4241480Smckusick int cdiodone(); 4341480Smckusick 4441480Smckusick #define cdunit(x) ((minor(x) >> 3) & 0x7) /* for consistency */ 4541480Smckusick 4641480Smckusick #define getcbuf() \ 4741480Smckusick ((struct buf *)malloc(sizeof(struct buf), M_DEVBUF, M_WAITOK)) 4841480Smckusick #define putcbuf(bp) \ 4941480Smckusick free((caddr_t)(bp), M_DEVBUF) 5041480Smckusick 5141480Smckusick struct cd_softc { 5241480Smckusick int sc_flags; /* flags */ 5341480Smckusick size_t sc_size; /* size of cd */ 5441480Smckusick int sc_ileave; /* interleave */ 5541480Smckusick int sc_ncdisks; /* number of components */ 5641480Smckusick struct cdcinfo sc_cinfo[NCDISKS]; /* component info */ 5741480Smckusick struct cdiinfo *sc_itable; /* interleave table */ 5841480Smckusick int sc_usecnt; /* number of requests active */ 5941480Smckusick struct buf *sc_bp; /* "current" request */ 6041480Smckusick int sc_dk; /* disk index */ 6141480Smckusick } cd_softc[NCD]; 6241480Smckusick 6341480Smckusick /* sc_flags */ 6441480Smckusick #define CDF_ALIVE 0x01 6541480Smckusick #define CDF_INITED 0x02 6641480Smckusick 6741480Smckusick cdinit(cd) 6841480Smckusick struct cddevice *cd; 6941480Smckusick { 7041480Smckusick register struct cd_softc *cs = &cd_softc[cd->cd_unit]; 7141480Smckusick register struct cdcinfo *ci; 7241480Smckusick register size_t size; 7341480Smckusick register int ix; 7441480Smckusick size_t minsize; 7541480Smckusick dev_t dev; 7641480Smckusick 7741480Smckusick #ifdef DEBUG 7841480Smckusick if (cddebug & (CDB_FOLLOW|CDB_INIT)) 7941480Smckusick printf("cdinit: unit %d\n", cd->cd_unit); 8041480Smckusick #endif 8141480Smckusick cs->sc_dk = cd->cd_dk; 8241480Smckusick cs->sc_size = 0; 8341480Smckusick cs->sc_ileave = cd->cd_interleave; 8441480Smckusick cs->sc_ncdisks = 0; 8541480Smckusick /* 8641480Smckusick * Verify that each component piece exists and record 8741480Smckusick * relevant information about it. 8841480Smckusick */ 8941480Smckusick minsize = 0; 9041480Smckusick for (ix = 0; ix < NCDISKS; ix++) { 9141480Smckusick if ((dev = cd->cd_dev[ix]) == NODEV) 9241480Smckusick break; 9341480Smckusick ci = &cs->sc_cinfo[ix]; 9441480Smckusick ci->ci_dev = dev; 9541480Smckusick /* 9641480Smckusick * Calculate size (truncated to interleave boundary 9741480Smckusick * if necessary. 9841480Smckusick */ 9941480Smckusick if (bdevsw[major(dev)].d_psize) { 10041480Smckusick size = (*bdevsw[major(dev)].d_psize)(dev); 10141480Smckusick if (size <= 0) 10241480Smckusick size = 0; 10341480Smckusick } else 10441480Smckusick size = 0; 10541480Smckusick if (cs->sc_ileave > 1) 10641480Smckusick size -= size % cs->sc_ileave; 10741480Smckusick if (size == 0) 10841480Smckusick return(0); 10941480Smckusick if (minsize == 0 || size < minsize) 11041480Smckusick minsize = size; 11141480Smckusick ci->ci_size = size; 11241480Smckusick cs->sc_size += size; 11341480Smckusick cs->sc_ncdisks++; 11441480Smckusick } 11541480Smckusick /* 11641480Smckusick * If uniform interleave is desired set all sizes to that of 11741480Smckusick * the smallest component. 11841480Smckusick */ 11941480Smckusick if (cd->cd_flags & CDF_UNIFORM) { 12041480Smckusick for (ci = cs->sc_cinfo; 12141480Smckusick ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++) 12241480Smckusick ci->ci_size = minsize; 12341480Smckusick cs->sc_size = cs->sc_ncdisks * minsize; 12441480Smckusick } 12541480Smckusick /* 12641480Smckusick * Construct the interleave table 12741480Smckusick */ 12841480Smckusick if (!cdinterleave(cs)) 12941480Smckusick return(0); 13041480Smckusick if (cd->cd_dk >= 0) 13141480Smckusick dk_wpms[cd->cd_dk] = 32 * (60 * DEV_BSIZE / 2); /* XXX */ 13241480Smckusick printf("cd%d: %d components (%d blocks) concatenated", 13341480Smckusick cd->cd_unit, cs->sc_ncdisks, cs->sc_size); 13441480Smckusick if (cs->sc_ileave) 13541480Smckusick printf(", %d block interleave\n", cs->sc_ileave); 13641480Smckusick else 13741480Smckusick printf(" serially\n"); 13841480Smckusick cs->sc_flags = CDF_ALIVE | CDF_INITED; 13941480Smckusick return(1); 14041480Smckusick } 14141480Smckusick 14241480Smckusick cdinterleave(cs) 14341480Smckusick register struct cd_softc *cs; 14441480Smckusick { 14541480Smckusick register struct cdcinfo *ci, *smallci; 14641480Smckusick register struct cdiinfo *ii; 14741480Smckusick register daddr_t bn, lbn; 14841480Smckusick register int ix; 14941480Smckusick u_long size; 15041480Smckusick 15141480Smckusick #ifdef DEBUG 15241480Smckusick if (cddebug & CDB_INIT) 15341480Smckusick printf("cdinterleave(%x): ileave %d\n", cs, cs->sc_ileave); 15441480Smckusick #endif 15541480Smckusick /* 15641480Smckusick * Allocate an interleave table. 15741480Smckusick * Chances are this is too big, but we don't care. 15841480Smckusick */ 15941480Smckusick size = (cs->sc_ncdisks + 1) * sizeof(struct cdiinfo); 16041480Smckusick cs->sc_itable = (struct cdiinfo *)malloc(size, M_DEVBUF, M_WAITOK); 16141480Smckusick bzero((caddr_t)cs->sc_itable, size); 16241480Smckusick /* 16341480Smckusick * Trivial case: no interleave (actually interleave of disk size). 16441480Smckusick * Each table entry represent a single component in its entirety. 16541480Smckusick */ 16641480Smckusick if (cs->sc_ileave == 0) { 16741480Smckusick bn = 0; 16841480Smckusick ii = cs->sc_itable; 16941480Smckusick for (ix = 0; ix < cs->sc_ncdisks; ix++) { 17041480Smckusick ii->ii_ndisk = 1; 17141480Smckusick ii->ii_startblk = bn; 17241480Smckusick ii->ii_startoff = 0; 17341480Smckusick ii->ii_index[0] = ix; 17441480Smckusick bn += cs->sc_cinfo[ix].ci_size; 17541480Smckusick ii++; 17641480Smckusick } 17741480Smckusick ii->ii_ndisk = 0; 17841480Smckusick #ifdef DEBUG 17941480Smckusick if (cddebug & CDB_INIT) 18041480Smckusick printiinfo(cs->sc_itable); 18141480Smckusick #endif 18241480Smckusick return(1); 18341480Smckusick } 18441480Smckusick /* 18541480Smckusick * The following isn't fast or pretty; it doesn't have to be. 18641480Smckusick */ 18741480Smckusick size = 0; 18841480Smckusick bn = lbn = 0; 18941480Smckusick for (ii = cs->sc_itable; ; ii++) { 19041480Smckusick /* 19141480Smckusick * Locate the smallest of the remaining components 19241480Smckusick */ 19341480Smckusick smallci = NULL; 19441480Smckusick for (ci = cs->sc_cinfo; 19541480Smckusick ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++) 19641480Smckusick if (ci->ci_size > size && 19741480Smckusick (smallci == NULL || 19841480Smckusick ci->ci_size < smallci->ci_size)) 19941480Smckusick smallci = ci; 20041480Smckusick /* 20141480Smckusick * Nobody left, all done 20241480Smckusick */ 20341480Smckusick if (smallci == NULL) { 20441480Smckusick ii->ii_ndisk = 0; 20541480Smckusick break; 20641480Smckusick } 20741480Smckusick /* 20841480Smckusick * Record starting logical block and component offset 20941480Smckusick */ 21041480Smckusick ii->ii_startblk = bn / cs->sc_ileave; 21141480Smckusick ii->ii_startoff = lbn; 21241480Smckusick /* 21341480Smckusick * Determine how many disks take part in this interleave 21441480Smckusick * and record their indices. 21541480Smckusick */ 21641480Smckusick ix = 0; 21741480Smckusick for (ci = cs->sc_cinfo; 21841480Smckusick ci < &cs->sc_cinfo[cs->sc_ncdisks]; ci++) 21941480Smckusick if (ci->ci_size >= smallci->ci_size) 22041480Smckusick ii->ii_index[ix++] = ci - cs->sc_cinfo; 22141480Smckusick ii->ii_ndisk = ix; 22241480Smckusick bn += ix * (smallci->ci_size - size); 22341480Smckusick lbn = smallci->ci_size / cs->sc_ileave; 22441480Smckusick size = smallci->ci_size; 22541480Smckusick } 22641480Smckusick #ifdef DEBUG 22741480Smckusick if (cddebug & CDB_INIT) 22841480Smckusick printiinfo(cs->sc_itable); 22941480Smckusick #endif 23041480Smckusick return(1); 23141480Smckusick } 23241480Smckusick 23341480Smckusick #ifdef DEBUG 23441480Smckusick printiinfo(ii) 23541480Smckusick struct cdiinfo *ii; 23641480Smckusick { 23741480Smckusick register int ix, i; 23841480Smckusick 23941480Smckusick for (ix = 0; ii->ii_ndisk; ix++, ii++) { 24041480Smckusick printf(" itab[%d]: #dk %d sblk %d soff %d", 24141480Smckusick ix, ii->ii_ndisk, ii->ii_startblk, ii->ii_startoff); 24241480Smckusick for (i = 0; i < ii->ii_ndisk; i++) 24341480Smckusick printf(" %d", ii->ii_index[i]); 24441480Smckusick printf("\n"); 24541480Smckusick } 24641480Smckusick } 24741480Smckusick #endif 24841480Smckusick 24941480Smckusick cdopen(dev, flags) 25041480Smckusick dev_t dev; 25141480Smckusick { 25241480Smckusick int unit = cdunit(dev); 25341480Smckusick register struct cd_softc *cs = &cd_softc[unit]; 25441480Smckusick 25541480Smckusick #ifdef DEBUG 25641480Smckusick if (cddebug & CDB_FOLLOW) 25741480Smckusick printf("cdopen(%x, %x)\n", dev, flags); 25841480Smckusick #endif 25941480Smckusick if (unit >= NCD || (cs->sc_flags & CDF_ALIVE) == 0) 26041480Smckusick return(ENXIO); 26141480Smckusick return(0); 26241480Smckusick } 26341480Smckusick 26441480Smckusick cdstrategy(bp) 26541480Smckusick register struct buf *bp; 26641480Smckusick { 26741480Smckusick register int unit = cdunit(bp->b_dev); 26841480Smckusick register struct cd_softc *cs = &cd_softc[unit]; 26945480Smckusick register daddr_t bn; 27045480Smckusick register int sz, s; 27141480Smckusick 27241480Smckusick #ifdef DEBUG 27341480Smckusick if (cddebug & CDB_FOLLOW) 27441480Smckusick printf("cdstrategy(%x): unit %d\n", bp, unit); 27541480Smckusick #endif 27641480Smckusick if ((cs->sc_flags & CDF_INITED) == 0) { 27741480Smckusick bp->b_error = ENXIO; 27845480Smckusick bp->b_flags |= B_ERROR; 27945480Smckusick goto done; 28041480Smckusick } 28141480Smckusick bn = bp->b_blkno; 28245480Smckusick sz = howmany(bp->b_bcount, DEV_BSIZE); 28341480Smckusick if (bn < 0 || bn + sz > cs->sc_size) { 28445480Smckusick sz = cs->sc_size - bn; 28545480Smckusick if (sz == 0) { 28645480Smckusick bp->b_resid = bp->b_bcount; 28741480Smckusick goto done; 28845480Smckusick } 28945480Smckusick if (sz < 0) { 29045480Smckusick bp->b_error = EINVAL; 29145480Smckusick bp->b_flags |= B_ERROR; 29245480Smckusick goto done; 29345480Smckusick } 29445480Smckusick bp->b_bcount = dbtob(sz); 29541480Smckusick } 29645480Smckusick bp->b_resid = bp->b_bcount; 29741480Smckusick /* 29841480Smckusick * "Start" the unit. 29941480Smckusick * XXX: the use of sc_bp is just to retain the "traditional" 30041480Smckusick * interface to the start routine. 30141480Smckusick */ 30241480Smckusick s = splbio(); 30341480Smckusick cs->sc_bp = bp; 30441480Smckusick cdstart(unit); 30541480Smckusick splx(s); 30641480Smckusick return; 30741480Smckusick done: 30845480Smckusick biodone(bp); 30941480Smckusick } 31041480Smckusick 31141480Smckusick cdstart(unit) 31241480Smckusick int unit; 31341480Smckusick { 31441480Smckusick register struct cd_softc *cs = &cd_softc[unit]; 31541480Smckusick register struct buf *bp = cs->sc_bp; 31641480Smckusick register long bcount, rcount; 31741480Smckusick struct buf *cbp; 31841480Smckusick caddr_t addr; 31941480Smckusick daddr_t bn; 32041480Smckusick 32141480Smckusick #ifdef DEBUG 32241480Smckusick if (cddebug & CDB_FOLLOW) 32341480Smckusick printf("cdstart(%d)\n", unit); 32441480Smckusick #endif 32541480Smckusick /* 32641480Smckusick * Instumentation (not real meaningful) 32741480Smckusick */ 32841480Smckusick cs->sc_usecnt++; 32941480Smckusick if (cs->sc_dk >= 0) { 33041480Smckusick dk_busy |= 1 << cs->sc_dk; 33141480Smckusick dk_xfer[cs->sc_dk]++; 33241480Smckusick dk_wds[cs->sc_dk] += bp->b_bcount >> 6; 33341480Smckusick } 33441480Smckusick /* 33541480Smckusick * Allocate component buffers and fire off the requests 33641480Smckusick */ 33741480Smckusick bn = bp->b_blkno; 33841480Smckusick addr = bp->b_un.b_addr; 33941480Smckusick for (bcount = bp->b_bcount; bcount > 0; bcount -= rcount) { 34041480Smckusick cbp = cdbuffer(cs, bp, bn, addr, bcount); 34141480Smckusick rcount = cbp->b_bcount; 34241480Smckusick (*bdevsw[major(cbp->b_dev)].d_strategy)(cbp); 34341480Smckusick bn += btodb(rcount); 34441480Smckusick addr += rcount; 34541480Smckusick } 34641480Smckusick } 34741480Smckusick 34841480Smckusick /* 34941480Smckusick * Build a component buffer header. 35041480Smckusick */ 35141480Smckusick struct buf * 35241480Smckusick cdbuffer(cs, bp, bn, addr, bcount) 35341480Smckusick register struct cd_softc *cs; 35441480Smckusick struct buf *bp; 35541480Smckusick daddr_t bn; 35641480Smckusick caddr_t addr; 35741480Smckusick long bcount; 35841480Smckusick { 35941480Smckusick register struct cdcinfo *ci; 36041480Smckusick register struct buf *cbp; 36141480Smckusick register daddr_t cbn, cboff; 36241480Smckusick 36341480Smckusick #ifdef DEBUG 36441480Smckusick if (cddebug & CDB_IO) 36541480Smckusick printf("cdbuffer(%x, %x, %d, %x, %d)\n", 36641480Smckusick cs, bp, bn, addr, bcount); 36741480Smckusick #endif 36841480Smckusick /* 36941480Smckusick * Determine which component bn falls in. 37041480Smckusick */ 37141480Smckusick cbn = bn; 37241480Smckusick cboff = 0; 37341480Smckusick /* 37441480Smckusick * Serially concatenated 37541480Smckusick */ 37641480Smckusick if (cs->sc_ileave == 0) { 37741480Smckusick register daddr_t sblk; 37841480Smckusick 37941480Smckusick sblk = 0; 38041480Smckusick for (ci = cs->sc_cinfo; cbn >= sblk + ci->ci_size; ci++) 38141480Smckusick sblk += ci->ci_size; 38241480Smckusick cbn -= sblk; 38341480Smckusick } 38441480Smckusick /* 38541480Smckusick * Interleaved 38641480Smckusick */ 38741480Smckusick else { 38841480Smckusick register struct cdiinfo *ii; 38941480Smckusick int cdisk, off; 39041480Smckusick 39141480Smckusick cboff = cbn % cs->sc_ileave; 39241480Smckusick cbn /= cs->sc_ileave; 39341480Smckusick for (ii = cs->sc_itable; ii->ii_ndisk; ii++) 39441480Smckusick if (ii->ii_startblk > cbn) 39541480Smckusick break; 39641480Smckusick ii--; 39741480Smckusick off = cbn - ii->ii_startblk; 39841480Smckusick if (ii->ii_ndisk == 1) { 39941480Smckusick cdisk = ii->ii_index[0]; 40041480Smckusick cbn = ii->ii_startoff + off; 40141480Smckusick } else { 40241480Smckusick cdisk = ii->ii_index[off % ii->ii_ndisk]; 40341480Smckusick cbn = ii->ii_startoff + off / ii->ii_ndisk; 40441480Smckusick } 40541480Smckusick cbn *= cs->sc_ileave; 40641480Smckusick ci = &cs->sc_cinfo[cdisk]; 40741480Smckusick } 40841480Smckusick /* 40941480Smckusick * Fill in the component buf structure. 41041480Smckusick */ 41141480Smckusick cbp = getcbuf(); 41241480Smckusick cbp->b_flags = bp->b_flags | B_CALL; 41341480Smckusick cbp->b_iodone = cdiodone; 41441480Smckusick cbp->b_proc = bp->b_proc; 41541480Smckusick cbp->b_dev = ci->ci_dev; 41641480Smckusick cbp->b_blkno = cbn + cboff; 41741480Smckusick cbp->b_un.b_addr = addr; 41845480Smckusick cbp->b_vp = 0; 41941480Smckusick if (cs->sc_ileave == 0) 42041480Smckusick cbp->b_bcount = dbtob(ci->ci_size - cbn); 42141480Smckusick else 42241480Smckusick cbp->b_bcount = dbtob(cs->sc_ileave - cboff); 42341480Smckusick if (cbp->b_bcount > bcount) 42441480Smckusick cbp->b_bcount = bcount; 42541480Smckusick /* 42641480Smckusick * XXX: context for cdiodone 42741480Smckusick */ 42845480Smckusick cbp->b_saveaddr = (caddr_t)bp; 42941480Smckusick cbp->b_pfcent = ((cs - cd_softc) << 16) | (ci - cs->sc_cinfo); 43041480Smckusick #ifdef DEBUG 43141480Smckusick if (cddebug & CDB_IO) 43241480Smckusick printf(" dev %x(u%d): cbp %x bn %d addr %x bcnt %d\n", 43341480Smckusick ci->ci_dev, ci-cs->sc_cinfo, cbp, cbp->b_blkno, 43441480Smckusick cbp->b_un.b_addr, cbp->b_bcount); 43541480Smckusick #endif 43641480Smckusick return(cbp); 43741480Smckusick } 43841480Smckusick 43941480Smckusick cdintr(unit) 44041480Smckusick int unit; 44141480Smckusick { 44241480Smckusick register struct cd_softc *cs = &cd_softc[unit]; 44341480Smckusick register struct buf *bp = cs->sc_bp; 44441480Smckusick 44541480Smckusick #ifdef DEBUG 44641480Smckusick if (cddebug & CDB_FOLLOW) 44745480Smckusick printf("cdintr(%d): bp %x\n", unit, bp); 44841480Smckusick #endif 44941480Smckusick /* 45041480Smckusick * Request is done for better or worse, wakeup the top half. 45141480Smckusick */ 45241480Smckusick if (--cs->sc_usecnt == 0 && cs->sc_dk >= 0) 45341480Smckusick dk_busy &= ~(1 << cs->sc_dk); 45441480Smckusick if (bp->b_flags & B_ERROR) 45541480Smckusick bp->b_resid = bp->b_bcount; 45645480Smckusick biodone(bp); 45741480Smckusick } 45841480Smckusick 45941480Smckusick /* 46045480Smckusick * Called by biodone at interrupt time. 46141480Smckusick * Mark the component as done and if all components are done, 46241480Smckusick * take a cd interrupt. 46341480Smckusick */ 46441480Smckusick cdiodone(cbp) 46541480Smckusick register struct buf *cbp; 46641480Smckusick { 46745480Smckusick register struct buf *bp = (struct buf *)cbp->b_saveaddr;/* XXX */ 46841480Smckusick register int unit = (cbp->b_pfcent >> 16) & 0xFFFF; /* XXX */ 46941480Smckusick int count, s; 47041480Smckusick 47141480Smckusick s = splbio(); 47241480Smckusick #ifdef DEBUG 47341480Smckusick if (cddebug & CDB_FOLLOW) 47441480Smckusick printf("cdiodone(%x)\n", cbp); 47541480Smckusick if (cddebug & CDB_IO) { 47641480Smckusick printf("cdiodone: bp %x bcount %d resid %d\n", 47741480Smckusick bp, bp->b_bcount, bp->b_resid); 47841480Smckusick printf(" dev %x(u%d), cbp %x bn %d addr %x bcnt %d\n", 47941480Smckusick cbp->b_dev, cbp->b_pfcent & 0xFFFF, cbp, 48041480Smckusick cbp->b_blkno, cbp->b_un.b_addr, cbp->b_bcount); 48141480Smckusick } 48241480Smckusick #endif 48341480Smckusick 48441480Smckusick if (cbp->b_flags & B_ERROR) { 48541480Smckusick bp->b_flags |= B_ERROR; 48645480Smckusick bp->b_error = biowait(cbp); 48741480Smckusick #ifdef DEBUG 48841480Smckusick printf("cd%d: error %d on component %d\n", 48941480Smckusick unit, bp->b_error, cbp->b_pfcent & 0xFFFF); 49041480Smckusick #endif 49141480Smckusick } 49241480Smckusick count = cbp->b_bcount; 49341480Smckusick putcbuf(cbp); 49441480Smckusick 49541480Smckusick /* 49641480Smckusick * If all done, "interrupt". 49741480Smckusick * Again, sc_bp is only used to preserve the traditional interface. 49841480Smckusick */ 49941480Smckusick bp->b_resid -= count; 50041480Smckusick if (bp->b_resid < 0) 50141480Smckusick panic("cdiodone: count"); 50241480Smckusick if (bp->b_resid == 0) { 50341480Smckusick cd_softc[unit].sc_bp = bp; 50441480Smckusick cdintr(unit); 50541480Smckusick } 50641480Smckusick splx(s); 50741480Smckusick } 50841480Smckusick 50941480Smckusick cdread(dev, uio) 51041480Smckusick dev_t dev; 51141480Smckusick struct uio *uio; 51241480Smckusick { 51341480Smckusick register int unit = cdunit(dev); 51441480Smckusick 51541480Smckusick #ifdef DEBUG 51641480Smckusick if (cddebug & CDB_FOLLOW) 51741480Smckusick printf("cdread(%x, %x)\n", dev, uio); 51841480Smckusick #endif 51941480Smckusick return(physio(cdstrategy, &cdbuf[unit], dev, B_READ, minphys, uio)); 52041480Smckusick } 52141480Smckusick 52241480Smckusick cdwrite(dev, uio) 52341480Smckusick dev_t dev; 52441480Smckusick struct uio *uio; 52541480Smckusick { 52641480Smckusick register int unit = cdunit(dev); 52741480Smckusick 52841480Smckusick #ifdef DEBUG 52941480Smckusick if (cddebug & CDB_FOLLOW) 53041480Smckusick printf("cdwrite(%x, %x)\n", dev, uio); 53141480Smckusick #endif 53241480Smckusick return(physio(cdstrategy, &cdbuf[unit], dev, B_WRITE, minphys, uio)); 53341480Smckusick } 53441480Smckusick 53541480Smckusick cdioctl(dev, cmd, data, flag) 53641480Smckusick dev_t dev; 53741480Smckusick int cmd; 53841480Smckusick caddr_t data; 53941480Smckusick int flag; 54041480Smckusick { 54141480Smckusick return(EINVAL); 54241480Smckusick } 54341480Smckusick 54441480Smckusick cdsize(dev) 54541480Smckusick dev_t dev; 54641480Smckusick { 54741480Smckusick int unit = cdunit(dev); 54841480Smckusick register struct cd_softc *cs = &cd_softc[unit]; 54941480Smckusick 55041480Smckusick if (unit >= NCD || (cs->sc_flags & CDF_INITED) == 0) 55141480Smckusick return(-1); 55241480Smckusick return(cs->sc_size); 55341480Smckusick } 55441480Smckusick 55541480Smckusick cddump(dev) 55641480Smckusick { 55741480Smckusick return(ENXIO); 55841480Smckusick } 55941480Smckusick #endif 560