USG_PG3/usr/source/io1/ht.c
#
/*
* TU16 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 "../head/param.h"
#include "../head/systm.h"
#include "../head/buf.h"
#include "../head/bufx.h"
#include "../head/conf.h"
#include "../head/file.h"
#include "../head/user.h"
#include "../head/userx.h"
#include "../head/elog.h"
#define NHT 4
#define HTADDR 0172440
struct htregs {
int htcs1, htwc, htba, htfc;
int htcs2, htds, hter, htas;
int htck, htdb, htmr, htdt;
int htsn, httc, htbae, htcs3;
};
struct devtab httab;
struct buf rhtbuf, chtbuf;
struct iostat htstat[NHT];
struct errtab htetab { etabinit(E_BLK|E_RH70,NHT,HT,htstat) };
char h_openf[NHT];
int h_den[NHT];
char *h_blkno[NHT], *h_nxrec[NHT];
#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 P800 01300 /* 800 + pdp11 mode */
#define P1600 02300 /* 1600 + pdp11 mode */
#define IENABLE 0100
#define RDY 0200
#define TMARK 04
#define DRY 0200
#define EOT 02000
#define CS 02000
#define COR 0100000
#define PES 040
#define WRL 04000
#define MOL 010000
#define PIP 020000
#define ERR 040000
#define FCE 01000
#define TRE 040000
#define HARD 064023 /* UNS|OPI|NEF|FMT|RMR|ILR|ILF */
#define SSEEK 1
#define SIO 2
#define SABORT 3
#define SRETRY 4
#define SCOM 5
#define SOK 6
#define SERR 7
htopen(dev, flag)
{
register unit, ds, i;
unit = dev&03;
if (unit >= NHT || h_openf[unit]) {
u.u_error = ENXIO;
return;
}
h_den[unit] = (dev&010 ? P1600 : P800)|unit;
flag =& FWRITE;
for(i = 0; i < 75; i++) { /* max 5 min wait on rewind */
h_blkno[unit] = 0;
h_nxrec[unit] = -1;
ds = hcommand(unit, NOP);
if ((ds&MOL)==0 || (flag && (ds&WRL)) || h_openf[unit]) {
u.u_error = ENXIO;
return;
}
if((ds&PIP)==0) {
if (u.u_error==0)
h_openf[unit]++;
return;
}
sleep(&lbolt,-1);
}
u.u_error = ENXIO;
}
htclose(dev, flag)
{
register int unit;
unit = dev&03;
flag =& FWRITE;
if (flag) {
hcommand(unit, WEOF);
hcommand(unit, WEOF);
}
if (dev&04) {
if (flag)
hcommand(unit, SREV); else
hcommand(unit, NOP);
} 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(abp)
struct buf *abp;
{
register struct buf *bp;
register char **p;
bp = abp;
p = &h_nxrec[bp->b_dev&03];
if (*p < bp->b_blkno || (*p == bp->b_blkno && bp->b_flags&B_READ)) {
if (bp->b_flags&B_READ)
bp->b_resid = bp->b_wcount;
else {
bp->b_flags =| B_ERROR;
bp->b_error = ENXIO;
}
iodone(bp);
return;
}
if ((bp->b_flags&B_READ)==0)
*p = bp->b_blkno + 1;
bp->av_forw = 0;
spl5();
if (httab.d_actf==0)
httab.d_actf = bp;
else
httab.d_actl->av_forw = bp;
httab.d_actl = bp;
if (httab.d_active==0)
htstart();
spl0();
}
htstart()
{
register struct buf *bp;
register int unit;
register char *blkno;
loop:
if ((bp = httab.d_actf) == 0)
return;
unit = bp->b_dev&03;
HTADDR->htcs2 = 0;
if((HTADDR->httc&03777)!=h_den[unit])
HTADDR->httc = h_den[unit];
blkno = h_blkno[unit];
if ((HTADDR->htds&MOL)==0)
goto abort;
htetab.e_aunit = &htstat[unit];
if (bp == &chtbuf) {
if (bp->b_resid==NOP) {
bp->b_resid = HTADDR->htds;
goto next;
}
httab.d_active = SCOM;
htetab.e_aunit->io_misc++;
HTADDR->htfc = 0;
HTADDR->htcs1 = bp->b_resid|IENABLE|GO;
return;
}
if (h_openf[unit] < 0)
goto abort;
if (blkno == bp->b_blkno) {
httab.d_active = SIO;
htetab.e_aunit->io_ops++;
blkacty =| (1<<HT);
rhstart(bp, &HTADDR->htfc, bp->b_wcount<<1, &HTADDR->htbae);
} else {
httab.d_active = SSEEK;
htetab.e_aunit->io_misc++;
if (blkno < bp->b_blkno) {
HTADDR->htfc = blkno - bp->b_blkno;
HTADDR->htcs1 = SFORW|IENABLE|GO;
} else {
HTADDR->htfc = bp->b_blkno - blkno;
HTADDR->htcs1 = SREV|IENABLE|GO;
}
}
return;
abort:
bp->b_flags =| B_ERROR;
next:
httab.d_actf = bp->av_forw;
iodone(bp);
goto loop;
}
htintr()
{
register struct buf *bp;
register int unit, state;
struct htregs htregs[0];
int err;
if ((bp = httab.d_actf)==0)
return;
blkacty =& ~(1<<HT);
unit = bp->b_dev&03;
state = httab.d_active;
httab.d_active = 0;
if (HTADDR->htcs1&TRE) {
err = HTADDR->hter;
if (HTADDR->htcs2.hibyte>0 || err&HARD)
state = SERR;
if (bp == &rhtbuf) {
err =& ~FCE;
}
if ((bp->b_flags&B_READ) && (HTADDR->htds&PES))
err =& ~(CS|COR);
if(HTADDR->htds&EOT) {
h_openf[unit] = -1;
}
else if(HTADDR->htds&TMARK) {
state = 0;
HTADDR->htwc = bp->b_wcount;
if(bp != &rhtbuf)
h_openf[unit] = -1;
}
else if(state != SERR && err == 0)
state = SOK;
else
fmtblk(&htetab,HTADDR,sizeof(htregs[0])/2,bp);
HTADDR->htcs1 = TRE|DCLR|GO;
htetab.e_aunit->io_misc++;
h_blkno[unit]++;
if (state==SIO && httab.d_errcnt < 10) {
if(httab.d_errcnt++ == 0)
logerr(&htetab,E_FIRST);
htetab.e_aunit->io_misc++;
httab.d_active = SRETRY;
HTADDR->htfc = -1;
HTADDR->htcs1 = SREV|IENABLE|GO;
return;
}
if (state!=SOK) {
if(state)
bp->b_flags =| B_ERROR;
state = SABORT;
}
} else if (HTADDR->htcs1 < 0) { /* SC */
if (HTADDR->htds&ERR) {
fmtblk(&htetab,HTADDR,sizeof(htregs[0])/2,bp);
HTADDR->htcs1 = DCLR|GO;
htetab.e_aunit->io_misc++;
}
}
switch(state) {
case SIO:
case SOK:
h_blkno[unit]++;
case SABORT:
case SCOM:
if(htetab.e_emsg != NULL)
logerr(&htetab,E_RETRY);
httab.d_errcnt = 0;
httab.d_actf = bp->av_forw;
bp->b_resid = HTADDR->htwc;
iodone(bp);
break;
case SRETRY:
if((bp->b_flags&B_READ)==0) {
htetab.e_aunit->io_misc++;
httab.d_active = SSEEK;
HTADDR->htcs1 = ERASE|IENABLE|GO;
return;
}
case SSEEK:
h_blkno[unit] = bp->b_blkno;
break;
default:
return;
}
htstart();
}
htread(dev)
{
htphys(dev);
physio(htstrategy, &rhtbuf, dev, B_READ, 0);
}
htwrite(dev)
{
htphys(dev);
physio(htstrategy, &rhtbuf, dev, B_WRITE, 0);
}
htphys(dev)
{
register unit, a;
unit = dev&03;
a = lshift(u.u_offset, -9);
h_blkno[unit] = a;
h_nxrec[unit] = ++a;
}