+/*
+ * 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);
+}