/* hp.c 4.3 12/19/80 */ #include "hp.h" #if NHP > 0 /* * RP06/RM03/RM05 disk driver */ #include "../h/param.h" #include "../h/systm.h" #include "../h/dk.h" #include "../h/buf.h" #include "../h/conf.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/map.h" #include "../h/pte.h" #include "../h/mba.h" #include "../h/mtpr.h" #include "../h/vm.h" struct device { int hpcs1; /* control and Status register 1 */ int hpds; /* Drive Status */ int hper1; /* Error register 1 */ int hpmr; /* Maintenance */ int hpas; /* Attention Summary */ int hpda; /* Desired address register */ int hpdt; /* Drive type */ int hpla; /* Look ahead */ 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 */ }; #define RP 022 #define RM 024 #define RM5 027 #define NSECT 22 #define NTRAC 19 #define NRMSECT 32 #define NRMTRAC 5 #define _hpSDIST 2 #define _hpRDIST 3 int hpSDIST = _hpSDIST; int hpRDIST = _hpRDIST; int hpseek; struct size { daddr_t nblocks; int cyloff; } hp_sizes[8] = { 15884, 0, /* A=cyl 0 thru 37 */ 33440, 38, /* B=cyl 38 thru 117 */ 340670, 0, /* C=cyl 0 thru 814 */ 0, 0, 0, 0, 0, 0, 291346, 118, /* G=cyl 118 thru 814 */ 0, 0, }, rm_sizes[8] = { 15884, 0, /* A=cyl 0 thru 99 */ 33440, 100, /* B=cyl 100 thru 309 */ 131680, 0, /* C=cyl 0 thru 822 */ 0, 0, 0, 0, 0, 0, 82080, 310, /* G=cyl 310 thru 822 */ 0, 0, }, rm5_sizes[8] = { 15884, 0, /* A=cyl 0 thru 26 */ 33440, 27, /* B=cyl 27 thru 81 */ 500992, 0, /* C=cyl 0 thru 823 */ 15884, 562, /* D=cyl 562 thru 588 */ 55936, 589, /* E=cyl 589 thru 680 */ 86944, 681, /* F=cyl 681 thru 823 */ 159296, 562, /* G=cyl 562 thru 823 */ 291346, 82, /* H=cyl 82 thru 561 */ }; #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]; char hp_type[NHP]; /* drive type */ #define GO 01 #define PRESET 020 #define RTC 016 #define OFFSET 014 #define SEEK 04 #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 #ifdef INTRLVE daddr_t dkblock(); #endif hpstrategy(bp) register struct buf *bp; { register struct buf *dp; register unit, xunit, nspc; long sz, bn; struct size *sizes; if ((mbaact&(1<b_dev) & 077; sz = bp->b_bcount; sz = (sz+511) >> 9; unit = dkunit(bp); if (hp_type[unit] == 0) { struct device *hpaddr; double mspw; /* determine device type */ hpaddr = mbadev(HPMBA, unit); /* record transfer rate (these are guesstimates secs/word) */ switch (hp_type[unit] = hpaddr->hpdt) { case RM: mspw = .0000019728; break; case RM5: mspw = .0000020345; break; case RP: mspw = .0000029592; break; } if (HPDK_N + unit <= HPDK_NMAX) dk_mspw[HPDK_N+unit] = mspw; } switch (hp_type[unit]) { case RM: sizes = rm_sizes; nspc = NRMSECT*NRMTRAC; break; case RM5: sizes = rm5_sizes; nspc = NRMSECT*NTRAC; break; case RP: sizes = hp_sizes; nspc = NSECT*NTRAC; break; default: printf("hp: unknown device type 0%o\n", hp_type[unit]); u.u_error = ENXIO; unit = NHP+1; /* force error */ } if (unit >= NHP || bp->b_blkno < 0 || (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) { bp->b_flags |= B_ERROR; iodone(bp); return; } bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff; dp = &hputab[unit]; (void) spl5(); disksort(dp, bp); if (dp->b_active == 0) { hpustart(unit); if(hptab.b_active == 0) hpstart(); } (void) spl0(); } hpustart(unit) register unit; { register struct buf *bp, *dp; register struct device *hpaddr; daddr_t bn; int sn, cn, csn; ((struct mba_regs *)HPMBA)->mba_cr |= MBAIE; hpaddr = mbadev(HPMBA, 0); hpaddr->hpas = 1<= NHP) return; if (unit+HPDK_N <= HPDK_NMAX) dk_busy &= ~(1<<(unit+HPDK_N)); dp = &hputab[unit]; if((bp=dp->b_actf) == NULL) return; hpaddr = mbadev(HPMBA, unit); if((hpaddr->hpds & VV) == 0) { hpaddr->hpcs1 = 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; switch (hp_type[unit]) { case RM: sn = bn%(NRMSECT*NRMTRAC); sn = (sn+NRMSECT-hpSDIST)%NRMSECT; break; case RM5: sn = bn%(NRMSECT*NTRAC); sn = (sn+NRMSECT-hpSDIST)%NRMSECT; break; case RP: sn = bn%(NSECT*NTRAC); sn = (sn+NSECT-hpSDIST)%NSECT; break; default: panic("hpustart"); } if(cn - (hpaddr->hpdc & 0xffff)) goto search; else if (hpseek) goto done; csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1; if(csn < 0) csn += NSECT; if(csn > NSECT-hpRDIST) goto done; search: hpaddr->hpdc = cn; if (hpseek) hpaddr->hpcs1 = SEEK|GO; else { hpaddr->hpda = sn; hpaddr->hpcs1 = SEARCH|GO; } unit += HPDK_N; if (unit <= HPDK_NMAX) { dk_busy |= 1<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; register struct device *hpaddr; daddr_t bn; int dn, sn, tn, cn, nspc, ns; 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); switch (hp_type[dn]) { case RM: nspc = NRMSECT*NRMTRAC; ns = NRMSECT; cn = rm_sizes[unit&07].cyloff; break; case RM5: nspc = NRMSECT*NTRAC; ns = NRMSECT; cn = rm5_sizes[unit&07].cyloff; break; case RP: nspc = NSECT*NTRAC; ns = NSECT; cn = hp_sizes[unit&07].cyloff; break; default: panic("hpstart"); } cn += bn/nspc; sn = bn%nspc; tn = sn/ns; sn = sn%ns; hpaddr = mbadev(HPMBA, 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 && (bp->b_flags&B_WRITE) == 0) { hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22; HPMBA->mba_cr &= ~MBAIE; hpaddr->hpcs1 = OFFSET|GO; while(hpaddr->hpds & PIP) ; HPMBA->mba_cr |= MBAIE; } hpaddr->hpdc = cn; hpaddr->hpda = (tn << 8) + sn; mbastart(bp, (int *)hpaddr); unit = dn+HPDK_N; if (unit <= HPDK_NMAX) { dk_busy |= 1<b_bcount>>6; } } hpintr(mbastat, as) { register struct buf *bp, *dp; register unit; register struct device *hpaddr; if(hptab.b_active) { dp = hptab.b_actf; bp = dp->b_actf; unit = dkunit(bp); if (HPDK_N+unit <= HPDK_NMAX) dk_busy &= ~(1<<(HPDK_N+unit)); hpaddr = mbadev(HPMBA, unit); if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { 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, mbastat, hpaddr->hper1); if ((hpaddr->hper1&0xffff) == DCK) { if (hpecc(hpaddr, bp)) return; } hpaddr->hpcs1 = DCLR|GO; if((hptab.b_errcnt&07) == 4) { HPMBA->mba_cr &= ~MBAIE; hpaddr->hpcs1 = RECAL|GO; while(hpaddr->hpds & PIP) ; HPMBA->mba_cr |= MBAIE; } } if(hptab.b_active) { if(hptab.b_errcnt) { HPMBA->mba_cr &= ~MBAIE; hpaddr->hpcs1 = RTC|GO; while(hpaddr->hpds & PIP) ; HPMBA->mba_cr |= MBAIE; } 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 = -HPMBA->mba_bcr & 0xffff; iodone(bp); if(dp->b_actf) hpustart(unit); } as &= ~(1<mba_cr |= MBAIE; } for(unit=0; unitmba_bcr & 0xffff; if (bcr) bcr |= 0xffff0000; /* sxt */ npf = btop(bcr + bp->b_bcount) - 1; reg = npf; o = (int)bp->b_un.b_addr & PGOFSET; printf("%D ", bp->b_blkno + npf); prdev("ECC", bp->b_dev); mask = rp->hpec2&0xffff; if (mask == 0) { rp->hpof = FMT22; return (0); } /* * Compute the byte and bit position of the error. * The variable i is the byte offset in the transfer, * the variable byte is the offset from a page boundary * in main memory. */ i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ bit = i&07; i = (i&~07)>>3; byte = i + o; /* * Correct while possible bits remain of mask. Since mask * contains 11 bits, we continue while the bit offset is > -11. * Also watch out for end of this block and the end of the whole * transfer. */ while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { mpte = mbp->mba_map[reg+btop(byte)]; addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); putmemc(addr, getmemc(addr)^(mask<hpcs1 = DCLR|GO; dn = dkunit(bp); bn = dkblock(bp); switch (hp_type[dn]) { case RM: ns = NRMSECT; nt = NRMTRAC; break; case RM5: ns = NRMSECT; nt = NTRAC; break; case RP: ns = NSECT; nt = NTRAC; break; default: panic("hpecc"); } cn = bp->b_cylin; sn = bn%(ns*nt) + npf + 1; tn = sn/ns; sn %= ns; cn += tn/nt; tn %= nt; rp->hpdc = cn; rp->hpda = (tn<<8) + sn; mbp->mba_sr = -1; mbp->mba_var = (int)ptob(reg+1) + o; rp->hpcs1 = RCOM|GO; return (1); } #endif