1*2607Swnj /* up.c 4.18 81/02/21 */ 2264Sbill 31937Swnj #include "up.h" 42395Swnj #if NSC21 > 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; 31*2607Swnj int sc_ndrive; 322395Swnj int sc_wticks; 332395Swnj } up_softc[NSC21]; 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 67*2607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 682395Swnj struct uba_minfo *upminfo[NSC21]; 692395Swnj struct uba_dinfo *updinfo[NUP]; 70*2607Swnj struct uba_dinfo *upip[NSC21][4]; 712395Swnj 72*2607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 732395Swnj struct uba_driver updriver = 74*2607Swnj { 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[] = { 84*2607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 85*2607Swnj /* 9300 actually has 815 cylinders... */ 862395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 872395Swnj }; 882395Swnj 89264Sbill int up_offset[16] = 90264Sbill { 91264Sbill P400, M400, P400, M400, 92264Sbill P800, M800, P800, M800, 93264Sbill P1200, M1200, P1200, M1200, 94264Sbill 0, 0, 0, 0, 95264Sbill }; 96264Sbill 972395Swnj struct buf rupbuf; /* GROT */ 98264Sbill 99264Sbill #define b_cylin b_resid 100264Sbill 101264Sbill #ifdef INTRLVE 102264Sbill daddr_t dkblock(); 103264Sbill #endif 1042395Swnj 1052395Swnj int upwstart, upwatch(); /* Have started guardian */ 1062470Swnj int upseek; 1072395Swnj 1082395Swnj /*ARGSUSED*/ 109*2607Swnj upprobe(reg) 1102395Swnj caddr_t reg; 1112395Swnj { 1122459Swnj register int br, cvec; 1132459Swnj 114*2607Swnj #ifdef lint 115*2607Swnj br = 0; cvec = br; br = cvec; 116*2607Swnj #endif 117*2607Swnj ((struct device *)reg)->upcs1 = (IE|RDY); 118*2607Swnj DELAY(10); 119*2607Swnj ((struct device *)reg)->upcs1 = 0; 1202459Swnj return (1); 1212395Swnj } 1222395Swnj 123*2607Swnj upslave(ui, reg) 1242395Swnj struct uba_dinfo *ui; 1252395Swnj caddr_t reg; 1262395Swnj { 1272395Swnj register struct device *upaddr = (struct device *)reg; 1282395Swnj 1292395Swnj upaddr->upcs1 = 0; /* conservative */ 130*2607Swnj upaddr->upcs2 = ui->ui_slave; 1312395Swnj if (upaddr->upcs2&NED) { 1322395Swnj upaddr->upcs1 = DCLR|GO; 1332395Swnj return (0); 1342395Swnj } 135*2607Swnj return (1); 136*2607Swnj } 137*2607Swnj 138*2607Swnj upattach(ui) 139*2607Swnj register struct uba_dinfo *ui; 140*2607Swnj { 141*2607Swnj 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; 148*2607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 149*2607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1502395Swnj } 151264Sbill 152264Sbill upstrategy(bp) 1532395Swnj register struct buf *bp; 154264Sbill { 1552395Swnj register struct uba_dinfo *ui; 1562395Swnj register struct upst *st; 1572395Swnj register int unit; 1582470Swnj register struct buf *dp; 1592395Swnj int xunit = minor(bp->b_dev) & 07; 1602470Swnj long bn, sz; 161264Sbill 1622470Swnj sz = (bp->b_bcount+511) >> 9; 163264Sbill unit = dkunit(bp); 1642395Swnj if (unit >= NUP) 1652395Swnj goto bad; 1662395Swnj ui = updinfo[unit]; 1672395Swnj if (ui == 0 || ui->ui_alive == 0) 1682395Swnj goto bad; 1692395Swnj st = &upst[ui->ui_type]; 1702395Swnj if (bp->b_blkno < 0 || 1712395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1722395Swnj goto bad; 1732395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 174264Sbill (void) spl5(); 1752470Swnj dp = &uputab[ui->ui_unit]; 1762470Swnj disksort(dp, bp); 1772470Swnj if (dp->b_active == 0) { 1782395Swnj (void) upustart(ui); 1792395Swnj bp = &ui->ui_mi->um_tab; 1802395Swnj if (bp->b_actf && bp->b_active == 0) 1812395Swnj (void) upstart(ui->ui_mi); 182264Sbill } 183264Sbill (void) spl0(); 1842395Swnj return; 1852395Swnj 1862395Swnj bad: 1872395Swnj bp->b_flags |= B_ERROR; 1882395Swnj iodone(bp); 1892395Swnj return; 190264Sbill } 191264Sbill 1922395Swnj upustart(ui) 1932395Swnj register struct uba_dinfo *ui; 194264Sbill { 195264Sbill register struct buf *bp, *dp; 1962395Swnj register struct uba_minfo *um; 1972395Swnj register struct device *upaddr; 1982395Swnj register struct upst *st; 199264Sbill daddr_t bn; 200264Sbill int sn, cn, csn; 201268Sbill int didie = 0; 202264Sbill 203*2607Swnj if (ui == 0) 204*2607Swnj return (0); 205*2607Swnj /* 206*2607Swnj * The SC21 cancels commands if you just say 207*2607Swnj * cs1 = IE 208*2607Swnj * so we are cautious about handling of cs1. 209*2607Swnj * Also don't bother to clear as bits other than in upintr(). 210*2607Swnj */ 2112395Swnj dk_busy &= ~(1<<ui->ui_dk); 2122395Swnj dp = &uputab[ui->ui_unit]; 213266Sbill if ((bp = dp->b_actf) == NULL) 214268Sbill goto out; 2152395Swnj /* dont confuse controller by giving SEARCH while dt in progress */ 2162395Swnj um = ui->ui_mi; 2172395Swnj if (um->um_tab.b_active) { 2182459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 219275Sbill return (0); 220275Sbill } 221276Sbill if (dp->b_active) 222276Sbill goto done; 223276Sbill dp->b_active = 1; 2242395Swnj upaddr = (struct device *)um->um_addr; 2252395Swnj upaddr->upcs2 = ui->ui_slave; 226266Sbill if ((upaddr->upds & VV) == 0) { 227*2607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 228266Sbill upaddr->upcs1 = IE|DCLR|GO; 229264Sbill upaddr->upcs1 = IE|PRESET|GO; 230264Sbill upaddr->upof = FMT22; 231268Sbill didie = 1; 232264Sbill } 233264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 234275Sbill goto done; 235*2607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 236*2607Swnj goto done; 2372395Swnj st = &upst[ui->ui_type]; 238264Sbill bn = dkblock(bp); 239264Sbill cn = bp->b_cylin; 2402395Swnj sn = bn%st->nspc; 2412395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 242266Sbill if (cn - upaddr->updc) 243266Sbill goto search; /* Not on-cylinder */ 244275Sbill else if (upseek) 245275Sbill goto done; /* Ok just to be on-cylinder */ 246264Sbill csn = (upaddr->upla>>6) - sn - 1; 247266Sbill if (csn < 0) 2482395Swnj csn += st->nsect; 2492395Swnj if (csn > st->nsect - upRDIST) 250264Sbill goto done; 251264Sbill search: 252264Sbill upaddr->updc = cn; 253275Sbill if (upseek) 254275Sbill upaddr->upcs1 = IE|SEEK|GO; 2552470Swnj else { 256275Sbill upaddr->upda = sn; 257275Sbill upaddr->upcs1 = IE|SEARCH|GO; 258275Sbill } 259268Sbill didie = 1; 2602395Swnj if (ui->ui_dk >= 0) { 2612395Swnj dk_busy |= 1<<ui->ui_dk; 2622395Swnj dk_seek[ui->ui_dk]++; 263264Sbill } 264268Sbill goto out; 265264Sbill done: 266264Sbill dp->b_forw = NULL; 2672395Swnj if (um->um_tab.b_actf == NULL) 2682395Swnj um->um_tab.b_actf = dp; 269264Sbill else 2702395Swnj um->um_tab.b_actl->b_forw = dp; 2712395Swnj um->um_tab.b_actl = dp; 272268Sbill out: 273268Sbill return (didie); 274264Sbill } 275264Sbill 2762395Swnj upstart(um) 2772395Swnj register struct uba_minfo *um; 278264Sbill { 279264Sbill register struct buf *bp, *dp; 2802395Swnj register struct uba_dinfo *ui; 281264Sbill register struct device *upaddr; 2822470Swnj struct upst *st; 283264Sbill daddr_t bn; 2842424Skre int dn, sn, tn, cmd; 285264Sbill 286264Sbill loop: 2872395Swnj if ((dp = um->um_tab.b_actf) == NULL) 288268Sbill return (0); 289264Sbill if ((bp = dp->b_actf) == NULL) { 2902395Swnj um->um_tab.b_actf = dp->b_forw; 291264Sbill goto loop; 292264Sbill } 293266Sbill /* 294266Sbill * Mark the controller busy, and multi-part disk address. 295266Sbill * Select the unit on which the i/o is to take place. 296266Sbill */ 2972395Swnj um->um_tab.b_active++; 2982395Swnj ui = updinfo[dkunit(bp)]; 299264Sbill bn = dkblock(bp); 3002395Swnj dn = ui->ui_slave; 3012395Swnj st = &upst[ui->ui_type]; 3022395Swnj sn = bn%st->nspc; 3032395Swnj tn = sn/st->nsect; 3042395Swnj sn %= st->nsect; 3052395Swnj upaddr = (struct device *)ui->ui_addr; 306*2607Swnj upaddr->upcs2 = dn; 307266Sbill /* 308266Sbill * If drive is not present and on-line, then 309266Sbill * get rid of this with an error and loop to get 310266Sbill * rid of the rest of its queued requests. 311266Sbill * (Then on to any other ready drives.) 312266Sbill */ 313264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 314*2607Swnj printf("up%d not ready", dkunit(bp)); 315893Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 316*2607Swnj printf("\n"); 3172395Swnj um->um_tab.b_active = 0; 3182395Swnj um->um_tab.b_errcnt = 0; 319893Sbill dp->b_actf = bp->av_forw; 320893Sbill dp->b_active = 0; 321893Sbill bp->b_flags |= B_ERROR; 322893Sbill iodone(bp); 323893Sbill goto loop; 324893Sbill } 325*2607Swnj printf(" (flakey... it came back)\n"); 326264Sbill } 327266Sbill /* 328266Sbill * If this is a retry, then with the 16'th retry we 329266Sbill * begin to try offsetting the heads to recover the data. 330266Sbill */ 3312395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 3322395Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | FMT22; 333266Sbill upaddr->upcs1 = IE|OFFSET|GO; 334266Sbill while (upaddr->upds & PIP) 335264Sbill DELAY(25); 336264Sbill } 337266Sbill /* 338266Sbill * Now set up the transfer, retrieving the high 339266Sbill * 2 bits of the UNIBUS address from the information 340266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 341266Sbill */ 3422424Skre upaddr->updc = bp->b_cylin; 343264Sbill upaddr->upda = (tn << 8) + sn; 344264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 345264Sbill if (bp->b_flags & B_READ) 3462571Swnj cmd = IE|RCOM|GO; 347264Sbill else 3482571Swnj cmd = IE|WCOM|GO; 3492571Swnj um->um_cmd = cmd; 3502571Swnj ubago(ui); 351268Sbill return (1); 352264Sbill } 353264Sbill 3542571Swnj updgo(um) 3552571Swnj struct uba_minfo *um; 3562395Swnj { 3572571Swnj register struct device *upaddr = (struct device *)um->um_addr; 3582470Swnj 3592571Swnj upaddr->upba = um->um_ubinfo; 3602571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 3612395Swnj } 3622395Swnj 363264Sbill /* 364264Sbill * Handle a device interrupt. 365264Sbill * 366264Sbill * If the transferring drive needs attention, service it 367264Sbill * retrying on error or beginning next transfer. 368264Sbill * Service all other ready drives, calling ustart to transfer 3692395Swnj * their blocks to the ready queue in um->um_tab, and then restart 370264Sbill * the controller if there is anything to do. 371264Sbill */ 3722395Swnj upintr(sc21) 3732395Swnj register sc21; 374264Sbill { 375264Sbill register struct buf *bp, *dp; 3762395Swnj register struct uba_minfo *um = upminfo[sc21]; 3772395Swnj register struct uba_dinfo *ui; 3782395Swnj register struct device *upaddr = (struct device *)um->um_addr; 379264Sbill register unit; 3802470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 381*2607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 382268Sbill int needie = 1; 383264Sbill 3842470Swnj sc->sc_wticks = 0; 385*2607Swnj sc->sc_softas = 0; 3862395Swnj if (um->um_tab.b_active) { 3872470Swnj if ((upaddr->upcs1 & RDY) == 0) 3882470Swnj printf("upintr !RDY\n"); 3892395Swnj dp = um->um_tab.b_actf; 390264Sbill bp = dp->b_actf; 3912395Swnj ui = updinfo[dkunit(bp)]; 3922395Swnj dk_busy &= ~(1 << ui->ui_dk); 3932395Swnj upaddr->upcs2 = ui->ui_slave; 394885Sbill if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) { 3951829Sbill int cs2; 396266Sbill while ((upaddr->upds & DRY) == 0) 397264Sbill DELAY(25); 398*2607Swnj if (upaddr->uper1&WLE) 399*2607Swnj printf("up%d is write locked\n", dkunit(bp)); 4002395Swnj if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE) 401264Sbill bp->b_flags |= B_ERROR; 402264Sbill else 4032395Swnj um->um_tab.b_active = 0; /* force retry */ 4042395Swnj if (um->um_tab.b_errcnt > 27) { 4051829Sbill cs2 = (int)upaddr->upcs2; 4062395Swnj deverror(bp, cs2, (int)upaddr->uper1); 4072395Swnj } 4082395Swnj if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui)) 409266Sbill return; 410264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 411268Sbill needie = 0; 4122395Swnj if ((um->um_tab.b_errcnt&07) == 4) { 413264Sbill upaddr->upcs1 = RECAL|GO|IE; 414264Sbill while(upaddr->upds & PIP) 415264Sbill DELAY(25); 416264Sbill } 4172395Swnj if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) { 4181829Sbill printf("FLAKEY UP "); 4192395Swnj ubareset(um->um_ubanum); 4201829Sbill return; 4211829Sbill } 422264Sbill } 4232571Swnj ubarelse(ui->ui_ubanum, &um->um_ubinfo); 4242395Swnj if (um->um_tab.b_active) { 4252395Swnj if (um->um_tab.b_errcnt >= 16) { 426266Sbill upaddr->upcs1 = RTC|GO|IE; 427266Sbill while (upaddr->upds & PIP) 428264Sbill DELAY(25); 429268Sbill needie = 0; 430264Sbill } 4312395Swnj um->um_tab.b_active = 0; 4322395Swnj um->um_tab.b_errcnt = 0; 4332395Swnj um->um_tab.b_actf = dp->b_forw; 434264Sbill dp->b_active = 0; 435264Sbill dp->b_errcnt = 0; 436264Sbill dp->b_actf = bp->av_forw; 437266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 438264Sbill iodone(bp); 4392395Swnj if (dp->b_actf) 4402395Swnj if (upustart(ui)) 441268Sbill needie = 0; 442264Sbill } 443*2607Swnj as &= ~(1<<ui->ui_slave); 444273Sbill } else { 4451756Sbill if (upaddr->upcs1 & TRE) 446264Sbill upaddr->upcs1 = TRE; 447264Sbill } 448*2607Swnj for (unit = 0; as; as >>= 1, unit++) 449*2607Swnj if (as & 1) { 4502470Swnj upaddr->upas = 1<<unit; 451*2607Swnj if (upustart(upip[sc21][unit])) 452273Sbill needie = 0; 453273Sbill } 4542395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 4552395Swnj if (upstart(um)) 456268Sbill needie = 0; 457275Sbill if (needie) 458266Sbill upaddr->upcs1 = IE; 459264Sbill } 460264Sbill 461264Sbill upread(dev) 462264Sbill { 4632470Swnj 464264Sbill physio(upstrategy, &rupbuf, dev, B_READ, minphys); 465264Sbill } 466264Sbill 467264Sbill upwrite(dev) 468264Sbill { 4692470Swnj 470264Sbill physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); 471264Sbill } 472264Sbill 473266Sbill /* 474266Sbill * Correct an ECC error, and restart the i/o to complete 475266Sbill * the transfer if necessary. This is quite complicated because 476266Sbill * the transfer may be going to an odd memory address base and/or 477266Sbill * across a page boundary. 478266Sbill */ 4792395Swnj upecc(ui) 4802395Swnj register struct uba_dinfo *ui; 481264Sbill { 4822395Swnj register struct device *up = (struct device *)ui->ui_addr; 4832395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 4842395Swnj register struct uba_minfo *um = ui->ui_mi; 4852395Swnj register struct upst *st; 4862395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 487266Sbill register int i; 488264Sbill caddr_t addr; 489266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 490264Sbill int bn, cn, tn, sn; 491264Sbill 492264Sbill /* 493266Sbill * Npf is the number of sectors transferred before the sector 494266Sbill * containing the ECC error, and reg is the UBA register 495266Sbill * mapping (the first part of) the transfer. 496266Sbill * O is offset within a memory page of the first byte transferred. 497264Sbill */ 498266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 4992571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 500264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 501264Sbill printf("%D ", bp->b_blkno+npf); 502264Sbill prdev("ECC", bp->b_dev); 503264Sbill mask = up->upec2; 504264Sbill if (mask == 0) { 505266Sbill up->upof = FMT22; /* == RTC ???? */ 506264Sbill return (0); 507264Sbill } 508266Sbill /* 509266Sbill * Flush the buffered data path, and compute the 510266Sbill * byte and bit position of the error. The variable i 511266Sbill * is the byte offset in the transfer, the variable byte 512266Sbill * is the offset from a page boundary in main memory. 513266Sbill */ 5142571Swnj ubp->uba_dpr[(um->um_ubinfo>>28)&0x0f] |= UBA_BNE; 515266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 516266Sbill bit = i&07; 517266Sbill i = (i&~07)>>3; 518264Sbill byte = i + o; 519266Sbill /* 520266Sbill * Correct while possible bits remain of mask. Since mask 521266Sbill * contains 11 bits, we continue while the bit offset is > -11. 522266Sbill * Also watch out for end of this block and the end of the whole 523266Sbill * transfer. 524266Sbill */ 525266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 526266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 527266Sbill (byte & PGOFSET); 528266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 529266Sbill byte++; 530266Sbill i++; 531266Sbill bit -= 8; 532264Sbill } 5332395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 534264Sbill if (up->upwc == 0) 535264Sbill return (0); 536266Sbill /* 537266Sbill * Have to continue the transfer... clear the drive, 538266Sbill * and compute the position where the transfer is to continue. 539266Sbill * We have completed npf+1 sectors of the transfer already; 540266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 541266Sbill */ 542266Sbill up->upcs1 = TRE|IE|DCLR|GO; 543264Sbill bn = dkblock(bp); 5442395Swnj st = &upst[ui->ui_type]; 545264Sbill cn = bp->b_cylin; 5462395Swnj sn = bn%st->nspc + npf + 1; 5472395Swnj tn = sn/st->nsect; 5482395Swnj sn %= st->nsect; 5492395Swnj cn += tn/st->ntrak; 5502395Swnj tn %= st->ntrak; 551264Sbill up->updc = cn; 552266Sbill up->upda = (tn << 8) | sn; 553266Sbill ubaddr = (int)ptob(reg+1) + o; 554266Sbill up->upba = ubaddr; 555266Sbill cmd = (ubaddr >> 8) & 0x300; 556266Sbill cmd |= IE|GO|RCOM; 557266Sbill up->upcs1 = cmd; 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 5732395Swnj for (sc21 = 0; sc21 < NSC21; 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); 5862571Swnj ubarelse(um->um_ubanum, &um->um_ubinfo); 5872395Swnj } 5882395Swnj ((struct device *)(um->um_addr))->upcs2 = 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); 6142395Swnj for (sc21 = 0; sc21 < NSC21; 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++) 6212395Swnj if (updinfo[unit]->ui_mi == um && 6222395Swnj uputab[unit].b_active) 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; 6312395Swnj printf("LOST INTERRUPT RESET"); 6322470Swnj /* SHOULD JUST RESET ONE CTLR, NOT ALL ON UBA */ 6332395Swnj upreset(um->um_ubanum); 6342395Swnj printf("\n"); 6352395Swnj } 636313Sbill } 637313Sbill } 6382379Swnj 6392379Swnj #define DBSIZE 20 6402379Swnj 6412379Swnj updump(dev) 6422379Swnj dev_t dev; 6432379Swnj { 6442379Swnj struct device *upaddr; 6452379Swnj char *start; 646*2607Swnj int num, blk, unit; 6472379Swnj struct size *sizes; 6482395Swnj register struct uba_regs *uba; 6492395Swnj register struct uba_dinfo *ui; 6502379Swnj register short *rp; 6512395Swnj struct upst *st; 6522379Swnj 6532395Swnj unit = minor(dev) >> 3; 6542395Swnj if (unit >= NUP) { 6552395Swnj printf("bad unit\n"); 6562395Swnj return (-1); 6572395Swnj } 6582470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 6592395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 6602395Swnj if (ui->ui_alive == 0) { 6612395Swnj printf("dna\n"); 6622395Swnj return(-1); 6632395Swnj } 6642395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 6652395Swnj #if VAX780 6662470Swnj if (cpu == VAX_780) 6672470Swnj ubainit(uba); 6681809Sbill #endif 6692379Swnj DELAY(1000000); 6702395Swnj upaddr = (struct device *)ui->ui_physaddr; 6712395Swnj while ((upaddr->upcs1&DVA) == 0) 6722379Swnj ; 6732379Swnj num = maxfree; 6742379Swnj start = 0; 6752379Swnj upaddr->upcs2 = unit; 6762379Swnj if ((upaddr->upds & VV) == 0) { 6772379Swnj upaddr->upcs1 = DCLR|GO; 6782379Swnj upaddr->upcs1 = PRESET|GO; 6792379Swnj upaddr->upof = FMT22; 6802379Swnj } 6812379Swnj if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 6822379Swnj printf("up !DPR || !MOL\n"); 6832379Swnj return (-1); 6842379Swnj } 6852470Swnj st = &upst[ui->ui_type]; 6862395Swnj sizes = phys(struct size *, st->sizes); 6872379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 6882395Swnj printf("oor\n"); 6892379Swnj return (-1); 6902379Swnj } 6912379Swnj while (num > 0) { 6922379Swnj register struct pte *io; 6932379Swnj register int i; 6942379Swnj int cn, sn, tn; 6952379Swnj daddr_t bn; 6962379Swnj 6972379Swnj blk = num > DBSIZE ? DBSIZE : num; 6982395Swnj io = uba->uba_map; 6992379Swnj for (i = 0; i < blk; i++) 7002395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 7012379Swnj *(int *)io = 0; 7022379Swnj bn = dumplo + btop(start); 703*2607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 704*2607Swnj sn = bn%st->nspc; 705*2607Swnj tn = sn/st->nsect; 706*2607Swnj sn = sn%st->nsect; 7072379Swnj upaddr->updc = cn; 7082379Swnj rp = (short *) &upaddr->upda; 7092379Swnj *rp = (tn << 8) + sn; 7102379Swnj *--rp = 0; 7112379Swnj *--rp = -blk*NBPG / sizeof (short); 7122379Swnj *--rp = GO|WCOM; 7132379Swnj do { 7142379Swnj DELAY(25); 7152379Swnj } while ((upaddr->upcs1 & RDY) == 0); 7162379Swnj if (upaddr->upcs1&ERR) { 7172379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 7182379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 7192379Swnj return (-1); 7202379Swnj } 7212379Swnj start += blk*NBPG; 7222379Swnj num -= blk; 7232379Swnj } 7242379Swnj return (0); 7252379Swnj } 7261902Swnj #endif 727