1*6305Sroot #define UPECCDEBUG 2*6305Sroot /* up.c 4.39 81/05/11 */ 3264Sbill 41937Swnj #include "up.h" 52646Swnj #if NSC > 0 6264Sbill /* 7885Sbill * UNIBUS disk driver with overlapped seeks and ECC recovery. 82889Swnj * 92889Swnj * TODO: 102889Swnj * Add bad sector forwarding code 113445Sroot * Check that offset recovery code works 12264Sbill */ 13264Sbill 14264Sbill #include "../h/param.h" 15264Sbill #include "../h/systm.h" 162395Swnj #include "../h/cpu.h" 172395Swnj #include "../h/nexus.h" 18308Sbill #include "../h/dk.h" 19264Sbill #include "../h/buf.h" 20264Sbill #include "../h/conf.h" 21264Sbill #include "../h/dir.h" 22264Sbill #include "../h/user.h" 23264Sbill #include "../h/map.h" 24420Sbill #include "../h/pte.h" 25264Sbill #include "../h/mtpr.h" 262571Swnj #include "../h/vm.h" 272983Swnj #include "../h/ubavar.h" 282983Swnj #include "../h/ubareg.h" 292379Swnj #include "../h/cmap.h" 30264Sbill 312379Swnj #include "../h/upreg.h" 32264Sbill 332395Swnj struct up_softc { 342395Swnj int sc_softas; 352607Swnj int sc_ndrive; 362395Swnj int sc_wticks; 372674Swnj int sc_recal; 382646Swnj } up_softc[NSC]; 39275Sbill 402395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 41264Sbill struct size 42264Sbill { 43264Sbill daddr_t nblocks; 44264Sbill int cyloff; 45264Sbill } up_sizes[8] = { 46264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 47264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 48341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 49264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 50264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 513730Sroot #ifndef NOBADSECT 523730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 533730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 543730Sroot #else 553730Sroot 81472, 681, 563730Sroot 153824, 562, 573730Sroot #endif 58264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 592395Swnj }, fj_sizes[8] = { 602395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 612395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 622395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 632395Swnj 0, 0, 642395Swnj 0, 0, 652395Swnj 0, 0, 662395Swnj 0, 0, 673730Sroot #ifndef NOBADSECT 683730Sroot 213664, 155, /* H=cyl 155 thru 822 */ 693730Sroot #else 703730Sroot 213760, 155, 713730Sroot #endif 72*6305Sroot }, am_sizes[8] = { 73*6305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 74*6305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 75*6305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 76*6305Sroot 0, 0, 77*6305Sroot 0, 0, 78*6305Sroot 0, 0, 79*6305Sroot 181760, 668, /* G=cyl 668 thru 1022 */ 80*6305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 81264Sbill }; 822395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 83264Sbill 842395Swnj #define _upSDIST 2 /* 1.0 msec */ 852395Swnj #define _upRDIST 4 /* 2.0 msec */ 86264Sbill 872395Swnj int upSDIST = _upSDIST; 882395Swnj int upRDIST = _upRDIST; 892395Swnj 902607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 912983Swnj struct uba_ctlr *upminfo[NSC]; 922983Swnj struct uba_device *updinfo[NUP]; 932983Swnj struct uba_device *upip[NSC][4]; 942395Swnj 952607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 962616Swnj struct uba_driver scdriver = 972607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 982395Swnj struct buf uputab[NUP]; 992395Swnj 1002395Swnj struct upst { 1012395Swnj short nsect; 1022395Swnj short ntrak; 1032395Swnj short nspc; 1042395Swnj short ncyl; 1052395Swnj struct size *sizes; 1062395Swnj } upst[] = { 1072607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 1082607Swnj /* 9300 actually has 815 cylinders... */ 1092395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 110*6305Sroot 32, 16, 32*16, 1024, am_sizes, /* fujitsu 160m */ 1112395Swnj }; 1122395Swnj 1132629Swnj u_char up_offset[16] = { 1143445Sroot UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1153445Sroot UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1163445Sroot UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1173445Sroot 0, 0, 0, 0 1182629Swnj }; 119264Sbill 1202616Swnj struct buf rupbuf[NUP]; 121264Sbill 122264Sbill #define b_cylin b_resid 123264Sbill 124264Sbill #ifdef INTRLVE 125264Sbill daddr_t dkblock(); 126264Sbill #endif 1272395Swnj 1282395Swnj int upwstart, upwatch(); /* Have started guardian */ 1292470Swnj int upseek; 1302681Swnj int upwaitdry; 1312395Swnj 1322395Swnj /*ARGSUSED*/ 1332607Swnj upprobe(reg) 1342395Swnj caddr_t reg; 1352395Swnj { 1362459Swnj register int br, cvec; 1372459Swnj 1382607Swnj #ifdef lint 1392607Swnj br = 0; cvec = br; br = cvec; 1402607Swnj #endif 1412629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1422607Swnj DELAY(10); 1432629Swnj ((struct updevice *)reg)->upcs1 = 0; 1442459Swnj return (1); 1452395Swnj } 1462395Swnj 1472607Swnj upslave(ui, reg) 1482983Swnj struct uba_device *ui; 1492395Swnj caddr_t reg; 1502395Swnj { 1512629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1522395Swnj 1532395Swnj upaddr->upcs1 = 0; /* conservative */ 1542607Swnj upaddr->upcs2 = ui->ui_slave; 1553445Sroot if (upaddr->upcs2&UPCS2_NED) { 1562629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1572395Swnj return (0); 1582395Swnj } 1592607Swnj return (1); 1602607Swnj } 1612607Swnj 1622607Swnj upattach(ui) 1632983Swnj register struct uba_device *ui; 1642607Swnj { 1652629Swnj register struct updevice *upaddr; 1662607Swnj 1672395Swnj if (upwstart == 0) { 1682759Swnj timeout(upwatch, (caddr_t)0, hz); 1692395Swnj upwstart++; 1702395Swnj } 1712571Swnj if (ui->ui_dk >= 0) 1722571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1732607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1742607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1752629Swnj upaddr = (struct updevice *)ui->ui_addr; 1762629Swnj upaddr->upcs1 = 0; 1772629Swnj upaddr->upcs2 = ui->ui_slave; 1783496Sroot upaddr->uphr = UPHR_MAXTRAK; 1793553Swnj if (upaddr->uphr == 9) 1803496Sroot ui->ui_type = 1; /* fujitsu hack */ 181*6305Sroot else if (upaddr->uphr == 15) 182*6305Sroot ui->ui_type = 2; /* ampex hack */ 1833496Sroot upaddr->upcs2 = UPCS2_CLR; 1843496Sroot /* 1853496Sroot upaddr->uphr = UPHR_MAXCYL; 1863496Sroot printf("maxcyl %d\n", upaddr->uphr); 1873496Sroot upaddr->uphr = UPHR_MAXTRAK; 1883496Sroot printf("maxtrak %d\n", upaddr->uphr); 1893496Sroot upaddr->uphr = UPHR_MAXSECT; 1903496Sroot printf("maxsect %d\n", upaddr->uphr); 1913496Sroot */ 1922395Swnj } 193264Sbill 194264Sbill upstrategy(bp) 1952395Swnj register struct buf *bp; 196264Sbill { 1972983Swnj register struct uba_device *ui; 1982395Swnj register struct upst *st; 1992395Swnj register int unit; 2002470Swnj register struct buf *dp; 2012395Swnj int xunit = minor(bp->b_dev) & 07; 2022470Swnj long bn, sz; 203264Sbill 2042470Swnj sz = (bp->b_bcount+511) >> 9; 205264Sbill unit = dkunit(bp); 2062395Swnj if (unit >= NUP) 2072395Swnj goto bad; 2082395Swnj ui = updinfo[unit]; 2092395Swnj if (ui == 0 || ui->ui_alive == 0) 2102395Swnj goto bad; 2112395Swnj st = &upst[ui->ui_type]; 2122395Swnj if (bp->b_blkno < 0 || 2132395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2142395Swnj goto bad; 2152395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 216*6305Sroot (void) spl5(); 2172470Swnj dp = &uputab[ui->ui_unit]; 2182470Swnj disksort(dp, bp); 2192470Swnj if (dp->b_active == 0) { 2202395Swnj (void) upustart(ui); 2212395Swnj bp = &ui->ui_mi->um_tab; 2222395Swnj if (bp->b_actf && bp->b_active == 0) 2232395Swnj (void) upstart(ui->ui_mi); 224264Sbill } 225*6305Sroot (void) spl0(); 2262395Swnj return; 2272395Swnj 2282395Swnj bad: 2292395Swnj bp->b_flags |= B_ERROR; 2302395Swnj iodone(bp); 2312395Swnj return; 232264Sbill } 233264Sbill 2342674Swnj /* 2352674Swnj * Unit start routine. 2362674Swnj * Seek the drive to be where the data is 2372674Swnj * and then generate another interrupt 2382674Swnj * to actually start the transfer. 2392674Swnj * If there is only one drive on the controller, 2402674Swnj * or we are very close to the data, don't 2412674Swnj * bother with the search. If called after 2422674Swnj * searching once, don't bother to look where 2432674Swnj * we are, just queue for transfer (to avoid 2442674Swnj * positioning forever without transferrring.) 2452674Swnj */ 2462395Swnj upustart(ui) 2472983Swnj register struct uba_device *ui; 248264Sbill { 249264Sbill register struct buf *bp, *dp; 2502983Swnj register struct uba_ctlr *um; 2512629Swnj register struct updevice *upaddr; 2522395Swnj register struct upst *st; 253264Sbill daddr_t bn; 2542674Swnj int sn, csn; 2552607Swnj /* 2562607Swnj * The SC21 cancels commands if you just say 2572629Swnj * cs1 = UP_IE 2582607Swnj * so we are cautious about handling of cs1. 2592607Swnj * Also don't bother to clear as bits other than in upintr(). 2602607Swnj */ 2612674Swnj int didie = 0; 2622674Swnj 2632674Swnj if (ui == 0) 2642674Swnj return (0); 2652983Swnj um = ui->ui_mi; 2662395Swnj dk_busy &= ~(1<<ui->ui_dk); 2672395Swnj dp = &uputab[ui->ui_unit]; 268266Sbill if ((bp = dp->b_actf) == NULL) 269268Sbill goto out; 2702674Swnj /* 2712674Swnj * If the controller is active, just remember 2722674Swnj * that this device would like to be positioned... 2732674Swnj * if we tried to position now we would confuse the SC21. 2742674Swnj */ 2752395Swnj if (um->um_tab.b_active) { 2762459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 277275Sbill return (0); 278275Sbill } 2792674Swnj /* 2802674Swnj * If we have already positioned this drive, 2812674Swnj * then just put it on the ready queue. 2822674Swnj */ 283276Sbill if (dp->b_active) 284276Sbill goto done; 285276Sbill dp->b_active = 1; 2862629Swnj upaddr = (struct updevice *)um->um_addr; 2872395Swnj upaddr->upcs2 = ui->ui_slave; 2882674Swnj /* 2892674Swnj * If drive has just come up, 2902674Swnj * setup the pack. 2912674Swnj */ 2923445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 2932607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 2942629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 2952629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 2963445Sroot upaddr->upof = UPOF_FMT22; 297268Sbill didie = 1; 298264Sbill } 2992674Swnj /* 3002674Swnj * If drive is offline, forget about positioning. 3012674Swnj */ 3023445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 303275Sbill goto done; 3042674Swnj /* 3052674Swnj * If there is only one drive, 3062674Swnj * dont bother searching. 3072674Swnj */ 3082607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3092607Swnj goto done; 3102674Swnj /* 3112674Swnj * Figure out where this transfer is going to 3122674Swnj * and see if we are close enough to justify not searching. 3132674Swnj */ 3142395Swnj st = &upst[ui->ui_type]; 315264Sbill bn = dkblock(bp); 3162395Swnj sn = bn%st->nspc; 3172395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 3182674Swnj if (bp->b_cylin - upaddr->updc) 319266Sbill goto search; /* Not on-cylinder */ 320275Sbill else if (upseek) 321275Sbill goto done; /* Ok just to be on-cylinder */ 322264Sbill csn = (upaddr->upla>>6) - sn - 1; 323266Sbill if (csn < 0) 3242395Swnj csn += st->nsect; 3252395Swnj if (csn > st->nsect - upRDIST) 326264Sbill goto done; 327264Sbill search: 3282674Swnj upaddr->updc = bp->b_cylin; 3292674Swnj /* 3302674Swnj * Not on cylinder at correct position, 3312674Swnj * seek/search. 3322674Swnj */ 333275Sbill if (upseek) 3342629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3352470Swnj else { 336275Sbill upaddr->upda = sn; 3372629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 338275Sbill } 339268Sbill didie = 1; 3402674Swnj /* 3412674Swnj * Mark unit busy for iostat. 3422674Swnj */ 3432395Swnj if (ui->ui_dk >= 0) { 3442395Swnj dk_busy |= 1<<ui->ui_dk; 3452395Swnj dk_seek[ui->ui_dk]++; 346264Sbill } 347268Sbill goto out; 348264Sbill done: 3492674Swnj /* 3502674Swnj * Device is ready to go. 3512674Swnj * Put it on the ready queue for the controller 3522674Swnj * (unless its already there.) 3532674Swnj */ 3542629Swnj if (dp->b_active != 2) { 3552629Swnj dp->b_forw = NULL; 3562629Swnj if (um->um_tab.b_actf == NULL) 3572629Swnj um->um_tab.b_actf = dp; 3582629Swnj else 3592629Swnj um->um_tab.b_actl->b_forw = dp; 3602629Swnj um->um_tab.b_actl = dp; 3612629Swnj dp->b_active = 2; 3622629Swnj } 363268Sbill out: 364268Sbill return (didie); 365264Sbill } 366264Sbill 3672674Swnj /* 3682674Swnj * Start up a transfer on a drive. 3692674Swnj */ 3702395Swnj upstart(um) 3712983Swnj register struct uba_ctlr *um; 372264Sbill { 373264Sbill register struct buf *bp, *dp; 3742983Swnj register struct uba_device *ui; 3752629Swnj register struct updevice *upaddr; 3762470Swnj struct upst *st; 377264Sbill daddr_t bn; 3782681Swnj int dn, sn, tn, cmd, waitdry; 379264Sbill 380264Sbill loop: 3812674Swnj /* 3822674Swnj * Pull a request off the controller queue 3832674Swnj */ 3842395Swnj if ((dp = um->um_tab.b_actf) == NULL) 385268Sbill return (0); 386264Sbill if ((bp = dp->b_actf) == NULL) { 3872395Swnj um->um_tab.b_actf = dp->b_forw; 388264Sbill goto loop; 389264Sbill } 3902674Swnj /* 3912674Swnj * Mark controller busy, and 3922674Swnj * determine destination of this request. 3932674Swnj */ 3942395Swnj um->um_tab.b_active++; 3952395Swnj ui = updinfo[dkunit(bp)]; 396264Sbill bn = dkblock(bp); 3972395Swnj dn = ui->ui_slave; 3982395Swnj st = &upst[ui->ui_type]; 3992395Swnj sn = bn%st->nspc; 4002395Swnj tn = sn/st->nsect; 4012395Swnj sn %= st->nsect; 4022629Swnj upaddr = (struct updevice *)ui->ui_addr; 4032674Swnj /* 4042674Swnj * Select drive if not selected already. 4052674Swnj */ 4062674Swnj if ((upaddr->upcs2&07) != dn) 4072674Swnj upaddr->upcs2 = dn; 4082674Swnj /* 4092674Swnj * Check that it is ready and online 4102674Swnj */ 4112681Swnj waitdry = 0; 4123445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4132681Swnj if (++waitdry > 512) 4142681Swnj break; 4152681Swnj upwaitdry++; 4162681Swnj } 4173445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4182931Swnj printf("up%d: not ready", dkunit(bp)); 4193445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4202607Swnj printf("\n"); 4212395Swnj um->um_tab.b_active = 0; 4222395Swnj um->um_tab.b_errcnt = 0; 423893Sbill dp->b_actf = bp->av_forw; 424893Sbill dp->b_active = 0; 425893Sbill bp->b_flags |= B_ERROR; 426893Sbill iodone(bp); 427893Sbill goto loop; 428893Sbill } 4292674Swnj /* 4302674Swnj * Oh, well, sometimes this 4312674Swnj * happens, for reasons unknown. 4322674Swnj */ 4332629Swnj printf(" (flakey)\n"); 434264Sbill } 4352674Swnj /* 4362674Swnj * Setup for the transfer, and get in the 4372674Swnj * UNIBUS adaptor queue. 4382674Swnj */ 4392424Skre upaddr->updc = bp->b_cylin; 440264Sbill upaddr->upda = (tn << 8) + sn; 441264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 442264Sbill if (bp->b_flags & B_READ) 4432629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 444264Sbill else 4452629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4462571Swnj um->um_cmd = cmd; 4473107Swnj (void) ubago(ui); 448268Sbill return (1); 449264Sbill } 450264Sbill 4512674Swnj /* 4522674Swnj * Now all ready to go, stuff the registers. 4532674Swnj */ 4542571Swnj updgo(um) 4552983Swnj struct uba_ctlr *um; 4562395Swnj { 4572629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4582470Swnj 4592571Swnj upaddr->upba = um->um_ubinfo; 4602571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4612395Swnj } 4622395Swnj 4632674Swnj /* 4642674Swnj * Handle a disk interrupt. 4652674Swnj */ 4662707Swnj upintr(sc21) 4672395Swnj register sc21; 468264Sbill { 469264Sbill register struct buf *bp, *dp; 4702983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4712983Swnj register struct uba_device *ui; 4722629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 473264Sbill register unit; 4742470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4752607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4762681Swnj int needie = 1, waitdry; 477264Sbill 4782470Swnj sc->sc_wticks = 0; 4792607Swnj sc->sc_softas = 0; 4802674Swnj /* 4812674Swnj * If controller wasn't transferring, then this is an 4822674Swnj * interrupt for attention status on seeking drives. 4832674Swnj * Just service them. 4842674Swnj */ 4852674Swnj if (um->um_tab.b_active == 0) { 4862674Swnj if (upaddr->upcs1 & UP_TRE) 4872674Swnj upaddr->upcs1 = UP_TRE; 4882674Swnj goto doattn; 4892674Swnj } 4902674Swnj /* 4912674Swnj * Get device and block structures, and a pointer 4922983Swnj * to the uba_device for the drive. Select the drive. 4932674Swnj */ 4942674Swnj dp = um->um_tab.b_actf; 4952674Swnj bp = dp->b_actf; 4962674Swnj ui = updinfo[dkunit(bp)]; 4972674Swnj dk_busy &= ~(1 << ui->ui_dk); 4982674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 4992395Swnj upaddr->upcs2 = ui->ui_slave; 5002674Swnj /* 5012674Swnj * Check for and process errors on 5022674Swnj * either the drive or the controller. 5032674Swnj */ 5043445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5052681Swnj waitdry = 0; 5063445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5072681Swnj if (++waitdry > 512) 5082681Swnj break; 5092681Swnj upwaitdry++; 5102681Swnj } 5113445Sroot if (upaddr->uper1&UPER1_WLE) { 5122674Swnj /* 5132674Swnj * Give up on write locked devices 5142674Swnj * immediately. 5152674Swnj */ 5162931Swnj printf("up%d: write locked\n", dkunit(bp)); 5172674Swnj bp->b_flags |= B_ERROR; 5182674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5192674Swnj /* 5202674Swnj * After 28 retries (16 without offset, and 5212674Swnj * 12 with offset positioning) give up. 5222674Swnj */ 5232931Swnj harderr(bp, "up"); 5242931Swnj printf("cs2=%b er1=%b er2=%b\n", 5252785Swnj upaddr->upcs2, UPCS2_BITS, 5262785Swnj upaddr->uper1, UPER1_BITS, 5272785Swnj upaddr->uper2, UPER2_BITS); 5282674Swnj bp->b_flags |= B_ERROR; 5292674Swnj } else { 5302674Swnj /* 5312674Swnj * Retriable error. 5322674Swnj * If a soft ecc, correct it (continuing 5332674Swnj * by returning if necessary. 5342674Swnj * Otherwise fall through and retry the transfer 5352674Swnj */ 5362674Swnj um->um_tab.b_active = 0; /* force retry */ 5373445Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) 5382629Swnj if (upecc(ui)) 5392629Swnj return; 5402674Swnj } 5412674Swnj /* 5422674Swnj * Clear drive error and, every eight attempts, 5432674Swnj * (starting with the fourth) 5442674Swnj * recalibrate to clear the slate. 5452674Swnj */ 5462674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5472674Swnj needie = 0; 5483182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5492674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5503160Swnj sc->sc_recal = 0; 5513160Swnj goto nextrecal; 5522674Swnj } 5532674Swnj } 5542674Swnj /* 5553160Swnj * Advance recalibration finite state machine 5563160Swnj * if recalibrate in progress, through 5573160Swnj * RECAL 5583160Swnj * SEEK 5593160Swnj * OFFSET (optional) 5603160Swnj * RETRY 5612674Swnj */ 5623160Swnj switch (sc->sc_recal) { 5633160Swnj 5643160Swnj case 1: 5653160Swnj upaddr->updc = bp->b_cylin; 5663160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 5673160Swnj goto nextrecal; 5683160Swnj case 2: 5693160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 5703160Swnj goto donerecal; 5713445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 5723160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 5733160Swnj goto nextrecal; 5743160Swnj nextrecal: 5753160Swnj sc->sc_recal++; 5763160Swnj um->um_tab.b_active = 1; 5773160Swnj return; 5783160Swnj donerecal: 5793160Swnj case 3: 5802674Swnj sc->sc_recal = 0; 5813160Swnj um->um_tab.b_active = 0; 5823160Swnj break; 5832674Swnj } 5842674Swnj /* 5852674Swnj * If still ``active'', then don't need any more retries. 5862674Swnj */ 5872674Swnj if (um->um_tab.b_active) { 5882674Swnj /* 5892674Swnj * If we were offset positioning, 5902674Swnj * return to centerline. 5912674Swnj */ 5922674Swnj if (um->um_tab.b_errcnt >= 16) { 5933445Sroot upaddr->upof = UPOF_FMT22; 5942674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 5953445Sroot while (upaddr->upds & UPDS_PIP) 5962674Swnj DELAY(25); 597268Sbill needie = 0; 598264Sbill } 5992674Swnj um->um_tab.b_active = 0; 6002674Swnj um->um_tab.b_errcnt = 0; 6012674Swnj um->um_tab.b_actf = dp->b_forw; 6022674Swnj dp->b_active = 0; 6032674Swnj dp->b_errcnt = 0; 6042674Swnj dp->b_actf = bp->av_forw; 6052674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6062674Swnj iodone(bp); 6072674Swnj /* 6082674Swnj * If this unit has more work to do, 6092674Swnj * then start it up right away. 6102674Swnj */ 6112674Swnj if (dp->b_actf) 6122674Swnj if (upustart(ui)) 613268Sbill needie = 0; 614264Sbill } 6152674Swnj as &= ~(1<<ui->ui_slave); 6163403Swnj /* 6173403Swnj * Release unibus resources and flush data paths. 6183403Swnj */ 6193403Swnj ubadone(um); 6202674Swnj doattn: 6212674Swnj /* 6222674Swnj * Process other units which need attention. 6232674Swnj * For each unit which needs attention, call 6242674Swnj * the unit start routine to place the slave 6252674Swnj * on the controller device queue. 6262674Swnj */ 6273160Swnj while (unit = ffs(as)) { 6283160Swnj unit--; /* was 1 origin */ 6293160Swnj as &= ~(1<<unit); 6303160Swnj upaddr->upas = 1<<unit; 6313160Swnj if (upustart(upip[sc21][unit])) 6323160Swnj needie = 0; 6333160Swnj } 6342674Swnj /* 6352674Swnj * If the controller is not transferring, but 6362674Swnj * there are devices ready to transfer, start 6372674Swnj * the controller. 6382674Swnj */ 6392395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6402395Swnj if (upstart(um)) 641268Sbill needie = 0; 642275Sbill if (needie) 6432629Swnj upaddr->upcs1 = UP_IE; 644264Sbill } 645264Sbill 646264Sbill upread(dev) 6472616Swnj dev_t dev; 648264Sbill { 6492616Swnj register int unit = minor(dev) >> 3; 6502470Swnj 6512616Swnj if (unit >= NUP) 6522616Swnj u.u_error = ENXIO; 6532616Swnj else 6542616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 655264Sbill } 656264Sbill 657264Sbill upwrite(dev) 6582616Swnj dev_t dev; 659264Sbill { 6602616Swnj register int unit = minor(dev) >> 3; 6612470Swnj 6622616Swnj if (unit >= NUP) 6632616Swnj u.u_error = ENXIO; 6642616Swnj else 6652616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 666264Sbill } 667264Sbill 668266Sbill /* 669266Sbill * Correct an ECC error, and restart the i/o to complete 670266Sbill * the transfer if necessary. This is quite complicated because 671266Sbill * the transfer may be going to an odd memory address base and/or 672266Sbill * across a page boundary. 673266Sbill */ 6742395Swnj upecc(ui) 6752983Swnj register struct uba_device *ui; 676264Sbill { 6772629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6782395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6792983Swnj register struct uba_ctlr *um = ui->ui_mi; 6802395Swnj register struct upst *st; 6812395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 682266Sbill register int i; 683264Sbill caddr_t addr; 684266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 685264Sbill int bn, cn, tn, sn; 686264Sbill 687264Sbill /* 688266Sbill * Npf is the number of sectors transferred before the sector 689266Sbill * containing the ECC error, and reg is the UBA register 690266Sbill * mapping (the first part of) the transfer. 691266Sbill * O is offset within a memory page of the first byte transferred. 692264Sbill */ 693266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 6942571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 695264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 6962983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 6972889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 698264Sbill mask = up->upec2; 6993445Sroot #ifdef UPECCDEBUG 7003403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7013403Swnj up->upec1); 7023445Sroot #endif 703266Sbill /* 704266Sbill * Flush the buffered data path, and compute the 705266Sbill * byte and bit position of the error. The variable i 706266Sbill * is the byte offset in the transfer, the variable byte 707266Sbill * is the offset from a page boundary in main memory. 708266Sbill */ 7092725Swnj ubapurge(um); 710266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 711266Sbill bit = i&07; 712266Sbill i = (i&~07)>>3; 713264Sbill byte = i + o; 714266Sbill /* 715266Sbill * Correct while possible bits remain of mask. Since mask 716266Sbill * contains 11 bits, we continue while the bit offset is > -11. 717266Sbill * Also watch out for end of this block and the end of the whole 718266Sbill * transfer. 719266Sbill */ 720266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 721266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 722266Sbill (byte & PGOFSET); 7233445Sroot #ifdef UPECCDEBUG 7243403Swnj printf("addr %x map reg %x\n", 7253403Swnj addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 7263403Swnj printf("old: %x, ", getmemc(addr)); 7273445Sroot #endif 728266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 7293445Sroot #ifdef UPECCDEBUG 7303403Swnj printf("new: %x\n", getmemc(addr)); 7313445Sroot #endif 732266Sbill byte++; 733266Sbill i++; 734266Sbill bit -= 8; 735264Sbill } 7362395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 737264Sbill if (up->upwc == 0) 738264Sbill return (0); 739266Sbill /* 740266Sbill * Have to continue the transfer... clear the drive, 741266Sbill * and compute the position where the transfer is to continue. 742266Sbill * We have completed npf+1 sectors of the transfer already; 743266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 744266Sbill */ 7452629Swnj #ifdef notdef 7462629Swnj up->uper1 = 0; 7472629Swnj up->upcs1 |= UP_GO; 7482629Swnj #else 7492629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 750264Sbill bn = dkblock(bp); 7512395Swnj st = &upst[ui->ui_type]; 752264Sbill cn = bp->b_cylin; 7532395Swnj sn = bn%st->nspc + npf + 1; 7542395Swnj tn = sn/st->nsect; 7552395Swnj sn %= st->nsect; 7562395Swnj cn += tn/st->ntrak; 7572395Swnj tn %= st->ntrak; 758264Sbill up->updc = cn; 759266Sbill up->upda = (tn << 8) | sn; 760266Sbill ubaddr = (int)ptob(reg+1) + o; 761266Sbill up->upba = ubaddr; 762266Sbill cmd = (ubaddr >> 8) & 0x300; 7632629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 764266Sbill up->upcs1 = cmd; 7652629Swnj #endif 766264Sbill return (1); 767264Sbill } 768286Sbill 769286Sbill /* 770286Sbill * Reset driver after UBA init. 771286Sbill * Cancel software state of all pending transfers 772286Sbill * and restart all units and the controller. 773286Sbill */ 7742395Swnj upreset(uban) 7752931Swnj int uban; 776286Sbill { 7772983Swnj register struct uba_ctlr *um; 7782983Swnj register struct uba_device *ui; 7792395Swnj register sc21, unit; 780286Sbill 7812646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7822470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7832470Swnj um->um_alive == 0) 7842395Swnj continue; 7852931Swnj printf(" sc%d", sc21); 7862395Swnj um->um_tab.b_active = 0; 7872395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7882931Swnj up_softc[sc21].sc_recal = 0; 7892571Swnj if (um->um_ubinfo) { 7902571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7912616Swnj ubadone(um); 7922395Swnj } 7933445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 7942395Swnj for (unit = 0; unit < NUP; unit++) { 7952395Swnj if ((ui = updinfo[unit]) == 0) 7962395Swnj continue; 7972931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 7982395Swnj continue; 7992395Swnj uputab[unit].b_active = 0; 8002395Swnj (void) upustart(ui); 8012395Swnj } 8022395Swnj (void) upstart(um); 803286Sbill } 804286Sbill } 805313Sbill 806313Sbill /* 807313Sbill * Wake up every second and if an interrupt is pending 808313Sbill * but nothing has happened increment a counter. 8092931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 810313Sbill * and begin anew. 811313Sbill */ 812313Sbill upwatch() 813313Sbill { 8142983Swnj register struct uba_ctlr *um; 8152395Swnj register sc21, unit; 8162470Swnj register struct up_softc *sc; 817313Sbill 8182759Swnj timeout(upwatch, (caddr_t)0, hz); 8192646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 8202395Swnj um = upminfo[sc21]; 8212470Swnj if (um == 0 || um->um_alive == 0) 8222470Swnj continue; 8232470Swnj sc = &up_softc[sc21]; 8242395Swnj if (um->um_tab.b_active == 0) { 8252395Swnj for (unit = 0; unit < NUP; unit++) 8262629Swnj if (uputab[unit].b_active && 8272629Swnj updinfo[unit]->ui_mi == um) 8282395Swnj goto active; 8292470Swnj sc->sc_wticks = 0; 8302395Swnj continue; 8312395Swnj } 8322931Swnj active: 8332470Swnj sc->sc_wticks++; 8342470Swnj if (sc->sc_wticks >= 20) { 8352470Swnj sc->sc_wticks = 0; 8362931Swnj printf("sc%d: lost interrupt\n", sc21); 8372646Swnj ubareset(um->um_ubanum); 8382395Swnj } 839313Sbill } 840313Sbill } 8412379Swnj 8422379Swnj #define DBSIZE 20 8432379Swnj 8442379Swnj updump(dev) 8452379Swnj dev_t dev; 8462379Swnj { 8472629Swnj struct updevice *upaddr; 8482379Swnj char *start; 8493107Swnj int num, blk, unit; 8502379Swnj struct size *sizes; 8512395Swnj register struct uba_regs *uba; 8522983Swnj register struct uba_device *ui; 8532379Swnj register short *rp; 8542395Swnj struct upst *st; 8552379Swnj 8562395Swnj unit = minor(dev) >> 3; 8572889Swnj if (unit >= NUP) 8582889Swnj return (ENXIO); 8592470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8602983Swnj ui = phys(struct uba_device *, updinfo[unit]); 8612889Swnj if (ui->ui_alive == 0) 8622889Swnj return (ENXIO); 8632395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8642983Swnj ubainit(uba); 8652629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8662983Swnj DELAY(2000000); 8672379Swnj num = maxfree; 8682379Swnj start = 0; 8692379Swnj upaddr->upcs2 = unit; 8702983Swnj DELAY(100); 8712983Swnj if ((upaddr->upcs1&UP_DVA) == 0) 8722983Swnj return (EFAULT); 8733445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 8742629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 8752629Swnj upaddr->upcs1 = UP_PRESET|UP_GO; 8763445Sroot upaddr->upof = UPOF_FMT22; 8772379Swnj } 8783445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 8792889Swnj return (EFAULT); 8802470Swnj st = &upst[ui->ui_type]; 8812395Swnj sizes = phys(struct size *, st->sizes); 8822889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 8832889Swnj return (EINVAL); 8842379Swnj while (num > 0) { 8852379Swnj register struct pte *io; 8862379Swnj register int i; 8872379Swnj int cn, sn, tn; 8882379Swnj daddr_t bn; 8892379Swnj 8902379Swnj blk = num > DBSIZE ? DBSIZE : num; 8912395Swnj io = uba->uba_map; 8922379Swnj for (i = 0; i < blk; i++) 8932983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 8942379Swnj *(int *)io = 0; 8952379Swnj bn = dumplo + btop(start); 8962607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 8972607Swnj sn = bn%st->nspc; 8982607Swnj tn = sn/st->nsect; 8992607Swnj sn = sn%st->nsect; 9002379Swnj upaddr->updc = cn; 9012379Swnj rp = (short *) &upaddr->upda; 9022379Swnj *rp = (tn << 8) + sn; 9032379Swnj *--rp = 0; 9042379Swnj *--rp = -blk*NBPG / sizeof (short); 9052629Swnj *--rp = UP_GO|UP_WCOM; 9062379Swnj do { 9072379Swnj DELAY(25); 9082629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 9093445Sroot if (upaddr->upds&UPDS_ERR) 9102889Swnj return (EIO); 9112379Swnj start += blk*NBPG; 9122379Swnj num -= blk; 9132379Swnj } 9142379Swnj return (0); 9152379Swnj } 9161902Swnj #endif 917