1*3445Sroot /* up.c 4.36 81/04/02 */ 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 10*3445Sroot * 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] = { 94*3445Sroot UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 95*3445Sroot UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 96*3445Sroot UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 97*3445Sroot 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; 135*3445Sroot 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 #ifdef notdef 1462629Swnj register struct updevice *upaddr; 1472629Swnj #endif 1482607Swnj 1492395Swnj if (upwstart == 0) { 1502759Swnj timeout(upwatch, (caddr_t)0, hz); 1512395Swnj upwstart++; 1522395Swnj } 1532571Swnj if (ui->ui_dk >= 0) 1542571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1552607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1562607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1572629Swnj #ifdef notdef 1582629Swnj upaddr = (struct updevice *)ui->ui_addr; 1592629Swnj upaddr->upcs1 = 0; 1602629Swnj upaddr->upcs2 = ui->ui_slave; 1612629Swnj upaddr->uphr = -1; 1622629Swnj /* ... */ 1632629Swnj if (upaddr-> ... == 10) 1642629Swnj ui->ui_type = 1; 1652629Swnj #endif 1662395Swnj } 167264Sbill 168264Sbill upstrategy(bp) 1692395Swnj register struct buf *bp; 170264Sbill { 1712983Swnj register struct uba_device *ui; 1722395Swnj register struct upst *st; 1732395Swnj register int unit; 1742470Swnj register struct buf *dp; 1752395Swnj int xunit = minor(bp->b_dev) & 07; 1762470Swnj long bn, sz; 177264Sbill 1782470Swnj sz = (bp->b_bcount+511) >> 9; 179264Sbill unit = dkunit(bp); 1802395Swnj if (unit >= NUP) 1812395Swnj goto bad; 1822395Swnj ui = updinfo[unit]; 1832395Swnj if (ui == 0 || ui->ui_alive == 0) 1842395Swnj goto bad; 1852395Swnj st = &upst[ui->ui_type]; 1862395Swnj if (bp->b_blkno < 0 || 1872395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1882395Swnj goto bad; 1892395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 190264Sbill (void) spl5(); 1912470Swnj dp = &uputab[ui->ui_unit]; 1922470Swnj disksort(dp, bp); 1932470Swnj if (dp->b_active == 0) { 1942395Swnj (void) upustart(ui); 1952395Swnj bp = &ui->ui_mi->um_tab; 1962395Swnj if (bp->b_actf && bp->b_active == 0) 1972395Swnj (void) upstart(ui->ui_mi); 198264Sbill } 199264Sbill (void) spl0(); 2002395Swnj return; 2012395Swnj 2022395Swnj bad: 2032395Swnj bp->b_flags |= B_ERROR; 2042395Swnj iodone(bp); 2052395Swnj return; 206264Sbill } 207264Sbill 2082674Swnj /* 2092674Swnj * Unit start routine. 2102674Swnj * Seek the drive to be where the data is 2112674Swnj * and then generate another interrupt 2122674Swnj * to actually start the transfer. 2132674Swnj * If there is only one drive on the controller, 2142674Swnj * or we are very close to the data, don't 2152674Swnj * bother with the search. If called after 2162674Swnj * searching once, don't bother to look where 2172674Swnj * we are, just queue for transfer (to avoid 2182674Swnj * positioning forever without transferrring.) 2192674Swnj */ 2202395Swnj upustart(ui) 2212983Swnj register struct uba_device *ui; 222264Sbill { 223264Sbill register struct buf *bp, *dp; 2242983Swnj register struct uba_ctlr *um; 2252629Swnj register struct updevice *upaddr; 2262395Swnj register struct upst *st; 227264Sbill daddr_t bn; 2282674Swnj int sn, csn; 2292607Swnj /* 2302607Swnj * The SC21 cancels commands if you just say 2312629Swnj * cs1 = UP_IE 2322607Swnj * so we are cautious about handling of cs1. 2332607Swnj * Also don't bother to clear as bits other than in upintr(). 2342607Swnj */ 2352674Swnj int didie = 0; 2362674Swnj 2372674Swnj if (ui == 0) 2382674Swnj return (0); 2392983Swnj um = ui->ui_mi; 2402395Swnj dk_busy &= ~(1<<ui->ui_dk); 2412395Swnj dp = &uputab[ui->ui_unit]; 242266Sbill if ((bp = dp->b_actf) == NULL) 243268Sbill goto out; 2442674Swnj /* 2452674Swnj * If the controller is active, just remember 2462674Swnj * that this device would like to be positioned... 2472674Swnj * if we tried to position now we would confuse the SC21. 2482674Swnj */ 2492395Swnj if (um->um_tab.b_active) { 2502459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 251275Sbill return (0); 252275Sbill } 2532674Swnj /* 2542674Swnj * If we have already positioned this drive, 2552674Swnj * then just put it on the ready queue. 2562674Swnj */ 257276Sbill if (dp->b_active) 258276Sbill goto done; 259276Sbill dp->b_active = 1; 2602629Swnj upaddr = (struct updevice *)um->um_addr; 2612395Swnj upaddr->upcs2 = ui->ui_slave; 2622674Swnj /* 2632674Swnj * If drive has just come up, 2642674Swnj * setup the pack. 2652674Swnj */ 266*3445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 2672607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2682629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2692629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 270*3445Sroot upaddr->upof = UPOF_FMT22; 271268Sbill didie = 1; 272264Sbill } 2732674Swnj /* 2742674Swnj * If drive is offline, forget about positioning. 2752674Swnj */ 276*3445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 277275Sbill goto done; 2782674Swnj /* 2792674Swnj * If there is only one drive, 2802674Swnj * dont bother searching. 2812674Swnj */ 2822607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 2832607Swnj goto done; 2842674Swnj /* 2852674Swnj * Figure out where this transfer is going to 2862674Swnj * and see if we are close enough to justify not searching. 2872674Swnj */ 2882395Swnj st = &upst[ui->ui_type]; 289264Sbill bn = dkblock(bp); 2902395Swnj sn = bn%st->nspc; 2912395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 2922674Swnj if (bp->b_cylin - upaddr->updc) 293266Sbill goto search; /* Not on-cylinder */ 294275Sbill else if (upseek) 295275Sbill goto done; /* Ok just to be on-cylinder */ 296264Sbill csn = (upaddr->upla>>6) - sn - 1; 297266Sbill if (csn < 0) 2982395Swnj csn += st->nsect; 2992395Swnj if (csn > st->nsect - upRDIST) 300264Sbill goto done; 301264Sbill search: 3022674Swnj upaddr->updc = bp->b_cylin; 3032674Swnj /* 3042674Swnj * Not on cylinder at correct position, 3052674Swnj * seek/search. 3062674Swnj */ 307275Sbill if (upseek) 3082629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3092470Swnj else { 310275Sbill upaddr->upda = sn; 3112629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 312275Sbill } 313268Sbill didie = 1; 3142674Swnj /* 3152674Swnj * Mark unit busy for iostat. 3162674Swnj */ 3172395Swnj if (ui->ui_dk >= 0) { 3182395Swnj dk_busy |= 1<<ui->ui_dk; 3192395Swnj dk_seek[ui->ui_dk]++; 320264Sbill } 321268Sbill goto out; 322264Sbill done: 3232674Swnj /* 3242674Swnj * Device is ready to go. 3252674Swnj * Put it on the ready queue for the controller 3262674Swnj * (unless its already there.) 3272674Swnj */ 3282629Swnj if (dp->b_active != 2) { 3292629Swnj dp->b_forw = NULL; 3302629Swnj if (um->um_tab.b_actf == NULL) 3312629Swnj um->um_tab.b_actf = dp; 3322629Swnj else 3332629Swnj um->um_tab.b_actl->b_forw = dp; 3342629Swnj um->um_tab.b_actl = dp; 3352629Swnj dp->b_active = 2; 3362629Swnj } 337268Sbill out: 338268Sbill return (didie); 339264Sbill } 340264Sbill 3412674Swnj /* 3422674Swnj * Start up a transfer on a drive. 3432674Swnj */ 3442395Swnj upstart(um) 3452983Swnj register struct uba_ctlr *um; 346264Sbill { 347264Sbill register struct buf *bp, *dp; 3482983Swnj register struct uba_device *ui; 3492629Swnj register struct updevice *upaddr; 3502470Swnj struct upst *st; 351264Sbill daddr_t bn; 3522681Swnj int dn, sn, tn, cmd, waitdry; 353264Sbill 354264Sbill loop: 3552674Swnj /* 3562674Swnj * Pull a request off the controller queue 3572674Swnj */ 3582395Swnj if ((dp = um->um_tab.b_actf) == NULL) 359268Sbill return (0); 360264Sbill if ((bp = dp->b_actf) == NULL) { 3612395Swnj um->um_tab.b_actf = dp->b_forw; 362264Sbill goto loop; 363264Sbill } 3642674Swnj /* 3652674Swnj * Mark controller busy, and 3662674Swnj * determine destination of this request. 3672674Swnj */ 3682395Swnj um->um_tab.b_active++; 3692395Swnj ui = updinfo[dkunit(bp)]; 370264Sbill bn = dkblock(bp); 3712395Swnj dn = ui->ui_slave; 3722395Swnj st = &upst[ui->ui_type]; 3732395Swnj sn = bn%st->nspc; 3742395Swnj tn = sn/st->nsect; 3752395Swnj sn %= st->nsect; 3762629Swnj upaddr = (struct updevice *)ui->ui_addr; 3772674Swnj /* 3782674Swnj * Select drive if not selected already. 3792674Swnj */ 3802674Swnj if ((upaddr->upcs2&07) != dn) 3812674Swnj upaddr->upcs2 = dn; 3822674Swnj /* 3832674Swnj * Check that it is ready and online 3842674Swnj */ 3852681Swnj waitdry = 0; 386*3445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 3872681Swnj if (++waitdry > 512) 3882681Swnj break; 3892681Swnj upwaitdry++; 3902681Swnj } 391*3445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 3922931Swnj printf("up%d: not ready", dkunit(bp)); 393*3445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 3942607Swnj printf("\n"); 3952395Swnj um->um_tab.b_active = 0; 3962395Swnj um->um_tab.b_errcnt = 0; 397893Sbill dp->b_actf = bp->av_forw; 398893Sbill dp->b_active = 0; 399893Sbill bp->b_flags |= B_ERROR; 400893Sbill iodone(bp); 401893Sbill goto loop; 402893Sbill } 4032674Swnj /* 4042674Swnj * Oh, well, sometimes this 4052674Swnj * happens, for reasons unknown. 4062674Swnj */ 4072629Swnj printf(" (flakey)\n"); 408264Sbill } 4092674Swnj /* 4102674Swnj * Setup for the transfer, and get in the 4112674Swnj * UNIBUS adaptor queue. 4122674Swnj */ 4132424Skre upaddr->updc = bp->b_cylin; 414264Sbill upaddr->upda = (tn << 8) + sn; 415264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 416264Sbill if (bp->b_flags & B_READ) 4172629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 418264Sbill else 4192629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4202571Swnj um->um_cmd = cmd; 4213107Swnj (void) ubago(ui); 422268Sbill return (1); 423264Sbill } 424264Sbill 4252674Swnj /* 4262674Swnj * Now all ready to go, stuff the registers. 4272674Swnj */ 4282571Swnj updgo(um) 4292983Swnj struct uba_ctlr *um; 4302395Swnj { 4312629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4322470Swnj 4332571Swnj upaddr->upba = um->um_ubinfo; 4342571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4352395Swnj } 4362395Swnj 4372674Swnj /* 4382674Swnj * Handle a disk interrupt. 4392674Swnj */ 4402707Swnj upintr(sc21) 4412395Swnj register sc21; 442264Sbill { 443264Sbill register struct buf *bp, *dp; 4442983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4452983Swnj register struct uba_device *ui; 4462629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 447264Sbill register unit; 4482470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4492607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4502681Swnj int needie = 1, waitdry; 451264Sbill 4522470Swnj sc->sc_wticks = 0; 4532607Swnj sc->sc_softas = 0; 4542674Swnj /* 4552674Swnj * If controller wasn't transferring, then this is an 4562674Swnj * interrupt for attention status on seeking drives. 4572674Swnj * Just service them. 4582674Swnj */ 4592674Swnj if (um->um_tab.b_active == 0) { 4602674Swnj if (upaddr->upcs1 & UP_TRE) 4612674Swnj upaddr->upcs1 = UP_TRE; 4622674Swnj goto doattn; 4632674Swnj } 4642674Swnj /* 4652674Swnj * Get device and block structures, and a pointer 4662983Swnj * to the uba_device for the drive. Select the drive. 4672674Swnj */ 4682674Swnj dp = um->um_tab.b_actf; 4692674Swnj bp = dp->b_actf; 4702674Swnj ui = updinfo[dkunit(bp)]; 4712674Swnj dk_busy &= ~(1 << ui->ui_dk); 4722674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 4732395Swnj upaddr->upcs2 = ui->ui_slave; 4742674Swnj /* 4752674Swnj * Check for and process errors on 4762674Swnj * either the drive or the controller. 4772674Swnj */ 478*3445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 4792681Swnj waitdry = 0; 480*3445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 4812681Swnj if (++waitdry > 512) 4822681Swnj break; 4832681Swnj upwaitdry++; 4842681Swnj } 485*3445Sroot if (upaddr->uper1&UPER1_WLE) { 4862674Swnj /* 4872674Swnj * Give up on write locked devices 4882674Swnj * immediately. 4892674Swnj */ 4902931Swnj printf("up%d: write locked\n", dkunit(bp)); 4912674Swnj bp->b_flags |= B_ERROR; 4922674Swnj } else if (++um->um_tab.b_errcnt > 27) { 4932674Swnj /* 4942674Swnj * After 28 retries (16 without offset, and 4952674Swnj * 12 with offset positioning) give up. 4962674Swnj */ 4972931Swnj harderr(bp, "up"); 4982931Swnj printf("cs2=%b er1=%b er2=%b\n", 4992785Swnj upaddr->upcs2, UPCS2_BITS, 5002785Swnj upaddr->uper1, UPER1_BITS, 5012785Swnj upaddr->uper2, UPER2_BITS); 5022674Swnj bp->b_flags |= B_ERROR; 5032674Swnj } else { 5042674Swnj /* 5052674Swnj * Retriable error. 5062674Swnj * If a soft ecc, correct it (continuing 5072674Swnj * by returning if necessary. 5082674Swnj * Otherwise fall through and retry the transfer 5092674Swnj */ 5102674Swnj um->um_tab.b_active = 0; /* force retry */ 511*3445Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) 5122629Swnj if (upecc(ui)) 5132629Swnj return; 5142674Swnj } 5152674Swnj /* 5162674Swnj * Clear drive error and, every eight attempts, 5172674Swnj * (starting with the fourth) 5182674Swnj * recalibrate to clear the slate. 5192674Swnj */ 5202674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5212674Swnj needie = 0; 5223182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5232674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5243160Swnj sc->sc_recal = 0; 5253160Swnj goto nextrecal; 5262674Swnj } 5272674Swnj } 5282674Swnj /* 5293160Swnj * Advance recalibration finite state machine 5303160Swnj * if recalibrate in progress, through 5313160Swnj * RECAL 5323160Swnj * SEEK 5333160Swnj * OFFSET (optional) 5343160Swnj * RETRY 5352674Swnj */ 5363160Swnj switch (sc->sc_recal) { 5373160Swnj 5383160Swnj case 1: 5393160Swnj upaddr->updc = bp->b_cylin; 5403160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 5413160Swnj goto nextrecal; 5423160Swnj case 2: 5433160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 5443160Swnj goto donerecal; 545*3445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 5463160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 5473160Swnj goto nextrecal; 5483160Swnj nextrecal: 5493160Swnj sc->sc_recal++; 5503160Swnj um->um_tab.b_active = 1; 5513160Swnj return; 5523160Swnj donerecal: 5533160Swnj case 3: 5542674Swnj sc->sc_recal = 0; 5553160Swnj um->um_tab.b_active = 0; 5563160Swnj break; 5572674Swnj } 5582674Swnj /* 5592674Swnj * If still ``active'', then don't need any more retries. 5602674Swnj */ 5612674Swnj if (um->um_tab.b_active) { 5622674Swnj /* 5632674Swnj * If we were offset positioning, 5642674Swnj * return to centerline. 5652674Swnj */ 5662674Swnj if (um->um_tab.b_errcnt >= 16) { 567*3445Sroot upaddr->upof = UPOF_FMT22; 5682674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 569*3445Sroot while (upaddr->upds & UPDS_PIP) 5702674Swnj DELAY(25); 571268Sbill needie = 0; 572264Sbill } 5732674Swnj um->um_tab.b_active = 0; 5742674Swnj um->um_tab.b_errcnt = 0; 5752674Swnj um->um_tab.b_actf = dp->b_forw; 5762674Swnj dp->b_active = 0; 5772674Swnj dp->b_errcnt = 0; 5782674Swnj dp->b_actf = bp->av_forw; 5792674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 5802674Swnj iodone(bp); 5812674Swnj /* 5822674Swnj * If this unit has more work to do, 5832674Swnj * then start it up right away. 5842674Swnj */ 5852674Swnj if (dp->b_actf) 5862674Swnj if (upustart(ui)) 587268Sbill needie = 0; 588264Sbill } 5892674Swnj as &= ~(1<<ui->ui_slave); 5903403Swnj /* 5913403Swnj * Release unibus resources and flush data paths. 5923403Swnj */ 5933403Swnj ubadone(um); 5942674Swnj doattn: 5952674Swnj /* 5962674Swnj * Process other units which need attention. 5972674Swnj * For each unit which needs attention, call 5982674Swnj * the unit start routine to place the slave 5992674Swnj * on the controller device queue. 6002674Swnj */ 6013160Swnj while (unit = ffs(as)) { 6023160Swnj unit--; /* was 1 origin */ 6033160Swnj as &= ~(1<<unit); 6043160Swnj upaddr->upas = 1<<unit; 6053160Swnj if (upustart(upip[sc21][unit])) 6063160Swnj needie = 0; 6073160Swnj } 6082674Swnj /* 6092674Swnj * If the controller is not transferring, but 6102674Swnj * there are devices ready to transfer, start 6112674Swnj * the controller. 6122674Swnj */ 6132395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6142395Swnj if (upstart(um)) 615268Sbill needie = 0; 616275Sbill if (needie) 6172629Swnj upaddr->upcs1 = UP_IE; 618264Sbill } 619264Sbill 620264Sbill upread(dev) 6212616Swnj dev_t dev; 622264Sbill { 6232616Swnj register int unit = minor(dev) >> 3; 6242470Swnj 6252616Swnj if (unit >= NUP) 6262616Swnj u.u_error = ENXIO; 6272616Swnj else 6282616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 629264Sbill } 630264Sbill 631264Sbill upwrite(dev) 6322616Swnj dev_t dev; 633264Sbill { 6342616Swnj register int unit = minor(dev) >> 3; 6352470Swnj 6362616Swnj if (unit >= NUP) 6372616Swnj u.u_error = ENXIO; 6382616Swnj else 6392616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 640264Sbill } 641264Sbill 642266Sbill /* 643266Sbill * Correct an ECC error, and restart the i/o to complete 644266Sbill * the transfer if necessary. This is quite complicated because 645266Sbill * the transfer may be going to an odd memory address base and/or 646266Sbill * across a page boundary. 647266Sbill */ 6482395Swnj upecc(ui) 6492983Swnj register struct uba_device *ui; 650264Sbill { 6512629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6522395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6532983Swnj register struct uba_ctlr *um = ui->ui_mi; 6542395Swnj register struct upst *st; 6552395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 656266Sbill register int i; 657264Sbill caddr_t addr; 658266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 659264Sbill int bn, cn, tn, sn; 660264Sbill 661264Sbill /* 662266Sbill * Npf is the number of sectors transferred before the sector 663266Sbill * containing the ECC error, and reg is the UBA register 664266Sbill * mapping (the first part of) the transfer. 665266Sbill * O is offset within a memory page of the first byte transferred. 666264Sbill */ 667266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 6682571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 669264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 6702983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 6712889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 672264Sbill mask = up->upec2; 673*3445Sroot #ifdef UPECCDEBUG 6743403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 6753403Swnj up->upec1); 676*3445Sroot #endif 677266Sbill /* 678266Sbill * Flush the buffered data path, and compute the 679266Sbill * byte and bit position of the error. The variable i 680266Sbill * is the byte offset in the transfer, the variable byte 681266Sbill * is the offset from a page boundary in main memory. 682266Sbill */ 6832725Swnj ubapurge(um); 684266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 685266Sbill bit = i&07; 686266Sbill i = (i&~07)>>3; 687264Sbill byte = i + o; 688266Sbill /* 689266Sbill * Correct while possible bits remain of mask. Since mask 690266Sbill * contains 11 bits, we continue while the bit offset is > -11. 691266Sbill * Also watch out for end of this block and the end of the whole 692266Sbill * transfer. 693266Sbill */ 694266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 695266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 696266Sbill (byte & PGOFSET); 697*3445Sroot #ifdef UPECCDEBUG 6983403Swnj printf("addr %x map reg %x\n", 6993403Swnj addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 7003403Swnj printf("old: %x, ", getmemc(addr)); 701*3445Sroot #endif 702266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 703*3445Sroot #ifdef UPECCDEBUG 7043403Swnj printf("new: %x\n", getmemc(addr)); 705*3445Sroot #endif 706266Sbill byte++; 707266Sbill i++; 708266Sbill bit -= 8; 709264Sbill } 7102395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 711264Sbill if (up->upwc == 0) 712264Sbill return (0); 713266Sbill /* 714266Sbill * Have to continue the transfer... clear the drive, 715266Sbill * and compute the position where the transfer is to continue. 716266Sbill * We have completed npf+1 sectors of the transfer already; 717266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 718266Sbill */ 7192629Swnj #ifdef notdef 7202629Swnj up->uper1 = 0; 7212629Swnj up->upcs1 |= UP_GO; 7222629Swnj #else 7232629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 724264Sbill bn = dkblock(bp); 7252395Swnj st = &upst[ui->ui_type]; 726264Sbill cn = bp->b_cylin; 7272395Swnj sn = bn%st->nspc + npf + 1; 7282395Swnj tn = sn/st->nsect; 7292395Swnj sn %= st->nsect; 7302395Swnj cn += tn/st->ntrak; 7312395Swnj tn %= st->ntrak; 732264Sbill up->updc = cn; 733266Sbill up->upda = (tn << 8) | sn; 734266Sbill ubaddr = (int)ptob(reg+1) + o; 735266Sbill up->upba = ubaddr; 736266Sbill cmd = (ubaddr >> 8) & 0x300; 7372629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 738266Sbill up->upcs1 = cmd; 7392629Swnj #endif 740264Sbill return (1); 741264Sbill } 742286Sbill 743286Sbill /* 744286Sbill * Reset driver after UBA init. 745286Sbill * Cancel software state of all pending transfers 746286Sbill * and restart all units and the controller. 747286Sbill */ 7482395Swnj upreset(uban) 7492931Swnj int uban; 750286Sbill { 7512983Swnj register struct uba_ctlr *um; 7522983Swnj register struct uba_device *ui; 7532395Swnj register sc21, unit; 754286Sbill 7552646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7562470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7572470Swnj um->um_alive == 0) 7582395Swnj continue; 7592931Swnj printf(" sc%d", sc21); 7602395Swnj um->um_tab.b_active = 0; 7612395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7622931Swnj up_softc[sc21].sc_recal = 0; 7632571Swnj if (um->um_ubinfo) { 7642571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7652616Swnj ubadone(um); 7662395Swnj } 767*3445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 7682395Swnj for (unit = 0; unit < NUP; unit++) { 7692395Swnj if ((ui = updinfo[unit]) == 0) 7702395Swnj continue; 7712931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 7722395Swnj continue; 7732395Swnj uputab[unit].b_active = 0; 7742395Swnj (void) upustart(ui); 7752395Swnj } 7762395Swnj (void) upstart(um); 777286Sbill } 778286Sbill } 779313Sbill 780313Sbill /* 781313Sbill * Wake up every second and if an interrupt is pending 782313Sbill * but nothing has happened increment a counter. 7832931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 784313Sbill * and begin anew. 785313Sbill */ 786313Sbill upwatch() 787313Sbill { 7882983Swnj register struct uba_ctlr *um; 7892395Swnj register sc21, unit; 7902470Swnj register struct up_softc *sc; 791313Sbill 7922759Swnj timeout(upwatch, (caddr_t)0, hz); 7932646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7942395Swnj um = upminfo[sc21]; 7952470Swnj if (um == 0 || um->um_alive == 0) 7962470Swnj continue; 7972470Swnj sc = &up_softc[sc21]; 7982395Swnj if (um->um_tab.b_active == 0) { 7992395Swnj for (unit = 0; unit < NUP; unit++) 8002629Swnj if (uputab[unit].b_active && 8012629Swnj updinfo[unit]->ui_mi == um) 8022395Swnj goto active; 8032470Swnj sc->sc_wticks = 0; 8042395Swnj continue; 8052395Swnj } 8062931Swnj active: 8072470Swnj sc->sc_wticks++; 8082470Swnj if (sc->sc_wticks >= 20) { 8092470Swnj sc->sc_wticks = 0; 8102931Swnj printf("sc%d: lost interrupt\n", sc21); 8112646Swnj ubareset(um->um_ubanum); 8122395Swnj } 813313Sbill } 814313Sbill } 8152379Swnj 8162379Swnj #define DBSIZE 20 8172379Swnj 8182379Swnj updump(dev) 8192379Swnj dev_t dev; 8202379Swnj { 8212629Swnj struct updevice *upaddr; 8222379Swnj char *start; 8233107Swnj int num, blk, unit; 8242379Swnj struct size *sizes; 8252395Swnj register struct uba_regs *uba; 8262983Swnj register struct uba_device *ui; 8272379Swnj register short *rp; 8282395Swnj struct upst *st; 8292379Swnj 8302395Swnj unit = minor(dev) >> 3; 8312889Swnj if (unit >= NUP) 8322889Swnj return (ENXIO); 8332470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8342983Swnj ui = phys(struct uba_device *, updinfo[unit]); 8352889Swnj if (ui->ui_alive == 0) 8362889Swnj return (ENXIO); 8372395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8382983Swnj ubainit(uba); 8392629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8402983Swnj DELAY(2000000); 8412379Swnj num = maxfree; 8422379Swnj start = 0; 8432379Swnj upaddr->upcs2 = unit; 8442983Swnj DELAY(100); 8452983Swnj if ((upaddr->upcs1&UP_DVA) == 0) 8462983Swnj return (EFAULT); 847*3445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 8482629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 8492629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 850*3445Sroot upaddr->upof = UPOF_FMT22; 8512379Swnj } 852*3445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 8532889Swnj return (EFAULT); 8542470Swnj st = &upst[ui->ui_type]; 8552395Swnj sizes = phys(struct size *, st->sizes); 8562889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 8572889Swnj return (EINVAL); 8582379Swnj while (num > 0) { 8592379Swnj register struct pte *io; 8602379Swnj register int i; 8612379Swnj int cn, sn, tn; 8622379Swnj daddr_t bn; 8632379Swnj 8642379Swnj blk = num > DBSIZE ? DBSIZE : num; 8652395Swnj io = uba->uba_map; 8662379Swnj for (i = 0; i < blk; i++) 8672983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 8682379Swnj *(int *)io = 0; 8692379Swnj bn = dumplo + btop(start); 8702607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 8712607Swnj sn = bn%st->nspc; 8722607Swnj tn = sn/st->nsect; 8732607Swnj sn = sn%st->nsect; 8742379Swnj upaddr->updc = cn; 8752379Swnj rp = (short *) &upaddr->upda; 8762379Swnj *rp = (tn << 8) + sn; 8772379Swnj *--rp = 0; 8782379Swnj *--rp = -blk*NBPG / sizeof (short); 8792629Swnj *--rp = UP_GO|UP_WCOM; 8802379Swnj do { 8812379Swnj DELAY(25); 8822629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 883*3445Sroot if (upaddr->upds&UPDS_ERR) 8842889Swnj return (EIO); 8852379Swnj start += blk*NBPG; 8862379Swnj num -= blk; 8872379Swnj } 8882379Swnj return (0); 8892379Swnj } 8901902Swnj #endif 891