/* * RP04/RP06 disk driver */ #include "../h/param.h" #include "../h/uba.h" #include "../h/systm.h" #include "../h/buf.h" #include "../h/conf.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/map.h" #include "../h/mba.h" #define DK_N 0 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 HPADDR ((struct device *)(MBA0 + MBA_ERB)) #define NHP 1 #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 23 */ 65536, 44, /* cyl 44 thru 200 */ 65536, 201, /* cyl 201 thru 514 */ 65536, 515, /* cyl 515 thru 671 */ 65536, 358, /* cyl 358 thru 407 */ 0, 0, 328548, 25, /* cyl 25 thru 810 */ 322278, 44, /* cyl 44 thru 717 */ }; #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; register struct device *hpaddr; daddr_t bn; int sn, cn, csn; ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; HPADDR->hpas = 1<<unit; if(unit >= NHP) return; dk_busy &= ~(1<<(unit+DK_N)); dp = &hputab[unit]; if((bp=dp->b_actf) == NULL) return; hpaddr = (struct device *)((int *)HPADDR + 32*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; sn = bn%(NSECT*NTRAC); sn = (sn+NSECT-SDIST)%NSECT; if((hpaddr->hpcc & 0xffff) != cn) goto search; csn = ((hpaddr->hpla & 0xffff)>>6) - sn + SDIST - 1; if(csn < 0) csn += NSECT; if(csn > NSECT-RDIST) goto done; search: hpaddr->hpdc = cn; hpaddr->hpda = sn; hpaddr->hpcs1 = 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; register struct device *hpaddr; 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 = (struct device *)((int *)HPADDR + 32*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; ((struct mba_regs *)MBA0)->mba_cr &= ~MBAIE; hpaddr->hpcs1 = OFFSET|GO; while(hpaddr->hpds & PIP) ; ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; } hpaddr->hpdc = cn; hpaddr->hpda = (tn << 8) + sn; mbastart(bp, hpaddr); dk_busy |= 1<<(DK_N+NHP); dk_numb[DK_N+NHP] += 1; unit = bp->b_bcount>>6; dk_wds[DK_N+NHP] += unit; } hpintr(mbastat, as) { register struct buf *bp, *dp; register unit; register struct device *hpaddr; int i, j; if(hptab.b_active) { dk_busy &= ~(1<<(DK_N+NHP)); dp = hptab.b_actf; bp = dp->b_actf; unit = dkunit(bp); hpaddr = (struct device *)((int *)HPADDR + 32*unit); if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { /* 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, mbastat, hpaddr->hper1); if((bp->b_flags&B_PHYS) == 0 && (hpaddr->hper1 & (DCK|ECH)) == DCK) { i = (hpaddr->hpec1 & 0xffff) - 1; j = i&037; i =>> 5; if(i >= 0 && i <128) { bp->b_un.b_words[i] =^ (hpaddr->hpec2 & 0xffff) << j; bp->b_un.b_words[i+1] =^ (hpaddr->hpec2 & 0xffff) >> (32-j); } hptab.b_active++; printf("%D ", bp->b_blkno); prdev("ECC", bp->b_dev); } hpaddr->hpcs1 = DCLR|GO; if((hptab.b_errcnt&07) == 4) { ((struct mba_regs *)MBA0)->mba_cr &= ~MBAIE; hpaddr->hpcs1 = RECAL|GO; while(hpaddr->hpds & PIP) ; ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; } } if(hptab.b_active) { if(hptab.b_errcnt) { ((struct mba_regs *)MBA0)->mba_cr &= ~MBAIE; hpaddr->hpcs1 = RTC|GO; while(hpaddr->hpds & PIP) ; ((struct mba_regs *)MBA0)->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 = -(((struct mba_regs *)MBA0)->mba_bcr) & 0xffff; iodone(bp); if(dp->b_actf) hpustart(unit); } as &= ~(1<<unit); } else { if(as == 0) ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; } 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); }