1*3730Sroot /* up.c 4.39 81/05/11 */ 2264Sbill 31937Swnj #include "up.h" 42646Swnj #if NSC > 0 5264Sbill /* 6885Sbill * UNIBUS disk driver with overlapped seeks and ECC recovery. 72889Swnj * 82889Swnj * TODO: 92889Swnj * Add bad sector forwarding code 103445Sroot * Check that offset recovery code works 11264Sbill */ 12264Sbill 13264Sbill #include "../h/param.h" 14264Sbill #include "../h/systm.h" 152395Swnj #include "../h/cpu.h" 162395Swnj #include "../h/nexus.h" 17308Sbill #include "../h/dk.h" 18264Sbill #include "../h/buf.h" 19264Sbill #include "../h/conf.h" 20264Sbill #include "../h/dir.h" 21264Sbill #include "../h/user.h" 22264Sbill #include "../h/map.h" 23420Sbill #include "../h/pte.h" 24264Sbill #include "../h/mtpr.h" 252571Swnj #include "../h/vm.h" 262983Swnj #include "../h/ubavar.h" 272983Swnj #include "../h/ubareg.h" 282379Swnj #include "../h/cmap.h" 29264Sbill 302379Swnj #include "../h/upreg.h" 31264Sbill 322395Swnj struct up_softc { 332395Swnj int sc_softas; 342607Swnj int sc_ndrive; 352395Swnj int sc_wticks; 362674Swnj int sc_recal; 372646Swnj } up_softc[NSC]; 38275Sbill 392395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 40264Sbill struct size 41264Sbill { 42264Sbill daddr_t nblocks; 43264Sbill int cyloff; 44264Sbill } up_sizes[8] = { 45264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 46264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 47341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 48264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 49264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 50*3730Sroot #ifndef NOBADSECT 51*3730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 52*3730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 53*3730Sroot #else 54*3730Sroot 81472, 681, 55*3730Sroot 153824, 562, 56*3730Sroot #endif 57264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 582395Swnj }, fj_sizes[8] = { 592395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 602395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 612395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 622395Swnj 0, 0, 632395Swnj 0, 0, 642395Swnj 0, 0, 652395Swnj 0, 0, 66*3730Sroot #ifndef NOBADSECT 67*3730Sroot 213664, 155, /* H=cyl 155 thru 822 */ 68*3730Sroot #else 69*3730Sroot 213760, 155, 70*3730Sroot #endif 71264Sbill }; 722395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 73264Sbill 742395Swnj #define _upSDIST 2 /* 1.0 msec */ 752395Swnj #define _upRDIST 4 /* 2.0 msec */ 76264Sbill 772395Swnj int upSDIST = _upSDIST; 782395Swnj int upRDIST = _upRDIST; 792395Swnj 802607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 812983Swnj struct uba_ctlr *upminfo[NSC]; 822983Swnj struct uba_device *updinfo[NUP]; 832983Swnj struct uba_device *upip[NSC][4]; 842395Swnj 852607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 862616Swnj struct uba_driver scdriver = 872607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 882395Swnj struct buf uputab[NUP]; 892395Swnj 902395Swnj struct upst { 912395Swnj short nsect; 922395Swnj short ntrak; 932395Swnj short nspc; 942395Swnj short ncyl; 952395Swnj struct size *sizes; 962395Swnj } upst[] = { 972607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 982607Swnj /* 9300 actually has 815 cylinders... */ 992395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 1002395Swnj }; 1012395Swnj 1022629Swnj u_char up_offset[16] = { 1033445Sroot UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1043445Sroot UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1053445Sroot UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1063445Sroot 0, 0, 0, 0 1072629Swnj }; 108264Sbill 1092616Swnj struct buf rupbuf[NUP]; 110264Sbill 111264Sbill #define b_cylin b_resid 112264Sbill 113264Sbill #ifdef INTRLVE 114264Sbill daddr_t dkblock(); 115264Sbill #endif 1162395Swnj 1172395Swnj int upwstart, upwatch(); /* Have started guardian */ 1182470Swnj int upseek; 1192681Swnj int upwaitdry; 1202395Swnj 1212395Swnj /*ARGSUSED*/ 1222607Swnj upprobe(reg) 1232395Swnj caddr_t reg; 1242395Swnj { 1252459Swnj register int br, cvec; 1262459Swnj 1272607Swnj #ifdef lint 1282607Swnj br = 0; cvec = br; br = cvec; 1292607Swnj #endif 1302629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1312607Swnj DELAY(10); 1322629Swnj ((struct updevice *)reg)->upcs1 = 0; 1332459Swnj return (1); 1342395Swnj } 1352395Swnj 1362607Swnj upslave(ui, reg) 1372983Swnj struct uba_device *ui; 1382395Swnj caddr_t reg; 1392395Swnj { 1402629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1412395Swnj 1422395Swnj upaddr->upcs1 = 0; /* conservative */ 1432607Swnj upaddr->upcs2 = ui->ui_slave; 1443445Sroot if (upaddr->upcs2&UPCS2_NED) { 1452629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1462395Swnj return (0); 1472395Swnj } 1482607Swnj return (1); 1492607Swnj } 1502607Swnj 1512607Swnj upattach(ui) 1522983Swnj register struct uba_device *ui; 1532607Swnj { 1542629Swnj register struct updevice *upaddr; 1552607Swnj 1562395Swnj if (upwstart == 0) { 1572759Swnj timeout(upwatch, (caddr_t)0, hz); 1582395Swnj upwstart++; 1592395Swnj } 1602571Swnj if (ui->ui_dk >= 0) 1612571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1622607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1632607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1642629Swnj upaddr = (struct updevice *)ui->ui_addr; 1652629Swnj upaddr->upcs1 = 0; 1662629Swnj upaddr->upcs2 = ui->ui_slave; 1673496Sroot upaddr->uphr = UPHR_MAXTRAK; 1683553Swnj if (upaddr->uphr == 9) 1693496Sroot ui->ui_type = 1; /* fujitsu hack */ 1703496Sroot upaddr->upcs2 = UPCS2_CLR; 1713496Sroot /* 1723496Sroot upaddr->uphr = UPHR_MAXCYL; 1733496Sroot printf("maxcyl %d\n", upaddr->uphr); 1743496Sroot upaddr->uphr = UPHR_MAXTRAK; 1753496Sroot printf("maxtrak %d\n", upaddr->uphr); 1763496Sroot upaddr->uphr = UPHR_MAXSECT; 1773496Sroot printf("maxsect %d\n", upaddr->uphr); 1783496Sroot */ 1792395Swnj } 180264Sbill 181264Sbill upstrategy(bp) 1822395Swnj register struct buf *bp; 183264Sbill { 1842983Swnj register struct uba_device *ui; 1852395Swnj register struct upst *st; 1862395Swnj register int unit; 1872470Swnj register struct buf *dp; 1882395Swnj int xunit = minor(bp->b_dev) & 07; 1892470Swnj long bn, sz; 190264Sbill 1912470Swnj sz = (bp->b_bcount+511) >> 9; 192264Sbill unit = dkunit(bp); 1932395Swnj if (unit >= NUP) 1942395Swnj goto bad; 1952395Swnj ui = updinfo[unit]; 1962395Swnj if (ui == 0 || ui->ui_alive == 0) 1972395Swnj goto bad; 1982395Swnj st = &upst[ui->ui_type]; 1992395Swnj if (bp->b_blkno < 0 || 2002395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2012395Swnj goto bad; 2022395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 203264Sbill (void) spl5(); 2042470Swnj dp = &uputab[ui->ui_unit]; 2052470Swnj disksort(dp, bp); 2062470Swnj if (dp->b_active == 0) { 2072395Swnj (void) upustart(ui); 2082395Swnj bp = &ui->ui_mi->um_tab; 2092395Swnj if (bp->b_actf && bp->b_active == 0) 2102395Swnj (void) upstart(ui->ui_mi); 211264Sbill } 212264Sbill (void) spl0(); 2132395Swnj return; 2142395Swnj 2152395Swnj bad: 2162395Swnj bp->b_flags |= B_ERROR; 2172395Swnj iodone(bp); 2182395Swnj return; 219264Sbill } 220264Sbill 2212674Swnj /* 2222674Swnj * Unit start routine. 2232674Swnj * Seek the drive to be where the data is 2242674Swnj * and then generate another interrupt 2252674Swnj * to actually start the transfer. 2262674Swnj * If there is only one drive on the controller, 2272674Swnj * or we are very close to the data, don't 2282674Swnj * bother with the search. If called after 2292674Swnj * searching once, don't bother to look where 2302674Swnj * we are, just queue for transfer (to avoid 2312674Swnj * positioning forever without transferrring.) 2322674Swnj */ 2332395Swnj upustart(ui) 2342983Swnj register struct uba_device *ui; 235264Sbill { 236264Sbill register struct buf *bp, *dp; 2372983Swnj register struct uba_ctlr *um; 2382629Swnj register struct updevice *upaddr; 2392395Swnj register struct upst *st; 240264Sbill daddr_t bn; 2412674Swnj int sn, csn; 2422607Swnj /* 2432607Swnj * The SC21 cancels commands if you just say 2442629Swnj * cs1 = UP_IE 2452607Swnj * so we are cautious about handling of cs1. 2462607Swnj * Also don't bother to clear as bits other than in upintr(). 2472607Swnj */ 2482674Swnj int didie = 0; 2492674Swnj 2502674Swnj if (ui == 0) 2512674Swnj return (0); 2522983Swnj um = ui->ui_mi; 2532395Swnj dk_busy &= ~(1<<ui->ui_dk); 2542395Swnj dp = &uputab[ui->ui_unit]; 255266Sbill if ((bp = dp->b_actf) == NULL) 256268Sbill goto out; 2572674Swnj /* 2582674Swnj * If the controller is active, just remember 2592674Swnj * that this device would like to be positioned... 2602674Swnj * if we tried to position now we would confuse the SC21. 2612674Swnj */ 2622395Swnj if (um->um_tab.b_active) { 2632459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 264275Sbill return (0); 265275Sbill } 2662674Swnj /* 2672674Swnj * If we have already positioned this drive, 2682674Swnj * then just put it on the ready queue. 2692674Swnj */ 270276Sbill if (dp->b_active) 271276Sbill goto done; 272276Sbill dp->b_active = 1; 2732629Swnj upaddr = (struct updevice *)um->um_addr; 2742395Swnj upaddr->upcs2 = ui->ui_slave; 2752674Swnj /* 2762674Swnj * If drive has just come up, 2772674Swnj * setup the pack. 2782674Swnj */ 2793445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 2802607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2812629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2822629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 2833445Sroot upaddr->upof = UPOF_FMT22; 284268Sbill didie = 1; 285264Sbill } 2862674Swnj /* 2872674Swnj * If drive is offline, forget about positioning. 2882674Swnj */ 2893445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 290275Sbill goto done; 2912674Swnj /* 2922674Swnj * If there is only one drive, 2932674Swnj * dont bother searching. 2942674Swnj */ 2952607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 2962607Swnj goto done; 2972674Swnj /* 2982674Swnj * Figure out where this transfer is going to 2992674Swnj * and see if we are close enough to justify not searching. 3002674Swnj */ 3012395Swnj st = &upst[ui->ui_type]; 302264Sbill bn = dkblock(bp); 3032395Swnj sn = bn%st->nspc; 3042395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 3052674Swnj if (bp->b_cylin - upaddr->updc) 306266Sbill goto search; /* Not on-cylinder */ 307275Sbill else if (upseek) 308275Sbill goto done; /* Ok just to be on-cylinder */ 309264Sbill csn = (upaddr->upla>>6) - sn - 1; 310266Sbill if (csn < 0) 3112395Swnj csn += st->nsect; 3122395Swnj if (csn > st->nsect - upRDIST) 313264Sbill goto done; 314264Sbill search: 3152674Swnj upaddr->updc = bp->b_cylin; 3162674Swnj /* 3172674Swnj * Not on cylinder at correct position, 3182674Swnj * seek/search. 3192674Swnj */ 320275Sbill if (upseek) 3212629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3222470Swnj else { 323275Sbill upaddr->upda = sn; 3242629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 325275Sbill } 326268Sbill didie = 1; 3272674Swnj /* 3282674Swnj * Mark unit busy for iostat. 3292674Swnj */ 3302395Swnj if (ui->ui_dk >= 0) { 3312395Swnj dk_busy |= 1<<ui->ui_dk; 3322395Swnj dk_seek[ui->ui_dk]++; 333264Sbill } 334268Sbill goto out; 335264Sbill done: 3362674Swnj /* 3372674Swnj * Device is ready to go. 3382674Swnj * Put it on the ready queue for the controller 3392674Swnj * (unless its already there.) 3402674Swnj */ 3412629Swnj if (dp->b_active != 2) { 3422629Swnj dp->b_forw = NULL; 3432629Swnj if (um->um_tab.b_actf == NULL) 3442629Swnj um->um_tab.b_actf = dp; 3452629Swnj else 3462629Swnj um->um_tab.b_actl->b_forw = dp; 3472629Swnj um->um_tab.b_actl = dp; 3482629Swnj dp->b_active = 2; 3492629Swnj } 350268Sbill out: 351268Sbill return (didie); 352264Sbill } 353264Sbill 3542674Swnj /* 3552674Swnj * Start up a transfer on a drive. 3562674Swnj */ 3572395Swnj upstart(um) 3582983Swnj register struct uba_ctlr *um; 359264Sbill { 360264Sbill register struct buf *bp, *dp; 3612983Swnj register struct uba_device *ui; 3622629Swnj register struct updevice *upaddr; 3632470Swnj struct upst *st; 364264Sbill daddr_t bn; 3652681Swnj int dn, sn, tn, cmd, waitdry; 366264Sbill 367264Sbill loop: 3682674Swnj /* 3692674Swnj * Pull a request off the controller queue 3702674Swnj */ 3712395Swnj if ((dp = um->um_tab.b_actf) == NULL) 372268Sbill return (0); 373264Sbill if ((bp = dp->b_actf) == NULL) { 3742395Swnj um->um_tab.b_actf = dp->b_forw; 375264Sbill goto loop; 376264Sbill } 3772674Swnj /* 3782674Swnj * Mark controller busy, and 3792674Swnj * determine destination of this request. 3802674Swnj */ 3812395Swnj um->um_tab.b_active++; 3822395Swnj ui = updinfo[dkunit(bp)]; 383264Sbill bn = dkblock(bp); 3842395Swnj dn = ui->ui_slave; 3852395Swnj st = &upst[ui->ui_type]; 3862395Swnj sn = bn%st->nspc; 3872395Swnj tn = sn/st->nsect; 3882395Swnj sn %= st->nsect; 3892629Swnj upaddr = (struct updevice *)ui->ui_addr; 3902674Swnj /* 3912674Swnj * Select drive if not selected already. 3922674Swnj */ 3932674Swnj if ((upaddr->upcs2&07) != dn) 3942674Swnj upaddr->upcs2 = dn; 3952674Swnj /* 3962674Swnj * Check that it is ready and online 3972674Swnj */ 3982681Swnj waitdry = 0; 3993445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4002681Swnj if (++waitdry > 512) 4012681Swnj break; 4022681Swnj upwaitdry++; 4032681Swnj } 4043445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4052931Swnj printf("up%d: not ready", dkunit(bp)); 4063445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4072607Swnj printf("\n"); 4082395Swnj um->um_tab.b_active = 0; 4092395Swnj um->um_tab.b_errcnt = 0; 410893Sbill dp->b_actf = bp->av_forw; 411893Sbill dp->b_active = 0; 412893Sbill bp->b_flags |= B_ERROR; 413893Sbill iodone(bp); 414893Sbill goto loop; 415893Sbill } 4162674Swnj /* 4172674Swnj * Oh, well, sometimes this 4182674Swnj * happens, for reasons unknown. 4192674Swnj */ 4202629Swnj printf(" (flakey)\n"); 421264Sbill } 4222674Swnj /* 4232674Swnj * Setup for the transfer, and get in the 4242674Swnj * UNIBUS adaptor queue. 4252674Swnj */ 4262424Skre upaddr->updc = bp->b_cylin; 427264Sbill upaddr->upda = (tn << 8) + sn; 428264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 429264Sbill if (bp->b_flags & B_READ) 4302629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 431264Sbill else 4322629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4332571Swnj um->um_cmd = cmd; 4343107Swnj (void) ubago(ui); 435268Sbill return (1); 436264Sbill } 437264Sbill 4382674Swnj /* 4392674Swnj * Now all ready to go, stuff the registers. 4402674Swnj */ 4412571Swnj updgo(um) 4422983Swnj struct uba_ctlr *um; 4432395Swnj { 4442629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4452470Swnj 4462571Swnj upaddr->upba = um->um_ubinfo; 4472571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4482395Swnj } 4492395Swnj 4502674Swnj /* 4512674Swnj * Handle a disk interrupt. 4522674Swnj */ 4532707Swnj upintr(sc21) 4542395Swnj register sc21; 455264Sbill { 456264Sbill register struct buf *bp, *dp; 4572983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4582983Swnj register struct uba_device *ui; 4592629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 460264Sbill register unit; 4612470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4622607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4632681Swnj int needie = 1, waitdry; 464264Sbill 4652470Swnj sc->sc_wticks = 0; 4662607Swnj sc->sc_softas = 0; 4672674Swnj /* 4682674Swnj * If controller wasn't transferring, then this is an 4692674Swnj * interrupt for attention status on seeking drives. 4702674Swnj * Just service them. 4712674Swnj */ 4722674Swnj if (um->um_tab.b_active == 0) { 4732674Swnj if (upaddr->upcs1 & UP_TRE) 4742674Swnj upaddr->upcs1 = UP_TRE; 4752674Swnj goto doattn; 4762674Swnj } 4772674Swnj /* 4782674Swnj * Get device and block structures, and a pointer 4792983Swnj * to the uba_device for the drive. Select the drive. 4802674Swnj */ 4812674Swnj dp = um->um_tab.b_actf; 4822674Swnj bp = dp->b_actf; 4832674Swnj ui = updinfo[dkunit(bp)]; 4842674Swnj dk_busy &= ~(1 << ui->ui_dk); 4852674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 4862395Swnj upaddr->upcs2 = ui->ui_slave; 4872674Swnj /* 4882674Swnj * Check for and process errors on 4892674Swnj * either the drive or the controller. 4902674Swnj */ 4913445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 4922681Swnj waitdry = 0; 4933445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 4942681Swnj if (++waitdry > 512) 4952681Swnj break; 4962681Swnj upwaitdry++; 4972681Swnj } 4983445Sroot if (upaddr->uper1&UPER1_WLE) { 4992674Swnj /* 5002674Swnj * Give up on write locked devices 5012674Swnj * immediately. 5022674Swnj */ 5032931Swnj printf("up%d: write locked\n", dkunit(bp)); 5042674Swnj bp->b_flags |= B_ERROR; 5052674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5062674Swnj /* 5072674Swnj * After 28 retries (16 without offset, and 5082674Swnj * 12 with offset positioning) give up. 5092674Swnj */ 5102931Swnj harderr(bp, "up"); 5112931Swnj printf("cs2=%b er1=%b er2=%b\n", 5122785Swnj upaddr->upcs2, UPCS2_BITS, 5132785Swnj upaddr->uper1, UPER1_BITS, 5142785Swnj upaddr->uper2, UPER2_BITS); 5152674Swnj bp->b_flags |= B_ERROR; 5162674Swnj } else { 5172674Swnj /* 5182674Swnj * Retriable error. 5192674Swnj * If a soft ecc, correct it (continuing 5202674Swnj * by returning if necessary. 5212674Swnj * Otherwise fall through and retry the transfer 5222674Swnj */ 5232674Swnj um->um_tab.b_active = 0; /* force retry */ 5243445Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) 5252629Swnj if (upecc(ui)) 5262629Swnj return; 5272674Swnj } 5282674Swnj /* 5292674Swnj * Clear drive error and, every eight attempts, 5302674Swnj * (starting with the fourth) 5312674Swnj * recalibrate to clear the slate. 5322674Swnj */ 5332674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5342674Swnj needie = 0; 5353182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5362674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5373160Swnj sc->sc_recal = 0; 5383160Swnj goto nextrecal; 5392674Swnj } 5402674Swnj } 5412674Swnj /* 5423160Swnj * Advance recalibration finite state machine 5433160Swnj * if recalibrate in progress, through 5443160Swnj * RECAL 5453160Swnj * SEEK 5463160Swnj * OFFSET (optional) 5473160Swnj * RETRY 5482674Swnj */ 5493160Swnj switch (sc->sc_recal) { 5503160Swnj 5513160Swnj case 1: 5523160Swnj upaddr->updc = bp->b_cylin; 5533160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 5543160Swnj goto nextrecal; 5553160Swnj case 2: 5563160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 5573160Swnj goto donerecal; 5583445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 5593160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 5603160Swnj goto nextrecal; 5613160Swnj nextrecal: 5623160Swnj sc->sc_recal++; 5633160Swnj um->um_tab.b_active = 1; 5643160Swnj return; 5653160Swnj donerecal: 5663160Swnj case 3: 5672674Swnj sc->sc_recal = 0; 5683160Swnj um->um_tab.b_active = 0; 5693160Swnj break; 5702674Swnj } 5712674Swnj /* 5722674Swnj * If still ``active'', then don't need any more retries. 5732674Swnj */ 5742674Swnj if (um->um_tab.b_active) { 5752674Swnj /* 5762674Swnj * If we were offset positioning, 5772674Swnj * return to centerline. 5782674Swnj */ 5792674Swnj if (um->um_tab.b_errcnt >= 16) { 5803445Sroot upaddr->upof = UPOF_FMT22; 5812674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 5823445Sroot while (upaddr->upds & UPDS_PIP) 5832674Swnj DELAY(25); 584268Sbill needie = 0; 585264Sbill } 5862674Swnj um->um_tab.b_active = 0; 5872674Swnj um->um_tab.b_errcnt = 0; 5882674Swnj um->um_tab.b_actf = dp->b_forw; 5892674Swnj dp->b_active = 0; 5902674Swnj dp->b_errcnt = 0; 5912674Swnj dp->b_actf = bp->av_forw; 5922674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 5932674Swnj iodone(bp); 5942674Swnj /* 5952674Swnj * If this unit has more work to do, 5962674Swnj * then start it up right away. 5972674Swnj */ 5982674Swnj if (dp->b_actf) 5992674Swnj if (upustart(ui)) 600268Sbill needie = 0; 601264Sbill } 6022674Swnj as &= ~(1<<ui->ui_slave); 6033403Swnj /* 6043403Swnj * Release unibus resources and flush data paths. 6053403Swnj */ 6063403Swnj ubadone(um); 6072674Swnj doattn: 6082674Swnj /* 6092674Swnj * Process other units which need attention. 6102674Swnj * For each unit which needs attention, call 6112674Swnj * the unit start routine to place the slave 6122674Swnj * on the controller device queue. 6132674Swnj */ 6143160Swnj while (unit = ffs(as)) { 6153160Swnj unit--; /* was 1 origin */ 6163160Swnj as &= ~(1<<unit); 6173160Swnj upaddr->upas = 1<<unit; 6183160Swnj if (upustart(upip[sc21][unit])) 6193160Swnj needie = 0; 6203160Swnj } 6212674Swnj /* 6222674Swnj * If the controller is not transferring, but 6232674Swnj * there are devices ready to transfer, start 6242674Swnj * the controller. 6252674Swnj */ 6262395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6272395Swnj if (upstart(um)) 628268Sbill needie = 0; 629275Sbill if (needie) 6302629Swnj upaddr->upcs1 = UP_IE; 631264Sbill } 632264Sbill 633264Sbill upread(dev) 6342616Swnj dev_t dev; 635264Sbill { 6362616Swnj register int unit = minor(dev) >> 3; 6372470Swnj 6382616Swnj if (unit >= NUP) 6392616Swnj u.u_error = ENXIO; 6402616Swnj else 6412616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 642264Sbill } 643264Sbill 644264Sbill upwrite(dev) 6452616Swnj dev_t dev; 646264Sbill { 6472616Swnj register int unit = minor(dev) >> 3; 6482470Swnj 6492616Swnj if (unit >= NUP) 6502616Swnj u.u_error = ENXIO; 6512616Swnj else 6522616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 653264Sbill } 654264Sbill 655266Sbill /* 656266Sbill * Correct an ECC error, and restart the i/o to complete 657266Sbill * the transfer if necessary. This is quite complicated because 658266Sbill * the transfer may be going to an odd memory address base and/or 659266Sbill * across a page boundary. 660266Sbill */ 6612395Swnj upecc(ui) 6622983Swnj register struct uba_device *ui; 663264Sbill { 6642629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6652395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6662983Swnj register struct uba_ctlr *um = ui->ui_mi; 6672395Swnj register struct upst *st; 6682395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 669266Sbill register int i; 670264Sbill caddr_t addr; 671266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 672264Sbill int bn, cn, tn, sn; 673264Sbill 674264Sbill /* 675266Sbill * Npf is the number of sectors transferred before the sector 676266Sbill * containing the ECC error, and reg is the UBA register 677266Sbill * mapping (the first part of) the transfer. 678266Sbill * O is offset within a memory page of the first byte transferred. 679264Sbill */ 680266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 6812571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 682264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 6832983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 6842889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 685264Sbill mask = up->upec2; 6863445Sroot #ifdef UPECCDEBUG 6873403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 6883403Swnj up->upec1); 6893445Sroot #endif 690266Sbill /* 691266Sbill * Flush the buffered data path, and compute the 692266Sbill * byte and bit position of the error. The variable i 693266Sbill * is the byte offset in the transfer, the variable byte 694266Sbill * is the offset from a page boundary in main memory. 695266Sbill */ 6962725Swnj ubapurge(um); 697266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 698266Sbill bit = i&07; 699266Sbill i = (i&~07)>>3; 700264Sbill byte = i + o; 701266Sbill /* 702266Sbill * Correct while possible bits remain of mask. Since mask 703266Sbill * contains 11 bits, we continue while the bit offset is > -11. 704266Sbill * Also watch out for end of this block and the end of the whole 705266Sbill * transfer. 706266Sbill */ 707266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 708266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 709266Sbill (byte & PGOFSET); 7103445Sroot #ifdef UPECCDEBUG 7113403Swnj printf("addr %x map reg %x\n", 7123403Swnj addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 7133403Swnj printf("old: %x, ", getmemc(addr)); 7143445Sroot #endif 715266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 7163445Sroot #ifdef UPECCDEBUG 7173403Swnj printf("new: %x\n", getmemc(addr)); 7183445Sroot #endif 719266Sbill byte++; 720266Sbill i++; 721266Sbill bit -= 8; 722264Sbill } 7232395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 724264Sbill if (up->upwc == 0) 725264Sbill return (0); 726266Sbill /* 727266Sbill * Have to continue the transfer... clear the drive, 728266Sbill * and compute the position where the transfer is to continue. 729266Sbill * We have completed npf+1 sectors of the transfer already; 730266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 731266Sbill */ 7322629Swnj #ifdef notdef 7332629Swnj up->uper1 = 0; 7342629Swnj up->upcs1 |= UP_GO; 7352629Swnj #else 7362629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 737264Sbill bn = dkblock(bp); 7382395Swnj st = &upst[ui->ui_type]; 739264Sbill cn = bp->b_cylin; 7402395Swnj sn = bn%st->nspc + npf + 1; 7412395Swnj tn = sn/st->nsect; 7422395Swnj sn %= st->nsect; 7432395Swnj cn += tn/st->ntrak; 7442395Swnj tn %= st->ntrak; 745264Sbill up->updc = cn; 746266Sbill up->upda = (tn << 8) | sn; 747266Sbill ubaddr = (int)ptob(reg+1) + o; 748266Sbill up->upba = ubaddr; 749266Sbill cmd = (ubaddr >> 8) & 0x300; 7502629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 751266Sbill up->upcs1 = cmd; 7522629Swnj #endif 753264Sbill return (1); 754264Sbill } 755286Sbill 756286Sbill /* 757286Sbill * Reset driver after UBA init. 758286Sbill * Cancel software state of all pending transfers 759286Sbill * and restart all units and the controller. 760286Sbill */ 7612395Swnj upreset(uban) 7622931Swnj int uban; 763286Sbill { 7642983Swnj register struct uba_ctlr *um; 7652983Swnj register struct uba_device *ui; 7662395Swnj register sc21, unit; 767286Sbill 7682646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7692470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7702470Swnj um->um_alive == 0) 7712395Swnj continue; 7722931Swnj printf(" sc%d", sc21); 7732395Swnj um->um_tab.b_active = 0; 7742395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7752931Swnj up_softc[sc21].sc_recal = 0; 7762571Swnj if (um->um_ubinfo) { 7772571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7782616Swnj ubadone(um); 7792395Swnj } 7803445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 7812395Swnj for (unit = 0; unit < NUP; unit++) { 7822395Swnj if ((ui = updinfo[unit]) == 0) 7832395Swnj continue; 7842931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 7852395Swnj continue; 7862395Swnj uputab[unit].b_active = 0; 7872395Swnj (void) upustart(ui); 7882395Swnj } 7892395Swnj (void) upstart(um); 790286Sbill } 791286Sbill } 792313Sbill 793313Sbill /* 794313Sbill * Wake up every second and if an interrupt is pending 795313Sbill * but nothing has happened increment a counter. 7962931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 797313Sbill * and begin anew. 798313Sbill */ 799313Sbill upwatch() 800313Sbill { 8012983Swnj register struct uba_ctlr *um; 8022395Swnj register sc21, unit; 8032470Swnj register struct up_softc *sc; 804313Sbill 8052759Swnj timeout(upwatch, (caddr_t)0, hz); 8062646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 8072395Swnj um = upminfo[sc21]; 8082470Swnj if (um == 0 || um->um_alive == 0) 8092470Swnj continue; 8102470Swnj sc = &up_softc[sc21]; 8112395Swnj if (um->um_tab.b_active == 0) { 8122395Swnj for (unit = 0; unit < NUP; unit++) 8132629Swnj if (uputab[unit].b_active && 8142629Swnj updinfo[unit]->ui_mi == um) 8152395Swnj goto active; 8162470Swnj sc->sc_wticks = 0; 8172395Swnj continue; 8182395Swnj } 8192931Swnj active: 8202470Swnj sc->sc_wticks++; 8212470Swnj if (sc->sc_wticks >= 20) { 8222470Swnj sc->sc_wticks = 0; 8232931Swnj printf("sc%d: lost interrupt\n", sc21); 8242646Swnj ubareset(um->um_ubanum); 8252395Swnj } 826313Sbill } 827313Sbill } 8282379Swnj 8292379Swnj #define DBSIZE 20 8302379Swnj 8312379Swnj updump(dev) 8322379Swnj dev_t dev; 8332379Swnj { 8342629Swnj struct updevice *upaddr; 8352379Swnj char *start; 8363107Swnj int num, blk, unit; 8372379Swnj struct size *sizes; 8382395Swnj register struct uba_regs *uba; 8392983Swnj register struct uba_device *ui; 8402379Swnj register short *rp; 8412395Swnj struct upst *st; 8422379Swnj 8432395Swnj unit = minor(dev) >> 3; 8442889Swnj if (unit >= NUP) 8452889Swnj return (ENXIO); 8462470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8472983Swnj ui = phys(struct uba_device *, updinfo[unit]); 8482889Swnj if (ui->ui_alive == 0) 8492889Swnj return (ENXIO); 8502395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8512983Swnj ubainit(uba); 8522629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8532983Swnj DELAY(2000000); 8542379Swnj num = maxfree; 8552379Swnj start = 0; 8562379Swnj upaddr->upcs2 = unit; 8572983Swnj DELAY(100); 8582983Swnj if ((upaddr->upcs1&UP_DVA) == 0) 8592983Swnj return (EFAULT); 8603445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 8612629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 8622629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 8633445Sroot upaddr->upof = UPOF_FMT22; 8642379Swnj } 8653445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 8662889Swnj return (EFAULT); 8672470Swnj st = &upst[ui->ui_type]; 8682395Swnj sizes = phys(struct size *, st->sizes); 8692889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 8702889Swnj return (EINVAL); 8712379Swnj while (num > 0) { 8722379Swnj register struct pte *io; 8732379Swnj register int i; 8742379Swnj int cn, sn, tn; 8752379Swnj daddr_t bn; 8762379Swnj 8772379Swnj blk = num > DBSIZE ? DBSIZE : num; 8782395Swnj io = uba->uba_map; 8792379Swnj for (i = 0; i < blk; i++) 8802983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 8812379Swnj *(int *)io = 0; 8822379Swnj bn = dumplo + btop(start); 8832607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 8842607Swnj sn = bn%st->nspc; 8852607Swnj tn = sn/st->nsect; 8862607Swnj sn = sn%st->nsect; 8872379Swnj upaddr->updc = cn; 8882379Swnj rp = (short *) &upaddr->upda; 8892379Swnj *rp = (tn << 8) + sn; 8902379Swnj *--rp = 0; 8912379Swnj *--rp = -blk*NBPG / sizeof (short); 8922629Swnj *--rp = UP_GO|UP_WCOM; 8932379Swnj do { 8942379Swnj DELAY(25); 8952629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 8963445Sroot if (upaddr->upds&UPDS_ERR) 8972889Swnj return (EIO); 8982379Swnj start += blk*NBPG; 8992379Swnj num -= blk; 9002379Swnj } 9012379Swnj return (0); 9022379Swnj } 9031902Swnj #endif 904