/* * RP04/RP06 disk driver */ #include "sys/param.h" #include "sys/dir.h" #include "sys/user.h" #include "sys/buf.h" #include "sys/elog.h" #include "sys/iobuf.h" #include "sys/systm.h" #include "sys/mba.h" struct device { int hpcs1, hpds, hper1, hpmr; int hpas, hpda, hpdt, hpla; int hpsn, hpof, hpdc, hpcc; int hper2, hper3, hpec1, hpec2; }; #define mbaddr ((struct mba *)0x8004e000) #define mbactl (mbaddr->mba_ireg.mba_regs) #define mbadev (mbaddr->mba_ereg) #define mbamap (mbaddr->mba_map) struct size { daddr_t nblocks; int cyloff; } hp_sizes[8]; struct iostat hpstat[8]; struct iobuf hptab = tabinit(HP0,0); struct iobuf hputab[8] = { tabinit(HP0,&hpstat[0]),tabinit(HP0,&hpstat[1]),tabinit(HP0,&hpstat[2]), tabinit(HP0,&hpstat[3]),tabinit(HP0,&hpstat[4]),tabinit(HP0,&hpstat[5]), tabinit(HP0,&hpstat[6]),tabinit(HP0,&hpstat[7]) }; struct buf hpbuf; #define NSECT 22 #define NTRAC 19 #define SDIST 3 #define RDIST 7 #define GDIST 1 #define GO 01 #define RECAL 06 #define DCLR 010 #define RELEASE 012 #define PRESET 020 #define SEARCH 030 #define WCOM 060 #define RCOM 070 #define ERR 040000 /* hpds - Error */ #define MOL 010000 /* hpds - Medium online */ #define VV 0100 /* hpds - volume valid */ #define WLE 04000 /* hper1 - Write lock error */ #define DCK 0100000 /* hper1 - Data check */ #define FMT22 010000 #define NED 0x40000 #define wtime b_flags #define WOK 0 #define WABORT 1 #define WNED 2 #define WMOL 4 #define WERR 30 #define acts io_s1 #define qcnt io_s2 #define trksec av_back #define cylin b_resid hpopen(dev) { register struct iobuf *dp; if ((hptab.b_flags&B_ONCE)==0) { hptab.b_flags |= B_ONCE; hptab.io_mba = (physadr)&mbactl; hptimer(); } dp = &hputab[dev>>3]; dp->io_addr = (physadr)&mbadev[dev>>3]; dp->io_mba = (physadr)&mbactl; dp->io_nreg = NDEVREG; } hpclose(dev) { } hpstrategy(bp) register struct buf *bp; { register struct iobuf *dp; register struct buf *ap; daddr_t last; register unit; int co; unit = minor(bp->b_dev); last = hp_sizes[unit&07].nblocks; co = hp_sizes[unit&07].cyloff; unit >>= 3; dp = &hputab[unit]; if (bp->b_blkno < 0 || bp->b_blkno >= last) { if (bp->b_blkno == last && bp->b_flags&B_READ) bp->b_resid = bp->b_bcount; else { bp->b_flags |= B_ERROR; bp->b_error = ENXIO; } iodone(bp); return; } bp->av_forw = NULL; bp->cylin = bp->b_blkno/(NSECT*NTRAC) + co; co = bp->b_blkno%(NSECT*NTRAC); *((int *)(&bp->trksec)) = ((co/NSECT)<<8)+(co%NSECT); hpstat[unit].io_ops++; spl6(); dp->qcnt++; if (dp->b_actf == NULL) { dp->b_actf = bp; dp->b_actl = bp; dp->acts = (int)bp; } else { register struct buf *cp; if (((int)hpstat[unit].io_ops&07) == 0) dp->acts = (int)dp->b_actl; for (ap = (struct buf *)dp->acts; cp = ap->av_forw; ap = cp) { int s1, s2; if ((s1 = ap->cylin - bp->cylin)<0) s1 = -s1; if ((s2 = ap->cylin - cp->cylin)<0) s2 = -s2; if (s1 < s2) break; } ap->av_forw = bp; if ((bp->av_forw = cp) == NULL) hputab[unit].b_actl = bp; } if (hputab[unit].b_active == 0) { hpustart(unit); if (hptab.b_active == 0 && hptab.b_actf != NULL) hpstart(); } spl0(); } hpustart(unit) { register struct buf *bp; register struct iobuf *dp; register struct device *rp; int sn, dsn; dp = &hputab[unit]; rp = (struct device *)&mbadev[unit]; mbactl.mba_cr |= MBAIE; rp->hpas = 1<<unit; bp = dp->b_actf; if ((rp->hpds&MOL) == 0) { if (dp->wtime!=WOK) return; if (bp == NULL) dp->wtime = WOK; else if (mbactl.mba_sr&NED) dp->wtime = WNED; else if (!pwr_act) dp->wtime = WMOL; else dp->wtime = WERR; return; } else if (rp->hpds&ERR) { dp->b_dev = makedev(HP0,unit); fmtberr(dp,(bp==NULL)?0:hp_sizes[minor(bp->b_dev)&07].cyloff); rp->hpcs1 = DCLR|GO; if (rp->hpds&ERR || ++dp->b_errcnt > 16) { printf("hard err on RP04/5/6 drive %d %o %o %o %o\n", unit, rp->hpds, rp->hper1, rp->hper2, rp->hper3); dp->wtime = WERR; rp->hpas = 1<<unit; return; } } dp->wtime = WOK; if ((rp->hpds&VV) == 0) { rp->hpcs1 = PRESET|GO; rp->hpof = FMT22; } if (bp == NULL) { rp->hpcs1 = RELEASE|GO; return; } if ((dp->b_errcnt&07) == 05) { dp->b_errcnt++; rp->hpcs1 = RECAL|GO; return; } dp->b_active++; sn = (int)bp->trksec&0377; dsn = (sn<<2) - ((rp->hpla&0xffff)>>4) - GDIST; if (dsn<=0) dsn += NSECT*4; if (((bp->cylin - rp->hpcc) || dsn > RDIST*4) && dp->b_active<3) { rp->hpdc = bp->cylin; sn -= SDIST; if (sn<0) sn += NSECT; rp->hpda = sn; /* sector search, track ignored, lookahead SDIST */ rp->hpcs1 = SEARCH|GO; if (dp->b_active == 1) { hpstat[unit].io_misc++; } } else { dp->b_forw = NULL; if (hptab.b_actf == NULL) hptab.b_actf = (struct buf *)dp; else hptab.b_actl->b_forw = (struct buf *)dp; hptab.b_actl = (struct buf *)dp; } } hpstart() { register struct buf *bp; register struct iobuf *dp; register struct device *rp; register unit; loop: if ((dp = (struct iobuf *)hptab.b_actf) == NULL) return; if ((bp = dp->b_actf) == NULL) { hptab.b_actf = dp->b_forw; goto loop; } unit = minor(bp->b_dev)>>3; rp = (struct device *)&mbadev[unit]; hptab.b_active++; rp->hpdc = bp->cylin; rp->hpda = (int)bp->trksec; blkacty |= (1<<HP0); mbastart(bp, rp, mbaddr); } hpintr(mbastat, as) { register struct buf *bp; register unit; register struct device *rp; register struct iobuf *dp; if (hptab.b_active) { /* data transfer underway */ blkacty &= ~(1<<HP0); dp = (struct iobuf *)hptab.b_actf; bp = dp->b_actf; unit = minor(bp->b_dev); rp = (struct device *)&mbadev[unit>>3]; if (mbastat & MBADTABT) { if (++dp->b_errcnt>16) bp->b_flags |= B_ERROR; else if (rp->hper1&WLE) { bp->b_flags |= B_ERROR; printf("Write lock error RP04/5/6 drive %d\n", unit>>3); } else { hptab.b_active = 0; } fmtberr(dp,hp_sizes[unit&07].cyloff); if (dp->b_errcnt > 2) deverr(dp, mbastat, rp->hper1); if ((rp->hper1&0xffff) == DCK) { if (hpecc(rp, bp)) return; } rp->hpcs1 = DCLR|GO; } unit >>= 3; if (hptab.b_active) { if (dp->io_erec) logberr(dp,bp->b_flags&B_ERROR); hptab.b_active = 0; dp->b_active = 0; dp->b_errcnt = 0; dp->b_actf = bp->av_forw; bp->b_resid = -(mbactl.mba_bcr) & 0xffff; dp->qcnt--; if (bp == (struct buf *)dp->acts) dp->acts = (int)dp->b_actf; iodone(bp); rp->hpcs1 = RELEASE|GO; } hptab.b_actf = dp->b_forw; if (dp->b_actf) hpustart(unit); as &= ~(1<<unit); } for (unit=0; as; unit++) if (as&(1<<unit)) { as &= ~(1<<unit); hpustart(unit); } if (hptab.b_actf != NULL) hpstart(); } hpread(dev) { if (physck(hp_sizes[dev&07].nblocks, B_READ)) physio(hpstrategy, &hpbuf, dev, B_READ); } hpwrite(dev) { if (physck(hp_sizes[dev&07].nblocks, B_WRITE)) physio(hpstrategy, &hpbuf, dev, B_WRITE); } hpecc(rp, bp) register struct device *rp; register struct buf *bp; { register i; register b, n, map, mix; register char * cp; register mask; extern short piget(); mask = rp->hpec2&0xffff; if (mask == 0) { rp->hpof = FMT22; return(0); } i = (rp->hpec1&0xffff) - 1; n = i&017; i = (i&~017)>>3; b = (((mbactl.mba_bcr&0xffff) + (bp->b_bcount) - 1)>>9)&0177; if (bp->b_flags&B_PHYS) map = 128 + b; else map = (paddr(bp) - (paddr_t)buffers)>>9; mix = i + ((int)paddr(bp)&0x1ff); i += b<<BSHIFT; if ( i < bp->b_bcount) { cp = (char *)((mbamap[map+(mix>>9)]&0x1fffff)<<9)+(mix&0x1ff); piput(cp,piget(cp)^(mask<<n)); } mix += 2; i += 2; if ( i < bp->b_bcount) { cp = (char *)((mbamap[map+(mix>>9)]&0x1fffff)<<9)+(mix&0x1ff); piput(cp,piget(cp)^(mask>>(16-n))); } hptab.b_active++; if (mbactl.mba_bcr) { i = (int)bp->trksec; i = NSECT*(i>>8) + (i&0377) + b + 1; if (i >= NSECT*NTRAC) { i -= NSECT*NTRAC; rp->hpdc = bp->cylin + 1; } else rp->hpdc = bp->cylin; rp->hpda = ((i/NSECT)<<8) + (i%NSECT); rp->hpcs1 = DCLR|GO; mbactl.mba_sr = -1; mbactl.mba_var = ((128+b+1)<<9)|((int)paddr(bp)&0x1ff); if (pwr_act >= 0) rp->hpcs1 = RCOM|GO; return(1); } else return(0); } hptimer() { register unit; register struct iobuf *dp; register struct buf *bp; for (unit=0; unit < 8; unit++) { dp = &hputab[unit]; if (dp->wtime == WOK) continue; hpustart(unit); if (dp->wtime == WOK) continue; if (dp->wtime == WABORT) { if (dp->io_erec) logberr(dp, B_ERROR); while (bp = dp->b_actf) { bp->b_flags |= B_ERROR; dp->b_actf = bp->av_forw; iodone(bp); } dp->b_active = 0; dp->b_errcnt = 0; dp->qcnt = 0; printf("RP04/5/6 drive %d not available\n", unit); } dp->wtime--; } if (hptab.b_active == 0 && hptab.b_actf != NULL) hpstart(); timeout(hptimer, 0, 15*HZ); } hpclr() { register unit; hptab.b_active = 0; hptab.b_actf = NULL; for (unit = 0; unit < 8; unit++) hpustart(unit); hpstart(); }