1*3289Swnj /* hp.c 4.33 81/03/17 */ 2*3289Swnj 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 123093Swnj * see if DCLR and/or RELEASE set attention status 1321Sbill */ 1421Sbill 1521Sbill #include "../h/param.h" 1621Sbill #include "../h/systm.h" 17305Sbill #include "../h/dk.h" 1821Sbill #include "../h/buf.h" 1921Sbill #include "../h/conf.h" 2021Sbill #include "../h/dir.h" 2121Sbill #include "../h/user.h" 2221Sbill #include "../h/map.h" 23420Sbill #include "../h/pte.h" 242978Swnj #include "../h/mbareg.h" 252978Swnj #include "../h/mbavar.h" 2621Sbill #include "../h/mtpr.h" 27420Sbill #include "../h/vm.h" 282362Swnj #include "../h/cmap.h" 2921Sbill 302383Swnj #include "../h/hpreg.h" 3121Sbill 322383Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 332383Swnj struct size { 3421Sbill daddr_t nblocks; 3521Sbill int cyloff; 362383Swnj } hp_sizes[8] = { 37886Sbill 15884, 0, /* A=cyl 0 thru 37 */ 38886Sbill 33440, 38, /* B=cyl 38 thru 117 */ 39886Sbill 340670, 0, /* C=cyl 0 thru 814 */ 4021Sbill 0, 0, 4121Sbill 0, 0, 4221Sbill 0, 0, 43886Sbill 291346, 118, /* G=cyl 118 thru 814 */ 4421Sbill 0, 0, 4521Sbill }, rm_sizes[8] = { 46886Sbill 15884, 0, /* A=cyl 0 thru 99 */ 47886Sbill 33440, 100, /* B=cyl 100 thru 309 */ 48886Sbill 131680, 0, /* C=cyl 0 thru 822 */ 492362Swnj 2720, 291, 5021Sbill 0, 0, 5121Sbill 0, 0, 52886Sbill 82080, 310, /* G=cyl 310 thru 822 */ 5321Sbill 0, 0, 54886Sbill }, rm5_sizes[8] = { 55886Sbill 15884, 0, /* A=cyl 0 thru 26 */ 56886Sbill 33440, 27, /* B=cyl 27 thru 81 */ 573271Swnj 500384, 0, /* C=cyl 0 thru 822 */ 58886Sbill 15884, 562, /* D=cyl 562 thru 588 */ 59886Sbill 55936, 589, /* E=cyl 589 thru 680 */ 603271Swnj 86636, 681, /* F=cyl 681 thru 822 */ 613271Swnj 158688, 562, /* G=cyl 562 thru 822 */ 62886Sbill 291346, 82, /* H=cyl 82 thru 561 */ 632383Swnj }, rm80_sizes[8] = { 642383Swnj 15884, 0, /* A=cyl 0 thru 36 */ 652383Swnj 33440, 37, /* B=cyl 37 thru 114 */ 662383Swnj 242606, 0, /* C=cyl 0 thru 558 */ 672383Swnj 0, 0, 682383Swnj 0, 0, 692383Swnj 0, 0, 702383Swnj 82080, 115, /* G=cyl 115 thru 304 */ 712383Swnj 110236, 305, /* H=cyl 305 thru 558 */ 7221Sbill }; 732383Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 7421Sbill 752383Swnj #define _hpSDIST 2 762383Swnj #define _hpRDIST 3 772383Swnj 782383Swnj int hpSDIST = _hpSDIST; 792383Swnj int hpRDIST = _hpRDIST; 802383Swnj 812383Swnj short hptypes[] = 822383Swnj { MBDT_RM03, MBDT_RM05, MBDT_RP06, MBDT_RM80, 0 }; 832978Swnj struct mba_device *hpinfo[NHP]; 842978Swnj int hpattach(),hpustart(),hpstart(),hpdtint(); 852383Swnj struct mba_driver hpdriver = 862978Swnj { hpattach, 0, hpustart, hpstart, hpdtint, 0, 872978Swnj hptypes, "hp", 0, hpinfo }; 882383Swnj 892383Swnj struct hpst { 902383Swnj short nsect; 912383Swnj short ntrak; 922383Swnj short nspc; 932383Swnj short ncyl; 942383Swnj struct size *sizes; 952383Swnj } hpst[] = { 962383Swnj 32, 5, 32*5, 823, rm_sizes, /* RM03 */ 972383Swnj 32, 19, 32*19, 823, rm5_sizes, /* RM05 */ 982383Swnj 22, 19, 22*19, 815, hp_sizes, /* RP06 */ 992383Swnj 31, 14, 31*14, 559, rm80_sizes /* RM80 */ 1002383Swnj }; 1012383Swnj 1022624Swnj u_char hp_offset[16] = { 1033093Swnj HPOF_P400, HPOF_M400, HPOF_P400, HPOF_M400, 1043093Swnj HPOF_P800, HPOF_M800, HPOF_P800, HPOF_M800, 1053093Swnj HPOF_P1200, HPOF_M1200, HPOF_P1200, HPOF_M1200, 1063093Swnj 0, 0, 0, 0, 10721Sbill }; 10821Sbill 1092624Swnj struct buf rhpbuf[NHP]; 1102892Swnj char hprecal[NHP]; 11121Sbill 11221Sbill #define b_cylin b_resid 11321Sbill 11421Sbill #ifdef INTRLVE 11521Sbill daddr_t dkblock(); 11621Sbill #endif 11721Sbill 1182604Swnj int hpseek; 1192604Swnj 1202978Swnj /*ARGSUSED*/ 1212978Swnj hpattach(mi, slave) 1222978Swnj struct mba_device *mi; 1232604Swnj { 1242604Swnj register struct hpst *st = &hpst[mi->mi_type]; 1252604Swnj 1262604Swnj if (mi->mi_dk >= 0) 1272757Swnj dk_mspw[mi->mi_dk] = 1.0 / 60 / (st->nsect * 256); 1282604Swnj } 1292604Swnj 13021Sbill hpstrategy(bp) 1312383Swnj register struct buf *bp; 13221Sbill { 1332978Swnj register struct mba_device *mi; 1342383Swnj register struct hpst *st; 1352383Swnj register int unit; 13621Sbill long sz, bn; 1372383Swnj int xunit = minor(bp->b_dev) & 07; 13821Sbill 13921Sbill sz = bp->b_bcount; 14021Sbill sz = (sz+511) >> 9; 14121Sbill unit = dkunit(bp); 1422383Swnj if (unit >= NHP) 1432383Swnj goto bad; 1442383Swnj mi = hpinfo[unit]; 1452395Swnj if (mi == 0 || mi->mi_alive == 0) 1462383Swnj goto bad; 1472383Swnj st = &hpst[mi->mi_type]; 1482383Swnj if (bp->b_blkno < 0 || 1492383Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1502383Swnj goto bad; 1512383Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 152127Sbill (void) spl5(); 1532383Swnj disksort(&mi->mi_tab, bp); 1542383Swnj if (mi->mi_tab.b_active == 0) 1552383Swnj mbustart(mi); 156127Sbill (void) spl0(); 1572383Swnj return; 1582383Swnj 1592383Swnj bad: 1602383Swnj bp->b_flags |= B_ERROR; 1612383Swnj iodone(bp); 1622383Swnj return; 16321Sbill } 16421Sbill 1652383Swnj hpustart(mi) 1662978Swnj register struct mba_device *mi; 16721Sbill { 1682624Swnj register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 1692383Swnj register struct buf *bp = mi->mi_tab.b_actf; 1702383Swnj register struct hpst *st; 17121Sbill daddr_t bn; 1723102Swnj int sn, dist; 17321Sbill 1742624Swnj if ((hpaddr->hpcs1&HP_DVA) == 0) 1752383Swnj return (MBU_BUSY); 1763093Swnj if ((hpaddr->hpds & HPDS_VV) == 0) { 1772624Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 1783140Swnj if (mi->mi_mba->mba_drv[0].mbd_as & (1<<mi->mi_drive)) 1793140Swnj printf("DCLR attn\n"); 1802624Swnj hpaddr->hpcs1 = HP_PRESET|HP_GO; 1813093Swnj hpaddr->hpof = HPOF_FMT22; 1823140Swnj mbclrattn(mi); 18321Sbill } 1842604Swnj if (mi->mi_tab.b_active || mi->mi_hd->mh_ndrive == 1) 1852383Swnj return (MBU_DODATA); 1863093Swnj if ((hpaddr->hpds & HPDS_DREADY) != HPDS_DREADY) 1872383Swnj return (MBU_DODATA); 1882395Swnj st = &hpst[mi->mi_type]; 1892395Swnj bn = dkblock(bp); 1902395Swnj sn = bn%st->nspc; 1912395Swnj sn = (sn+st->nsect-hpSDIST)%st->nsect; 1922383Swnj if (bp->b_cylin == (hpaddr->hpdc & 0xffff)) { 1932604Swnj if (hpseek) 1942383Swnj return (MBU_DODATA); 1952383Swnj dist = ((hpaddr->hpla & 0xffff)>>6) - st->nsect + 1; 1962383Swnj if (dist < 0) 1972383Swnj dist += st->nsect; 1982383Swnj if (dist > st->nsect - hpRDIST) 1992383Swnj return (MBU_DODATA); 2002614Swnj } else 2012614Swnj hpaddr->hpdc = bp->b_cylin; 2022604Swnj if (hpseek) 2032624Swnj hpaddr->hpcs1 = HP_SEEK|HP_GO; 204305Sbill else { 205305Sbill hpaddr->hpda = sn; 2062624Swnj hpaddr->hpcs1 = HP_SEARCH|HP_GO; 207305Sbill } 2082383Swnj return (MBU_STARTED); 20921Sbill } 21021Sbill 2112383Swnj hpstart(mi) 2122978Swnj register struct mba_device *mi; 21321Sbill { 2142624Swnj register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 2152383Swnj register struct buf *bp = mi->mi_tab.b_actf; 2162383Swnj register struct hpst *st = &hpst[mi->mi_type]; 21721Sbill daddr_t bn; 2182383Swnj int sn, tn; 21921Sbill 22021Sbill bn = dkblock(bp); 2212383Swnj sn = bn%st->nspc; 2222383Swnj tn = sn/st->nsect; 2232395Swnj sn %= st->nsect; 2242383Swnj hpaddr->hpdc = bp->b_cylin; 22521Sbill hpaddr->hpda = (tn << 8) + sn; 22621Sbill } 22721Sbill 2283102Swnj hpdtint(mi, mbsr) 2292978Swnj register struct mba_device *mi; 2303102Swnj int mbsr; 23121Sbill { 2322624Swnj register struct hpdevice *hpaddr = (struct hpdevice *)mi->mi_drv; 2332383Swnj register struct buf *bp = mi->mi_tab.b_actf; 2342826Swnj int retry = 0; 23521Sbill 2363102Swnj if (hpaddr->hpds&HPDS_ERR || mbsr&MBSR_EBITS) { 237*3289Swnj if (hpdebug) { 238*3289Swnj printf("errcnt %d ", mi->mi_tab.b_errcnt); 239*3289Swnj printf("mbsr=%b ", mbsr, mbsr_bits); 240*3289Swnj printf("er1=%b er2=%b\n", 241*3289Swnj hpaddr->hper1, HPER1_BITS, 242*3289Swnj hpaddr->hper2, HPER2_BITS); 243*3289Swnj DELAY(1000000); 244*3289Swnj } 2453093Swnj if (hpaddr->hper1&HPER1_WLE) { 2462925Swnj printf("hp%d: write locked\n", dkunit(bp)); 2472826Swnj bp->b_flags |= B_ERROR; 2482826Swnj } else if (++mi->mi_tab.b_errcnt > 27 || 2493102Swnj mbsr & MBSR_HARD || 2502826Swnj hpaddr->hper1 & HPER1_HARD || 2512826Swnj hpaddr->hper2 & HPER2_HARD) { 2522925Swnj harderr(bp, "hp"); 2533271Swnj if (mbsr & (MBSR_EBITS &~ (MBSR_DTABT|MBSR_MBEXC))) 2543271Swnj printf("mbsr=%b ", mbsr, mbsr_bits); 2553271Swnj printf("er1=%b er2=%b\n", 2562826Swnj hpaddr->hper1, HPER1_BITS, 2572826Swnj hpaddr->hper2, HPER2_BITS); 2582826Swnj bp->b_flags |= B_ERROR; 2593143Swnj hprecal[mi->mi_unit] = 0; 2603143Swnj } else if (hptypes[mi->mi_type] == MBDT_RM80 && hpaddr->hper2&HPER2_SSE) { 2612883Swnj hpecc(mi, 1); 2622883Swnj return (MBD_RESTARTED); 2633093Swnj } else if ((hpaddr->hper1&(HPER1_DCK|HPER1_ECH))==HPER1_DCK) { 2642883Swnj if (hpecc(mi, 0)) 2652383Swnj return (MBD_RESTARTED); 2662826Swnj /* else done */ 2672826Swnj } else 2682826Swnj retry = 1; 2692826Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 2702826Swnj if ((mi->mi_tab.b_errcnt&07) == 4) { 2712826Swnj hpaddr->hpcs1 = HP_RECAL|HP_GO; 2723093Swnj hprecal[mi->mi_unit] = 0; 2733093Swnj goto nextrecal; 27421Sbill } 2752826Swnj if (retry) 2762826Swnj return (MBD_RETRY); 2772826Swnj } 278*3289Swnj else 279*3289Swnj if (hpdebug && hprecal[mi->mi_unit]) { 280*3289Swnj printf("recal %d ", hprecal[mi->mi_unit]); 281*3289Swnj printf("errcnt %d\n", mi->mi_tab.b_errcnt); 282*3289Swnj printf("mbsr=%b ", mbsr, mbsr_bits); 283*3289Swnj printf("er1=%b er2=%b\n", 284*3289Swnj hpaddr->hper1, HPER1_BITS, 285*3289Swnj hpaddr->hper2, HPER2_BITS); 286*3289Swnj } 2873093Swnj switch (hprecal[mi->mi_unit]) { 2883093Swnj 2893093Swnj case 1: 2903093Swnj hpaddr->hpdc = bp->b_cylin; 2913093Swnj hpaddr->hpcs1 = HP_SEEK|HP_GO; 2923093Swnj goto nextrecal; 2933093Swnj case 2: 2943093Swnj if (mi->mi_tab.b_errcnt < 16 || 295*3289Swnj (bp->b_flags & B_READ) == 0) 2963093Swnj goto donerecal; 2973093Swnj hpaddr->hpof = hp_offset[mi->mi_tab.b_errcnt & 017]|HPOF_FMT22; 2983093Swnj hpaddr->hpcs1 = HP_OFFSET|HP_GO; 2993093Swnj goto nextrecal; 3003093Swnj nextrecal: 3013093Swnj hprecal[mi->mi_unit]++; 3023093Swnj return (MBD_RESTARTED); 3033093Swnj donerecal: 3043158Swnj case 3: 3052892Swnj hprecal[mi->mi_unit] = 0; 3062892Swnj return (MBD_RETRY); 3072892Swnj } 3082383Swnj bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff; 3092826Swnj if (mi->mi_tab.b_errcnt > 16) { 3103093Swnj /* 3113093Swnj * This is fast and occurs rarely; we don't 3123093Swnj * bother with interrupts. 3133093Swnj */ 3142624Swnj hpaddr->hpcs1 = HP_RTC|HP_GO; 3153093Swnj while (hpaddr->hpds & HPDS_PIP) 3162383Swnj ; 3172383Swnj mbclrattn(mi); 31821Sbill } 3192624Swnj hpaddr->hpcs1 = HP_RELEASE|HP_GO; 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; 4092883Swnj #ifdef notdef 4102883Swnj if (rp->hpof&SSEI) 4112883Swnj sn++; 4122883Swnj #endif 413420Sbill rp->hpdc = cn; 414420Sbill rp->hpda = (tn<<8) + sn; 415420Sbill mbp->mba_sr = -1; 416420Sbill mbp->mba_var = (int)ptob(reg+1) + o; 4172624Swnj rp->hpcs1 = HP_RCOM|HP_GO; 4182624Swnj #endif 419420Sbill return (1); 42021Sbill } 4212362Swnj 4222362Swnj #define DBSIZE 20 4232362Swnj 4242362Swnj hpdump(dev) 4252362Swnj dev_t dev; 4262362Swnj { 4272978Swnj register struct mba_device *mi; 4282383Swnj register struct mba_regs *mba; 4292624Swnj struct hpdevice *hpaddr; 4302362Swnj char *start; 4312383Swnj int num, unit; 4322383Swnj register struct hpst *st; 4332362Swnj 4342362Swnj num = maxfree; 4352362Swnj start = 0; 4362362Swnj unit = minor(dev) >> 3; 4372827Swnj if (unit >= NHP) 4382827Swnj return (ENXIO); 4392383Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 4402978Swnj mi = phys(hpinfo[unit],struct mba_device *); 4412827Swnj if (mi == 0 || mi->mi_alive == 0) 4422827Swnj return (ENXIO); 4432383Swnj mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 4443102Swnj mba->mba_cr = MBCR_INIT; 4452624Swnj hpaddr = (struct hpdevice *)&mba->mba_drv[mi->mi_drive]; 4463093Swnj if ((hpaddr->hpds & HPDS_VV) == 0) { 4472624Swnj hpaddr->hpcs1 = HP_DCLR|HP_GO; 4482624Swnj hpaddr->hpcs1 = HP_PRESET|HP_GO; 4493093Swnj hpaddr->hpof = HPOF_FMT22; 4502362Swnj } 4512383Swnj st = &hpst[mi->mi_type]; 4522827Swnj if (dumplo < 0 || dumplo + num >= st->sizes[minor(dev)&07].nblocks) 4532827Swnj return (EINVAL); 4542362Swnj while (num > 0) { 4552383Swnj register struct pte *hpte = mba->mba_map; 4562362Swnj register int i; 4572383Swnj int blk, cn, sn, tn; 4582362Swnj daddr_t bn; 4592362Swnj 4602362Swnj blk = num > DBSIZE ? DBSIZE : num; 4612362Swnj bn = dumplo + btop(start); 4622383Swnj cn = bn/st->nspc + st->sizes[minor(dev)&07].cyloff; 4632383Swnj sn = bn%st->nspc; 4642383Swnj tn = sn/st->nsect; 4652383Swnj sn = sn%st->nsect; 4662362Swnj hpaddr->hpdc = cn; 4672362Swnj hpaddr->hpda = (tn << 8) + sn; 4682362Swnj for (i = 0; i < blk; i++) 4692362Swnj *(int *)hpte++ = (btop(start)+i) | PG_V; 4702383Swnj mba->mba_sr = -1; 4712383Swnj mba->mba_bcr = -(blk*NBPG); 4722383Swnj mba->mba_var = 0; 4732624Swnj hpaddr->hpcs1 = HP_WCOM | HP_GO; 4743093Swnj while ((hpaddr->hpds & HPDS_DRY) == 0) 4752362Swnj ; 4763093Swnj if (hpaddr->hpds&HPDS_ERR) 4772827Swnj return (EIO); 4782362Swnj start += blk*NBPG; 4792362Swnj num -= blk; 4802362Swnj } 4812362Swnj return (0); 4822362Swnj } 4831565Sbill #endif 484