home *** CD-ROM | disk | FTP | other *** search
- /*
- * This driver runs the RD50/51 controller on the pro3xx. It
- * expects bad sector forwarding
- * tables to be in a BAD144 style. Bad sectors are marked by writing a nonzero
- * backup revision field in the sector header. The standalone program, "rdfmt"
- * should be run to format and bad scan the disk before this driver is used
- * if BADSECT is enabled.
- */
-
- #include "rd.h"
- #if NRD > 0
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/buf.h>
- #include <sys/dir.h>
- #include <sys/conf.h>
- #include <sys/user.h>
- #include <sys/seg.h>
- #ifndef INTRLVE
- #include <sys/inline.h>
- #endif INTRLVE
- #ifdef BADSECT
- #include <sys/dkbad.h>
- #endif BADSECT
- #include <sys/ivecpos.h>
- #include <sys/rdreg.h>
-
-
- #define OPEN 1
- #define GOTBAD 2
-
- extern struct size rd_sizes[];
- extern struct rddevice *RDADDR;
-
- struct buf rdtab;
- struct buf rrdbuf;
- #ifdef BADSECT
- struct dkbad rdbad;
- #endif BADSECT
- union wordval rdval;
- struct rdst rdst[] = {
- 16, 4, 16*4, 305,
- 16, 4, 16*4, 152,
- 0, 0, 0, 0,
- };
-
- struct rd_softc {
- char sc_stat;
- char sc_type;
- } rd_softc;
-
- void rdroot()
- {
- rdattach(RDADDR, 0);
- }
-
- rdattach(addr, unit)
- struct rddevice *addr;
- {
- if (unit == 0) {
- RDADDR = addr;
- return(1);
- }
- return(0);
- }
-
- rdopen(dev) {
- register int cnt, *ptr, tmp;
-
- if (rd_softc.sc_stat & OPEN)
- return;
- rd_softc.sc_stat |= OPEN;
- rdinit();
- if (!(rd_softc.sc_stat & GOTBAD)) {
- while (1) {
- RDADDR->sec = 0;
- RDADDR->trk = rdst[rd_softc.sc_type].ntrak-1;
- RDADDR->cyl = rdst[rd_softc.sc_type].ncyl;
- RDADDR->csr = RD_READCOM;
- while (RDADDR->st & RD_BUSY) ;
- if (RDADDR->csr & RD_ERROR) {
- if (RDADDR->err & RD_IDNF)
- rd_softc.sc_type++;
- rdinit();
- } else {
- #ifdef BADSECT
- ptr = &rdbad;
- #endif BADSECT
- for (cnt = 0; cnt < 256; cnt++) {
- while ((RDADDR->st & RD_DRQ) == 0) ;
- #ifdef BADSECT
- if (cnt < ((sizeof rdbad)/2))
- *ptr++ = RDADDR->db;
- else
- #endif BADSECT
- tmp = RDADDR->db;
- }
- break;
- }
- }
- rd_softc.sc_stat |= GOTBAD;
- }
- }
-
- rdstrategy(bp)
- register struct buf *bp;
- {
- register struct buf *dp;
- register struct rdst *st;
- register int unit;
- int s;
- long bn;
- long sz;
-
- unit = minor(bp->b_dev)&07;
- sz = bp->b_bcount;
- sz = (sz+511)>>9;
- st = &rdst[rd_softc.sc_type];
- if (unit >= (NRD<<3) || (RDADDR == (struct rddevice *) NULL)) {
- bp->b_error = ENXIO;
- goto errexit;
- }
- if (bp->b_blkno < 0 || ((bn = dkblock(bp))+sz > rd_sizes[unit].nblocks
- && rd_sizes[unit].nblocks >= 0)) {
- bp->b_error = EINVAL;
- errexit:
- bp->b_flags |= B_ERROR;
- iodone(bp);
- return;
- }
- bp->b_cylin = bn/st->nspc+rd_sizes[unit].cyloff;
- dp = &rdtab;
- (void) _spl4();
- disksort(dp, bp);
- if (dp->b_active == NULL)
- rdstart();
- (void) _spl0();
- }
-
- rdstart()
- {
- register struct buf *bp;
- register int unit;
-
- if ((bp = rdtab.b_actf) == NULL)
- return;
- bp->b_resid = bp->b_bcount;
- rdstrt(dkblock(bp), bp);
- #ifdef RD_DKN
- dk_busy |= 1<<RD_DKN;
- dk_numb[RD_DKN] += 1;
- #endif RD_DKN
- }
-
- rdstrt(bn, bp)
- daddr_t bn;
- register struct buf *bp;
- {
- register u_short cnt;
- register char *ptr;
- register struct rdst *st;
- long taddr;
- int sn;
- u_short xfer;
-
- rdtab.b_active++;
- st = &rdst[rd_softc.sc_type];
- while (RDADDR->st & RD_BUSY)
- ;
- RDADDR->cyl = bn/(st->nspc)+rd_sizes[minor(bp->b_dev)&07].cyloff;
- sn = bn % st->nspc;
- RDADDR->trk = sn / st->nsect;
- RDADDR->sec = sn % st->nsect;
- if (bp->b_flags & B_READ) {
- ienable(IVEC(RDADDR, APOS));
- ienable(IVEC(RDADDR, BPOS));
- RDADDR->csr = RD_READCOM;
- } else {
- /* Kernel seg. 5 is used to map the i/o buffer into kernel
- * virtual so that the copy loop can be performed.
- */
- segm save;
- xfer = (bp->b_resid < 01000)?bp->b_resid:01000;
- taddr = (((((long)bp->b_xmem)<<16)&0x3f0000l)|
- (((long)bp->b_un.b_addr)&0xffff))+
- (bp->b_bcount-bp->b_resid);
- ptr = (char *)((taddr & 077)+SEG5);
- ienable(IVEC(RDADDR, APOS));
- RDADDR->csr = RD_WRITECOM;
- saveseg5(save);
- mapseg5(((caddr_t)(taddr>>6)), 04406);
- for (cnt = 0; cnt < 0400; cnt++) {
- while ((RDADDR->st & RD_DRQ) == 0)
- ;
- if (cnt < (xfer/02)) {
- rdval.byte[0] = *ptr++;
- rdval.byte[1] = *ptr++;
- }
- RDADDR->db = rdval.word;
- }
- restorseg5(save);
- }
- }
-
- /* This interrupt service routine is accessed via. both the A and B vectors */
- rdintr()
- {
- register struct buf *bp;
- register u_short cnt;
- register char *ptr;
- long taddr;
- daddr_t bn;
- u_short xfer;
-
- if (rdtab.b_active == NULL) {
- idisable(IVEC(RDADDR, APOS));
- idisable(IVEC(RDADDR, BPOS));
- return;
- }
- #ifdef RD_DKN
- dk_busy &= ~(1<<RD_DKN);
- #endif RD_DKN
- bp = rdtab.b_actf;
- rdtab.b_active = NULL;
- while (RDADDR->st & RD_BUSY)
- ;
- if ((RDADDR->csr & (RD_WFAULT|RD_ERROR))
- #ifdef BADSECT
- || (RDADDR->sec & 0177400)
- #endif
- ) {
- #ifdef BADSECT
- if ((RDADDR->err & (RD_DMNF|RD_IDNF|RD_CRC)) || (RDADDR->sec & 0177400)) {
- idisable(IVEC(RDADDR, APOS));
- idisable(IVEC(RDADDR, BPOS));
- if (baderr(bp)) {
- return;
- }
- }
- #endif
- if (++rdtab.b_errcnt <= 10) {
- rdinit();
- bn = dkblock(bp)+((bp->b_bcount-bp->b_resid)>>9);
- idisable(IVEC(RDADDR, APOS));
- idisable(IVEC(RDADDR, BPOS));
- rdstrt(bn, bp);
- return;
- }
- #ifdef UCB_DEVERR
- harderr(bp, "rd");
- printf("cs=%b er=%b\n",RDADDR->csr,RDCS_BITS,RDADDR->err,RDER_BITS);
- #else
- deverror(bp, RDADDR->csr, RDADDR->err);
- #endif
- rdinit();
- bp->b_flags |= B_ERROR;
- rdtab.b_errcnt = 0;
- rdtab.b_actf = bp->av_forw;
- bp->b_resid = 0;
- iodone(bp);
- idisable(IVEC(RDADDR, APOS));
- idisable(IVEC(RDADDR, BPOS));
- rdstart();
- return;
- }
- xfer = (bp->b_resid < 01000)?bp->b_resid:01000;
- if (bp->b_flags & B_READ) {
- segm save;
- taddr = (((((long)bp->b_xmem)<<16)&0x3f0000l)|
- (((long)bp->b_un.b_addr)&0xffff))+
- (bp->b_bcount-bp->b_resid);
- ptr = (char *)((taddr & 077)+SEG5);
- saveseg5(save);
- mapseg5(((caddr_t)(taddr>>6)), 04406);
- for (cnt = 0; cnt < 0400; cnt++) {
- while ((RDADDR->st & RD_DRQ) == 0)
- ;
- rdval.word = RDADDR->db;
- if (cnt < (xfer/02)) {
- *ptr++ = rdval.byte[0];
- *ptr++ = rdval.byte[1];
- }
- }
- restorseg5(save);
- }
- rdtab.b_errcnt = 0;
- bp->b_resid -= xfer;
- if (bp->b_resid == 0) {
- rdtab.b_actf = bp->av_forw;
- iodone(bp);
- idisable(IVEC(RDADDR, APOS));
- idisable(IVEC(RDADDR, BPOS));
- rdstart();
- return;
- }
- bn = dkblock(bp)+((bp->b_bcount-bp->b_resid)>>9);
- idisable(IVEC(RDADDR, APOS));
- idisable(IVEC(RDADDR, BPOS));
- rdstrt(bn, bp);
- }
-
- rdinit()
- {
- RDADDR->st = RD_INIT;
- while (RDADDR->st & RD_BUSY)
- ;
- RDADDR->csr = RD_RESTORE;
- while ((RDADDR->st & RD_BUSY) || (!(RDADDR->st & RD_OPENDED)))
- ;
- }
-
- rdread(dev)
- {
-
- physio(rdstrategy, &rrdbuf, dev, B_READ);
- }
-
- rdwrite(dev)
- {
-
- physio(rdstrategy, &rrdbuf, dev, B_WRITE);
- }
- #ifdef BADSECT
- baderr(bp)
- struct buf *bp;
- {
- register int sn,cn;
- register struct rdst *st;
- int tn;
- daddr_t bn, isbad();
-
- st = &rdst[rd_softc.sc_type];
- bn = dkblock(bp) + ((bp->b_bcount-bp->b_resid)>>9)+
- rd_sizes[(minor(bp->b_dev)&07)].cyloff;
- cn = bn/(st->nspc);
- sn = bn%(st->nspc);
- tn = sn/(st->nsect);
- sn %= (st->nsect);
- if ((bn = isbad(&rdbad, cn, tn, sn)) < 0)
- return(0);
- cn = st->ncyl-rd_sizes[(minor(bp->b_dev)&07)].cyloff;
- bn = cn*st->nspc+st->nsect*(st->ntrak-1)-1-bn;
- rdstrt(bn, bp);
- return(1);
- }
- #endif
- #ifdef RD_DUMP
- /* This is the RD50/51 dump routine. It uses mapin/mapout to get
- * at all of memory.
- */
-
- rddump(dev)
- dev_t dev;
- {
- register int *ptr, cnt;
- register struct rdst *st = &rdst[rd_softc.sc_type];
- daddr_t bn, dumpsize;
- long paddr;
- int sn, unit;
- segm save;
-
- unit = minor(dev) >> 3;
- if ((bdevsw[major(dev)].d_strategy != rdstrategy)
- || unit >= NRD)
- return(EINVAL);
- dumpsize = rd_sizes[minor(dev)&07].nblocks;
- if ((dumplo < 0) || (dumplo >= dumpsize))
- return(EINVAL);
- dumpsize -= dumplo;
- /* Initialize the controller/drive */
- rdinit();
- /* Loop until dump complete */
- for (paddr = 0L; dumpsize > 0; dumpsize--) {
- bn = dumplo + (paddr>>PGSHIFT);
- RDADDR->cyl = (bn/st->nspc) + rd_sizes[minor(dev)&07].cyloff;
- sn = bn%st->nspc;
- RDADDR->trk = sn/st->nsect;
- RDADDR->sec = sn%st->nsect;
- RDADDR->csr = RD_WRITECOM;
- ptr = (int *)((paddr & 077)+SEG5);
- saveseg5(save);
- mapseg5(((caddr_t)(paddr>>6)), 04406);
- for (cnt = 0; cnt < 256; cnt++) {
- while ((RDADDR->st & RD_DRQ) == 0)
- ;
- RDADDR->db = *ptr++;
- }
- restorseg5(save);
- while ((RDADDR->st & RD_BUSY) || (!(RDADDR->st & RD_OPENDED)))
- ;
- if ((RDADDR->csr & (RD_WFAULT|RD_ERROR))
- return(EIO);
- paddr += (1<<PGSHIFT);
- }
- return(0);
- }
- #endif RD_DUMP
- #endif
-