1*2674Swnj /* up.c 4.22 81/02/25 */ 2264Sbill 31937Swnj #include "up.h" 42646Swnj #if NSC > 0 5264Sbill /* 6885Sbill * UNIBUS disk driver with overlapped seeks and ECC recovery. 7264Sbill */ 81756Sbill #define DELAY(N) { register int d; d = N; while (--d > 0); } 9264Sbill 10264Sbill #include "../h/param.h" 11264Sbill #include "../h/systm.h" 122395Swnj #include "../h/cpu.h" 132395Swnj #include "../h/nexus.h" 14308Sbill #include "../h/dk.h" 15264Sbill #include "../h/buf.h" 16264Sbill #include "../h/conf.h" 17264Sbill #include "../h/dir.h" 18264Sbill #include "../h/user.h" 19264Sbill #include "../h/map.h" 20420Sbill #include "../h/pte.h" 21264Sbill #include "../h/mba.h" 22264Sbill #include "../h/mtpr.h" 232571Swnj #include "../h/vm.h" 24264Sbill #include "../h/uba.h" 252379Swnj #include "../h/cmap.h" 26264Sbill 272379Swnj #include "../h/upreg.h" 28264Sbill 292395Swnj struct up_softc { 302395Swnj int sc_softas; 312607Swnj int sc_ndrive; 322395Swnj int sc_wticks; 33*2674Swnj int sc_recal; 342646Swnj } up_softc[NSC]; 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 682607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 692646Swnj struct uba_minfo *upminfo[NSC]; 702395Swnj struct uba_dinfo *updinfo[NUP]; 712646Swnj struct uba_dinfo *upip[NSC][4]; 722395Swnj 732607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 742616Swnj struct uba_driver scdriver = 752607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", 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[] = { 852607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 862607Swnj /* 9300 actually has 815 cylinders... */ 872395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 882395Swnj }; 892395Swnj 902629Swnj u_char up_offset[16] = { 912629Swnj UP_P400, UP_M400, UP_P400, UP_M400, UP_P800, UP_M800, UP_P800, UP_M800, 922629Swnj UP_P1200, UP_M1200, UP_P1200, UP_M1200, 0, 0, 0, 0 932629Swnj }; 94264Sbill 952616Swnj struct buf rupbuf[NUP]; 96264Sbill 97264Sbill #define b_cylin b_resid 98264Sbill 99264Sbill #ifdef INTRLVE 100264Sbill daddr_t dkblock(); 101264Sbill #endif 1022395Swnj 1032395Swnj int upwstart, upwatch(); /* Have started guardian */ 1042470Swnj int upseek; 105*2674Swnj int updrydel; 1062395Swnj 1072395Swnj /*ARGSUSED*/ 1082607Swnj upprobe(reg) 1092395Swnj caddr_t reg; 1102395Swnj { 1112459Swnj register int br, cvec; 1122459Swnj 1132607Swnj #ifdef lint 1142607Swnj br = 0; cvec = br; br = cvec; 1152607Swnj #endif 1162629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1172607Swnj DELAY(10); 1182629Swnj ((struct updevice *)reg)->upcs1 = 0; 1192459Swnj return (1); 1202395Swnj } 1212395Swnj 1222607Swnj upslave(ui, reg) 1232395Swnj struct uba_dinfo *ui; 1242395Swnj caddr_t reg; 1252395Swnj { 1262629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1272395Swnj 1282395Swnj upaddr->upcs1 = 0; /* conservative */ 1292607Swnj upaddr->upcs2 = ui->ui_slave; 1302629Swnj if (upaddr->upcs2&UP_NED) { 1312629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1322395Swnj return (0); 1332395Swnj } 1342607Swnj return (1); 1352607Swnj } 1362607Swnj 1372607Swnj upattach(ui) 1382607Swnj register struct uba_dinfo *ui; 1392607Swnj { 1402629Swnj #ifdef notdef 1412629Swnj register struct updevice *upaddr; 1422629Swnj #endif 1432607Swnj 1442395Swnj if (upwstart == 0) { 1452395Swnj timeout(upwatch, (caddr_t)0, HZ); 1462395Swnj upwstart++; 1472395Swnj } 1482571Swnj if (ui->ui_dk >= 0) 1492571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1502607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1512607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1522629Swnj #ifdef notdef 1532629Swnj upaddr = (struct updevice *)ui->ui_addr; 1542629Swnj upaddr->upcs1 = 0; 1552629Swnj upaddr->upcs2 = ui->ui_slave; 1562629Swnj upaddr->uphr = -1; 1572629Swnj /* ... */ 1582629Swnj if (upaddr-> ... == 10) 1592629Swnj ui->ui_type = 1; 1602629Swnj #endif 1612395Swnj } 162264Sbill 163264Sbill upstrategy(bp) 1642395Swnj register struct buf *bp; 165264Sbill { 1662395Swnj register struct uba_dinfo *ui; 1672395Swnj register struct upst *st; 1682395Swnj register int unit; 1692470Swnj register struct buf *dp; 1702395Swnj int xunit = minor(bp->b_dev) & 07; 1712470Swnj long bn, sz; 172264Sbill 1732470Swnj sz = (bp->b_bcount+511) >> 9; 174264Sbill unit = dkunit(bp); 1752395Swnj if (unit >= NUP) 1762395Swnj goto bad; 1772395Swnj ui = updinfo[unit]; 1782395Swnj if (ui == 0 || ui->ui_alive == 0) 1792395Swnj goto bad; 1802395Swnj st = &upst[ui->ui_type]; 1812395Swnj if (bp->b_blkno < 0 || 1822395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1832395Swnj goto bad; 1842395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 185264Sbill (void) spl5(); 1862470Swnj dp = &uputab[ui->ui_unit]; 1872470Swnj disksort(dp, bp); 1882470Swnj if (dp->b_active == 0) { 1892395Swnj (void) upustart(ui); 1902395Swnj bp = &ui->ui_mi->um_tab; 1912395Swnj if (bp->b_actf && bp->b_active == 0) 1922395Swnj (void) upstart(ui->ui_mi); 193264Sbill } 194264Sbill (void) spl0(); 1952395Swnj return; 1962395Swnj 1972395Swnj bad: 1982395Swnj bp->b_flags |= B_ERROR; 1992395Swnj iodone(bp); 2002395Swnj return; 201264Sbill } 202264Sbill 203*2674Swnj /* 204*2674Swnj * Unit start routine. 205*2674Swnj * Seek the drive to be where the data is 206*2674Swnj * and then generate another interrupt 207*2674Swnj * to actually start the transfer. 208*2674Swnj * If there is only one drive on the controller, 209*2674Swnj * or we are very close to the data, don't 210*2674Swnj * bother with the search. If called after 211*2674Swnj * searching once, don't bother to look where 212*2674Swnj * we are, just queue for transfer (to avoid 213*2674Swnj * positioning forever without transferrring.) 214*2674Swnj */ 2152395Swnj upustart(ui) 2162395Swnj register struct uba_dinfo *ui; 217264Sbill { 218264Sbill register struct buf *bp, *dp; 219*2674Swnj register struct uba_minfo *um = ui->ui_mi; 2202629Swnj register struct updevice *upaddr; 2212395Swnj register struct upst *st; 222264Sbill daddr_t bn; 223*2674Swnj int sn, csn; 2242607Swnj /* 2252607Swnj * The SC21 cancels commands if you just say 2262629Swnj * cs1 = UP_IE 2272607Swnj * so we are cautious about handling of cs1. 2282607Swnj * Also don't bother to clear as bits other than in upintr(). 2292607Swnj */ 230*2674Swnj int didie = 0; 231*2674Swnj 232*2674Swnj if (ui == 0) 233*2674Swnj return (0); 2342395Swnj dk_busy &= ~(1<<ui->ui_dk); 2352395Swnj dp = &uputab[ui->ui_unit]; 236266Sbill if ((bp = dp->b_actf) == NULL) 237268Sbill goto out; 238*2674Swnj /* 239*2674Swnj * If the controller is active, just remember 240*2674Swnj * that this device would like to be positioned... 241*2674Swnj * if we tried to position now we would confuse the SC21. 242*2674Swnj */ 2432395Swnj if (um->um_tab.b_active) { 2442459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 245275Sbill return (0); 246275Sbill } 247*2674Swnj /* 248*2674Swnj * If we have already positioned this drive, 249*2674Swnj * then just put it on the ready queue. 250*2674Swnj */ 251276Sbill if (dp->b_active) 252276Sbill goto done; 253276Sbill dp->b_active = 1; 2542629Swnj upaddr = (struct updevice *)um->um_addr; 2552395Swnj upaddr->upcs2 = ui->ui_slave; 256*2674Swnj /* 257*2674Swnj * If drive has just come up, 258*2674Swnj * setup the pack. 259*2674Swnj */ 2602629Swnj if ((upaddr->upds & UP_VV) == 0) { 2612607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2622629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2632629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 2642629Swnj upaddr->upof = UP_FMT22; 265268Sbill didie = 1; 266264Sbill } 267*2674Swnj /* 268*2674Swnj * If drive is offline, forget about positioning. 269*2674Swnj */ 2702629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) 271275Sbill goto done; 272*2674Swnj /* 273*2674Swnj * If there is only one drive, 274*2674Swnj * dont bother searching. 275*2674Swnj */ 2762607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 2772607Swnj goto done; 278*2674Swnj /* 279*2674Swnj * Figure out where this transfer is going to 280*2674Swnj * and see if we are close enough to justify not searching. 281*2674Swnj */ 2822395Swnj st = &upst[ui->ui_type]; 283264Sbill bn = dkblock(bp); 2842395Swnj sn = bn%st->nspc; 2852395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 286*2674Swnj if (bp->b_cylin - upaddr->updc) 287266Sbill goto search; /* Not on-cylinder */ 288275Sbill else if (upseek) 289275Sbill goto done; /* Ok just to be on-cylinder */ 290264Sbill csn = (upaddr->upla>>6) - sn - 1; 291266Sbill if (csn < 0) 2922395Swnj csn += st->nsect; 2932395Swnj if (csn > st->nsect - upRDIST) 294264Sbill goto done; 295264Sbill search: 296*2674Swnj upaddr->updc = bp->b_cylin; 297*2674Swnj /* 298*2674Swnj * Not on cylinder at correct position, 299*2674Swnj * seek/search. 300*2674Swnj */ 301275Sbill if (upseek) 3022629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3032470Swnj else { 304275Sbill upaddr->upda = sn; 3052629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 306275Sbill } 307268Sbill didie = 1; 308*2674Swnj /* 309*2674Swnj * Mark unit busy for iostat. 310*2674Swnj */ 3112395Swnj if (ui->ui_dk >= 0) { 3122395Swnj dk_busy |= 1<<ui->ui_dk; 3132395Swnj dk_seek[ui->ui_dk]++; 314264Sbill } 315268Sbill goto out; 316264Sbill done: 317*2674Swnj /* 318*2674Swnj * Device is ready to go. 319*2674Swnj * Put it on the ready queue for the controller 320*2674Swnj * (unless its already there.) 321*2674Swnj */ 3222629Swnj if (dp->b_active != 2) { 3232629Swnj dp->b_forw = NULL; 3242629Swnj if (um->um_tab.b_actf == NULL) 3252629Swnj um->um_tab.b_actf = dp; 3262629Swnj else 3272629Swnj um->um_tab.b_actl->b_forw = dp; 3282629Swnj um->um_tab.b_actl = dp; 3292629Swnj dp->b_active = 2; 3302629Swnj } 331268Sbill out: 332268Sbill return (didie); 333264Sbill } 334264Sbill 335*2674Swnj /* 336*2674Swnj * Start up a transfer on a drive. 337*2674Swnj */ 3382395Swnj upstart(um) 3392395Swnj register struct uba_minfo *um; 340264Sbill { 341264Sbill register struct buf *bp, *dp; 3422395Swnj register struct uba_dinfo *ui; 3432629Swnj register struct updevice *upaddr; 3442470Swnj struct upst *st; 345264Sbill daddr_t bn; 3462424Skre int dn, sn, tn, cmd; 347264Sbill 348264Sbill loop: 349*2674Swnj /* 350*2674Swnj * Pull a request off the controller queue 351*2674Swnj */ 3522395Swnj if ((dp = um->um_tab.b_actf) == NULL) 353268Sbill return (0); 354264Sbill if ((bp = dp->b_actf) == NULL) { 3552395Swnj um->um_tab.b_actf = dp->b_forw; 356264Sbill goto loop; 357264Sbill } 358*2674Swnj /* 359*2674Swnj * Mark controller busy, and 360*2674Swnj * determine destination of this request. 361*2674Swnj */ 3622395Swnj um->um_tab.b_active++; 3632395Swnj ui = updinfo[dkunit(bp)]; 364264Sbill bn = dkblock(bp); 3652395Swnj dn = ui->ui_slave; 3662395Swnj st = &upst[ui->ui_type]; 3672395Swnj sn = bn%st->nspc; 3682395Swnj tn = sn/st->nsect; 3692395Swnj sn %= st->nsect; 3702629Swnj upaddr = (struct updevice *)ui->ui_addr; 371*2674Swnj /* 372*2674Swnj * Select drive if not selected already. 373*2674Swnj */ 374*2674Swnj if ((upaddr->upcs2&07) != dn) 375*2674Swnj upaddr->upcs2 = dn; 376*2674Swnj /* 377*2674Swnj * Check that it is ready and online 378*2674Swnj */ 3792629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) { 3802607Swnj printf("up%d not ready", dkunit(bp)); 3812629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) { 3822607Swnj printf("\n"); 3832395Swnj um->um_tab.b_active = 0; 3842395Swnj um->um_tab.b_errcnt = 0; 385893Sbill dp->b_actf = bp->av_forw; 386893Sbill dp->b_active = 0; 387893Sbill bp->b_flags |= B_ERROR; 388893Sbill iodone(bp); 389893Sbill goto loop; 390893Sbill } 391*2674Swnj /* 392*2674Swnj * Oh, well, sometimes this 393*2674Swnj * happens, for reasons unknown. 394*2674Swnj */ 3952629Swnj printf(" (flakey)\n"); 396264Sbill } 397*2674Swnj /* 398*2674Swnj * After 16th retry, do offset positioning 399*2674Swnj */ 4002395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 4012629Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UP_FMT22; 4022629Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 4032629Swnj while (upaddr->upds & UP_PIP) 404264Sbill DELAY(25); 405264Sbill } 406*2674Swnj /* 407*2674Swnj * Setup for the transfer, and get in the 408*2674Swnj * UNIBUS adaptor queue. 409*2674Swnj */ 4102424Skre upaddr->updc = bp->b_cylin; 411264Sbill upaddr->upda = (tn << 8) + sn; 412264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 413264Sbill if (bp->b_flags & B_READ) 4142629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 415264Sbill else 4162629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4172571Swnj um->um_cmd = cmd; 4182571Swnj ubago(ui); 419268Sbill return (1); 420264Sbill } 421264Sbill 422*2674Swnj /* 423*2674Swnj * Now all ready to go, stuff the registers. 424*2674Swnj */ 4252571Swnj updgo(um) 4262571Swnj struct uba_minfo *um; 4272395Swnj { 4282629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4292470Swnj 4302571Swnj upaddr->upba = um->um_ubinfo; 4312571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4322395Swnj } 4332395Swnj 434*2674Swnj /* 435*2674Swnj * Handle a disk interrupt. 436*2674Swnj */ 4372616Swnj scintr(sc21) 4382395Swnj register sc21; 439264Sbill { 440264Sbill register struct buf *bp, *dp; 4412395Swnj register struct uba_minfo *um = upminfo[sc21]; 4422395Swnj register struct uba_dinfo *ui; 4432629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 444264Sbill register unit; 4452470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4462607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 447268Sbill int needie = 1; 448264Sbill 4492470Swnj sc->sc_wticks = 0; 4502607Swnj sc->sc_softas = 0; 451*2674Swnj /* 452*2674Swnj * If controller wasn't transferring, then this is an 453*2674Swnj * interrupt for attention status on seeking drives. 454*2674Swnj * Just service them. 455*2674Swnj */ 456*2674Swnj if (um->um_tab.b_active == 0) { 457*2674Swnj if (upaddr->upcs1 & UP_TRE) 458*2674Swnj upaddr->upcs1 = UP_TRE; 459*2674Swnj goto doattn; 460*2674Swnj } 461*2674Swnj if ((upaddr->upcs1 & UP_RDY) == 0) 462*2674Swnj printf("upintr !RDY\n"); /* shouldn't happen */ 463*2674Swnj /* 464*2674Swnj * Get device and block structures, and a pointer 465*2674Swnj * to the uba_dinfo for the drive. Select the drive. 466*2674Swnj */ 467*2674Swnj dp = um->um_tab.b_actf; 468*2674Swnj bp = dp->b_actf; 469*2674Swnj ui = updinfo[dkunit(bp)]; 470*2674Swnj dk_busy &= ~(1 << ui->ui_dk); 471*2674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 4722395Swnj upaddr->upcs2 = ui->ui_slave; 473*2674Swnj /* 474*2674Swnj * Check for and process errors on 475*2674Swnj * either the drive or the controller. 476*2674Swnj */ 477*2674Swnj if ((upaddr->upds&UP_ERR) || (upaddr->upcs1&UP_TRE)) { 478*2674Swnj while ((upaddr->upds & UP_DRY) == 0) 479*2674Swnj updrydel++; 480*2674Swnj if (upaddr->uper1&UP_WLE) { 481*2674Swnj /* 482*2674Swnj * Give up on write locked devices 483*2674Swnj * immediately. 484*2674Swnj */ 485*2674Swnj printf("up%d is write locked\n", dkunit(bp)); 486*2674Swnj bp->b_flags |= B_ERROR; 487*2674Swnj } else if (++um->um_tab.b_errcnt > 27) { 488*2674Swnj /* 489*2674Swnj * After 28 retries (16 without offset, and 490*2674Swnj * 12 with offset positioning) give up. 491*2674Swnj */ 492*2674Swnj if (upaddr->upcs2&(UP_NEM|UP_MXF)) { 493*2674Swnj printf("FLAKEY UP "); 494*2674Swnj ubareset(um->um_ubanum); 495*2674Swnj return; 4962395Swnj } 497*2674Swnj harderr(bp); 498*2674Swnj printf("up%d cs2 %b er1 %b er2 %b\n", 499*2674Swnj dkunit(bp), upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 500*2674Swnj UPER1_BITS, upaddr->uper2, UPER2_BITS); 501*2674Swnj bp->b_flags |= B_ERROR; 502*2674Swnj } else { 503*2674Swnj /* 504*2674Swnj * Retriable error. 505*2674Swnj * If a soft ecc, correct it (continuing 506*2674Swnj * by returning if necessary. 507*2674Swnj * Otherwise fall through and retry the transfer 508*2674Swnj */ 509*2674Swnj um->um_tab.b_active = 0; /* force retry */ 5102629Swnj if ((upaddr->uper1&(UP_DCK|UP_ECH))==UP_DCK) 5112629Swnj if (upecc(ui)) 5122629Swnj return; 513*2674Swnj } 514*2674Swnj /* 515*2674Swnj * Clear drive error and, every eight attempts, 516*2674Swnj * (starting with the fourth) 517*2674Swnj * recalibrate to clear the slate. 518*2674Swnj */ 519*2674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 520*2674Swnj needie = 0; 521*2674Swnj if ((um->um_tab.b_errcnt&07) == 4) { 522*2674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 523*2674Swnj um->um_tab.b_active = 1; 524*2674Swnj sc->sc_recal = 1; 525*2674Swnj return; 526*2674Swnj } 527*2674Swnj } 528*2674Swnj /* 529*2674Swnj * Done retrying transfer... release 530*2674Swnj * resources... if we were recalibrating, 531*2674Swnj * then retry the transfer. 532*2674Swnj * Mathematical note: 28%8 != 4. 533*2674Swnj */ 534*2674Swnj ubadone(um); 535*2674Swnj if (sc->sc_recal) { 536*2674Swnj sc->sc_recal = 0; 537*2674Swnj um->um_tab.b_active = 0; /* force retry */ 538*2674Swnj } 539*2674Swnj /* 540*2674Swnj * If still ``active'', then don't need any more retries. 541*2674Swnj */ 542*2674Swnj if (um->um_tab.b_active) { 543*2674Swnj /* 544*2674Swnj * If we were offset positioning, 545*2674Swnj * return to centerline. 546*2674Swnj */ 547*2674Swnj if (um->um_tab.b_errcnt >= 16) { 548*2674Swnj upaddr->upof = UP_FMT22; 549*2674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 550*2674Swnj while (upaddr->upds & UP_PIP) 551*2674Swnj DELAY(25); 552268Sbill needie = 0; 553264Sbill } 554*2674Swnj um->um_tab.b_active = 0; 555*2674Swnj um->um_tab.b_errcnt = 0; 556*2674Swnj um->um_tab.b_actf = dp->b_forw; 557*2674Swnj dp->b_active = 0; 558*2674Swnj dp->b_errcnt = 0; 559*2674Swnj dp->b_actf = bp->av_forw; 560*2674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 561*2674Swnj iodone(bp); 562*2674Swnj /* 563*2674Swnj * If this unit has more work to do, 564*2674Swnj * then start it up right away. 565*2674Swnj */ 566*2674Swnj if (dp->b_actf) 567*2674Swnj if (upustart(ui)) 568268Sbill needie = 0; 569264Sbill } 570*2674Swnj as &= ~(1<<ui->ui_slave); 571*2674Swnj doattn: 572*2674Swnj /* 573*2674Swnj * Process other units which need attention. 574*2674Swnj * For each unit which needs attention, call 575*2674Swnj * the unit start routine to place the slave 576*2674Swnj * on the controller device queue. 577*2674Swnj */ 5782607Swnj for (unit = 0; as; as >>= 1, unit++) 5792607Swnj if (as & 1) { 5802470Swnj upaddr->upas = 1<<unit; 5812607Swnj if (upustart(upip[sc21][unit])) 582273Sbill needie = 0; 583273Sbill } 584*2674Swnj /* 585*2674Swnj * If the controller is not transferring, but 586*2674Swnj * there are devices ready to transfer, start 587*2674Swnj * the controller. 588*2674Swnj */ 5892395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 5902395Swnj if (upstart(um)) 591268Sbill needie = 0; 592275Sbill if (needie) 5932629Swnj upaddr->upcs1 = UP_IE; 594264Sbill } 595264Sbill 596264Sbill upread(dev) 5972616Swnj dev_t dev; 598264Sbill { 5992616Swnj register int unit = minor(dev) >> 3; 6002470Swnj 6012616Swnj if (unit >= NUP) 6022616Swnj u.u_error = ENXIO; 6032616Swnj else 6042616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 605264Sbill } 606264Sbill 607264Sbill upwrite(dev) 6082616Swnj dev_t dev; 609264Sbill { 6102616Swnj register int unit = minor(dev) >> 3; 6112470Swnj 6122616Swnj if (unit >= NUP) 6132616Swnj u.u_error = ENXIO; 6142616Swnj else 6152616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 616264Sbill } 617264Sbill 618266Sbill /* 619266Sbill * Correct an ECC error, and restart the i/o to complete 620266Sbill * the transfer if necessary. This is quite complicated because 621266Sbill * the transfer may be going to an odd memory address base and/or 622266Sbill * across a page boundary. 623266Sbill */ 6242395Swnj upecc(ui) 6252395Swnj register struct uba_dinfo *ui; 626264Sbill { 6272629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6282395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6292395Swnj register struct uba_minfo *um = ui->ui_mi; 6302395Swnj register struct upst *st; 6312395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 632266Sbill register int i; 633264Sbill caddr_t addr; 634266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 635264Sbill int bn, cn, tn, sn; 636264Sbill 637264Sbill /* 638266Sbill * Npf is the number of sectors transferred before the sector 639266Sbill * containing the ECC error, and reg is the UBA register 640266Sbill * mapping (the first part of) the transfer. 641266Sbill * O is offset within a memory page of the first byte transferred. 642264Sbill */ 643266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 6442571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 645264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 646264Sbill printf("%D ", bp->b_blkno+npf); 647264Sbill prdev("ECC", bp->b_dev); 648264Sbill mask = up->upec2; 649264Sbill if (mask == 0) { 6502629Swnj up->upof = UP_FMT22; /* == RTC ???? */ 651264Sbill return (0); 652264Sbill } 653266Sbill /* 654266Sbill * Flush the buffered data path, and compute the 655266Sbill * byte and bit position of the error. The variable i 656266Sbill * is the byte offset in the transfer, the variable byte 657266Sbill * is the offset from a page boundary in main memory. 658266Sbill */ 6592571Swnj ubp->uba_dpr[(um->um_ubinfo>>28)&0x0f] |= UBA_BNE; 660266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 661266Sbill bit = i&07; 662266Sbill i = (i&~07)>>3; 663264Sbill byte = i + o; 664266Sbill /* 665266Sbill * Correct while possible bits remain of mask. Since mask 666266Sbill * contains 11 bits, we continue while the bit offset is > -11. 667266Sbill * Also watch out for end of this block and the end of the whole 668266Sbill * transfer. 669266Sbill */ 670266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 671266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 672266Sbill (byte & PGOFSET); 673266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 674266Sbill byte++; 675266Sbill i++; 676266Sbill bit -= 8; 677264Sbill } 6782395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 679264Sbill if (up->upwc == 0) 680264Sbill return (0); 681266Sbill /* 682266Sbill * Have to continue the transfer... clear the drive, 683266Sbill * and compute the position where the transfer is to continue. 684266Sbill * We have completed npf+1 sectors of the transfer already; 685266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 686266Sbill */ 6872629Swnj #ifdef notdef 6882629Swnj up->uper1 = 0; 6892629Swnj up->upcs1 |= UP_GO; 6902629Swnj #else 6912629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 692264Sbill bn = dkblock(bp); 6932395Swnj st = &upst[ui->ui_type]; 694264Sbill cn = bp->b_cylin; 6952395Swnj sn = bn%st->nspc + npf + 1; 6962395Swnj tn = sn/st->nsect; 6972395Swnj sn %= st->nsect; 6982395Swnj cn += tn/st->ntrak; 6992395Swnj tn %= st->ntrak; 700264Sbill up->updc = cn; 701266Sbill up->upda = (tn << 8) | sn; 702266Sbill ubaddr = (int)ptob(reg+1) + o; 703266Sbill up->upba = ubaddr; 704266Sbill cmd = (ubaddr >> 8) & 0x300; 7052629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 706266Sbill up->upcs1 = cmd; 7072629Swnj #endif 708264Sbill return (1); 709264Sbill } 710286Sbill 711286Sbill /* 712286Sbill * Reset driver after UBA init. 713286Sbill * Cancel software state of all pending transfers 714286Sbill * and restart all units and the controller. 715286Sbill */ 7162395Swnj upreset(uban) 717286Sbill { 7182395Swnj register struct uba_minfo *um; 7192395Swnj register struct uba_dinfo *ui; 7202395Swnj register sc21, unit; 7212424Skre int any = 0; 722286Sbill 7232646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7242470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7252470Swnj um->um_alive == 0) 7262395Swnj continue; 7272424Skre if (any == 0) { 7282424Skre printf(" up"); 7292470Swnj DELAY(10000000); /* give it time to self-test */ 7302424Skre any++; 7312424Skre } 7322395Swnj um->um_tab.b_active = 0; 7332395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7342571Swnj if (um->um_ubinfo) { 7352571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7362616Swnj ubadone(um); 7372395Swnj } 7382629Swnj ((struct updevice *)(um->um_addr))->upcs2 = UP_CLR; 7392395Swnj for (unit = 0; unit < NUP; unit++) { 7402395Swnj if ((ui = updinfo[unit]) == 0) 7412395Swnj continue; 7422395Swnj if (ui->ui_alive == 0) 7432395Swnj continue; 7442395Swnj uputab[unit].b_active = 0; 7452395Swnj (void) upustart(ui); 7462395Swnj } 7472395Swnj (void) upstart(um); 748286Sbill } 749286Sbill } 750313Sbill 751313Sbill /* 752313Sbill * Wake up every second and if an interrupt is pending 753313Sbill * but nothing has happened increment a counter. 754313Sbill * If nothing happens for 20 seconds, reset the controller 755313Sbill * and begin anew. 756313Sbill */ 757313Sbill upwatch() 758313Sbill { 7592395Swnj register struct uba_minfo *um; 7602395Swnj register sc21, unit; 7612470Swnj register struct up_softc *sc; 762313Sbill 7631783Sbill timeout(upwatch, (caddr_t)0, HZ); 7642646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7652395Swnj um = upminfo[sc21]; 7662470Swnj if (um == 0 || um->um_alive == 0) 7672470Swnj continue; 7682470Swnj sc = &up_softc[sc21]; 7692395Swnj if (um->um_tab.b_active == 0) { 7702395Swnj for (unit = 0; unit < NUP; unit++) 7712629Swnj if (uputab[unit].b_active && 7722629Swnj updinfo[unit]->ui_mi == um) 7732395Swnj goto active; 7742470Swnj sc->sc_wticks = 0; 7752395Swnj continue; 7762395Swnj } 7772395Swnj active: 7782470Swnj sc->sc_wticks++; 7792470Swnj if (sc->sc_wticks >= 20) { 7802470Swnj sc->sc_wticks = 0; 7812646Swnj printf("LOST upintr "); 7822646Swnj ubareset(um->um_ubanum); 7832395Swnj } 784313Sbill } 785313Sbill } 7862379Swnj 7872379Swnj #define DBSIZE 20 7882379Swnj 7892379Swnj updump(dev) 7902379Swnj dev_t dev; 7912379Swnj { 7922629Swnj struct updevice *upaddr; 7932379Swnj char *start; 7942607Swnj int num, blk, unit; 7952379Swnj struct size *sizes; 7962395Swnj register struct uba_regs *uba; 7972395Swnj register struct uba_dinfo *ui; 7982379Swnj register short *rp; 7992395Swnj struct upst *st; 8002379Swnj 8012395Swnj unit = minor(dev) >> 3; 8022395Swnj if (unit >= NUP) { 8032395Swnj printf("bad unit\n"); 8042395Swnj return (-1); 8052395Swnj } 8062470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8072395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 8082395Swnj if (ui->ui_alive == 0) { 8092395Swnj printf("dna\n"); 8102395Swnj return(-1); 8112395Swnj } 8122395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8132395Swnj #if VAX780 8142470Swnj if (cpu == VAX_780) 8152470Swnj ubainit(uba); 8161809Sbill #endif 8172379Swnj DELAY(1000000); 8182629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8192629Swnj while ((upaddr->upcs1&UP_DVA) == 0) 8202379Swnj ; 8212379Swnj num = maxfree; 8222379Swnj start = 0; 8232379Swnj upaddr->upcs2 = unit; 8242629Swnj if ((upaddr->upds & UP_VV) == 0) { 8252629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 8262629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 8272629Swnj upaddr->upof = UP_FMT22; 8282379Swnj } 8292629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) { 8302629Swnj printf("dna\n"); 8312379Swnj return (-1); 8322379Swnj } 8332470Swnj st = &upst[ui->ui_type]; 8342395Swnj sizes = phys(struct size *, st->sizes); 8352379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 8362395Swnj printf("oor\n"); 8372379Swnj return (-1); 8382379Swnj } 8392379Swnj while (num > 0) { 8402379Swnj register struct pte *io; 8412379Swnj register int i; 8422379Swnj int cn, sn, tn; 8432379Swnj daddr_t bn; 8442379Swnj 8452379Swnj blk = num > DBSIZE ? DBSIZE : num; 8462395Swnj io = uba->uba_map; 8472379Swnj for (i = 0; i < blk; i++) 8482395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 8492379Swnj *(int *)io = 0; 8502379Swnj bn = dumplo + btop(start); 8512607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 8522607Swnj sn = bn%st->nspc; 8532607Swnj tn = sn/st->nsect; 8542607Swnj sn = sn%st->nsect; 8552379Swnj upaddr->updc = cn; 8562379Swnj rp = (short *) &upaddr->upda; 8572379Swnj *rp = (tn << 8) + sn; 8582379Swnj *--rp = 0; 8592379Swnj *--rp = -blk*NBPG / sizeof (short); 8602629Swnj *--rp = UP_GO|UP_WCOM; 8612379Swnj do { 8622379Swnj DELAY(25); 8632629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 8642629Swnj if (upaddr->upcs1&UP_ERR) { 8652379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 8662379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 8672379Swnj return (-1); 8682379Swnj } 8692379Swnj start += blk*NBPG; 8702379Swnj num -= blk; 8712379Swnj } 8722379Swnj return (0); 8732379Swnj } 8741902Swnj #endif 875