V7/usr/sys/dev/tc.c
#
/*
* TC-11 DECtape driver
*/
#include "../h/param.h"
#include "../h/conf.h"
#include "../h/buf.h"
#include "../h/dir.h"
#include "../h/user.h"
struct device {
int tccsr;
union wb {
int w;
char b[2];
} tccm;
int tcwc;
int tcba;
int tcdt;
};
struct buf tctab;
char tcper[8];
#define TCADDR ((struct device *) 0177340)
#define NTCBLK 578
#define TAPERR 0100000
#define TREV 04000
#define READY 0200
#define IENABLE 0100
#define UPS 0200
#define ENDZ 0100000
#define BLKM 02000
#define ILGOP 010000
#define SELERR 04000
#define SAT 0
#define RNUM 02
#define RDATA 04
#define SST 010
#define WDATA 014
#define GO 01
#define SFORW 1
#define SREV 2
#define SIO 3
tcclose(dev)
{
bflush(dev);
tcper[dev&07] = 0;
}
tcstrategy(bp)
register struct buf *bp;
{
if(bp->b_flags&B_PHYS)
mapalloc(bp);
bp->b_resid = 0;
if(bp->b_blkno >= NTCBLK || tcper[minor(bp->b_dev)&07]) {
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
bp->av_forw = 0;
spl6();
if (tctab.b_actf==0)
tctab.b_actf = bp;
else
tctab.b_actl->av_forw = bp;
tctab.b_actl = bp;
if (tctab.b_active==0)
tcstart();
spl0();
}
tcstart()
{
register struct buf *bp;
register int com;
register union wb *tccmp;
loop:
tccmp = &TCADDR->tccm;
if ((bp = tctab.b_actf) == 0)
return;
if(tcper[minor(bp->b_dev)&07]) {
if((tctab.b_actf = bp->av_forw) == 0)
tccmp->b[0] = SAT|GO;
bp->b_flags |= B_ERROR;
iodone(bp);
goto loop;
}
if ((tccmp->b[1]&07) != minor(bp->b_dev))
tccmp->b[0] = SAT|GO;
tctab.b_errcnt = 20;
tctab.b_active = SFORW;
com = (minor(bp->b_dev)<<8) | IENABLE|RNUM|GO;
if ((TCADDR->tccsr & UPS) == 0) {
com |= TREV;
tctab.b_active = SREV;
}
tccmp->w = com;
}
tcintr()
{
register struct buf *bp;
register union wb *tccmp;
register int *tcdtp;
tccmp = &TCADDR->tccm;
tcdtp = &TCADDR->tccsr;
bp = tctab.b_actf;
if (tccmp->w&TAPERR) {
if((*tcdtp&(ENDZ|BLKM)) == 0)
deverror(bp, *tcdtp, 0);
if(*tcdtp & (ILGOP|SELERR)) {
tcper[bp->b_dev&07]++;
tctab.b_errcnt = 0;
}
tccmp->w &= ~TAPERR;
if (--tctab.b_errcnt == 0) {
bp->b_flags |= B_ERROR;
goto done;
}
if (tccmp->w&TREV) {
setforw:
tctab.b_active = SFORW;
tccmp->w &= ~TREV;
} else {
setback:
tctab.b_active = SREV;
tccmp->w |= TREV;
}
tccmp->b[0] = IENABLE|RNUM|GO;
return;
}
tcdtp = &TCADDR->tcdt;
switch (tctab.b_active) {
case SIO:
done:
tctab.b_active = 0;
if (tctab.b_actf = bp->av_forw)
tcstart();
else
TCADDR->tccm.b[0] = SAT|GO;
iodone(bp);
return;
case SFORW:
if (*tcdtp > bp->b_blkno)
goto setback;
if (*tcdtp < bp->b_blkno)
goto setforw;
*--tcdtp = (int)bp->b_un.b_addr; /* core address */
*--tcdtp = -(bp->b_bcount>>1);
tccmp->b[0] = ((bp->b_xmem & 03) << 4) | IENABLE|GO
| (bp->b_flags&B_READ?RDATA:WDATA);
tctab.b_active = SIO;
return;
case SREV:
if (*tcdtp+3 > bp->b_blkno)
goto setback;
goto setforw;
}
}