1*1465Sbill /* hp.c 3.16 10/16/80 */ 221Sbill 321Sbill /* 4886Sbill * RP06/RM03/RM05 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" 15420Sbill #include "../h/pte.h" 1621Sbill #include "../h/mba.h" 1721Sbill #include "../h/mtpr.h" 18420Sbill #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 43420Sbill #define HPMBA MBA0 44420Sbill #define HPMBANUM 0 45420Sbill 46342Sbill #define NHP 2 4721Sbill #define RP 022 4821Sbill #define RM 024 49886Sbill #define RM5 027 5021Sbill #define NSECT 22 5121Sbill #define NTRAC 19 5221Sbill #define NRMSECT 32 5321Sbill #define NRMTRAC 5 5421Sbill 55305Sbill #define _hpSDIST 3 56305Sbill #define _hpRDIST 6 57305Sbill 58305Sbill int hpSDIST = _hpSDIST; 59305Sbill int hpRDIST = _hpRDIST; 60305Sbill int hpseek; 61305Sbill 6221Sbill struct size 6321Sbill { 6421Sbill daddr_t nblocks; 6521Sbill int cyloff; 6621Sbill } hp_sizes[8] = 6721Sbill { 68886Sbill 15884, 0, /* A=cyl 0 thru 37 */ 69886Sbill 33440, 38, /* B=cyl 38 thru 117 */ 70886Sbill 340670, 0, /* C=cyl 0 thru 814 */ 7121Sbill 0, 0, 7221Sbill 0, 0, 7321Sbill 0, 0, 74886Sbill 291346, 118, /* G=cyl 118 thru 814 */ 7521Sbill 0, 0, 7621Sbill }, rm_sizes[8] = { 77886Sbill 15884, 0, /* A=cyl 0 thru 99 */ 78886Sbill 33440, 100, /* B=cyl 100 thru 309 */ 79886Sbill 131680, 0, /* C=cyl 0 thru 822 */ 8021Sbill 0, 0, 8121Sbill 0, 0, 8221Sbill 0, 0, 83886Sbill 82080, 310, /* G=cyl 310 thru 822 */ 8421Sbill 0, 0, 85886Sbill }, rm5_sizes[8] = { 86886Sbill 15884, 0, /* A=cyl 0 thru 26 */ 87886Sbill 33440, 27, /* B=cyl 27 thru 81 */ 88886Sbill 500992, 0, /* C=cyl 0 thru 823 */ 89886Sbill 15884, 562, /* D=cyl 562 thru 588 */ 90886Sbill 55936, 589, /* E=cyl 589 thru 680 */ 91886Sbill 86944, 681, /* F=cyl 681 thru 823 */ 92886Sbill 159296, 562, /* G=cyl 562 thru 823 */ 93886Sbill 291346, 82, /* H=cyl 82 thru 561 */ 9421Sbill }; 9521Sbill 9621Sbill #define P400 020 9721Sbill #define M400 0220 9821Sbill #define P800 040 9921Sbill #define M800 0240 10021Sbill #define P1200 060 10121Sbill #define M1200 0260 10221Sbill int hp_offset[16] = 10321Sbill { 10421Sbill P400, M400, P400, M400, 10521Sbill P800, M800, P800, M800, 10621Sbill P1200, M1200, P1200, M1200, 10721Sbill 0, 0, 0, 0, 10821Sbill }; 10921Sbill 11021Sbill struct buf hptab; 11121Sbill struct buf rhpbuf; 11221Sbill struct buf hputab[NHP]; 11321Sbill char hp_type[NHP]; /* drive type */ 11421Sbill 11521Sbill #define GO 01 11621Sbill #define PRESET 020 11721Sbill #define RTC 016 11821Sbill #define OFFSET 014 119305Sbill #define SEEK 04 12021Sbill #define SEARCH 030 12121Sbill #define RECAL 06 12221Sbill #define DCLR 010 12321Sbill #define WCOM 060 12421Sbill #define RCOM 070 12521Sbill 12621Sbill #define IE 0100 12721Sbill #define PIP 020000 12821Sbill #define DRY 0200 12921Sbill #define ERR 040000 13021Sbill #define TRE 040000 13121Sbill #define DCK 0100000 13221Sbill #define WLE 04000 13321Sbill #define ECH 0100 13421Sbill #define VV 0100 13521Sbill #define DPR 0400 13621Sbill #define MOL 010000 13721Sbill #define FMT22 010000 13821Sbill 13921Sbill #define b_cylin b_resid 14021Sbill 14121Sbill #ifdef INTRLVE 14221Sbill daddr_t dkblock(); 14321Sbill #endif 14421Sbill 14521Sbill hpstrategy(bp) 14621Sbill register struct buf *bp; 14721Sbill { 14821Sbill register struct buf *dp; 14921Sbill register unit, xunit, nspc; 15021Sbill long sz, bn; 15121Sbill struct size *sizes; 15221Sbill 153420Sbill if ((mbaact&(1<<HPMBANUM)) == 0) 154420Sbill mbainit(HPMBANUM); 15521Sbill xunit = minor(bp->b_dev) & 077; 15621Sbill sz = bp->b_bcount; 15721Sbill sz = (sz+511) >> 9; 15821Sbill unit = dkunit(bp); 15921Sbill if (hp_type[unit] == 0) { 16021Sbill struct device *hpaddr; 1611413Sbill double mspw; 16221Sbill 16321Sbill /* determine device type */ 164420Sbill hpaddr = mbadev(HPMBA, unit); 1651413Sbill 1661413Sbill /* record transfer rate (these are guesstimates secs/word) */ 1671413Sbill switch (hp_type[unit] = hpaddr->hpdt) { 1681413Sbill case RM: mspw = .0000019728; break; 1691413Sbill case RM5: mspw = .0000020345; break; 1701413Sbill case RP: mspw = .0000029592; break; 1711413Sbill } 1721413Sbill if (DK_N + unit <= DK_NMAX) 1731413Sbill dk_mspw[DK_N+unit] = mspw; 17421Sbill } 175886Sbill switch (hp_type[unit]) { 176886Sbill 177886Sbill case RM: 17821Sbill sizes = rm_sizes; 17921Sbill nspc = NRMSECT*NRMTRAC; 180886Sbill break; 181886Sbill case RM5: 182886Sbill sizes = rm5_sizes; 183886Sbill nspc = NRMSECT*NTRAC; 184886Sbill break; 185886Sbill case RP: 18621Sbill sizes = hp_sizes; 18721Sbill nspc = NSECT*NTRAC; 188886Sbill break; 189886Sbill default: 190886Sbill printf("hp: unknown device type 0%o\n", hp_type[unit]); 191886Sbill u.u_error = ENXIO; 192886Sbill unit = NHP+1; /* force error */ 19321Sbill } 19421Sbill if (unit >= NHP || 19521Sbill bp->b_blkno < 0 || 19621Sbill (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) { 19721Sbill bp->b_flags |= B_ERROR; 19821Sbill iodone(bp); 19921Sbill return; 20021Sbill } 20121Sbill bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff; 20221Sbill dp = &hputab[unit]; 203127Sbill (void) spl5(); 20421Sbill disksort(dp, bp); 20521Sbill if (dp->b_active == 0) { 20621Sbill hpustart(unit); 20721Sbill if(hptab.b_active == 0) 20821Sbill hpstart(); 20921Sbill } 210127Sbill (void) spl0(); 21121Sbill } 21221Sbill 21321Sbill hpustart(unit) 21421Sbill register unit; 21521Sbill { 21621Sbill register struct buf *bp, *dp; 21721Sbill register struct device *hpaddr; 21821Sbill daddr_t bn; 21921Sbill int sn, cn, csn; 22021Sbill 22121Sbill ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; 222420Sbill hpaddr = mbadev(HPMBA, 0); 223420Sbill hpaddr->hpas = 1<<unit; 22421Sbill 22521Sbill if(unit >= NHP) 22621Sbill return; 227344Sbill if (unit+DK_N <= DK_NMAX) 228344Sbill dk_busy &= ~(1<<(unit+DK_N)); 22921Sbill dp = &hputab[unit]; 23021Sbill if((bp=dp->b_actf) == NULL) 23121Sbill return; 232420Sbill hpaddr = mbadev(HPMBA, unit); 23321Sbill if((hpaddr->hpds & VV) == 0) { 23421Sbill hpaddr->hpcs1 = PRESET|GO; 23521Sbill hpaddr->hpof = FMT22; 23621Sbill } 23721Sbill if(dp->b_active) 23821Sbill goto done; 23921Sbill dp->b_active++; 24021Sbill if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) 24121Sbill goto done; 24221Sbill 24321Sbill bn = dkblock(bp); 24421Sbill cn = bp->b_cylin; 245886Sbill switch (hp_type[unit]) { 246886Sbill 247886Sbill case RM: 24821Sbill sn = bn%(NRMSECT*NRMTRAC); 249305Sbill sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 250886Sbill break; 251886Sbill case RM5: 252886Sbill sn = bn%(NRMSECT*NTRAC); 253886Sbill sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 254886Sbill break; 255886Sbill case RP: 25621Sbill sn = bn%(NSECT*NTRAC); 257305Sbill sn = (sn+NSECT-hpSDIST)%NSECT; 258886Sbill break; 259886Sbill default: 260886Sbill panic("hpustart"); 26121Sbill } 26221Sbill 26321Sbill if(cn - (hpaddr->hpdc & 0xffff)) 26421Sbill goto search; 265305Sbill else if (hpseek) 266305Sbill goto done; 267305Sbill csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1; 26821Sbill if(csn < 0) 26921Sbill csn += NSECT; 270305Sbill if(csn > NSECT-hpRDIST) 27121Sbill goto done; 27221Sbill 27321Sbill search: 27421Sbill hpaddr->hpdc = cn; 275305Sbill if (hpseek) 276305Sbill hpaddr->hpcs1 = SEEK|GO; 277305Sbill else { 278305Sbill hpaddr->hpda = sn; 279305Sbill hpaddr->hpcs1 = SEARCH|GO; 280305Sbill } 28121Sbill unit += DK_N; 282*1465Sbill if (unit <= DK_NMAX) { 283344Sbill dk_busy |= 1<<unit; 2841413Sbill dk_seek[unit]++; 285*1465Sbill } 28621Sbill return; 28721Sbill 28821Sbill done: 28921Sbill dp->b_forw = NULL; 29021Sbill if(hptab.b_actf == NULL) 291344Sbill hptab.b_actf = dp; 292344Sbill else 29321Sbill hptab.b_actl->b_forw = dp; 29421Sbill hptab.b_actl = dp; 29521Sbill } 29621Sbill 29721Sbill hpstart() 29821Sbill { 29921Sbill register struct buf *bp, *dp; 30021Sbill register unit; 30121Sbill register struct device *hpaddr; 30221Sbill daddr_t bn; 30321Sbill int dn, sn, tn, cn, nspc, ns; 30421Sbill 30521Sbill loop: 30621Sbill if ((dp = hptab.b_actf) == NULL) 30721Sbill return; 30821Sbill if ((bp = dp->b_actf) == NULL) { 30921Sbill hptab.b_actf = dp->b_forw; 31021Sbill goto loop; 31121Sbill } 31221Sbill hptab.b_active++; 31321Sbill unit = minor(bp->b_dev) & 077; 31421Sbill dn = dkunit(bp); 31521Sbill bn = dkblock(bp); 316886Sbill switch (hp_type[dn]) { 317886Sbill case RM: 31821Sbill nspc = NRMSECT*NRMTRAC; 31921Sbill ns = NRMSECT; 32021Sbill cn = rm_sizes[unit&07].cyloff; 321886Sbill break; 322886Sbill case RM5: 323886Sbill nspc = NRMSECT*NTRAC; 324886Sbill ns = NRMSECT; 325886Sbill cn = rm5_sizes[unit&07].cyloff; 326886Sbill break; 327886Sbill case RP: 32821Sbill nspc = NSECT*NTRAC; 32921Sbill ns = NSECT; 33021Sbill cn = hp_sizes[unit&07].cyloff; 331886Sbill break; 332886Sbill default: 333886Sbill panic("hpstart"); 33421Sbill } 33521Sbill cn += bn/nspc; 33621Sbill sn = bn%nspc; 33721Sbill tn = sn/ns; 33821Sbill sn = sn%ns; 33921Sbill 340420Sbill hpaddr = mbadev(HPMBA, dn); 34121Sbill if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) { 34221Sbill hptab.b_active = 0; 34321Sbill hptab.b_errcnt = 0; 34421Sbill dp->b_actf = bp->av_forw; 34521Sbill bp->b_flags |= B_ERROR; 34621Sbill iodone(bp); 34721Sbill goto loop; 34821Sbill } 349923Sbill if(hptab.b_errcnt >= 16 && (bp->b_flags&B_WRITE) == 0) { 35021Sbill hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22; 351420Sbill HPMBA->mba_cr &= ~MBAIE; 35221Sbill hpaddr->hpcs1 = OFFSET|GO; 35321Sbill while(hpaddr->hpds & PIP) 35421Sbill ; 355420Sbill HPMBA->mba_cr |= MBAIE; 35621Sbill } 35721Sbill hpaddr->hpdc = cn; 35821Sbill hpaddr->hpda = (tn << 8) + sn; 35921Sbill mbastart(bp, (int *)hpaddr); 36021Sbill 361344Sbill unit = dn+DK_N; 362344Sbill if (unit <= DK_NMAX) { 363344Sbill dk_busy |= 1<<unit; 3641413Sbill dk_xfer[unit]++; 365344Sbill dk_wds[unit] += bp->b_bcount>>6; 366344Sbill } 36721Sbill } 36821Sbill 36921Sbill hpintr(mbastat, as) 37021Sbill { 37121Sbill register struct buf *bp, *dp; 37221Sbill register unit; 37321Sbill register struct device *hpaddr; 37421Sbill 37521Sbill if(hptab.b_active) { 37621Sbill dp = hptab.b_actf; 37721Sbill bp = dp->b_actf; 37821Sbill unit = dkunit(bp); 3791413Sbill if (DK_N+unit <= DK_NMAX) 380344Sbill dk_busy &= ~(1<<(DK_N+unit)); 381420Sbill hpaddr = mbadev(HPMBA, unit); 382420Sbill if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { 38321Sbill while((hpaddr->hpds & DRY) == 0) 38421Sbill ; 38521Sbill if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE) 386420Sbill bp->b_flags |= B_ERROR; 387420Sbill else 38821Sbill hptab.b_active = 0; 38921Sbill if(hptab.b_errcnt > 27) 39021Sbill deverror(bp, mbastat, hpaddr->hper1); 39121Sbill if ((hpaddr->hper1&0xffff) == DCK) { 39221Sbill if (hpecc(hpaddr, bp)) 39321Sbill return; 39421Sbill } 39521Sbill hpaddr->hpcs1 = DCLR|GO; 39621Sbill if((hptab.b_errcnt&07) == 4) { 397420Sbill HPMBA->mba_cr &= ~MBAIE; 39821Sbill hpaddr->hpcs1 = RECAL|GO; 39921Sbill while(hpaddr->hpds & PIP) 40021Sbill ; 401420Sbill HPMBA->mba_cr |= MBAIE; 40221Sbill } 40321Sbill } 40421Sbill if(hptab.b_active) { 40521Sbill if(hptab.b_errcnt) { 406420Sbill HPMBA->mba_cr &= ~MBAIE; 40721Sbill hpaddr->hpcs1 = RTC|GO; 40821Sbill while(hpaddr->hpds & PIP) 40921Sbill ; 410420Sbill HPMBA->mba_cr |= MBAIE; 41121Sbill } 41221Sbill hptab.b_active = 0; 41321Sbill hptab.b_errcnt = 0; 41421Sbill hptab.b_actf = dp->b_forw; 41521Sbill dp->b_active = 0; 41621Sbill dp->b_errcnt = 0; 41721Sbill dp->b_actf = bp->av_forw; 418420Sbill bp->b_resid = -HPMBA->mba_bcr & 0xffff; 41921Sbill iodone(bp); 42021Sbill if(dp->b_actf) 42121Sbill hpustart(unit); 42221Sbill } 42321Sbill as &= ~(1<<unit); 42421Sbill } else { 42521Sbill if(as == 0) 426420Sbill HPMBA->mba_cr |= MBAIE; 42721Sbill } 42821Sbill for(unit=0; unit<NHP; unit++) 42921Sbill if(as & (1<<unit)) 43021Sbill hpustart(unit); 43121Sbill hpstart(); 43221Sbill } 43321Sbill 43421Sbill hpread(dev) 43521Sbill { 43621Sbill 43721Sbill physio(hpstrategy, &rhpbuf, dev, B_READ, minphys); 43821Sbill } 43921Sbill 44021Sbill hpwrite(dev) 44121Sbill { 44221Sbill 44321Sbill physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys); 44421Sbill } 44521Sbill 44621Sbill hpecc(rp, bp) 44721Sbill register struct device *rp; 44821Sbill register struct buf *bp; 44921Sbill { 450420Sbill struct mba_regs *mbp = HPMBA; 451420Sbill register int i; 452420Sbill caddr_t addr; 453420Sbill int reg, bit, byte, npf, mask, o; 454420Sbill int dn, bn, cn, tn, sn, ns, nt; 455106Sbill extern char buffers[NBUF][BSIZE]; 456420Sbill struct pte mpte; 457914Sbill int bcr; 45821Sbill 459420Sbill /* 460420Sbill * Npf is the number of sectors transferred before the sector 461420Sbill * containing the ECC error, and reg is the MBA register 462420Sbill * mapping (the first part of)the transfer. 463420Sbill * O is offset within a memory page of the first byte transferred. 464420Sbill */ 465914Sbill bcr = mbp->mba_bcr & 0xffff; 466914Sbill if (bcr) 467914Sbill bcr |= 0xffff0000; /* sxt */ 468719Sbill npf = btop(bcr + bp->b_bcount) - 1; 4691413Sbill reg = npf; 470420Sbill o = (int)bp->b_un.b_addr & PGOFSET; 471420Sbill printf("%D ", bp->b_blkno + npf); 47221Sbill prdev("ECC", bp->b_dev); 47321Sbill mask = rp->hpec2&0xffff; 47421Sbill if (mask == 0) { 47521Sbill rp->hpof = FMT22; 476420Sbill return (0); 47721Sbill } 478420Sbill 479420Sbill /* 480420Sbill * Compute the byte and bit position of the error. 481420Sbill * The variable i is the byte offset in the transfer, 482420Sbill * the variable byte is the offset from a page boundary 483420Sbill * in main memory. 484420Sbill */ 485420Sbill i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 486719Sbill bit = i&07; 487420Sbill i = (i&~07)>>3; 488420Sbill byte = i + o; 489420Sbill /* 490420Sbill * Correct while possible bits remain of mask. Since mask 491420Sbill * contains 11 bits, we continue while the bit offset is > -11. 492420Sbill * Also watch out for end of this block and the end of the whole 493420Sbill * transfer. 494420Sbill */ 495420Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 496420Sbill mpte = mbp->mba_map[reg+btop(byte)]; 497420Sbill addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 498420Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 499420Sbill byte++; 500420Sbill i++; 501420Sbill bit -= 8; 50221Sbill } 503420Sbill hptab.b_active++; /* Either complete or continuing */ 504719Sbill if (bcr == 0) 505420Sbill return (0); 506420Sbill /* 507420Sbill * Have to continue the transfer... clear the drive, 508420Sbill * and compute the position where the transfer is to continue. 509420Sbill * We have completed npf+1 sectores of the transfer already; 510420Sbill * restart at offset o of next sector (i.e. in MBA register reg+1). 511420Sbill */ 512420Sbill rp->hpcs1 = DCLR|GO; 513420Sbill dn = dkunit(bp); 514420Sbill bn = dkblock(bp); 515886Sbill switch (hp_type[dn]) { 516886Sbill 517886Sbill case RM: 518886Sbill ns = NRMSECT; nt = NRMTRAC; break; 519886Sbill case RM5: 520886Sbill ns = NRMSECT; nt = NTRAC; break; 521886Sbill case RP: 522886Sbill ns = NSECT; nt = NTRAC; break; 523886Sbill default: 524886Sbill panic("hpecc"); 52521Sbill } 526420Sbill cn = bp->b_cylin; 527420Sbill sn = bn%(ns*nt) + npf + 1; 528420Sbill tn = sn/ns; 529420Sbill sn %= ns; 530420Sbill cn += tn/nt; 531420Sbill tn %= nt; 532420Sbill rp->hpdc = cn; 533420Sbill rp->hpda = (tn<<8) + sn; 534420Sbill mbp->mba_sr = -1; 535420Sbill mbp->mba_var = (int)ptob(reg+1) + o; 536420Sbill rp->hpcs1 = RCOM|GO; 537420Sbill return (1); 53821Sbill } 539