1*2298Skre /* hp.c 4.4 01/28/81 */ 221Sbill 31939Swnj #include "hp.h" 41565Sbill #if NHP > 0 521Sbill /* 6886Sbill * RP06/RM03/RM05 disk driver 721Sbill */ 821Sbill 921Sbill #include "../h/param.h" 1021Sbill #include "../h/systm.h" 11305Sbill #include "../h/dk.h" 1221Sbill #include "../h/buf.h" 1321Sbill #include "../h/conf.h" 1421Sbill #include "../h/dir.h" 1521Sbill #include "../h/user.h" 1621Sbill #include "../h/map.h" 17420Sbill #include "../h/pte.h" 1821Sbill #include "../h/mba.h" 1921Sbill #include "../h/mtpr.h" 20420Sbill #include "../h/vm.h" 2121Sbill 2221Sbill struct device 2321Sbill { 2421Sbill int hpcs1; /* control and Status register 1 */ 2521Sbill int hpds; /* Drive Status */ 2621Sbill int hper1; /* Error register 1 */ 2721Sbill int hpmr; /* Maintenance */ 2821Sbill int hpas; /* Attention Summary */ 2921Sbill int hpda; /* Desired address register */ 3021Sbill int hpdt; /* Drive type */ 3121Sbill int hpla; /* Look ahead */ 3221Sbill int hpsn; /* serial number */ 3321Sbill int hpof; /* Offset register */ 3421Sbill int hpdc; /* Desired Cylinder address register */ 3521Sbill int hpcc; /* Current Cylinder */ 3621Sbill int hper2; /* Error register 2 */ 3721Sbill int hper3; /* Error register 3 */ 3821Sbill int hpec1; /* Burst error bit position */ 3921Sbill int hpec2; /* Burst error bit pattern */ 4021Sbill }; 4121Sbill 4221Sbill #define RP 022 4321Sbill #define RM 024 44886Sbill #define RM5 027 4521Sbill #define NSECT 22 4621Sbill #define NTRAC 19 4721Sbill #define NRMSECT 32 4821Sbill #define NRMTRAC 5 4921Sbill 501591Sbill #define _hpSDIST 2 511591Sbill #define _hpRDIST 3 52305Sbill 53305Sbill int hpSDIST = _hpSDIST; 54305Sbill int hpRDIST = _hpRDIST; 55305Sbill int hpseek; 56305Sbill 5721Sbill struct size 5821Sbill { 5921Sbill daddr_t nblocks; 6021Sbill int cyloff; 6121Sbill } hp_sizes[8] = 6221Sbill { 63886Sbill 15884, 0, /* A=cyl 0 thru 37 */ 64886Sbill 33440, 38, /* B=cyl 38 thru 117 */ 65886Sbill 340670, 0, /* C=cyl 0 thru 814 */ 6621Sbill 0, 0, 6721Sbill 0, 0, 6821Sbill 0, 0, 69886Sbill 291346, 118, /* G=cyl 118 thru 814 */ 7021Sbill 0, 0, 7121Sbill }, rm_sizes[8] = { 72886Sbill 15884, 0, /* A=cyl 0 thru 99 */ 73886Sbill 33440, 100, /* B=cyl 100 thru 309 */ 74886Sbill 131680, 0, /* C=cyl 0 thru 822 */ 7521Sbill 0, 0, 7621Sbill 0, 0, 7721Sbill 0, 0, 78886Sbill 82080, 310, /* G=cyl 310 thru 822 */ 7921Sbill 0, 0, 80886Sbill }, rm5_sizes[8] = { 81886Sbill 15884, 0, /* A=cyl 0 thru 26 */ 82886Sbill 33440, 27, /* B=cyl 27 thru 81 */ 83886Sbill 500992, 0, /* C=cyl 0 thru 823 */ 84886Sbill 15884, 562, /* D=cyl 562 thru 588 */ 85886Sbill 55936, 589, /* E=cyl 589 thru 680 */ 86886Sbill 86944, 681, /* F=cyl 681 thru 823 */ 87886Sbill 159296, 562, /* G=cyl 562 thru 823 */ 88886Sbill 291346, 82, /* H=cyl 82 thru 561 */ 8921Sbill }; 9021Sbill 9121Sbill #define P400 020 9221Sbill #define M400 0220 9321Sbill #define P800 040 9421Sbill #define M800 0240 9521Sbill #define P1200 060 9621Sbill #define M1200 0260 9721Sbill int hp_offset[16] = 9821Sbill { 9921Sbill P400, M400, P400, M400, 10021Sbill P800, M800, P800, M800, 10121Sbill P1200, M1200, P1200, M1200, 10221Sbill 0, 0, 0, 0, 10321Sbill }; 10421Sbill 10521Sbill struct buf hptab; 10621Sbill struct buf rhpbuf; 10721Sbill struct buf hputab[NHP]; 10821Sbill char hp_type[NHP]; /* drive type */ 10921Sbill 11021Sbill #define GO 01 11121Sbill #define PRESET 020 11221Sbill #define RTC 016 11321Sbill #define OFFSET 014 114305Sbill #define SEEK 04 11521Sbill #define SEARCH 030 11621Sbill #define RECAL 06 11721Sbill #define DCLR 010 11821Sbill #define WCOM 060 11921Sbill #define RCOM 070 12021Sbill 12121Sbill #define IE 0100 12221Sbill #define PIP 020000 12321Sbill #define DRY 0200 12421Sbill #define ERR 040000 12521Sbill #define TRE 040000 12621Sbill #define DCK 0100000 12721Sbill #define WLE 04000 12821Sbill #define ECH 0100 12921Sbill #define VV 0100 13021Sbill #define DPR 0400 13121Sbill #define MOL 010000 13221Sbill #define FMT22 010000 13321Sbill 13421Sbill #define b_cylin b_resid 13521Sbill 13621Sbill #ifdef INTRLVE 13721Sbill daddr_t dkblock(); 13821Sbill #endif 13921Sbill 14021Sbill hpstrategy(bp) 14121Sbill register struct buf *bp; 14221Sbill { 14321Sbill register struct buf *dp; 14421Sbill register unit, xunit, nspc; 14521Sbill long sz, bn; 14621Sbill struct size *sizes; 14721Sbill 148420Sbill if ((mbaact&(1<<HPMBANUM)) == 0) 149420Sbill mbainit(HPMBANUM); 15021Sbill xunit = minor(bp->b_dev) & 077; 15121Sbill sz = bp->b_bcount; 15221Sbill sz = (sz+511) >> 9; 15321Sbill unit = dkunit(bp); 15421Sbill if (hp_type[unit] == 0) { 15521Sbill struct device *hpaddr; 1561413Sbill double mspw; 15721Sbill 15821Sbill /* determine device type */ 159420Sbill hpaddr = mbadev(HPMBA, unit); 1601413Sbill 1611413Sbill /* record transfer rate (these are guesstimates secs/word) */ 1621413Sbill switch (hp_type[unit] = hpaddr->hpdt) { 1631413Sbill case RM: mspw = .0000019728; break; 1641413Sbill case RM5: mspw = .0000020345; break; 1651413Sbill case RP: mspw = .0000029592; break; 1661413Sbill } 1671946Swnj if (HPDK_N + unit <= HPDK_NMAX) 1681946Swnj dk_mspw[HPDK_N+unit] = mspw; 16921Sbill } 170886Sbill switch (hp_type[unit]) { 171886Sbill 172886Sbill case RM: 17321Sbill sizes = rm_sizes; 17421Sbill nspc = NRMSECT*NRMTRAC; 175886Sbill break; 176886Sbill case RM5: 177886Sbill sizes = rm5_sizes; 178886Sbill nspc = NRMSECT*NTRAC; 179886Sbill break; 180886Sbill case RP: 18121Sbill sizes = hp_sizes; 18221Sbill nspc = NSECT*NTRAC; 183886Sbill break; 184886Sbill default: 185886Sbill printf("hp: unknown device type 0%o\n", hp_type[unit]); 186886Sbill u.u_error = ENXIO; 187886Sbill unit = NHP+1; /* force error */ 18821Sbill } 18921Sbill if (unit >= NHP || 19021Sbill bp->b_blkno < 0 || 19121Sbill (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) { 19221Sbill bp->b_flags |= B_ERROR; 19321Sbill iodone(bp); 19421Sbill return; 19521Sbill } 19621Sbill bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff; 19721Sbill dp = &hputab[unit]; 198127Sbill (void) spl5(); 19921Sbill disksort(dp, bp); 20021Sbill if (dp->b_active == 0) { 20121Sbill hpustart(unit); 20221Sbill if(hptab.b_active == 0) 20321Sbill hpstart(); 20421Sbill } 205127Sbill (void) spl0(); 20621Sbill } 20721Sbill 20821Sbill hpustart(unit) 20921Sbill register unit; 21021Sbill { 21121Sbill register struct buf *bp, *dp; 21221Sbill register struct device *hpaddr; 21321Sbill daddr_t bn; 214*2298Skre int sn, cn, csn, ns; 21521Sbill 2161734Sbill ((struct mba_regs *)HPMBA)->mba_cr |= MBAIE; 217420Sbill hpaddr = mbadev(HPMBA, 0); 218420Sbill hpaddr->hpas = 1<<unit; 21921Sbill 22021Sbill if(unit >= NHP) 22121Sbill return; 2221946Swnj if (unit+HPDK_N <= HPDK_NMAX) 2231946Swnj dk_busy &= ~(1<<(unit+HPDK_N)); 22421Sbill dp = &hputab[unit]; 22521Sbill if((bp=dp->b_actf) == NULL) 22621Sbill return; 227420Sbill hpaddr = mbadev(HPMBA, unit); 22821Sbill if((hpaddr->hpds & VV) == 0) { 229*2298Skre hpaddr->hpcs1 = DCLR|GO; 23021Sbill hpaddr->hpcs1 = PRESET|GO; 23121Sbill hpaddr->hpof = FMT22; 23221Sbill } 23321Sbill if(dp->b_active) 23421Sbill goto done; 23521Sbill dp->b_active++; 23621Sbill if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) 23721Sbill goto done; 23821Sbill 239*2298Skre #if NHP > 1 24021Sbill bn = dkblock(bp); 24121Sbill cn = bp->b_cylin; 242886Sbill switch (hp_type[unit]) { 243886Sbill 244886Sbill case RM: 24521Sbill sn = bn%(NRMSECT*NRMTRAC); 246305Sbill sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 247*2298Skre ns = NRMSECT; 248886Sbill break; 249886Sbill case RM5: 250886Sbill sn = bn%(NRMSECT*NTRAC); 251886Sbill sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 252*2298Skre ns = NRMSECT; 253886Sbill break; 254886Sbill case RP: 25521Sbill sn = bn%(NSECT*NTRAC); 256305Sbill sn = (sn+NSECT-hpSDIST)%NSECT; 257*2298Skre ns = 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) 269*2298Skre csn += ns; 270*2298Skre if(csn > ns-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 } 2811946Swnj unit += HPDK_N; 2821946Swnj if (unit <= HPDK_NMAX) { 283344Sbill dk_busy |= 1<<unit; 2841413Sbill dk_seek[unit]++; 2851465Sbill } 28621Sbill return; 287*2298Skre #endif 28821Sbill 28921Sbill done: 29021Sbill dp->b_forw = NULL; 29121Sbill if(hptab.b_actf == NULL) 292344Sbill hptab.b_actf = dp; 293344Sbill else 29421Sbill hptab.b_actl->b_forw = dp; 29521Sbill hptab.b_actl = dp; 29621Sbill } 29721Sbill 29821Sbill hpstart() 29921Sbill { 30021Sbill register struct buf *bp, *dp; 30121Sbill register unit; 30221Sbill register struct device *hpaddr; 30321Sbill daddr_t bn; 30421Sbill int dn, sn, tn, cn, nspc, ns; 30521Sbill 30621Sbill loop: 30721Sbill if ((dp = hptab.b_actf) == NULL) 30821Sbill return; 30921Sbill if ((bp = dp->b_actf) == NULL) { 31021Sbill hptab.b_actf = dp->b_forw; 31121Sbill goto loop; 31221Sbill } 31321Sbill hptab.b_active++; 31421Sbill unit = minor(bp->b_dev) & 077; 31521Sbill dn = dkunit(bp); 31621Sbill bn = dkblock(bp); 317886Sbill switch (hp_type[dn]) { 318886Sbill case RM: 31921Sbill nspc = NRMSECT*NRMTRAC; 32021Sbill ns = NRMSECT; 32121Sbill cn = rm_sizes[unit&07].cyloff; 322886Sbill break; 323886Sbill case RM5: 324886Sbill nspc = NRMSECT*NTRAC; 325886Sbill ns = NRMSECT; 326886Sbill cn = rm5_sizes[unit&07].cyloff; 327886Sbill break; 328886Sbill case RP: 32921Sbill nspc = NSECT*NTRAC; 33021Sbill ns = NSECT; 33121Sbill cn = hp_sizes[unit&07].cyloff; 332886Sbill break; 333886Sbill default: 334886Sbill panic("hpstart"); 33521Sbill } 33621Sbill cn += bn/nspc; 33721Sbill sn = bn%nspc; 33821Sbill tn = sn/ns; 33921Sbill sn = sn%ns; 34021Sbill 341420Sbill hpaddr = mbadev(HPMBA, dn); 34221Sbill if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) { 34321Sbill hptab.b_active = 0; 34421Sbill hptab.b_errcnt = 0; 34521Sbill dp->b_actf = bp->av_forw; 34621Sbill bp->b_flags |= B_ERROR; 34721Sbill iodone(bp); 34821Sbill goto loop; 34921Sbill } 350*2298Skre if(hptab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 35121Sbill hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22; 352420Sbill HPMBA->mba_cr &= ~MBAIE; 35321Sbill hpaddr->hpcs1 = OFFSET|GO; 35421Sbill while(hpaddr->hpds & PIP) 35521Sbill ; 356420Sbill HPMBA->mba_cr |= MBAIE; 35721Sbill } 35821Sbill hpaddr->hpdc = cn; 35921Sbill hpaddr->hpda = (tn << 8) + sn; 36021Sbill mbastart(bp, (int *)hpaddr); 36121Sbill 3621946Swnj unit = dn+HPDK_N; 3631946Swnj if (unit <= HPDK_NMAX) { 364344Sbill dk_busy |= 1<<unit; 3651413Sbill dk_xfer[unit]++; 366344Sbill dk_wds[unit] += bp->b_bcount>>6; 367344Sbill } 36821Sbill } 36921Sbill 37021Sbill hpintr(mbastat, as) 37121Sbill { 37221Sbill register struct buf *bp, *dp; 37321Sbill register unit; 37421Sbill register struct device *hpaddr; 37521Sbill 37621Sbill if(hptab.b_active) { 37721Sbill dp = hptab.b_actf; 37821Sbill bp = dp->b_actf; 37921Sbill unit = dkunit(bp); 3801946Swnj if (HPDK_N+unit <= HPDK_NMAX) 3811946Swnj dk_busy &= ~(1<<(HPDK_N+unit)); 382420Sbill hpaddr = mbadev(HPMBA, unit); 383420Sbill if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { 38421Sbill while((hpaddr->hpds & DRY) == 0) 38521Sbill ; 38621Sbill if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE) 387420Sbill bp->b_flags |= B_ERROR; 388420Sbill else 38921Sbill hptab.b_active = 0; 39021Sbill if(hptab.b_errcnt > 27) 39121Sbill deverror(bp, mbastat, hpaddr->hper1); 39221Sbill if ((hpaddr->hper1&0xffff) == DCK) { 39321Sbill if (hpecc(hpaddr, bp)) 39421Sbill return; 39521Sbill } 39621Sbill hpaddr->hpcs1 = DCLR|GO; 39721Sbill if((hptab.b_errcnt&07) == 4) { 398420Sbill HPMBA->mba_cr &= ~MBAIE; 39921Sbill hpaddr->hpcs1 = RECAL|GO; 40021Sbill while(hpaddr->hpds & PIP) 40121Sbill ; 402420Sbill HPMBA->mba_cr |= MBAIE; 40321Sbill } 40421Sbill } 40521Sbill if(hptab.b_active) { 40621Sbill if(hptab.b_errcnt) { 407420Sbill HPMBA->mba_cr &= ~MBAIE; 40821Sbill hpaddr->hpcs1 = RTC|GO; 40921Sbill while(hpaddr->hpds & PIP) 41021Sbill ; 411420Sbill HPMBA->mba_cr |= MBAIE; 41221Sbill } 41321Sbill hptab.b_active = 0; 41421Sbill hptab.b_errcnt = 0; 41521Sbill hptab.b_actf = dp->b_forw; 41621Sbill dp->b_active = 0; 41721Sbill dp->b_errcnt = 0; 41821Sbill dp->b_actf = bp->av_forw; 419420Sbill bp->b_resid = -HPMBA->mba_bcr & 0xffff; 42021Sbill iodone(bp); 42121Sbill if(dp->b_actf) 42221Sbill hpustart(unit); 42321Sbill } 42421Sbill as &= ~(1<<unit); 42521Sbill } else { 42621Sbill if(as == 0) 427420Sbill HPMBA->mba_cr |= MBAIE; 42821Sbill } 42921Sbill for(unit=0; unit<NHP; unit++) 43021Sbill if(as & (1<<unit)) 43121Sbill hpustart(unit); 43221Sbill hpstart(); 43321Sbill } 43421Sbill 43521Sbill hpread(dev) 43621Sbill { 43721Sbill 43821Sbill physio(hpstrategy, &rhpbuf, dev, B_READ, minphys); 43921Sbill } 44021Sbill 44121Sbill hpwrite(dev) 44221Sbill { 44321Sbill 44421Sbill physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys); 44521Sbill } 44621Sbill 44721Sbill hpecc(rp, bp) 44821Sbill register struct device *rp; 44921Sbill register struct buf *bp; 45021Sbill { 451420Sbill struct mba_regs *mbp = HPMBA; 452420Sbill register int i; 453420Sbill caddr_t addr; 454420Sbill int reg, bit, byte, npf, mask, o; 455420Sbill int dn, bn, cn, tn, sn, ns, nt; 456106Sbill extern char buffers[NBUF][BSIZE]; 457420Sbill struct pte mpte; 458914Sbill int bcr; 45921Sbill 460420Sbill /* 461420Sbill * Npf is the number of sectors transferred before the sector 462420Sbill * containing the ECC error, and reg is the MBA register 463420Sbill * mapping (the first part of)the transfer. 464420Sbill * O is offset within a memory page of the first byte transferred. 465420Sbill */ 466914Sbill bcr = mbp->mba_bcr & 0xffff; 467914Sbill if (bcr) 468914Sbill bcr |= 0xffff0000; /* sxt */ 469719Sbill npf = btop(bcr + bp->b_bcount) - 1; 4701413Sbill reg = npf; 471420Sbill o = (int)bp->b_un.b_addr & PGOFSET; 472420Sbill printf("%D ", bp->b_blkno + npf); 47321Sbill prdev("ECC", bp->b_dev); 47421Sbill mask = rp->hpec2&0xffff; 47521Sbill if (mask == 0) { 47621Sbill rp->hpof = FMT22; 477420Sbill return (0); 47821Sbill } 479420Sbill 480420Sbill /* 481420Sbill * Compute the byte and bit position of the error. 482420Sbill * The variable i is the byte offset in the transfer, 483420Sbill * the variable byte is the offset from a page boundary 484420Sbill * in main memory. 485420Sbill */ 486420Sbill i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 487719Sbill bit = i&07; 488420Sbill i = (i&~07)>>3; 489420Sbill byte = i + o; 490420Sbill /* 491420Sbill * Correct while possible bits remain of mask. Since mask 492420Sbill * contains 11 bits, we continue while the bit offset is > -11. 493420Sbill * Also watch out for end of this block and the end of the whole 494420Sbill * transfer. 495420Sbill */ 496420Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 497420Sbill mpte = mbp->mba_map[reg+btop(byte)]; 498420Sbill addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 499420Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 500420Sbill byte++; 501420Sbill i++; 502420Sbill bit -= 8; 50321Sbill } 504420Sbill hptab.b_active++; /* Either complete or continuing */ 505719Sbill if (bcr == 0) 506420Sbill return (0); 507420Sbill /* 508420Sbill * Have to continue the transfer... clear the drive, 509420Sbill * and compute the position where the transfer is to continue. 510420Sbill * We have completed npf+1 sectores of the transfer already; 511420Sbill * restart at offset o of next sector (i.e. in MBA register reg+1). 512420Sbill */ 513420Sbill rp->hpcs1 = DCLR|GO; 514420Sbill dn = dkunit(bp); 515420Sbill bn = dkblock(bp); 516886Sbill switch (hp_type[dn]) { 517886Sbill 518886Sbill case RM: 519886Sbill ns = NRMSECT; nt = NRMTRAC; break; 520886Sbill case RM5: 521886Sbill ns = NRMSECT; nt = NTRAC; break; 522886Sbill case RP: 523886Sbill ns = NSECT; nt = NTRAC; break; 524886Sbill default: 525886Sbill panic("hpecc"); 52621Sbill } 527420Sbill cn = bp->b_cylin; 528420Sbill sn = bn%(ns*nt) + npf + 1; 529420Sbill tn = sn/ns; 530420Sbill sn %= ns; 531420Sbill cn += tn/nt; 532420Sbill tn %= nt; 533420Sbill rp->hpdc = cn; 534420Sbill rp->hpda = (tn<<8) + sn; 535420Sbill mbp->mba_sr = -1; 536420Sbill mbp->mba_var = (int)ptob(reg+1) + o; 537420Sbill rp->hpcs1 = RCOM|GO; 538420Sbill return (1); 53921Sbill } 5401565Sbill #endif 541