/* * 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/file.h" #include "../h/user.h" struct device { int htcs1; int htwc; caddr_t htba; int htfc; int htcs2; int htds; int hter; int htas; int htck; int htdb; int htmr; int htdt; int htsn; int httc; int htbae; /* 11/70 bus extension */ int htcs3; }; struct buf httab; struct buf rhtbuf; struct buf chtbuf; #define NUNIT 1 #define INF 1000000 char h_flags[NUNIT]; char h_openf[NUNIT]; daddr_t h_blkno[NUNIT]; daddr_t h_nxrec[NUNIT]; #define HTADDR ((struct device *)0172440) #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 01300 /* 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 CLR 040 /* controller clear (in cs2) */ #define NED 010000 #define SIO 1 #define SSFOR 2 #define SSREV 3 #define SRETRY 4 #define SCOM 5 #define SOK 6 #define H_WRITTEN 1 htopen(dev, flag) { register unit, ds; httab.b_flags |= B_TAPE; unit = minor(dev) & 077; if (unit >= NUNIT || h_openf[unit]) { u.u_error = ENXIO; return; } h_blkno[unit] = 0; h_nxrec[unit] = INF; h_flags[unit] = 0; 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) & 077; if (flag == FWRITE || ((flag&FWRITE) && (h_flags[unit]&H_WRITTEN))) { hcommand(dev, WEOF); hcommand(dev, WEOF); hcommand(dev, SREV); } if ((minor(dev)&0200) == 0) hcommand(dev, REW); 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((caddr_t)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((caddr_t)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)&077]; 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; h_flags[minor(bp->b_dev)&077] |= H_WRITTEN; } } 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) & 0177; HTADDR->htcs2 = ((unit>>3)&07); den = P1600 | (unit&07); if(unit > 077) den = P800 | (unit&07); if((HTADDR->httc&03777) != den) HTADDR->httc = den; if (HTADDR->htcs2 & NED || (HTADDR->htds&MOL)==0) goto abort; unit &= 077; blkno = h_blkno[unit]; if (bp == &chtbuf) { if (bp->b_resid==NOP) { bp->b_resid = HTADDR->htds; goto next; } httab.b_active = SCOM; HTADDR->htfc = 0; HTADDR->htcs1 = bp->b_resid|IENABLE|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->htba = bp->b_un.b_addr; if(cputype == 70) HTADDR->htbae = bp->b_xmem; HTADDR->htfc = -bp->b_bcount; HTADDR->htwc = -(bp->b_bcount>>1); den = ((bp->b_xmem&3) << 8) | IENABLE | GO; if(bp->b_flags & B_READ) den |= RCOM; else { if(HTADDR->htds & EOT) { bp->b_resid = bp->b_bcount; goto next; } den |= WCOM; } HTADDR->htcs1 = den; } else { if (blkno < bp->b_blkno) { httab.b_active = SSFOR; HTADDR->htfc = blkno - bp->b_blkno; HTADDR->htcs1 = SFORW|IENABLE|GO; } else { httab.b_active = SSREV; HTADDR->htfc = bp->b_blkno - blkno; HTADDR->htcs1 = SREV|IENABLE|GO; } } return; abort: bp->b_flags |= B_ERROR; next: httab.b_actf = bp->av_forw; iodone(bp); goto loop; } htintr() { register struct buf *bp; register int unit, state; int err; if ((bp = httab.b_actf)==NULL) return; unit = minor(bp->b_dev) & 077; state = httab.b_active; httab.b_active = 0; if (HTADDR->htcs1&TRE) { err = HTADDR->hter; if (HTADDR->htcs2&077400 || (err&HARD)) state = 0; if (bp == &rhtbuf) err &= ~FCE; if ((bp->b_flags&B_READ) && (HTADDR->htds&PES)) err &= ~(CS|COR); if((HTADDR->htds&MOL) == 0) { if(h_openf[unit]) h_openf[unit] = -1; } else if(HTADDR->htds&TM) { HTADDR->htwc = -(bp->b_bcount>>1); h_nxrec[unit] = bp->b_blkno; state = SOK; } else if(state && err == 0) state = SOK; if(httab.b_errcnt > 4) deverror(bp, HTADDR->hter, HTADDR->htcs2); htinit(); if (state==SIO && ++httab.b_errcnt < 10) { httab.b_active = SRETRY; h_blkno[unit]++; HTADDR->htfc = -1; HTADDR->htcs1 = SREV|IENABLE|GO; return; } if (state!=SOK) { bp->b_flags |= B_ERROR; state = SIO; } } else if (HTADDR->htcs1 < 0) { /* SC */ if(HTADDR->htds & ERR) htinit(); } switch(state) { case SIO: case SOK: h_blkno[unit]++; case SCOM: httab.b_errcnt = 0; httab.b_actf = bp->av_forw; iodone(bp); bp->b_resid = (-HTADDR->htwc)<<1; break; case SRETRY: if((bp->b_flags&B_READ)==0) { httab.b_active = SSFOR; HTADDR->htcs1 = ERASE|IENABLE|GO; return; } case SSFOR: case SSREV: if(HTADDR->htds & TM) { if(state == SSREV) { h_nxrec[unit] = bp->b_blkno - HTADDR->htfc; h_blkno[unit] = h_nxrec[unit]; } else { h_nxrec[unit] = bp->b_blkno + HTADDR->htfc - 1; h_blkno[unit] = h_nxrec[unit]+1; } } else h_blkno[unit] = bp->b_blkno; break; default: return; } htstart(); } htinit() { register ocs2; register omttc; omttc = HTADDR->httc & 03777; /* preserve old slave select, dens, format */ ocs2 = HTADDR->htcs2 & 07; /* preserve old unit */ HTADDR->htcs2 = CLR; HTADDR->htcs2 = ocs2; HTADDR->httc = omttc; HTADDR->htcs1 = DCLR|GO; } 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) & 077; if(unit < NUNIT) { a = u.u_offset >> 9; h_blkno[unit] = a; h_nxrec[unit] = a+1; } }