1*3553Swnj /* up.c 4.38 81/04/18 */ 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 */ 50264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 51264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 52264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 532395Swnj }, fj_sizes[8] = { 542395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 552395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 562395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 572395Swnj 0, 0, 582395Swnj 0, 0, 592395Swnj 0, 0, 602395Swnj 0, 0, 612395Swnj 213760, 155, /* H=cyl 155 thru 822 */ 62264Sbill }; 632395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 64264Sbill 652395Swnj #define _upSDIST 2 /* 1.0 msec */ 662395Swnj #define _upRDIST 4 /* 2.0 msec */ 67264Sbill 682395Swnj int upSDIST = _upSDIST; 692395Swnj int upRDIST = _upRDIST; 702395Swnj 712607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 722983Swnj struct uba_ctlr *upminfo[NSC]; 732983Swnj struct uba_device *updinfo[NUP]; 742983Swnj struct uba_device *upip[NSC][4]; 752395Swnj 762607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 772616Swnj struct uba_driver scdriver = 782607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 792395Swnj struct buf uputab[NUP]; 802395Swnj 812395Swnj struct upst { 822395Swnj short nsect; 832395Swnj short ntrak; 842395Swnj short nspc; 852395Swnj short ncyl; 862395Swnj struct size *sizes; 872395Swnj } upst[] = { 882607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 892607Swnj /* 9300 actually has 815 cylinders... */ 902395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 912395Swnj }; 922395Swnj 932629Swnj u_char up_offset[16] = { 943445Sroot UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 953445Sroot UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 963445Sroot UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 973445Sroot 0, 0, 0, 0 982629Swnj }; 99264Sbill 1002616Swnj struct buf rupbuf[NUP]; 101264Sbill 102264Sbill #define b_cylin b_resid 103264Sbill 104264Sbill #ifdef INTRLVE 105264Sbill daddr_t dkblock(); 106264Sbill #endif 1072395Swnj 1082395Swnj int upwstart, upwatch(); /* Have started guardian */ 1092470Swnj int upseek; 1102681Swnj int upwaitdry; 1112395Swnj 1122395Swnj /*ARGSUSED*/ 1132607Swnj upprobe(reg) 1142395Swnj caddr_t reg; 1152395Swnj { 1162459Swnj register int br, cvec; 1172459Swnj 1182607Swnj #ifdef lint 1192607Swnj br = 0; cvec = br; br = cvec; 1202607Swnj #endif 1212629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1222607Swnj DELAY(10); 1232629Swnj ((struct updevice *)reg)->upcs1 = 0; 1242459Swnj return (1); 1252395Swnj } 1262395Swnj 1272607Swnj upslave(ui, reg) 1282983Swnj struct uba_device *ui; 1292395Swnj caddr_t reg; 1302395Swnj { 1312629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1322395Swnj 1332395Swnj upaddr->upcs1 = 0; /* conservative */ 1342607Swnj upaddr->upcs2 = ui->ui_slave; 1353445Sroot if (upaddr->upcs2&UPCS2_NED) { 1362629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1372395Swnj return (0); 1382395Swnj } 1392607Swnj return (1); 1402607Swnj } 1412607Swnj 1422607Swnj upattach(ui) 1432983Swnj register struct uba_device *ui; 1442607Swnj { 1452629Swnj register struct updevice *upaddr; 1462607Swnj 1472395Swnj if (upwstart == 0) { 1482759Swnj timeout(upwatch, (caddr_t)0, hz); 1492395Swnj upwstart++; 1502395Swnj } 1512571Swnj if (ui->ui_dk >= 0) 1522571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1532607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1542607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1552629Swnj upaddr = (struct updevice *)ui->ui_addr; 1562629Swnj upaddr->upcs1 = 0; 1572629Swnj upaddr->upcs2 = ui->ui_slave; 1583496Sroot upaddr->uphr = UPHR_MAXTRAK; 159*3553Swnj if (upaddr->uphr == 9) 1603496Sroot ui->ui_type = 1; /* fujitsu hack */ 1613496Sroot upaddr->upcs2 = UPCS2_CLR; 1623496Sroot /* 1633496Sroot upaddr->uphr = UPHR_MAXCYL; 1643496Sroot printf("maxcyl %d\n", upaddr->uphr); 1653496Sroot upaddr->uphr = UPHR_MAXTRAK; 1663496Sroot printf("maxtrak %d\n", upaddr->uphr); 1673496Sroot upaddr->uphr = UPHR_MAXSECT; 1683496Sroot printf("maxsect %d\n", upaddr->uphr); 1693496Sroot */ 1702395Swnj } 171264Sbill 172264Sbill upstrategy(bp) 1732395Swnj register struct buf *bp; 174264Sbill { 1752983Swnj register struct uba_device *ui; 1762395Swnj register struct upst *st; 1772395Swnj register int unit; 1782470Swnj register struct buf *dp; 1792395Swnj int xunit = minor(bp->b_dev) & 07; 1802470Swnj long bn, sz; 181264Sbill 1822470Swnj sz = (bp->b_bcount+511) >> 9; 183264Sbill unit = dkunit(bp); 1842395Swnj if (unit >= NUP) 1852395Swnj goto bad; 1862395Swnj ui = updinfo[unit]; 1872395Swnj if (ui == 0 || ui->ui_alive == 0) 1882395Swnj goto bad; 1892395Swnj st = &upst[ui->ui_type]; 1902395Swnj if (bp->b_blkno < 0 || 1912395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1922395Swnj goto bad; 1932395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 194264Sbill (void) spl5(); 1952470Swnj dp = &uputab[ui->ui_unit]; 1962470Swnj disksort(dp, bp); 1972470Swnj if (dp->b_active == 0) { 1982395Swnj (void) upustart(ui); 1992395Swnj bp = &ui->ui_mi->um_tab; 2002395Swnj if (bp->b_actf && bp->b_active == 0) 2012395Swnj (void) upstart(ui->ui_mi); 202264Sbill } 203264Sbill (void) spl0(); 2042395Swnj return; 2052395Swnj 2062395Swnj bad: 2072395Swnj bp->b_flags |= B_ERROR; 2082395Swnj iodone(bp); 2092395Swnj return; 210264Sbill } 211264Sbill 2122674Swnj /* 2132674Swnj * Unit start routine. 2142674Swnj * Seek the drive to be where the data is 2152674Swnj * and then generate another interrupt 2162674Swnj * to actually start the transfer. 2172674Swnj * If there is only one drive on the controller, 2182674Swnj * or we are very close to the data, don't 2192674Swnj * bother with the search. If called after 2202674Swnj * searching once, don't bother to look where 2212674Swnj * we are, just queue for transfer (to avoid 2222674Swnj * positioning forever without transferrring.) 2232674Swnj */ 2242395Swnj upustart(ui) 2252983Swnj register struct uba_device *ui; 226264Sbill { 227264Sbill register struct buf *bp, *dp; 2282983Swnj register struct uba_ctlr *um; 2292629Swnj register struct updevice *upaddr; 2302395Swnj register struct upst *st; 231264Sbill daddr_t bn; 2322674Swnj int sn, csn; 2332607Swnj /* 2342607Swnj * The SC21 cancels commands if you just say 2352629Swnj * cs1 = UP_IE 2362607Swnj * so we are cautious about handling of cs1. 2372607Swnj * Also don't bother to clear as bits other than in upintr(). 2382607Swnj */ 2392674Swnj int didie = 0; 2402674Swnj 2412674Swnj if (ui == 0) 2422674Swnj return (0); 2432983Swnj um = ui->ui_mi; 2442395Swnj dk_busy &= ~(1<<ui->ui_dk); 2452395Swnj dp = &uputab[ui->ui_unit]; 246266Sbill if ((bp = dp->b_actf) == NULL) 247268Sbill goto out; 2482674Swnj /* 2492674Swnj * If the controller is active, just remember 2502674Swnj * that this device would like to be positioned... 2512674Swnj * if we tried to position now we would confuse the SC21. 2522674Swnj */ 2532395Swnj if (um->um_tab.b_active) { 2542459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 255275Sbill return (0); 256275Sbill } 2572674Swnj /* 2582674Swnj * If we have already positioned this drive, 2592674Swnj * then just put it on the ready queue. 2602674Swnj */ 261276Sbill if (dp->b_active) 262276Sbill goto done; 263276Sbill dp->b_active = 1; 2642629Swnj upaddr = (struct updevice *)um->um_addr; 2652395Swnj upaddr->upcs2 = ui->ui_slave; 2662674Swnj /* 2672674Swnj * If drive has just come up, 2682674Swnj * setup the pack. 2692674Swnj */ 2703445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 2712607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2722629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2732629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 2743445Sroot upaddr->upof = UPOF_FMT22; 275268Sbill didie = 1; 276264Sbill } 2772674Swnj /* 2782674Swnj * If drive is offline, forget about positioning. 2792674Swnj */ 2803445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 281275Sbill goto done; 2822674Swnj /* 2832674Swnj * If there is only one drive, 2842674Swnj * dont bother searching. 2852674Swnj */ 2862607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 2872607Swnj goto done; 2882674Swnj /* 2892674Swnj * Figure out where this transfer is going to 2902674Swnj * and see if we are close enough to justify not searching. 2912674Swnj */ 2922395Swnj st = &upst[ui->ui_type]; 293264Sbill bn = dkblock(bp); 2942395Swnj sn = bn%st->nspc; 2952395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 2962674Swnj if (bp->b_cylin - upaddr->updc) 297266Sbill goto search; /* Not on-cylinder */ 298275Sbill else if (upseek) 299275Sbill goto done; /* Ok just to be on-cylinder */ 300264Sbill csn = (upaddr->upla>>6) - sn - 1; 301266Sbill if (csn < 0) 3022395Swnj csn += st->nsect; 3032395Swnj if (csn > st->nsect - upRDIST) 304264Sbill goto done; 305264Sbill search: 3062674Swnj upaddr->updc = bp->b_cylin; 3072674Swnj /* 3082674Swnj * Not on cylinder at correct position, 3092674Swnj * seek/search. 3102674Swnj */ 311275Sbill if (upseek) 3122629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3132470Swnj else { 314275Sbill upaddr->upda = sn; 3152629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 316275Sbill } 317268Sbill didie = 1; 3182674Swnj /* 3192674Swnj * Mark unit busy for iostat. 3202674Swnj */ 3212395Swnj if (ui->ui_dk >= 0) { 3222395Swnj dk_busy |= 1<<ui->ui_dk; 3232395Swnj dk_seek[ui->ui_dk]++; 324264Sbill } 325268Sbill goto out; 326264Sbill done: 3272674Swnj /* 3282674Swnj * Device is ready to go. 3292674Swnj * Put it on the ready queue for the controller 3302674Swnj * (unless its already there.) 3312674Swnj */ 3322629Swnj if (dp->b_active != 2) { 3332629Swnj dp->b_forw = NULL; 3342629Swnj if (um->um_tab.b_actf == NULL) 3352629Swnj um->um_tab.b_actf = dp; 3362629Swnj else 3372629Swnj um->um_tab.b_actl->b_forw = dp; 3382629Swnj um->um_tab.b_actl = dp; 3392629Swnj dp->b_active = 2; 3402629Swnj } 341268Sbill out: 342268Sbill return (didie); 343264Sbill } 344264Sbill 3452674Swnj /* 3462674Swnj * Start up a transfer on a drive. 3472674Swnj */ 3482395Swnj upstart(um) 3492983Swnj register struct uba_ctlr *um; 350264Sbill { 351264Sbill register struct buf *bp, *dp; 3522983Swnj register struct uba_device *ui; 3532629Swnj register struct updevice *upaddr; 3542470Swnj struct upst *st; 355264Sbill daddr_t bn; 3562681Swnj int dn, sn, tn, cmd, waitdry; 357264Sbill 358264Sbill loop: 3592674Swnj /* 3602674Swnj * Pull a request off the controller queue 3612674Swnj */ 3622395Swnj if ((dp = um->um_tab.b_actf) == NULL) 363268Sbill return (0); 364264Sbill if ((bp = dp->b_actf) == NULL) { 3652395Swnj um->um_tab.b_actf = dp->b_forw; 366264Sbill goto loop; 367264Sbill } 3682674Swnj /* 3692674Swnj * Mark controller busy, and 3702674Swnj * determine destination of this request. 3712674Swnj */ 3722395Swnj um->um_tab.b_active++; 3732395Swnj ui = updinfo[dkunit(bp)]; 374264Sbill bn = dkblock(bp); 3752395Swnj dn = ui->ui_slave; 3762395Swnj st = &upst[ui->ui_type]; 3772395Swnj sn = bn%st->nspc; 3782395Swnj tn = sn/st->nsect; 3792395Swnj sn %= st->nsect; 3802629Swnj upaddr = (struct updevice *)ui->ui_addr; 3812674Swnj /* 3822674Swnj * Select drive if not selected already. 3832674Swnj */ 3842674Swnj if ((upaddr->upcs2&07) != dn) 3852674Swnj upaddr->upcs2 = dn; 3862674Swnj /* 3872674Swnj * Check that it is ready and online 3882674Swnj */ 3892681Swnj waitdry = 0; 3903445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 3912681Swnj if (++waitdry > 512) 3922681Swnj break; 3932681Swnj upwaitdry++; 3942681Swnj } 3953445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 3962931Swnj printf("up%d: not ready", dkunit(bp)); 3973445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 3982607Swnj printf("\n"); 3992395Swnj um->um_tab.b_active = 0; 4002395Swnj um->um_tab.b_errcnt = 0; 401893Sbill dp->b_actf = bp->av_forw; 402893Sbill dp->b_active = 0; 403893Sbill bp->b_flags |= B_ERROR; 404893Sbill iodone(bp); 405893Sbill goto loop; 406893Sbill } 4072674Swnj /* 4082674Swnj * Oh, well, sometimes this 4092674Swnj * happens, for reasons unknown. 4102674Swnj */ 4112629Swnj printf(" (flakey)\n"); 412264Sbill } 4132674Swnj /* 4142674Swnj * Setup for the transfer, and get in the 4152674Swnj * UNIBUS adaptor queue. 4162674Swnj */ 4172424Skre upaddr->updc = bp->b_cylin; 418264Sbill upaddr->upda = (tn << 8) + sn; 419264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 420264Sbill if (bp->b_flags & B_READ) 4212629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 422264Sbill else 4232629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4242571Swnj um->um_cmd = cmd; 4253107Swnj (void) ubago(ui); 426268Sbill return (1); 427264Sbill } 428264Sbill 4292674Swnj /* 4302674Swnj * Now all ready to go, stuff the registers. 4312674Swnj */ 4322571Swnj updgo(um) 4332983Swnj struct uba_ctlr *um; 4342395Swnj { 4352629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4362470Swnj 4372571Swnj upaddr->upba = um->um_ubinfo; 4382571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4392395Swnj } 4402395Swnj 4412674Swnj /* 4422674Swnj * Handle a disk interrupt. 4432674Swnj */ 4442707Swnj upintr(sc21) 4452395Swnj register sc21; 446264Sbill { 447264Sbill register struct buf *bp, *dp; 4482983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4492983Swnj register struct uba_device *ui; 4502629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 451264Sbill register unit; 4522470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4532607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4542681Swnj int needie = 1, waitdry; 455264Sbill 4562470Swnj sc->sc_wticks = 0; 4572607Swnj sc->sc_softas = 0; 4582674Swnj /* 4592674Swnj * If controller wasn't transferring, then this is an 4602674Swnj * interrupt for attention status on seeking drives. 4612674Swnj * Just service them. 4622674Swnj */ 4632674Swnj if (um->um_tab.b_active == 0) { 4642674Swnj if (upaddr->upcs1 & UP_TRE) 4652674Swnj upaddr->upcs1 = UP_TRE; 4662674Swnj goto doattn; 4672674Swnj } 4682674Swnj /* 4692674Swnj * Get device and block structures, and a pointer 4702983Swnj * to the uba_device for the drive. Select the drive. 4712674Swnj */ 4722674Swnj dp = um->um_tab.b_actf; 4732674Swnj bp = dp->b_actf; 4742674Swnj ui = updinfo[dkunit(bp)]; 4752674Swnj dk_busy &= ~(1 << ui->ui_dk); 4762674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 4772395Swnj upaddr->upcs2 = ui->ui_slave; 4782674Swnj /* 4792674Swnj * Check for and process errors on 4802674Swnj * either the drive or the controller. 4812674Swnj */ 4823445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 4832681Swnj waitdry = 0; 4843445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 4852681Swnj if (++waitdry > 512) 4862681Swnj break; 4872681Swnj upwaitdry++; 4882681Swnj } 4893445Sroot if (upaddr->uper1&UPER1_WLE) { 4902674Swnj /* 4912674Swnj * Give up on write locked devices 4922674Swnj * immediately. 4932674Swnj */ 4942931Swnj printf("up%d: write locked\n", dkunit(bp)); 4952674Swnj bp->b_flags |= B_ERROR; 4962674Swnj } else if (++um->um_tab.b_errcnt > 27) { 4972674Swnj /* 4982674Swnj * After 28 retries (16 without offset, and 4992674Swnj * 12 with offset positioning) give up. 5002674Swnj */ 5012931Swnj harderr(bp, "up"); 5022931Swnj printf("cs2=%b er1=%b er2=%b\n", 5032785Swnj upaddr->upcs2, UPCS2_BITS, 5042785Swnj upaddr->uper1, UPER1_BITS, 5052785Swnj upaddr->uper2, UPER2_BITS); 5062674Swnj bp->b_flags |= B_ERROR; 5072674Swnj } else { 5082674Swnj /* 5092674Swnj * Retriable error. 5102674Swnj * If a soft ecc, correct it (continuing 5112674Swnj * by returning if necessary. 5122674Swnj * Otherwise fall through and retry the transfer 5132674Swnj */ 5142674Swnj um->um_tab.b_active = 0; /* force retry */ 5153445Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) 5162629Swnj if (upecc(ui)) 5172629Swnj return; 5182674Swnj } 5192674Swnj /* 5202674Swnj * Clear drive error and, every eight attempts, 5212674Swnj * (starting with the fourth) 5222674Swnj * recalibrate to clear the slate. 5232674Swnj */ 5242674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5252674Swnj needie = 0; 5263182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5272674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5283160Swnj sc->sc_recal = 0; 5293160Swnj goto nextrecal; 5302674Swnj } 5312674Swnj } 5322674Swnj /* 5333160Swnj * Advance recalibration finite state machine 5343160Swnj * if recalibrate in progress, through 5353160Swnj * RECAL 5363160Swnj * SEEK 5373160Swnj * OFFSET (optional) 5383160Swnj * RETRY 5392674Swnj */ 5403160Swnj switch (sc->sc_recal) { 5413160Swnj 5423160Swnj case 1: 5433160Swnj upaddr->updc = bp->b_cylin; 5443160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 5453160Swnj goto nextrecal; 5463160Swnj case 2: 5473160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 5483160Swnj goto donerecal; 5493445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 5503160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 5513160Swnj goto nextrecal; 5523160Swnj nextrecal: 5533160Swnj sc->sc_recal++; 5543160Swnj um->um_tab.b_active = 1; 5553160Swnj return; 5563160Swnj donerecal: 5573160Swnj case 3: 5582674Swnj sc->sc_recal = 0; 5593160Swnj um->um_tab.b_active = 0; 5603160Swnj break; 5612674Swnj } 5622674Swnj /* 5632674Swnj * If still ``active'', then don't need any more retries. 5642674Swnj */ 5652674Swnj if (um->um_tab.b_active) { 5662674Swnj /* 5672674Swnj * If we were offset positioning, 5682674Swnj * return to centerline. 5692674Swnj */ 5702674Swnj if (um->um_tab.b_errcnt >= 16) { 5713445Sroot upaddr->upof = UPOF_FMT22; 5722674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 5733445Sroot while (upaddr->upds & UPDS_PIP) 5742674Swnj DELAY(25); 575268Sbill needie = 0; 576264Sbill } 5772674Swnj um->um_tab.b_active = 0; 5782674Swnj um->um_tab.b_errcnt = 0; 5792674Swnj um->um_tab.b_actf = dp->b_forw; 5802674Swnj dp->b_active = 0; 5812674Swnj dp->b_errcnt = 0; 5822674Swnj dp->b_actf = bp->av_forw; 5832674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 5842674Swnj iodone(bp); 5852674Swnj /* 5862674Swnj * If this unit has more work to do, 5872674Swnj * then start it up right away. 5882674Swnj */ 5892674Swnj if (dp->b_actf) 5902674Swnj if (upustart(ui)) 591268Sbill needie = 0; 592264Sbill } 5932674Swnj as &= ~(1<<ui->ui_slave); 5943403Swnj /* 5953403Swnj * Release unibus resources and flush data paths. 5963403Swnj */ 5973403Swnj ubadone(um); 5982674Swnj doattn: 5992674Swnj /* 6002674Swnj * Process other units which need attention. 6012674Swnj * For each unit which needs attention, call 6022674Swnj * the unit start routine to place the slave 6032674Swnj * on the controller device queue. 6042674Swnj */ 6053160Swnj while (unit = ffs(as)) { 6063160Swnj unit--; /* was 1 origin */ 6073160Swnj as &= ~(1<<unit); 6083160Swnj upaddr->upas = 1<<unit; 6093160Swnj if (upustart(upip[sc21][unit])) 6103160Swnj needie = 0; 6113160Swnj } 6122674Swnj /* 6132674Swnj * If the controller is not transferring, but 6142674Swnj * there are devices ready to transfer, start 6152674Swnj * the controller. 6162674Swnj */ 6172395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6182395Swnj if (upstart(um)) 619268Sbill needie = 0; 620275Sbill if (needie) 6212629Swnj upaddr->upcs1 = UP_IE; 622264Sbill } 623264Sbill 624264Sbill upread(dev) 6252616Swnj dev_t dev; 626264Sbill { 6272616Swnj register int unit = minor(dev) >> 3; 6282470Swnj 6292616Swnj if (unit >= NUP) 6302616Swnj u.u_error = ENXIO; 6312616Swnj else 6322616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 633264Sbill } 634264Sbill 635264Sbill upwrite(dev) 6362616Swnj dev_t dev; 637264Sbill { 6382616Swnj register int unit = minor(dev) >> 3; 6392470Swnj 6402616Swnj if (unit >= NUP) 6412616Swnj u.u_error = ENXIO; 6422616Swnj else 6432616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 644264Sbill } 645264Sbill 646266Sbill /* 647266Sbill * Correct an ECC error, and restart the i/o to complete 648266Sbill * the transfer if necessary. This is quite complicated because 649266Sbill * the transfer may be going to an odd memory address base and/or 650266Sbill * across a page boundary. 651266Sbill */ 6522395Swnj upecc(ui) 6532983Swnj register struct uba_device *ui; 654264Sbill { 6552629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6562395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6572983Swnj register struct uba_ctlr *um = ui->ui_mi; 6582395Swnj register struct upst *st; 6592395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 660266Sbill register int i; 661264Sbill caddr_t addr; 662266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 663264Sbill int bn, cn, tn, sn; 664264Sbill 665264Sbill /* 666266Sbill * Npf is the number of sectors transferred before the sector 667266Sbill * containing the ECC error, and reg is the UBA register 668266Sbill * mapping (the first part of) the transfer. 669266Sbill * O is offset within a memory page of the first byte transferred. 670264Sbill */ 671266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 6722571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 673264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 6742983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 6752889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 676264Sbill mask = up->upec2; 6773445Sroot #ifdef UPECCDEBUG 6783403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 6793403Swnj up->upec1); 6803445Sroot #endif 681266Sbill /* 682266Sbill * Flush the buffered data path, and compute the 683266Sbill * byte and bit position of the error. The variable i 684266Sbill * is the byte offset in the transfer, the variable byte 685266Sbill * is the offset from a page boundary in main memory. 686266Sbill */ 6872725Swnj ubapurge(um); 688266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 689266Sbill bit = i&07; 690266Sbill i = (i&~07)>>3; 691264Sbill byte = i + o; 692266Sbill /* 693266Sbill * Correct while possible bits remain of mask. Since mask 694266Sbill * contains 11 bits, we continue while the bit offset is > -11. 695266Sbill * Also watch out for end of this block and the end of the whole 696266Sbill * transfer. 697266Sbill */ 698266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 699266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 700266Sbill (byte & PGOFSET); 7013445Sroot #ifdef UPECCDEBUG 7023403Swnj printf("addr %x map reg %x\n", 7033403Swnj addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 7043403Swnj printf("old: %x, ", getmemc(addr)); 7053445Sroot #endif 706266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 7073445Sroot #ifdef UPECCDEBUG 7083403Swnj printf("new: %x\n", getmemc(addr)); 7093445Sroot #endif 710266Sbill byte++; 711266Sbill i++; 712266Sbill bit -= 8; 713264Sbill } 7142395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 715264Sbill if (up->upwc == 0) 716264Sbill return (0); 717266Sbill /* 718266Sbill * Have to continue the transfer... clear the drive, 719266Sbill * and compute the position where the transfer is to continue. 720266Sbill * We have completed npf+1 sectors of the transfer already; 721266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 722266Sbill */ 7232629Swnj #ifdef notdef 7242629Swnj up->uper1 = 0; 7252629Swnj up->upcs1 |= UP_GO; 7262629Swnj #else 7272629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 728264Sbill bn = dkblock(bp); 7292395Swnj st = &upst[ui->ui_type]; 730264Sbill cn = bp->b_cylin; 7312395Swnj sn = bn%st->nspc + npf + 1; 7322395Swnj tn = sn/st->nsect; 7332395Swnj sn %= st->nsect; 7342395Swnj cn += tn/st->ntrak; 7352395Swnj tn %= st->ntrak; 736264Sbill up->updc = cn; 737266Sbill up->upda = (tn << 8) | sn; 738266Sbill ubaddr = (int)ptob(reg+1) + o; 739266Sbill up->upba = ubaddr; 740266Sbill cmd = (ubaddr >> 8) & 0x300; 7412629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 742266Sbill up->upcs1 = cmd; 7432629Swnj #endif 744264Sbill return (1); 745264Sbill } 746286Sbill 747286Sbill /* 748286Sbill * Reset driver after UBA init. 749286Sbill * Cancel software state of all pending transfers 750286Sbill * and restart all units and the controller. 751286Sbill */ 7522395Swnj upreset(uban) 7532931Swnj int uban; 754286Sbill { 7552983Swnj register struct uba_ctlr *um; 7562983Swnj register struct uba_device *ui; 7572395Swnj register sc21, unit; 758286Sbill 7592646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7602470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7612470Swnj um->um_alive == 0) 7622395Swnj continue; 7632931Swnj printf(" sc%d", sc21); 7642395Swnj um->um_tab.b_active = 0; 7652395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7662931Swnj up_softc[sc21].sc_recal = 0; 7672571Swnj if (um->um_ubinfo) { 7682571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7692616Swnj ubadone(um); 7702395Swnj } 7713445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 7722395Swnj for (unit = 0; unit < NUP; unit++) { 7732395Swnj if ((ui = updinfo[unit]) == 0) 7742395Swnj continue; 7752931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 7762395Swnj continue; 7772395Swnj uputab[unit].b_active = 0; 7782395Swnj (void) upustart(ui); 7792395Swnj } 7802395Swnj (void) upstart(um); 781286Sbill } 782286Sbill } 783313Sbill 784313Sbill /* 785313Sbill * Wake up every second and if an interrupt is pending 786313Sbill * but nothing has happened increment a counter. 7872931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 788313Sbill * and begin anew. 789313Sbill */ 790313Sbill upwatch() 791313Sbill { 7922983Swnj register struct uba_ctlr *um; 7932395Swnj register sc21, unit; 7942470Swnj register struct up_softc *sc; 795313Sbill 7962759Swnj timeout(upwatch, (caddr_t)0, hz); 7972646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7982395Swnj um = upminfo[sc21]; 7992470Swnj if (um == 0 || um->um_alive == 0) 8002470Swnj continue; 8012470Swnj sc = &up_softc[sc21]; 8022395Swnj if (um->um_tab.b_active == 0) { 8032395Swnj for (unit = 0; unit < NUP; unit++) 8042629Swnj if (uputab[unit].b_active && 8052629Swnj updinfo[unit]->ui_mi == um) 8062395Swnj goto active; 8072470Swnj sc->sc_wticks = 0; 8082395Swnj continue; 8092395Swnj } 8102931Swnj active: 8112470Swnj sc->sc_wticks++; 8122470Swnj if (sc->sc_wticks >= 20) { 8132470Swnj sc->sc_wticks = 0; 8142931Swnj printf("sc%d: lost interrupt\n", sc21); 8152646Swnj ubareset(um->um_ubanum); 8162395Swnj } 817313Sbill } 818313Sbill } 8192379Swnj 8202379Swnj #define DBSIZE 20 8212379Swnj 8222379Swnj updump(dev) 8232379Swnj dev_t dev; 8242379Swnj { 8252629Swnj struct updevice *upaddr; 8262379Swnj char *start; 8273107Swnj int num, blk, unit; 8282379Swnj struct size *sizes; 8292395Swnj register struct uba_regs *uba; 8302983Swnj register struct uba_device *ui; 8312379Swnj register short *rp; 8322395Swnj struct upst *st; 8332379Swnj 8342395Swnj unit = minor(dev) >> 3; 8352889Swnj if (unit >= NUP) 8362889Swnj return (ENXIO); 8372470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8382983Swnj ui = phys(struct uba_device *, updinfo[unit]); 8392889Swnj if (ui->ui_alive == 0) 8402889Swnj return (ENXIO); 8412395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8422983Swnj ubainit(uba); 8432629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8442983Swnj DELAY(2000000); 8452379Swnj num = maxfree; 8462379Swnj start = 0; 8472379Swnj upaddr->upcs2 = unit; 8482983Swnj DELAY(100); 8492983Swnj if ((upaddr->upcs1&UP_DVA) == 0) 8502983Swnj return (EFAULT); 8513445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 8522629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 8532629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 8543445Sroot upaddr->upof = UPOF_FMT22; 8552379Swnj } 8563445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 8572889Swnj return (EFAULT); 8582470Swnj st = &upst[ui->ui_type]; 8592395Swnj sizes = phys(struct size *, st->sizes); 8602889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 8612889Swnj return (EINVAL); 8622379Swnj while (num > 0) { 8632379Swnj register struct pte *io; 8642379Swnj register int i; 8652379Swnj int cn, sn, tn; 8662379Swnj daddr_t bn; 8672379Swnj 8682379Swnj blk = num > DBSIZE ? DBSIZE : num; 8692395Swnj io = uba->uba_map; 8702379Swnj for (i = 0; i < blk; i++) 8712983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 8722379Swnj *(int *)io = 0; 8732379Swnj bn = dumplo + btop(start); 8742607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 8752607Swnj sn = bn%st->nspc; 8762607Swnj tn = sn/st->nsect; 8772607Swnj sn = sn%st->nsect; 8782379Swnj upaddr->updc = cn; 8792379Swnj rp = (short *) &upaddr->upda; 8802379Swnj *rp = (tn << 8) + sn; 8812379Swnj *--rp = 0; 8822379Swnj *--rp = -blk*NBPG / sizeof (short); 8832629Swnj *--rp = UP_GO|UP_WCOM; 8842379Swnj do { 8852379Swnj DELAY(25); 8862629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 8873445Sroot if (upaddr->upds&UPDS_ERR) 8882889Swnj return (EIO); 8892379Swnj start += blk*NBPG; 8902379Swnj num -= blk; 8912379Swnj } 8922379Swnj return (0); 8932379Swnj } 8941902Swnj #endif 895