/* * TJU16 tape driver */ #include "../h/param.h" #include "../h/systm.h" #include "../h/buf.h" #include "../h/conf.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/uba.h" #include "../h/map.h" #include "../h/mba.h" struct device { int htcs1; int htds; int hter; int htmr; int htas; int htfc; int htdt; int htck; int htsn; int httc; }; struct buf httab; struct buf rhtbuf; struct buf chtbuf; #define NUNIT 1 #define BUNIT 2 #define INF 1000000 char h_openf[NUNIT]; daddr_t h_blkno[NUNIT]; daddr_t h_nxrec[NUNIT]; #define HTADDR ((struct device *)(MBA1 + MBA_ERB)) #define GO 01 #define WCOM 060 #define RCOM 070 #define NOP 0 #define WEOF 026 #define SFORW 030 #define SREV 032 #define ERASE 024 #define REW 06 #define DCLR 010 #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 064023 /* 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 = minor(dev) & 03; if (unit >= NUNIT || h_openf[unit]) { u.u_error = ENXIO; return; } h_blkno[unit] = 0; h_nxrec[unit] = INF; ds = hcommand(dev, NOP); if ((ds&MOL)==0 || (flag && (ds&WRL))) u.u_error = ENXIO; if (u.u_error==0) h_openf[unit]++; } htclose(dev, flag) { register int unit; unit = minor(dev) & 03; if (flag) { hcommand(dev, WEOF); hcommand(dev, WEOF); } /* hcommand(dev, REW); */ /* for 'mtm' file positioning */ if((minor(dev)&4) == 0) /* no 4 -> rewind */ hcommand(dev,REW) ; else if(flag) /* no rewind - backup over last EOF */ hcommand(dev&(~4),SREV) ; h_openf[unit] = 0; } hcommand(dev, 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 = dev; 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[minor(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) { bp->b_resid = bp->b_bcount; clrbuf(bp); 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 unit, den; daddr_t blkno; loop: if ((bp = httab.b_actf) == NULL) return; unit = minor(bp->b_dev); den = P800 | (unit&03); if(unit >= 8) den = P1600 | (unit&03); if((HTADDR->httc&03777) != den) HTADDR->httc = den; unit &= 03; blkno = h_blkno[unit]; if (bp == &chtbuf) { if (bp->b_resid==NOP) { bp->b_resid = HTADDR->htds & 0xffff; goto next; } httab.b_active = SCOM; HTADDR->htfc = 0; HTADDR->htcs1 = bp->b_resid|GO; return; } if (h_openf[unit] < 0 || bp->b_blkno > h_nxrec[unit]) goto abort; if (blkno == bp->b_blkno) { httab.b_active = SIO; HTADDR->htfc = -bp->b_bcount; mbastart(bp, HTADDR); } else { if (blkno < bp->b_blkno) { httab.b_active = SSFOR; HTADDR->htfc = blkno - bp->b_blkno; HTADDR->htcs1 = SFORW|GO; } else { httab.b_active = SSREV; HTADDR->htfc = bp->b_blkno - blkno; HTADDR->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; int err; if ((bp = httab.b_actf)==NULL) return; unit = minor(bp->b_dev) & 03; state = httab.b_active; httab.b_active = 0; if (HTADDR->htds&(ERR|EOT|TM) || mbastat & MBAEBITS) { err = HTADDR->hter & 0xffff; /* printf("ht2:mbas=%x, ds=%x, err=%x\n", mbastat, HTADDR->htds, err); */ if ((mbastat & MBAEBITS) || (err&HARD)) state = 0; if (bp == &rhtbuf) err &= ~FCE; if ((bp->b_flags&B_READ) && (HTADDR->htds&PES)) err &= ~(CS|COR); if(HTADDR->htds&EOT || (HTADDR->htds&MOL)==0) { if(h_openf[unit]) h_openf[unit] = -1; } else if(HTADDR->htds&TM) { HTADDR->htfc = 0; h_nxrec[unit] = bp->b_blkno; state = SOK; } else if(state && err == 0) state = SOK; if(httab.b_errcnt > 4) { deverror(bp, HTADDR->hter, mbastat); } ((struct mba_regs *)MBA1)->mba_cr &= ~MBAIE; HTADDR->htcs1 = DCLR|GO; ((struct mba_regs *)MBA1)->mba_cr |= MBAIE; if (state==SIO && ++httab.b_errcnt < 10) { httab.b_active = SRETRY; h_blkno[unit]++; HTADDR->htfc = -1; HTADDR->htcs1 = SREV|GO; return; } if (state!=SOK) { bp->b_flags |= B_ERROR; state = SIO; } } else if (HTADDR->htcs1 < 0) { /* SC */ if(HTADDR->htds & ERR) { ((struct mba_regs *)MBA1)->mba_cr &= ~MBAIE; HTADDR->htcs1 = DCLR|GO; ((struct mba_regs *)MBA1)->mba_cr |= MBAIE; } } switch(state) { case SIO: case SOK: h_blkno[unit]++; case SCOM: httab.b_errcnt = 0; httab.b_actf = bp->av_forw; bp->b_resid = - (HTADDR->htfc & 0xffff); if (bp->b_flags & B_READ) bp->b_resid += bp->b_bcount; iodone(bp); break; case SRETRY: if((bp->b_flags&B_READ)==0) { httab.b_active = SSFOR; HTADDR->htcs1 = ERASE|GO; return; } case SSFOR: case SSREV: if(HTADDR->htds & TM) { if(state == SSREV) { h_nxrec[unit] = bp->b_blkno - (HTADDR->htfc&0xffff); h_blkno[unit] = h_nxrec[unit]; } else { h_nxrec[unit] = bp->b_blkno + (HTADDR->htfc & 0xffff) - 1; h_blkno[unit] = bp->b_blkno + (HTADDR->htfc & 0xffff); } } 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 = minor(dev) & 03; if(unit < NUNIT) { a = u.u_offset >> 9; h_blkno[unit] = a; h_nxrec[unit] = a+1; } }