1*2681Swnj /* up.c 4.23 81/02/25 */ 2264Sbill 31937Swnj #include "up.h" 42646Swnj #if NSC > 0 5264Sbill /* 6885Sbill * UNIBUS disk driver with overlapped seeks and ECC recovery. 7264Sbill */ 81756Sbill #define DELAY(N) { register int d; d = N; while (--d > 0); } 9264Sbill 10264Sbill #include "../h/param.h" 11264Sbill #include "../h/systm.h" 122395Swnj #include "../h/cpu.h" 132395Swnj #include "../h/nexus.h" 14308Sbill #include "../h/dk.h" 15264Sbill #include "../h/buf.h" 16264Sbill #include "../h/conf.h" 17264Sbill #include "../h/dir.h" 18264Sbill #include "../h/user.h" 19264Sbill #include "../h/map.h" 20420Sbill #include "../h/pte.h" 21264Sbill #include "../h/mba.h" 22264Sbill #include "../h/mtpr.h" 232571Swnj #include "../h/vm.h" 24264Sbill #include "../h/uba.h" 252379Swnj #include "../h/cmap.h" 26264Sbill 272379Swnj #include "../h/upreg.h" 28264Sbill 292395Swnj struct up_softc { 302395Swnj int sc_softas; 312607Swnj int sc_ndrive; 322395Swnj int sc_wticks; 332674Swnj int sc_recal; 342646Swnj } up_softc[NSC]; 35275Sbill 362395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 37264Sbill struct size 38264Sbill { 39264Sbill daddr_t nblocks; 40264Sbill int cyloff; 41264Sbill } up_sizes[8] = { 42264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 43264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 44341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 45264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 46264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 47264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 48264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 49264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 502395Swnj }, fj_sizes[8] = { 512395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 522395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 532395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 542395Swnj 0, 0, 552395Swnj 0, 0, 562395Swnj 0, 0, 572395Swnj 0, 0, 582395Swnj 213760, 155, /* H=cyl 155 thru 822 */ 59264Sbill }; 602395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 61264Sbill 622395Swnj #define _upSDIST 2 /* 1.0 msec */ 632395Swnj #define _upRDIST 4 /* 2.0 msec */ 64264Sbill 652395Swnj int upSDIST = _upSDIST; 662395Swnj int upRDIST = _upRDIST; 672395Swnj 682607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 692646Swnj struct uba_minfo *upminfo[NSC]; 702395Swnj struct uba_dinfo *updinfo[NUP]; 712646Swnj struct uba_dinfo *upip[NSC][4]; 722395Swnj 732607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 742616Swnj struct uba_driver scdriver = 752607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 762395Swnj struct buf uputab[NUP]; 772395Swnj 782395Swnj struct upst { 792395Swnj short nsect; 802395Swnj short ntrak; 812395Swnj short nspc; 822395Swnj short ncyl; 832395Swnj struct size *sizes; 842395Swnj } upst[] = { 852607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 862607Swnj /* 9300 actually has 815 cylinders... */ 872395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 882395Swnj }; 892395Swnj 902629Swnj u_char up_offset[16] = { 912629Swnj UP_P400, UP_M400, UP_P400, UP_M400, UP_P800, UP_M800, UP_P800, UP_M800, 922629Swnj UP_P1200, UP_M1200, UP_P1200, UP_M1200, 0, 0, 0, 0 932629Swnj }; 94264Sbill 952616Swnj struct buf rupbuf[NUP]; 96264Sbill 97264Sbill #define b_cylin b_resid 98264Sbill 99264Sbill #ifdef INTRLVE 100264Sbill daddr_t dkblock(); 101264Sbill #endif 1022395Swnj 1032395Swnj int upwstart, upwatch(); /* Have started guardian */ 1042470Swnj int upseek; 105*2681Swnj int upwaitdry; 1062395Swnj 1072395Swnj /*ARGSUSED*/ 1082607Swnj upprobe(reg) 1092395Swnj caddr_t reg; 1102395Swnj { 1112459Swnj register int br, cvec; 1122459Swnj 1132607Swnj #ifdef lint 1142607Swnj br = 0; cvec = br; br = cvec; 1152607Swnj #endif 1162629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1172607Swnj DELAY(10); 1182629Swnj ((struct updevice *)reg)->upcs1 = 0; 1192459Swnj return (1); 1202395Swnj } 1212395Swnj 1222607Swnj upslave(ui, reg) 1232395Swnj struct uba_dinfo *ui; 1242395Swnj caddr_t reg; 1252395Swnj { 1262629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1272395Swnj 1282395Swnj upaddr->upcs1 = 0; /* conservative */ 1292607Swnj upaddr->upcs2 = ui->ui_slave; 1302629Swnj if (upaddr->upcs2&UP_NED) { 1312629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1322395Swnj return (0); 1332395Swnj } 1342607Swnj return (1); 1352607Swnj } 1362607Swnj 1372607Swnj upattach(ui) 1382607Swnj register struct uba_dinfo *ui; 1392607Swnj { 1402629Swnj #ifdef notdef 1412629Swnj register struct updevice *upaddr; 1422629Swnj #endif 1432607Swnj 1442395Swnj if (upwstart == 0) { 1452395Swnj timeout(upwatch, (caddr_t)0, HZ); 1462395Swnj upwstart++; 1472395Swnj } 1482571Swnj if (ui->ui_dk >= 0) 1492571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1502607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1512607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1522629Swnj #ifdef notdef 1532629Swnj upaddr = (struct updevice *)ui->ui_addr; 1542629Swnj upaddr->upcs1 = 0; 1552629Swnj upaddr->upcs2 = ui->ui_slave; 1562629Swnj upaddr->uphr = -1; 1572629Swnj /* ... */ 1582629Swnj if (upaddr-> ... == 10) 1592629Swnj ui->ui_type = 1; 1602629Swnj #endif 1612395Swnj } 162264Sbill 163264Sbill upstrategy(bp) 1642395Swnj register struct buf *bp; 165264Sbill { 1662395Swnj register struct uba_dinfo *ui; 1672395Swnj register struct upst *st; 1682395Swnj register int unit; 1692470Swnj register struct buf *dp; 1702395Swnj int xunit = minor(bp->b_dev) & 07; 1712470Swnj long bn, sz; 172264Sbill 1732470Swnj sz = (bp->b_bcount+511) >> 9; 174264Sbill unit = dkunit(bp); 1752395Swnj if (unit >= NUP) 1762395Swnj goto bad; 1772395Swnj ui = updinfo[unit]; 1782395Swnj if (ui == 0 || ui->ui_alive == 0) 1792395Swnj goto bad; 1802395Swnj st = &upst[ui->ui_type]; 1812395Swnj if (bp->b_blkno < 0 || 1822395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1832395Swnj goto bad; 1842395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 185264Sbill (void) spl5(); 1862470Swnj dp = &uputab[ui->ui_unit]; 1872470Swnj disksort(dp, bp); 1882470Swnj if (dp->b_active == 0) { 1892395Swnj (void) upustart(ui); 1902395Swnj bp = &ui->ui_mi->um_tab; 1912395Swnj if (bp->b_actf && bp->b_active == 0) 1922395Swnj (void) upstart(ui->ui_mi); 193264Sbill } 194264Sbill (void) spl0(); 1952395Swnj return; 1962395Swnj 1972395Swnj bad: 1982395Swnj bp->b_flags |= B_ERROR; 1992395Swnj iodone(bp); 2002395Swnj return; 201264Sbill } 202264Sbill 2032674Swnj /* 2042674Swnj * Unit start routine. 2052674Swnj * Seek the drive to be where the data is 2062674Swnj * and then generate another interrupt 2072674Swnj * to actually start the transfer. 2082674Swnj * If there is only one drive on the controller, 2092674Swnj * or we are very close to the data, don't 2102674Swnj * bother with the search. If called after 2112674Swnj * searching once, don't bother to look where 2122674Swnj * we are, just queue for transfer (to avoid 2132674Swnj * positioning forever without transferrring.) 2142674Swnj */ 2152395Swnj upustart(ui) 2162395Swnj register struct uba_dinfo *ui; 217264Sbill { 218264Sbill register struct buf *bp, *dp; 2192674Swnj register struct uba_minfo *um = ui->ui_mi; 2202629Swnj register struct updevice *upaddr; 2212395Swnj register struct upst *st; 222264Sbill daddr_t bn; 2232674Swnj int sn, csn; 2242607Swnj /* 2252607Swnj * The SC21 cancels commands if you just say 2262629Swnj * cs1 = UP_IE 2272607Swnj * so we are cautious about handling of cs1. 2282607Swnj * Also don't bother to clear as bits other than in upintr(). 2292607Swnj */ 2302674Swnj int didie = 0; 2312674Swnj 2322674Swnj if (ui == 0) 2332674Swnj return (0); 2342395Swnj dk_busy &= ~(1<<ui->ui_dk); 2352395Swnj dp = &uputab[ui->ui_unit]; 236266Sbill if ((bp = dp->b_actf) == NULL) 237268Sbill goto out; 2382674Swnj /* 2392674Swnj * If the controller is active, just remember 2402674Swnj * that this device would like to be positioned... 2412674Swnj * if we tried to position now we would confuse the SC21. 2422674Swnj */ 2432395Swnj if (um->um_tab.b_active) { 2442459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 245275Sbill return (0); 246275Sbill } 2472674Swnj /* 2482674Swnj * If we have already positioned this drive, 2492674Swnj * then just put it on the ready queue. 2502674Swnj */ 251276Sbill if (dp->b_active) 252276Sbill goto done; 253276Sbill dp->b_active = 1; 2542629Swnj upaddr = (struct updevice *)um->um_addr; 2552395Swnj upaddr->upcs2 = ui->ui_slave; 2562674Swnj /* 2572674Swnj * If drive has just come up, 2582674Swnj * setup the pack. 2592674Swnj */ 2602629Swnj if ((upaddr->upds & UP_VV) == 0) { 2612607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2622629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2632629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 2642629Swnj upaddr->upof = UP_FMT22; 265268Sbill didie = 1; 266264Sbill } 2672674Swnj /* 2682674Swnj * If drive is offline, forget about positioning. 2692674Swnj */ 2702629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) 271275Sbill goto done; 2722674Swnj /* 2732674Swnj * If there is only one drive, 2742674Swnj * dont bother searching. 2752674Swnj */ 2762607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 2772607Swnj goto done; 2782674Swnj /* 2792674Swnj * Figure out where this transfer is going to 2802674Swnj * and see if we are close enough to justify not searching. 2812674Swnj */ 2822395Swnj st = &upst[ui->ui_type]; 283264Sbill bn = dkblock(bp); 2842395Swnj sn = bn%st->nspc; 2852395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 2862674Swnj if (bp->b_cylin - upaddr->updc) 287266Sbill goto search; /* Not on-cylinder */ 288275Sbill else if (upseek) 289275Sbill goto done; /* Ok just to be on-cylinder */ 290264Sbill csn = (upaddr->upla>>6) - sn - 1; 291266Sbill if (csn < 0) 2922395Swnj csn += st->nsect; 2932395Swnj if (csn > st->nsect - upRDIST) 294264Sbill goto done; 295264Sbill search: 2962674Swnj upaddr->updc = bp->b_cylin; 2972674Swnj /* 2982674Swnj * Not on cylinder at correct position, 2992674Swnj * seek/search. 3002674Swnj */ 301275Sbill if (upseek) 3022629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3032470Swnj else { 304275Sbill upaddr->upda = sn; 3052629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 306275Sbill } 307268Sbill didie = 1; 3082674Swnj /* 3092674Swnj * Mark unit busy for iostat. 3102674Swnj */ 3112395Swnj if (ui->ui_dk >= 0) { 3122395Swnj dk_busy |= 1<<ui->ui_dk; 3132395Swnj dk_seek[ui->ui_dk]++; 314264Sbill } 315268Sbill goto out; 316264Sbill done: 3172674Swnj /* 3182674Swnj * Device is ready to go. 3192674Swnj * Put it on the ready queue for the controller 3202674Swnj * (unless its already there.) 3212674Swnj */ 3222629Swnj if (dp->b_active != 2) { 3232629Swnj dp->b_forw = NULL; 3242629Swnj if (um->um_tab.b_actf == NULL) 3252629Swnj um->um_tab.b_actf = dp; 3262629Swnj else 3272629Swnj um->um_tab.b_actl->b_forw = dp; 3282629Swnj um->um_tab.b_actl = dp; 3292629Swnj dp->b_active = 2; 3302629Swnj } 331268Sbill out: 332268Sbill return (didie); 333264Sbill } 334264Sbill 3352674Swnj /* 3362674Swnj * Start up a transfer on a drive. 3372674Swnj */ 3382395Swnj upstart(um) 3392395Swnj register struct uba_minfo *um; 340264Sbill { 341264Sbill register struct buf *bp, *dp; 3422395Swnj register struct uba_dinfo *ui; 3432629Swnj register struct updevice *upaddr; 3442470Swnj struct upst *st; 345264Sbill daddr_t bn; 346*2681Swnj int dn, sn, tn, cmd, waitdry; 347264Sbill 348264Sbill loop: 3492674Swnj /* 3502674Swnj * Pull a request off the controller queue 3512674Swnj */ 3522395Swnj if ((dp = um->um_tab.b_actf) == NULL) 353268Sbill return (0); 354264Sbill if ((bp = dp->b_actf) == NULL) { 3552395Swnj um->um_tab.b_actf = dp->b_forw; 356264Sbill goto loop; 357264Sbill } 3582674Swnj /* 3592674Swnj * Mark controller busy, and 3602674Swnj * determine destination of this request. 3612674Swnj */ 3622395Swnj um->um_tab.b_active++; 3632395Swnj ui = updinfo[dkunit(bp)]; 364264Sbill bn = dkblock(bp); 3652395Swnj dn = ui->ui_slave; 3662395Swnj st = &upst[ui->ui_type]; 3672395Swnj sn = bn%st->nspc; 3682395Swnj tn = sn/st->nsect; 3692395Swnj sn %= st->nsect; 3702629Swnj upaddr = (struct updevice *)ui->ui_addr; 3712674Swnj /* 3722674Swnj * Select drive if not selected already. 3732674Swnj */ 3742674Swnj if ((upaddr->upcs2&07) != dn) 3752674Swnj upaddr->upcs2 = dn; 3762674Swnj /* 3772674Swnj * Check that it is ready and online 3782674Swnj */ 379*2681Swnj waitdry = 0; 380*2681Swnj while ((upaddr->upds&UP_DRY) == 0) { 381*2681Swnj if (++waitdry > 512) 382*2681Swnj break; 383*2681Swnj upwaitdry++; 384*2681Swnj } 385*2681Swnj if ((upaddr->upds & UP_DREADY) != UP_DREADY) { 3862607Swnj printf("up%d not ready", dkunit(bp)); 387*2681Swnj if ((upaddr->upds & UP_DREADY) != UP_DREADY) { 3882607Swnj printf("\n"); 3892395Swnj um->um_tab.b_active = 0; 3902395Swnj um->um_tab.b_errcnt = 0; 391893Sbill dp->b_actf = bp->av_forw; 392893Sbill dp->b_active = 0; 393893Sbill bp->b_flags |= B_ERROR; 394893Sbill iodone(bp); 395893Sbill goto loop; 396893Sbill } 3972674Swnj /* 3982674Swnj * Oh, well, sometimes this 3992674Swnj * happens, for reasons unknown. 4002674Swnj */ 4012629Swnj printf(" (flakey)\n"); 402264Sbill } 4032674Swnj /* 4042674Swnj * After 16th retry, do offset positioning 4052674Swnj */ 4062395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 4072629Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UP_FMT22; 4082629Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 4092629Swnj while (upaddr->upds & UP_PIP) 410264Sbill DELAY(25); 411264Sbill } 4122674Swnj /* 4132674Swnj * Setup for the transfer, and get in the 4142674Swnj * UNIBUS adaptor queue. 4152674Swnj */ 4162424Skre upaddr->updc = bp->b_cylin; 417264Sbill upaddr->upda = (tn << 8) + sn; 418264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 419264Sbill if (bp->b_flags & B_READ) 4202629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 421264Sbill else 4222629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4232571Swnj um->um_cmd = cmd; 4242571Swnj ubago(ui); 425268Sbill return (1); 426264Sbill } 427264Sbill 4282674Swnj /* 4292674Swnj * Now all ready to go, stuff the registers. 4302674Swnj */ 4312571Swnj updgo(um) 4322571Swnj struct uba_minfo *um; 4332395Swnj { 4342629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4352470Swnj 4362571Swnj upaddr->upba = um->um_ubinfo; 4372571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4382395Swnj } 4392395Swnj 4402674Swnj /* 4412674Swnj * Handle a disk interrupt. 4422674Swnj */ 4432616Swnj scintr(sc21) 4442395Swnj register sc21; 445264Sbill { 446264Sbill register struct buf *bp, *dp; 4472395Swnj register struct uba_minfo *um = upminfo[sc21]; 4482395Swnj register struct uba_dinfo *ui; 4492629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 450264Sbill register unit; 4512470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4522607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 453*2681Swnj int needie = 1, waitdry; 454264Sbill 4552470Swnj sc->sc_wticks = 0; 4562607Swnj sc->sc_softas = 0; 4572674Swnj /* 4582674Swnj * If controller wasn't transferring, then this is an 4592674Swnj * interrupt for attention status on seeking drives. 4602674Swnj * Just service them. 4612674Swnj */ 4622674Swnj if (um->um_tab.b_active == 0) { 4632674Swnj if (upaddr->upcs1 & UP_TRE) 4642674Swnj upaddr->upcs1 = UP_TRE; 4652674Swnj goto doattn; 4662674Swnj } 4672674Swnj if ((upaddr->upcs1 & UP_RDY) == 0) 4682674Swnj printf("upintr !RDY\n"); /* shouldn't happen */ 4692674Swnj /* 4702674Swnj * Get device and block structures, and a pointer 4712674Swnj * to the uba_dinfo for the drive. Select the drive. 4722674Swnj */ 4732674Swnj dp = um->um_tab.b_actf; 4742674Swnj bp = dp->b_actf; 4752674Swnj ui = updinfo[dkunit(bp)]; 4762674Swnj dk_busy &= ~(1 << ui->ui_dk); 4772674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 4782395Swnj upaddr->upcs2 = ui->ui_slave; 4792674Swnj /* 4802674Swnj * Check for and process errors on 4812674Swnj * either the drive or the controller. 4822674Swnj */ 4832674Swnj if ((upaddr->upds&UP_ERR) || (upaddr->upcs1&UP_TRE)) { 484*2681Swnj waitdry = 0; 485*2681Swnj while ((upaddr->upds & UP_DRY) == 0) { 486*2681Swnj if (++waitdry > 512) 487*2681Swnj break; 488*2681Swnj upwaitdry++; 489*2681Swnj } 490*2681Swnj if ((upaddr->upds&UP_DREADY) != UP_DREADY) { 491*2681Swnj printf("up%d not ready", dkunit(bp)); 492*2681Swnj bp->b_flags |= B_ERROR; 493*2681Swnj } else if (upaddr->uper1&UP_WLE) { 4942674Swnj /* 4952674Swnj * Give up on write locked devices 4962674Swnj * immediately. 4972674Swnj */ 4982674Swnj printf("up%d is write locked\n", dkunit(bp)); 4992674Swnj bp->b_flags |= B_ERROR; 5002674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5012674Swnj /* 5022674Swnj * After 28 retries (16 without offset, and 5032674Swnj * 12 with offset positioning) give up. 5042674Swnj */ 5052674Swnj if (upaddr->upcs2&(UP_NEM|UP_MXF)) { 5062674Swnj printf("FLAKEY UP "); 5072674Swnj ubareset(um->um_ubanum); 5082674Swnj return; 5092395Swnj } 5102674Swnj harderr(bp); 5112674Swnj printf("up%d cs2 %b er1 %b er2 %b\n", 5122674Swnj dkunit(bp), upaddr->upcs2, UPCS2_BITS, upaddr->uper1, 5132674Swnj UPER1_BITS, upaddr->uper2, UPER2_BITS); 5142674Swnj bp->b_flags |= B_ERROR; 5152674Swnj } else { 5162674Swnj /* 5172674Swnj * Retriable error. 5182674Swnj * If a soft ecc, correct it (continuing 5192674Swnj * by returning if necessary. 5202674Swnj * Otherwise fall through and retry the transfer 5212674Swnj */ 5222674Swnj um->um_tab.b_active = 0; /* force retry */ 5232629Swnj if ((upaddr->uper1&(UP_DCK|UP_ECH))==UP_DCK) 5242629Swnj if (upecc(ui)) 5252629Swnj return; 5262674Swnj } 5272674Swnj /* 5282674Swnj * Clear drive error and, every eight attempts, 5292674Swnj * (starting with the fourth) 5302674Swnj * recalibrate to clear the slate. 5312674Swnj */ 5322674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5332674Swnj needie = 0; 5342674Swnj if ((um->um_tab.b_errcnt&07) == 4) { 5352674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5362674Swnj um->um_tab.b_active = 1; 5372674Swnj sc->sc_recal = 1; 5382674Swnj return; 5392674Swnj } 5402674Swnj } 5412674Swnj /* 5422674Swnj * Done retrying transfer... release 5432674Swnj * resources... if we were recalibrating, 5442674Swnj * then retry the transfer. 5452674Swnj * Mathematical note: 28%8 != 4. 5462674Swnj */ 5472674Swnj ubadone(um); 5482674Swnj if (sc->sc_recal) { 5492674Swnj sc->sc_recal = 0; 5502674Swnj um->um_tab.b_active = 0; /* force retry */ 5512674Swnj } 5522674Swnj /* 5532674Swnj * If still ``active'', then don't need any more retries. 5542674Swnj */ 5552674Swnj if (um->um_tab.b_active) { 5562674Swnj /* 5572674Swnj * If we were offset positioning, 5582674Swnj * return to centerline. 5592674Swnj */ 5602674Swnj if (um->um_tab.b_errcnt >= 16) { 5612674Swnj upaddr->upof = UP_FMT22; 5622674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 5632674Swnj while (upaddr->upds & UP_PIP) 5642674Swnj DELAY(25); 565268Sbill needie = 0; 566264Sbill } 5672674Swnj um->um_tab.b_active = 0; 5682674Swnj um->um_tab.b_errcnt = 0; 5692674Swnj um->um_tab.b_actf = dp->b_forw; 5702674Swnj dp->b_active = 0; 5712674Swnj dp->b_errcnt = 0; 5722674Swnj dp->b_actf = bp->av_forw; 5732674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 5742674Swnj iodone(bp); 5752674Swnj /* 5762674Swnj * If this unit has more work to do, 5772674Swnj * then start it up right away. 5782674Swnj */ 5792674Swnj if (dp->b_actf) 5802674Swnj if (upustart(ui)) 581268Sbill needie = 0; 582264Sbill } 5832674Swnj as &= ~(1<<ui->ui_slave); 5842674Swnj doattn: 5852674Swnj /* 5862674Swnj * Process other units which need attention. 5872674Swnj * For each unit which needs attention, call 5882674Swnj * the unit start routine to place the slave 5892674Swnj * on the controller device queue. 5902674Swnj */ 5912607Swnj for (unit = 0; as; as >>= 1, unit++) 5922607Swnj if (as & 1) { 5932470Swnj upaddr->upas = 1<<unit; 5942607Swnj if (upustart(upip[sc21][unit])) 595273Sbill needie = 0; 596273Sbill } 5972674Swnj /* 5982674Swnj * If the controller is not transferring, but 5992674Swnj * there are devices ready to transfer, start 6002674Swnj * the controller. 6012674Swnj */ 6022395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6032395Swnj if (upstart(um)) 604268Sbill needie = 0; 605275Sbill if (needie) 6062629Swnj upaddr->upcs1 = UP_IE; 607264Sbill } 608264Sbill 609264Sbill upread(dev) 6102616Swnj dev_t dev; 611264Sbill { 6122616Swnj register int unit = minor(dev) >> 3; 6132470Swnj 6142616Swnj if (unit >= NUP) 6152616Swnj u.u_error = ENXIO; 6162616Swnj else 6172616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 618264Sbill } 619264Sbill 620264Sbill upwrite(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_WRITE, minphys); 629264Sbill } 630264Sbill 631266Sbill /* 632266Sbill * Correct an ECC error, and restart the i/o to complete 633266Sbill * the transfer if necessary. This is quite complicated because 634266Sbill * the transfer may be going to an odd memory address base and/or 635266Sbill * across a page boundary. 636266Sbill */ 6372395Swnj upecc(ui) 6382395Swnj register struct uba_dinfo *ui; 639264Sbill { 6402629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6412395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6422395Swnj register struct uba_minfo *um = ui->ui_mi; 6432395Swnj register struct upst *st; 6442395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 645266Sbill register int i; 646264Sbill caddr_t addr; 647266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 648264Sbill int bn, cn, tn, sn; 649264Sbill 650264Sbill /* 651266Sbill * Npf is the number of sectors transferred before the sector 652266Sbill * containing the ECC error, and reg is the UBA register 653266Sbill * mapping (the first part of) the transfer. 654266Sbill * O is offset within a memory page of the first byte transferred. 655264Sbill */ 656266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 6572571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 658264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 659264Sbill printf("%D ", bp->b_blkno+npf); 660264Sbill prdev("ECC", bp->b_dev); 661264Sbill mask = up->upec2; 662264Sbill if (mask == 0) { 6632629Swnj up->upof = UP_FMT22; /* == RTC ???? */ 664264Sbill return (0); 665264Sbill } 666266Sbill /* 667266Sbill * Flush the buffered data path, and compute the 668266Sbill * byte and bit position of the error. The variable i 669266Sbill * is the byte offset in the transfer, the variable byte 670266Sbill * is the offset from a page boundary in main memory. 671266Sbill */ 6722571Swnj ubp->uba_dpr[(um->um_ubinfo>>28)&0x0f] |= UBA_BNE; 673266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 674266Sbill bit = i&07; 675266Sbill i = (i&~07)>>3; 676264Sbill byte = i + o; 677266Sbill /* 678266Sbill * Correct while possible bits remain of mask. Since mask 679266Sbill * contains 11 bits, we continue while the bit offset is > -11. 680266Sbill * Also watch out for end of this block and the end of the whole 681266Sbill * transfer. 682266Sbill */ 683266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 684266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 685266Sbill (byte & PGOFSET); 686266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 687266Sbill byte++; 688266Sbill i++; 689266Sbill bit -= 8; 690264Sbill } 6912395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 692264Sbill if (up->upwc == 0) 693264Sbill return (0); 694266Sbill /* 695266Sbill * Have to continue the transfer... clear the drive, 696266Sbill * and compute the position where the transfer is to continue. 697266Sbill * We have completed npf+1 sectors of the transfer already; 698266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 699266Sbill */ 7002629Swnj #ifdef notdef 7012629Swnj up->uper1 = 0; 7022629Swnj up->upcs1 |= UP_GO; 7032629Swnj #else 7042629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 705264Sbill bn = dkblock(bp); 7062395Swnj st = &upst[ui->ui_type]; 707264Sbill cn = bp->b_cylin; 7082395Swnj sn = bn%st->nspc + npf + 1; 7092395Swnj tn = sn/st->nsect; 7102395Swnj sn %= st->nsect; 7112395Swnj cn += tn/st->ntrak; 7122395Swnj tn %= st->ntrak; 713264Sbill up->updc = cn; 714266Sbill up->upda = (tn << 8) | sn; 715266Sbill ubaddr = (int)ptob(reg+1) + o; 716266Sbill up->upba = ubaddr; 717266Sbill cmd = (ubaddr >> 8) & 0x300; 7182629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 719266Sbill up->upcs1 = cmd; 7202629Swnj #endif 721264Sbill return (1); 722264Sbill } 723286Sbill 724286Sbill /* 725286Sbill * Reset driver after UBA init. 726286Sbill * Cancel software state of all pending transfers 727286Sbill * and restart all units and the controller. 728286Sbill */ 7292395Swnj upreset(uban) 730286Sbill { 7312395Swnj register struct uba_minfo *um; 7322395Swnj register struct uba_dinfo *ui; 7332395Swnj register sc21, unit; 7342424Skre int any = 0; 735286Sbill 7362646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7372470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7382470Swnj um->um_alive == 0) 7392395Swnj continue; 7402424Skre if (any == 0) { 7412424Skre printf(" up"); 7422470Swnj DELAY(10000000); /* give it time to self-test */ 7432424Skre any++; 7442424Skre } 7452395Swnj um->um_tab.b_active = 0; 7462395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7472571Swnj if (um->um_ubinfo) { 7482571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7492616Swnj ubadone(um); 7502395Swnj } 7512629Swnj ((struct updevice *)(um->um_addr))->upcs2 = UP_CLR; 7522395Swnj for (unit = 0; unit < NUP; unit++) { 7532395Swnj if ((ui = updinfo[unit]) == 0) 7542395Swnj continue; 7552395Swnj if (ui->ui_alive == 0) 7562395Swnj continue; 7572395Swnj uputab[unit].b_active = 0; 7582395Swnj (void) upustart(ui); 7592395Swnj } 7602395Swnj (void) upstart(um); 761286Sbill } 762286Sbill } 763313Sbill 764313Sbill /* 765313Sbill * Wake up every second and if an interrupt is pending 766313Sbill * but nothing has happened increment a counter. 767313Sbill * If nothing happens for 20 seconds, reset the controller 768313Sbill * and begin anew. 769313Sbill */ 770313Sbill upwatch() 771313Sbill { 7722395Swnj register struct uba_minfo *um; 7732395Swnj register sc21, unit; 7742470Swnj register struct up_softc *sc; 775313Sbill 7761783Sbill timeout(upwatch, (caddr_t)0, HZ); 7772646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7782395Swnj um = upminfo[sc21]; 7792470Swnj if (um == 0 || um->um_alive == 0) 7802470Swnj continue; 7812470Swnj sc = &up_softc[sc21]; 7822395Swnj if (um->um_tab.b_active == 0) { 7832395Swnj for (unit = 0; unit < NUP; unit++) 7842629Swnj if (uputab[unit].b_active && 7852629Swnj updinfo[unit]->ui_mi == um) 7862395Swnj goto active; 7872470Swnj sc->sc_wticks = 0; 7882395Swnj continue; 7892395Swnj } 7902395Swnj active: 7912470Swnj sc->sc_wticks++; 7922470Swnj if (sc->sc_wticks >= 20) { 7932470Swnj sc->sc_wticks = 0; 7942646Swnj printf("LOST upintr "); 7952646Swnj ubareset(um->um_ubanum); 7962395Swnj } 797313Sbill } 798313Sbill } 7992379Swnj 8002379Swnj #define DBSIZE 20 8012379Swnj 8022379Swnj updump(dev) 8032379Swnj dev_t dev; 8042379Swnj { 8052629Swnj struct updevice *upaddr; 8062379Swnj char *start; 8072607Swnj int num, blk, unit; 8082379Swnj struct size *sizes; 8092395Swnj register struct uba_regs *uba; 8102395Swnj register struct uba_dinfo *ui; 8112379Swnj register short *rp; 8122395Swnj struct upst *st; 8132379Swnj 8142395Swnj unit = minor(dev) >> 3; 8152395Swnj if (unit >= NUP) { 8162395Swnj printf("bad unit\n"); 8172395Swnj return (-1); 8182395Swnj } 8192470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8202395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 8212395Swnj if (ui->ui_alive == 0) { 8222395Swnj printf("dna\n"); 8232395Swnj return(-1); 8242395Swnj } 8252395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8262395Swnj #if VAX780 8272470Swnj if (cpu == VAX_780) 8282470Swnj ubainit(uba); 8291809Sbill #endif 8302379Swnj DELAY(1000000); 8312629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8322629Swnj while ((upaddr->upcs1&UP_DVA) == 0) 8332379Swnj ; 8342379Swnj num = maxfree; 8352379Swnj start = 0; 8362379Swnj upaddr->upcs2 = unit; 8372629Swnj if ((upaddr->upds & UP_VV) == 0) { 8382629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 8392629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 8402629Swnj upaddr->upof = UP_FMT22; 8412379Swnj } 8422629Swnj if ((upaddr->upds & (UP_DPR|UP_MOL)) != (UP_DPR|UP_MOL)) { 8432629Swnj printf("dna\n"); 8442379Swnj return (-1); 8452379Swnj } 8462470Swnj st = &upst[ui->ui_type]; 8472395Swnj sizes = phys(struct size *, st->sizes); 8482379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 8492395Swnj printf("oor\n"); 8502379Swnj return (-1); 8512379Swnj } 8522379Swnj while (num > 0) { 8532379Swnj register struct pte *io; 8542379Swnj register int i; 8552379Swnj int cn, sn, tn; 8562379Swnj daddr_t bn; 8572379Swnj 8582379Swnj blk = num > DBSIZE ? DBSIZE : num; 8592395Swnj io = uba->uba_map; 8602379Swnj for (i = 0; i < blk; i++) 8612395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 8622379Swnj *(int *)io = 0; 8632379Swnj bn = dumplo + btop(start); 8642607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 8652607Swnj sn = bn%st->nspc; 8662607Swnj tn = sn/st->nsect; 8672607Swnj sn = sn%st->nsect; 8682379Swnj upaddr->updc = cn; 8692379Swnj rp = (short *) &upaddr->upda; 8702379Swnj *rp = (tn << 8) + sn; 8712379Swnj *--rp = 0; 8722379Swnj *--rp = -blk*NBPG / sizeof (short); 8732629Swnj *--rp = UP_GO|UP_WCOM; 8742379Swnj do { 8752379Swnj DELAY(25); 8762629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 8772629Swnj if (upaddr->upcs1&UP_ERR) { 8782379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 8792379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 8802379Swnj return (-1); 8812379Swnj } 8822379Swnj start += blk*NBPG; 8832379Swnj num -= blk; 8842379Swnj } 8852379Swnj return (0); 8862379Swnj } 8871902Swnj #endif 888