V7M/sys/dev/rp.c
/*
* RP disk driver
*/
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/buf.h"
#include "../h/dir.h"
#include "../h/conf.h"
#include "../h/user.h"
struct device {
int rpds;
int rper;
union {
int w;
char c;
} rpcs;
int rpwc;
char *rpba;
int rpca;
int rpda;
};
#define RPADDR ((struct device *) 0176710)
#define NRP 2
/* char rp_tr 0; */ /* tells iostat RP03 xfer rate */
struct {
daddr_t nblocks;
int cyloff;
} rp_sizes[] = {
9600, 0, /* cyl 0- 47, root file system */
8000, 48, /* cyl 48- 87, swap area */
7400, 88, /* cyl 88-124, /sys (system sources) */
55000, 125, /* cyl 125-399, /usr (users + sources) */
80000, 0, /* cyl 0-399, users- all of RP03 pack */
0, 0,
0, 0,
0, 0,
};
char rp_opn;
struct buf rptab;
struct buf rrpbuf;
#define GO 01
#define RESET 0
#define HSEEK 014
#define IENABLE 0100
#define READY 0200
#define RCOM 4
#define WCOM 2
#define SUFU 01000
#define SUSU 02000
#define SUSI 04000
#define HNF 010000
/*
* Use av_back to save track+sector,
* b_resid for cylinder.
*/
#define trksec av_back
#define cylin b_resid
/*
* Monitoring device number
* and iostat structure.
*/
struct ios rp_ios[NRP];
#define DK_N 4
#define DK_T 8 /* RP03 transfer rate indicator */
rpstrategy(bp)
register struct buf *bp;
{
register struct buf *dp;
register int unit;
long sz;
if(bp->b_flags&B_PHYS)
mapalloc(bp);
unit = minor(bp->b_dev);
sz = bp->b_bcount;
sz = (sz+511)>>9;
if (unit >= (NRP<<3) ||
bp->b_blkno+sz >= rp_sizes[unit&07].nblocks) {
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
bp->av_forw = NULL;
unit >>= 3;
if(rp_opn == 0) {
rp_opn++;
spl6();
dk_iop[DK_N] = &rp_ios[0];
dk_nd[DK_N] = NRP;
}
spl5();
dp = & rptab;
if (dp->b_actf == NULL)
dp->b_actf = bp;
else
dp->b_actl->av_forw = bp;
dp->b_actl = bp;
if (dp->b_active == NULL)
rpstart();
spl0();
}
rpstart()
{
register struct buf *bp;
register int unit;
int com,cn,tn,sn,dn;
daddr_t bn;
if ((bp = rptab.b_actf) == NULL)
return;
rptab.b_active++;
unit = minor(bp->b_dev);
dn = unit>>3;
bn = bp->b_blkno;
cn = bn/(20*10) + rp_sizes[unit&07].cyloff;
sn = bn%(20*10);
tn = sn/10;
sn = sn%10;
RPADDR->rpcs.w = (dn<<8);
RPADDR->rpda = (tn<<8) | sn;
RPADDR->rpca = cn;
RPADDR->rpba = bp->b_un.b_addr;
RPADDR->rpwc = -(bp->b_bcount>>1);
com = ((bp->b_xmem&3)<<4) | IENABLE | GO;
if (bp->b_flags & B_READ)
com |= RCOM; else
com |= WCOM;
RPADDR->rpcs.w |= com;
rp_ios[dn].dk_tr = DK_T;
rp_ios[dn].dk_busy++; /* drive active */
rp_ios[dn].dk_numb++; /* count number of xfer's */
unit = bp->b_bcount>>6;
rp_ios[dn].dk_wds += unit; /* count words xfer'd */
}
rpintr()
{
register struct buf *bp;
register int ctr;
if (rptab.b_active == NULL)
return;
bp = rptab.b_actf;
ctr = (bp->b_dev >> 3) & 7;
rp_ios[ctr].dk_busy = 0; /* drive no longer active */
rptab.b_active = NULL;
if (RPADDR->rpcs.w < 0) { /* error bit */
deverror(bp, RPADDR->rper, RPADDR->rpds);
if(RPADDR->rpds & (SUFU|SUSI|HNF)) {
RPADDR->rpcs.c = HSEEK|GO;
ctr = 0;
while ((RPADDR->rpds&SUSU) && --ctr)
;
}
RPADDR->rpcs.w = RESET|GO;
ctr = 0;
while ((RPADDR->rpcs.w&READY) == 0 && --ctr)
;
if (++rptab.b_errcnt <= 10) {
rpstart();
return;
}
bp->b_flags |= B_ERROR;
}
rptab.b_errcnt = 0;
rptab.b_actf = bp->av_forw;
bp->b_resid = 0;
iodone(bp);
rpstart();
}
rpread(dev)
{
physio(rpstrategy, &rrpbuf, dev, B_READ);
}
rpwrite(dev)
{
physio(rpstrategy, &rrpbuf, dev, B_WRITE);
}