# /* */ /* * RK06/07 disk driver * * This driver has been tested on a working RK06 for a short time. * It does not attempt ECC error correction and is probably * deficient in general in the case of errors and when packs * are dismounted. Code for multiple drives has not been tested. * * ian johnstone * AGSM 1978 */ #include "../param.h" #include "../buf.h" #include "../conf.h" #include "../user.h" struct { int hkcs1; /* Control and Status register 1 */ int hkwc; /* Word count register */ int hkba; /* UNIBUS address register */ int hkda; /* Desired address register */ int hkcs2; /* Control and Status register 2*/ int hkds; /* Drive Status */ int hker; /* Error register */ int hkas; /* Attention Summary */ int hkdc; /* Desired cylinder */ int hk00; /* Unused */ int hkdb; /* Data buffer */ int hkmr1; /* Maintenance register 1 */ int hkecps; /* ECC position register */ int hkecpt; /* ECC pattern register */ int hkmr2; /* Maintenance register 2 */ int hkmr3; /* Maintenance register 3 */ }; #define HKADDR 0177440 #define NHK 8 char *hksizes[2] { 27126, 53790 }; struct {char *uns;}; struct devtab hktab; struct buf hkbuf; char hk_openf 0; char hk_rk07 0377; #define GO 01 /* Drive Commands */ #define ACK 02 #define RECAL 012 #define RCLR 04 #define WCOM 022 #define RCOM 020 #define RK07 02000 #define IENABLE 0100 /* hkcs1 - interrupt enable */ #define READY 0200 /* hkds - drive ready */ #define DDT 0400 /* hkds - drive type */ #define PIP 020000 /* hkds - Positioning Operation in Progress */ #define ERR 0100000 /* hkcs1 - composite error */ #define DU 040000 /* hker - Drive Unsafe */ #define DTE 010000 /* hker - Drive Timing Error */ #define OPI 020000 /* hker - Operation Incomplete */ /* Error Correction Code errors */ #define DCK 0100000 /* hker - Data Check error */ #define ECH 0100 /* hker - ECC hard error */ #define CLR 040 /* hkcs2 - Controller Clear */ /* * Use av_back to save track+sector, * b_resid for cylinder. */ #define trksec av_back #define cylin b_resid hkopen(dev) { register int dbit; dbit = dev.d_minor&0377; if(dbit >= NHK) { u.u_error = ENXIO; return; } dbit = 1 << dbit; if((hk_openf & dbit) == 0) { if(hk_openf == 0) HKADDR->hkcs2 = CLR; hk_openf =| dbit; HKADDR->hkcs2 = dev.d_minor; #ifdef MIXED_DRIVES if(HKADDR->hkds & DDT) /* an rk07 */ { hk_rk07 =| dbit; dbit = RK07; } else { hk_rk07 =& ~dbit; dbit = 0; } #endif #ifndef MIXED_DRIVES dbit = (hk_rk07 & dbit) ? RK07 : 0; #endif HKADDR->hkcs1 = dbit|ACK|GO; while(HKADDR->hkcs1&READY == 0); HKADDR->hkcs2 = dev.d_minor; HKADDR->hkcs1 = dbit|RCLR|GO; } } hkstrategy(abp) struct buf *abp; { register struct buf *bp; register char *p1, *p2; bp = abp; if(bp->b_dev.d_minor >= NHK || bp->b_blkno.uns >= hksizes[(hk_rk07 >> bp->b_dev.d_minor)&01]) { bp->b_flags =| B_ERROR; iodone(bp); return; } bp->av_forw = 0; p1 = bp->b_blkno; p2 = lrem(p1, 22); p1 = ldiv(p1, 22); bp->trksec = (p1%3)<<8|p2; bp->cylin = p1/3; spl5(); if((p1 = hktab.d_actf) == 0) hktab.d_actf = bp; else { for(; p2 = p1->av_forw; p1 = p2) { if(p1->cylin <= bp->cylin && bp->cylin < p2->cylin || p1->cylin >= bp->cylin && bp->cylin >p2-> cylin) break; } bp->av_forw = p2; p1->av_forw = bp; } if(hktab.d_active == 0) hkstart(); spl0(); } hkstart() { register struct buf *bp; register d; if((bp = hktab.d_actf) == 0) return; hktab.d_active++; d = (hk_rk07 << (10 - bp->b_dev.d_minor)) & RK07; HKADDR->hkcs2 = bp->b_dev.d_minor; /* select drive */ HKADDR->hkdc = bp->cylin; /* desired cylinder */ HKADDR->hkda = bp->trksec; /* track & sector */ HKADDR->hkba = bp->b_addr; /* buffer address */ HKADDR->hkwc = bp->b_wcount; /* word count */ HKADDR->hkcs1 = d | IENABLE | GO | ((bp->b_xmem & 03) << 8) | (bp->b_flags&B_READ ? RCOM : WCOM); } hkintr() { register struct buf *bp; register d; if(hktab.d_active == 0) return; bp = hktab.d_actf; d = (hk_rk07 << (10 - bp->b_dev.d_minor)) & RK07; hktab.d_active = 0; if(HKADDR->hkcs1&ERR) { /* error bit */ printf("HKERR er=%o cs1=%o cs2=%o ds=%o da=%o dc=%o\n", HKADDR->hker,HKADDR->hkcs1,HKADDR->hkcs2,HKADDR->hkds,HKADDR->hkda,HKADDR->hkdc); if(HKADDR->hker&(DU|DTE|OPI)) { HKADDR->hkcs1 = ERR; /* reset error */ HKADDR->hkcs2 = bp->b_dev.d_minor; HKADDR->hkcs1 = d|RCLR|GO; while(HKADDR->hkcs1&READY == 0); HKADDR->hkcs2 = bp->b_dev.d_minor; HKADDR->hkcs1 = d|RECAL|GO; while(HKADDR->hkcs1&READY == 0); } HKADDR->hkcs1 = ERR; /* reset error */ HKADDR->hkcs2 = bp->b_dev.d_minor; HKADDR->hkcs1 = d|RCLR|GO; while(HKADDR->hkcs1&READY == 0); if(++hktab.d_errcnt <= 10) { hkstart(); return; } bp->b_flags =| B_ERROR; } hktab.d_errcnt = 0; hktab.d_actf = bp->av_forw; bp->b_resid = HKADDR->hkwc; iodone(bp); hkstart(); } hkread(dev) { if(hkphys(dev)) physio(hkstrategy, &hkbuf, dev, B_READ); } hkwrite(dev) { if(hkphys(dev)) physio(hkstrategy, &hkbuf, dev, B_WRITE); } hkphys(dev) { register char *c; c = lshift(u.u_offset, -9); c =+ ldiv(u.u_count+511, 512); if(c > hksizes[(hk_rk07 >> dev.d_minor) & 01]) { u.u_error = ENXIO; return(0); } return(1); }