1*6346Swnj /* up.c 4.44 82/03/29 */ 2264Sbill 31937Swnj #include "up.h" 42646Swnj #if NSC > 0 5264Sbill /* 6885Sbill * UNIBUS disk driver with overlapped seeks and ECC recovery. 72889Swnj * 82889Swnj * TODO: 92889Swnj * Add bad sector forwarding code 103445Sroot * Check that offset recovery code works 11264Sbill */ 12264Sbill 13264Sbill #include "../h/param.h" 14264Sbill #include "../h/systm.h" 152395Swnj #include "../h/cpu.h" 162395Swnj #include "../h/nexus.h" 17308Sbill #include "../h/dk.h" 18264Sbill #include "../h/buf.h" 19264Sbill #include "../h/conf.h" 20264Sbill #include "../h/dir.h" 21264Sbill #include "../h/user.h" 22264Sbill #include "../h/map.h" 23420Sbill #include "../h/pte.h" 24264Sbill #include "../h/mtpr.h" 252571Swnj #include "../h/vm.h" 262983Swnj #include "../h/ubavar.h" 272983Swnj #include "../h/ubareg.h" 282379Swnj #include "../h/cmap.h" 29264Sbill 302379Swnj #include "../h/upreg.h" 31264Sbill 322395Swnj struct up_softc { 332395Swnj int sc_softas; 342607Swnj int sc_ndrive; 352395Swnj int sc_wticks; 362674Swnj int sc_recal; 372646Swnj } up_softc[NSC]; 38275Sbill 392395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 40264Sbill struct size 41264Sbill { 42264Sbill daddr_t nblocks; 43264Sbill int cyloff; 44264Sbill } up_sizes[8] = { 45264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 46264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 47341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 48264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 49264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 503730Sroot #ifndef NOBADSECT 513730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 523730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 533730Sroot #else 543730Sroot 81472, 681, 553730Sroot 153824, 562, 563730Sroot #endif 57264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 582395Swnj }, fj_sizes[8] = { 592395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 602395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 612395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 622395Swnj 0, 0, 632395Swnj 0, 0, 642395Swnj 0, 0, 652395Swnj 0, 0, 663730Sroot #ifndef NOBADSECT 673730Sroot 213664, 155, /* H=cyl 155 thru 822 */ 683730Sroot #else 693730Sroot 213760, 155, 703730Sroot #endif 716305Sroot }, am_sizes[8] = { 726305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 736305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 746305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 756305Sroot 0, 0, 766305Sroot 0, 0, 776305Sroot 0, 0, 786305Sroot 181760, 668, /* G=cyl 668 thru 1022 */ 796305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 80264Sbill }; 812395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 82264Sbill 83*6346Swnj /* 84*6346Swnj * On a 780 upSDIST could be 2, but 85*6346Swnj * in the interest of 750's... 86*6346Swnj */ 87*6346Swnj #define _upSDIST 3 /* 1.5 msec */ 882395Swnj #define _upRDIST 4 /* 2.0 msec */ 89264Sbill 902395Swnj int upSDIST = _upSDIST; 912395Swnj int upRDIST = _upRDIST; 922395Swnj 932607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 942983Swnj struct uba_ctlr *upminfo[NSC]; 952983Swnj struct uba_device *updinfo[NUP]; 962983Swnj struct uba_device *upip[NSC][4]; 972395Swnj 982607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 992616Swnj struct uba_driver scdriver = 1002607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 1012395Swnj struct buf uputab[NUP]; 1022395Swnj 1032395Swnj struct upst { 1042395Swnj short nsect; 1052395Swnj short ntrak; 1062395Swnj short nspc; 1072395Swnj short ncyl; 1082395Swnj struct size *sizes; 1092395Swnj } upst[] = { 1102607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 1112607Swnj /* 9300 actually has 815 cylinders... */ 1122395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 113*6346Swnj 32, 16, 32*16, 1024, am_sizes, /* ampex capricorn */ 1142395Swnj }; 1152395Swnj 1162629Swnj u_char up_offset[16] = { 1173445Sroot UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1183445Sroot UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1193445Sroot UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1203445Sroot 0, 0, 0, 0 1212629Swnj }; 122264Sbill 1232616Swnj struct buf rupbuf[NUP]; 124264Sbill 125264Sbill #define b_cylin b_resid 126264Sbill 127264Sbill #ifdef INTRLVE 128264Sbill daddr_t dkblock(); 129264Sbill #endif 1302395Swnj 1312395Swnj int upwstart, upwatch(); /* Have started guardian */ 1322470Swnj int upseek; 1332681Swnj int upwaitdry; 1342395Swnj 1352395Swnj /*ARGSUSED*/ 1362607Swnj upprobe(reg) 1372395Swnj caddr_t reg; 1382395Swnj { 1392459Swnj register int br, cvec; 1402459Swnj 1412607Swnj #ifdef lint 1422607Swnj br = 0; cvec = br; br = cvec; 1432607Swnj #endif 1442629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1452607Swnj DELAY(10); 1462629Swnj ((struct updevice *)reg)->upcs1 = 0; 1472459Swnj return (1); 1482395Swnj } 1492395Swnj 1502607Swnj upslave(ui, reg) 1512983Swnj struct uba_device *ui; 1522395Swnj caddr_t reg; 1532395Swnj { 1542629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1552395Swnj 1562395Swnj upaddr->upcs1 = 0; /* conservative */ 1572607Swnj upaddr->upcs2 = ui->ui_slave; 1583445Sroot if (upaddr->upcs2&UPCS2_NED) { 1592629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1602395Swnj return (0); 1612395Swnj } 1622607Swnj return (1); 1632607Swnj } 1642607Swnj 1652607Swnj upattach(ui) 1662983Swnj register struct uba_device *ui; 1672607Swnj { 1682629Swnj register struct updevice *upaddr; 1692607Swnj 1702395Swnj if (upwstart == 0) { 1712759Swnj timeout(upwatch, (caddr_t)0, hz); 1722395Swnj upwstart++; 1732395Swnj } 1742571Swnj if (ui->ui_dk >= 0) 1752571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1762607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1772607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1782629Swnj upaddr = (struct updevice *)ui->ui_addr; 1792629Swnj upaddr->upcs1 = 0; 1802629Swnj upaddr->upcs2 = ui->ui_slave; 1813496Sroot upaddr->uphr = UPHR_MAXTRAK; 1823553Swnj if (upaddr->uphr == 9) 1833496Sroot ui->ui_type = 1; /* fujitsu hack */ 1846305Sroot else if (upaddr->uphr == 15) 1856305Sroot ui->ui_type = 2; /* ampex hack */ 1863496Sroot upaddr->upcs2 = UPCS2_CLR; 1873496Sroot /* 1883496Sroot upaddr->uphr = UPHR_MAXCYL; 1893496Sroot printf("maxcyl %d\n", upaddr->uphr); 1903496Sroot upaddr->uphr = UPHR_MAXTRAK; 1913496Sroot printf("maxtrak %d\n", upaddr->uphr); 1923496Sroot upaddr->uphr = UPHR_MAXSECT; 1933496Sroot printf("maxsect %d\n", upaddr->uphr); 1943496Sroot */ 1952395Swnj } 196264Sbill 197264Sbill upstrategy(bp) 1982395Swnj register struct buf *bp; 199264Sbill { 2002983Swnj register struct uba_device *ui; 2012395Swnj register struct upst *st; 2022395Swnj register int unit; 2032470Swnj register struct buf *dp; 2042395Swnj int xunit = minor(bp->b_dev) & 07; 2052470Swnj long bn, sz; 206264Sbill 2072470Swnj sz = (bp->b_bcount+511) >> 9; 208264Sbill unit = dkunit(bp); 2092395Swnj if (unit >= NUP) 2102395Swnj goto bad; 2112395Swnj ui = updinfo[unit]; 2122395Swnj if (ui == 0 || ui->ui_alive == 0) 2132395Swnj goto bad; 2142395Swnj st = &upst[ui->ui_type]; 2152395Swnj if (bp->b_blkno < 0 || 2162395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2172395Swnj goto bad; 2182395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2196305Sroot (void) spl5(); 2202470Swnj dp = &uputab[ui->ui_unit]; 2212470Swnj disksort(dp, bp); 2222470Swnj if (dp->b_active == 0) { 2232395Swnj (void) upustart(ui); 2242395Swnj bp = &ui->ui_mi->um_tab; 2252395Swnj if (bp->b_actf && bp->b_active == 0) 2262395Swnj (void) upstart(ui->ui_mi); 227264Sbill } 2286305Sroot (void) spl0(); 2292395Swnj return; 2302395Swnj 2312395Swnj bad: 2322395Swnj bp->b_flags |= B_ERROR; 2332395Swnj iodone(bp); 2342395Swnj return; 235264Sbill } 236264Sbill 2372674Swnj /* 2382674Swnj * Unit start routine. 2392674Swnj * Seek the drive to be where the data is 2402674Swnj * and then generate another interrupt 2412674Swnj * to actually start the transfer. 2422674Swnj * If there is only one drive on the controller, 2432674Swnj * or we are very close to the data, don't 2442674Swnj * bother with the search. If called after 2452674Swnj * searching once, don't bother to look where 2462674Swnj * we are, just queue for transfer (to avoid 2472674Swnj * positioning forever without transferrring.) 2482674Swnj */ 2492395Swnj upustart(ui) 2502983Swnj register struct uba_device *ui; 251264Sbill { 252264Sbill register struct buf *bp, *dp; 2532983Swnj register struct uba_ctlr *um; 2542629Swnj register struct updevice *upaddr; 2552395Swnj register struct upst *st; 256264Sbill daddr_t bn; 2572674Swnj int sn, csn; 2582607Swnj /* 2592607Swnj * The SC21 cancels commands if you just say 2602629Swnj * cs1 = UP_IE 2612607Swnj * so we are cautious about handling of cs1. 2622607Swnj * Also don't bother to clear as bits other than in upintr(). 2632607Swnj */ 2642674Swnj int didie = 0; 2652674Swnj 2662674Swnj if (ui == 0) 2672674Swnj return (0); 2682983Swnj um = ui->ui_mi; 2692395Swnj dk_busy &= ~(1<<ui->ui_dk); 2702395Swnj dp = &uputab[ui->ui_unit]; 271266Sbill if ((bp = dp->b_actf) == NULL) 272268Sbill goto out; 2732674Swnj /* 2742674Swnj * If the controller is active, just remember 2752674Swnj * that this device would like to be positioned... 2762674Swnj * if we tried to position now we would confuse the SC21. 2772674Swnj */ 2782395Swnj if (um->um_tab.b_active) { 2792459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 280275Sbill return (0); 281275Sbill } 2822674Swnj /* 2832674Swnj * If we have already positioned this drive, 2842674Swnj * then just put it on the ready queue. 2852674Swnj */ 286276Sbill if (dp->b_active) 287276Sbill goto done; 288276Sbill dp->b_active = 1; 2892629Swnj upaddr = (struct updevice *)um->um_addr; 2902395Swnj upaddr->upcs2 = ui->ui_slave; 2912674Swnj /* 2922674Swnj * If drive has just come up, 2932674Swnj * setup the pack. 2942674Swnj */ 2953445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 2962607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2972629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2982629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 2993445Sroot upaddr->upof = UPOF_FMT22; 300268Sbill didie = 1; 301264Sbill } 3022674Swnj /* 3032674Swnj * If drive is offline, forget about positioning. 3042674Swnj */ 3053445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 306275Sbill goto done; 3072674Swnj /* 3082674Swnj * If there is only one drive, 3092674Swnj * dont bother searching. 3102674Swnj */ 3112607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3122607Swnj goto done; 3132674Swnj /* 3142674Swnj * Figure out where this transfer is going to 3152674Swnj * and see if we are close enough to justify not searching. 3162674Swnj */ 3172395Swnj st = &upst[ui->ui_type]; 318264Sbill bn = dkblock(bp); 3192395Swnj sn = bn%st->nspc; 3202395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 3212674Swnj if (bp->b_cylin - upaddr->updc) 322266Sbill goto search; /* Not on-cylinder */ 323275Sbill else if (upseek) 324275Sbill goto done; /* Ok just to be on-cylinder */ 325264Sbill csn = (upaddr->upla>>6) - sn - 1; 326266Sbill if (csn < 0) 3272395Swnj csn += st->nsect; 3282395Swnj if (csn > st->nsect - upRDIST) 329264Sbill goto done; 330264Sbill search: 3312674Swnj upaddr->updc = bp->b_cylin; 3322674Swnj /* 3332674Swnj * Not on cylinder at correct position, 3342674Swnj * seek/search. 3352674Swnj */ 336275Sbill if (upseek) 3372629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3382470Swnj else { 339275Sbill upaddr->upda = sn; 3402629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 341275Sbill } 342268Sbill didie = 1; 3432674Swnj /* 3442674Swnj * Mark unit busy for iostat. 3452674Swnj */ 3462395Swnj if (ui->ui_dk >= 0) { 3472395Swnj dk_busy |= 1<<ui->ui_dk; 3482395Swnj dk_seek[ui->ui_dk]++; 349264Sbill } 350268Sbill goto out; 351264Sbill done: 3522674Swnj /* 3532674Swnj * Device is ready to go. 3542674Swnj * Put it on the ready queue for the controller 3552674Swnj * (unless its already there.) 3562674Swnj */ 3572629Swnj if (dp->b_active != 2) { 3582629Swnj dp->b_forw = NULL; 3592629Swnj if (um->um_tab.b_actf == NULL) 3602629Swnj um->um_tab.b_actf = dp; 3612629Swnj else 3622629Swnj um->um_tab.b_actl->b_forw = dp; 3632629Swnj um->um_tab.b_actl = dp; 3642629Swnj dp->b_active = 2; 3652629Swnj } 366268Sbill out: 367268Sbill return (didie); 368264Sbill } 369264Sbill 3702674Swnj /* 3712674Swnj * Start up a transfer on a drive. 3722674Swnj */ 3732395Swnj upstart(um) 3742983Swnj register struct uba_ctlr *um; 375264Sbill { 376264Sbill register struct buf *bp, *dp; 3772983Swnj register struct uba_device *ui; 3782629Swnj register struct updevice *upaddr; 3792470Swnj struct upst *st; 380264Sbill daddr_t bn; 3812681Swnj int dn, sn, tn, cmd, waitdry; 382264Sbill 383264Sbill loop: 3842674Swnj /* 3852674Swnj * Pull a request off the controller queue 3862674Swnj */ 3872395Swnj if ((dp = um->um_tab.b_actf) == NULL) 388268Sbill return (0); 389264Sbill if ((bp = dp->b_actf) == NULL) { 3902395Swnj um->um_tab.b_actf = dp->b_forw; 391264Sbill goto loop; 392264Sbill } 3932674Swnj /* 3942674Swnj * Mark controller busy, and 3952674Swnj * determine destination of this request. 3962674Swnj */ 3972395Swnj um->um_tab.b_active++; 3982395Swnj ui = updinfo[dkunit(bp)]; 399264Sbill bn = dkblock(bp); 4002395Swnj dn = ui->ui_slave; 4012395Swnj st = &upst[ui->ui_type]; 4022395Swnj sn = bn%st->nspc; 4032395Swnj tn = sn/st->nsect; 4042395Swnj sn %= st->nsect; 4052629Swnj upaddr = (struct updevice *)ui->ui_addr; 4062674Swnj /* 4072674Swnj * Select drive if not selected already. 4082674Swnj */ 4092674Swnj if ((upaddr->upcs2&07) != dn) 4102674Swnj upaddr->upcs2 = dn; 4112674Swnj /* 4122674Swnj * Check that it is ready and online 4132674Swnj */ 4142681Swnj waitdry = 0; 4153445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4162681Swnj if (++waitdry > 512) 4172681Swnj break; 4182681Swnj upwaitdry++; 4192681Swnj } 4203445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4212931Swnj printf("up%d: not ready", dkunit(bp)); 4223445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4232607Swnj printf("\n"); 4242395Swnj um->um_tab.b_active = 0; 4252395Swnj um->um_tab.b_errcnt = 0; 426893Sbill dp->b_actf = bp->av_forw; 427893Sbill dp->b_active = 0; 428893Sbill bp->b_flags |= B_ERROR; 429893Sbill iodone(bp); 430893Sbill goto loop; 431893Sbill } 4322674Swnj /* 4332674Swnj * Oh, well, sometimes this 4342674Swnj * happens, for reasons unknown. 4352674Swnj */ 4362629Swnj printf(" (flakey)\n"); 437264Sbill } 4382674Swnj /* 4392674Swnj * Setup for the transfer, and get in the 4402674Swnj * UNIBUS adaptor queue. 4412674Swnj */ 4422424Skre upaddr->updc = bp->b_cylin; 443264Sbill upaddr->upda = (tn << 8) + sn; 444264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 445264Sbill if (bp->b_flags & B_READ) 4462629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 447264Sbill else 4482629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4492571Swnj um->um_cmd = cmd; 4503107Swnj (void) ubago(ui); 451268Sbill return (1); 452264Sbill } 453264Sbill 4542674Swnj /* 4552674Swnj * Now all ready to go, stuff the registers. 4562674Swnj */ 4572571Swnj updgo(um) 4582983Swnj struct uba_ctlr *um; 4592395Swnj { 4602629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4612470Swnj 462*6346Swnj um->um_tab.b_active++; /* should now be 2 */ 4632571Swnj upaddr->upba = um->um_ubinfo; 4642571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4652395Swnj } 4662395Swnj 4672674Swnj /* 4682674Swnj * Handle a disk interrupt. 4692674Swnj */ 4702707Swnj upintr(sc21) 4712395Swnj register sc21; 472264Sbill { 473264Sbill register struct buf *bp, *dp; 4742983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4752983Swnj register struct uba_device *ui; 4762629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 477264Sbill register unit; 4782470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4792607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4802681Swnj int needie = 1, waitdry; 481264Sbill 4822470Swnj sc->sc_wticks = 0; 4832607Swnj sc->sc_softas = 0; 4842674Swnj /* 4852674Swnj * If controller wasn't transferring, then this is an 4862674Swnj * interrupt for attention status on seeking drives. 4872674Swnj * Just service them. 4882674Swnj */ 489*6346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 4902674Swnj if (upaddr->upcs1 & UP_TRE) 4912674Swnj upaddr->upcs1 = UP_TRE; 4922674Swnj goto doattn; 4932674Swnj } 4942674Swnj /* 4952674Swnj * Get device and block structures, and a pointer 4962983Swnj * to the uba_device for the drive. Select the drive. 4972674Swnj */ 4982674Swnj dp = um->um_tab.b_actf; 4992674Swnj bp = dp->b_actf; 5002674Swnj ui = updinfo[dkunit(bp)]; 5012674Swnj dk_busy &= ~(1 << ui->ui_dk); 5022674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5032395Swnj upaddr->upcs2 = ui->ui_slave; 5042674Swnj /* 5052674Swnj * Check for and process errors on 5062674Swnj * either the drive or the controller. 5072674Swnj */ 5083445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5092681Swnj waitdry = 0; 5103445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5112681Swnj if (++waitdry > 512) 5122681Swnj break; 5132681Swnj upwaitdry++; 5142681Swnj } 5153445Sroot if (upaddr->uper1&UPER1_WLE) { 5162674Swnj /* 5172674Swnj * Give up on write locked devices 5182674Swnj * immediately. 5192674Swnj */ 5202931Swnj printf("up%d: write locked\n", dkunit(bp)); 5212674Swnj bp->b_flags |= B_ERROR; 5222674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5232674Swnj /* 5242674Swnj * After 28 retries (16 without offset, and 5252674Swnj * 12 with offset positioning) give up. 5262674Swnj */ 5272931Swnj harderr(bp, "up"); 5282931Swnj printf("cs2=%b er1=%b er2=%b\n", 5292785Swnj upaddr->upcs2, UPCS2_BITS, 5302785Swnj upaddr->uper1, UPER1_BITS, 5312785Swnj upaddr->uper2, UPER2_BITS); 5322674Swnj bp->b_flags |= B_ERROR; 5332674Swnj } else { 5342674Swnj /* 5352674Swnj * Retriable error. 5362674Swnj * If a soft ecc, correct it (continuing 5372674Swnj * by returning if necessary. 5382674Swnj * Otherwise fall through and retry the transfer 5392674Swnj */ 5402674Swnj um->um_tab.b_active = 0; /* force retry */ 5413445Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) 5422629Swnj if (upecc(ui)) 5432629Swnj return; 5442674Swnj } 5452674Swnj /* 5462674Swnj * Clear drive error and, every eight attempts, 5472674Swnj * (starting with the fourth) 5482674Swnj * recalibrate to clear the slate. 5492674Swnj */ 5502674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5512674Swnj needie = 0; 5523182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5532674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5543160Swnj sc->sc_recal = 0; 5553160Swnj goto nextrecal; 5562674Swnj } 5572674Swnj } 5582674Swnj /* 5593160Swnj * Advance recalibration finite state machine 5603160Swnj * if recalibrate in progress, through 5613160Swnj * RECAL 5623160Swnj * SEEK 5633160Swnj * OFFSET (optional) 5643160Swnj * RETRY 5652674Swnj */ 5663160Swnj switch (sc->sc_recal) { 5673160Swnj 5683160Swnj case 1: 5693160Swnj upaddr->updc = bp->b_cylin; 5703160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 5713160Swnj goto nextrecal; 5723160Swnj case 2: 5733160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 5743160Swnj goto donerecal; 5753445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 5763160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 5773160Swnj goto nextrecal; 5783160Swnj nextrecal: 5793160Swnj sc->sc_recal++; 5803160Swnj um->um_tab.b_active = 1; 5813160Swnj return; 5823160Swnj donerecal: 5833160Swnj case 3: 5842674Swnj sc->sc_recal = 0; 5853160Swnj um->um_tab.b_active = 0; 5863160Swnj break; 5872674Swnj } 5882674Swnj /* 5892674Swnj * If still ``active'', then don't need any more retries. 5902674Swnj */ 5912674Swnj if (um->um_tab.b_active) { 5922674Swnj /* 5932674Swnj * If we were offset positioning, 5942674Swnj * return to centerline. 5952674Swnj */ 5962674Swnj if (um->um_tab.b_errcnt >= 16) { 5973445Sroot upaddr->upof = UPOF_FMT22; 5982674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 5993445Sroot while (upaddr->upds & UPDS_PIP) 6002674Swnj DELAY(25); 601268Sbill needie = 0; 602264Sbill } 6032674Swnj um->um_tab.b_active = 0; 6042674Swnj um->um_tab.b_errcnt = 0; 6052674Swnj um->um_tab.b_actf = dp->b_forw; 6062674Swnj dp->b_active = 0; 6072674Swnj dp->b_errcnt = 0; 6082674Swnj dp->b_actf = bp->av_forw; 6092674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6102674Swnj iodone(bp); 6112674Swnj /* 6122674Swnj * If this unit has more work to do, 6132674Swnj * then start it up right away. 6142674Swnj */ 6152674Swnj if (dp->b_actf) 6162674Swnj if (upustart(ui)) 617268Sbill needie = 0; 618264Sbill } 6192674Swnj as &= ~(1<<ui->ui_slave); 6203403Swnj /* 6213403Swnj * Release unibus resources and flush data paths. 6223403Swnj */ 6233403Swnj ubadone(um); 6242674Swnj doattn: 6252674Swnj /* 6262674Swnj * Process other units which need attention. 6272674Swnj * For each unit which needs attention, call 6282674Swnj * the unit start routine to place the slave 6292674Swnj * on the controller device queue. 6302674Swnj */ 6313160Swnj while (unit = ffs(as)) { 6323160Swnj unit--; /* was 1 origin */ 6333160Swnj as &= ~(1<<unit); 6343160Swnj upaddr->upas = 1<<unit; 6353160Swnj if (upustart(upip[sc21][unit])) 6363160Swnj needie = 0; 6373160Swnj } 6382674Swnj /* 6392674Swnj * If the controller is not transferring, but 6402674Swnj * there are devices ready to transfer, start 6412674Swnj * the controller. 6422674Swnj */ 6432395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6442395Swnj if (upstart(um)) 645268Sbill needie = 0; 646275Sbill if (needie) 6472629Swnj upaddr->upcs1 = UP_IE; 648264Sbill } 649264Sbill 650264Sbill upread(dev) 6512616Swnj dev_t dev; 652264Sbill { 6532616Swnj register int unit = minor(dev) >> 3; 6542470Swnj 6552616Swnj if (unit >= NUP) 6562616Swnj u.u_error = ENXIO; 6572616Swnj else 6582616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 659264Sbill } 660264Sbill 661264Sbill upwrite(dev) 6622616Swnj dev_t dev; 663264Sbill { 6642616Swnj register int unit = minor(dev) >> 3; 6652470Swnj 6662616Swnj if (unit >= NUP) 6672616Swnj u.u_error = ENXIO; 6682616Swnj else 6692616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 670264Sbill } 671264Sbill 672266Sbill /* 673266Sbill * Correct an ECC error, and restart the i/o to complete 674266Sbill * the transfer if necessary. This is quite complicated because 675266Sbill * the transfer may be going to an odd memory address base and/or 676266Sbill * across a page boundary. 677266Sbill */ 6782395Swnj upecc(ui) 6792983Swnj register struct uba_device *ui; 680264Sbill { 6812629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6822395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6832983Swnj register struct uba_ctlr *um = ui->ui_mi; 6842395Swnj register struct upst *st; 6852395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 686266Sbill register int i; 687264Sbill caddr_t addr; 688266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 689264Sbill int bn, cn, tn, sn; 690264Sbill 691264Sbill /* 692266Sbill * Npf is the number of sectors transferred before the sector 693266Sbill * containing the ECC error, and reg is the UBA register 694266Sbill * mapping (the first part of) the transfer. 695266Sbill * O is offset within a memory page of the first byte transferred. 696264Sbill */ 697266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 6982571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 699264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 7002983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 7012889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 702264Sbill mask = up->upec2; 7033445Sroot #ifdef UPECCDEBUG 7043403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7053403Swnj up->upec1); 7063445Sroot #endif 707266Sbill /* 708266Sbill * Flush the buffered data path, and compute the 709266Sbill * byte and bit position of the error. The variable i 710266Sbill * is the byte offset in the transfer, the variable byte 711266Sbill * is the offset from a page boundary in main memory. 712266Sbill */ 7132725Swnj ubapurge(um); 714266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 715266Sbill bit = i&07; 716266Sbill i = (i&~07)>>3; 717264Sbill byte = i + o; 718266Sbill /* 719266Sbill * Correct while possible bits remain of mask. Since mask 720266Sbill * contains 11 bits, we continue while the bit offset is > -11. 721266Sbill * Also watch out for end of this block and the end of the whole 722266Sbill * transfer. 723266Sbill */ 724266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 725266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 726266Sbill (byte & PGOFSET); 7273445Sroot #ifdef UPECCDEBUG 7283403Swnj printf("addr %x map reg %x\n", 7293403Swnj addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 7303403Swnj printf("old: %x, ", getmemc(addr)); 7313445Sroot #endif 732266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 7333445Sroot #ifdef UPECCDEBUG 7343403Swnj printf("new: %x\n", getmemc(addr)); 7353445Sroot #endif 736266Sbill byte++; 737266Sbill i++; 738266Sbill bit -= 8; 739264Sbill } 740*6346Swnj um->um_tab.b_active = 2; /* Either complete or continuing... */ 741264Sbill if (up->upwc == 0) 742264Sbill return (0); 743266Sbill /* 744266Sbill * Have to continue the transfer... clear the drive, 745266Sbill * and compute the position where the transfer is to continue. 746266Sbill * We have completed npf+1 sectors of the transfer already; 747266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 748266Sbill */ 7492629Swnj #ifdef notdef 7502629Swnj up->uper1 = 0; 7512629Swnj up->upcs1 |= UP_GO; 7522629Swnj #else 7532629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 754264Sbill bn = dkblock(bp); 7552395Swnj st = &upst[ui->ui_type]; 756264Sbill cn = bp->b_cylin; 7572395Swnj sn = bn%st->nspc + npf + 1; 7582395Swnj tn = sn/st->nsect; 7592395Swnj sn %= st->nsect; 7602395Swnj cn += tn/st->ntrak; 7612395Swnj tn %= st->ntrak; 762264Sbill up->updc = cn; 763266Sbill up->upda = (tn << 8) | sn; 764266Sbill ubaddr = (int)ptob(reg+1) + o; 765266Sbill up->upba = ubaddr; 766266Sbill cmd = (ubaddr >> 8) & 0x300; 7672629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 768266Sbill up->upcs1 = cmd; 7692629Swnj #endif 770264Sbill return (1); 771264Sbill } 772286Sbill 773286Sbill /* 774286Sbill * Reset driver after UBA init. 775286Sbill * Cancel software state of all pending transfers 776286Sbill * and restart all units and the controller. 777286Sbill */ 7782395Swnj upreset(uban) 7792931Swnj int uban; 780286Sbill { 7812983Swnj register struct uba_ctlr *um; 7822983Swnj register struct uba_device *ui; 7832395Swnj register sc21, unit; 784286Sbill 7852646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7862470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7872470Swnj um->um_alive == 0) 7882395Swnj continue; 7892931Swnj printf(" sc%d", sc21); 7902395Swnj um->um_tab.b_active = 0; 7912395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7922931Swnj up_softc[sc21].sc_recal = 0; 793*6346Swnj up_softc[sc21].sc_wticks = 0; 7942571Swnj if (um->um_ubinfo) { 7952571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7962616Swnj ubadone(um); 7972395Swnj } 7983445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 7992395Swnj for (unit = 0; unit < NUP; unit++) { 8002395Swnj if ((ui = updinfo[unit]) == 0) 8012395Swnj continue; 8022931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 8032395Swnj continue; 8042395Swnj uputab[unit].b_active = 0; 8052395Swnj (void) upustart(ui); 8062395Swnj } 8072395Swnj (void) upstart(um); 808286Sbill } 809286Sbill } 810313Sbill 811313Sbill /* 812313Sbill * Wake up every second and if an interrupt is pending 813313Sbill * but nothing has happened increment a counter. 8142931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 815313Sbill * and begin anew. 816313Sbill */ 817313Sbill upwatch() 818313Sbill { 8192983Swnj register struct uba_ctlr *um; 8202395Swnj register sc21, unit; 8212470Swnj register struct up_softc *sc; 822313Sbill 8232759Swnj timeout(upwatch, (caddr_t)0, hz); 8242646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 8252395Swnj um = upminfo[sc21]; 8262470Swnj if (um == 0 || um->um_alive == 0) 8272470Swnj continue; 8282470Swnj sc = &up_softc[sc21]; 8292395Swnj if (um->um_tab.b_active == 0) { 8302395Swnj for (unit = 0; unit < NUP; unit++) 8312629Swnj if (uputab[unit].b_active && 8322629Swnj updinfo[unit]->ui_mi == um) 8332395Swnj goto active; 8342470Swnj sc->sc_wticks = 0; 8352395Swnj continue; 8362395Swnj } 8372931Swnj active: 8382470Swnj sc->sc_wticks++; 8392470Swnj if (sc->sc_wticks >= 20) { 8402470Swnj sc->sc_wticks = 0; 8412931Swnj printf("sc%d: lost interrupt\n", sc21); 8422646Swnj ubareset(um->um_ubanum); 8432395Swnj } 844313Sbill } 845313Sbill } 8462379Swnj 8472379Swnj #define DBSIZE 20 8482379Swnj 8492379Swnj updump(dev) 8502379Swnj dev_t dev; 8512379Swnj { 8522629Swnj struct updevice *upaddr; 8532379Swnj char *start; 8543107Swnj int num, blk, unit; 8552379Swnj struct size *sizes; 8562395Swnj register struct uba_regs *uba; 8572983Swnj register struct uba_device *ui; 8582379Swnj register short *rp; 8592395Swnj struct upst *st; 8602379Swnj 8612395Swnj unit = minor(dev) >> 3; 8622889Swnj if (unit >= NUP) 8632889Swnj return (ENXIO); 8642470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8652983Swnj ui = phys(struct uba_device *, updinfo[unit]); 8662889Swnj if (ui->ui_alive == 0) 8672889Swnj return (ENXIO); 8682395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8692983Swnj ubainit(uba); 8702629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8712983Swnj DELAY(2000000); 8722379Swnj num = maxfree; 8732379Swnj start = 0; 8742379Swnj upaddr->upcs2 = unit; 8752983Swnj DELAY(100); 8762983Swnj if ((upaddr->upcs1&UP_DVA) == 0) 8772983Swnj return (EFAULT); 8783445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 8792629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 8802629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 8813445Sroot upaddr->upof = UPOF_FMT22; 8822379Swnj } 8833445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 8842889Swnj return (EFAULT); 8852470Swnj st = &upst[ui->ui_type]; 8862395Swnj sizes = phys(struct size *, st->sizes); 8872889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 8882889Swnj return (EINVAL); 8892379Swnj while (num > 0) { 8902379Swnj register struct pte *io; 8912379Swnj register int i; 8922379Swnj int cn, sn, tn; 8932379Swnj daddr_t bn; 8942379Swnj 8952379Swnj blk = num > DBSIZE ? DBSIZE : num; 8962395Swnj io = uba->uba_map; 8972379Swnj for (i = 0; i < blk; i++) 8982983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 8992379Swnj *(int *)io = 0; 9002379Swnj bn = dumplo + btop(start); 9012607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 9022607Swnj sn = bn%st->nspc; 9032607Swnj tn = sn/st->nsect; 9042607Swnj sn = sn%st->nsect; 9052379Swnj upaddr->updc = cn; 9062379Swnj rp = (short *) &upaddr->upda; 9072379Swnj *rp = (tn << 8) + sn; 9082379Swnj *--rp = 0; 9092379Swnj *--rp = -blk*NBPG / sizeof (short); 9102629Swnj *--rp = UP_GO|UP_WCOM; 9112379Swnj do { 9122379Swnj DELAY(25); 9132629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 9143445Sroot if (upaddr->upds&UPDS_ERR) 9152889Swnj return (EIO); 9162379Swnj start += blk*NBPG; 9172379Swnj num -= blk; 9182379Swnj } 9192379Swnj return (0); 9202379Swnj } 9211902Swnj #endif 922