1*2604Swnj /* hp.c 4.10 81/02/21 */ 221Sbill 31939Swnj #include "hp.h" 41565Sbill #if NHP > 0 521Sbill /* 62383Swnj * RP/RM 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" 212362Swnj #include "../h/cmap.h" 2221Sbill 232383Swnj #include "../h/hpreg.h" 2421Sbill 252383Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 262383Swnj struct size { 2721Sbill daddr_t nblocks; 2821Sbill int cyloff; 292383Swnj } hp_sizes[8] = { 30886Sbill 15884, 0, /* A=cyl 0 thru 37 */ 31886Sbill 33440, 38, /* B=cyl 38 thru 117 */ 32886Sbill 340670, 0, /* C=cyl 0 thru 814 */ 3321Sbill 0, 0, 3421Sbill 0, 0, 3521Sbill 0, 0, 36886Sbill 291346, 118, /* G=cyl 118 thru 814 */ 3721Sbill 0, 0, 3821Sbill }, rm_sizes[8] = { 39886Sbill 15884, 0, /* A=cyl 0 thru 99 */ 40886Sbill 33440, 100, /* B=cyl 100 thru 309 */ 41886Sbill 131680, 0, /* C=cyl 0 thru 822 */ 422362Swnj 2720, 291, 4321Sbill 0, 0, 4421Sbill 0, 0, 45886Sbill 82080, 310, /* G=cyl 310 thru 822 */ 4621Sbill 0, 0, 47886Sbill }, rm5_sizes[8] = { 48886Sbill 15884, 0, /* A=cyl 0 thru 26 */ 49886Sbill 33440, 27, /* B=cyl 27 thru 81 */ 50886Sbill 500992, 0, /* C=cyl 0 thru 823 */ 51886Sbill 15884, 562, /* D=cyl 562 thru 588 */ 52886Sbill 55936, 589, /* E=cyl 589 thru 680 */ 53886Sbill 86944, 681, /* F=cyl 681 thru 823 */ 54886Sbill 159296, 562, /* G=cyl 562 thru 823 */ 55886Sbill 291346, 82, /* H=cyl 82 thru 561 */ 562383Swnj }, rm80_sizes[8] = { 572383Swnj 15884, 0, /* A=cyl 0 thru 36 */ 582383Swnj 33440, 37, /* B=cyl 37 thru 114 */ 592383Swnj 242606, 0, /* C=cyl 0 thru 558 */ 602383Swnj 0, 0, 612383Swnj 0, 0, 622383Swnj 0, 0, 632383Swnj 82080, 115, /* G=cyl 115 thru 304 */ 642383Swnj 110236, 305, /* H=cyl 305 thru 558 */ 6521Sbill }; 662383Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 6721Sbill 682383Swnj #define _hpSDIST 2 692383Swnj #define _hpRDIST 3 702383Swnj 712383Swnj int hpSDIST = _hpSDIST; 722383Swnj int hpRDIST = _hpRDIST; 732383Swnj 742383Swnj short hptypes[] = 752383Swnj { MBDT_RM03, MBDT_RM05, MBDT_RP06, MBDT_RM80, 0 }; 762383Swnj struct mba_info *hpinfo[NHP]; 772383Swnj int hpdkinit(),hpustart(),hpstart(),hpdtint(); 782383Swnj struct mba_driver hpdriver = 792383Swnj { hpdkinit, hpustart, hpstart, hpdtint, 0, hptypes, hpinfo }; 802383Swnj 812383Swnj struct hpst { 822383Swnj short nsect; 832383Swnj short ntrak; 842383Swnj short nspc; 852383Swnj short ncyl; 862383Swnj struct size *sizes; 872383Swnj } hpst[] = { 882383Swnj 32, 5, 32*5, 823, rm_sizes, /* RM03 */ 892383Swnj 32, 19, 32*19, 823, rm5_sizes, /* RM05 */ 902383Swnj 22, 19, 22*19, 815, hp_sizes, /* RP06 */ 912383Swnj 31, 14, 31*14, 559, rm80_sizes /* RM80 */ 922383Swnj }; 932383Swnj 942383Swnj int hp_offset[16] = { 9521Sbill P400, M400, P400, M400, 9621Sbill P800, M800, P800, M800, 9721Sbill P1200, M1200, P1200, M1200, 9821Sbill 0, 0, 0, 0, 9921Sbill }; 10021Sbill 10121Sbill struct buf rhpbuf; 10221Sbill 10321Sbill #define b_cylin b_resid 10421Sbill 10521Sbill #ifdef INTRLVE 10621Sbill daddr_t dkblock(); 10721Sbill #endif 10821Sbill 109*2604Swnj int hpseek; 110*2604Swnj 111*2604Swnj hpdkinit(mi) 112*2604Swnj struct mba_info *mi; 113*2604Swnj { 114*2604Swnj register struct hpst *st = &hpst[mi->mi_type]; 115*2604Swnj 116*2604Swnj if (mi->mi_dk >= 0) 117*2604Swnj dk_mspw[mi->mi_dk] = 1.0 / HZ / (st->nsect * 256); 118*2604Swnj } 119*2604Swnj 12021Sbill hpstrategy(bp) 1212383Swnj register struct buf *bp; 12221Sbill { 1232383Swnj register struct mba_info *mi; 1242383Swnj register struct hpst *st; 1252383Swnj register int unit; 12621Sbill long sz, bn; 1272383Swnj int xunit = minor(bp->b_dev) & 07; 12821Sbill 12921Sbill sz = bp->b_bcount; 13021Sbill sz = (sz+511) >> 9; 13121Sbill unit = dkunit(bp); 1322383Swnj if (unit >= NHP) 1332383Swnj goto bad; 1342383Swnj mi = hpinfo[unit]; 1352395Swnj if (mi == 0 || mi->mi_alive == 0) 1362383Swnj goto bad; 1372383Swnj st = &hpst[mi->mi_type]; 1382383Swnj if (bp->b_blkno < 0 || 1392383Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1402383Swnj goto bad; 1412383Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 142127Sbill (void) spl5(); 1432383Swnj disksort(&mi->mi_tab, bp); 1442383Swnj if (mi->mi_tab.b_active == 0) 1452383Swnj mbustart(mi); 146127Sbill (void) spl0(); 1472383Swnj return; 1482383Swnj 1492383Swnj bad: 1502383Swnj bp->b_flags |= B_ERROR; 1512383Swnj iodone(bp); 1522383Swnj return; 15321Sbill } 15421Sbill 1552383Swnj hpustart(mi) 1562383Swnj register struct mba_info *mi; 15721Sbill { 1582383Swnj register struct device *hpaddr = (struct device *)mi->mi_drv; 1592383Swnj register struct buf *bp = mi->mi_tab.b_actf; 1602383Swnj register struct hpst *st; 16121Sbill daddr_t bn; 1622383Swnj int sn, dist, flags; 16321Sbill 1642383Swnj if ((hpaddr->hpcs1&DVA) == 0) 1652383Swnj return (MBU_BUSY); 1662383Swnj if ((hpaddr->hpds & VV) == 0) { 1672298Skre hpaddr->hpcs1 = DCLR|GO; 16821Sbill hpaddr->hpcs1 = PRESET|GO; 16921Sbill hpaddr->hpof = FMT22; 17021Sbill } 171*2604Swnj if (mi->mi_tab.b_active || mi->mi_hd->mh_ndrive == 1) 1722383Swnj return (MBU_DODATA); 17321Sbill if ((hpaddr->hpds & (DPR|MOL)) != (DPR|MOL)) 1742383Swnj return (MBU_DODATA); 1752383Swnj hpaddr->hpdc = bp->b_cylin; 1762395Swnj st = &hpst[mi->mi_type]; 1772395Swnj bn = dkblock(bp); 1782395Swnj sn = bn%st->nspc; 1792395Swnj sn = (sn+st->nsect-hpSDIST)%st->nsect; 1802383Swnj if (bp->b_cylin == (hpaddr->hpdc & 0xffff)) { 181*2604Swnj if (hpseek) 1822383Swnj return (MBU_DODATA); 1832383Swnj dist = ((hpaddr->hpla & 0xffff)>>6) - st->nsect + 1; 1842383Swnj if (dist < 0) 1852383Swnj dist += st->nsect; 1862383Swnj if (dist > st->nsect - hpRDIST) 1872383Swnj return (MBU_DODATA); 18821Sbill } 189*2604Swnj if (hpseek) 190305Sbill hpaddr->hpcs1 = SEEK|GO; 191305Sbill else { 192305Sbill hpaddr->hpda = sn; 193305Sbill hpaddr->hpcs1 = SEARCH|GO; 194305Sbill } 1952383Swnj return (MBU_STARTED); 19621Sbill } 19721Sbill 1982383Swnj hpstart(mi) 1992383Swnj register struct mba_info *mi; 20021Sbill { 2012383Swnj register struct device *hpaddr = (struct device *)mi->mi_drv; 2022383Swnj register struct buf *bp = mi->mi_tab.b_actf; 2032383Swnj register struct hpst *st = &hpst[mi->mi_type]; 20421Sbill daddr_t bn; 2052383Swnj int sn, tn; 20621Sbill 20721Sbill bn = dkblock(bp); 2082383Swnj sn = bn%st->nspc; 2092383Swnj tn = sn/st->nsect; 2102395Swnj sn %= st->nsect; 2112383Swnj if (mi->mi_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 2122383Swnj hpaddr->hpof = hp_offset[mi->mi_tab.b_errcnt & 017] | FMT22; 21321Sbill hpaddr->hpcs1 = OFFSET|GO; 2142383Swnj while (hpaddr->hpds & PIP) 21521Sbill ; 2162383Swnj mbclrattn(mi); 21721Sbill } 2182383Swnj hpaddr->hpdc = bp->b_cylin; 21921Sbill hpaddr->hpda = (tn << 8) + sn; 22021Sbill } 22121Sbill 2222383Swnj hpdtint(mi, mbastat) 2232383Swnj register struct mba_info *mi; 2242383Swnj int mbastat; 22521Sbill { 2262383Swnj register struct device *hpaddr = (struct device *)mi->mi_drv; 2272383Swnj register struct buf *bp = mi->mi_tab.b_actf; 22821Sbill 2292383Swnj while ((hpaddr->hpds & DRY) == 0) /* shouldn't happen */ 2302383Swnj printf("hp dry not set\n"); 2312383Swnj if (hpaddr->hpds & ERR || mbastat & MBAEBITS) 2322383Swnj if (++mi->mi_tab.b_errcnt < 28 && (hpaddr->hper1&WLE) == 0) { 2332383Swnj if ((hpaddr->hper1&0xffff) != DCK) { 2342383Swnj hpaddr->hpcs1 = DCLR|GO; 2352383Swnj if ((mi->mi_tab.b_errcnt&07) == 4) { 2362383Swnj hpaddr->hpcs1 = RECAL|GO; 2372383Swnj while (hpaddr->hpds & PIP) 2382383Swnj ; 2392383Swnj mbclrattn(mi); 2402383Swnj } 2412383Swnj return (MBD_RETRY); 2422383Swnj } else if (hpecc(mi)) 2432383Swnj return (MBD_RESTARTED); 2442383Swnj } else { 2452383Swnj deverror(bp, mbastat, hpaddr->hper1); 2462383Swnj bp->b_flags |= B_ERROR; 24721Sbill } 2482383Swnj bp->b_resid = -(mi->mi_mba->mba_bcr) & 0xffff; 2492383Swnj if (mi->mi_tab.b_errcnt) { 2502383Swnj hpaddr->hpcs1 = RTC|GO; 2512383Swnj while (hpaddr->hpds & PIP) 2522383Swnj ; 2532383Swnj mbclrattn(mi); 25421Sbill } 2552383Swnj hpaddr->hpcs1 = RELEASE|GO; 2562383Swnj return (MBD_DONE); 25721Sbill } 25821Sbill 25921Sbill hpread(dev) 26021Sbill { 26121Sbill 26221Sbill physio(hpstrategy, &rhpbuf, dev, B_READ, minphys); 26321Sbill } 26421Sbill 26521Sbill hpwrite(dev) 26621Sbill { 26721Sbill 26821Sbill physio(hpstrategy, &rhpbuf, dev, B_WRITE, minphys); 26921Sbill } 27021Sbill 2712383Swnj hpecc(mi) 2722383Swnj register struct mba_info *mi; 27321Sbill { 2742383Swnj register struct mba_regs *mbp = mi->mi_mba; 2752383Swnj register struct device *rp = (struct device *)mi->mi_drv; 2762383Swnj register struct buf *bp = mi->mi_tab.b_actf; 2772383Swnj register struct hpst *st; 278420Sbill register int i; 279420Sbill caddr_t addr; 280420Sbill int reg, bit, byte, npf, mask, o; 2812383Swnj int bn, cn, tn, sn; 282420Sbill struct pte mpte; 283914Sbill int bcr; 28421Sbill 285420Sbill /* 286420Sbill * Npf is the number of sectors transferred before the sector 287420Sbill * containing the ECC error, and reg is the MBA register 288420Sbill * mapping (the first part of)the transfer. 289420Sbill * O is offset within a memory page of the first byte transferred. 290420Sbill */ 291914Sbill bcr = mbp->mba_bcr & 0xffff; 292914Sbill if (bcr) 293914Sbill bcr |= 0xffff0000; /* sxt */ 294719Sbill npf = btop(bcr + bp->b_bcount) - 1; 2951413Sbill reg = npf; 296420Sbill o = (int)bp->b_un.b_addr & PGOFSET; 297420Sbill printf("%D ", bp->b_blkno + npf); 29821Sbill prdev("ECC", bp->b_dev); 29921Sbill mask = rp->hpec2&0xffff; 30021Sbill if (mask == 0) { 30121Sbill rp->hpof = FMT22; 302420Sbill return (0); 30321Sbill } 304420Sbill 305420Sbill /* 306420Sbill * Compute the byte and bit position of the error. 307420Sbill * The variable i is the byte offset in the transfer, 308420Sbill * the variable byte is the offset from a page boundary 309420Sbill * in main memory. 310420Sbill */ 311420Sbill i = (rp->hpec1&0xffff) - 1; /* -1 makes 0 origin */ 312719Sbill bit = i&07; 313420Sbill i = (i&~07)>>3; 314420Sbill byte = i + o; 315420Sbill /* 316420Sbill * Correct while possible bits remain of mask. Since mask 317420Sbill * contains 11 bits, we continue while the bit offset is > -11. 318420Sbill * Also watch out for end of this block and the end of the whole 319420Sbill * transfer. 320420Sbill */ 321420Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 322420Sbill mpte = mbp->mba_map[reg+btop(byte)]; 323420Sbill addr = ptob(mpte.pg_pfnum) + (byte & PGOFSET); 324420Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 325420Sbill byte++; 326420Sbill i++; 327420Sbill bit -= 8; 32821Sbill } 3292383Swnj mi->mi_hd->mh_active++; /* Either complete or continuing */ 330719Sbill if (bcr == 0) 331420Sbill return (0); 332420Sbill /* 333420Sbill * Have to continue the transfer... clear the drive, 334420Sbill * and compute the position where the transfer is to continue. 335420Sbill * We have completed npf+1 sectores of the transfer already; 336420Sbill * restart at offset o of next sector (i.e. in MBA register reg+1). 337420Sbill */ 338420Sbill rp->hpcs1 = DCLR|GO; 339420Sbill bn = dkblock(bp); 3402383Swnj st = &hpst[mi->mi_type]; 341420Sbill cn = bp->b_cylin; 3422383Swnj sn = bn%(st->nspc) + npf + 1; 3432383Swnj tn = sn/st->nsect; 3442383Swnj sn %= st->nsect; 3452383Swnj cn += tn/st->ntrak; 3462383Swnj tn %= st->ntrak; 347420Sbill rp->hpdc = cn; 348420Sbill rp->hpda = (tn<<8) + sn; 349420Sbill mbp->mba_sr = -1; 350420Sbill mbp->mba_var = (int)ptob(reg+1) + o; 351420Sbill rp->hpcs1 = RCOM|GO; 352420Sbill return (1); 35321Sbill } 3542362Swnj 3552362Swnj #define DBSIZE 20 3562362Swnj 3572362Swnj hpdump(dev) 3582362Swnj dev_t dev; 3592362Swnj { 3602383Swnj register struct mba_info *mi; 3612383Swnj register struct mba_regs *mba; 3622362Swnj struct device *hpaddr; 3632362Swnj char *start; 3642383Swnj int num, unit; 3652383Swnj register struct hpst *st; 3662362Swnj 3672362Swnj num = maxfree; 3682362Swnj start = 0; 3692362Swnj unit = minor(dev) >> 3; 3702362Swnj if (unit >= NHP) { 3712362Swnj printf("bad unit\n"); 3722362Swnj return (-1); 3732362Swnj } 3742383Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 3752383Swnj mi = phys(hpinfo[unit],struct mba_info *); 3762383Swnj if (mi->mi_alive == 0) { 3772383Swnj printf("dna\n"); 3782383Swnj return (-1); 3792383Swnj } 3802383Swnj mba = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 3812383Swnj mba->mba_cr = MBAINIT; 3822383Swnj hpaddr = (struct device *)&mba->mba_drv[mi->mi_drive]; 3832383Swnj if ((hpaddr->hpds & VV) == 0) { 3842383Swnj hpaddr->hpcs1 = DCLR|GO; 3852362Swnj hpaddr->hpcs1 = PRESET|GO; 3862362Swnj hpaddr->hpof = FMT22; 3872362Swnj } 3882383Swnj st = &hpst[mi->mi_type]; 3892383Swnj if (dumplo < 0 || dumplo + num >= st->sizes[minor(dev)&07].nblocks) { 3902383Swnj printf("oor\n"); 3912362Swnj return (-1); 3922362Swnj } 3932362Swnj while (num > 0) { 3942383Swnj register struct pte *hpte = mba->mba_map; 3952362Swnj register int i; 3962383Swnj int blk, cn, sn, tn; 3972362Swnj daddr_t bn; 3982362Swnj 3992362Swnj blk = num > DBSIZE ? DBSIZE : num; 4002362Swnj bn = dumplo + btop(start); 4012383Swnj cn = bn/st->nspc + st->sizes[minor(dev)&07].cyloff; 4022383Swnj sn = bn%st->nspc; 4032383Swnj tn = sn/st->nsect; 4042383Swnj sn = sn%st->nsect; 4052362Swnj hpaddr->hpdc = cn; 4062362Swnj hpaddr->hpda = (tn << 8) + sn; 4072362Swnj for (i = 0; i < blk; i++) 4082362Swnj *(int *)hpte++ = (btop(start)+i) | PG_V; 4092383Swnj mba->mba_sr = -1; 4102383Swnj mba->mba_bcr = -(blk*NBPG); 4112383Swnj mba->mba_var = 0; 4122362Swnj hpaddr->hpcs1 = WCOM | GO; 4132362Swnj while ((hpaddr->hpds & DRY) == 0) 4142362Swnj ; 4152362Swnj if (hpaddr->hpds&ERR) { 4162383Swnj printf("dskerr: (%d,%d,%d) ds=%x er=%x\n", 4172362Swnj cn, tn, sn, hpaddr->hpds, hpaddr->hper1); 4182362Swnj return (-1); 4192362Swnj } 4202362Swnj start += blk*NBPG; 4212362Swnj num -= blk; 4222362Swnj } 4232362Swnj return (0); 4242362Swnj } 4251565Sbill #endif 426