1*420Sbill /* hp.c 3.9 07/29/80 */ 221Sbill 321Sbill /* 4344Sbill * RP06/RM03 disk driver 521Sbill */ 621Sbill 721Sbill #include "../h/param.h" 821Sbill #include "../h/systm.h" 9305Sbill #include "../h/dk.h" 1021Sbill #include "../h/buf.h" 1121Sbill #include "../h/conf.h" 1221Sbill #include "../h/dir.h" 1321Sbill #include "../h/user.h" 1421Sbill #include "../h/map.h" 15*420Sbill #include "../h/pte.h" 1621Sbill #include "../h/mba.h" 1721Sbill #include "../h/mtpr.h" 18*420Sbill #include "../h/vm.h" 1921Sbill 2021Sbill #define DK_N 0 21344Sbill #define DK_NMAX 1 2221Sbill 2321Sbill struct device 2421Sbill { 2521Sbill int hpcs1; /* control and Status register 1 */ 2621Sbill int hpds; /* Drive Status */ 2721Sbill int hper1; /* Error register 1 */ 2821Sbill int hpmr; /* Maintenance */ 2921Sbill int hpas; /* Attention Summary */ 3021Sbill int hpda; /* Desired address register */ 3121Sbill int hpdt; /* Drive type */ 3221Sbill int hpla; /* Look ahead */ 3321Sbill int hpsn; /* serial number */ 3421Sbill int hpof; /* Offset register */ 3521Sbill int hpdc; /* Desired Cylinder address register */ 3621Sbill int hpcc; /* Current Cylinder */ 3721Sbill int hper2; /* Error register 2 */ 3821Sbill int hper3; /* Error register 3 */ 3921Sbill int hpec1; /* Burst error bit position */ 4021Sbill int hpec2; /* Burst error bit pattern */ 4121Sbill }; 4221Sbill 43*420Sbill #define HPMBA MBA0 44*420Sbill #define HPMBANUM 0 45*420Sbill 46342Sbill #define NHP 2 4721Sbill #define RP 022 4821Sbill #define RM 024 4921Sbill #define NSECT 22 5021Sbill #define NTRAC 19 5121Sbill #define NRMSECT 32 5221Sbill #define NRMTRAC 5 5321Sbill 54305Sbill #define _hpSDIST 3 55305Sbill #define _hpRDIST 6 56305Sbill 57305Sbill int hpSDIST = _hpSDIST; 58305Sbill int hpRDIST = _hpRDIST; 59305Sbill int hpseek; 60305Sbill 6121Sbill struct size 6221Sbill { 6321Sbill daddr_t nblocks; 6421Sbill int cyloff; 6521Sbill } hp_sizes[8] = 6621Sbill { 6721Sbill 15884, 0, /* cyl 0 thru 37 */ 6821Sbill 33440, 38, /* cyl 38 thru 117 */ 6921Sbill 8360, 98, /* cyl 98 thru 117 */ 7021Sbill #ifdef ERNIE 7121Sbill 15884, 118, /* cyl 118 thru 155 */ 7221Sbill 66880, 156, /* cyl 156 thru 315 */ 7321Sbill 0, 0, 7421Sbill 291346, 118, /* cyl 118 thru 814, (like distrib) */ 7521Sbill 208582, 316, /* cyl 316 thru 814 */ 7621Sbill #else 7721Sbill 0, 0, 7821Sbill 0, 0, 7921Sbill 0, 0, 8021Sbill 291346, 118, /* cyl 118 thru 814 */ 8121Sbill 0, 0, 8221Sbill #endif 8321Sbill }, rm_sizes[8] = { 8421Sbill 15884, 0, /* cyl 0 thru 99 */ 8521Sbill 33440, 100, /* cyl 100 thru 309 */ 8621Sbill 0, 0, 8721Sbill 0, 0, 8821Sbill 0, 0, 8921Sbill 0, 0, 9021Sbill 82080, 310, /* cyl 310 thru 822 */ 9121Sbill 0, 0, 9221Sbill }; 9321Sbill 9421Sbill #define P400 020 9521Sbill #define M400 0220 9621Sbill #define P800 040 9721Sbill #define M800 0240 9821Sbill #define P1200 060 9921Sbill #define M1200 0260 10021Sbill int hp_offset[16] = 10121Sbill { 10221Sbill P400, M400, P400, M400, 10321Sbill P800, M800, P800, M800, 10421Sbill P1200, M1200, P1200, M1200, 10521Sbill 0, 0, 0, 0, 10621Sbill }; 10721Sbill 10821Sbill struct buf hptab; 10921Sbill struct buf rhpbuf; 11021Sbill struct buf hputab[NHP]; 11121Sbill char hp_type[NHP]; /* drive type */ 11221Sbill 11321Sbill #define GO 01 11421Sbill #define PRESET 020 11521Sbill #define RTC 016 11621Sbill #define OFFSET 014 117305Sbill #define SEEK 04 11821Sbill #define SEARCH 030 11921Sbill #define RECAL 06 12021Sbill #define DCLR 010 12121Sbill #define WCOM 060 12221Sbill #define RCOM 070 12321Sbill 12421Sbill #define IE 0100 12521Sbill #define PIP 020000 12621Sbill #define DRY 0200 12721Sbill #define ERR 040000 12821Sbill #define TRE 040000 12921Sbill #define DCK 0100000 13021Sbill #define WLE 04000 13121Sbill #define ECH 0100 13221Sbill #define VV 0100 13321Sbill #define DPR 0400 13421Sbill #define MOL 010000 13521Sbill #define FMT22 010000 13621Sbill 13721Sbill #define b_cylin b_resid 13821Sbill 13921Sbill #ifdef INTRLVE 14021Sbill daddr_t dkblock(); 14121Sbill #endif 14221Sbill 14321Sbill hpstrategy(bp) 14421Sbill register struct buf *bp; 14521Sbill { 14621Sbill register struct buf *dp; 14721Sbill register unit, xunit, nspc; 14821Sbill long sz, bn; 14921Sbill struct size *sizes; 15021Sbill 151*420Sbill if ((mbaact&(1<<HPMBANUM)) == 0) 152*420Sbill mbainit(HPMBANUM); 15321Sbill xunit = minor(bp->b_dev) & 077; 15421Sbill sz = bp->b_bcount; 15521Sbill sz = (sz+511) >> 9; 15621Sbill unit = dkunit(bp); 15721Sbill if (hp_type[unit] == 0) { 15821Sbill struct device *hpaddr; 15921Sbill 16021Sbill /* determine device type */ 161*420Sbill hpaddr = mbadev(HPMBA, unit); 16221Sbill hp_type[unit] = hpaddr->hpdt; 16321Sbill } 16421Sbill if (hp_type[unit] == RM) { 16521Sbill sizes = rm_sizes; 16621Sbill nspc = NRMSECT*NRMTRAC; 16721Sbill } else { 16821Sbill sizes = hp_sizes; 16921Sbill nspc = NSECT*NTRAC; 17021Sbill } 17121Sbill if (unit >= NHP || 17221Sbill bp->b_blkno < 0 || 17321Sbill (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) { 17421Sbill bp->b_flags |= B_ERROR; 17521Sbill iodone(bp); 17621Sbill return; 17721Sbill } 17821Sbill bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff; 17921Sbill dp = &hputab[unit]; 180127Sbill (void) spl5(); 18121Sbill disksort(dp, bp); 18221Sbill if (dp->b_active == 0) { 18321Sbill hpustart(unit); 18421Sbill if(hptab.b_active == 0) 18521Sbill hpstart(); 18621Sbill } 187127Sbill (void) spl0(); 18821Sbill } 18921Sbill 19021Sbill hpustart(unit) 19121Sbill register unit; 19221Sbill { 19321Sbill register struct buf *bp, *dp; 19421Sbill register struct device *hpaddr; 19521Sbill daddr_t bn; 19621Sbill int sn, cn, csn; 19721Sbill 19821Sbill ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; 199*420Sbill hpaddr = mbadev(HPMBA, 0); 200*420Sbill hpaddr->hpas = 1<<unit; 20121Sbill 20221Sbill if(unit >= NHP) 20321Sbill return; 204344Sbill if (unit+DK_N <= DK_NMAX) 205344Sbill dk_busy &= ~(1<<(unit+DK_N)); 20621Sbill dp = &hputab[unit]; 20721Sbill if((bp=dp->b_actf) == NULL) 20821Sbill return; 209*420Sbill hpaddr = mbadev(HPMBA, unit); 21021Sbill if((hpaddr->hpds & VV) == 0) { 21121Sbill hpaddr->hpcs1 = PRESET|GO; 21221Sbill hpaddr->hpof = FMT22; 21321Sbill } 21421Sbill if(dp->b_active) 21521Sbill goto done; 21621Sbill dp->b_active++; 21721Sbill if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) 21821Sbill goto done; 21921Sbill 22021Sbill bn = dkblock(bp); 22121Sbill cn = bp->b_cylin; 22221Sbill if(hp_type[unit] == RM) { 22321Sbill sn = bn%(NRMSECT*NRMTRAC); 224305Sbill sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 22521Sbill } else { 22621Sbill sn = bn%(NSECT*NTRAC); 227305Sbill sn = (sn+NSECT-hpSDIST)%NSECT; 22821Sbill } 22921Sbill 23021Sbill if(cn - (hpaddr->hpdc & 0xffff)) 23121Sbill goto search; 232305Sbill else if (hpseek) 233305Sbill goto done; 234305Sbill csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1; 23521Sbill if(csn < 0) 23621Sbill csn += NSECT; 237305Sbill if(csn > NSECT-hpRDIST) 23821Sbill goto done; 23921Sbill 24021Sbill search: 24121Sbill hpaddr->hpdc = cn; 242305Sbill if (hpseek) 243305Sbill hpaddr->hpcs1 = SEEK|GO; 244305Sbill else { 245305Sbill hpaddr->hpda = sn; 246305Sbill hpaddr->hpcs1 = SEARCH|GO; 247305Sbill } 24821Sbill unit += DK_N; 249344Sbill if (unit <= DK_NMAX && DK_N+NHP <= DK_NMAX) { 250344Sbill dk_busy |= 1<<unit; 251344Sbill dk_numb[unit]++; 252344Sbill } 25321Sbill return; 25421Sbill 25521Sbill done: 25621Sbill dp->b_forw = NULL; 25721Sbill if(hptab.b_actf == NULL) 258344Sbill hptab.b_actf = dp; 259344Sbill else 26021Sbill hptab.b_actl->b_forw = dp; 26121Sbill hptab.b_actl = dp; 26221Sbill } 26321Sbill 26421Sbill hpstart() 26521Sbill { 26621Sbill register struct buf *bp, *dp; 26721Sbill register unit; 26821Sbill register struct device *hpaddr; 26921Sbill daddr_t bn; 27021Sbill int dn, sn, tn, cn, nspc, ns; 27121Sbill 27221Sbill loop: 27321Sbill if ((dp = hptab.b_actf) == NULL) 27421Sbill return; 27521Sbill if ((bp = dp->b_actf) == NULL) { 27621Sbill hptab.b_actf = dp->b_forw; 27721Sbill goto loop; 27821Sbill } 27921Sbill hptab.b_active++; 28021Sbill unit = minor(bp->b_dev) & 077; 28121Sbill dn = dkunit(bp); 28221Sbill bn = dkblock(bp); 28321Sbill if (hp_type[dn] == RM) { 28421Sbill nspc = NRMSECT*NRMTRAC; 28521Sbill ns = NRMSECT; 28621Sbill cn = rm_sizes[unit&07].cyloff; 28721Sbill } else { 28821Sbill nspc = NSECT*NTRAC; 28921Sbill ns = NSECT; 29021Sbill cn = hp_sizes[unit&07].cyloff; 29121Sbill } 29221Sbill cn += bn/nspc; 29321Sbill sn = bn%nspc; 29421Sbill tn = sn/ns; 29521Sbill sn = sn%ns; 29621Sbill 297*420Sbill hpaddr = mbadev(HPMBA, dn); 29821Sbill if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) { 29921Sbill hptab.b_active = 0; 30021Sbill hptab.b_errcnt = 0; 30121Sbill dp->b_actf = bp->av_forw; 30221Sbill bp->b_flags |= B_ERROR; 30321Sbill iodone(bp); 30421Sbill goto loop; 30521Sbill } 30621Sbill if(hptab.b_errcnt >= 16) { 30721Sbill hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22; 308*420Sbill HPMBA->mba_cr &= ~MBAIE; 30921Sbill hpaddr->hpcs1 = OFFSET|GO; 31021Sbill while(hpaddr->hpds & PIP) 31121Sbill ; 312*420Sbill HPMBA->mba_cr |= MBAIE; 31321Sbill } 31421Sbill hpaddr->hpdc = cn; 31521Sbill hpaddr->hpda = (tn << 8) + sn; 31621Sbill mbastart(bp, (int *)hpaddr); 31721Sbill 318344Sbill unit = dn+DK_N; 319344Sbill if (NHP+DK_N == DK_NMAX) 320344Sbill unit = NHP+DK_N; 321344Sbill if (unit <= DK_NMAX) { 322344Sbill dk_busy |= 1<<unit; 323344Sbill dk_numb[unit]++; 324344Sbill dk_wds[unit] += bp->b_bcount>>6; 325344Sbill } 32621Sbill } 32721Sbill 32821Sbill hpintr(mbastat, as) 32921Sbill { 33021Sbill register struct buf *bp, *dp; 33121Sbill register unit; 33221Sbill register struct device *hpaddr; 33321Sbill 33421Sbill if(hptab.b_active) { 33521Sbill dp = hptab.b_actf; 33621Sbill bp = dp->b_actf; 33721Sbill unit = dkunit(bp); 338344Sbill if (DK_N+NHP == DK_NMAX) 339344Sbill dk_busy &= ~(1<<(DK_N+NHP)); 340344Sbill else if (DK_N+unit <= DK_NMAX) 341344Sbill dk_busy &= ~(1<<(DK_N+unit)); 342*420Sbill hpaddr = mbadev(HPMBA, unit); 343*420Sbill if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { 34421Sbill while((hpaddr->hpds & DRY) == 0) 34521Sbill ; 34621Sbill if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE) 347*420Sbill bp->b_flags |= B_ERROR; 348*420Sbill else 34921Sbill hptab.b_active = 0; 35021Sbill if(hptab.b_errcnt > 27) 35121Sbill deverror(bp, mbastat, hpaddr->hper1); 35221Sbill if ((hpaddr->hper1&0xffff) == DCK) { 35321Sbill if (hpecc(hpaddr, bp)) 35421Sbill return; 35521Sbill } 35621Sbill hpaddr->hpcs1 = DCLR|GO; 35721Sbill if((hptab.b_errcnt&07) == 4) { 358*420Sbill HPMBA->mba_cr &= ~MBAIE; 35921Sbill hpaddr->hpcs1 = RECAL|GO; 36021Sbill while(hpaddr->hpds & PIP) 36121Sbill ; 362*420Sbill HPMBA->mba_cr |= MBAIE; 36321Sbill } 36421Sbill } 36521Sbill if(hptab.b_active) { 36621Sbill if(hptab.b_errcnt) { 367*420Sbill HPMBA->mba_cr &= ~MBAIE; 36821Sbill hpaddr->hpcs1 = RTC|GO; 36921Sbill while(hpaddr->hpds & PIP) 37021Sbill ; 371*420Sbill HPMBA->mba_cr |= MBAIE; 37221Sbill } 37321Sbill hptab.b_active = 0; 37421Sbill hptab.b_errcnt = 0; 37521Sbill hptab.b_actf = dp->b_forw; 37621Sbill dp->b_active = 0; 37721Sbill dp->b_errcnt = 0; 37821Sbill dp->b_actf = bp->av_forw; 379*420Sbill bp->b_resid = -HPMBA->mba_bcr & 0xffff; 38021Sbill iodone(bp); 38121Sbill if(dp->b_actf) 38221Sbill hpustart(unit); 38321Sbill } 38421Sbill as &= ~(1<<unit); 38521Sbill } else { 38621Sbill if(as == 0) 387*420Sbill HPMBA->mba_cr |= MBAIE; 38821Sbill } 38921Sbill for(unit=0; unit<NHP; unit++) 39021Sbill if(as & (1<<unit)) 39121Sbill hpustart(unit); 39221Sbill hpstart(); 39321Sbill } 39421Sbill 39521Sbill hpread(dev) 39621Sbill { 39721Sbill 39821Sbill physio(hpstrategy, &rhpbuf, dev, B_READ, minphys); 39921Sbill } 40021Sbill 40121Sbill hpwrite(dev) 40221Sbill { 40321Sbill 40421Sbill physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys); 40521Sbill } 40621Sbill 40721Sbill hpecc(rp, bp) 40821Sbill register struct device *rp; 40921Sbill register struct buf *bp; 41021Sbill { 411*420Sbill struct mba_regs *mbp = HPMBA; 412*420Sbill register int i; 413*420Sbill caddr_t addr; 414*420Sbill int reg, bit, byte, npf, mask, o; 415*420Sbill int dn, bn, cn, tn, sn, ns, nt; 416106Sbill extern char buffers[NBUF][BSIZE]; 417*420Sbill struct pte mpte; 41821Sbill 419*420Sbill /* 420*420Sbill * Npf is the number of sectors transferred before the sector 421*420Sbill * containing the ECC error, and reg is the MBA register 422*420Sbill * mapping (the first part of)the transfer. 423*420Sbill * O is offset within a memory page of the first byte transferred. 424*420Sbill */ 425*420Sbill npf = btop((mbp->mba_bcr&0xffff) + bp->b_bcount) - 1; 426*420Sbill if (bp->b_flags&B_PHYS) 427*420Sbill reg = 128 + npf; 428*420Sbill else 429*420Sbill reg = btop(bp->b_un.b_addr - buffers[0]) + npf; 430*420Sbill o = (int)bp->b_un.b_addr & PGOFSET; 431*420Sbill printf("%D ", bp->b_blkno + npf); 43221Sbill prdev("ECC", bp->b_dev); 43321Sbill mask = rp->hpec2&0xffff; 43421Sbill if (mask == 0) { 43521Sbill rp->hpof = FMT22; 436*420Sbill return (0); 43721Sbill } 438*420Sbill 439*420Sbill /* 440*420Sbill * Compute the byte and bit position of the error. 441*420Sbill * The variable i is the byte offset in the transfer, 442*420Sbill * the variable byte is the offset from a page boundary 443*420Sbill * in main memory. 444*420Sbill */ 445*420Sbill i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 446*420Sbill bit = i&017; 447*420Sbill i = (i&~07)>>3; 448*420Sbill byte = i + o; 449*420Sbill /* 450*420Sbill * Correct while possible bits remain of mask. Since mask 451*420Sbill * contains 11 bits, we continue while the bit offset is > -11. 452*420Sbill * Also watch out for end of this block and the end of the whole 453*420Sbill * transfer. 454*420Sbill */ 455*420Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 456*420Sbill mpte = mbp->mba_map[reg+btop(byte)]; 457*420Sbill addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 458*420Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 459*420Sbill byte++; 460*420Sbill i++; 461*420Sbill bit -= 8; 46221Sbill } 463*420Sbill hptab.b_active++; /* Either complete or continuing */ 464*420Sbill if (mbp->mba_bcr == 0) 465*420Sbill return (0); 466*420Sbill /* 467*420Sbill * Have to continue the transfer... clear the drive, 468*420Sbill * and compute the position where the transfer is to continue. 469*420Sbill * We have completed npf+1 sectores of the transfer already; 470*420Sbill * restart at offset o of next sector (i.e. in MBA register reg+1). 471*420Sbill */ 472*420Sbill rp->hpcs1 = DCLR|GO; 473*420Sbill dn = dkunit(bp); 474*420Sbill bn = dkblock(bp); 475*420Sbill if (hp_type[dn] == RM) { 476*420Sbill ns = NRMSECT; 477*420Sbill nt = NRMTRAC; 478*420Sbill } else { 479*420Sbill ns = NSECT; 480*420Sbill nt = NTRAC; 48121Sbill } 482*420Sbill cn = bp->b_cylin; 483*420Sbill sn = bn%(ns*nt) + npf + 1; 484*420Sbill tn = sn/ns; 485*420Sbill sn %= ns; 486*420Sbill cn += tn/nt; 487*420Sbill tn %= nt; 488*420Sbill rp->hpdc = cn; 489*420Sbill rp->hpda = (tn<<8) + sn; 490*420Sbill mbp->mba_sr = -1; 491*420Sbill mbp->mba_var = (int)ptob(reg+1) + o; 492*420Sbill rp->hpcs1 = RCOM|GO; 493*420Sbill return (1); 49421Sbill } 495