1*914Sbill /* hp.c 3.12 09/25/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; 16121Sbill 16221Sbill /* determine device type */ 163420Sbill hpaddr = mbadev(HPMBA, unit); 16421Sbill hp_type[unit] = hpaddr->hpdt; 16521Sbill } 166886Sbill switch (hp_type[unit]) { 167886Sbill 168886Sbill case RM: 16921Sbill sizes = rm_sizes; 17021Sbill nspc = NRMSECT*NRMTRAC; 171886Sbill break; 172886Sbill case RM5: 173886Sbill sizes = rm5_sizes; 174886Sbill nspc = NRMSECT*NTRAC; 175886Sbill break; 176886Sbill case RP: 17721Sbill sizes = hp_sizes; 17821Sbill nspc = NSECT*NTRAC; 179886Sbill break; 180886Sbill default: 181886Sbill printf("hp: unknown device type 0%o\n", hp_type[unit]); 182886Sbill u.u_error = ENXIO; 183886Sbill unit = NHP+1; /* force error */ 18421Sbill } 18521Sbill if (unit >= NHP || 18621Sbill bp->b_blkno < 0 || 18721Sbill (bn = dkblock(bp))+sz > sizes[xunit&07].nblocks) { 18821Sbill bp->b_flags |= B_ERROR; 18921Sbill iodone(bp); 19021Sbill return; 19121Sbill } 19221Sbill bp->b_cylin = bn/nspc + sizes[xunit&07].cyloff; 19321Sbill dp = &hputab[unit]; 194127Sbill (void) spl5(); 19521Sbill disksort(dp, bp); 19621Sbill if (dp->b_active == 0) { 19721Sbill hpustart(unit); 19821Sbill if(hptab.b_active == 0) 19921Sbill hpstart(); 20021Sbill } 201127Sbill (void) spl0(); 20221Sbill } 20321Sbill 20421Sbill hpustart(unit) 20521Sbill register unit; 20621Sbill { 20721Sbill register struct buf *bp, *dp; 20821Sbill register struct device *hpaddr; 20921Sbill daddr_t bn; 21021Sbill int sn, cn, csn; 21121Sbill 21221Sbill ((struct mba_regs *)MBA0)->mba_cr |= MBAIE; 213420Sbill hpaddr = mbadev(HPMBA, 0); 214420Sbill hpaddr->hpas = 1<<unit; 21521Sbill 21621Sbill if(unit >= NHP) 21721Sbill return; 218344Sbill if (unit+DK_N <= DK_NMAX) 219344Sbill dk_busy &= ~(1<<(unit+DK_N)); 22021Sbill dp = &hputab[unit]; 22121Sbill if((bp=dp->b_actf) == NULL) 22221Sbill return; 223420Sbill hpaddr = mbadev(HPMBA, unit); 22421Sbill if((hpaddr->hpds & VV) == 0) { 22521Sbill hpaddr->hpcs1 = PRESET|GO; 22621Sbill hpaddr->hpof = FMT22; 22721Sbill } 22821Sbill if(dp->b_active) 22921Sbill goto done; 23021Sbill dp->b_active++; 23121Sbill if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) 23221Sbill goto done; 23321Sbill 23421Sbill bn = dkblock(bp); 23521Sbill cn = bp->b_cylin; 236886Sbill switch (hp_type[unit]) { 237886Sbill 238886Sbill case RM: 23921Sbill sn = bn%(NRMSECT*NRMTRAC); 240305Sbill sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 241886Sbill break; 242886Sbill case RM5: 243886Sbill sn = bn%(NRMSECT*NTRAC); 244886Sbill sn = (sn+NRMSECT-hpSDIST)%NRMSECT; 245886Sbill break; 246886Sbill case RP: 24721Sbill sn = bn%(NSECT*NTRAC); 248305Sbill sn = (sn+NSECT-hpSDIST)%NSECT; 249886Sbill break; 250886Sbill default: 251886Sbill panic("hpustart"); 25221Sbill } 25321Sbill 25421Sbill if(cn - (hpaddr->hpdc & 0xffff)) 25521Sbill goto search; 256305Sbill else if (hpseek) 257305Sbill goto done; 258305Sbill csn = ((hpaddr->hpla & 0xffff)>>6) - sn + 1; 25921Sbill if(csn < 0) 26021Sbill csn += NSECT; 261305Sbill if(csn > NSECT-hpRDIST) 26221Sbill goto done; 26321Sbill 26421Sbill search: 26521Sbill hpaddr->hpdc = cn; 266305Sbill if (hpseek) 267305Sbill hpaddr->hpcs1 = SEEK|GO; 268305Sbill else { 269305Sbill hpaddr->hpda = sn; 270305Sbill hpaddr->hpcs1 = SEARCH|GO; 271305Sbill } 27221Sbill unit += DK_N; 273344Sbill if (unit <= DK_NMAX && DK_N+NHP <= DK_NMAX) { 274344Sbill dk_busy |= 1<<unit; 275344Sbill dk_numb[unit]++; 276344Sbill } 27721Sbill return; 27821Sbill 27921Sbill done: 28021Sbill dp->b_forw = NULL; 28121Sbill if(hptab.b_actf == NULL) 282344Sbill hptab.b_actf = dp; 283344Sbill else 28421Sbill hptab.b_actl->b_forw = dp; 28521Sbill hptab.b_actl = dp; 28621Sbill } 28721Sbill 28821Sbill hpstart() 28921Sbill { 29021Sbill register struct buf *bp, *dp; 29121Sbill register unit; 29221Sbill register struct device *hpaddr; 29321Sbill daddr_t bn; 29421Sbill int dn, sn, tn, cn, nspc, ns; 29521Sbill 29621Sbill loop: 29721Sbill if ((dp = hptab.b_actf) == NULL) 29821Sbill return; 29921Sbill if ((bp = dp->b_actf) == NULL) { 30021Sbill hptab.b_actf = dp->b_forw; 30121Sbill goto loop; 30221Sbill } 30321Sbill hptab.b_active++; 30421Sbill unit = minor(bp->b_dev) & 077; 30521Sbill dn = dkunit(bp); 30621Sbill bn = dkblock(bp); 307886Sbill switch (hp_type[dn]) { 308886Sbill case RM: 30921Sbill nspc = NRMSECT*NRMTRAC; 31021Sbill ns = NRMSECT; 31121Sbill cn = rm_sizes[unit&07].cyloff; 312886Sbill break; 313886Sbill case RM5: 314886Sbill nspc = NRMSECT*NTRAC; 315886Sbill ns = NRMSECT; 316886Sbill cn = rm5_sizes[unit&07].cyloff; 317886Sbill break; 318886Sbill case RP: 31921Sbill nspc = NSECT*NTRAC; 32021Sbill ns = NSECT; 32121Sbill cn = hp_sizes[unit&07].cyloff; 322886Sbill break; 323886Sbill default: 324886Sbill panic("hpstart"); 32521Sbill } 32621Sbill cn += bn/nspc; 32721Sbill sn = bn%nspc; 32821Sbill tn = sn/ns; 32921Sbill sn = sn%ns; 33021Sbill 331420Sbill hpaddr = mbadev(HPMBA, dn); 33221Sbill if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) { 33321Sbill hptab.b_active = 0; 33421Sbill hptab.b_errcnt = 0; 33521Sbill dp->b_actf = bp->av_forw; 33621Sbill bp->b_flags |= B_ERROR; 33721Sbill iodone(bp); 33821Sbill goto loop; 33921Sbill } 34021Sbill if(hptab.b_errcnt >= 16) { 34121Sbill hpaddr->hpof = hp_offset[hptab.b_errcnt & 017] | FMT22; 342420Sbill HPMBA->mba_cr &= ~MBAIE; 34321Sbill hpaddr->hpcs1 = OFFSET|GO; 34421Sbill while(hpaddr->hpds & PIP) 34521Sbill ; 346420Sbill HPMBA->mba_cr |= MBAIE; 34721Sbill } 34821Sbill hpaddr->hpdc = cn; 34921Sbill hpaddr->hpda = (tn << 8) + sn; 35021Sbill mbastart(bp, (int *)hpaddr); 35121Sbill 352344Sbill unit = dn+DK_N; 353344Sbill if (NHP+DK_N == DK_NMAX) 354344Sbill unit = NHP+DK_N; 355344Sbill if (unit <= DK_NMAX) { 356344Sbill dk_busy |= 1<<unit; 357344Sbill dk_numb[unit]++; 358344Sbill dk_wds[unit] += bp->b_bcount>>6; 359344Sbill } 36021Sbill } 36121Sbill 36221Sbill hpintr(mbastat, as) 36321Sbill { 36421Sbill register struct buf *bp, *dp; 36521Sbill register unit; 36621Sbill register struct device *hpaddr; 36721Sbill 36821Sbill if(hptab.b_active) { 36921Sbill dp = hptab.b_actf; 37021Sbill bp = dp->b_actf; 37121Sbill unit = dkunit(bp); 372344Sbill if (DK_N+NHP == DK_NMAX) 373344Sbill dk_busy &= ~(1<<(DK_N+NHP)); 374344Sbill else if (DK_N+unit <= DK_NMAX) 375344Sbill dk_busy &= ~(1<<(DK_N+unit)); 376420Sbill hpaddr = mbadev(HPMBA, unit); 377420Sbill if (hpaddr->hpds & ERR || mbastat & MBAEBITS) { 37821Sbill while((hpaddr->hpds & DRY) == 0) 37921Sbill ; 38021Sbill if(++hptab.b_errcnt > 28 || hpaddr->hper1&WLE) 381420Sbill bp->b_flags |= B_ERROR; 382420Sbill else 38321Sbill hptab.b_active = 0; 38421Sbill if(hptab.b_errcnt > 27) 38521Sbill deverror(bp, mbastat, hpaddr->hper1); 38621Sbill if ((hpaddr->hper1&0xffff) == DCK) { 38721Sbill if (hpecc(hpaddr, bp)) 38821Sbill return; 38921Sbill } 39021Sbill hpaddr->hpcs1 = DCLR|GO; 39121Sbill if((hptab.b_errcnt&07) == 4) { 392420Sbill HPMBA->mba_cr &= ~MBAIE; 39321Sbill hpaddr->hpcs1 = RECAL|GO; 39421Sbill while(hpaddr->hpds & PIP) 39521Sbill ; 396420Sbill HPMBA->mba_cr |= MBAIE; 39721Sbill } 39821Sbill } 39921Sbill if(hptab.b_active) { 40021Sbill if(hptab.b_errcnt) { 401420Sbill HPMBA->mba_cr &= ~MBAIE; 40221Sbill hpaddr->hpcs1 = RTC|GO; 40321Sbill while(hpaddr->hpds & PIP) 40421Sbill ; 405420Sbill HPMBA->mba_cr |= MBAIE; 40621Sbill } 40721Sbill hptab.b_active = 0; 40821Sbill hptab.b_errcnt = 0; 40921Sbill hptab.b_actf = dp->b_forw; 41021Sbill dp->b_active = 0; 41121Sbill dp->b_errcnt = 0; 41221Sbill dp->b_actf = bp->av_forw; 413420Sbill bp->b_resid = -HPMBA->mba_bcr & 0xffff; 41421Sbill iodone(bp); 41521Sbill if(dp->b_actf) 41621Sbill hpustart(unit); 41721Sbill } 41821Sbill as &= ~(1<<unit); 41921Sbill } else { 42021Sbill if(as == 0) 421420Sbill HPMBA->mba_cr |= MBAIE; 42221Sbill } 42321Sbill for(unit=0; unit<NHP; unit++) 42421Sbill if(as & (1<<unit)) 42521Sbill hpustart(unit); 42621Sbill hpstart(); 42721Sbill } 42821Sbill 42921Sbill hpread(dev) 43021Sbill { 43121Sbill 43221Sbill physio(hpstrategy, &rhpbuf, dev, B_READ, minphys); 43321Sbill } 43421Sbill 43521Sbill hpwrite(dev) 43621Sbill { 43721Sbill 43821Sbill physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys); 43921Sbill } 44021Sbill 44121Sbill hpecc(rp, bp) 44221Sbill register struct device *rp; 44321Sbill register struct buf *bp; 44421Sbill { 445420Sbill struct mba_regs *mbp = HPMBA; 446420Sbill register int i; 447420Sbill caddr_t addr; 448420Sbill int reg, bit, byte, npf, mask, o; 449420Sbill int dn, bn, cn, tn, sn, ns, nt; 450106Sbill extern char buffers[NBUF][BSIZE]; 451420Sbill struct pte mpte; 452*914Sbill int bcr; 45321Sbill 454420Sbill /* 455420Sbill * Npf is the number of sectors transferred before the sector 456420Sbill * containing the ECC error, and reg is the MBA register 457420Sbill * mapping (the first part of)the transfer. 458420Sbill * O is offset within a memory page of the first byte transferred. 459420Sbill */ 460*914Sbill bcr = mbp->mba_bcr & 0xffff; 461*914Sbill if (bcr) 462*914Sbill bcr |= 0xffff0000; /* sxt */ 463719Sbill npf = btop(bcr + bp->b_bcount) - 1; 464719Sbill printf("bcr %d npf %d\n", bcr, npf); 465420Sbill if (bp->b_flags&B_PHYS) 466420Sbill reg = 128 + npf; 467420Sbill else 468420Sbill reg = btop(bp->b_un.b_addr - buffers[0]) + npf; 469420Sbill o = (int)bp->b_un.b_addr & PGOFSET; 470420Sbill printf("%D ", bp->b_blkno + npf); 47121Sbill prdev("ECC", bp->b_dev); 47221Sbill mask = rp->hpec2&0xffff; 47321Sbill if (mask == 0) { 47421Sbill rp->hpof = FMT22; 475420Sbill return (0); 47621Sbill } 477420Sbill 478420Sbill /* 479420Sbill * Compute the byte and bit position of the error. 480420Sbill * The variable i is the byte offset in the transfer, 481420Sbill * the variable byte is the offset from a page boundary 482420Sbill * in main memory. 483420Sbill */ 484420Sbill i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 485719Sbill bit = i&07; 486420Sbill i = (i&~07)>>3; 487420Sbill byte = i + o; 488420Sbill /* 489420Sbill * Correct while possible bits remain of mask. Since mask 490420Sbill * contains 11 bits, we continue while the bit offset is > -11. 491420Sbill * Also watch out for end of this block and the end of the whole 492420Sbill * transfer. 493420Sbill */ 494420Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 495420Sbill mpte = mbp->mba_map[reg+btop(byte)]; 496420Sbill addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 497420Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 498420Sbill byte++; 499420Sbill i++; 500420Sbill bit -= 8; 50121Sbill } 502420Sbill hptab.b_active++; /* Either complete or continuing */ 503719Sbill if (bcr == 0) 504420Sbill return (0); 505420Sbill /* 506420Sbill * Have to continue the transfer... clear the drive, 507420Sbill * and compute the position where the transfer is to continue. 508420Sbill * We have completed npf+1 sectores of the transfer already; 509420Sbill * restart at offset o of next sector (i.e. in MBA register reg+1). 510420Sbill */ 511420Sbill rp->hpcs1 = DCLR|GO; 512420Sbill dn = dkunit(bp); 513420Sbill bn = dkblock(bp); 514886Sbill switch (hp_type[dn]) { 515886Sbill 516886Sbill case RM: 517886Sbill ns = NRMSECT; nt = NRMTRAC; break; 518886Sbill case RM5: 519886Sbill ns = NRMSECT; nt = NTRAC; break; 520886Sbill case RP: 521886Sbill ns = NSECT; nt = NTRAC; break; 522886Sbill default: 523886Sbill panic("hpecc"); 52421Sbill } 525420Sbill cn = bp->b_cylin; 526420Sbill sn = bn%(ns*nt) + npf + 1; 527420Sbill tn = sn/ns; 528420Sbill sn %= ns; 529420Sbill cn += tn/nt; 530420Sbill tn %= nt; 531420Sbill rp->hpdc = cn; 532420Sbill rp->hpda = (tn<<8) + sn; 533420Sbill mbp->mba_sr = -1; 534420Sbill mbp->mba_var = (int)ptob(reg+1) + o; 535420Sbill rp->hpcs1 = RCOM|GO; 536420Sbill return (1); 53721Sbill } 538