V7/usr/sys/dev/hp.c
/*
* RP04/RP06 disk driver
*/
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/buf.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/user.h"
#define DK_N 0
struct device
{
union {
int w;
char c[2];
} hpcs1; /* Control and Status register 1 */
int hpwc; /* Word count register */
caddr_t hpba; /* UNIBUS address register */
int hpda; /* Desired address register */
union {
int w;
char c[2];
} hpcs2; /* Control and Status register 2*/
int hpds; /* Drive Status */
int hper1; /* Error register 1 */
int hpas; /* Attention Summary */
int hpla; /* Look ahead */
int hpdb; /* Data buffer */
int hpmr; /* Maintenance register */
int hpdt; /* Drive type */
int hpsn; /* Serial number */
int hpof; /* Offset register */
int hpdc; /* Desired Cylinder address register*/
int hpcc; /* Current Cylinder */
int hper2; /* Error register 2 */
int hper3; /* Error register 3 */
int hpec1; /* Burst error bit position */
int hpec2; /* Burst error bit pattern */
int hpbae; /* 11/70 bus extension */
int hpcs3;
};
#define HPADDR ((struct device *)0176700)
#define NHP 2
#define NSECT 22
#define NTRAC 19
#define SDIST 2
#define RDIST 6
struct size
{
daddr_t nblocks;
int cyloff;
} hp_sizes[8] =
{
9614, 0, /* cyl 0 thru 22 */
8778, 23, /* cyl 23 thru 43 */
0, 0,
0, 0,
161348, 44, /* cyl 44 thru 429 */
160930, 430, /* cyl 430 thru 814 */
153406, 44, /* cyl 44 thru 410 (rp04, rp05) */
322278, 44, /* cyl 44 thru 814 (rp06) */
};
#define P400 020
#define M400 0220
#define P800 040
#define M800 0240
#define P1200 060
#define M1200 0260
int hp_offset[16] =
{
P400, M400, P400, M400,
P800, M800, P800, M800,
P1200, M1200, P1200, M1200,
0, 0, 0, 0,
};
struct buf hptab;
struct buf rhpbuf;
struct buf hputab[NHP];
#define GO 01
#define PRESET 020
#define RTC 016
#define OFFSET 014
#define SEARCH 030
#define RECAL 06
#define DCLR 010
#define WCOM 060
#define RCOM 070
#define IE 0100
#define PIP 020000
#define DRY 0200
#define ERR 040000
#define TRE 040000
#define DCK 0100000
#define WLE 04000
#define ECH 0100
#define VV 0100
#define DPR 0400
#define MOL 010000
#define FMT22 010000
#define b_cylin b_resid
daddr_t dkblock();
hpstrategy(bp)
register struct buf *bp;
{
register struct buf *dp;
register unit;
long sz, bn;
unit = minor(bp->b_dev) & 077;
sz = bp->b_bcount;
sz = (sz+511) >> 9;
if (unit >= (NHP<<3) ||
bp->b_blkno < 0 ||
(bn = dkblock(bp))+sz > hp_sizes[unit&07].nblocks) {
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
bp->b_cylin = bn/(NSECT*NTRAC) + hp_sizes[unit&07].cyloff;
unit = dkunit(bp);
dp = &hputab[unit];
spl5();
disksort(dp, bp);
if (dp->b_active == 0) {
hpustart(unit);
if(hptab.b_active == 0)
hpstart();
}
spl0();
}
hpustart(unit)
register unit;
{
register struct buf *bp, *dp;
daddr_t bn;
int sn, cn, csn;
HPADDR->hpcs2.w = unit;
HPADDR->hpcs1.c[0] = IE;
HPADDR->hpas = 1<<unit;
if(unit >= NHP)
return;
dk_busy &= ~(1<<(unit+DK_N));
dp = &hputab[unit];
if((bp=dp->b_actf) == NULL)
return;
if((HPADDR->hpds & VV) == 0) {
HPADDR->hpcs1.c[0] = IE|PRESET|GO;
HPADDR->hpof = FMT22;
}
if(dp->b_active)
goto done;
dp->b_active++;
if ((HPADDR->hpds & (DPR|MOL)) != (DPR|MOL))
goto done;
bn = dkblock(bp);
cn = bp->b_cylin;
sn = bn%(NSECT*NTRAC);
sn = (sn+NSECT-SDIST)%NSECT;
if(HPADDR->hpcc != cn)
goto search;
csn = (HPADDR->hpla>>6) - sn + SDIST - 1;
if(csn < 0)
csn += NSECT;
if(csn > NSECT-RDIST)
goto done;
search:
HPADDR->hpdc = cn;
HPADDR->hpda = sn;
HPADDR->hpcs1.c[0] = IE|SEARCH|GO;
unit += DK_N;
dk_busy |= 1<<unit;
dk_numb[unit] += 1;
return;
done:
dp->b_forw = NULL;
if(hptab.b_actf == NULL)
hptab.b_actf = dp; else
hptab.b_actl->b_forw = dp;
hptab.b_actl = dp;
}
hpstart()
{
register struct buf *bp, *dp;
register unit;
daddr_t bn;
int dn, sn, tn, cn;
loop:
if ((dp = hptab.b_actf) == NULL)
return;
if ((bp = dp->b_actf) == NULL) {
hptab.b_actf = dp->b_forw;
goto loop;
}
hptab.b_active++;
unit = minor(bp->b_dev) & 077;
dn = dkunit(bp);
bn = dkblock(bp);
cn = bn/(NSECT*NTRAC) + hp_sizes[unit&07].cyloff;
sn = bn%(NSECT*NTRAC);
tn = sn/NSECT;
sn = sn%NSECT;
HPADDR->hpcs2.w = dn;
if ((HPADDR->hpds & (DPR|MOL)) != (DPR|MOL)) {
hptab.b_active = 0;
hptab.b_errcnt = 0;
dp->b_actf = bp->av_forw;
bp->b_flags |= B_ERROR;
iodone(bp);
goto loop;
}
if(hptab.b_errcnt >= 16) {
HPADDR->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22;
HPADDR->hpcs1.w = OFFSET|GO;
while(HPADDR->hpds & PIP)
;
}
HPADDR->hpdc = cn;
HPADDR->hpda = (tn << 8) + sn;
HPADDR->hpba = bp->b_un.b_addr;
if(cputype == 70)
HPADDR->hpbae = bp->b_xmem;
HPADDR->hpwc = -(bp->b_bcount>>1);
unit = ((bp->b_xmem&3) << 8) | IE | GO;
if(bp->b_flags & B_READ)
unit |= RCOM; else
unit |= WCOM;
HPADDR->hpcs1.w = unit;
dk_busy |= 1<<(DK_N+NHP);
dk_numb[DK_N+NHP] += 1;
unit = bp->b_bcount>>6;
dk_wds[DK_N+NHP] += unit;
}
hpintr()
{
register struct buf *bp, *dp;
register unit;
int as, i, j;
as = HPADDR->hpas & 0377;
if(hptab.b_active) {
dk_busy &= ~(1<<(DK_N+NHP));
dp = hptab.b_actf;
bp = dp->b_actf;
unit = dkunit(bp);
HPADDR->hpcs2.c[0] = unit;
if (HPADDR->hpcs1.w & TRE) { /* error bit */
while((HPADDR->hpds & DRY) == 0)
;
if(++hptab.b_errcnt > 28 || HPADDR->hper1&WLE)
bp->b_flags |= B_ERROR; else
hptab.b_active = 0;
if(hptab.b_errcnt > 27)
deverror(bp, HPADDR->hpcs2.w, HPADDR->hper1);
if((bp->b_flags&B_PHYS) == 0 &&
(HPADDR->hper1 & (DCK|ECH)) == DCK) {
i = HPADDR->hpec1 - 1;
j = i&017;
i >>= 4;
if(i >= 0 && i <256) {
bp->b_un.b_words[i] ^= HPADDR->hpec2 << j;
bp->b_un.b_words[i+1] ^= HPADDR->hpec2 >> (16-j);
}
hptab.b_active++;
printf("%D ", bp->b_blkno);
prdev("ECC", bp->b_dev);
}
HPADDR->hpcs1.w = TRE|IE|DCLR|GO;
if((hptab.b_errcnt&07) == 4) {
HPADDR->hpcs1.w = RECAL|IE|GO;
while(HPADDR->hpds & PIP)
;
}
}
if(hptab.b_active) {
if(hptab.b_errcnt) {
HPADDR->hpcs1.w = RTC|GO;
while(HPADDR->hpds & PIP)
;
}
hptab.b_active = 0;
hptab.b_errcnt = 0;
hptab.b_actf = dp->b_forw;
dp->b_active = 0;
dp->b_errcnt = 0;
dp->b_actf = bp->av_forw;
bp->b_resid = -(HPADDR->hpwc<<1);
iodone(bp);
HPADDR->hpcs1.w = IE;
if(dp->b_actf)
hpustart(unit);
}
as &= ~(1<<unit);
} else {
if(as == 0)
HPADDR->hpcs1.w = IE;
HPADDR->hpcs1.c[1] = TRE>>8;
}
for(unit=0; unit<NHP; unit++)
if(as & (1<<unit))
hpustart(unit);
hpstart();
}
hpread(dev)
{
physio(hpstrategy, &rhpbuf, dev, B_READ);
}
hpwrite(dev)
{
physio(hpstrategy, &rhpbuf, dev, B_WRITE);
}