1*2616Swnj /* up.c 4.19 81/02/22 */ 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; 312607Swnj 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 672607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 682395Swnj struct uba_minfo *upminfo[NSC21]; 692395Swnj struct uba_dinfo *updinfo[NUP]; 702607Swnj struct uba_dinfo *upip[NSC21][4]; 712395Swnj 722607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 73*2616Swnj 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 89*2616Swnj u_char up_offset[16] = 90*2616Swnj { P400,M400,P400,M400,P800,M800,P800,M800,P1200,M1200,P1200,M1200,0,0,0,0 }; 91264Sbill 92*2616Swnj struct buf rupbuf[NUP]; 93264Sbill 94264Sbill #define b_cylin b_resid 95264Sbill 96264Sbill #ifdef INTRLVE 97264Sbill daddr_t dkblock(); 98264Sbill #endif 992395Swnj 1002395Swnj int upwstart, upwatch(); /* Have started guardian */ 1012470Swnj int upseek; 1022395Swnj 1032395Swnj /*ARGSUSED*/ 1042607Swnj upprobe(reg) 1052395Swnj caddr_t reg; 1062395Swnj { 1072459Swnj register int br, cvec; 1082459Swnj 1092607Swnj #ifdef lint 1102607Swnj br = 0; cvec = br; br = cvec; 1112607Swnj #endif 1122607Swnj ((struct device *)reg)->upcs1 = (IE|RDY); 1132607Swnj DELAY(10); 1142607Swnj ((struct device *)reg)->upcs1 = 0; 1152459Swnj return (1); 1162395Swnj } 1172395Swnj 1182607Swnj upslave(ui, reg) 1192395Swnj struct uba_dinfo *ui; 1202395Swnj caddr_t reg; 1212395Swnj { 1222395Swnj register struct device *upaddr = (struct device *)reg; 1232395Swnj 1242395Swnj upaddr->upcs1 = 0; /* conservative */ 1252607Swnj upaddr->upcs2 = ui->ui_slave; 1262395Swnj if (upaddr->upcs2&NED) { 1272395Swnj upaddr->upcs1 = DCLR|GO; 1282395Swnj return (0); 1292395Swnj } 1302607Swnj return (1); 1312607Swnj } 1322607Swnj 1332607Swnj upattach(ui) 1342607Swnj register struct uba_dinfo *ui; 1352607Swnj { 1362607Swnj 1372395Swnj if (upwstart == 0) { 1382395Swnj timeout(upwatch, (caddr_t)0, HZ); 1392395Swnj upwstart++; 1402395Swnj } 1412571Swnj if (ui->ui_dk >= 0) 1422571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1432607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1442607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1452395Swnj } 146264Sbill 147264Sbill upstrategy(bp) 1482395Swnj register struct buf *bp; 149264Sbill { 1502395Swnj register struct uba_dinfo *ui; 1512395Swnj register struct upst *st; 1522395Swnj register int unit; 1532470Swnj register struct buf *dp; 1542395Swnj int xunit = minor(bp->b_dev) & 07; 1552470Swnj long bn, sz; 156264Sbill 1572470Swnj sz = (bp->b_bcount+511) >> 9; 158264Sbill unit = dkunit(bp); 1592395Swnj if (unit >= NUP) 1602395Swnj goto bad; 1612395Swnj ui = updinfo[unit]; 1622395Swnj if (ui == 0 || ui->ui_alive == 0) 1632395Swnj goto bad; 1642395Swnj st = &upst[ui->ui_type]; 1652395Swnj if (bp->b_blkno < 0 || 1662395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1672395Swnj goto bad; 1682395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 169264Sbill (void) spl5(); 1702470Swnj dp = &uputab[ui->ui_unit]; 1712470Swnj disksort(dp, bp); 1722470Swnj if (dp->b_active == 0) { 1732395Swnj (void) upustart(ui); 1742395Swnj bp = &ui->ui_mi->um_tab; 1752395Swnj if (bp->b_actf && bp->b_active == 0) 1762395Swnj (void) upstart(ui->ui_mi); 177264Sbill } 178264Sbill (void) spl0(); 1792395Swnj return; 1802395Swnj 1812395Swnj bad: 1822395Swnj bp->b_flags |= B_ERROR; 1832395Swnj iodone(bp); 1842395Swnj return; 185264Sbill } 186264Sbill 1872395Swnj upustart(ui) 1882395Swnj register struct uba_dinfo *ui; 189264Sbill { 190264Sbill register struct buf *bp, *dp; 1912395Swnj register struct uba_minfo *um; 1922395Swnj register struct device *upaddr; 1932395Swnj register struct upst *st; 194264Sbill daddr_t bn; 195264Sbill int sn, cn, csn; 196268Sbill int didie = 0; 197264Sbill 1982607Swnj if (ui == 0) 1992607Swnj return (0); 2002607Swnj /* 2012607Swnj * The SC21 cancels commands if you just say 2022607Swnj * cs1 = IE 2032607Swnj * so we are cautious about handling of cs1. 2042607Swnj * Also don't bother to clear as bits other than in upintr(). 2052607Swnj */ 2062395Swnj dk_busy &= ~(1<<ui->ui_dk); 2072395Swnj dp = &uputab[ui->ui_unit]; 208266Sbill if ((bp = dp->b_actf) == NULL) 209268Sbill goto out; 2102395Swnj /* dont confuse controller by giving SEARCH while dt in progress */ 2112395Swnj um = ui->ui_mi; 2122395Swnj if (um->um_tab.b_active) { 2132459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 214275Sbill return (0); 215275Sbill } 216276Sbill if (dp->b_active) 217276Sbill goto done; 218276Sbill dp->b_active = 1; 2192395Swnj upaddr = (struct device *)um->um_addr; 2202395Swnj upaddr->upcs2 = ui->ui_slave; 221266Sbill if ((upaddr->upds & VV) == 0) { 2222607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 223266Sbill upaddr->upcs1 = IE|DCLR|GO; 224264Sbill upaddr->upcs1 = IE|PRESET|GO; 225264Sbill upaddr->upof = FMT22; 226268Sbill didie = 1; 227264Sbill } 228264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 229275Sbill goto done; 2302607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 2312607Swnj goto done; 2322395Swnj st = &upst[ui->ui_type]; 233264Sbill bn = dkblock(bp); 234264Sbill cn = bp->b_cylin; 2352395Swnj sn = bn%st->nspc; 2362395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 237266Sbill if (cn - upaddr->updc) 238266Sbill goto search; /* Not on-cylinder */ 239275Sbill else if (upseek) 240275Sbill goto done; /* Ok just to be on-cylinder */ 241264Sbill csn = (upaddr->upla>>6) - sn - 1; 242266Sbill if (csn < 0) 2432395Swnj csn += st->nsect; 2442395Swnj if (csn > st->nsect - upRDIST) 245264Sbill goto done; 246264Sbill search: 247264Sbill upaddr->updc = cn; 248275Sbill if (upseek) 249275Sbill upaddr->upcs1 = IE|SEEK|GO; 2502470Swnj else { 251275Sbill upaddr->upda = sn; 252275Sbill upaddr->upcs1 = IE|SEARCH|GO; 253275Sbill } 254268Sbill didie = 1; 2552395Swnj if (ui->ui_dk >= 0) { 2562395Swnj dk_busy |= 1<<ui->ui_dk; 2572395Swnj dk_seek[ui->ui_dk]++; 258264Sbill } 259268Sbill goto out; 260264Sbill done: 261264Sbill dp->b_forw = NULL; 2622395Swnj if (um->um_tab.b_actf == NULL) 2632395Swnj um->um_tab.b_actf = dp; 264264Sbill else 2652395Swnj um->um_tab.b_actl->b_forw = dp; 2662395Swnj um->um_tab.b_actl = dp; 267268Sbill out: 268268Sbill return (didie); 269264Sbill } 270264Sbill 2712395Swnj upstart(um) 2722395Swnj register struct uba_minfo *um; 273264Sbill { 274264Sbill register struct buf *bp, *dp; 2752395Swnj register struct uba_dinfo *ui; 276264Sbill register struct device *upaddr; 2772470Swnj struct upst *st; 278264Sbill daddr_t bn; 2792424Skre int dn, sn, tn, cmd; 280264Sbill 281264Sbill loop: 2822395Swnj if ((dp = um->um_tab.b_actf) == NULL) 283268Sbill return (0); 284264Sbill if ((bp = dp->b_actf) == NULL) { 2852395Swnj um->um_tab.b_actf = dp->b_forw; 286264Sbill goto loop; 287264Sbill } 288266Sbill /* 289266Sbill * Mark the controller busy, and multi-part disk address. 290266Sbill * Select the unit on which the i/o is to take place. 291266Sbill */ 2922395Swnj um->um_tab.b_active++; 2932395Swnj ui = updinfo[dkunit(bp)]; 294264Sbill bn = dkblock(bp); 2952395Swnj dn = ui->ui_slave; 2962395Swnj st = &upst[ui->ui_type]; 2972395Swnj sn = bn%st->nspc; 2982395Swnj tn = sn/st->nsect; 2992395Swnj sn %= st->nsect; 3002395Swnj upaddr = (struct device *)ui->ui_addr; 3012607Swnj upaddr->upcs2 = dn; 302266Sbill /* 303266Sbill * If drive is not present and on-line, then 304266Sbill * get rid of this with an error and loop to get 305266Sbill * rid of the rest of its queued requests. 306266Sbill * (Then on to any other ready drives.) 307266Sbill */ 308264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 3092607Swnj printf("up%d not ready", dkunit(bp)); 310893Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 3112607Swnj printf("\n"); 3122395Swnj um->um_tab.b_active = 0; 3132395Swnj um->um_tab.b_errcnt = 0; 314893Sbill dp->b_actf = bp->av_forw; 315893Sbill dp->b_active = 0; 316893Sbill bp->b_flags |= B_ERROR; 317893Sbill iodone(bp); 318893Sbill goto loop; 319893Sbill } 3202607Swnj printf(" (flakey... it came back)\n"); 321264Sbill } 322266Sbill /* 323266Sbill * If this is a retry, then with the 16'th retry we 324266Sbill * begin to try offsetting the heads to recover the data. 325266Sbill */ 3262395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 3272395Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | FMT22; 328266Sbill upaddr->upcs1 = IE|OFFSET|GO; 329266Sbill while (upaddr->upds & PIP) 330264Sbill DELAY(25); 331264Sbill } 332266Sbill /* 333266Sbill * Now set up the transfer, retrieving the high 334266Sbill * 2 bits of the UNIBUS address from the information 335266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 336266Sbill */ 3372424Skre upaddr->updc = bp->b_cylin; 338264Sbill upaddr->upda = (tn << 8) + sn; 339264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 340264Sbill if (bp->b_flags & B_READ) 3412571Swnj cmd = IE|RCOM|GO; 342264Sbill else 3432571Swnj cmd = IE|WCOM|GO; 3442571Swnj um->um_cmd = cmd; 3452571Swnj ubago(ui); 346268Sbill return (1); 347264Sbill } 348264Sbill 3492571Swnj updgo(um) 3502571Swnj struct uba_minfo *um; 3512395Swnj { 3522571Swnj register struct device *upaddr = (struct device *)um->um_addr; 3532470Swnj 3542571Swnj upaddr->upba = um->um_ubinfo; 3552571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 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 */ 367*2616Swnj scintr(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; 3752470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 3762607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 377268Sbill int needie = 1; 378264Sbill 3792470Swnj sc->sc_wticks = 0; 3802607Swnj sc->sc_softas = 0; 3812395Swnj if (um->um_tab.b_active) { 3822470Swnj if ((upaddr->upcs1 & RDY) == 0) 3832470Swnj 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); 3932607Swnj if (upaddr->uper1&WLE) 3942607Swnj printf("up%d is write locked\n", dkunit(bp)); 3952395Swnj if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE) 396264Sbill bp->b_flags |= B_ERROR; 397264Sbill else 3982395Swnj um->um_tab.b_active = 0; /* force retry */ 3992395Swnj if (um->um_tab.b_errcnt > 27) { 4001829Sbill cs2 = (int)upaddr->upcs2; 4012395Swnj deverror(bp, cs2, (int)upaddr->uper1); 4022395Swnj } 4032395Swnj if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui)) 404266Sbill return; 405264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 406268Sbill needie = 0; 4072395Swnj if ((um->um_tab.b_errcnt&07) == 4) { 408264Sbill upaddr->upcs1 = RECAL|GO|IE; 409264Sbill while(upaddr->upds & PIP) 410264Sbill DELAY(25); 411264Sbill } 4122395Swnj if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) { 4131829Sbill printf("FLAKEY UP "); 4142395Swnj ubareset(um->um_ubanum); 4151829Sbill return; 4161829Sbill } 417264Sbill } 418*2616Swnj ubadone(um); 4192395Swnj if (um->um_tab.b_active) { 4202395Swnj if (um->um_tab.b_errcnt >= 16) { 421266Sbill upaddr->upcs1 = RTC|GO|IE; 422266Sbill while (upaddr->upds & PIP) 423264Sbill DELAY(25); 424268Sbill needie = 0; 425264Sbill } 4262395Swnj um->um_tab.b_active = 0; 4272395Swnj um->um_tab.b_errcnt = 0; 4282395Swnj um->um_tab.b_actf = dp->b_forw; 429264Sbill dp->b_active = 0; 430264Sbill dp->b_errcnt = 0; 431264Sbill dp->b_actf = bp->av_forw; 432266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 433264Sbill iodone(bp); 4342395Swnj if (dp->b_actf) 4352395Swnj if (upustart(ui)) 436268Sbill needie = 0; 437264Sbill } 4382607Swnj as &= ~(1<<ui->ui_slave); 439273Sbill } else { 4401756Sbill if (upaddr->upcs1 & TRE) 441264Sbill upaddr->upcs1 = TRE; 442264Sbill } 4432607Swnj for (unit = 0; as; as >>= 1, unit++) 4442607Swnj if (as & 1) { 4452470Swnj upaddr->upas = 1<<unit; 4462607Swnj if (upustart(upip[sc21][unit])) 447273Sbill needie = 0; 448273Sbill } 4492395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 4502395Swnj if (upstart(um)) 451268Sbill needie = 0; 452275Sbill if (needie) 453266Sbill upaddr->upcs1 = IE; 454264Sbill } 455264Sbill 456264Sbill upread(dev) 457*2616Swnj dev_t dev; 458264Sbill { 459*2616Swnj register int unit = minor(dev) >> 3; 4602470Swnj 461*2616Swnj if (unit >= NUP) 462*2616Swnj u.u_error = ENXIO; 463*2616Swnj else 464*2616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 465264Sbill } 466264Sbill 467264Sbill upwrite(dev) 468*2616Swnj dev_t dev; 469264Sbill { 470*2616Swnj register int unit = minor(dev) >> 3; 4712470Swnj 472*2616Swnj if (unit >= NUP) 473*2616Swnj u.u_error = ENXIO; 474*2616Swnj else 475*2616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 476264Sbill } 477264Sbill 478266Sbill /* 479266Sbill * Correct an ECC error, and restart the i/o to complete 480266Sbill * the transfer if necessary. This is quite complicated because 481266Sbill * the transfer may be going to an odd memory address base and/or 482266Sbill * across a page boundary. 483266Sbill */ 4842395Swnj upecc(ui) 4852395Swnj register struct uba_dinfo *ui; 486264Sbill { 4872395Swnj register struct device *up = (struct device *)ui->ui_addr; 4882395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 4892395Swnj register struct uba_minfo *um = ui->ui_mi; 4902395Swnj register struct upst *st; 4912395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 492266Sbill register int i; 493264Sbill caddr_t addr; 494266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 495264Sbill int bn, cn, tn, sn; 496264Sbill 497264Sbill /* 498266Sbill * Npf is the number of sectors transferred before the sector 499266Sbill * containing the ECC error, and reg is the UBA register 500266Sbill * mapping (the first part of) the transfer. 501266Sbill * O is offset within a memory page of the first byte transferred. 502264Sbill */ 503266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 5042571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 505264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 506264Sbill printf("%D ", bp->b_blkno+npf); 507264Sbill prdev("ECC", bp->b_dev); 508264Sbill mask = up->upec2; 509264Sbill if (mask == 0) { 510266Sbill up->upof = FMT22; /* == RTC ???? */ 511264Sbill return (0); 512264Sbill } 513266Sbill /* 514266Sbill * Flush the buffered data path, and compute the 515266Sbill * byte and bit position of the error. The variable i 516266Sbill * is the byte offset in the transfer, the variable byte 517266Sbill * is the offset from a page boundary in main memory. 518266Sbill */ 5192571Swnj ubp->uba_dpr[(um->um_ubinfo>>28)&0x0f] |= UBA_BNE; 520266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 521266Sbill bit = i&07; 522266Sbill i = (i&~07)>>3; 523264Sbill byte = i + o; 524266Sbill /* 525266Sbill * Correct while possible bits remain of mask. Since mask 526266Sbill * contains 11 bits, we continue while the bit offset is > -11. 527266Sbill * Also watch out for end of this block and the end of the whole 528266Sbill * transfer. 529266Sbill */ 530266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 531266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 532266Sbill (byte & PGOFSET); 533266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 534266Sbill byte++; 535266Sbill i++; 536266Sbill bit -= 8; 537264Sbill } 5382395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 539264Sbill if (up->upwc == 0) 540264Sbill return (0); 541266Sbill /* 542266Sbill * Have to continue the transfer... clear the drive, 543266Sbill * and compute the position where the transfer is to continue. 544266Sbill * We have completed npf+1 sectors of the transfer already; 545266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 546266Sbill */ 547266Sbill up->upcs1 = TRE|IE|DCLR|GO; 548264Sbill bn = dkblock(bp); 5492395Swnj st = &upst[ui->ui_type]; 550264Sbill cn = bp->b_cylin; 5512395Swnj sn = bn%st->nspc + npf + 1; 5522395Swnj tn = sn/st->nsect; 5532395Swnj sn %= st->nsect; 5542395Swnj cn += tn/st->ntrak; 5552395Swnj tn %= st->ntrak; 556264Sbill up->updc = cn; 557266Sbill up->upda = (tn << 8) | sn; 558266Sbill ubaddr = (int)ptob(reg+1) + o; 559266Sbill up->upba = ubaddr; 560266Sbill cmd = (ubaddr >> 8) & 0x300; 561266Sbill cmd |= IE|GO|RCOM; 562266Sbill up->upcs1 = cmd; 563264Sbill return (1); 564264Sbill } 565286Sbill 566286Sbill /* 567286Sbill * Reset driver after UBA init. 568286Sbill * Cancel software state of all pending transfers 569286Sbill * and restart all units and the controller. 570286Sbill */ 5712395Swnj upreset(uban) 572286Sbill { 5732395Swnj register struct uba_minfo *um; 5742395Swnj register struct uba_dinfo *ui; 5752395Swnj register sc21, unit; 5762424Skre int any = 0; 577286Sbill 5782395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 5792470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 5802470Swnj um->um_alive == 0) 5812395Swnj continue; 5822424Skre if (any == 0) { 5832424Skre printf(" up"); 5842470Swnj DELAY(10000000); /* give it time to self-test */ 5852424Skre any++; 5862424Skre } 5872395Swnj um->um_tab.b_active = 0; 5882395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 5892571Swnj if (um->um_ubinfo) { 5902571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 591*2616Swnj ubadone(um); 5922395Swnj } 5932395Swnj ((struct device *)(um->um_addr))->upcs2 = CLR; 5942395Swnj for (unit = 0; unit < NUP; unit++) { 5952395Swnj if ((ui = updinfo[unit]) == 0) 5962395Swnj continue; 5972395Swnj if (ui->ui_alive == 0) 5982395Swnj continue; 5992395Swnj uputab[unit].b_active = 0; 6002395Swnj (void) upustart(ui); 6012395Swnj } 6022395Swnj (void) upstart(um); 603286Sbill } 604286Sbill } 605313Sbill 606313Sbill /* 607313Sbill * Wake up every second and if an interrupt is pending 608313Sbill * but nothing has happened increment a counter. 609313Sbill * If nothing happens for 20 seconds, reset the controller 610313Sbill * and begin anew. 611313Sbill */ 612313Sbill upwatch() 613313Sbill { 6142395Swnj register struct uba_minfo *um; 6152395Swnj register sc21, unit; 6162470Swnj register struct up_softc *sc; 617313Sbill 6181783Sbill timeout(upwatch, (caddr_t)0, HZ); 6192395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 6202395Swnj um = upminfo[sc21]; 6212470Swnj if (um == 0 || um->um_alive == 0) 6222470Swnj continue; 6232470Swnj sc = &up_softc[sc21]; 6242395Swnj if (um->um_tab.b_active == 0) { 6252395Swnj for (unit = 0; unit < NUP; unit++) 6262395Swnj if (updinfo[unit]->ui_mi == um && 6272395Swnj uputab[unit].b_active) 6282395Swnj goto active; 6292470Swnj sc->sc_wticks = 0; 6302395Swnj continue; 6312395Swnj } 6322395Swnj active: 6332470Swnj sc->sc_wticks++; 6342470Swnj if (sc->sc_wticks >= 20) { 6352470Swnj sc->sc_wticks = 0; 6362395Swnj printf("LOST INTERRUPT RESET"); 6372470Swnj /* SHOULD JUST RESET ONE CTLR, NOT ALL ON UBA */ 6382395Swnj upreset(um->um_ubanum); 6392395Swnj printf("\n"); 6402395Swnj } 641313Sbill } 642313Sbill } 6432379Swnj 6442379Swnj #define DBSIZE 20 6452379Swnj 6462379Swnj updump(dev) 6472379Swnj dev_t dev; 6482379Swnj { 6492379Swnj struct device *upaddr; 6502379Swnj char *start; 6512607Swnj int num, blk, unit; 6522379Swnj struct size *sizes; 6532395Swnj register struct uba_regs *uba; 6542395Swnj register struct uba_dinfo *ui; 6552379Swnj register short *rp; 6562395Swnj struct upst *st; 6572379Swnj 6582395Swnj unit = minor(dev) >> 3; 6592395Swnj if (unit >= NUP) { 6602395Swnj printf("bad unit\n"); 6612395Swnj return (-1); 6622395Swnj } 6632470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 6642395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 6652395Swnj if (ui->ui_alive == 0) { 6662395Swnj printf("dna\n"); 6672395Swnj return(-1); 6682395Swnj } 6692395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 6702395Swnj #if VAX780 6712470Swnj if (cpu == VAX_780) 6722470Swnj ubainit(uba); 6731809Sbill #endif 6742379Swnj DELAY(1000000); 6752395Swnj upaddr = (struct device *)ui->ui_physaddr; 6762395Swnj while ((upaddr->upcs1&DVA) == 0) 6772379Swnj ; 6782379Swnj num = maxfree; 6792379Swnj start = 0; 6802379Swnj upaddr->upcs2 = unit; 6812379Swnj if ((upaddr->upds & VV) == 0) { 6822379Swnj upaddr->upcs1 = DCLR|GO; 6832379Swnj upaddr->upcs1 = PRESET|GO; 6842379Swnj upaddr->upof = FMT22; 6852379Swnj } 6862379Swnj if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 6872379Swnj printf("up !DPR || !MOL\n"); 6882379Swnj return (-1); 6892379Swnj } 6902470Swnj st = &upst[ui->ui_type]; 6912395Swnj sizes = phys(struct size *, st->sizes); 6922379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 6932395Swnj printf("oor\n"); 6942379Swnj return (-1); 6952379Swnj } 6962379Swnj while (num > 0) { 6972379Swnj register struct pte *io; 6982379Swnj register int i; 6992379Swnj int cn, sn, tn; 7002379Swnj daddr_t bn; 7012379Swnj 7022379Swnj blk = num > DBSIZE ? DBSIZE : num; 7032395Swnj io = uba->uba_map; 7042379Swnj for (i = 0; i < blk; i++) 7052395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 7062379Swnj *(int *)io = 0; 7072379Swnj bn = dumplo + btop(start); 7082607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 7092607Swnj sn = bn%st->nspc; 7102607Swnj tn = sn/st->nsect; 7112607Swnj sn = sn%st->nsect; 7122379Swnj upaddr->updc = cn; 7132379Swnj rp = (short *) &upaddr->upda; 7142379Swnj *rp = (tn << 8) + sn; 7152379Swnj *--rp = 0; 7162379Swnj *--rp = -blk*NBPG / sizeof (short); 7172379Swnj *--rp = GO|WCOM; 7182379Swnj do { 7192379Swnj DELAY(25); 7202379Swnj } while ((upaddr->upcs1 & RDY) == 0); 7212379Swnj if (upaddr->upcs1&ERR) { 7222379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 7232379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 7242379Swnj return (-1); 7252379Swnj } 7262379Swnj start += blk*NBPG; 7272379Swnj num -= blk; 7282379Swnj } 7292379Swnj return (0); 7302379Swnj } 7311902Swnj #endif 732