1*3403Swnj /* up.c 4.35 81/04/01 */ 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 132983Swnj * Check that offset recovery code, etc works 14264Sbill */ 15264Sbill 16264Sbill #include "../h/param.h" 17264Sbill #include "../h/systm.h" 182395Swnj #include "../h/cpu.h" 192395Swnj #include "../h/nexus.h" 20308Sbill #include "../h/dk.h" 21264Sbill #include "../h/buf.h" 22264Sbill #include "../h/conf.h" 23264Sbill #include "../h/dir.h" 24264Sbill #include "../h/user.h" 25264Sbill #include "../h/map.h" 26420Sbill #include "../h/pte.h" 27264Sbill #include "../h/mtpr.h" 282571Swnj #include "../h/vm.h" 292983Swnj #include "../h/ubavar.h" 302983Swnj #include "../h/ubareg.h" 312379Swnj #include "../h/cmap.h" 32264Sbill 332379Swnj #include "../h/upreg.h" 34264Sbill 352395Swnj struct up_softc { 362395Swnj int sc_softas; 372607Swnj int sc_ndrive; 382395Swnj int sc_wticks; 392674Swnj int sc_recal; 402646Swnj } up_softc[NSC]; 41275Sbill 422395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 43264Sbill struct size 44264Sbill { 45264Sbill daddr_t nblocks; 46264Sbill int cyloff; 47264Sbill } up_sizes[8] = { 48264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 49264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 50341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 51264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 52264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 53264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 54264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 55264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 562395Swnj }, fj_sizes[8] = { 572395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 582395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 592395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 602395Swnj 0, 0, 612395Swnj 0, 0, 622395Swnj 0, 0, 632395Swnj 0, 0, 642395Swnj 213760, 155, /* H=cyl 155 thru 822 */ 65264Sbill }; 662395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 67264Sbill 682395Swnj #define _upSDIST 2 /* 1.0 msec */ 692395Swnj #define _upRDIST 4 /* 2.0 msec */ 70264Sbill 712395Swnj int upSDIST = _upSDIST; 722395Swnj int upRDIST = _upRDIST; 732395Swnj 742607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 752983Swnj struct uba_ctlr *upminfo[NSC]; 762983Swnj struct uba_device *updinfo[NUP]; 772983Swnj struct uba_device *upip[NSC][4]; 782395Swnj 792607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 802616Swnj struct uba_driver scdriver = 812607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 822395Swnj struct buf uputab[NUP]; 832395Swnj 842395Swnj struct upst { 852395Swnj short nsect; 862395Swnj short ntrak; 872395Swnj short nspc; 882395Swnj short ncyl; 892395Swnj struct size *sizes; 902395Swnj } upst[] = { 912607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 922607Swnj /* 9300 actually has 815 cylinders... */ 932395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 942395Swnj }; 952395Swnj 962629Swnj u_char up_offset[16] = { 972629Swnj UP_P400, UP_M400, UP_P400, UP_M400, UP_P800, UP_M800, UP_P800, UP_M800, 982629Swnj UP_P1200, UP_M1200, UP_P1200, UP_M1200, 0, 0, 0, 0 992629Swnj }; 100264Sbill 1012616Swnj struct buf rupbuf[NUP]; 102264Sbill 103264Sbill #define b_cylin b_resid 104264Sbill 105264Sbill #ifdef INTRLVE 106264Sbill daddr_t dkblock(); 107264Sbill #endif 1082395Swnj 1092395Swnj int upwstart, upwatch(); /* Have started guardian */ 1102470Swnj int upseek; 1112681Swnj int upwaitdry; 1122395Swnj 1132395Swnj /*ARGSUSED*/ 1142607Swnj upprobe(reg) 1152395Swnj caddr_t reg; 1162395Swnj { 1172459Swnj register int br, cvec; 1182459Swnj 1192607Swnj #ifdef lint 1202607Swnj br = 0; cvec = br; br = cvec; 1212607Swnj #endif 1222629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1232607Swnj DELAY(10); 1242629Swnj ((struct updevice *)reg)->upcs1 = 0; 1252459Swnj return (1); 1262395Swnj } 1272395Swnj 1282607Swnj upslave(ui, reg) 1292983Swnj struct uba_device *ui; 1302395Swnj caddr_t reg; 1312395Swnj { 1322629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1332395Swnj 1342395Swnj upaddr->upcs1 = 0; /* conservative */ 1352607Swnj upaddr->upcs2 = ui->ui_slave; 1362629Swnj if (upaddr->upcs2&UP_NED) { 1372629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1382395Swnj return (0); 1392395Swnj } 1402607Swnj return (1); 1412607Swnj } 1422607Swnj 1432607Swnj upattach(ui) 1442983Swnj register struct uba_device *ui; 1452607Swnj { 1462629Swnj #ifdef notdef 1472629Swnj register struct updevice *upaddr; 1482629Swnj #endif 1492607Swnj 1502395Swnj if (upwstart == 0) { 1512759Swnj timeout(upwatch, (caddr_t)0, hz); 1522395Swnj upwstart++; 1532395Swnj } 1542571Swnj if (ui->ui_dk >= 0) 1552571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1562607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1572607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1582629Swnj #ifdef notdef 1592629Swnj upaddr = (struct updevice *)ui->ui_addr; 1602629Swnj upaddr->upcs1 = 0; 1612629Swnj upaddr->upcs2 = ui->ui_slave; 1622629Swnj upaddr->uphr = -1; 1632629Swnj /* ... */ 1642629Swnj if (upaddr-> ... == 10) 1652629Swnj ui->ui_type = 1; 1662629Swnj #endif 1672395Swnj } 168264Sbill 169264Sbill upstrategy(bp) 1702395Swnj register struct buf *bp; 171264Sbill { 1722983Swnj register struct uba_device *ui; 1732395Swnj register struct upst *st; 1742395Swnj register int unit; 1752470Swnj register struct buf *dp; 1762395Swnj int xunit = minor(bp->b_dev) & 07; 1772470Swnj long bn, sz; 178264Sbill 1792470Swnj sz = (bp->b_bcount+511) >> 9; 180264Sbill unit = dkunit(bp); 1812395Swnj if (unit >= NUP) 1822395Swnj goto bad; 1832395Swnj ui = updinfo[unit]; 1842395Swnj if (ui == 0 || ui->ui_alive == 0) 1852395Swnj goto bad; 1862395Swnj st = &upst[ui->ui_type]; 1872395Swnj if (bp->b_blkno < 0 || 1882395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1892395Swnj goto bad; 1902395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 191264Sbill (void) spl5(); 1922470Swnj dp = &uputab[ui->ui_unit]; 1932470Swnj disksort(dp, bp); 1942470Swnj if (dp->b_active == 0) { 1952395Swnj (void) upustart(ui); 1962395Swnj bp = &ui->ui_mi->um_tab; 1972395Swnj if (bp->b_actf && bp->b_active == 0) 1982395Swnj (void) upstart(ui->ui_mi); 199264Sbill } 200264Sbill (void) spl0(); 2012395Swnj return; 2022395Swnj 2032395Swnj bad: 2042395Swnj bp->b_flags |= B_ERROR; 2052395Swnj iodone(bp); 2062395Swnj return; 207264Sbill } 208264Sbill 2092674Swnj /* 2102674Swnj * Unit start routine. 2112674Swnj * Seek the drive to be where the data is 2122674Swnj * and then generate another interrupt 2132674Swnj * to actually start the transfer. 2142674Swnj * If there is only one drive on the controller, 2152674Swnj * or we are very close to the data, don't 2162674Swnj * bother with the search. If called after 2172674Swnj * searching once, don't bother to look where 2182674Swnj * we are, just queue for transfer (to avoid 2192674Swnj * positioning forever without transferrring.) 2202674Swnj */ 2212395Swnj upustart(ui) 2222983Swnj register struct uba_device *ui; 223264Sbill { 224264Sbill register struct buf *bp, *dp; 2252983Swnj register struct uba_ctlr *um; 2262629Swnj register struct updevice *upaddr; 2272395Swnj register struct upst *st; 228264Sbill daddr_t bn; 2292674Swnj int sn, csn; 2302607Swnj /* 2312607Swnj * The SC21 cancels commands if you just say 2322629Swnj * cs1 = UP_IE 2332607Swnj * so we are cautious about handling of cs1. 2342607Swnj * Also don't bother to clear as bits other than in upintr(). 2352607Swnj */ 2362674Swnj int didie = 0; 2372674Swnj 2382674Swnj if (ui == 0) 2392674Swnj return (0); 2402983Swnj um = ui->ui_mi; 2412395Swnj dk_busy &= ~(1<<ui->ui_dk); 2422395Swnj dp = &uputab[ui->ui_unit]; 243266Sbill if ((bp = dp->b_actf) == NULL) 244268Sbill goto out; 2452674Swnj /* 2462674Swnj * If the controller is active, just remember 2472674Swnj * that this device would like to be positioned... 2482674Swnj * if we tried to position now we would confuse the SC21. 2492674Swnj */ 2502395Swnj if (um->um_tab.b_active) { 2512459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 252275Sbill return (0); 253275Sbill } 2542674Swnj /* 2552674Swnj * If we have already positioned this drive, 2562674Swnj * then just put it on the ready queue. 2572674Swnj */ 258276Sbill if (dp->b_active) 259276Sbill goto done; 260276Sbill dp->b_active = 1; 2612629Swnj upaddr = (struct updevice *)um->um_addr; 2622395Swnj upaddr->upcs2 = ui->ui_slave; 2632674Swnj /* 2642674Swnj * If drive has just come up, 2652674Swnj * setup the pack. 2662674Swnj */ 2672629Swnj if ((upaddr->upds & UP_VV) == 0) { 2682607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2692629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2702629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 2712629Swnj upaddr->upof = UP_FMT22; 272268Sbill didie = 1; 273264Sbill } 2742674Swnj /* 2752674Swnj * If drive is offline, forget about positioning. 2762674Swnj */ 2772629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) 278275Sbill goto done; 2792674Swnj /* 2802674Swnj * If there is only one drive, 2812674Swnj * dont bother searching. 2822674Swnj */ 2832607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 2842607Swnj goto done; 2852674Swnj /* 2862674Swnj * Figure out where this transfer is going to 2872674Swnj * and see if we are close enough to justify not searching. 2882674Swnj */ 2892395Swnj st = &upst[ui->ui_type]; 290264Sbill bn = dkblock(bp); 2912395Swnj sn = bn%st->nspc; 2922395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 2932674Swnj if (bp->b_cylin - upaddr->updc) 294266Sbill goto search; /* Not on-cylinder */ 295275Sbill else if (upseek) 296275Sbill goto done; /* Ok just to be on-cylinder */ 297264Sbill csn = (upaddr->upla>>6) - sn - 1; 298266Sbill if (csn < 0) 2992395Swnj csn += st->nsect; 3002395Swnj if (csn > st->nsect - upRDIST) 301264Sbill goto done; 302264Sbill search: 3032674Swnj upaddr->updc = bp->b_cylin; 3042674Swnj /* 3052674Swnj * Not on cylinder at correct position, 3062674Swnj * seek/search. 3072674Swnj */ 308275Sbill if (upseek) 3092629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3102470Swnj else { 311275Sbill upaddr->upda = sn; 3122629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 313275Sbill } 314268Sbill didie = 1; 3152674Swnj /* 3162674Swnj * Mark unit busy for iostat. 3172674Swnj */ 3182395Swnj if (ui->ui_dk >= 0) { 3192395Swnj dk_busy |= 1<<ui->ui_dk; 3202395Swnj dk_seek[ui->ui_dk]++; 321264Sbill } 322268Sbill goto out; 323264Sbill done: 3242674Swnj /* 3252674Swnj * Device is ready to go. 3262674Swnj * Put it on the ready queue for the controller 3272674Swnj * (unless its already there.) 3282674Swnj */ 3292629Swnj if (dp->b_active != 2) { 3302629Swnj dp->b_forw = NULL; 3312629Swnj if (um->um_tab.b_actf == NULL) 3322629Swnj um->um_tab.b_actf = dp; 3332629Swnj else 3342629Swnj um->um_tab.b_actl->b_forw = dp; 3352629Swnj um->um_tab.b_actl = dp; 3362629Swnj dp->b_active = 2; 3372629Swnj } 338268Sbill out: 339268Sbill return (didie); 340264Sbill } 341264Sbill 3422674Swnj /* 3432674Swnj * Start up a transfer on a drive. 3442674Swnj */ 3452395Swnj upstart(um) 3462983Swnj register struct uba_ctlr *um; 347264Sbill { 348264Sbill register struct buf *bp, *dp; 3492983Swnj register struct uba_device *ui; 3502629Swnj register struct updevice *upaddr; 3512470Swnj struct upst *st; 352264Sbill daddr_t bn; 3532681Swnj int dn, sn, tn, cmd, waitdry; 354264Sbill 355264Sbill loop: 3562674Swnj /* 3572674Swnj * Pull a request off the controller queue 3582674Swnj */ 3592395Swnj if ((dp = um->um_tab.b_actf) == NULL) 360268Sbill return (0); 361264Sbill if ((bp = dp->b_actf) == NULL) { 3622395Swnj um->um_tab.b_actf = dp->b_forw; 363264Sbill goto loop; 364264Sbill } 3652674Swnj /* 3662674Swnj * Mark controller busy, and 3672674Swnj * determine destination of this request. 3682674Swnj */ 3692395Swnj um->um_tab.b_active++; 3702395Swnj ui = updinfo[dkunit(bp)]; 371264Sbill bn = dkblock(bp); 3722395Swnj dn = ui->ui_slave; 3732395Swnj st = &upst[ui->ui_type]; 3742395Swnj sn = bn%st->nspc; 3752395Swnj tn = sn/st->nsect; 3762395Swnj sn %= st->nsect; 3772629Swnj upaddr = (struct updevice *)ui->ui_addr; 3782674Swnj /* 3792674Swnj * Select drive if not selected already. 3802674Swnj */ 3812674Swnj if ((upaddr->upcs2&07) != dn) 3822674Swnj upaddr->upcs2 = dn; 3832674Swnj /* 3842674Swnj * Check that it is ready and online 3852674Swnj */ 3862681Swnj waitdry = 0; 3872681Swnj while ((upaddr->upds&UP_DRY) == 0) { 3882681Swnj if (++waitdry > 512) 3892681Swnj break; 3902681Swnj upwaitdry++; 3912681Swnj } 3922681Swnj if ((upaddr->upds & UP_DREADY) != UP_DREADY) { 3932931Swnj printf("up%d: not ready", dkunit(bp)); 3942681Swnj if ((upaddr->upds & UP_DREADY) != UP_DREADY) { 3952607Swnj printf("\n"); 3962395Swnj um->um_tab.b_active = 0; 3972395Swnj um->um_tab.b_errcnt = 0; 398893Sbill dp->b_actf = bp->av_forw; 399893Sbill dp->b_active = 0; 400893Sbill bp->b_flags |= B_ERROR; 401893Sbill iodone(bp); 402893Sbill goto loop; 403893Sbill } 4042674Swnj /* 4052674Swnj * Oh, well, sometimes this 4062674Swnj * happens, for reasons unknown. 4072674Swnj */ 4082629Swnj printf(" (flakey)\n"); 409264Sbill } 4102674Swnj /* 4112674Swnj * Setup for the transfer, and get in the 4122674Swnj * UNIBUS adaptor queue. 4132674Swnj */ 4142424Skre upaddr->updc = bp->b_cylin; 415264Sbill upaddr->upda = (tn << 8) + sn; 416264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 417264Sbill if (bp->b_flags & B_READ) 4182629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 419264Sbill else 4202629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4212571Swnj um->um_cmd = cmd; 4223107Swnj (void) ubago(ui); 423268Sbill return (1); 424264Sbill } 425264Sbill 4262674Swnj /* 4272674Swnj * Now all ready to go, stuff the registers. 4282674Swnj */ 4292571Swnj updgo(um) 4302983Swnj struct uba_ctlr *um; 4312395Swnj { 4322629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4332470Swnj 4342571Swnj upaddr->upba = um->um_ubinfo; 4352571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4362395Swnj } 4372395Swnj 4382674Swnj /* 4392674Swnj * Handle a disk interrupt. 4402674Swnj */ 4412707Swnj upintr(sc21) 4422395Swnj register sc21; 443264Sbill { 444264Sbill register struct buf *bp, *dp; 4452983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4462983Swnj register struct uba_device *ui; 4472629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 448264Sbill register unit; 4492470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4502607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4512681Swnj int needie = 1, waitdry; 452264Sbill 4532470Swnj sc->sc_wticks = 0; 4542607Swnj sc->sc_softas = 0; 4552674Swnj /* 4562674Swnj * If controller wasn't transferring, then this is an 4572674Swnj * interrupt for attention status on seeking drives. 4582674Swnj * Just service them. 4592674Swnj */ 4602674Swnj if (um->um_tab.b_active == 0) { 4612674Swnj if (upaddr->upcs1 & UP_TRE) 4622674Swnj upaddr->upcs1 = UP_TRE; 4632674Swnj goto doattn; 4642674Swnj } 4652674Swnj /* 4662674Swnj * Get device and block structures, and a pointer 4672983Swnj * to the uba_device for the drive. Select the drive. 4682674Swnj */ 4692674Swnj dp = um->um_tab.b_actf; 4702674Swnj bp = dp->b_actf; 4712674Swnj ui = updinfo[dkunit(bp)]; 4722674Swnj dk_busy &= ~(1 << ui->ui_dk); 4732674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 4742395Swnj upaddr->upcs2 = ui->ui_slave; 4752674Swnj /* 4762674Swnj * Check for and process errors on 4772674Swnj * either the drive or the controller. 4782674Swnj */ 4792674Swnj if ((upaddr->upds&UP_ERR) || (upaddr->upcs1&UP_TRE)) { 4802681Swnj waitdry = 0; 4812681Swnj while ((upaddr->upds & UP_DRY) == 0) { 4822681Swnj if (++waitdry > 512) 4832681Swnj break; 4842681Swnj upwaitdry++; 4852681Swnj } 4862931Swnj if (upaddr->uper1&UP_WLE) { 4872674Swnj /* 4882674Swnj * Give up on write locked devices 4892674Swnj * immediately. 4902674Swnj */ 4912931Swnj printf("up%d: write locked\n", dkunit(bp)); 4922674Swnj bp->b_flags |= B_ERROR; 4932674Swnj } else if (++um->um_tab.b_errcnt > 27) { 4942674Swnj /* 4952674Swnj * After 28 retries (16 without offset, and 4962674Swnj * 12 with offset positioning) give up. 4972674Swnj */ 4982931Swnj harderr(bp, "up"); 4992931Swnj printf("cs2=%b er1=%b er2=%b\n", 5002785Swnj upaddr->upcs2, UPCS2_BITS, 5012785Swnj upaddr->uper1, UPER1_BITS, 5022785Swnj upaddr->uper2, UPER2_BITS); 5032674Swnj bp->b_flags |= B_ERROR; 5042674Swnj } else { 5052674Swnj /* 5062674Swnj * Retriable error. 5072674Swnj * If a soft ecc, correct it (continuing 5082674Swnj * by returning if necessary. 5092674Swnj * Otherwise fall through and retry the transfer 5102674Swnj */ 5112674Swnj um->um_tab.b_active = 0; /* force retry */ 5122629Swnj if ((upaddr->uper1&(UP_DCK|UP_ECH))==UP_DCK) 5132629Swnj if (upecc(ui)) 5142629Swnj return; 5152674Swnj } 5162674Swnj /* 5172674Swnj * Clear drive error and, every eight attempts, 5182674Swnj * (starting with the fourth) 5192674Swnj * recalibrate to clear the slate. 5202674Swnj */ 5212674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5222674Swnj needie = 0; 5233182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5242674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5253160Swnj sc->sc_recal = 0; 5263160Swnj goto nextrecal; 5272674Swnj } 5282674Swnj } 5292674Swnj /* 5303160Swnj * Advance recalibration finite state machine 5313160Swnj * if recalibrate in progress, through 5323160Swnj * RECAL 5333160Swnj * SEEK 5343160Swnj * OFFSET (optional) 5353160Swnj * RETRY 5362674Swnj */ 5373160Swnj switch (sc->sc_recal) { 5383160Swnj 5393160Swnj case 1: 5403160Swnj upaddr->updc = bp->b_cylin; 5413160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 5423160Swnj goto nextrecal; 5433160Swnj case 2: 5443160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 5453160Swnj goto donerecal; 5463160Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UP_FMT22; 5473160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 5483160Swnj goto nextrecal; 5493160Swnj nextrecal: 5503160Swnj sc->sc_recal++; 5513160Swnj um->um_tab.b_active = 1; 5523160Swnj return; 5533160Swnj donerecal: 5543160Swnj case 3: 5552674Swnj sc->sc_recal = 0; 5563160Swnj um->um_tab.b_active = 0; 5573160Swnj break; 5582674Swnj } 5592674Swnj /* 5602674Swnj * If still ``active'', then don't need any more retries. 5612674Swnj */ 5622674Swnj if (um->um_tab.b_active) { 5632674Swnj /* 5642674Swnj * If we were offset positioning, 5652674Swnj * return to centerline. 5662674Swnj */ 5672674Swnj if (um->um_tab.b_errcnt >= 16) { 5682674Swnj upaddr->upof = UP_FMT22; 5692674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 5702674Swnj while (upaddr->upds & UP_PIP) 5712674Swnj DELAY(25); 572268Sbill needie = 0; 573264Sbill } 5742674Swnj um->um_tab.b_active = 0; 5752674Swnj um->um_tab.b_errcnt = 0; 5762674Swnj um->um_tab.b_actf = dp->b_forw; 5772674Swnj dp->b_active = 0; 5782674Swnj dp->b_errcnt = 0; 5792674Swnj dp->b_actf = bp->av_forw; 5802674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 5812674Swnj iodone(bp); 5822674Swnj /* 5832674Swnj * If this unit has more work to do, 5842674Swnj * then start it up right away. 5852674Swnj */ 5862674Swnj if (dp->b_actf) 5872674Swnj if (upustart(ui)) 588268Sbill needie = 0; 589264Sbill } 5902674Swnj as &= ~(1<<ui->ui_slave); 591*3403Swnj /* 592*3403Swnj * Release unibus resources and flush data paths. 593*3403Swnj */ 594*3403Swnj ubadone(um); 5952674Swnj doattn: 5962674Swnj /* 5972674Swnj * Process other units which need attention. 5982674Swnj * For each unit which needs attention, call 5992674Swnj * the unit start routine to place the slave 6002674Swnj * on the controller device queue. 6012674Swnj */ 6023160Swnj while (unit = ffs(as)) { 6033160Swnj unit--; /* was 1 origin */ 6043160Swnj as &= ~(1<<unit); 6053160Swnj upaddr->upas = 1<<unit; 6063160Swnj if (upustart(upip[sc21][unit])) 6073160Swnj needie = 0; 6083160Swnj } 6092674Swnj /* 6102674Swnj * If the controller is not transferring, but 6112674Swnj * there are devices ready to transfer, start 6122674Swnj * the controller. 6132674Swnj */ 6142395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6152395Swnj if (upstart(um)) 616268Sbill needie = 0; 617275Sbill if (needie) 6182629Swnj upaddr->upcs1 = UP_IE; 619264Sbill } 620264Sbill 621264Sbill upread(dev) 6222616Swnj dev_t dev; 623264Sbill { 6242616Swnj register int unit = minor(dev) >> 3; 6252470Swnj 6262616Swnj if (unit >= NUP) 6272616Swnj u.u_error = ENXIO; 6282616Swnj else 6292616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 630264Sbill } 631264Sbill 632264Sbill upwrite(dev) 6332616Swnj dev_t dev; 634264Sbill { 6352616Swnj register int unit = minor(dev) >> 3; 6362470Swnj 6372616Swnj if (unit >= NUP) 6382616Swnj u.u_error = ENXIO; 6392616Swnj else 6402616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 641264Sbill } 642264Sbill 643266Sbill /* 644266Sbill * Correct an ECC error, and restart the i/o to complete 645266Sbill * the transfer if necessary. This is quite complicated because 646266Sbill * the transfer may be going to an odd memory address base and/or 647266Sbill * across a page boundary. 648266Sbill */ 6492395Swnj upecc(ui) 6502983Swnj register struct uba_device *ui; 651264Sbill { 6522629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6532395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6542983Swnj register struct uba_ctlr *um = ui->ui_mi; 6552395Swnj register struct upst *st; 6562395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 657266Sbill register int i; 658264Sbill caddr_t addr; 659266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 660264Sbill int bn, cn, tn, sn; 661264Sbill 662264Sbill /* 663266Sbill * Npf is the number of sectors transferred before the sector 664266Sbill * containing the ECC error, and reg is the UBA register 665266Sbill * mapping (the first part of) the transfer. 666266Sbill * O is offset within a memory page of the first byte transferred. 667264Sbill */ 668266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 6692571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 670264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 6712983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 6722889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 673264Sbill mask = up->upec2; 674*3403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 675*3403Swnj up->upec1); 676266Sbill /* 677266Sbill * Flush the buffered data path, and compute the 678266Sbill * byte and bit position of the error. The variable i 679266Sbill * is the byte offset in the transfer, the variable byte 680266Sbill * is the offset from a page boundary in main memory. 681266Sbill */ 6822725Swnj ubapurge(um); 683266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 684266Sbill bit = i&07; 685266Sbill i = (i&~07)>>3; 686264Sbill byte = i + o; 687266Sbill /* 688266Sbill * Correct while possible bits remain of mask. Since mask 689266Sbill * contains 11 bits, we continue while the bit offset is > -11. 690266Sbill * Also watch out for end of this block and the end of the whole 691266Sbill * transfer. 692266Sbill */ 693266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 694266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 695266Sbill (byte & PGOFSET); 696*3403Swnj printf("addr %x map reg %x\n", 697*3403Swnj addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 698*3403Swnj printf("old: %x, ", getmemc(addr)); 699266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 700*3403Swnj printf("new: %x\n", getmemc(addr)); 701266Sbill byte++; 702266Sbill i++; 703266Sbill bit -= 8; 704264Sbill } 7052395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 706264Sbill if (up->upwc == 0) 707264Sbill return (0); 708266Sbill /* 709266Sbill * Have to continue the transfer... clear the drive, 710266Sbill * and compute the position where the transfer is to continue. 711266Sbill * We have completed npf+1 sectors of the transfer already; 712266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 713266Sbill */ 7142629Swnj #ifdef notdef 7152629Swnj up->uper1 = 0; 7162629Swnj up->upcs1 |= UP_GO; 7172629Swnj #else 7182629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 719264Sbill bn = dkblock(bp); 7202395Swnj st = &upst[ui->ui_type]; 721264Sbill cn = bp->b_cylin; 7222395Swnj sn = bn%st->nspc + npf + 1; 7232395Swnj tn = sn/st->nsect; 7242395Swnj sn %= st->nsect; 7252395Swnj cn += tn/st->ntrak; 7262395Swnj tn %= st->ntrak; 727264Sbill up->updc = cn; 728266Sbill up->upda = (tn << 8) | sn; 729266Sbill ubaddr = (int)ptob(reg+1) + o; 730266Sbill up->upba = ubaddr; 731266Sbill cmd = (ubaddr >> 8) & 0x300; 7322629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 733266Sbill up->upcs1 = cmd; 7342629Swnj #endif 735264Sbill return (1); 736264Sbill } 737286Sbill 738286Sbill /* 739286Sbill * Reset driver after UBA init. 740286Sbill * Cancel software state of all pending transfers 741286Sbill * and restart all units and the controller. 742286Sbill */ 7432395Swnj upreset(uban) 7442931Swnj int uban; 745286Sbill { 7462983Swnj register struct uba_ctlr *um; 7472983Swnj register struct uba_device *ui; 7482395Swnj register sc21, unit; 749286Sbill 7502646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7512470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7522470Swnj um->um_alive == 0) 7532395Swnj continue; 7542931Swnj printf(" sc%d", sc21); 7552395Swnj um->um_tab.b_active = 0; 7562395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7572931Swnj up_softc[sc21].sc_recal = 0; 7582571Swnj if (um->um_ubinfo) { 7592571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7602616Swnj ubadone(um); 7612395Swnj } 7622629Swnj ((struct updevice *)(um->um_addr))->upcs2 = UP_CLR; 7632395Swnj for (unit = 0; unit < NUP; unit++) { 7642395Swnj if ((ui = updinfo[unit]) == 0) 7652395Swnj continue; 7662931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 7672395Swnj continue; 7682395Swnj uputab[unit].b_active = 0; 7692395Swnj (void) upustart(ui); 7702395Swnj } 7712395Swnj (void) upstart(um); 772286Sbill } 773286Sbill } 774313Sbill 775313Sbill /* 776313Sbill * Wake up every second and if an interrupt is pending 777313Sbill * but nothing has happened increment a counter. 7782931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 779313Sbill * and begin anew. 780313Sbill */ 781313Sbill upwatch() 782313Sbill { 7832983Swnj register struct uba_ctlr *um; 7842395Swnj register sc21, unit; 7852470Swnj register struct up_softc *sc; 786313Sbill 7872759Swnj timeout(upwatch, (caddr_t)0, hz); 7882646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7892395Swnj um = upminfo[sc21]; 7902470Swnj if (um == 0 || um->um_alive == 0) 7912470Swnj continue; 7922470Swnj sc = &up_softc[sc21]; 7932395Swnj if (um->um_tab.b_active == 0) { 7942395Swnj for (unit = 0; unit < NUP; unit++) 7952629Swnj if (uputab[unit].b_active && 7962629Swnj updinfo[unit]->ui_mi == um) 7972395Swnj goto active; 7982470Swnj sc->sc_wticks = 0; 7992395Swnj continue; 8002395Swnj } 8012931Swnj active: 8022470Swnj sc->sc_wticks++; 8032470Swnj if (sc->sc_wticks >= 20) { 8042470Swnj sc->sc_wticks = 0; 8052931Swnj printf("sc%d: lost interrupt\n", sc21); 8062646Swnj ubareset(um->um_ubanum); 8072395Swnj } 808313Sbill } 809313Sbill } 8102379Swnj 8112379Swnj #define DBSIZE 20 8122379Swnj 8132379Swnj updump(dev) 8142379Swnj dev_t dev; 8152379Swnj { 8162629Swnj struct updevice *upaddr; 8172379Swnj char *start; 8183107Swnj int num, blk, unit; 8192379Swnj struct size *sizes; 8202395Swnj register struct uba_regs *uba; 8212983Swnj register struct uba_device *ui; 8222379Swnj register short *rp; 8232395Swnj struct upst *st; 8242379Swnj 8252395Swnj unit = minor(dev) >> 3; 8262889Swnj if (unit >= NUP) 8272889Swnj return (ENXIO); 8282470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8292983Swnj ui = phys(struct uba_device *, updinfo[unit]); 8302889Swnj if (ui->ui_alive == 0) 8312889Swnj return (ENXIO); 8322395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8332983Swnj ubainit(uba); 8342629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8352983Swnj DELAY(2000000); 8362379Swnj num = maxfree; 8372379Swnj start = 0; 8382379Swnj upaddr->upcs2 = unit; 8392983Swnj DELAY(100); 8402983Swnj if ((upaddr->upcs1&UP_DVA) == 0) 8412983Swnj return (EFAULT); 8422629Swnj if ((upaddr->upds & UP_VV) == 0) { 8432629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 8442629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 8452629Swnj upaddr->upof = UP_FMT22; 8462379Swnj } 8472889Swnj if ((upaddr->upds & UP_DREADY) != UP_DREADY) 8482889Swnj return (EFAULT); 8492470Swnj st = &upst[ui->ui_type]; 8502395Swnj sizes = phys(struct size *, st->sizes); 8512889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 8522889Swnj return (EINVAL); 8532379Swnj while (num > 0) { 8542379Swnj register struct pte *io; 8552379Swnj register int i; 8562379Swnj int cn, sn, tn; 8572379Swnj daddr_t bn; 8582379Swnj 8592379Swnj blk = num > DBSIZE ? DBSIZE : num; 8602395Swnj io = uba->uba_map; 8612379Swnj for (i = 0; i < blk; i++) 8622983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 8632379Swnj *(int *)io = 0; 8642379Swnj bn = dumplo + btop(start); 8652607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 8662607Swnj sn = bn%st->nspc; 8672607Swnj tn = sn/st->nsect; 8682607Swnj sn = sn%st->nsect; 8692379Swnj upaddr->updc = cn; 8702379Swnj rp = (short *) &upaddr->upda; 8712379Swnj *rp = (tn << 8) + sn; 8722379Swnj *--rp = 0; 8732379Swnj *--rp = -blk*NBPG / sizeof (short); 8742629Swnj *--rp = UP_GO|UP_WCOM; 8752379Swnj do { 8762379Swnj DELAY(25); 8772629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 8782889Swnj if (upaddr->upcs1&UP_ERR) 8792889Swnj return (EIO); 8802379Swnj start += blk*NBPG; 8812379Swnj num -= blk; 8822379Swnj } 8832379Swnj return (0); 8842379Swnj } 8851902Swnj #endif 886