V7/usr/sys/dev/rl.c
/*
* RL disk driver
*/
#define DK_N 2
#include "../h/param.h"
#include "../h/buf.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/systm.h"
#define NRLBLK 10240
#define RLCYLSZ 10240
#define RLSECSZ 256
#define RESET 013
#define STAT 03
#define GETSTAT 04
#define WCOM 012
#define RCOM 014
#define SEEK 06
#define SEEKHI 5
#define SEEKLO 1
#define RDHDR 010
#define IENABLE 0100
#define CRDY 0200
#define OPI 02000
#define CRCERR 04000
#define TIMOUT 010000
#define NXM 020000
#define DE 040000
struct device
{
int rlcs, rlba, rlda, rlmp;
};
#define RLADDR ((struct device *)0174400)
#define RL_CNT 1
struct buf rrlbuf;
struct buf rltab;
struct
{
int cn[4]; /* location of heads for each drive */
int dn; /* drive number */
int com; /* read or write command word */
int chn; /* cylinder and head number */
unsigned int bleft; /* bytes left to be transferred */
unsigned int bpart; /* number of bytes transferred */
int sn; /* sector number */
union {
int w[2];
long l;
} addr; /* address of memory for transfer */
} rl = {-1,-1,-1,-1};
rlstrategy(bp)
register struct buf *bp;
{
if(bp->b_blkno >= NRLBLK) {
if(bp->b_blkno == NRLBLK && bp->b_flags&B_READ)
bp->b_resid = bp->b_bcount;
else {
bp->b_flags |= B_ERROR;
bp->b_error = ENXIO;
}
iodone(bp);
return;
}
bp->av_forw = NULL;
spl5();
if(rltab.b_actf == NULL)
rltab.b_actf = bp;
else
rltab.b_actl->av_forw = bp;
rltab.b_actl = bp;
if(rltab.b_active == NULL)
rlstart();
spl0();
}
rlstart()
{
register struct buf *bp;
if ((bp = rltab.b_actf) == NULL)
return;
rltab.b_active++;
rl.dn = minor(bp->b_dev);
rl.chn = bp->b_blkno/20;
rl.sn = (bp->b_blkno%20) << 1;
rl.bleft = bp->b_bcount;
rl.addr.w[0] = bp->b_xmem & 3;
rl.addr.w[1] = (int)bp->b_un.b_addr;
rl.com = (rl.dn << 8) | IENABLE;
if (bp->b_flags & B_READ)
rl.com |= RCOM;
else
rl.com |= WCOM;
rlio();
}
rlintr()
{
register struct buf *bp;
register struct device *rp;
register int status;
rp = RLADDR;
if (rltab.b_active == NULL) {
/*
logstray(rp);
*/
return;
}
bp = rltab.b_actf;
dk_busy &= ~(1<<DK_N);
if (rp->rlcs < 0) { /* error bit */
if (rp->rlcs & 036000) {
if(rltab.b_errcnt > 2)
deverror(bp, rp->rlcs, rp->rlda);
}
if (rp->rlcs & 040000) {
rp->rlda = STAT;
rp->rlcs = (rl.dn << 8) | GETSTAT;
while ((rp->rlcs & CRDY) == 0)
;
status = rp->rlmp;
if(rltab.b_errcnt > 2)
deverror(bp, status, rp->rlda);
rp->rlda = RESET;
rp->rlcs = (rl.dn << 8) | GETSTAT;
while ((rp->rlcs & CRDY) == 0)
;
if(status & 01000) {
rlstart();
return;
}
}
if (++rltab.b_errcnt <= 10) {
rl.cn[rl.dn] = -1;
rlstart();
return;
}
else {
bp->b_flags |= B_ERROR;
rl.bpart = rl.bleft;
}
}
if ((rl.bleft -= rl.bpart) > 0) {
rl.addr.l += rl.bpart;
rl.sn=0;
rl.chn++;
rlio();
return;
}
rltab.b_active = NULL;
rltab.b_errcnt = 0;
rltab.b_actf = bp->av_forw;
bp->b_resid = 0;
iodone(bp);
rlstart();
}
rlio()
{
register struct device *rp;
register dif;
register int head;
rp = RLADDR;
dk_busy |= 1<<DK_N;
dk_numb[DK_N] += 1;
head = rl.bpart>>6;
dk_wds[DK_N] += head;
if (rl.cn[rl.dn] < 0) {
rp->rlcs = (rl.dn << 8) | RDHDR;
while ((rp->rlcs&CRDY) == 0)
;
rl.cn[rl.dn] = (rp->rlmp&077700) >> 6;
}
dif =(rl.cn[rl.dn] >> 1) - (rl.chn >>1);
head = (rl.chn & 1) << 4;
if (dif < 0)
rp->rlda = (-dif <<7) | SEEKHI | head;
else
rp->rlda = (dif << 7) | SEEKLO | head;
rp->rlcs = (rl.dn << 8) | SEEK;
rl.cn[rl.dn] = rl.chn;
if (rl.bleft < (rl.bpart = RLCYLSZ - (rl.sn * RLSECSZ)))
rl.bpart = rl.bleft;
while ((rp->rlcs&CRDY) == 0)
;
rp->rlda = (rl.chn << 6) | rl.sn;
rp->rlba = rl.addr.w[1];
rp->rlmp = -(rl.bpart >> 1);
rp->rlcs = rl.com | rl.addr.w[0] << 4;
}
rlread(dev)
{
physio(rlstrategy, &rrlbuf, dev, B_READ);
}
rlwrite(dev)
{
physio(rlstrategy, &rrlbuf, dev, B_WRITE);
}