1*3640Swnj /* hp.c 4.36 81/04/29 */ 23289Swnj int hpdebug; 321Sbill 41939Swnj #include "hp.h" 51565Sbill #if NHP > 0 621Sbill /* 72624Swnj * HP disk driver for RP0x+RM0x 82827Swnj * 92827Swnj * TODO: 103093Swnj * check RM80 skip sector handling, esp when ECC's occur later 113093Swnj * check offset recovery handling 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 */ 4821Sbill 0, 0, 4921Sbill 0, 0, 503442Sroot 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 */ 563271Swnj 500384, 0, /* C=cyl 0 thru 822 */ 57886Sbill 15884, 562, /* D=cyl 562 thru 588 */ 58886Sbill 55936, 589, /* E=cyl 589 thru 680 */ 593271Swnj 86636, 681, /* F=cyl 681 thru 822 */ 603271Swnj 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) { 2363289Swnj if (hpdebug) { 2373289Swnj printf("errcnt %d ", mi->mi_tab.b_errcnt); 2383289Swnj printf("mbsr=%b ", mbsr, mbsr_bits); 2393289Swnj printf("er1=%b er2=%b\n", 2403289Swnj hpaddr->hper1, HPER1_BITS, 2413289Swnj hpaddr->hper2, HPER2_BITS); 2423289Swnj DELAY(1000000); 2433289Swnj } 2443093Swnj if (hpaddr->hper1&HPER1_WLE) { 2452925Swnj printf("hp%d: write locked\n", dkunit(bp)); 2462826Swnj bp->b_flags |= B_ERROR; 2472826Swnj } else if (++mi->mi_tab.b_errcnt > 27 || 2483102Swnj mbsr & MBSR_HARD || 2492826Swnj hpaddr->hper1 & HPER1_HARD || 2502826Swnj hpaddr->hper2 & HPER2_HARD) { 2512925Swnj harderr(bp, "hp"); 2523271Swnj if (mbsr & (MBSR_EBITS &~ (MBSR_DTABT|MBSR_MBEXC))) 2533271Swnj printf("mbsr=%b ", mbsr, mbsr_bits); 2543271Swnj printf("er1=%b er2=%b\n", 2552826Swnj hpaddr->hper1, HPER1_BITS, 2562826Swnj hpaddr->hper2, HPER2_BITS); 2572826Swnj bp->b_flags |= B_ERROR; 2583143Swnj hprecal[mi->mi_unit] = 0; 2593143Swnj } else if (hptypes[mi->mi_type] == MBDT_RM80 && hpaddr->hper2&HPER2_SSE) { 2602883Swnj hpecc(mi, 1); 2612883Swnj return (MBD_RESTARTED); 2623093Swnj } else if ((hpaddr->hper1&(HPER1_DCK|HPER1_ECH))==HPER1_DCK) { 2632883Swnj if (hpecc(mi, 0)) 2642383Swnj return (MBD_RESTARTED); 2652826Swnj /* else done */ 2662826Swnj } else 2672826Swnj retry = 1; 2682826Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 2692826Swnj if ((mi->mi_tab.b_errcnt&07) == 4) { 2702826Swnj hpaddr->hpcs1 = HP_RECAL|HP_GO; 2713093Swnj hprecal[mi->mi_unit] = 0; 2723093Swnj goto nextrecal; 27321Sbill } 2742826Swnj if (retry) 2752826Swnj return (MBD_RETRY); 2762826Swnj } 2773289Swnj else 2783289Swnj if (hpdebug && hprecal[mi->mi_unit]) { 2793289Swnj printf("recal %d ", hprecal[mi->mi_unit]); 2803289Swnj printf("errcnt %d\n", mi->mi_tab.b_errcnt); 2813289Swnj printf("mbsr=%b ", mbsr, mbsr_bits); 2823289Swnj printf("er1=%b er2=%b\n", 2833289Swnj hpaddr->hper1, HPER1_BITS, 2843289Swnj hpaddr->hper2, HPER2_BITS); 2853289Swnj } 2863093Swnj switch (hprecal[mi->mi_unit]) { 2873093Swnj 2883093Swnj case 1: 2893093Swnj hpaddr->hpdc = bp->b_cylin; 2903093Swnj hpaddr->hpcs1 = HP_SEEK|HP_GO; 2913093Swnj goto nextrecal; 2923093Swnj case 2: 2933093Swnj if (mi->mi_tab.b_errcnt < 16 || 2943289Swnj (bp->b_flags & B_READ) == 0) 2953093Swnj goto donerecal; 2963093Swnj hpaddr->hpof = hp_offset[mi->mi_tab.b_errcnt & 017]|HPOF_FMT22; 2973093Swnj hpaddr->hpcs1 = HP_OFFSET|HP_GO; 2983093Swnj goto nextrecal; 2993093Swnj nextrecal: 3003093Swnj hprecal[mi->mi_unit]++; 3013093Swnj return (MBD_RESTARTED); 3023093Swnj donerecal: 3033158Swnj case 3: 3042892Swnj hprecal[mi->mi_unit] = 0; 3052892Swnj return (MBD_RETRY); 3062892Swnj } 3072383Swnj bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff; 308*3640Swnj if (mi->mi_tab.b_errcnt >= 16) { 3093093Swnj /* 3103093Swnj * This is fast and occurs rarely; we don't 3113093Swnj * bother with interrupts. 3123093Swnj */ 3132624Swnj hpaddr->hpcs1 = HP_RTC|HP_GO; 3143093Swnj while (hpaddr->hpds & HPDS_PIP) 3152383Swnj ; 3162383Swnj mbclrattn(mi); 31721Sbill } 3182624Swnj hpaddr->hpcs1 = HP_RELEASE|HP_GO; 3193350Swnj hpaddr->hpof = HPOF_FMT22; 3203140Swnj if (mi->mi_mba->mba_drv[0].mbd_as & (1<<mi->mi_drive)) 3213140Swnj printf("REL attn\n"); 3223140Swnj mbclrattn(mi); 3232383Swnj return (MBD_DONE); 32421Sbill } 32521Sbill 32621Sbill hpread(dev) 3272624Swnj dev_t dev; 32821Sbill { 3292624Swnj register int unit = minor(dev) >> 3; 33021Sbill 3312624Swnj if (unit >= NHP) 3322624Swnj u.u_error = ENXIO; 3332624Swnj else 3342624Swnj physio(hpstrategy, &rhpbuf[unit], dev, B_READ, minphys); 33521Sbill } 33621Sbill 33721Sbill hpwrite(dev) 3382624Swnj dev_t dev; 33921Sbill { 3402624Swnj register int unit = minor(dev) >> 3; 34121Sbill 3422624Swnj if (unit >= NHP) 3432624Swnj u.u_error = ENXIO; 3442624Swnj else 3452624Swnj physio(hpstrategy, &rhpbuf[unit], dev, B_WRITE, minphys); 34621Sbill } 34721Sbill 3483102Swnj /*ARGSUSED*/ 3492883Swnj hpecc(mi, rm80sse) 3502978Swnj register struct mba_device *mi; 3512883Swnj int rm80sse; 35221Sbill { 3532383Swnj register struct mba_regs *mbp = mi->mi_mba; 3542624Swnj register struct hpdevice *rp = (struct hpdevice *)mi->mi_drv; 3552383Swnj register struct buf *bp = mi->mi_tab.b_actf; 3562383Swnj register struct hpst *st; 357420Sbill register int i; 358420Sbill caddr_t addr; 359420Sbill int reg, bit, byte, npf, mask, o; 3602383Swnj int bn, cn, tn, sn; 361420Sbill struct pte mpte; 362914Sbill int bcr; 36321Sbill 364914Sbill bcr = mbp->mba_bcr & 0xffff; 365914Sbill if (bcr) 366914Sbill bcr |= 0xffff0000; /* sxt */ 367719Sbill npf = btop(bcr + bp->b_bcount) - 1; 3681413Sbill reg = npf; 3692883Swnj if (rm80sse) { 3703093Swnj rp->hpof |= HPOF_SSEI; 3713102Swnj reg--; /* compensate in advance for reg+1 below */ 3722883Swnj goto sse; 3732883Swnj } 374420Sbill o = (int)bp->b_un.b_addr & PGOFSET; 3752942Swnj printf("hp%d%c: soft ecc sn%d\n", dkunit(bp), 3762826Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 37721Sbill mask = rp->hpec2&0xffff; 378420Sbill i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 379719Sbill bit = i&07; 380420Sbill i = (i&~07)>>3; 381420Sbill byte = i + o; 382420Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 383420Sbill mpte = mbp->mba_map[reg+btop(byte)]; 384420Sbill addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 385420Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 386420Sbill byte++; 387420Sbill i++; 388420Sbill bit -= 8; 38921Sbill } 390719Sbill if (bcr == 0) 391420Sbill return (0); 3922624Swnj #ifdef notdef 3932883Swnj sse: 3943093Swnj if (rpof&HPOF_SSEI) 3952883Swnj rp->hpda = rp->hpda + 1; 3962624Swnj rp->hper1 = 0; 3972624Swnj rp->hpcs1 = HP_RCOM|HP_GO; 3982624Swnj #else 3992883Swnj sse: 4002624Swnj rp->hpcs1 = HP_DCLR|HP_GO; 401420Sbill bn = dkblock(bp); 4022383Swnj st = &hpst[mi->mi_type]; 403420Sbill cn = bp->b_cylin; 4042383Swnj sn = bn%(st->nspc) + npf + 1; 4052383Swnj tn = sn/st->nsect; 4062383Swnj sn %= st->nsect; 4072383Swnj cn += tn/st->ntrak; 4082383Swnj tn %= st->ntrak; 4093350Swnj if (rp->hpof&HPOF_SSEI) 4102883Swnj sn++; 411420Sbill rp->hpdc = cn; 412420Sbill rp->hpda = (tn<<8) + sn; 413420Sbill mbp->mba_sr = -1; 414420Sbill mbp->mba_var = (int)ptob(reg+1) + o; 4152624Swnj rp->hpcs1 = HP_RCOM|HP_GO; 4162624Swnj #endif 417420Sbill return (1); 41821Sbill } 4192362Swnj 4202362Swnj #define DBSIZE 20 4212362Swnj 4222362Swnj hpdump(dev) 4232362Swnj dev_t dev; 4242362Swnj { 4252978Swnj register struct mba_device *mi; 4262383Swnj register struct mba_regs *mba; 4272624Swnj struct hpdevice *hpaddr; 4282362Swnj char *start; 4292383Swnj int num, unit; 4302383Swnj register struct hpst *st; 4312362Swnj 4322362Swnj num = maxfree; 4332362Swnj start = 0; 4342362Swnj unit = minor(dev) >> 3; 4352827Swnj if (unit >= NHP) 4362827Swnj return (ENXIO); 4372383Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 4382978Swnj mi = phys(hpinfo[unit],struct mba_device *); 4392827Swnj if (mi == 0 || mi->mi_alive == 0) 4402827Swnj return (ENXIO); 4412383Swnj mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 4423102Swnj mba->mba_cr = MBCR_INIT; 4432624Swnj hpaddr = (struct hpdevice *)&mba->mba_drv[mi->mi_drive]; 4443093Swnj if ((hpaddr->hpds & HPDS_VV) == 0) { 4452624Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 4462624Swnj hpaddr->hpcs1 = HP_PRESET|HP_GO; 4473093Swnj hpaddr->hpof = HPOF_FMT22; 4482362Swnj } 4492383Swnj st = &hpst[mi->mi_type]; 4502827Swnj if (dumplo < 0 || dumplo + num >= st->sizes[minor(dev)&07].nblocks) 4512827Swnj return (EINVAL); 4522362Swnj while (num > 0) { 4532383Swnj register struct pte *hpte = mba->mba_map; 4542362Swnj register int i; 4552383Swnj int blk, cn, sn, tn; 4562362Swnj daddr_t bn; 4572362Swnj 4582362Swnj blk = num > DBSIZE ? DBSIZE : num; 4592362Swnj bn = dumplo + btop(start); 4602383Swnj cn = bn/st->nspc + st->sizes[minor(dev)&07].cyloff; 4612383Swnj sn = bn%st->nspc; 4622383Swnj tn = sn/st->nsect; 4632383Swnj sn = sn%st->nsect; 4642362Swnj hpaddr->hpdc = cn; 4652362Swnj hpaddr->hpda = (tn << 8) + sn; 4662362Swnj for (i = 0; i < blk; i++) 4672362Swnj *(int *)hpte++ = (btop(start)+i) | PG_V; 4682383Swnj mba->mba_sr = -1; 4692383Swnj mba->mba_bcr = -(blk*NBPG); 4702383Swnj mba->mba_var = 0; 4712624Swnj hpaddr->hpcs1 = HP_WCOM | HP_GO; 4723093Swnj while ((hpaddr->hpds & HPDS_DRY) == 0) 4732362Swnj ; 4743093Swnj if (hpaddr->hpds&HPDS_ERR) 4752827Swnj return (EIO); 4762362Swnj start += blk*NBPG; 4772362Swnj num -= blk; 4782362Swnj } 4792362Swnj return (0); 4802362Swnj } 4811565Sbill #endif 482