1*3271Swnj /* hp.c 4.32 81/03/16 */ 221Sbill 31939Swnj #include "hp.h" 41565Sbill #if NHP > 0 521Sbill /* 62624Swnj * HP disk driver for RP0x+RM0x 72827Swnj * 82827Swnj * TODO: 93093Swnj * check RM80 skip sector handling, esp when ECC's occur later 103093Swnj * check offset recovery handling 113093Swnj * see if DCLR and/or RELEASE set attention status 1221Sbill */ 1321Sbill 1421Sbill #include "../h/param.h" 1521Sbill #include "../h/systm.h" 16305Sbill #include "../h/dk.h" 1721Sbill #include "../h/buf.h" 1821Sbill #include "../h/conf.h" 1921Sbill #include "../h/dir.h" 2021Sbill #include "../h/user.h" 2121Sbill #include "../h/map.h" 22420Sbill #include "../h/pte.h" 232978Swnj #include "../h/mbareg.h" 242978Swnj #include "../h/mbavar.h" 2521Sbill #include "../h/mtpr.h" 26420Sbill #include "../h/vm.h" 272362Swnj #include "../h/cmap.h" 2821Sbill 292383Swnj #include "../h/hpreg.h" 3021Sbill 312383Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 322383Swnj struct size { 3321Sbill daddr_t nblocks; 3421Sbill int cyloff; 352383Swnj } hp_sizes[8] = { 36886Sbill 15884, 0, /* A=cyl 0 thru 37 */ 37886Sbill 33440, 38, /* B=cyl 38 thru 117 */ 38886Sbill 340670, 0, /* C=cyl 0 thru 814 */ 3921Sbill 0, 0, 4021Sbill 0, 0, 4121Sbill 0, 0, 42886Sbill 291346, 118, /* G=cyl 118 thru 814 */ 4321Sbill 0, 0, 4421Sbill }, rm_sizes[8] = { 45886Sbill 15884, 0, /* A=cyl 0 thru 99 */ 46886Sbill 33440, 100, /* B=cyl 100 thru 309 */ 47886Sbill 131680, 0, /* C=cyl 0 thru 822 */ 482362Swnj 2720, 291, 4921Sbill 0, 0, 5021Sbill 0, 0, 51886Sbill 82080, 310, /* G=cyl 310 thru 822 */ 5221Sbill 0, 0, 53886Sbill }, rm5_sizes[8] = { 54886Sbill 15884, 0, /* A=cyl 0 thru 26 */ 55886Sbill 33440, 27, /* B=cyl 27 thru 81 */ 56*3271Swnj 500384, 0, /* C=cyl 0 thru 822 */ 57886Sbill 15884, 562, /* D=cyl 562 thru 588 */ 58886Sbill 55936, 589, /* E=cyl 589 thru 680 */ 59*3271Swnj 86636, 681, /* F=cyl 681 thru 822 */ 60*3271Swnj 158688, 562, /* G=cyl 562 thru 822 */ 61886Sbill 291346, 82, /* H=cyl 82 thru 561 */ 622383Swnj }, rm80_sizes[8] = { 632383Swnj 15884, 0, /* A=cyl 0 thru 36 */ 642383Swnj 33440, 37, /* B=cyl 37 thru 114 */ 652383Swnj 242606, 0, /* C=cyl 0 thru 558 */ 662383Swnj 0, 0, 672383Swnj 0, 0, 682383Swnj 0, 0, 692383Swnj 82080, 115, /* G=cyl 115 thru 304 */ 702383Swnj 110236, 305, /* H=cyl 305 thru 558 */ 7121Sbill }; 722383Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 7321Sbill 742383Swnj #define _hpSDIST 2 752383Swnj #define _hpRDIST 3 762383Swnj 772383Swnj int hpSDIST = _hpSDIST; 782383Swnj int hpRDIST = _hpRDIST; 792383Swnj 802383Swnj short hptypes[] = 812383Swnj { MBDT_RM03, MBDT_RM05, MBDT_RP06, MBDT_RM80, 0 }; 822978Swnj struct mba_device *hpinfo[NHP]; 832978Swnj int hpattach(),hpustart(),hpstart(),hpdtint(); 842383Swnj struct mba_driver hpdriver = 852978Swnj { hpattach, 0, hpustart, hpstart, hpdtint, 0, 862978Swnj hptypes, "hp", 0, hpinfo }; 872383Swnj 882383Swnj struct hpst { 892383Swnj short nsect; 902383Swnj short ntrak; 912383Swnj short nspc; 922383Swnj short ncyl; 932383Swnj struct size *sizes; 942383Swnj } hpst[] = { 952383Swnj 32, 5, 32*5, 823, rm_sizes, /* RM03 */ 962383Swnj 32, 19, 32*19, 823, rm5_sizes, /* RM05 */ 972383Swnj 22, 19, 22*19, 815, hp_sizes, /* RP06 */ 982383Swnj 31, 14, 31*14, 559, rm80_sizes /* RM80 */ 992383Swnj }; 1002383Swnj 1012624Swnj u_char hp_offset[16] = { 1023093Swnj HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, 1033093Swnj HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, 1043093Swnj HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, 1053093Swnj 0, 0, 0, 0, 10621Sbill }; 10721Sbill 1082624Swnj struct buf rhpbuf[NHP]; 1092892Swnj char hprecal[NHP]; 11021Sbill 11121Sbill #define b_cylin b_resid 11221Sbill 11321Sbill #ifdef INTRLVE 11421Sbill daddr_t dkblock(); 11521Sbill #endif 11621Sbill 1172604Swnj int hpseek; 1182604Swnj 1192978Swnj /*ARGSUSED*/ 1202978Swnj hpattach(mi, slave) 1212978Swnj struct mba_device *mi; 1222604Swnj { 1232604Swnj register struct hpst *st = &hpst[mi->mi_type]; 1242604Swnj 1252604Swnj if (mi->mi_dk >= 0) 1262757Swnj dk_mspw[mi->mi_dk] = 1.0 / 60 / (st->nsect * 256); 1272604Swnj } 1282604Swnj 12921Sbill hpstrategy(bp) 1302383Swnj register struct buf *bp; 13121Sbill { 1322978Swnj register struct mba_device *mi; 1332383Swnj register struct hpst *st; 1342383Swnj register int unit; 13521Sbill long sz, bn; 1362383Swnj int xunit = minor(bp->b_dev) & 07; 13721Sbill 13821Sbill sz = bp->b_bcount; 13921Sbill sz = (sz+511) >> 9; 14021Sbill unit = dkunit(bp); 1412383Swnj if (unit >= NHP) 1422383Swnj goto bad; 1432383Swnj mi = hpinfo[unit]; 1442395Swnj if (mi == 0 || mi->mi_alive == 0) 1452383Swnj goto bad; 1462383Swnj st = &hpst[mi->mi_type]; 1472383Swnj if (bp->b_blkno < 0 || 1482383Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1492383Swnj goto bad; 1502383Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 151127Sbill (void) spl5(); 1522383Swnj disksort(&mi->mi_tab, bp); 1532383Swnj if (mi->mi_tab.b_active == 0) 1542383Swnj mbustart(mi); 155127Sbill (void) spl0(); 1562383Swnj return; 1572383Swnj 1582383Swnj bad: 1592383Swnj bp->b_flags |= B_ERROR; 1602383Swnj iodone(bp); 1612383Swnj return; 16221Sbill } 16321Sbill 1642383Swnj hpustart(mi) 1652978Swnj register struct mba_device *mi; 16621Sbill { 1672624Swnj register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 1682383Swnj register struct buf *bp = mi->mi_tab.b_actf; 1692383Swnj register struct hpst *st; 17021Sbill daddr_t bn; 1713102Swnj int sn, dist; 17221Sbill 1732624Swnj if ((hpaddr->hpcs1&HP_DVA) == 0) 1742383Swnj return (MBU_BUSY); 1753093Swnj if ((hpaddr->hpds & HPDS_VV) == 0) { 1762624Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 1773140Swnj if (mi->mi_mba->mba_drv[0].mbd_as & (1<<mi->mi_drive)) 1783140Swnj printf("DCLR attn\n"); 1792624Swnj hpaddr->hpcs1 = HP_PRESET|HP_GO; 1803093Swnj hpaddr->hpof = HPOF_FMT22; 1813140Swnj mbclrattn(mi); 18221Sbill } 1832604Swnj if (mi->mi_tab.b_active || mi->mi_hd->mh_ndrive == 1) 1842383Swnj return (MBU_DODATA); 1853093Swnj if ((hpaddr->hpds & HPDS_DREADY) != HPDS_DREADY) 1862383Swnj return (MBU_DODATA); 1872395Swnj st = &hpst[mi->mi_type]; 1882395Swnj bn = dkblock(bp); 1892395Swnj sn = bn%st->nspc; 1902395Swnj sn = (sn+st->nsect-hpSDIST)%st->nsect; 1912383Swnj if (bp->b_cylin == (hpaddr->hpdc & 0xffff)) { 1922604Swnj if (hpseek) 1932383Swnj return (MBU_DODATA); 1942383Swnj dist = ((hpaddr->hpla & 0xffff)>>6) - st->nsect + 1; 1952383Swnj if (dist < 0) 1962383Swnj dist += st->nsect; 1972383Swnj if (dist > st->nsect - hpRDIST) 1982383Swnj return (MBU_DODATA); 1992614Swnj } else 2002614Swnj hpaddr->hpdc = bp->b_cylin; 2012604Swnj if (hpseek) 2022624Swnj hpaddr->hpcs1 = HP_SEEK|HP_GO; 203305Sbill else { 204305Sbill hpaddr->hpda = sn; 2052624Swnj hpaddr->hpcs1 = HP_SEARCH|HP_GO; 206305Sbill } 2072383Swnj return (MBU_STARTED); 20821Sbill } 20921Sbill 2102383Swnj hpstart(mi) 2112978Swnj register struct mba_device *mi; 21221Sbill { 2132624Swnj register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 2142383Swnj register struct buf *bp = mi->mi_tab.b_actf; 2152383Swnj register struct hpst *st = &hpst[mi->mi_type]; 21621Sbill daddr_t bn; 2172383Swnj int sn, tn; 21821Sbill 21921Sbill bn = dkblock(bp); 2202383Swnj sn = bn%st->nspc; 2212383Swnj tn = sn/st->nsect; 2222395Swnj sn %= st->nsect; 2232383Swnj hpaddr->hpdc = bp->b_cylin; 22421Sbill hpaddr->hpda = (tn << 8) + sn; 22521Sbill } 22621Sbill 2273102Swnj hpdtint(mi, mbsr) 2282978Swnj register struct mba_device *mi; 2293102Swnj int mbsr; 23021Sbill { 2312624Swnj register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 2322383Swnj register struct buf *bp = mi->mi_tab.b_actf; 2332826Swnj int retry = 0; 23421Sbill 2353102Swnj if (hpaddr->hpds&HPDS_ERR || mbsr&MBSR_EBITS) { 2363093Swnj if (hpaddr->hper1&HPER1_WLE) { 2372925Swnj printf("hp%d: write locked\n", dkunit(bp)); 2382826Swnj bp->b_flags |= B_ERROR; 2392826Swnj } else if (++mi->mi_tab.b_errcnt > 27 || 2403102Swnj mbsr & MBSR_HARD || 2412826Swnj hpaddr->hper1 & HPER1_HARD || 2422826Swnj hpaddr->hper2 & HPER2_HARD) { 2432925Swnj harderr(bp, "hp"); 244*3271Swnj if (mbsr & (MBSR_EBITS &~ (MBSR_DTABT|MBSR_MBEXC))) 245*3271Swnj printf("mbsr=%b ", mbsr, mbsr_bits); 246*3271Swnj printf("er1=%b er2=%b\n", 2472826Swnj hpaddr->hper1, HPER1_BITS, 2482826Swnj hpaddr->hper2, HPER2_BITS); 2492826Swnj bp->b_flags |= B_ERROR; 2503143Swnj hprecal[mi->mi_unit] = 0; 2513143Swnj } else if (hptypes[mi->mi_type] == MBDT_RM80 && hpaddr->hper2&HPER2_SSE) { 2522883Swnj hpecc(mi, 1); 2532883Swnj return (MBD_RESTARTED); 2543093Swnj } else if ((hpaddr->hper1&(HPER1_DCK|HPER1_ECH))==HPER1_DCK) { 2552883Swnj if (hpecc(mi, 0)) 2562383Swnj return (MBD_RESTARTED); 2572826Swnj /* else done */ 2582826Swnj } else 2592826Swnj retry = 1; 2602826Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 2612826Swnj if ((mi->mi_tab.b_errcnt&07) == 4) { 2622826Swnj hpaddr->hpcs1 = HP_RECAL|HP_GO; 2633093Swnj hprecal[mi->mi_unit] = 0; 2643093Swnj goto nextrecal; 26521Sbill } 2662826Swnj if (retry) 2672826Swnj return (MBD_RETRY); 2682826Swnj } 2693093Swnj switch (hprecal[mi->mi_unit]) { 2703093Swnj 2713093Swnj case 1: 2723093Swnj hpaddr->hpdc = bp->b_cylin; 2733093Swnj hpaddr->hpcs1 = HP_SEEK|HP_GO; 2743093Swnj goto nextrecal; 2753093Swnj case 2: 2763093Swnj if (mi->mi_tab.b_errcnt < 16 || 2773093Swnj (bp->b_flags & B_READ) != 0) 2783093Swnj goto donerecal; 2793093Swnj hpaddr->hpof = hp_offset[mi->mi_tab.b_errcnt & 017]|HPOF_FMT22; 2803093Swnj hpaddr->hpcs1 = HP_OFFSET|HP_GO; 2813093Swnj goto nextrecal; 2823093Swnj nextrecal: 2833093Swnj hprecal[mi->mi_unit]++; 2843093Swnj return (MBD_RESTARTED); 2853093Swnj donerecal: 2863158Swnj case 3: 2872892Swnj hprecal[mi->mi_unit] = 0; 2882892Swnj return (MBD_RETRY); 2892892Swnj } 2902383Swnj bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff; 2912826Swnj if (mi->mi_tab.b_errcnt > 16) { 2923093Swnj /* 2933093Swnj * This is fast and occurs rarely; we don't 2943093Swnj * bother with interrupts. 2953093Swnj */ 2962624Swnj hpaddr->hpcs1 = HP_RTC|HP_GO; 2973093Swnj while (hpaddr->hpds & HPDS_PIP) 2982383Swnj ; 2992383Swnj mbclrattn(mi); 30021Sbill } 3012624Swnj hpaddr->hpcs1 = HP_RELEASE|HP_GO; 3023140Swnj if (mi->mi_mba->mba_drv[0].mbd_as & (1<<mi->mi_drive)) 3033140Swnj printf("REL attn\n"); 3043140Swnj mbclrattn(mi); 3052383Swnj return (MBD_DONE); 30621Sbill } 30721Sbill 30821Sbill hpread(dev) 3092624Swnj dev_t dev; 31021Sbill { 3112624Swnj register int unit = minor(dev) >> 3; 31221Sbill 3132624Swnj if (unit >= NHP) 3142624Swnj u.u_error = ENXIO; 3152624Swnj else 3162624Swnj physio(hpstrategy, &rhpbuf[unit], dev, B_READ, minphys); 31721Sbill } 31821Sbill 31921Sbill hpwrite(dev) 3202624Swnj dev_t dev; 32121Sbill { 3222624Swnj register int unit = minor(dev) >> 3; 32321Sbill 3242624Swnj if (unit >= NHP) 3252624Swnj u.u_error = ENXIO; 3262624Swnj else 3272624Swnj physio(hpstrategy, &rhpbuf[unit], dev, B_WRITE, minphys); 32821Sbill } 32921Sbill 3303102Swnj /*ARGSUSED*/ 3312883Swnj hpecc(mi, rm80sse) 3322978Swnj register struct mba_device *mi; 3332883Swnj int rm80sse; 33421Sbill { 3352383Swnj register struct mba_regs *mbp = mi->mi_mba; 3362624Swnj register struct hpdevice *rp = (struct hpdevice *)mi->mi_drv; 3372383Swnj register struct buf *bp = mi->mi_tab.b_actf; 3382383Swnj register struct hpst *st; 339420Sbill register int i; 340420Sbill caddr_t addr; 341420Sbill int reg, bit, byte, npf, mask, o; 3422383Swnj int bn, cn, tn, sn; 343420Sbill struct pte mpte; 344914Sbill int bcr; 34521Sbill 346914Sbill bcr = mbp->mba_bcr & 0xffff; 347914Sbill if (bcr) 348914Sbill bcr |= 0xffff0000; /* sxt */ 349719Sbill npf = btop(bcr + bp->b_bcount) - 1; 3501413Sbill reg = npf; 3512883Swnj if (rm80sse) { 3523093Swnj rp->hpof |= HPOF_SSEI; 3533102Swnj reg--; /* compensate in advance for reg+1 below */ 3542883Swnj goto sse; 3552883Swnj } 356420Sbill o = (int)bp->b_un.b_addr & PGOFSET; 3572942Swnj printf("hp%d%c: soft ecc sn%d\n", dkunit(bp), 3582826Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 35921Sbill mask = rp->hpec2&0xffff; 360420Sbill i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 361719Sbill bit = i&07; 362420Sbill i = (i&~07)>>3; 363420Sbill byte = i + o; 364420Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 365420Sbill mpte = mbp->mba_map[reg+btop(byte)]; 366420Sbill addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 367420Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 368420Sbill byte++; 369420Sbill i++; 370420Sbill bit -= 8; 37121Sbill } 372719Sbill if (bcr == 0) 373420Sbill return (0); 3742624Swnj #ifdef notdef 3752883Swnj sse: 3763093Swnj if (rpof&HPOF_SSEI) 3772883Swnj rp->hpda = rp->hpda + 1; 3782624Swnj rp->hper1 = 0; 3792624Swnj rp->hpcs1 = HP_RCOM|HP_GO; 3802624Swnj #else 3812883Swnj sse: 3822624Swnj rp->hpcs1 = HP_DCLR|HP_GO; 383420Sbill bn = dkblock(bp); 3842383Swnj st = &hpst[mi->mi_type]; 385420Sbill cn = bp->b_cylin; 3862383Swnj sn = bn%(st->nspc) + npf + 1; 3872383Swnj tn = sn/st->nsect; 3882383Swnj sn %= st->nsect; 3892383Swnj cn += tn/st->ntrak; 3902383Swnj tn %= st->ntrak; 3912883Swnj #ifdef notdef 3922883Swnj if (rp->hpof&SSEI) 3932883Swnj sn++; 3942883Swnj #endif 395420Sbill rp->hpdc = cn; 396420Sbill rp->hpda = (tn<<8) + sn; 397420Sbill mbp->mba_sr = -1; 398420Sbill mbp->mba_var = (int)ptob(reg+1) + o; 3992624Swnj rp->hpcs1 = HP_RCOM|HP_GO; 4002624Swnj #endif 401420Sbill return (1); 40221Sbill } 4032362Swnj 4042362Swnj #define DBSIZE 20 4052362Swnj 4062362Swnj hpdump(dev) 4072362Swnj dev_t dev; 4082362Swnj { 4092978Swnj register struct mba_device *mi; 4102383Swnj register struct mba_regs *mba; 4112624Swnj struct hpdevice *hpaddr; 4122362Swnj char *start; 4132383Swnj int num, unit; 4142383Swnj register struct hpst *st; 4152362Swnj 4162362Swnj num = maxfree; 4172362Swnj start = 0; 4182362Swnj unit = minor(dev) >> 3; 4192827Swnj if (unit >= NHP) 4202827Swnj return (ENXIO); 4212383Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 4222978Swnj mi = phys(hpinfo[unit],struct mba_device *); 4232827Swnj if (mi == 0 || mi->mi_alive == 0) 4242827Swnj return (ENXIO); 4252383Swnj mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 4263102Swnj mba->mba_cr = MBCR_INIT; 4272624Swnj hpaddr = (struct hpdevice *)&mba->mba_drv[mi->mi_drive]; 4283093Swnj if ((hpaddr->hpds & HPDS_VV) == 0) { 4292624Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 4302624Swnj hpaddr->hpcs1 = HP_PRESET|HP_GO; 4313093Swnj hpaddr->hpof = HPOF_FMT22; 4322362Swnj } 4332383Swnj st = &hpst[mi->mi_type]; 4342827Swnj if (dumplo < 0 || dumplo + num >= st->sizes[minor(dev)&07].nblocks) 4352827Swnj return (EINVAL); 4362362Swnj while (num > 0) { 4372383Swnj register struct pte *hpte = mba->mba_map; 4382362Swnj register int i; 4392383Swnj int blk, cn, sn, tn; 4402362Swnj daddr_t bn; 4412362Swnj 4422362Swnj blk = num > DBSIZE ? DBSIZE : num; 4432362Swnj bn = dumplo + btop(start); 4442383Swnj cn = bn/st->nspc + st->sizes[minor(dev)&07].cyloff; 4452383Swnj sn = bn%st->nspc; 4462383Swnj tn = sn/st->nsect; 4472383Swnj sn = sn%st->nsect; 4482362Swnj hpaddr->hpdc = cn; 4492362Swnj hpaddr->hpda = (tn << 8) + sn; 4502362Swnj for (i = 0; i < blk; i++) 4512362Swnj *(int *)hpte++ = (btop(start)+i) | PG_V; 4522383Swnj mba->mba_sr = -1; 4532383Swnj mba->mba_bcr = -(blk*NBPG); 4542383Swnj mba->mba_var = 0; 4552624Swnj hpaddr->hpcs1 = HP_WCOM | HP_GO; 4563093Swnj while ((hpaddr->hpds & HPDS_DRY) == 0) 4572362Swnj ; 4583093Swnj if (hpaddr->hpds&HPDS_ERR) 4592827Swnj return (EIO); 4602362Swnj start += blk*NBPG; 4612362Swnj num -= blk; 4622362Swnj } 4632362Swnj return (0); 4642362Swnj } 4651565Sbill #endif 466