1*2646Swnj /* up.c 4.21 81/02/23 */ 2264Sbill 31937Swnj #include "up.h" 4*2646Swnj #if NSC > 0 5264Sbill /* 6885Sbill * UNIBUS disk driver with overlapped seeks and ECC recovery. 7264Sbill */ 81756Sbill #define DELAY(N) { register int d; d = N; while (--d > 0); } 9264Sbill 10264Sbill #include "../h/param.h" 11264Sbill #include "../h/systm.h" 122395Swnj #include "../h/cpu.h" 132395Swnj #include "../h/nexus.h" 14308Sbill #include "../h/dk.h" 15264Sbill #include "../h/buf.h" 16264Sbill #include "../h/conf.h" 17264Sbill #include "../h/dir.h" 18264Sbill #include "../h/user.h" 19264Sbill #include "../h/map.h" 20420Sbill #include "../h/pte.h" 21264Sbill #include "../h/mba.h" 22264Sbill #include "../h/mtpr.h" 232571Swnj #include "../h/vm.h" 24264Sbill #include "../h/uba.h" 252379Swnj #include "../h/cmap.h" 26264Sbill 272379Swnj #include "../h/upreg.h" 28264Sbill 292395Swnj struct up_softc { 302395Swnj int sc_softas; 312607Swnj int sc_ndrive; 322395Swnj int sc_wticks; 33*2646Swnj } up_softc[NSC]; 34275Sbill 352395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 36264Sbill struct size 37264Sbill { 38264Sbill daddr_t nblocks; 39264Sbill int cyloff; 40264Sbill } up_sizes[8] = { 41264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 42264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 43341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 44264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 45264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 46264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 47264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 48264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 492395Swnj }, fj_sizes[8] = { 502395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 512395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 522395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 532395Swnj 0, 0, 542395Swnj 0, 0, 552395Swnj 0, 0, 562395Swnj 0, 0, 572395Swnj 213760, 155, /* H=cyl 155 thru 822 */ 58264Sbill }; 592395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 60264Sbill 612395Swnj #define _upSDIST 2 /* 1.0 msec */ 622395Swnj #define _upRDIST 4 /* 2.0 msec */ 63264Sbill 642395Swnj int upSDIST = _upSDIST; 652395Swnj int upRDIST = _upRDIST; 662395Swnj 672607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 68*2646Swnj struct uba_minfo *upminfo[NSC]; 692395Swnj struct uba_dinfo *updinfo[NUP]; 70*2646Swnj struct uba_dinfo *upip[NSC][4]; 712395Swnj 722607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 732616Swnj struct uba_driver scdriver = 742607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 752395Swnj struct buf uputab[NUP]; 762395Swnj 772395Swnj struct upst { 782395Swnj short nsect; 792395Swnj short ntrak; 802395Swnj short nspc; 812395Swnj short ncyl; 822395Swnj struct size *sizes; 832395Swnj } upst[] = { 842607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 852607Swnj /* 9300 actually has 815 cylinders... */ 862395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 872395Swnj }; 882395Swnj 892629Swnj u_char up_offset[16] = { 902629Swnj UP_P400, UP_M400, UP_P400, UP_M400, UP_P800, UP_M800, UP_P800, UP_M800, 912629Swnj UP_P1200, UP_M1200, UP_P1200, UP_M1200, 0, 0, 0, 0 922629Swnj }; 93264Sbill 942616Swnj struct buf rupbuf[NUP]; 95264Sbill 96264Sbill #define b_cylin b_resid 97264Sbill 98264Sbill #ifdef INTRLVE 99264Sbill daddr_t dkblock(); 100264Sbill #endif 1012395Swnj 1022395Swnj int upwstart, upwatch(); /* Have started guardian */ 1032470Swnj int upseek; 1042395Swnj 1052395Swnj /*ARGSUSED*/ 1062607Swnj upprobe(reg) 1072395Swnj caddr_t reg; 1082395Swnj { 1092459Swnj register int br, cvec; 1102459Swnj 1112607Swnj #ifdef lint 1122607Swnj br = 0; cvec = br; br = cvec; 1132607Swnj #endif 1142629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1152607Swnj DELAY(10); 1162629Swnj ((struct updevice *)reg)->upcs1 = 0; 1172459Swnj return (1); 1182395Swnj } 1192395Swnj 1202607Swnj upslave(ui, reg) 1212395Swnj struct uba_dinfo *ui; 1222395Swnj caddr_t reg; 1232395Swnj { 1242629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1252395Swnj 1262395Swnj upaddr->upcs1 = 0; /* conservative */ 1272607Swnj upaddr->upcs2 = ui->ui_slave; 1282629Swnj if (upaddr->upcs2&UP_NED) { 1292629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1302395Swnj return (0); 1312395Swnj } 1322607Swnj return (1); 1332607Swnj } 1342607Swnj 1352607Swnj upattach(ui) 1362607Swnj register struct uba_dinfo *ui; 1372607Swnj { 1382629Swnj #ifdef notdef 1392629Swnj register struct updevice *upaddr; 1402629Swnj #endif 1412607Swnj 1422395Swnj if (upwstart == 0) { 1432395Swnj timeout(upwatch, (caddr_t)0, HZ); 1442395Swnj upwstart++; 1452395Swnj } 1462571Swnj if (ui->ui_dk >= 0) 1472571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1482607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1492607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1502629Swnj #ifdef notdef 1512629Swnj upaddr = (struct updevice *)ui->ui_addr; 1522629Swnj upaddr->upcs1 = 0; 1532629Swnj upaddr->upcs2 = ui->ui_slave; 1542629Swnj upaddr->uphr = -1; 1552629Swnj /* ... */ 1562629Swnj if (upaddr-> ... == 10) 1572629Swnj ui->ui_type = 1; 1582629Swnj #endif 1592395Swnj } 160264Sbill 161264Sbill upstrategy(bp) 1622395Swnj register struct buf *bp; 163264Sbill { 1642395Swnj register struct uba_dinfo *ui; 1652395Swnj register struct upst *st; 1662395Swnj register int unit; 1672470Swnj register struct buf *dp; 1682395Swnj int xunit = minor(bp->b_dev) & 07; 1692470Swnj long bn, sz; 170264Sbill 1712470Swnj sz = (bp->b_bcount+511) >> 9; 172264Sbill unit = dkunit(bp); 1732395Swnj if (unit >= NUP) 1742395Swnj goto bad; 1752395Swnj ui = updinfo[unit]; 1762395Swnj if (ui == 0 || ui->ui_alive == 0) 1772395Swnj goto bad; 1782395Swnj st = &upst[ui->ui_type]; 1792395Swnj if (bp->b_blkno < 0 || 1802395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1812395Swnj goto bad; 1822395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 183264Sbill (void) spl5(); 1842470Swnj dp = &uputab[ui->ui_unit]; 1852470Swnj disksort(dp, bp); 1862470Swnj if (dp->b_active == 0) { 1872395Swnj (void) upustart(ui); 1882395Swnj bp = &ui->ui_mi->um_tab; 1892395Swnj if (bp->b_actf && bp->b_active == 0) 1902395Swnj (void) upstart(ui->ui_mi); 191264Sbill } 192264Sbill (void) spl0(); 1932395Swnj return; 1942395Swnj 1952395Swnj bad: 1962395Swnj bp->b_flags |= B_ERROR; 1972395Swnj iodone(bp); 1982395Swnj return; 199264Sbill } 200264Sbill 2012395Swnj upustart(ui) 2022395Swnj register struct uba_dinfo *ui; 203264Sbill { 204264Sbill register struct buf *bp, *dp; 2052395Swnj register struct uba_minfo *um; 2062629Swnj register struct updevice *upaddr; 2072395Swnj register struct upst *st; 208264Sbill daddr_t bn; 209264Sbill int sn, cn, csn; 210268Sbill int didie = 0; 211264Sbill 2122607Swnj if (ui == 0) 2132607Swnj return (0); 2142607Swnj /* 2152607Swnj * The SC21 cancels commands if you just say 2162629Swnj * cs1 = UP_IE 2172607Swnj * so we are cautious about handling of cs1. 2182607Swnj * Also don't bother to clear as bits other than in upintr(). 2192607Swnj */ 2202395Swnj dk_busy &= ~(1<<ui->ui_dk); 2212395Swnj dp = &uputab[ui->ui_unit]; 222266Sbill if ((bp = dp->b_actf) == NULL) 223268Sbill goto out; 2242395Swnj /* dont confuse controller by giving SEARCH while dt in progress */ 2252395Swnj um = ui->ui_mi; 2262395Swnj if (um->um_tab.b_active) { 2272459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 228275Sbill return (0); 229275Sbill } 230276Sbill if (dp->b_active) 231276Sbill goto done; 232276Sbill dp->b_active = 1; 2332629Swnj upaddr = (struct updevice *)um->um_addr; 2342395Swnj upaddr->upcs2 = ui->ui_slave; 2352629Swnj if ((upaddr->upds & UP_VV) == 0) { 2362607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2372629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2382629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 2392629Swnj upaddr->upof = UP_FMT22; 240268Sbill didie = 1; 241264Sbill } 2422629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) 243275Sbill goto done; 2442607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 2452607Swnj goto done; 2462395Swnj st = &upst[ui->ui_type]; 247264Sbill bn = dkblock(bp); 248264Sbill cn = bp->b_cylin; 2492395Swnj sn = bn%st->nspc; 2502395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 251266Sbill if (cn - upaddr->updc) 252266Sbill goto search; /* Not on-cylinder */ 253275Sbill else if (upseek) 254275Sbill goto done; /* Ok just to be on-cylinder */ 255264Sbill csn = (upaddr->upla>>6) - sn - 1; 256266Sbill if (csn < 0) 2572395Swnj csn += st->nsect; 2582395Swnj if (csn > st->nsect - upRDIST) 259264Sbill goto done; 260264Sbill search: 261264Sbill upaddr->updc = cn; 262275Sbill if (upseek) 2632629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 2642470Swnj else { 265275Sbill upaddr->upda = sn; 2662629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 267275Sbill } 268268Sbill didie = 1; 2692395Swnj if (ui->ui_dk >= 0) { 2702395Swnj dk_busy |= 1<<ui->ui_dk; 2712395Swnj dk_seek[ui->ui_dk]++; 272264Sbill } 273268Sbill goto out; 274264Sbill done: 2752629Swnj if (dp->b_active != 2) { 2762629Swnj dp->b_forw = NULL; 2772629Swnj if (um->um_tab.b_actf == NULL) 2782629Swnj um->um_tab.b_actf = dp; 2792629Swnj else 2802629Swnj um->um_tab.b_actl->b_forw = dp; 2812629Swnj um->um_tab.b_actl = dp; 2822629Swnj dp->b_active = 2; 2832629Swnj } 284268Sbill out: 285268Sbill return (didie); 286264Sbill } 287264Sbill 2882395Swnj upstart(um) 2892395Swnj register struct uba_minfo *um; 290264Sbill { 291264Sbill register struct buf *bp, *dp; 2922395Swnj register struct uba_dinfo *ui; 2932629Swnj register struct updevice *upaddr; 2942470Swnj struct upst *st; 295264Sbill daddr_t bn; 2962424Skre int dn, sn, tn, cmd; 297264Sbill 298264Sbill loop: 2992395Swnj if ((dp = um->um_tab.b_actf) == NULL) 300268Sbill return (0); 301264Sbill if ((bp = dp->b_actf) == NULL) { 3022395Swnj um->um_tab.b_actf = dp->b_forw; 303264Sbill goto loop; 304264Sbill } 3052395Swnj um->um_tab.b_active++; 3062395Swnj ui = updinfo[dkunit(bp)]; 307264Sbill bn = dkblock(bp); 3082395Swnj dn = ui->ui_slave; 3092395Swnj st = &upst[ui->ui_type]; 3102395Swnj sn = bn%st->nspc; 3112395Swnj tn = sn/st->nsect; 3122395Swnj sn %= st->nsect; 3132629Swnj upaddr = (struct updevice *)ui->ui_addr; 3142607Swnj upaddr->upcs2 = dn; 3152629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) { 3162607Swnj printf("up%d not ready", dkunit(bp)); 3172629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) { 3182607Swnj printf("\n"); 3192395Swnj um->um_tab.b_active = 0; 3202395Swnj um->um_tab.b_errcnt = 0; 321893Sbill dp->b_actf = bp->av_forw; 322893Sbill dp->b_active = 0; 323893Sbill bp->b_flags |= B_ERROR; 324893Sbill iodone(bp); 325893Sbill goto loop; 326893Sbill } 3272629Swnj printf(" (flakey)\n"); 328264Sbill } 3292395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 3302629Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UP_FMT22; 3312629Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 3322629Swnj while (upaddr->upds & UP_PIP) 333264Sbill DELAY(25); 334264Sbill } 3352424Skre upaddr->updc = bp->b_cylin; 336264Sbill upaddr->upda = (tn << 8) + sn; 337264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 338264Sbill if (bp->b_flags & B_READ) 3392629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 340264Sbill else 3412629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 3422571Swnj um->um_cmd = cmd; 3432571Swnj ubago(ui); 344268Sbill return (1); 345264Sbill } 346264Sbill 3472571Swnj updgo(um) 3482571Swnj struct uba_minfo *um; 3492395Swnj { 3502629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 3512470Swnj 3522571Swnj upaddr->upba = um->um_ubinfo; 3532571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 3542395Swnj } 3552395Swnj 3562616Swnj scintr(sc21) 3572395Swnj register sc21; 358264Sbill { 359264Sbill register struct buf *bp, *dp; 3602395Swnj register struct uba_minfo *um = upminfo[sc21]; 3612395Swnj register struct uba_dinfo *ui; 3622629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 363264Sbill register unit; 3642470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 3652607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 366268Sbill int needie = 1; 367264Sbill 3682470Swnj sc->sc_wticks = 0; 3692607Swnj sc->sc_softas = 0; 3702395Swnj if (um->um_tab.b_active) { 3712629Swnj if ((upaddr->upcs1 & UP_RDY) == 0) 3722470Swnj printf("upintr !RDY\n"); 3732395Swnj dp = um->um_tab.b_actf; 374264Sbill bp = dp->b_actf; 3752395Swnj ui = updinfo[dkunit(bp)]; 3762395Swnj dk_busy &= ~(1 << ui->ui_dk); 3772395Swnj upaddr->upcs2 = ui->ui_slave; 3782629Swnj if ((upaddr->upds&UP_ERR) || (upaddr->upcs1&UP_TRE)) { 3791829Sbill int cs2; 3802629Swnj while ((upaddr->upds & UP_DRY) == 0) 381264Sbill DELAY(25); 3822629Swnj if (upaddr->uper1&UP_WLE) 3832607Swnj printf("up%d is write locked\n", dkunit(bp)); 3842629Swnj if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&UP_WLE) 385264Sbill bp->b_flags |= B_ERROR; 386264Sbill else 3872395Swnj um->um_tab.b_active = 0; /* force retry */ 3882395Swnj if (um->um_tab.b_errcnt > 27) { 3891829Sbill cs2 = (int)upaddr->upcs2; 3902395Swnj deverror(bp, cs2, (int)upaddr->uper1); 3912395Swnj } 3922629Swnj if ((upaddr->uper1&(UP_DCK|UP_ECH))==UP_DCK) 3932629Swnj if (upecc(ui)) 3942629Swnj return; 3952629Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 396268Sbill needie = 0; 3972395Swnj if ((um->um_tab.b_errcnt&07) == 4) { 3982629Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 3992629Swnj while(upaddr->upds & UP_PIP) 400264Sbill DELAY(25); 401264Sbill } 4022629Swnj if (um->um_tab.b_errcnt == 28 && cs2&(UP_NEM|UP_MXF)) { 4031829Sbill printf("FLAKEY UP "); 4042395Swnj ubareset(um->um_ubanum); 4051829Sbill return; 4061829Sbill } 407264Sbill } 4082616Swnj ubadone(um); 4092395Swnj if (um->um_tab.b_active) { 4102395Swnj if (um->um_tab.b_errcnt >= 16) { 4112629Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 4122629Swnj while (upaddr->upds & UP_PIP) 413264Sbill DELAY(25); 414268Sbill needie = 0; 415264Sbill } 4162395Swnj um->um_tab.b_active = 0; 4172395Swnj um->um_tab.b_errcnt = 0; 4182395Swnj um->um_tab.b_actf = dp->b_forw; 419264Sbill dp->b_active = 0; 420264Sbill dp->b_errcnt = 0; 421264Sbill dp->b_actf = bp->av_forw; 422266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 423264Sbill iodone(bp); 4242395Swnj if (dp->b_actf) 4252395Swnj if (upustart(ui)) 426268Sbill needie = 0; 427264Sbill } 4282607Swnj as &= ~(1<<ui->ui_slave); 429273Sbill } else { 4302629Swnj if (upaddr->upcs1 & UP_TRE) 4312629Swnj upaddr->upcs1 = UP_TRE; 432264Sbill } 4332607Swnj for (unit = 0; as; as >>= 1, unit++) 4342607Swnj if (as & 1) { 4352470Swnj upaddr->upas = 1<<unit; 4362607Swnj if (upustart(upip[sc21][unit])) 437273Sbill needie = 0; 438273Sbill } 4392395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 4402395Swnj if (upstart(um)) 441268Sbill needie = 0; 442275Sbill if (needie) 4432629Swnj upaddr->upcs1 = UP_IE; 444264Sbill } 445264Sbill 446264Sbill upread(dev) 4472616Swnj dev_t dev; 448264Sbill { 4492616Swnj register int unit = minor(dev) >> 3; 4502470Swnj 4512616Swnj if (unit >= NUP) 4522616Swnj u.u_error = ENXIO; 4532616Swnj else 4542616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 455264Sbill } 456264Sbill 457264Sbill upwrite(dev) 4582616Swnj dev_t dev; 459264Sbill { 4602616Swnj register int unit = minor(dev) >> 3; 4612470Swnj 4622616Swnj if (unit >= NUP) 4632616Swnj u.u_error = ENXIO; 4642616Swnj else 4652616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 466264Sbill } 467264Sbill 468266Sbill /* 469266Sbill * Correct an ECC error, and restart the i/o to complete 470266Sbill * the transfer if necessary. This is quite complicated because 471266Sbill * the transfer may be going to an odd memory address base and/or 472266Sbill * across a page boundary. 473266Sbill */ 4742395Swnj upecc(ui) 4752395Swnj register struct uba_dinfo *ui; 476264Sbill { 4772629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 4782395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 4792395Swnj register struct uba_minfo *um = ui->ui_mi; 4802395Swnj register struct upst *st; 4812395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 482266Sbill register int i; 483264Sbill caddr_t addr; 484266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 485264Sbill int bn, cn, tn, sn; 486264Sbill 487264Sbill /* 488266Sbill * Npf is the number of sectors transferred before the sector 489266Sbill * containing the ECC error, and reg is the UBA register 490266Sbill * mapping (the first part of) the transfer. 491266Sbill * O is offset within a memory page of the first byte transferred. 492264Sbill */ 493266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 4942571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 495264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 496264Sbill printf("%D ", bp->b_blkno+npf); 497264Sbill prdev("ECC", bp->b_dev); 498264Sbill mask = up->upec2; 499264Sbill if (mask == 0) { 5002629Swnj up->upof = UP_FMT22; /* == RTC ???? */ 501264Sbill return (0); 502264Sbill } 503266Sbill /* 504266Sbill * Flush the buffered data path, and compute the 505266Sbill * byte and bit position of the error. The variable i 506266Sbill * is the byte offset in the transfer, the variable byte 507266Sbill * is the offset from a page boundary in main memory. 508266Sbill */ 5092571Swnj ubp->uba_dpr[(um->um_ubinfo>>28)&0x0f] |= UBA_BNE; 510266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 511266Sbill bit = i&07; 512266Sbill i = (i&~07)>>3; 513264Sbill byte = i + o; 514266Sbill /* 515266Sbill * Correct while possible bits remain of mask. Since mask 516266Sbill * contains 11 bits, we continue while the bit offset is > -11. 517266Sbill * Also watch out for end of this block and the end of the whole 518266Sbill * transfer. 519266Sbill */ 520266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 521266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 522266Sbill (byte & PGOFSET); 523266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 524266Sbill byte++; 525266Sbill i++; 526266Sbill bit -= 8; 527264Sbill } 5282395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 529264Sbill if (up->upwc == 0) 530264Sbill return (0); 531266Sbill /* 532266Sbill * Have to continue the transfer... clear the drive, 533266Sbill * and compute the position where the transfer is to continue. 534266Sbill * We have completed npf+1 sectors of the transfer already; 535266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 536266Sbill */ 5372629Swnj #ifdef notdef 5382629Swnj up->uper1 = 0; 5392629Swnj up->upcs1 |= UP_GO; 5402629Swnj #else 5412629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 542264Sbill bn = dkblock(bp); 5432395Swnj st = &upst[ui->ui_type]; 544264Sbill cn = bp->b_cylin; 5452395Swnj sn = bn%st->nspc + npf + 1; 5462395Swnj tn = sn/st->nsect; 5472395Swnj sn %= st->nsect; 5482395Swnj cn += tn/st->ntrak; 5492395Swnj tn %= st->ntrak; 550264Sbill up->updc = cn; 551266Sbill up->upda = (tn << 8) | sn; 552266Sbill ubaddr = (int)ptob(reg+1) + o; 553266Sbill up->upba = ubaddr; 554266Sbill cmd = (ubaddr >> 8) & 0x300; 5552629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 556266Sbill up->upcs1 = cmd; 5572629Swnj #endif 558264Sbill return (1); 559264Sbill } 560286Sbill 561286Sbill /* 562286Sbill * Reset driver after UBA init. 563286Sbill * Cancel software state of all pending transfers 564286Sbill * and restart all units and the controller. 565286Sbill */ 5662395Swnj upreset(uban) 567286Sbill { 5682395Swnj register struct uba_minfo *um; 5692395Swnj register struct uba_dinfo *ui; 5702395Swnj register sc21, unit; 5712424Skre int any = 0; 572286Sbill 573*2646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 5742470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 5752470Swnj um->um_alive == 0) 5762395Swnj continue; 5772424Skre if (any == 0) { 5782424Skre printf(" up"); 5792470Swnj DELAY(10000000); /* give it time to self-test */ 5802424Skre any++; 5812424Skre } 5822395Swnj um->um_tab.b_active = 0; 5832395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 5842571Swnj if (um->um_ubinfo) { 5852571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 5862616Swnj ubadone(um); 5872395Swnj } 5882629Swnj ((struct updevice *)(um->um_addr))->upcs2 = UP_CLR; 5892395Swnj for (unit = 0; unit < NUP; unit++) { 5902395Swnj if ((ui = updinfo[unit]) == 0) 5912395Swnj continue; 5922395Swnj if (ui->ui_alive == 0) 5932395Swnj continue; 5942395Swnj uputab[unit].b_active = 0; 5952395Swnj (void) upustart(ui); 5962395Swnj } 5972395Swnj (void) upstart(um); 598286Sbill } 599286Sbill } 600313Sbill 601313Sbill /* 602313Sbill * Wake up every second and if an interrupt is pending 603313Sbill * but nothing has happened increment a counter. 604313Sbill * If nothing happens for 20 seconds, reset the controller 605313Sbill * and begin anew. 606313Sbill */ 607313Sbill upwatch() 608313Sbill { 6092395Swnj register struct uba_minfo *um; 6102395Swnj register sc21, unit; 6112470Swnj register struct up_softc *sc; 612313Sbill 6131783Sbill timeout(upwatch, (caddr_t)0, HZ); 614*2646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 6152395Swnj um = upminfo[sc21]; 6162470Swnj if (um == 0 || um->um_alive == 0) 6172470Swnj continue; 6182470Swnj sc = &up_softc[sc21]; 6192395Swnj if (um->um_tab.b_active == 0) { 6202395Swnj for (unit = 0; unit < NUP; unit++) 6212629Swnj if (uputab[unit].b_active && 6222629Swnj updinfo[unit]->ui_mi == um) 6232395Swnj goto active; 6242470Swnj sc->sc_wticks = 0; 6252395Swnj continue; 6262395Swnj } 6272395Swnj active: 6282470Swnj sc->sc_wticks++; 6292470Swnj if (sc->sc_wticks >= 20) { 6302470Swnj sc->sc_wticks = 0; 631*2646Swnj printf("LOST upintr "); 632*2646Swnj ubareset(um->um_ubanum); 6332395Swnj } 634313Sbill } 635313Sbill } 6362379Swnj 6372379Swnj #define DBSIZE 20 6382379Swnj 6392379Swnj updump(dev) 6402379Swnj dev_t dev; 6412379Swnj { 6422629Swnj struct updevice *upaddr; 6432379Swnj char *start; 6442607Swnj int num, blk, unit; 6452379Swnj struct size *sizes; 6462395Swnj register struct uba_regs *uba; 6472395Swnj register struct uba_dinfo *ui; 6482379Swnj register short *rp; 6492395Swnj struct upst *st; 6502379Swnj 6512395Swnj unit = minor(dev) >> 3; 6522395Swnj if (unit >= NUP) { 6532395Swnj printf("bad unit\n"); 6542395Swnj return (-1); 6552395Swnj } 6562470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 6572395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 6582395Swnj if (ui->ui_alive == 0) { 6592395Swnj printf("dna\n"); 6602395Swnj return(-1); 6612395Swnj } 6622395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 6632395Swnj #if VAX780 6642470Swnj if (cpu == VAX_780) 6652470Swnj ubainit(uba); 6661809Sbill #endif 6672379Swnj DELAY(1000000); 6682629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 6692629Swnj while ((upaddr->upcs1&UP_DVA) == 0) 6702379Swnj ; 6712379Swnj num = maxfree; 6722379Swnj start = 0; 6732379Swnj upaddr->upcs2 = unit; 6742629Swnj if ((upaddr->upds & UP_VV) == 0) { 6752629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 6762629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 6772629Swnj upaddr->upof = UP_FMT22; 6782379Swnj } 6792629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) { 6802629Swnj printf("dna\n"); 6812379Swnj return (-1); 6822379Swnj } 6832470Swnj st = &upst[ui->ui_type]; 6842395Swnj sizes = phys(struct size *, st->sizes); 6852379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 6862395Swnj printf("oor\n"); 6872379Swnj return (-1); 6882379Swnj } 6892379Swnj while (num > 0) { 6902379Swnj register struct pte *io; 6912379Swnj register int i; 6922379Swnj int cn, sn, tn; 6932379Swnj daddr_t bn; 6942379Swnj 6952379Swnj blk = num > DBSIZE ? DBSIZE : num; 6962395Swnj io = uba->uba_map; 6972379Swnj for (i = 0; i < blk; i++) 6982395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 6992379Swnj *(int *)io = 0; 7002379Swnj bn = dumplo + btop(start); 7012607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 7022607Swnj sn = bn%st->nspc; 7032607Swnj tn = sn/st->nsect; 7042607Swnj sn = sn%st->nsect; 7052379Swnj upaddr->updc = cn; 7062379Swnj rp = (short *) &upaddr->upda; 7072379Swnj *rp = (tn << 8) + sn; 7082379Swnj *--rp = 0; 7092379Swnj *--rp = -blk*NBPG / sizeof (short); 7102629Swnj *--rp = UP_GO|UP_WCOM; 7112379Swnj do { 7122379Swnj DELAY(25); 7132629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 7142629Swnj if (upaddr->upcs1&UP_ERR) { 7152379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 7162379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 7172379Swnj return (-1); 7182379Swnj } 7192379Swnj start += blk*NBPG; 7202379Swnj num -= blk; 7212379Swnj } 7222379Swnj return (0); 7232379Swnj } 7241902Swnj #endif 725