1*2470Swnj /* up.c 4.16 81/02/17 */ 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" 23264Sbill #include "../h/uba.h" 24264Sbill #include "../h/vm.h" 252379Swnj #include "../h/cmap.h" 26264Sbill 272379Swnj #include "../h/upreg.h" 28264Sbill 292395Swnj struct up_softc { 302395Swnj int sc_softas; 312395Swnj int sc_seek; 322395Swnj int sc_info; 332395Swnj int sc_wticks; 342424Skre /* struct uba_minfo sc_minfo; */ 352395Swnj } up_softc[NSC21]; 36275Sbill 372395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 38264Sbill struct size 39264Sbill { 40264Sbill daddr_t nblocks; 41264Sbill int cyloff; 42264Sbill } up_sizes[8] = { 43264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 44264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 45341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 46264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 47264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 48264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 49264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 50264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 512395Swnj }, fj_sizes[8] = { 522395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 532395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 542395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 552395Swnj 0, 0, 562395Swnj 0, 0, 572395Swnj 0, 0, 582395Swnj 0, 0, 592395Swnj 213760, 155, /* H=cyl 155 thru 822 */ 60264Sbill }; 612395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 62264Sbill 632395Swnj #define _upSDIST 2 /* 1.0 msec */ 642395Swnj #define _upRDIST 4 /* 2.0 msec */ 65264Sbill 662395Swnj int upSDIST = _upSDIST; 672395Swnj int upRDIST = _upRDIST; 682395Swnj 692395Swnj int upcntrlr(), upslave(), updgo(), upintr(); 702395Swnj struct uba_minfo *upminfo[NSC21]; 712395Swnj struct uba_dinfo *updinfo[NUP]; 722395Swnj 732459Swnj u_short upstd[] = { 0776700, 0774400, 0776300 }; 742395Swnj struct uba_driver updriver = 752459Swnj { upcntrlr, upslave, updgo, 0, upstd, "up", updinfo, upminfo }; 762395Swnj struct buf uputab[NUP]; 772395Swnj 782395Swnj struct upst { 792395Swnj short nsect; 802395Swnj short ntrak; 812395Swnj short nspc; 822395Swnj short ncyl; 832395Swnj struct size *sizes; 842395Swnj } upst[] = { 852395Swnj 32, 19, 32*19, 815, up_sizes, /* 9300 */ 862395Swnj 32, 19, 32*19, 823, up_sizes, /* so cdc will boot */ 872395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 882395Swnj }; 892395Swnj 90264Sbill int up_offset[16] = 91264Sbill { 92264Sbill P400, M400, P400, M400, 93264Sbill P800, M800, P800, M800, 94264Sbill P1200, M1200, P1200, M1200, 95264Sbill 0, 0, 0, 0, 96264Sbill }; 97264Sbill 982395Swnj struct buf rupbuf; /* GROT */ 99264Sbill 100264Sbill #define b_cylin b_resid 101264Sbill 102264Sbill #ifdef INTRLVE 103264Sbill daddr_t dkblock(); 104264Sbill #endif 1052395Swnj 1062395Swnj int upwstart, upwatch(); /* Have started guardian */ 107*2470Swnj int upseek; 1082395Swnj 1092395Swnj /*ARGSUSED*/ 1102395Swnj upcntrlr(um, reg) 1112395Swnj struct uba_minfo *um; 1122395Swnj caddr_t reg; 1132395Swnj { 1142459Swnj register int br, cvec; 1152459Swnj 1162395Swnj ((struct device *)reg)->upcs1 |= (IE|RDY); 1172459Swnj return (1); 1182395Swnj } 1192395Swnj 1202459Swnj upslave(ui, reg, slaveno) 1212395Swnj struct uba_dinfo *ui; 1222395Swnj caddr_t reg; 1232395Swnj { 1242395Swnj register struct device *upaddr = (struct device *)reg; 1252395Swnj 1262395Swnj upaddr->upcs1 = 0; /* conservative */ 1272395Swnj upaddr->upcs2 = slaveno; 1282395Swnj if (upaddr->upcs2&NED) { 1292395Swnj upaddr->upcs1 = DCLR|GO; 1302395Swnj return (0); 1312395Swnj } 1322395Swnj if (upwstart == 0) { 1332395Swnj timeout(upwatch, (caddr_t)0, HZ); 1342395Swnj upwstart++; 1352395Swnj } 1362395Swnj return (1); 1372395Swnj } 138264Sbill 139264Sbill /* 1402395Swnj dk_mspw[UPDK_N+unit] = .0000020345; 1412395Swnj */ 1422395Swnj 143264Sbill upstrategy(bp) 1442395Swnj register struct buf *bp; 145264Sbill { 1462395Swnj register struct uba_dinfo *ui; 1472395Swnj register struct upst *st; 1482395Swnj register int unit; 149*2470Swnj register struct buf *dp; 1502395Swnj int xunit = minor(bp->b_dev) & 07; 151*2470Swnj long bn, sz; 152264Sbill 153*2470Swnj sz = (bp->b_bcount+511) >> 9; 154264Sbill unit = dkunit(bp); 1552395Swnj if (unit >= NUP) 1562395Swnj goto bad; 1572395Swnj ui = updinfo[unit]; 1582395Swnj if (ui == 0 || ui->ui_alive == 0) 1592395Swnj goto bad; 1602395Swnj st = &upst[ui->ui_type]; 1612395Swnj if (bp->b_blkno < 0 || 1622395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1632395Swnj goto bad; 1642395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 165264Sbill (void) spl5(); 166*2470Swnj dp = &uputab[ui->ui_unit]; 167*2470Swnj disksort(dp, bp); 168*2470Swnj if (dp->b_active == 0) { 1692395Swnj (void) upustart(ui); 1702395Swnj bp = &ui->ui_mi->um_tab; 1712395Swnj if (bp->b_actf && bp->b_active == 0) 1722395Swnj (void) upstart(ui->ui_mi); 173264Sbill } 174264Sbill (void) spl0(); 1752395Swnj return; 1762395Swnj 1772395Swnj bad: 1782395Swnj bp->b_flags |= B_ERROR; 1792395Swnj iodone(bp); 1802395Swnj return; 181264Sbill } 182264Sbill 1832395Swnj upustart(ui) 1842395Swnj register struct uba_dinfo *ui; 185264Sbill { 186264Sbill register struct buf *bp, *dp; 1872395Swnj register struct uba_minfo *um; 1882395Swnj register struct device *upaddr; 1892395Swnj register struct upst *st; 190264Sbill daddr_t bn; 191264Sbill int sn, cn, csn; 192268Sbill int didie = 0; 193264Sbill 1942395Swnj /* SC21 cancels commands if you say cs1 = IE, so dont */ 1952395Swnj /* being ultra-cautious, we clear as bits only in upintr() */ 1962395Swnj dk_busy &= ~(1<<ui->ui_dk); 1972395Swnj dp = &uputab[ui->ui_unit]; 198266Sbill if ((bp = dp->b_actf) == NULL) 199268Sbill goto out; 2002395Swnj /* dont confuse controller by giving SEARCH while dt in progress */ 2012395Swnj um = ui->ui_mi; 2022395Swnj if (um->um_tab.b_active) { 2032459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 204275Sbill return (0); 205275Sbill } 206276Sbill if (dp->b_active) 207276Sbill goto done; 208276Sbill dp->b_active = 1; 2092395Swnj upaddr = (struct device *)um->um_addr; 2102395Swnj upaddr->upcs2 = ui->ui_slave; 211266Sbill if ((upaddr->upds & VV) == 0) { 212266Sbill upaddr->upcs1 = IE|DCLR|GO; 213264Sbill upaddr->upcs1 = IE|PRESET|GO; 214264Sbill upaddr->upof = FMT22; 215268Sbill didie = 1; 216264Sbill } 217264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 218275Sbill goto done; 2192395Swnj st = &upst[ui->ui_type]; 220264Sbill bn = dkblock(bp); 221264Sbill cn = bp->b_cylin; 2222395Swnj sn = bn%st->nspc; 2232395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 224266Sbill if (cn - upaddr->updc) 225266Sbill goto search; /* Not on-cylinder */ 226275Sbill else if (upseek) 227275Sbill goto done; /* Ok just to be on-cylinder */ 228264Sbill csn = (upaddr->upla>>6) - sn - 1; 229266Sbill if (csn < 0) 2302395Swnj csn += st->nsect; 2312395Swnj if (csn > st->nsect - upRDIST) 232264Sbill goto done; 233264Sbill search: 234264Sbill upaddr->updc = cn; 235275Sbill if (upseek) 236275Sbill upaddr->upcs1 = IE|SEEK|GO; 237*2470Swnj else { 238275Sbill upaddr->upda = sn; 239275Sbill upaddr->upcs1 = IE|SEARCH|GO; 240275Sbill } 241268Sbill didie = 1; 2422395Swnj if (ui->ui_dk >= 0) { 2432395Swnj dk_busy |= 1<<ui->ui_dk; 2442395Swnj dk_seek[ui->ui_dk]++; 245264Sbill } 246268Sbill goto out; 247264Sbill done: 248264Sbill dp->b_forw = NULL; 2492395Swnj if (um->um_tab.b_actf == NULL) 2502395Swnj um->um_tab.b_actf = dp; 251264Sbill else 2522395Swnj um->um_tab.b_actl->b_forw = dp; 2532395Swnj um->um_tab.b_actl = dp; 254268Sbill out: 255268Sbill return (didie); 256264Sbill } 257264Sbill 2582395Swnj upstart(um) 2592395Swnj register struct uba_minfo *um; 260264Sbill { 261264Sbill register struct buf *bp, *dp; 2622395Swnj register struct uba_dinfo *ui; 263264Sbill register unit; 264264Sbill register struct device *upaddr; 265*2470Swnj struct upst *st; 266*2470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 267264Sbill daddr_t bn; 2682424Skre int dn, sn, tn, cmd; 269264Sbill 270264Sbill loop: 2712395Swnj if ((dp = um->um_tab.b_actf) == NULL) 272268Sbill return (0); 273264Sbill if ((bp = dp->b_actf) == NULL) { 2742395Swnj um->um_tab.b_actf = dp->b_forw; 275264Sbill goto loop; 276264Sbill } 277266Sbill /* 278266Sbill * Mark the controller busy, and multi-part disk address. 279266Sbill * Select the unit on which the i/o is to take place. 280266Sbill */ 2812395Swnj um->um_tab.b_active++; 2822395Swnj ui = updinfo[dkunit(bp)]; 283264Sbill bn = dkblock(bp); 2842395Swnj dn = ui->ui_slave; 2852395Swnj st = &upst[ui->ui_type]; 2862395Swnj sn = bn%st->nspc; 2872395Swnj tn = sn/st->nsect; 2882395Swnj sn %= st->nsect; 2892395Swnj upaddr = (struct device *)ui->ui_addr; 2901756Sbill if ((upaddr->upcs2 & 07) != dn) 291264Sbill upaddr->upcs2 = dn; 292*2470Swnj sc->sc_info = 2932395Swnj ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP|UBA_CANTWAIT); 294266Sbill /* 295266Sbill * If drive is not present and on-line, then 296266Sbill * get rid of this with an error and loop to get 297266Sbill * rid of the rest of its queued requests. 298266Sbill * (Then on to any other ready drives.) 299266Sbill */ 300264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 301893Sbill printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds); 302893Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 303893Sbill printf("-- hard\n"); 3042395Swnj um->um_tab.b_active = 0; 3052395Swnj um->um_tab.b_errcnt = 0; 306893Sbill dp->b_actf = bp->av_forw; 307893Sbill dp->b_active = 0; 308893Sbill bp->b_flags |= B_ERROR; 309893Sbill iodone(bp); 310893Sbill /* A funny place to do this ... */ 311*2470Swnj ubarelse(ui->ui_ubanum, &sc->sc_info); 312893Sbill goto loop; 313893Sbill } 314893Sbill printf("-- came back\n"); 315264Sbill } 316266Sbill /* 317266Sbill * If this is a retry, then with the 16'th retry we 318266Sbill * begin to try offsetting the heads to recover the data. 319266Sbill */ 3202395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 3212395Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | FMT22; 322266Sbill upaddr->upcs1 = IE|OFFSET|GO; 323266Sbill while (upaddr->upds & PIP) 324264Sbill DELAY(25); 325264Sbill } 326266Sbill /* 327266Sbill * Now set up the transfer, retrieving the high 328266Sbill * 2 bits of the UNIBUS address from the information 329266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 330266Sbill */ 3312424Skre upaddr->updc = bp->b_cylin; 332264Sbill upaddr->upda = (tn << 8) + sn; 333*2470Swnj upaddr->upba = sc->sc_info; 334264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 335*2470Swnj cmd = (sc->sc_info >> 8) & 0x300; 336264Sbill if (bp->b_flags & B_READ) 337266Sbill cmd |= IE|RCOM|GO; 338264Sbill else 339266Sbill cmd |= IE|WCOM|GO; 340266Sbill upaddr->upcs1 = cmd; 341266Sbill /* 342*2470Swnj * Mark i/o in progress 343266Sbill */ 344*2470Swnj if (ui->ui_dk >= 0) { 345*2470Swnj unit = ui->ui_dk; 346*2470Swnj dk_busy |= 1<<unit; 347*2470Swnj dk_xfer[unit]++; 348*2470Swnj dk_wds[unit] += bp->b_bcount>>6; 349*2470Swnj } 350268Sbill return (1); 351264Sbill } 352264Sbill 3532395Swnj updgo() 3542395Swnj { 355*2470Swnj 3562395Swnj } 3572395Swnj 358264Sbill /* 359264Sbill * Handle a device interrupt. 360264Sbill * 361264Sbill * If the transferring drive needs attention, service it 362264Sbill * retrying on error or beginning next transfer. 363264Sbill * Service all other ready drives, calling ustart to transfer 3642395Swnj * their blocks to the ready queue in um->um_tab, and then restart 365264Sbill * the controller if there is anything to do. 366264Sbill */ 3672395Swnj upintr(sc21) 3682395Swnj register sc21; 369264Sbill { 370264Sbill register struct buf *bp, *dp; 3712395Swnj register struct uba_minfo *um = upminfo[sc21]; 3722395Swnj register struct uba_dinfo *ui; 3732395Swnj register struct device *upaddr = (struct device *)um->um_addr; 374264Sbill register unit; 375*2470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 376264Sbill int as = upaddr->upas & 0377; 377268Sbill int needie = 1; 378264Sbill 379276Sbill (void) spl6(); 380*2470Swnj sc->sc_wticks = 0; 3812395Swnj if (um->um_tab.b_active) { 382*2470Swnj if ((upaddr->upcs1 & RDY) == 0) 383*2470Swnj printf("upintr !RDY\n"); 3842395Swnj dp = um->um_tab.b_actf; 385264Sbill bp = dp->b_actf; 3862395Swnj ui = updinfo[dkunit(bp)]; 3872395Swnj dk_busy &= ~(1 << ui->ui_dk); 3882395Swnj upaddr->upcs2 = ui->ui_slave; 389885Sbill if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) { 3901829Sbill int cs2; 391266Sbill while ((upaddr->upds & DRY) == 0) 392264Sbill DELAY(25); 3932395Swnj if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE) 394264Sbill bp->b_flags |= B_ERROR; 395264Sbill else 3962395Swnj um->um_tab.b_active = 0; /* force retry */ 3972395Swnj if (um->um_tab.b_errcnt > 27) { 3981829Sbill cs2 = (int)upaddr->upcs2; 3992395Swnj deverror(bp, cs2, (int)upaddr->uper1); 4002395Swnj } 4012395Swnj if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui)) 402266Sbill return; 403264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 404268Sbill needie = 0; 4052395Swnj if ((um->um_tab.b_errcnt&07) == 4) { 406264Sbill upaddr->upcs1 = RECAL|GO|IE; 407264Sbill while(upaddr->upds & PIP) 408264Sbill DELAY(25); 409264Sbill } 4102395Swnj if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) { 4111829Sbill printf("FLAKEY UP "); 4122395Swnj ubareset(um->um_ubanum); 4131829Sbill return; 4141829Sbill } 415264Sbill } 4162395Swnj if (um->um_tab.b_active) { 4172395Swnj if (um->um_tab.b_errcnt >= 16) { 418266Sbill upaddr->upcs1 = RTC|GO|IE; 419266Sbill while (upaddr->upds & PIP) 420264Sbill DELAY(25); 421268Sbill needie = 0; 422264Sbill } 4232395Swnj um->um_tab.b_active = 0; 4242395Swnj um->um_tab.b_errcnt = 0; 4252395Swnj um->um_tab.b_actf = dp->b_forw; 426264Sbill dp->b_active = 0; 427264Sbill dp->b_errcnt = 0; 428264Sbill dp->b_actf = bp->av_forw; 429266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 430*2470Swnj /* CHECK FOR WRITE LOCK HERE... */ 431275Sbill if (bp->b_resid) 432341Sbill printf("resid %d ds %o er? %o %o %o\n", 433341Sbill bp->b_resid, upaddr->upds, 434275Sbill upaddr->uper1, upaddr->uper2, upaddr->uper3); 435264Sbill iodone(bp); 4362395Swnj if (dp->b_actf) 4372395Swnj if (upustart(ui)) 438268Sbill needie = 0; 439264Sbill } 440*2470Swnj sc->sc_softas &= ~(1<<ui->ui_slave); 441*2470Swnj ubarelse(ui->ui_ubanum, &sc->sc_info); 442273Sbill } else { 4431756Sbill if (upaddr->upcs1 & TRE) 444264Sbill upaddr->upcs1 = TRE; 445264Sbill } 446*2470Swnj as |= sc->sc_softas; 447*2470Swnj sc->sc_softas = 0; 4482395Swnj for (unit = 0; unit < NUP; unit++) { 4492395Swnj if ((ui = updinfo[unit]) == 0 || ui->ui_mi != um) 4502395Swnj continue; 4512395Swnj if (as & (1<<unit)) { 452*2470Swnj upaddr->upas = 1<<unit; 4532395Swnj if (upustart(ui)) 454273Sbill needie = 0; 455273Sbill } 4562395Swnj } 4572395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 4582395Swnj if (upstart(um)) 459268Sbill needie = 0; 460275Sbill if (needie) 461266Sbill upaddr->upcs1 = IE; 462264Sbill } 463264Sbill 464264Sbill upread(dev) 465264Sbill { 466*2470Swnj 467264Sbill physio(upstrategy, &rupbuf, dev, B_READ, minphys); 468264Sbill } 469264Sbill 470264Sbill upwrite(dev) 471264Sbill { 472*2470Swnj 473264Sbill physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); 474264Sbill } 475264Sbill 476266Sbill /* 477266Sbill * Correct an ECC error, and restart the i/o to complete 478266Sbill * the transfer if necessary. This is quite complicated because 479266Sbill * the transfer may be going to an odd memory address base and/or 480266Sbill * across a page boundary. 481266Sbill */ 4822395Swnj upecc(ui) 4832395Swnj register struct uba_dinfo *ui; 484264Sbill { 4852395Swnj register struct device *up = (struct device *)ui->ui_addr; 4862395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 4872395Swnj register struct uba_minfo *um = ui->ui_mi; 4882395Swnj register struct upst *st; 489*2470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4902395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 491266Sbill register int i; 492264Sbill caddr_t addr; 493266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 494264Sbill int bn, cn, tn, sn; 495264Sbill 496264Sbill /* 497266Sbill * Npf is the number of sectors transferred before the sector 498266Sbill * containing the ECC error, and reg is the UBA register 499266Sbill * mapping (the first part of) the transfer. 500266Sbill * O is offset within a memory page of the first byte transferred. 501264Sbill */ 502266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 503*2470Swnj reg = btop(sc->sc_info&0x3ffff) + npf; 504264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 505264Sbill printf("%D ", bp->b_blkno+npf); 506264Sbill prdev("ECC", bp->b_dev); 507264Sbill mask = up->upec2; 508264Sbill if (mask == 0) { 509266Sbill up->upof = FMT22; /* == RTC ???? */ 510264Sbill return (0); 511264Sbill } 512266Sbill /* 513266Sbill * Flush the buffered data path, and compute the 514266Sbill * byte and bit position of the error. The variable i 515266Sbill * is the byte offset in the transfer, the variable byte 516266Sbill * is the offset from a page boundary in main memory. 517266Sbill */ 518*2470Swnj ubp->uba_dpr[(sc->sc_info>>28)&0x0f] |= UBA_BNE; 519266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 520266Sbill bit = i&07; 521266Sbill i = (i&~07)>>3; 522264Sbill byte = i + o; 523266Sbill /* 524266Sbill * Correct while possible bits remain of mask. Since mask 525266Sbill * contains 11 bits, we continue while the bit offset is > -11. 526266Sbill * Also watch out for end of this block and the end of the whole 527266Sbill * transfer. 528266Sbill */ 529266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 530266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 531266Sbill (byte & PGOFSET); 532266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 533266Sbill byte++; 534266Sbill i++; 535266Sbill bit -= 8; 536264Sbill } 5372395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 538264Sbill if (up->upwc == 0) 539264Sbill return (0); 540266Sbill /* 541266Sbill * Have to continue the transfer... clear the drive, 542266Sbill * and compute the position where the transfer is to continue. 543266Sbill * We have completed npf+1 sectors of the transfer already; 544266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 545266Sbill */ 546266Sbill up->upcs1 = TRE|IE|DCLR|GO; 547264Sbill bn = dkblock(bp); 5482395Swnj st = &upst[ui->ui_type]; 549264Sbill cn = bp->b_cylin; 5502395Swnj sn = bn%st->nspc + npf + 1; 5512395Swnj tn = sn/st->nsect; 5522395Swnj sn %= st->nsect; 5532395Swnj cn += tn/st->ntrak; 5542395Swnj tn %= st->ntrak; 555264Sbill up->updc = cn; 556266Sbill up->upda = (tn << 8) | sn; 557266Sbill ubaddr = (int)ptob(reg+1) + o; 558266Sbill up->upba = ubaddr; 559266Sbill cmd = (ubaddr >> 8) & 0x300; 560266Sbill cmd |= IE|GO|RCOM; 561266Sbill up->upcs1 = cmd; 562264Sbill return (1); 563264Sbill } 564286Sbill 565286Sbill /* 566286Sbill * Reset driver after UBA init. 567286Sbill * Cancel software state of all pending transfers 568286Sbill * and restart all units and the controller. 569286Sbill */ 5702395Swnj upreset(uban) 571286Sbill { 5722395Swnj register struct uba_minfo *um; 5732395Swnj register struct uba_dinfo *ui; 5742395Swnj register sc21, unit; 575*2470Swnj struct up_softc *sc; 5762424Skre int any = 0; 577286Sbill 5782395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 579*2470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 580*2470Swnj um->um_alive == 0) 5812395Swnj continue; 582*2470Swnj sc = &up_softc[um->um_ctlr]; 5832424Skre if (any == 0) { 5842424Skre printf(" up"); 585*2470Swnj DELAY(10000000); /* give it time to self-test */ 5862424Skre any++; 5872424Skre } 5882395Swnj um->um_tab.b_active = 0; 5892395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 590*2470Swnj if (sc->sc_info) { 591*2470Swnj printf("<%d>", (sc->sc_info>>28)&0xf); 592*2470Swnj ubarelse(um->um_ubanum, &sc->sc_info); 5932395Swnj } 5942395Swnj ((struct device *)(um->um_addr))->upcs2 = CLR; 5952395Swnj for (unit = 0; unit < NUP; unit++) { 5962395Swnj if ((ui = updinfo[unit]) == 0) 5972395Swnj continue; 5982395Swnj if (ui->ui_alive == 0) 5992395Swnj continue; 6002395Swnj uputab[unit].b_active = 0; 6012395Swnj (void) upustart(ui); 6022395Swnj } 6032395Swnj (void) upstart(um); 604286Sbill } 605286Sbill } 606313Sbill 607313Sbill /* 608313Sbill * Wake up every second and if an interrupt is pending 609313Sbill * but nothing has happened increment a counter. 610313Sbill * If nothing happens for 20 seconds, reset the controller 611313Sbill * and begin anew. 612313Sbill */ 613313Sbill upwatch() 614313Sbill { 6152395Swnj register struct uba_minfo *um; 6162395Swnj register sc21, unit; 617*2470Swnj register struct up_softc *sc; 618313Sbill 6191783Sbill timeout(upwatch, (caddr_t)0, HZ); 6202395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 6212395Swnj um = upminfo[sc21]; 622*2470Swnj if (um == 0 || um->um_alive == 0) 623*2470Swnj continue; 624*2470Swnj sc = &up_softc[sc21]; 6252395Swnj if (um->um_tab.b_active == 0) { 6262395Swnj for (unit = 0; unit < NUP; unit++) 6272395Swnj if (updinfo[unit]->ui_mi == um && 6282395Swnj uputab[unit].b_active) 6292395Swnj goto active; 630*2470Swnj sc->sc_wticks = 0; 6312395Swnj continue; 6322395Swnj } 6332395Swnj active: 634*2470Swnj sc->sc_wticks++; 635*2470Swnj if (sc->sc_wticks >= 20) { 636*2470Swnj sc->sc_wticks = 0; 6372395Swnj printf("LOST INTERRUPT RESET"); 638*2470Swnj /* SHOULD JUST RESET ONE CTLR, NOT ALL ON UBA */ 6392395Swnj upreset(um->um_ubanum); 6402395Swnj printf("\n"); 6412395Swnj } 642313Sbill } 643313Sbill } 6442379Swnj 6452379Swnj #define DBSIZE 20 6462379Swnj 6472379Swnj updump(dev) 6482379Swnj dev_t dev; 6492379Swnj { 6502379Swnj struct device *upaddr; 6512379Swnj char *start; 6522379Swnj int num, blk, unit, nsect, ntrak, nspc; 6532379Swnj struct size *sizes; 6542395Swnj register struct uba_regs *uba; 6552395Swnj register struct uba_dinfo *ui; 6562379Swnj register short *rp; 6572395Swnj struct upst *st; 6582379Swnj 6592395Swnj unit = minor(dev) >> 3; 6602395Swnj if (unit >= NUP) { 6612395Swnj printf("bad unit\n"); 6622395Swnj return (-1); 6632395Swnj } 664*2470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 6652395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 6662395Swnj if (ui->ui_alive == 0) { 6672395Swnj printf("dna\n"); 6682395Swnj return(-1); 6692395Swnj } 6702395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 6712395Swnj #if VAX780 672*2470Swnj if (cpu == VAX_780) 673*2470Swnj ubainit(uba); 6741809Sbill #endif 6752379Swnj DELAY(1000000); 6762395Swnj upaddr = (struct device *)ui->ui_physaddr; 6772395Swnj while ((upaddr->upcs1&DVA) == 0) 6782379Swnj ; 6792379Swnj num = maxfree; 6802379Swnj start = 0; 6812379Swnj upaddr->upcs2 = unit; 6822379Swnj if ((upaddr->upds & VV) == 0) { 6832379Swnj upaddr->upcs1 = DCLR|GO; 6842379Swnj upaddr->upcs1 = PRESET|GO; 6852379Swnj upaddr->upof = FMT22; 6862379Swnj } 6872379Swnj if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 6882379Swnj printf("up !DPR || !MOL\n"); 6892379Swnj return (-1); 6902379Swnj } 691*2470Swnj st = &upst[ui->ui_type]; 6922395Swnj nsect = st->nsect; 6932395Swnj ntrak = st->ntrak; 6942395Swnj sizes = phys(struct size *, st->sizes); 6952379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 6962395Swnj printf("oor\n"); 6972379Swnj return (-1); 6982379Swnj } 6992395Swnj nspc = st->nspc; 7002379Swnj while (num > 0) { 7012379Swnj register struct pte *io; 7022379Swnj register int i; 7032379Swnj int cn, sn, tn; 7042379Swnj daddr_t bn; 7052379Swnj 7062379Swnj blk = num > DBSIZE ? DBSIZE : num; 7072395Swnj io = uba->uba_map; 7082379Swnj for (i = 0; i < blk; i++) 7092395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 7102379Swnj *(int *)io = 0; 7112379Swnj bn = dumplo + btop(start); 7122379Swnj cn = bn/nspc + sizes[minor(dev)&07].cyloff; 7132379Swnj sn = bn%nspc; 7142379Swnj tn = sn/nsect; 7152379Swnj sn = sn%nsect; 7162379Swnj upaddr->updc = cn; 7172379Swnj rp = (short *) &upaddr->upda; 7182379Swnj *rp = (tn << 8) + sn; 7192379Swnj *--rp = 0; 7202379Swnj *--rp = -blk*NBPG / sizeof (short); 7212379Swnj *--rp = GO|WCOM; 7222379Swnj do { 7232379Swnj DELAY(25); 7242379Swnj } while ((upaddr->upcs1 & RDY) == 0); 7252379Swnj if (upaddr->upcs1&ERR) { 7262379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 7272379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 7282379Swnj return (-1); 7292379Swnj } 7302379Swnj start += blk*NBPG; 7312379Swnj num -= blk; 7322379Swnj } 7332379Swnj return (0); 7342379Swnj } 7351902Swnj #endif 736