1*2983Swnj /* up.c 4.30 81/03/07 */ 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 reading of bad sector information and disk layout from sector 1 102889Swnj * Add bad sector forwarding code 112889Swnj * Check multiple drive handling 122889Swnj * Check unibus reset code 13*2983Swnj * Check that offset recovery code, etc works 14264Sbill */ 151756Sbill #define DELAY(N) { register int d; d = N; while (--d > 0); } 16264Sbill 17264Sbill #include "../h/param.h" 18264Sbill #include "../h/systm.h" 192395Swnj #include "../h/cpu.h" 202395Swnj #include "../h/nexus.h" 21308Sbill #include "../h/dk.h" 22264Sbill #include "../h/buf.h" 23264Sbill #include "../h/conf.h" 24264Sbill #include "../h/dir.h" 25264Sbill #include "../h/user.h" 26264Sbill #include "../h/map.h" 27420Sbill #include "../h/pte.h" 28264Sbill #include "../h/mtpr.h" 292571Swnj #include "../h/vm.h" 30*2983Swnj #include "../h/ubavar.h" 31*2983Swnj #include "../h/ubareg.h" 322379Swnj #include "../h/cmap.h" 33264Sbill 342379Swnj #include "../h/upreg.h" 35264Sbill 362395Swnj struct up_softc { 372395Swnj int sc_softas; 382607Swnj int sc_ndrive; 392395Swnj int sc_wticks; 402674Swnj int sc_recal; 412646Swnj } up_softc[NSC]; 42275Sbill 432395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 44264Sbill struct size 45264Sbill { 46264Sbill daddr_t nblocks; 47264Sbill int cyloff; 48264Sbill } up_sizes[8] = { 49264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 50264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 51341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 52264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 53264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 54264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 55264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 56264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 572395Swnj }, fj_sizes[8] = { 582395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 592395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 602395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 612395Swnj 0, 0, 622395Swnj 0, 0, 632395Swnj 0, 0, 642395Swnj 0, 0, 652395Swnj 213760, 155, /* H=cyl 155 thru 822 */ 66264Sbill }; 672395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 68264Sbill 692395Swnj #define _upSDIST 2 /* 1.0 msec */ 702395Swnj #define _upRDIST 4 /* 2.0 msec */ 71264Sbill 722395Swnj int upSDIST = _upSDIST; 732395Swnj int upRDIST = _upRDIST; 742395Swnj 752607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 76*2983Swnj struct uba_ctlr *upminfo[NSC]; 77*2983Swnj struct uba_device *updinfo[NUP]; 78*2983Swnj struct uba_device *upip[NSC][4]; 792395Swnj 802607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 812616Swnj struct uba_driver scdriver = 822607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 832395Swnj struct buf uputab[NUP]; 842395Swnj 852395Swnj struct upst { 862395Swnj short nsect; 872395Swnj short ntrak; 882395Swnj short nspc; 892395Swnj short ncyl; 902395Swnj struct size *sizes; 912395Swnj } upst[] = { 922607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 932607Swnj /* 9300 actually has 815 cylinders... */ 942395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 952395Swnj }; 962395Swnj 972629Swnj u_char up_offset[16] = { 982629Swnj UP_P400, UP_M400, UP_P400, UP_M400, UP_P800, UP_M800, UP_P800, UP_M800, 992629Swnj UP_P1200, UP_M1200, UP_P1200, UP_M1200, 0, 0, 0, 0 1002629Swnj }; 101264Sbill 1022616Swnj struct buf rupbuf[NUP]; 103264Sbill 104264Sbill #define b_cylin b_resid 105264Sbill 106264Sbill #ifdef INTRLVE 107264Sbill daddr_t dkblock(); 108264Sbill #endif 1092395Swnj 1102395Swnj int upwstart, upwatch(); /* Have started guardian */ 1112470Swnj int upseek; 1122681Swnj int upwaitdry; 1132395Swnj 1142395Swnj /*ARGSUSED*/ 1152607Swnj upprobe(reg) 1162395Swnj caddr_t reg; 1172395Swnj { 1182459Swnj register int br, cvec; 1192459Swnj 1202607Swnj #ifdef lint 1212607Swnj br = 0; cvec = br; br = cvec; 1222607Swnj #endif 1232629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1242607Swnj DELAY(10); 1252629Swnj ((struct updevice *)reg)->upcs1 = 0; 1262459Swnj return (1); 1272395Swnj } 1282395Swnj 1292607Swnj upslave(ui, reg) 130*2983Swnj struct uba_device *ui; 1312395Swnj caddr_t reg; 1322395Swnj { 1332629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1342395Swnj 1352395Swnj upaddr->upcs1 = 0; /* conservative */ 1362607Swnj upaddr->upcs2 = ui->ui_slave; 1372629Swnj if (upaddr->upcs2&UP_NED) { 1382629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1392395Swnj return (0); 1402395Swnj } 1412607Swnj return (1); 1422607Swnj } 1432607Swnj 1442607Swnj upattach(ui) 145*2983Swnj register struct uba_device *ui; 1462607Swnj { 1472629Swnj #ifdef notdef 1482629Swnj register struct updevice *upaddr; 1492629Swnj #endif 1502607Swnj 1512395Swnj if (upwstart == 0) { 1522759Swnj timeout(upwatch, (caddr_t)0, hz); 1532395Swnj upwstart++; 1542395Swnj } 1552571Swnj if (ui->ui_dk >= 0) 1562571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1572607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1582607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1592629Swnj #ifdef notdef 1602629Swnj upaddr = (struct updevice *)ui->ui_addr; 1612629Swnj upaddr->upcs1 = 0; 1622629Swnj upaddr->upcs2 = ui->ui_slave; 1632629Swnj upaddr->uphr = -1; 1642629Swnj /* ... */ 1652629Swnj if (upaddr-> ... == 10) 1662629Swnj ui->ui_type = 1; 1672629Swnj #endif 1682395Swnj } 169264Sbill 170264Sbill upstrategy(bp) 1712395Swnj register struct buf *bp; 172264Sbill { 173*2983Swnj register struct uba_device *ui; 1742395Swnj register struct upst *st; 1752395Swnj register int unit; 1762470Swnj register struct buf *dp; 1772395Swnj int xunit = minor(bp->b_dev) & 07; 1782470Swnj long bn, sz; 179264Sbill 1802470Swnj sz = (bp->b_bcount+511) >> 9; 181264Sbill unit = dkunit(bp); 1822395Swnj if (unit >= NUP) 1832395Swnj goto bad; 1842395Swnj ui = updinfo[unit]; 1852395Swnj if (ui == 0 || ui->ui_alive == 0) 1862395Swnj goto bad; 1872395Swnj st = &upst[ui->ui_type]; 1882395Swnj if (bp->b_blkno < 0 || 1892395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1902395Swnj goto bad; 1912395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 192264Sbill (void) spl5(); 1932470Swnj dp = &uputab[ui->ui_unit]; 1942470Swnj disksort(dp, bp); 1952470Swnj if (dp->b_active == 0) { 1962395Swnj (void) upustart(ui); 1972395Swnj bp = &ui->ui_mi->um_tab; 1982395Swnj if (bp->b_actf && bp->b_active == 0) 1992395Swnj (void) upstart(ui->ui_mi); 200264Sbill } 201264Sbill (void) spl0(); 2022395Swnj return; 2032395Swnj 2042395Swnj bad: 2052395Swnj bp->b_flags |= B_ERROR; 2062395Swnj iodone(bp); 2072395Swnj return; 208264Sbill } 209264Sbill 2102674Swnj /* 2112674Swnj * Unit start routine. 2122674Swnj * Seek the drive to be where the data is 2132674Swnj * and then generate another interrupt 2142674Swnj * to actually start the transfer. 2152674Swnj * If there is only one drive on the controller, 2162674Swnj * or we are very close to the data, don't 2172674Swnj * bother with the search. If called after 2182674Swnj * searching once, don't bother to look where 2192674Swnj * we are, just queue for transfer (to avoid 2202674Swnj * positioning forever without transferrring.) 2212674Swnj */ 2222395Swnj upustart(ui) 223*2983Swnj register struct uba_device *ui; 224264Sbill { 225264Sbill register struct buf *bp, *dp; 226*2983Swnj register struct uba_ctlr *um; 2272629Swnj register struct updevice *upaddr; 2282395Swnj register struct upst *st; 229264Sbill daddr_t bn; 2302674Swnj int sn, csn; 2312607Swnj /* 2322607Swnj * The SC21 cancels commands if you just say 2332629Swnj * cs1 = UP_IE 2342607Swnj * so we are cautious about handling of cs1. 2352607Swnj * Also don't bother to clear as bits other than in upintr(). 2362607Swnj */ 2372674Swnj int didie = 0; 2382674Swnj 2392674Swnj if (ui == 0) 2402674Swnj return (0); 241*2983Swnj um = ui->ui_mi; 2422395Swnj dk_busy &= ~(1<<ui->ui_dk); 2432395Swnj dp = &uputab[ui->ui_unit]; 244266Sbill if ((bp = dp->b_actf) == NULL) 245268Sbill goto out; 2462674Swnj /* 2472674Swnj * If the controller is active, just remember 2482674Swnj * that this device would like to be positioned... 2492674Swnj * if we tried to position now we would confuse the SC21. 2502674Swnj */ 2512395Swnj if (um->um_tab.b_active) { 2522459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 253275Sbill return (0); 254275Sbill } 2552674Swnj /* 2562674Swnj * If we have already positioned this drive, 2572674Swnj * then just put it on the ready queue. 2582674Swnj */ 259276Sbill if (dp->b_active) 260276Sbill goto done; 261276Sbill dp->b_active = 1; 2622629Swnj upaddr = (struct updevice *)um->um_addr; 2632395Swnj upaddr->upcs2 = ui->ui_slave; 2642674Swnj /* 2652674Swnj * If drive has just come up, 2662674Swnj * setup the pack. 2672674Swnj */ 2682629Swnj if ((upaddr->upds & UP_VV) == 0) { 2692607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2702629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2712629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 2722629Swnj upaddr->upof = UP_FMT22; 273268Sbill didie = 1; 274264Sbill } 2752674Swnj /* 2762674Swnj * If drive is offline, forget about positioning. 2772674Swnj */ 2782629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) 279275Sbill goto done; 2802674Swnj /* 2812674Swnj * If there is only one drive, 2822674Swnj * dont bother searching. 2832674Swnj */ 2842607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 2852607Swnj goto done; 2862674Swnj /* 2872674Swnj * Figure out where this transfer is going to 2882674Swnj * and see if we are close enough to justify not searching. 2892674Swnj */ 2902395Swnj st = &upst[ui->ui_type]; 291264Sbill bn = dkblock(bp); 2922395Swnj sn = bn%st->nspc; 2932395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 2942674Swnj if (bp->b_cylin - upaddr->updc) 295266Sbill goto search; /* Not on-cylinder */ 296275Sbill else if (upseek) 297275Sbill goto done; /* Ok just to be on-cylinder */ 298264Sbill csn = (upaddr->upla>>6) - sn - 1; 299266Sbill if (csn < 0) 3002395Swnj csn += st->nsect; 3012395Swnj if (csn > st->nsect - upRDIST) 302264Sbill goto done; 303264Sbill search: 3042674Swnj upaddr->updc = bp->b_cylin; 3052674Swnj /* 3062674Swnj * Not on cylinder at correct position, 3072674Swnj * seek/search. 3082674Swnj */ 309275Sbill if (upseek) 3102629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3112470Swnj else { 312275Sbill upaddr->upda = sn; 3132629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 314275Sbill } 315268Sbill didie = 1; 3162674Swnj /* 3172674Swnj * Mark unit busy for iostat. 3182674Swnj */ 3192395Swnj if (ui->ui_dk >= 0) { 3202395Swnj dk_busy |= 1<<ui->ui_dk; 3212395Swnj dk_seek[ui->ui_dk]++; 322264Sbill } 323268Sbill goto out; 324264Sbill done: 3252674Swnj /* 3262674Swnj * Device is ready to go. 3272674Swnj * Put it on the ready queue for the controller 3282674Swnj * (unless its already there.) 3292674Swnj */ 3302629Swnj if (dp->b_active != 2) { 3312629Swnj dp->b_forw = NULL; 3322629Swnj if (um->um_tab.b_actf == NULL) 3332629Swnj um->um_tab.b_actf = dp; 3342629Swnj else 3352629Swnj um->um_tab.b_actl->b_forw = dp; 3362629Swnj um->um_tab.b_actl = dp; 3372629Swnj dp->b_active = 2; 3382629Swnj } 339268Sbill out: 340268Sbill return (didie); 341264Sbill } 342264Sbill 3432674Swnj /* 3442674Swnj * Start up a transfer on a drive. 3452674Swnj */ 3462395Swnj upstart(um) 347*2983Swnj register struct uba_ctlr *um; 348264Sbill { 349264Sbill register struct buf *bp, *dp; 350*2983Swnj register struct uba_device *ui; 3512629Swnj register struct updevice *upaddr; 3522470Swnj struct upst *st; 353264Sbill daddr_t bn; 3542681Swnj int dn, sn, tn, cmd, waitdry; 355264Sbill 356264Sbill loop: 3572674Swnj /* 3582674Swnj * Pull a request off the controller queue 3592674Swnj */ 3602395Swnj if ((dp = um->um_tab.b_actf) == NULL) 361268Sbill return (0); 362264Sbill if ((bp = dp->b_actf) == NULL) { 3632395Swnj um->um_tab.b_actf = dp->b_forw; 364264Sbill goto loop; 365264Sbill } 3662674Swnj /* 3672674Swnj * Mark controller busy, and 3682674Swnj * determine destination of this request. 3692674Swnj */ 3702395Swnj um->um_tab.b_active++; 3712395Swnj ui = updinfo[dkunit(bp)]; 372264Sbill bn = dkblock(bp); 3732395Swnj dn = ui->ui_slave; 3742395Swnj st = &upst[ui->ui_type]; 3752395Swnj sn = bn%st->nspc; 3762395Swnj tn = sn/st->nsect; 3772395Swnj sn %= st->nsect; 3782629Swnj upaddr = (struct updevice *)ui->ui_addr; 3792674Swnj /* 3802674Swnj * Select drive if not selected already. 3812674Swnj */ 3822674Swnj if ((upaddr->upcs2&07) != dn) 3832674Swnj upaddr->upcs2 = dn; 3842674Swnj /* 3852674Swnj * Check that it is ready and online 3862674Swnj */ 3872681Swnj waitdry = 0; 3882681Swnj while ((upaddr->upds&UP_DRY) == 0) { 3892681Swnj if (++waitdry > 512) 3902681Swnj break; 3912681Swnj upwaitdry++; 3922681Swnj } 3932681Swnj if ((upaddr->upds & UP_DREADY) != UP_DREADY) { 3942931Swnj printf("up%d: not ready", dkunit(bp)); 3952681Swnj if ((upaddr->upds & UP_DREADY) != UP_DREADY) { 3962607Swnj printf("\n"); 3972395Swnj um->um_tab.b_active = 0; 3982395Swnj um->um_tab.b_errcnt = 0; 399893Sbill dp->b_actf = bp->av_forw; 400893Sbill dp->b_active = 0; 401893Sbill bp->b_flags |= B_ERROR; 402893Sbill iodone(bp); 403893Sbill goto loop; 404893Sbill } 4052674Swnj /* 4062674Swnj * Oh, well, sometimes this 4072674Swnj * happens, for reasons unknown. 4082674Swnj */ 4092629Swnj printf(" (flakey)\n"); 410264Sbill } 4112674Swnj /* 4122674Swnj * After 16th retry, do offset positioning 4132674Swnj */ 4142395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 4152629Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UP_FMT22; 4162629Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 4172629Swnj while (upaddr->upds & UP_PIP) 418264Sbill DELAY(25); 419264Sbill } 4202674Swnj /* 4212674Swnj * Setup for the transfer, and get in the 4222674Swnj * UNIBUS adaptor queue. 4232674Swnj */ 4242424Skre upaddr->updc = bp->b_cylin; 425264Sbill upaddr->upda = (tn << 8) + sn; 426264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 427264Sbill if (bp->b_flags & B_READ) 4282629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 429264Sbill else 4302629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4312571Swnj um->um_cmd = cmd; 4322571Swnj ubago(ui); 433268Sbill return (1); 434264Sbill } 435264Sbill 4362674Swnj /* 4372674Swnj * Now all ready to go, stuff the registers. 4382674Swnj */ 4392571Swnj updgo(um) 440*2983Swnj struct uba_ctlr *um; 4412395Swnj { 4422629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4432470Swnj 4442571Swnj upaddr->upba = um->um_ubinfo; 4452571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4462395Swnj } 4472395Swnj 4482674Swnj /* 4492674Swnj * Handle a disk interrupt. 4502674Swnj */ 4512707Swnj upintr(sc21) 4522395Swnj register sc21; 453264Sbill { 454264Sbill register struct buf *bp, *dp; 455*2983Swnj register struct uba_ctlr *um = upminfo[sc21]; 456*2983Swnj register struct uba_device *ui; 4572629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 458264Sbill register unit; 4592470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4602607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4612681Swnj int needie = 1, waitdry; 462264Sbill 4632470Swnj sc->sc_wticks = 0; 4642607Swnj sc->sc_softas = 0; 4652674Swnj /* 4662674Swnj * If controller wasn't transferring, then this is an 4672674Swnj * interrupt for attention status on seeking drives. 4682674Swnj * Just service them. 4692674Swnj */ 4702674Swnj if (um->um_tab.b_active == 0) { 4712674Swnj if (upaddr->upcs1 & UP_TRE) 4722674Swnj upaddr->upcs1 = UP_TRE; 4732674Swnj goto doattn; 4742674Swnj } 4752674Swnj /* 4762674Swnj * Get device and block structures, and a pointer 477*2983Swnj * to the uba_device for the drive. Select the drive. 4782674Swnj */ 4792674Swnj dp = um->um_tab.b_actf; 4802674Swnj bp = dp->b_actf; 4812674Swnj ui = updinfo[dkunit(bp)]; 4822674Swnj dk_busy &= ~(1 << ui->ui_dk); 4832674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 4842395Swnj upaddr->upcs2 = ui->ui_slave; 4852674Swnj /* 4862674Swnj * Check for and process errors on 4872674Swnj * either the drive or the controller. 4882674Swnj */ 4892674Swnj if ((upaddr->upds&UP_ERR) || (upaddr->upcs1&UP_TRE)) { 4902681Swnj waitdry = 0; 4912681Swnj while ((upaddr->upds & UP_DRY) == 0) { 4922681Swnj if (++waitdry > 512) 4932681Swnj break; 4942681Swnj upwaitdry++; 4952681Swnj } 4962931Swnj if (upaddr->uper1&UP_WLE) { 4972674Swnj /* 4982674Swnj * Give up on write locked devices 4992674Swnj * immediately. 5002674Swnj */ 5012931Swnj printf("up%d: write locked\n", dkunit(bp)); 5022674Swnj bp->b_flags |= B_ERROR; 5032674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5042674Swnj /* 5052674Swnj * After 28 retries (16 without offset, and 5062674Swnj * 12 with offset positioning) give up. 5072674Swnj */ 5082931Swnj harderr(bp, "up"); 5092931Swnj printf("cs2=%b er1=%b er2=%b\n", 5102785Swnj upaddr->upcs2, UPCS2_BITS, 5112785Swnj upaddr->uper1, UPER1_BITS, 5122785Swnj upaddr->uper2, UPER2_BITS); 5132674Swnj bp->b_flags |= B_ERROR; 5142674Swnj } else { 5152674Swnj /* 5162674Swnj * Retriable error. 5172674Swnj * If a soft ecc, correct it (continuing 5182674Swnj * by returning if necessary. 5192674Swnj * Otherwise fall through and retry the transfer 5202674Swnj */ 5212674Swnj um->um_tab.b_active = 0; /* force retry */ 5222629Swnj if ((upaddr->uper1&(UP_DCK|UP_ECH))==UP_DCK) 5232629Swnj if (upecc(ui)) 5242629Swnj return; 5252674Swnj } 5262674Swnj /* 5272674Swnj * Clear drive error and, every eight attempts, 5282674Swnj * (starting with the fourth) 5292674Swnj * recalibrate to clear the slate. 5302674Swnj */ 5312674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5322674Swnj needie = 0; 5332674Swnj if ((um->um_tab.b_errcnt&07) == 4) { 5342674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5352674Swnj um->um_tab.b_active = 1; 5362674Swnj sc->sc_recal = 1; 5372674Swnj return; 5382674Swnj } 5392674Swnj } 5402674Swnj /* 5412674Swnj * Done retrying transfer... release 5422674Swnj * resources... if we were recalibrating, 5432674Swnj * then retry the transfer. 5442674Swnj * Mathematical note: 28%8 != 4. 5452674Swnj */ 5462674Swnj ubadone(um); 5472674Swnj if (sc->sc_recal) { 5482674Swnj sc->sc_recal = 0; 5492674Swnj um->um_tab.b_active = 0; /* force retry */ 5502674Swnj } 5512674Swnj /* 5522674Swnj * If still ``active'', then don't need any more retries. 5532674Swnj */ 5542674Swnj if (um->um_tab.b_active) { 5552674Swnj /* 5562674Swnj * If we were offset positioning, 5572674Swnj * return to centerline. 5582674Swnj */ 5592674Swnj if (um->um_tab.b_errcnt >= 16) { 5602674Swnj upaddr->upof = UP_FMT22; 5612674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 5622674Swnj while (upaddr->upds & UP_PIP) 5632674Swnj DELAY(25); 564268Sbill needie = 0; 565264Sbill } 5662674Swnj um->um_tab.b_active = 0; 5672674Swnj um->um_tab.b_errcnt = 0; 5682674Swnj um->um_tab.b_actf = dp->b_forw; 5692674Swnj dp->b_active = 0; 5702674Swnj dp->b_errcnt = 0; 5712674Swnj dp->b_actf = bp->av_forw; 5722674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 5732674Swnj iodone(bp); 5742674Swnj /* 5752674Swnj * If this unit has more work to do, 5762674Swnj * then start it up right away. 5772674Swnj */ 5782674Swnj if (dp->b_actf) 5792674Swnj if (upustart(ui)) 580268Sbill needie = 0; 581264Sbill } 5822674Swnj as &= ~(1<<ui->ui_slave); 5832674Swnj doattn: 5842674Swnj /* 5852674Swnj * Process other units which need attention. 5862674Swnj * For each unit which needs attention, call 5872674Swnj * the unit start routine to place the slave 5882674Swnj * on the controller device queue. 5892674Swnj */ 5902607Swnj for (unit = 0; as; as >>= 1, unit++) 5912607Swnj if (as & 1) { 5922470Swnj upaddr->upas = 1<<unit; 5932607Swnj if (upustart(upip[sc21][unit])) 594273Sbill needie = 0; 595273Sbill } 5962674Swnj /* 5972674Swnj * If the controller is not transferring, but 5982674Swnj * there are devices ready to transfer, start 5992674Swnj * the controller. 6002674Swnj */ 6012395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6022395Swnj if (upstart(um)) 603268Sbill needie = 0; 604275Sbill if (needie) 6052629Swnj upaddr->upcs1 = UP_IE; 606264Sbill } 607264Sbill 608264Sbill upread(dev) 6092616Swnj dev_t dev; 610264Sbill { 6112616Swnj register int unit = minor(dev) >> 3; 6122470Swnj 6132616Swnj if (unit >= NUP) 6142616Swnj u.u_error = ENXIO; 6152616Swnj else 6162616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 617264Sbill } 618264Sbill 619264Sbill upwrite(dev) 6202616Swnj dev_t dev; 621264Sbill { 6222616Swnj register int unit = minor(dev) >> 3; 6232470Swnj 6242616Swnj if (unit >= NUP) 6252616Swnj u.u_error = ENXIO; 6262616Swnj else 6272616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 628264Sbill } 629264Sbill 630266Sbill /* 631266Sbill * Correct an ECC error, and restart the i/o to complete 632266Sbill * the transfer if necessary. This is quite complicated because 633266Sbill * the transfer may be going to an odd memory address base and/or 634266Sbill * across a page boundary. 635266Sbill */ 6362395Swnj upecc(ui) 637*2983Swnj register struct uba_device *ui; 638264Sbill { 6392629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6402395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 641*2983Swnj register struct uba_ctlr *um = ui->ui_mi; 6422395Swnj register struct upst *st; 6432395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 644266Sbill register int i; 645264Sbill caddr_t addr; 646266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 647264Sbill int bn, cn, tn, sn; 648264Sbill 649264Sbill /* 650266Sbill * Npf is the number of sectors transferred before the sector 651266Sbill * containing the ECC error, and reg is the UBA register 652266Sbill * mapping (the first part of) the transfer. 653266Sbill * O is offset within a memory page of the first byte transferred. 654264Sbill */ 655266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 6562571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 657264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 658*2983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 6592889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 660264Sbill mask = up->upec2; 661266Sbill /* 662266Sbill * Flush the buffered data path, and compute the 663266Sbill * byte and bit position of the error. The variable i 664266Sbill * is the byte offset in the transfer, the variable byte 665266Sbill * is the offset from a page boundary in main memory. 666266Sbill */ 6672725Swnj ubapurge(um); 668266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 669266Sbill bit = i&07; 670266Sbill i = (i&~07)>>3; 671264Sbill byte = i + o; 672266Sbill /* 673266Sbill * Correct while possible bits remain of mask. Since mask 674266Sbill * contains 11 bits, we continue while the bit offset is > -11. 675266Sbill * Also watch out for end of this block and the end of the whole 676266Sbill * transfer. 677266Sbill */ 678266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 679266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 680266Sbill (byte & PGOFSET); 681266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 682266Sbill byte++; 683266Sbill i++; 684266Sbill bit -= 8; 685264Sbill } 6862395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 687264Sbill if (up->upwc == 0) 688264Sbill return (0); 689266Sbill /* 690266Sbill * Have to continue the transfer... clear the drive, 691266Sbill * and compute the position where the transfer is to continue. 692266Sbill * We have completed npf+1 sectors of the transfer already; 693266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 694266Sbill */ 6952629Swnj #ifdef notdef 6962629Swnj up->uper1 = 0; 6972629Swnj up->upcs1 |= UP_GO; 6982629Swnj #else 6992629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 700264Sbill bn = dkblock(bp); 7012395Swnj st = &upst[ui->ui_type]; 702264Sbill cn = bp->b_cylin; 7032395Swnj sn = bn%st->nspc + npf + 1; 7042395Swnj tn = sn/st->nsect; 7052395Swnj sn %= st->nsect; 7062395Swnj cn += tn/st->ntrak; 7072395Swnj tn %= st->ntrak; 708264Sbill up->updc = cn; 709266Sbill up->upda = (tn << 8) | sn; 710266Sbill ubaddr = (int)ptob(reg+1) + o; 711266Sbill up->upba = ubaddr; 712266Sbill cmd = (ubaddr >> 8) & 0x300; 7132629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 714266Sbill up->upcs1 = cmd; 7152629Swnj #endif 716264Sbill return (1); 717264Sbill } 718286Sbill 719286Sbill /* 720286Sbill * Reset driver after UBA init. 721286Sbill * Cancel software state of all pending transfers 722286Sbill * and restart all units and the controller. 723286Sbill */ 7242395Swnj upreset(uban) 7252931Swnj int uban; 726286Sbill { 727*2983Swnj register struct uba_ctlr *um; 728*2983Swnj register struct uba_device *ui; 7292395Swnj register sc21, unit; 730286Sbill 7312646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7322470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7332470Swnj um->um_alive == 0) 7342395Swnj continue; 7352931Swnj printf(" sc%d", sc21); 7362395Swnj um->um_tab.b_active = 0; 7372395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7382931Swnj up_softc[sc21].sc_recal = 0; 7392571Swnj if (um->um_ubinfo) { 7402571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7412616Swnj ubadone(um); 7422395Swnj } 7432629Swnj ((struct updevice *)(um->um_addr))->upcs2 = UP_CLR; 7442395Swnj for (unit = 0; unit < NUP; unit++) { 7452395Swnj if ((ui = updinfo[unit]) == 0) 7462395Swnj continue; 7472931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 7482395Swnj continue; 7492395Swnj uputab[unit].b_active = 0; 7502395Swnj (void) upustart(ui); 7512395Swnj } 7522395Swnj (void) upstart(um); 753286Sbill } 754286Sbill } 755313Sbill 756313Sbill /* 757313Sbill * Wake up every second and if an interrupt is pending 758313Sbill * but nothing has happened increment a counter. 7592931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 760313Sbill * and begin anew. 761313Sbill */ 762313Sbill upwatch() 763313Sbill { 764*2983Swnj register struct uba_ctlr *um; 7652395Swnj register sc21, unit; 7662470Swnj register struct up_softc *sc; 767313Sbill 7682759Swnj timeout(upwatch, (caddr_t)0, hz); 7692646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7702395Swnj um = upminfo[sc21]; 7712470Swnj if (um == 0 || um->um_alive == 0) 7722470Swnj continue; 7732470Swnj sc = &up_softc[sc21]; 7742395Swnj if (um->um_tab.b_active == 0) { 7752395Swnj for (unit = 0; unit < NUP; unit++) 7762629Swnj if (uputab[unit].b_active && 7772629Swnj updinfo[unit]->ui_mi == um) 7782395Swnj goto active; 7792470Swnj sc->sc_wticks = 0; 7802395Swnj continue; 7812395Swnj } 7822931Swnj active: 7832470Swnj sc->sc_wticks++; 7842470Swnj if (sc->sc_wticks >= 20) { 7852470Swnj sc->sc_wticks = 0; 7862931Swnj printf("sc%d: lost interrupt\n", sc21); 7872646Swnj ubareset(um->um_ubanum); 7882395Swnj } 789313Sbill } 790313Sbill } 7912379Swnj 7922379Swnj #define DBSIZE 20 7932379Swnj 7942379Swnj updump(dev) 7952379Swnj dev_t dev; 7962379Swnj { 7972629Swnj struct updevice *upaddr; 7982379Swnj char *start; 7992889Swnj int num, blk, unit, i; 8002379Swnj struct size *sizes; 8012395Swnj register struct uba_regs *uba; 802*2983Swnj register struct uba_device *ui; 8032379Swnj register short *rp; 8042395Swnj struct upst *st; 8052379Swnj 8062395Swnj unit = minor(dev) >> 3; 8072889Swnj if (unit >= NUP) 8082889Swnj return (ENXIO); 8092470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 810*2983Swnj ui = phys(struct uba_device *, updinfo[unit]); 8112889Swnj if (ui->ui_alive == 0) 8122889Swnj return (ENXIO); 8132395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 814*2983Swnj ubainit(uba); 8152629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 816*2983Swnj DELAY(2000000); 8172379Swnj num = maxfree; 8182379Swnj start = 0; 8192379Swnj upaddr->upcs2 = unit; 820*2983Swnj DELAY(100); 821*2983Swnj if ((upaddr->upcs1&UP_DVA) == 0) 822*2983Swnj return (EFAULT); 8232629Swnj if ((upaddr->upds & UP_VV) == 0) { 8242629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 8252629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 8262629Swnj upaddr->upof = UP_FMT22; 8272379Swnj } 8282889Swnj if ((upaddr->upds & UP_DREADY) != UP_DREADY) 8292889Swnj return (EFAULT); 8302470Swnj st = &upst[ui->ui_type]; 8312395Swnj sizes = phys(struct size *, st->sizes); 8322889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 8332889Swnj return (EINVAL); 8342379Swnj while (num > 0) { 8352379Swnj register struct pte *io; 8362379Swnj register int i; 8372379Swnj int cn, sn, tn; 8382379Swnj daddr_t bn; 8392379Swnj 8402379Swnj blk = num > DBSIZE ? DBSIZE : num; 8412395Swnj io = uba->uba_map; 8422379Swnj for (i = 0; i < blk; i++) 843*2983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 8442379Swnj *(int *)io = 0; 8452379Swnj bn = dumplo + btop(start); 8462607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 8472607Swnj sn = bn%st->nspc; 8482607Swnj tn = sn/st->nsect; 8492607Swnj sn = sn%st->nsect; 8502379Swnj upaddr->updc = cn; 8512379Swnj rp = (short *) &upaddr->upda; 8522379Swnj *rp = (tn << 8) + sn; 8532379Swnj *--rp = 0; 8542379Swnj *--rp = -blk*NBPG / sizeof (short); 8552629Swnj *--rp = UP_GO|UP_WCOM; 8562379Swnj do { 8572379Swnj DELAY(25); 8582629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 8592889Swnj if (upaddr->upcs1&UP_ERR) 8602889Swnj return (EIO); 8612379Swnj start += blk*NBPG; 8622379Swnj num -= blk; 8632379Swnj } 8642379Swnj return (0); 8652379Swnj } 8661902Swnj #endif 867