1*2571Swnj /* up.c 4.17 81/02/19 */ 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" 23*2571Swnj #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; 312395Swnj int sc_seek; 322395Swnj int sc_wticks; 332424Skre /* struct uba_minfo sc_minfo; */ 342395Swnj } up_softc[NSC21]; 35275Sbill 362395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 37264Sbill struct size 38264Sbill { 39264Sbill daddr_t nblocks; 40264Sbill int cyloff; 41264Sbill } up_sizes[8] = { 42264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 43264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 44341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 45264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 46264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 47264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 48264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 49264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 502395Swnj }, fj_sizes[8] = { 512395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 522395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 532395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 542395Swnj 0, 0, 552395Swnj 0, 0, 562395Swnj 0, 0, 572395Swnj 0, 0, 582395Swnj 213760, 155, /* H=cyl 155 thru 822 */ 59264Sbill }; 602395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 61264Sbill 622395Swnj #define _upSDIST 2 /* 1.0 msec */ 632395Swnj #define _upRDIST 4 /* 2.0 msec */ 64264Sbill 652395Swnj int upSDIST = _upSDIST; 662395Swnj int upRDIST = _upRDIST; 672395Swnj 682395Swnj int upcntrlr(), upslave(), updgo(), upintr(); 692395Swnj struct uba_minfo *upminfo[NSC21]; 702395Swnj struct uba_dinfo *updinfo[NUP]; 712395Swnj 722459Swnj u_short upstd[] = { 0776700, 0774400, 0776300 }; 732395Swnj struct uba_driver updriver = 74*2571Swnj { upcntrlr, upslave, updgo, 0, 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[] = { 842395Swnj 32, 19, 32*19, 815, up_sizes, /* 9300 */ 852395Swnj 32, 19, 32*19, 823, up_sizes, /* so cdc will boot */ 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*/ 1092395Swnj upcntrlr(um, reg) 1102395Swnj struct uba_minfo *um; 1112395Swnj caddr_t reg; 1122395Swnj { 1132459Swnj register int br, cvec; 1142459Swnj 1152395Swnj ((struct device *)reg)->upcs1 |= (IE|RDY); 1162459Swnj return (1); 1172395Swnj } 1182395Swnj 1192459Swnj upslave(ui, reg, slaveno) 1202395Swnj struct uba_dinfo *ui; 1212395Swnj caddr_t reg; 1222395Swnj { 1232395Swnj register struct device *upaddr = (struct device *)reg; 1242395Swnj 1252395Swnj upaddr->upcs1 = 0; /* conservative */ 1262395Swnj upaddr->upcs2 = slaveno; 1272395Swnj if (upaddr->upcs2&NED) { 1282395Swnj upaddr->upcs1 = DCLR|GO; 1292395Swnj return (0); 1302395Swnj } 1312395Swnj if (upwstart == 0) { 1322395Swnj timeout(upwatch, (caddr_t)0, HZ); 1332395Swnj upwstart++; 1342395Swnj } 135*2571Swnj if (ui->ui_dk >= 0) 136*2571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1372395Swnj return (1); 1382395Swnj } 139264Sbill 140264Sbill upstrategy(bp) 1412395Swnj register struct buf *bp; 142264Sbill { 1432395Swnj register struct uba_dinfo *ui; 1442395Swnj register struct upst *st; 1452395Swnj register int unit; 1462470Swnj register struct buf *dp; 1472395Swnj int xunit = minor(bp->b_dev) & 07; 1482470Swnj long bn, sz; 149264Sbill 1502470Swnj sz = (bp->b_bcount+511) >> 9; 151264Sbill unit = dkunit(bp); 1522395Swnj if (unit >= NUP) 1532395Swnj goto bad; 1542395Swnj ui = updinfo[unit]; 1552395Swnj if (ui == 0 || ui->ui_alive == 0) 1562395Swnj goto bad; 1572395Swnj st = &upst[ui->ui_type]; 1582395Swnj if (bp->b_blkno < 0 || 1592395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1602395Swnj goto bad; 1612395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 162264Sbill (void) spl5(); 1632470Swnj dp = &uputab[ui->ui_unit]; 1642470Swnj disksort(dp, bp); 1652470Swnj if (dp->b_active == 0) { 1662395Swnj (void) upustart(ui); 1672395Swnj bp = &ui->ui_mi->um_tab; 1682395Swnj if (bp->b_actf && bp->b_active == 0) 1692395Swnj (void) upstart(ui->ui_mi); 170264Sbill } 171264Sbill (void) spl0(); 1722395Swnj return; 1732395Swnj 1742395Swnj bad: 1752395Swnj bp->b_flags |= B_ERROR; 1762395Swnj iodone(bp); 1772395Swnj return; 178264Sbill } 179264Sbill 1802395Swnj upustart(ui) 1812395Swnj register struct uba_dinfo *ui; 182264Sbill { 183264Sbill register struct buf *bp, *dp; 1842395Swnj register struct uba_minfo *um; 1852395Swnj register struct device *upaddr; 1862395Swnj register struct upst *st; 187264Sbill daddr_t bn; 188264Sbill int sn, cn, csn; 189268Sbill int didie = 0; 190264Sbill 1912395Swnj /* SC21 cancels commands if you say cs1 = IE, so dont */ 1922395Swnj /* being ultra-cautious, we clear as bits only in upintr() */ 1932395Swnj dk_busy &= ~(1<<ui->ui_dk); 1942395Swnj dp = &uputab[ui->ui_unit]; 195266Sbill if ((bp = dp->b_actf) == NULL) 196268Sbill goto out; 1972395Swnj /* dont confuse controller by giving SEARCH while dt in progress */ 1982395Swnj um = ui->ui_mi; 1992395Swnj if (um->um_tab.b_active) { 2002459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 201275Sbill return (0); 202275Sbill } 203276Sbill if (dp->b_active) 204276Sbill goto done; 205276Sbill dp->b_active = 1; 2062395Swnj upaddr = (struct device *)um->um_addr; 2072395Swnj upaddr->upcs2 = ui->ui_slave; 208266Sbill if ((upaddr->upds & VV) == 0) { 209266Sbill upaddr->upcs1 = IE|DCLR|GO; 210264Sbill upaddr->upcs1 = IE|PRESET|GO; 211264Sbill upaddr->upof = FMT22; 212268Sbill didie = 1; 213264Sbill } 214264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 215275Sbill goto done; 2162395Swnj st = &upst[ui->ui_type]; 217264Sbill bn = dkblock(bp); 218264Sbill cn = bp->b_cylin; 2192395Swnj sn = bn%st->nspc; 2202395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 221266Sbill if (cn - upaddr->updc) 222266Sbill goto search; /* Not on-cylinder */ 223275Sbill else if (upseek) 224275Sbill goto done; /* Ok just to be on-cylinder */ 225264Sbill csn = (upaddr->upla>>6) - sn - 1; 226266Sbill if (csn < 0) 2272395Swnj csn += st->nsect; 2282395Swnj if (csn > st->nsect - upRDIST) 229264Sbill goto done; 230264Sbill search: 231264Sbill upaddr->updc = cn; 232275Sbill if (upseek) 233275Sbill upaddr->upcs1 = IE|SEEK|GO; 2342470Swnj else { 235275Sbill upaddr->upda = sn; 236275Sbill upaddr->upcs1 = IE|SEARCH|GO; 237275Sbill } 238268Sbill didie = 1; 2392395Swnj if (ui->ui_dk >= 0) { 2402395Swnj dk_busy |= 1<<ui->ui_dk; 2412395Swnj dk_seek[ui->ui_dk]++; 242264Sbill } 243268Sbill goto out; 244264Sbill done: 245264Sbill dp->b_forw = NULL; 2462395Swnj if (um->um_tab.b_actf == NULL) 2472395Swnj um->um_tab.b_actf = dp; 248264Sbill else 2492395Swnj um->um_tab.b_actl->b_forw = dp; 2502395Swnj um->um_tab.b_actl = dp; 251268Sbill out: 252268Sbill return (didie); 253264Sbill } 254264Sbill 2552395Swnj upstart(um) 2562395Swnj register struct uba_minfo *um; 257264Sbill { 258264Sbill register struct buf *bp, *dp; 2592395Swnj register struct uba_dinfo *ui; 260264Sbill register unit; 261264Sbill register struct device *upaddr; 2622470Swnj struct upst *st; 2632470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 264264Sbill daddr_t bn; 2652424Skre int dn, sn, tn, cmd; 266264Sbill 267264Sbill loop: 2682395Swnj if ((dp = um->um_tab.b_actf) == NULL) 269268Sbill return (0); 270264Sbill if ((bp = dp->b_actf) == NULL) { 2712395Swnj um->um_tab.b_actf = dp->b_forw; 272264Sbill goto loop; 273264Sbill } 274266Sbill /* 275266Sbill * Mark the controller busy, and multi-part disk address. 276266Sbill * Select the unit on which the i/o is to take place. 277266Sbill */ 2782395Swnj um->um_tab.b_active++; 2792395Swnj ui = updinfo[dkunit(bp)]; 280264Sbill bn = dkblock(bp); 2812395Swnj dn = ui->ui_slave; 2822395Swnj st = &upst[ui->ui_type]; 2832395Swnj sn = bn%st->nspc; 2842395Swnj tn = sn/st->nsect; 2852395Swnj sn %= st->nsect; 2862395Swnj upaddr = (struct device *)ui->ui_addr; 2871756Sbill if ((upaddr->upcs2 & 07) != dn) 288264Sbill upaddr->upcs2 = dn; 289266Sbill /* 290266Sbill * If drive is not present and on-line, then 291266Sbill * get rid of this with an error and loop to get 292266Sbill * rid of the rest of its queued requests. 293266Sbill * (Then on to any other ready drives.) 294266Sbill */ 295264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 296893Sbill printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds); 297893Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 298893Sbill printf("-- hard\n"); 2992395Swnj um->um_tab.b_active = 0; 3002395Swnj um->um_tab.b_errcnt = 0; 301893Sbill dp->b_actf = bp->av_forw; 302893Sbill dp->b_active = 0; 303893Sbill bp->b_flags |= B_ERROR; 304893Sbill iodone(bp); 305893Sbill goto loop; 306893Sbill } 307893Sbill printf("-- came back\n"); 308264Sbill } 309266Sbill /* 310266Sbill * If this is a retry, then with the 16'th retry we 311266Sbill * begin to try offsetting the heads to recover the data. 312266Sbill */ 3132395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 3142395Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | FMT22; 315266Sbill upaddr->upcs1 = IE|OFFSET|GO; 316266Sbill while (upaddr->upds & PIP) 317264Sbill DELAY(25); 318264Sbill } 319266Sbill /* 320266Sbill * Now set up the transfer, retrieving the high 321266Sbill * 2 bits of the UNIBUS address from the information 322266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 323266Sbill */ 3242424Skre upaddr->updc = bp->b_cylin; 325264Sbill upaddr->upda = (tn << 8) + sn; 326264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 327264Sbill if (bp->b_flags & B_READ) 328*2571Swnj cmd = IE|RCOM|GO; 329264Sbill else 330*2571Swnj cmd = IE|WCOM|GO; 331*2571Swnj um->um_cmd = cmd; 332*2571Swnj ubago(ui); 333268Sbill return (1); 334264Sbill } 335264Sbill 336*2571Swnj updgo(um) 337*2571Swnj struct uba_minfo *um; 3382395Swnj { 339*2571Swnj register struct device *upaddr = (struct device *)um->um_addr; 3402470Swnj 341*2571Swnj upaddr->upba = um->um_ubinfo; 342*2571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 3432395Swnj } 3442395Swnj 345264Sbill /* 346264Sbill * Handle a device interrupt. 347264Sbill * 348264Sbill * If the transferring drive needs attention, service it 349264Sbill * retrying on error or beginning next transfer. 350264Sbill * Service all other ready drives, calling ustart to transfer 3512395Swnj * their blocks to the ready queue in um->um_tab, and then restart 352264Sbill * the controller if there is anything to do. 353264Sbill */ 3542395Swnj upintr(sc21) 3552395Swnj register sc21; 356264Sbill { 357264Sbill register struct buf *bp, *dp; 3582395Swnj register struct uba_minfo *um = upminfo[sc21]; 3592395Swnj register struct uba_dinfo *ui; 3602395Swnj register struct device *upaddr = (struct device *)um->um_addr; 361264Sbill register unit; 3622470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 363264Sbill int as = upaddr->upas & 0377; 364268Sbill int needie = 1; 365264Sbill 3662470Swnj sc->sc_wticks = 0; 3672395Swnj if (um->um_tab.b_active) { 3682470Swnj if ((upaddr->upcs1 & RDY) == 0) 3692470Swnj printf("upintr !RDY\n"); 3702395Swnj dp = um->um_tab.b_actf; 371264Sbill bp = dp->b_actf; 3722395Swnj ui = updinfo[dkunit(bp)]; 3732395Swnj dk_busy &= ~(1 << ui->ui_dk); 3742395Swnj upaddr->upcs2 = ui->ui_slave; 375885Sbill if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) { 3761829Sbill int cs2; 377266Sbill while ((upaddr->upds & DRY) == 0) 378264Sbill DELAY(25); 3792395Swnj if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE) 380264Sbill bp->b_flags |= B_ERROR; 381264Sbill else 3822395Swnj um->um_tab.b_active = 0; /* force retry */ 3832395Swnj if (um->um_tab.b_errcnt > 27) { 3841829Sbill cs2 = (int)upaddr->upcs2; 3852395Swnj deverror(bp, cs2, (int)upaddr->uper1); 3862395Swnj } 3872395Swnj if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui)) 388266Sbill return; 389264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 390268Sbill needie = 0; 3912395Swnj if ((um->um_tab.b_errcnt&07) == 4) { 392264Sbill upaddr->upcs1 = RECAL|GO|IE; 393264Sbill while(upaddr->upds & PIP) 394264Sbill DELAY(25); 395264Sbill } 3962395Swnj if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) { 3971829Sbill printf("FLAKEY UP "); 3982395Swnj ubareset(um->um_ubanum); 3991829Sbill return; 4001829Sbill } 401264Sbill } 402*2571Swnj ubarelse(ui->ui_ubanum, &um->um_ubinfo); 4032395Swnj if (um->um_tab.b_active) { 4042395Swnj if (um->um_tab.b_errcnt >= 16) { 405266Sbill upaddr->upcs1 = RTC|GO|IE; 406266Sbill while (upaddr->upds & PIP) 407264Sbill DELAY(25); 408268Sbill needie = 0; 409264Sbill } 4102395Swnj um->um_tab.b_active = 0; 4112395Swnj um->um_tab.b_errcnt = 0; 4122395Swnj um->um_tab.b_actf = dp->b_forw; 413264Sbill dp->b_active = 0; 414264Sbill dp->b_errcnt = 0; 415264Sbill dp->b_actf = bp->av_forw; 416266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 4172470Swnj /* CHECK FOR WRITE LOCK HERE... */ 418275Sbill if (bp->b_resid) 419341Sbill printf("resid %d ds %o er? %o %o %o\n", 420341Sbill bp->b_resid, upaddr->upds, 421275Sbill upaddr->uper1, upaddr->uper2, upaddr->uper3); 422264Sbill iodone(bp); 4232395Swnj if (dp->b_actf) 4242395Swnj if (upustart(ui)) 425268Sbill needie = 0; 426264Sbill } 4272470Swnj sc->sc_softas &= ~(1<<ui->ui_slave); 428273Sbill } else { 4291756Sbill if (upaddr->upcs1 & TRE) 430264Sbill upaddr->upcs1 = TRE; 431264Sbill } 4322470Swnj as |= sc->sc_softas; 4332470Swnj sc->sc_softas = 0; 4342395Swnj for (unit = 0; unit < NUP; unit++) { 4352395Swnj if ((ui = updinfo[unit]) == 0 || ui->ui_mi != um) 4362395Swnj continue; 4372395Swnj if (as & (1<<unit)) { 4382470Swnj upaddr->upas = 1<<unit; 4392395Swnj if (upustart(ui)) 440273Sbill needie = 0; 441273Sbill } 4422395Swnj } 4432395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 4442395Swnj if (upstart(um)) 445268Sbill needie = 0; 446275Sbill if (needie) 447266Sbill upaddr->upcs1 = IE; 448264Sbill } 449264Sbill 450264Sbill upread(dev) 451264Sbill { 4522470Swnj 453264Sbill physio(upstrategy, &rupbuf, dev, B_READ, minphys); 454264Sbill } 455264Sbill 456264Sbill upwrite(dev) 457264Sbill { 4582470Swnj 459264Sbill physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); 460264Sbill } 461264Sbill 462266Sbill /* 463266Sbill * Correct an ECC error, and restart the i/o to complete 464266Sbill * the transfer if necessary. This is quite complicated because 465266Sbill * the transfer may be going to an odd memory address base and/or 466266Sbill * across a page boundary. 467266Sbill */ 4682395Swnj upecc(ui) 4692395Swnj register struct uba_dinfo *ui; 470264Sbill { 4712395Swnj register struct device *up = (struct device *)ui->ui_addr; 4722395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 4732395Swnj register struct uba_minfo *um = ui->ui_mi; 4742395Swnj register struct upst *st; 4752470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4762395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 477266Sbill register int i; 478264Sbill caddr_t addr; 479266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 480264Sbill int bn, cn, tn, sn; 481264Sbill 482264Sbill /* 483266Sbill * Npf is the number of sectors transferred before the sector 484266Sbill * containing the ECC error, and reg is the UBA register 485266Sbill * mapping (the first part of) the transfer. 486266Sbill * O is offset within a memory page of the first byte transferred. 487264Sbill */ 488266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 489*2571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 490264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 491264Sbill printf("%D ", bp->b_blkno+npf); 492264Sbill prdev("ECC", bp->b_dev); 493264Sbill mask = up->upec2; 494264Sbill if (mask == 0) { 495266Sbill up->upof = FMT22; /* == RTC ???? */ 496264Sbill return (0); 497264Sbill } 498266Sbill /* 499266Sbill * Flush the buffered data path, and compute the 500266Sbill * byte and bit position of the error. The variable i 501266Sbill * is the byte offset in the transfer, the variable byte 502266Sbill * is the offset from a page boundary in main memory. 503266Sbill */ 504*2571Swnj ubp->uba_dpr[(um->um_ubinfo>>28)&0x0f] |= UBA_BNE; 505266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 506266Sbill bit = i&07; 507266Sbill i = (i&~07)>>3; 508264Sbill byte = i + o; 509266Sbill /* 510266Sbill * Correct while possible bits remain of mask. Since mask 511266Sbill * contains 11 bits, we continue while the bit offset is > -11. 512266Sbill * Also watch out for end of this block and the end of the whole 513266Sbill * transfer. 514266Sbill */ 515266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 516266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 517266Sbill (byte & PGOFSET); 518266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 519266Sbill byte++; 520266Sbill i++; 521266Sbill bit -= 8; 522264Sbill } 5232395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 524264Sbill if (up->upwc == 0) 525264Sbill return (0); 526266Sbill /* 527266Sbill * Have to continue the transfer... clear the drive, 528266Sbill * and compute the position where the transfer is to continue. 529266Sbill * We have completed npf+1 sectors of the transfer already; 530266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 531266Sbill */ 532266Sbill up->upcs1 = TRE|IE|DCLR|GO; 533264Sbill bn = dkblock(bp); 5342395Swnj st = &upst[ui->ui_type]; 535264Sbill cn = bp->b_cylin; 5362395Swnj sn = bn%st->nspc + npf + 1; 5372395Swnj tn = sn/st->nsect; 5382395Swnj sn %= st->nsect; 5392395Swnj cn += tn/st->ntrak; 5402395Swnj tn %= st->ntrak; 541264Sbill up->updc = cn; 542266Sbill up->upda = (tn << 8) | sn; 543266Sbill ubaddr = (int)ptob(reg+1) + o; 544266Sbill up->upba = ubaddr; 545266Sbill cmd = (ubaddr >> 8) & 0x300; 546266Sbill cmd |= IE|GO|RCOM; 547266Sbill up->upcs1 = cmd; 548264Sbill return (1); 549264Sbill } 550286Sbill 551286Sbill /* 552286Sbill * Reset driver after UBA init. 553286Sbill * Cancel software state of all pending transfers 554286Sbill * and restart all units and the controller. 555286Sbill */ 5562395Swnj upreset(uban) 557286Sbill { 5582395Swnj register struct uba_minfo *um; 5592395Swnj register struct uba_dinfo *ui; 5602395Swnj register sc21, unit; 5612470Swnj struct up_softc *sc; 5622424Skre int any = 0; 563286Sbill 5642395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 5652470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 5662470Swnj um->um_alive == 0) 5672395Swnj continue; 5682470Swnj sc = &up_softc[um->um_ctlr]; 5692424Skre if (any == 0) { 5702424Skre printf(" up"); 5712470Swnj DELAY(10000000); /* give it time to self-test */ 5722424Skre any++; 5732424Skre } 5742395Swnj um->um_tab.b_active = 0; 5752395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 576*2571Swnj if (um->um_ubinfo) { 577*2571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 578*2571Swnj ubarelse(um->um_ubanum, &um->um_ubinfo); 5792395Swnj } 5802395Swnj ((struct device *)(um->um_addr))->upcs2 = CLR; 5812395Swnj for (unit = 0; unit < NUP; unit++) { 5822395Swnj if ((ui = updinfo[unit]) == 0) 5832395Swnj continue; 5842395Swnj if (ui->ui_alive == 0) 5852395Swnj continue; 5862395Swnj uputab[unit].b_active = 0; 5872395Swnj (void) upustart(ui); 5882395Swnj } 5892395Swnj (void) upstart(um); 590286Sbill } 591286Sbill } 592313Sbill 593313Sbill /* 594313Sbill * Wake up every second and if an interrupt is pending 595313Sbill * but nothing has happened increment a counter. 596313Sbill * If nothing happens for 20 seconds, reset the controller 597313Sbill * and begin anew. 598313Sbill */ 599313Sbill upwatch() 600313Sbill { 6012395Swnj register struct uba_minfo *um; 6022395Swnj register sc21, unit; 6032470Swnj register struct up_softc *sc; 604313Sbill 6051783Sbill timeout(upwatch, (caddr_t)0, HZ); 6062395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 6072395Swnj um = upminfo[sc21]; 6082470Swnj if (um == 0 || um->um_alive == 0) 6092470Swnj continue; 6102470Swnj sc = &up_softc[sc21]; 6112395Swnj if (um->um_tab.b_active == 0) { 6122395Swnj for (unit = 0; unit < NUP; unit++) 6132395Swnj if (updinfo[unit]->ui_mi == um && 6142395Swnj uputab[unit].b_active) 6152395Swnj goto active; 6162470Swnj sc->sc_wticks = 0; 6172395Swnj continue; 6182395Swnj } 6192395Swnj active: 6202470Swnj sc->sc_wticks++; 6212470Swnj if (sc->sc_wticks >= 20) { 6222470Swnj sc->sc_wticks = 0; 6232395Swnj printf("LOST INTERRUPT RESET"); 6242470Swnj /* SHOULD JUST RESET ONE CTLR, NOT ALL ON UBA */ 6252395Swnj upreset(um->um_ubanum); 6262395Swnj printf("\n"); 6272395Swnj } 628313Sbill } 629313Sbill } 6302379Swnj 6312379Swnj #define DBSIZE 20 6322379Swnj 6332379Swnj updump(dev) 6342379Swnj dev_t dev; 6352379Swnj { 6362379Swnj struct device *upaddr; 6372379Swnj char *start; 6382379Swnj int num, blk, unit, nsect, ntrak, nspc; 6392379Swnj struct size *sizes; 6402395Swnj register struct uba_regs *uba; 6412395Swnj register struct uba_dinfo *ui; 6422379Swnj register short *rp; 6432395Swnj struct upst *st; 6442379Swnj 6452395Swnj unit = minor(dev) >> 3; 6462395Swnj if (unit >= NUP) { 6472395Swnj printf("bad unit\n"); 6482395Swnj return (-1); 6492395Swnj } 6502470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 6512395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 6522395Swnj if (ui->ui_alive == 0) { 6532395Swnj printf("dna\n"); 6542395Swnj return(-1); 6552395Swnj } 6562395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 6572395Swnj #if VAX780 6582470Swnj if (cpu == VAX_780) 6592470Swnj ubainit(uba); 6601809Sbill #endif 6612379Swnj DELAY(1000000); 6622395Swnj upaddr = (struct device *)ui->ui_physaddr; 6632395Swnj while ((upaddr->upcs1&DVA) == 0) 6642379Swnj ; 6652379Swnj num = maxfree; 6662379Swnj start = 0; 6672379Swnj upaddr->upcs2 = unit; 6682379Swnj if ((upaddr->upds & VV) == 0) { 6692379Swnj upaddr->upcs1 = DCLR|GO; 6702379Swnj upaddr->upcs1 = PRESET|GO; 6712379Swnj upaddr->upof = FMT22; 6722379Swnj } 6732379Swnj if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 6742379Swnj printf("up !DPR || !MOL\n"); 6752379Swnj return (-1); 6762379Swnj } 6772470Swnj st = &upst[ui->ui_type]; 6782395Swnj nsect = st->nsect; 6792395Swnj ntrak = st->ntrak; 6802395Swnj sizes = phys(struct size *, st->sizes); 6812379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 6822395Swnj printf("oor\n"); 6832379Swnj return (-1); 6842379Swnj } 6852395Swnj nspc = st->nspc; 6862379Swnj while (num > 0) { 6872379Swnj register struct pte *io; 6882379Swnj register int i; 6892379Swnj int cn, sn, tn; 6902379Swnj daddr_t bn; 6912379Swnj 6922379Swnj blk = num > DBSIZE ? DBSIZE : num; 6932395Swnj io = uba->uba_map; 6942379Swnj for (i = 0; i < blk; i++) 6952395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 6962379Swnj *(int *)io = 0; 6972379Swnj bn = dumplo + btop(start); 6982379Swnj cn = bn/nspc + sizes[minor(dev)&07].cyloff; 6992379Swnj sn = bn%nspc; 7002379Swnj tn = sn/nsect; 7012379Swnj sn = sn%nsect; 7022379Swnj upaddr->updc = cn; 7032379Swnj rp = (short *) &upaddr->upda; 7042379Swnj *rp = (tn << 8) + sn; 7052379Swnj *--rp = 0; 7062379Swnj *--rp = -blk*NBPG / sizeof (short); 7072379Swnj *--rp = GO|WCOM; 7082379Swnj do { 7092379Swnj DELAY(25); 7102379Swnj } while ((upaddr->upcs1 & RDY) == 0); 7112379Swnj if (upaddr->upcs1&ERR) { 7122379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 7132379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 7142379Swnj return (-1); 7152379Swnj } 7162379Swnj start += blk*NBPG; 7172379Swnj num -= blk; 7182379Swnj } 7192379Swnj return (0); 7202379Swnj } 7211902Swnj #endif 722