/* * TJU16 tape driver * Handles one TM02 controller, up to 4 TU16 slave transports * minor device classes: * bits 0,1: slave select * bit 2 off: rewind on close; on: position after first TM * bit 3 off: 800 bpi; on: 1600 bpi */ #include "sys/param.h" #include "sys/systm.h" #include "sys/buf.h" #include "sys/dir.h" #include "sys/user.h" #include "sys/file.h" #include "sys/elog.h" #include "sys/iobuf.h" #include "sys/mba.h" struct device { int htcs1, htds, hter, htmr; int htas, htfc, htdt, htck; int htsn, httc; }; #define NUNIT 4 struct iostat htstat[NUNIT]; struct iobuf httab = tabinit(HT0,htstat); struct buf rhtbuf, chtbuf; #define INF 1000000 char h_openf[NUNIT]; int h_den[NUNIT]; int h_eot[NUNIT]; daddr_t h_blkno[NUNIT]; daddr_t h_nxrec[NUNIT]; #define mbaddr ((struct mba *)0x80050000) #define mbactl (mbaddr->mba_ireg.mba_regs) #define mbadev (mbaddr->mba_ereg) #define GO 01 #define NOP 0 #define WEOF 026 #define SFORW 030 #define SREV 032 #define ERASE 024 #define REW 06 #define DCLR 010 #define WCOM 060 #define RCOM 070 #define P800 01700 /* 800 + pdp11 mode */ #define P1600 02300 /* 1600 + pdp11 mode */ #define IENABLE 0100 #define RDY 0200 #define TM 04 #define DRY 0200 #define EOT 02000 #define CS 02000 #define COR 0100000 #define PES 040 #define WRL 04000 #define MOL 010000 #define ERR 040000 #define FCE 01000 #define TRE 040000 #define HARD 064027 /* UNS|OPI|NEF|FMT|RMR|ILR|ILF */ #define SIO 1 #define SSFOR 2 #define SSREV 3 #define SRETRY 4 #define SCOM 5 #define SOK 6 htopen(dev, flag) { register unit, ds; httab.b_flags |= B_TAPE; unit = dev&03; if (unit >= NUNIT || h_openf[unit]) { u.u_error = ENXIO; return; } httab.io_addr = (physadr)&mbadev[0]; httab.io_mba = (physadr)&mbactl; httab.io_nreg = NDEVREG; h_openf[unit]++; h_den[unit] = (dev&010 ? P1600 : P800)|unit; h_blkno[unit] = 0; h_nxrec[unit] = INF; ds = hcommand(unit, NOP); if ((ds&MOL)==0 || ((flag&FWRITE) && (ds&WRL))) { u.u_error = ENXIO; h_openf[unit] = 0; return; } if (flag&FAPPEND) { hcommand(unit, SFORW); hcommand(unit, SREV); } } htclose(dev, flag) { register unit; unit = dev&03; if (flag&FWRITE) { hcommand(unit, WEOF); hcommand(unit, WEOF); } if (dev&04) { if (flag&FWRITE) hcommand(unit, SREV); else { hcommand(unit, NOP); if (h_blkno[unit] <= h_nxrec[unit]) hcommand(unit, SFORW); } } else hcommand(unit, REW); h_openf[unit] = 0; } hcommand(unit, com) { register struct buf *bp; bp = &chtbuf; spl5(); while(bp->b_flags&B_BUSY) { bp->b_flags |= B_WANTED; sleep(bp, PRIBIO); } spl0(); bp->b_dev = unit; bp->b_resid = com; bp->b_blkno = 0; bp->b_flags = B_BUSY|B_READ; htstrategy(bp); iowait(bp); if (bp->b_flags&B_WANTED) wakeup(bp); bp->b_flags = 0; return(bp->b_resid); } htstrategy(bp) register struct buf *bp; { register daddr_t *p; if (bp != &chtbuf) { p = &h_nxrec[bp->b_dev&03]; if (bp->b_blkno > *p) { bp->b_flags |= B_ERROR; bp->b_error = ENXIO; iodone(bp); return; } if (bp->b_blkno == *p && bp->b_flags&B_READ) { clrbuf(bp); bp->b_resid = bp->b_bcount; iodone(bp); return; } if ((bp->b_flags&B_READ)==0) *p = bp->b_blkno + 1; } bp->av_forw = NULL; spl5(); if (httab.b_actf == NULL) httab.b_actf = bp; else httab.b_actl->av_forw = bp; httab.b_actl = bp; if (httab.b_active==0) htstart(); spl0(); } htstart() { register struct buf *bp; register int unit; register struct device *rp; daddr_t blkno; rp = (struct device *)&mbadev[0]; loop: if ((bp = httab.b_actf) == NULL) return; unit = bp->b_dev&03; rp->htas = 1<<0; if ((rp->httc&03777) != h_den[unit]) rp->httc = h_den[unit]; if ((rp->htds&(MOL|DRY)) != (MOL|DRY)) goto abort; blkno = h_blkno[unit]; if (bp == &chtbuf) { if (bp->b_resid==NOP) { bp->b_resid = rp->htds & 0xffff; goto next; } htstat[unit].io_misc++; httab.b_active = SCOM; rp->htfc = 0; rp->htcs1 = bp->b_resid|GO; return; } if (h_openf[unit] < 0 || bp->b_blkno > h_nxrec[unit]) goto abort; if (blkno == bp->b_blkno) { if (h_eot[unit] > 8) goto abort; if ((bp->b_flags&B_READ)==0 && h_eot[unit] && blkno > h_eot[unit]) { bp->b_error = ENOSPC; goto abort; } httab.b_active = SIO; rp->htfc = -bp->b_bcount; htstat[unit].io_ops++; blkacty |= (1<<HT0); mbastart(bp, rp, mbaddr); } else { htstat[unit].io_misc++; if (blkno < bp->b_blkno) { httab.b_active = SSFOR; rp->htfc = blkno - bp->b_blkno; rp->htcs1 = SFORW|GO; } else { httab.b_active = SSREV; rp->htfc = bp->b_blkno - blkno; rp->htcs1 = SREV|GO; } } return; abort: bp->b_flags |= B_ERROR; next: httab.b_actf = bp->av_forw; iodone(bp); goto loop; } htintr(mbastat, as) { register struct buf *bp; register int unit, state; register struct device *rp; int err; rp = (struct device *)&mbadev[0]; if ((bp = httab.b_actf)==NULL) { logstray(rp); return; } blkacty &= ~(1<<HT0); unit = bp->b_dev&03; state = httab.b_active; httab.b_active = 0; if (mbastat & MBADTABT) { err = rp->hter & 0xffff; if (err&HARD) state = 0; if (bp == &rhtbuf) err &= ~FCE; if ((bp->b_flags&B_READ) && (rp->htds&PES)) err &= ~(CS|COR); if ((rp->htds&MOL)==0) h_openf[unit] = -1; else if (rp->htds&TM) { mbactl.mba_bcr = -bp->b_bcount; h_nxrec[unit] = bp->b_blkno; state = SOK; } else if (state && err == 0) state = SOK; if (state != SOK) { httab.io_stp = &htstat[unit]; fmtberr(&httab,0); } if (httab.b_errcnt > 2) deverr(&httab, rp->hter, mbastat); rp->htcs1 = DCLR|GO; if (state==SIO && ++httab.b_errcnt < 10) { httab.b_active = SRETRY; h_blkno[unit]++; rp->htfc = -1; htstat[unit].io_misc++; rp->htcs1 = SREV|GO; return; } if (state!=SOK) { bp->b_flags |= B_ERROR; state = SIO; } } else if (rp->htds & ERR) { if ((rp->htds & TM) == 0) { httab.io_stp = &htstat[unit]; fmtberr(&httab,0); } rp->htcs1 = DCLR|GO; } switch(state) { case SIO: case SOK: h_blkno[unit]++; case SCOM: if (rp->htds&EOT) h_eot[unit]++; else h_eot[unit] = 0; if (httab.io_erec) logberr(&httab,bp->b_flags&B_ERROR); httab.b_errcnt = 0; httab.b_actf = bp->av_forw; bp->b_resid = (-mbactl.mba_bcr) & 0xffff; iodone(bp); break; case SRETRY: if ((bp->b_flags&B_READ)==0) { htstat[unit].io_misc++; httab.b_active = SSFOR; rp->htcs1 = ERASE|GO; return; } case SSFOR: case SSREV: if (rp->htds & TM) { if (state == SSREV) { h_blkno[unit] = bp->b_blkno - (rp->htfc&0xffff); h_nxrec[unit] = h_blkno[unit]; } else { h_blkno[unit] = bp->b_blkno + (rp->htfc&0xffff); h_nxrec[unit] = h_blkno[unit] - 1; } } else h_blkno[unit] = bp->b_blkno; break; default: return; } htstart(); } htread(dev) { htphys(dev); physio(htstrategy, &rhtbuf, dev, B_READ); } htwrite(dev) { htphys(dev); physio(htstrategy, &rhtbuf, dev, B_WRITE); } htphys(dev) { register unit; daddr_t a; unit = dev&03; a = u.u_offset >> BSHIFT; h_blkno[unit] = a; h_nxrec[unit] = a+1; }