1*10858Ssam /* up.c 4.66 83/02/10 */ 2264Sbill 31937Swnj #include "up.h" 42646Swnj #if NSC > 0 5264Sbill /* 69548Ssam * UNIBUS disk driver with: 79548Ssam * overlapped seeks, 89548Ssam * ECC recovery, and 99548Ssam * bad sector forwarding. 102889Swnj * 112889Swnj * TODO: 123445Sroot * Check that offset recovery code works 13264Sbill */ 149782Ssam #include "../machine/pte.h" 15264Sbill 16264Sbill #include "../h/param.h" 17264Sbill #include "../h/systm.h" 18308Sbill #include "../h/dk.h" 199548Ssam #include "../h/dkbad.h" 20264Sbill #include "../h/buf.h" 21264Sbill #include "../h/conf.h" 22264Sbill #include "../h/dir.h" 23264Sbill #include "../h/user.h" 24264Sbill #include "../h/map.h" 252571Swnj #include "../h/vm.h" 262379Swnj #include "../h/cmap.h" 279357Ssam #include "../h/uio.h" 28264Sbill 299357Ssam #include "../vax/cpu.h" 309357Ssam #include "../vax/nexus.h" 319357Ssam #include "../vaxuba/ubavar.h" 329357Ssam #include "../vaxuba/ubareg.h" 339357Ssam #include "../vaxuba/upreg.h" 349357Ssam 352395Swnj struct up_softc { 362395Swnj int sc_softas; 372607Swnj int sc_ndrive; 382395Swnj int sc_wticks; 392674Swnj int sc_recal; 402646Swnj } up_softc[NSC]; 41275Sbill 422395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 43*10858Ssam struct size { 44264Sbill daddr_t nblocks; 45264Sbill int cyloff; 46264Sbill } up_sizes[8] = { 47264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 48264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 49341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 50264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 51264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 523730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 533730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 54264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 552395Swnj }, fj_sizes[8] = { 562395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 572395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 582395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 592395Swnj 0, 0, 602395Swnj 0, 0, 612395Swnj 0, 0, 622395Swnj 0, 0, 633730Sroot 213664, 155, /* H=cyl 155 thru 822 */ 646851Ssam }, upam_sizes[8] = { 656305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 666305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 676305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 686602Ssam 27786, 668, 696602Ssam 27786, 723, 706602Ssam 125440, 778, 716305Sroot 181760, 668, /* G=cyl 668 thru 1022 */ 726305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 73264Sbill }; 742395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 75264Sbill 766346Swnj /* 776346Swnj * On a 780 upSDIST could be 2, but 786346Swnj * in the interest of 750's... 796346Swnj */ 806346Swnj #define _upSDIST 3 /* 1.5 msec */ 812395Swnj #define _upRDIST 4 /* 2.0 msec */ 82264Sbill 832395Swnj int upSDIST = _upSDIST; 842395Swnj int upRDIST = _upRDIST; 852395Swnj 862607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 872983Swnj struct uba_ctlr *upminfo[NSC]; 882983Swnj struct uba_device *updinfo[NUP]; 896383Swnj #define UPIPUNITS 8 906383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 912395Swnj 922607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 932616Swnj struct uba_driver scdriver = 942607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 952395Swnj struct buf uputab[NUP]; 969548Ssam char upinit[NUP]; 972395Swnj 982395Swnj struct upst { 992395Swnj short nsect; 1002395Swnj short ntrak; 1012395Swnj short nspc; 1022395Swnj short ncyl; 1032395Swnj struct size *sizes; 1042395Swnj } upst[] = { 1052607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 1062607Swnj /* 9300 actually has 815 cylinders... */ 1072395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 1086851Ssam 32, 16, 32*16, 1024, upam_sizes, /* ampex capricorn */ 1092395Swnj }; 1102395Swnj 1112629Swnj u_char up_offset[16] = { 1129548Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1139548Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1149548Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1159548Ssam 0, 0, 0, 0 1162629Swnj }; 117264Sbill 1182616Swnj struct buf rupbuf[NUP]; 1199548Ssam struct buf bupbuf[NUP]; 1209548Ssam struct dkbad upbad[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; 1449357Ssam return (sizeof (struct updevice)); 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; 1556843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1563445Sroot if (upaddr->upcs2&UPCS2_NED) { 1572629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1582395Swnj return (0); 1592395Swnj } 1602607Swnj return (1); 1612607Swnj } 1622607Swnj 1632607Swnj upattach(ui) 1642983Swnj register struct uba_device *ui; 1652607Swnj { 1662629Swnj register struct updevice *upaddr; 1672607Swnj 1682395Swnj if (upwstart == 0) { 1692759Swnj timeout(upwatch, (caddr_t)0, hz); 1702395Swnj upwstart++; 1712395Swnj } 1722571Swnj if (ui->ui_dk >= 0) 1732571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1742607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1752607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1762629Swnj upaddr = (struct updevice *)ui->ui_addr; 1772629Swnj upaddr->upcs1 = 0; 1782629Swnj upaddr->upcs2 = ui->ui_slave; 1793496Sroot upaddr->uphr = UPHR_MAXTRAK; 1803553Swnj if (upaddr->uphr == 9) 1813496Sroot ui->ui_type = 1; /* fujitsu hack */ 1826305Sroot else if (upaddr->uphr == 15) 1836305Sroot ui->ui_type = 2; /* ampex hack */ 1843496Sroot upaddr->upcs2 = UPCS2_CLR; 1852395Swnj } 186264Sbill 1879548Ssam upopen(dev) 1889548Ssam dev_t dev; 1899548Ssam { 1909548Ssam register int unit = minor(dev) >> 3; 1919548Ssam register struct uba_device *ui; 1929548Ssam 1939548Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 1949548Ssam return (ENXIO); 1959548Ssam return (0); 1969548Ssam } 1979548Ssam 198264Sbill upstrategy(bp) 1992395Swnj register struct buf *bp; 200264Sbill { 2012983Swnj register struct uba_device *ui; 2022395Swnj register struct upst *st; 2032395Swnj register int unit; 2042470Swnj register struct buf *dp; 2052395Swnj int xunit = minor(bp->b_dev) & 07; 2062470Swnj long bn, sz; 207264Sbill 2082470Swnj sz = (bp->b_bcount+511) >> 9; 209264Sbill unit = dkunit(bp); 2102395Swnj if (unit >= NUP) 2112395Swnj goto bad; 2122395Swnj ui = updinfo[unit]; 2132395Swnj if (ui == 0 || ui->ui_alive == 0) 2142395Swnj goto bad; 2152395Swnj st = &upst[ui->ui_type]; 2162395Swnj if (bp->b_blkno < 0 || 2172395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2182395Swnj goto bad; 2192395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2206305Sroot (void) spl5(); 2212470Swnj dp = &uputab[ui->ui_unit]; 2222470Swnj disksort(dp, bp); 2232470Swnj if (dp->b_active == 0) { 2242395Swnj (void) upustart(ui); 2252395Swnj bp = &ui->ui_mi->um_tab; 2262395Swnj if (bp->b_actf && bp->b_active == 0) 2272395Swnj (void) upstart(ui->ui_mi); 228264Sbill } 2296305Sroot (void) spl0(); 2302395Swnj return; 2312395Swnj 2322395Swnj bad: 2332395Swnj bp->b_flags |= B_ERROR; 2342395Swnj iodone(bp); 2352395Swnj return; 236264Sbill } 237264Sbill 2382674Swnj /* 2392674Swnj * Unit start routine. 2402674Swnj * Seek the drive to be where the data is 2412674Swnj * and then generate another interrupt 2422674Swnj * to actually start the transfer. 2432674Swnj * If there is only one drive on the controller, 2442674Swnj * or we are very close to the data, don't 2452674Swnj * bother with the search. If called after 2462674Swnj * searching once, don't bother to look where 2472674Swnj * we are, just queue for transfer (to avoid 2482674Swnj * positioning forever without transferrring.) 2492674Swnj */ 2502395Swnj upustart(ui) 2512983Swnj register struct uba_device *ui; 252264Sbill { 253264Sbill register struct buf *bp, *dp; 2542983Swnj register struct uba_ctlr *um; 2552629Swnj register struct updevice *upaddr; 2562395Swnj register struct upst *st; 257264Sbill daddr_t bn; 2582674Swnj int sn, csn; 2592607Swnj /* 2602607Swnj * The SC21 cancels commands if you just say 2612629Swnj * cs1 = UP_IE 2622607Swnj * so we are cautious about handling of cs1. 2632607Swnj * Also don't bother to clear as bits other than in upintr(). 2642607Swnj */ 2652674Swnj int didie = 0; 2662674Swnj 2672674Swnj if (ui == 0) 2682674Swnj return (0); 2692983Swnj um = ui->ui_mi; 2702395Swnj dk_busy &= ~(1<<ui->ui_dk); 2712395Swnj dp = &uputab[ui->ui_unit]; 272266Sbill if ((bp = dp->b_actf) == NULL) 273268Sbill goto out; 2742674Swnj /* 2752674Swnj * If the controller is active, just remember 2762674Swnj * that this device would like to be positioned... 2772674Swnj * if we tried to position now we would confuse the SC21. 2782674Swnj */ 2792395Swnj if (um->um_tab.b_active) { 2802459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 281275Sbill return (0); 282275Sbill } 2832674Swnj /* 2842674Swnj * If we have already positioned this drive, 2852674Swnj * then just put it on the ready queue. 2862674Swnj */ 287276Sbill if (dp->b_active) 288276Sbill goto done; 289276Sbill dp->b_active = 1; 2902629Swnj upaddr = (struct updevice *)um->um_addr; 2912395Swnj upaddr->upcs2 = ui->ui_slave; 2922674Swnj /* 2932674Swnj * If drive has just come up, 2942674Swnj * setup the pack. 2952674Swnj */ 2969548Ssam if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { 2979548Ssam struct buf *bbp = &bupbuf[ui->ui_unit]; 298*10858Ssam 2992607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3009548Ssam upinit[ui->ui_unit] = 1; 3012629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3022629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3033445Sroot upaddr->upof = UPOF_FMT22; 304268Sbill didie = 1; 3059548Ssam st = &upst[ui->ui_type]; 3069548Ssam bbp->b_flags = B_READ|B_BUSY; 3079548Ssam bbp->b_dev = bp->b_dev; 3089548Ssam bbp->b_bcount = 512; 3099548Ssam bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; 3109548Ssam bbp->b_blkno = st->ncyl * st->nspc - st->nsect; 3119548Ssam bbp->b_cylin = st->ncyl - 1; 3129548Ssam dp->b_actf = bbp; 3139548Ssam bbp->av_forw = bp; 3149548Ssam bp = bbp; 315264Sbill } 3162674Swnj /* 3172674Swnj * If drive is offline, forget about positioning. 3182674Swnj */ 3193445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 320275Sbill goto done; 3212674Swnj /* 3222674Swnj * If there is only one drive, 3232674Swnj * dont bother searching. 3242674Swnj */ 3252607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3262607Swnj goto done; 3272674Swnj /* 3282674Swnj * Figure out where this transfer is going to 3292674Swnj * and see if we are close enough to justify not searching. 3302674Swnj */ 3312395Swnj st = &upst[ui->ui_type]; 332264Sbill bn = dkblock(bp); 3332395Swnj sn = bn%st->nspc; 3342395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 3352674Swnj if (bp->b_cylin - upaddr->updc) 336266Sbill goto search; /* Not on-cylinder */ 337275Sbill else if (upseek) 338275Sbill goto done; /* Ok just to be on-cylinder */ 339264Sbill csn = (upaddr->upla>>6) - sn - 1; 340266Sbill if (csn < 0) 3412395Swnj csn += st->nsect; 3422395Swnj if (csn > st->nsect - upRDIST) 343264Sbill goto done; 344264Sbill search: 3452674Swnj upaddr->updc = bp->b_cylin; 3462674Swnj /* 3472674Swnj * Not on cylinder at correct position, 3482674Swnj * seek/search. 3492674Swnj */ 350275Sbill if (upseek) 3512629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3522470Swnj else { 353275Sbill upaddr->upda = sn; 3542629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 355275Sbill } 356268Sbill didie = 1; 3572674Swnj /* 3582674Swnj * Mark unit busy for iostat. 3592674Swnj */ 3602395Swnj if (ui->ui_dk >= 0) { 3612395Swnj dk_busy |= 1<<ui->ui_dk; 3622395Swnj dk_seek[ui->ui_dk]++; 363264Sbill } 364268Sbill goto out; 365264Sbill done: 3662674Swnj /* 3672674Swnj * Device is ready to go. 3682674Swnj * Put it on the ready queue for the controller 3692674Swnj * (unless its already there.) 3702674Swnj */ 3712629Swnj if (dp->b_active != 2) { 3722629Swnj dp->b_forw = NULL; 3732629Swnj if (um->um_tab.b_actf == NULL) 3742629Swnj um->um_tab.b_actf = dp; 3752629Swnj else 3762629Swnj um->um_tab.b_actl->b_forw = dp; 3772629Swnj um->um_tab.b_actl = dp; 3782629Swnj dp->b_active = 2; 3792629Swnj } 380268Sbill out: 381268Sbill return (didie); 382264Sbill } 383264Sbill 3842674Swnj /* 3852674Swnj * Start up a transfer on a drive. 3862674Swnj */ 3872395Swnj upstart(um) 3882983Swnj register struct uba_ctlr *um; 389264Sbill { 390264Sbill register struct buf *bp, *dp; 3912983Swnj register struct uba_device *ui; 3922629Swnj register struct updevice *upaddr; 3932470Swnj struct upst *st; 394264Sbill daddr_t bn; 3952681Swnj int dn, sn, tn, cmd, waitdry; 396264Sbill 397264Sbill loop: 3982674Swnj /* 3992674Swnj * Pull a request off the controller queue 4002674Swnj */ 4012395Swnj if ((dp = um->um_tab.b_actf) == NULL) 402268Sbill return (0); 403264Sbill if ((bp = dp->b_actf) == NULL) { 4042395Swnj um->um_tab.b_actf = dp->b_forw; 405264Sbill goto loop; 406264Sbill } 4072674Swnj /* 4082674Swnj * Mark controller busy, and 4092674Swnj * determine destination of this request. 4102674Swnj */ 4112395Swnj um->um_tab.b_active++; 4122395Swnj ui = updinfo[dkunit(bp)]; 413264Sbill bn = dkblock(bp); 4142395Swnj dn = ui->ui_slave; 4152395Swnj st = &upst[ui->ui_type]; 4162395Swnj sn = bn%st->nspc; 4172395Swnj tn = sn/st->nsect; 4182395Swnj sn %= st->nsect; 4192629Swnj upaddr = (struct updevice *)ui->ui_addr; 4202674Swnj /* 4212674Swnj * Select drive if not selected already. 4222674Swnj */ 4232674Swnj if ((upaddr->upcs2&07) != dn) 4242674Swnj upaddr->upcs2 = dn; 4252674Swnj /* 4262674Swnj * Check that it is ready and online 4272674Swnj */ 4282681Swnj waitdry = 0; 4293445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4307036Swnj printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds); 4312681Swnj if (++waitdry > 512) 4322681Swnj break; 4332681Swnj upwaitdry++; 4342681Swnj } 4353445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4362931Swnj printf("up%d: not ready", dkunit(bp)); 4373445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4382607Swnj printf("\n"); 4392395Swnj um->um_tab.b_active = 0; 4402395Swnj um->um_tab.b_errcnt = 0; 441893Sbill dp->b_actf = bp->av_forw; 442893Sbill dp->b_active = 0; 443893Sbill bp->b_flags |= B_ERROR; 444893Sbill iodone(bp); 445893Sbill goto loop; 446893Sbill } 4472674Swnj /* 4482674Swnj * Oh, well, sometimes this 4492674Swnj * happens, for reasons unknown. 4502674Swnj */ 4512629Swnj printf(" (flakey)\n"); 452264Sbill } 4532674Swnj /* 4542674Swnj * Setup for the transfer, and get in the 4552674Swnj * UNIBUS adaptor queue. 4562674Swnj */ 4572424Skre upaddr->updc = bp->b_cylin; 458264Sbill upaddr->upda = (tn << 8) + sn; 459264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 460264Sbill if (bp->b_flags & B_READ) 4612629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 462264Sbill else 4632629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4642571Swnj um->um_cmd = cmd; 4653107Swnj (void) ubago(ui); 466268Sbill return (1); 467264Sbill } 468264Sbill 4692674Swnj /* 4702674Swnj * Now all ready to go, stuff the registers. 4712674Swnj */ 4722571Swnj updgo(um) 4732983Swnj struct uba_ctlr *um; 4742395Swnj { 4752629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4762470Swnj 4776953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 4782571Swnj upaddr->upba = um->um_ubinfo; 4792571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4802395Swnj } 4812395Swnj 4822674Swnj /* 4832674Swnj * Handle a disk interrupt. 4842674Swnj */ 4852707Swnj upintr(sc21) 4862395Swnj register sc21; 487264Sbill { 488264Sbill register struct buf *bp, *dp; 4892983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4902983Swnj register struct uba_device *ui; 4912629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 492264Sbill register unit; 4932470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4942607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4952681Swnj int needie = 1, waitdry; 496264Sbill 4972470Swnj sc->sc_wticks = 0; 4982607Swnj sc->sc_softas = 0; 4992674Swnj /* 5002674Swnj * If controller wasn't transferring, then this is an 5012674Swnj * interrupt for attention status on seeking drives. 5022674Swnj * Just service them. 5032674Swnj */ 5046346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 5052674Swnj if (upaddr->upcs1 & UP_TRE) 5062674Swnj upaddr->upcs1 = UP_TRE; 5072674Swnj goto doattn; 5082674Swnj } 5096953Swnj um->um_tab.b_active = 1; 5102674Swnj /* 5112674Swnj * Get device and block structures, and a pointer 5122983Swnj * to the uba_device for the drive. Select the drive. 5132674Swnj */ 5142674Swnj dp = um->um_tab.b_actf; 5152674Swnj bp = dp->b_actf; 5162674Swnj ui = updinfo[dkunit(bp)]; 5172674Swnj dk_busy &= ~(1 << ui->ui_dk); 5182674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5192395Swnj upaddr->upcs2 = ui->ui_slave; 5209548Ssam if (bp->b_flags&B_BAD) { 5219548Ssam if (upecc(ui, CONT)) 5229548Ssam return; 5239548Ssam } 5242674Swnj /* 5252674Swnj * Check for and process errors on 5262674Swnj * either the drive or the controller. 5272674Swnj */ 5283445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5292681Swnj waitdry = 0; 5303445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5312681Swnj if (++waitdry > 512) 5322681Swnj break; 5332681Swnj upwaitdry++; 5342681Swnj } 5353445Sroot if (upaddr->uper1&UPER1_WLE) { 5362674Swnj /* 5372674Swnj * Give up on write locked devices 5382674Swnj * immediately. 5392674Swnj */ 5402931Swnj printf("up%d: write locked\n", dkunit(bp)); 5412674Swnj bp->b_flags |= B_ERROR; 5422674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5432674Swnj /* 5442674Swnj * After 28 retries (16 without offset, and 5452674Swnj * 12 with offset positioning) give up. 5462674Swnj */ 5479548Ssam hard: 5482931Swnj harderr(bp, "up"); 5499548Ssam printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", 5509548Ssam upaddr->updc, ((upaddr->upda)>>8)&077, 5519548Ssam (upaddr->upda)&037, 5529548Ssam upaddr->upcs2, UPCS2_BITS, 5539548Ssam upaddr->uper1, UPER1_BITS, 5549548Ssam upaddr->uper2, UPER2_BITS); 5552674Swnj bp->b_flags |= B_ERROR; 5569548Ssam } else if (upaddr->uper2 & UPER2_BSE) { 5579548Ssam if (upecc(ui, BSE)) 5589548Ssam return; 5599548Ssam else 5609548Ssam goto hard; 5612674Swnj } else { 5622674Swnj /* 5632674Swnj * Retriable error. 5642674Swnj * If a soft ecc, correct it (continuing 5652674Swnj * by returning if necessary. 5662674Swnj * Otherwise fall through and retry the transfer 5672674Swnj */ 5687183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 5699548Ssam if (upecc(ui, ECC)) 5702629Swnj return; 5717183Sroot } else 5727183Sroot um->um_tab.b_active = 0; /* force retry */ 5732674Swnj } 5742674Swnj /* 5752674Swnj * Clear drive error and, every eight attempts, 5762674Swnj * (starting with the fourth) 5772674Swnj * recalibrate to clear the slate. 5782674Swnj */ 5792674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5802674Swnj needie = 0; 5813182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5822674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5833160Swnj sc->sc_recal = 0; 5843160Swnj goto nextrecal; 5852674Swnj } 5862674Swnj } 5872674Swnj /* 5883160Swnj * Advance recalibration finite state machine 5893160Swnj * if recalibrate in progress, through 5903160Swnj * RECAL 5913160Swnj * SEEK 5923160Swnj * OFFSET (optional) 5933160Swnj * RETRY 5942674Swnj */ 5953160Swnj switch (sc->sc_recal) { 5963160Swnj 5973160Swnj case 1: 5983160Swnj upaddr->updc = bp->b_cylin; 5993160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 6003160Swnj goto nextrecal; 6013160Swnj case 2: 6023160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 6033160Swnj goto donerecal; 6043445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 6053160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 6063160Swnj goto nextrecal; 6073160Swnj nextrecal: 6083160Swnj sc->sc_recal++; 6093160Swnj um->um_tab.b_active = 1; 6103160Swnj return; 6113160Swnj donerecal: 6123160Swnj case 3: 6132674Swnj sc->sc_recal = 0; 6143160Swnj um->um_tab.b_active = 0; 6153160Swnj break; 6162674Swnj } 6172674Swnj /* 6182674Swnj * If still ``active'', then don't need any more retries. 6192674Swnj */ 6202674Swnj if (um->um_tab.b_active) { 6212674Swnj /* 6222674Swnj * If we were offset positioning, 6232674Swnj * return to centerline. 6242674Swnj */ 6252674Swnj if (um->um_tab.b_errcnt >= 16) { 6263445Sroot upaddr->upof = UPOF_FMT22; 6272674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6283445Sroot while (upaddr->upds & UPDS_PIP) 6292674Swnj DELAY(25); 630268Sbill needie = 0; 631264Sbill } 6322674Swnj um->um_tab.b_active = 0; 6332674Swnj um->um_tab.b_errcnt = 0; 6342674Swnj um->um_tab.b_actf = dp->b_forw; 6352674Swnj dp->b_active = 0; 6362674Swnj dp->b_errcnt = 0; 6372674Swnj dp->b_actf = bp->av_forw; 6382674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6392674Swnj iodone(bp); 6402674Swnj /* 6412674Swnj * If this unit has more work to do, 6422674Swnj * then start it up right away. 6432674Swnj */ 6442674Swnj if (dp->b_actf) 6452674Swnj if (upustart(ui)) 646268Sbill needie = 0; 647264Sbill } 6482674Swnj as &= ~(1<<ui->ui_slave); 6493403Swnj /* 6503403Swnj * Release unibus resources and flush data paths. 6513403Swnj */ 6523403Swnj ubadone(um); 6532674Swnj doattn: 6542674Swnj /* 6552674Swnj * Process other units which need attention. 6562674Swnj * For each unit which needs attention, call 6572674Swnj * the unit start routine to place the slave 6582674Swnj * on the controller device queue. 6592674Swnj */ 6603160Swnj while (unit = ffs(as)) { 6613160Swnj unit--; /* was 1 origin */ 6623160Swnj as &= ~(1<<unit); 6633160Swnj upaddr->upas = 1<<unit; 6646383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 6653160Swnj needie = 0; 6663160Swnj } 6672674Swnj /* 6682674Swnj * If the controller is not transferring, but 6692674Swnj * there are devices ready to transfer, start 6702674Swnj * the controller. 6712674Swnj */ 6722395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6732395Swnj if (upstart(um)) 674268Sbill needie = 0; 675275Sbill if (needie) 6762629Swnj upaddr->upcs1 = UP_IE; 677264Sbill } 678264Sbill 6799357Ssam upread(dev, uio) 6802616Swnj dev_t dev; 6819357Ssam struct uio *uio; 682264Sbill { 6832616Swnj register int unit = minor(dev) >> 3; 6842470Swnj 6852616Swnj if (unit >= NUP) 6869357Ssam return (ENXIO); 6879357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio)); 688264Sbill } 689264Sbill 6909357Ssam upwrite(dev, uio) 6912616Swnj dev_t dev; 6929357Ssam struct uio *uio; 693264Sbill { 6942616Swnj register int unit = minor(dev) >> 3; 6952470Swnj 6962616Swnj if (unit >= NUP) 6979357Ssam return (ENXIO); 6989357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio)); 699264Sbill } 700264Sbill 701266Sbill /* 702266Sbill * Correct an ECC error, and restart the i/o to complete 703266Sbill * the transfer if necessary. This is quite complicated because 704266Sbill * the transfer may be going to an odd memory address base and/or 705266Sbill * across a page boundary. 706266Sbill */ 7079548Ssam upecc(ui, flag) 7082983Swnj register struct uba_device *ui; 7099548Ssam int flag; 710264Sbill { 7112629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 7122395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 7132983Swnj register struct uba_ctlr *um = ui->ui_mi; 7142395Swnj register struct upst *st; 7152395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 716266Sbill register int i; 717264Sbill caddr_t addr; 718266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 719264Sbill int bn, cn, tn, sn; 720264Sbill 721264Sbill /* 722266Sbill * Npf is the number of sectors transferred before the sector 723266Sbill * containing the ECC error, and reg is the UBA register 724266Sbill * mapping (the first part of) the transfer. 725266Sbill * O is offset within a memory page of the first byte transferred. 726264Sbill */ 7279548Ssam if (flag == CONT) 7289548Ssam npf = bp->b_error; 7299548Ssam else 730*10858Ssam npf = btop((up->upwc * sizeof(short)) + bp->b_bcount); 7312571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 732264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 733264Sbill mask = up->upec2; 7343445Sroot #ifdef UPECCDEBUG 7353403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7363403Swnj up->upec1); 7373445Sroot #endif 7389548Ssam bn = dkblock(bp); 7399548Ssam st = &upst[ui->ui_type]; 7409548Ssam cn = bp->b_cylin; 7419548Ssam sn = bn%st->nspc + npf; 7429548Ssam tn = sn/st->nsect; 7439548Ssam sn %= st->nsect; 7449548Ssam cn += tn/st->ntrak; 7459548Ssam tn %= st->ntrak; 7462725Swnj ubapurge(um); 7479548Ssam um->um_tab.b_active=2; 748266Sbill /* 7499548Ssam * action taken depends on the flag 750266Sbill */ 7519548Ssam switch(flag){ 7529548Ssam case ECC: 7539548Ssam npf--; 7549548Ssam reg--; 7559548Ssam mask = up->upec2; 7569548Ssam printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 7579548Ssam 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 7589548Ssam /* 7599548Ssam * Flush the buffered data path, and compute the 7609548Ssam * byte and bit position of the error. The variable i 7619548Ssam * is the byte offset in the transfer, the variable byte 7629548Ssam * is the offset from a page boundary in main memory. 7639548Ssam */ 7649548Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 7659548Ssam bit = i&07; 7669548Ssam i = (i&~07)>>3; 7679548Ssam byte = i + o; 7689548Ssam /* 7699548Ssam * Correct while possible bits remain of mask. Since mask 7709548Ssam * contains 11 bits, we continue while the bit offset is > -11. 7719548Ssam * Also watch out for end of this block and the end of the whole 7729548Ssam * transfer. 7739548Ssam */ 7749548Ssam while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 7759548Ssam addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 7769548Ssam (byte & PGOFSET); 7773445Sroot #ifdef UPECCDEBUG 7789548Ssam printf("addr %x map reg %x\n", 7799548Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 7809548Ssam printf("old: %x, ", getmemc(addr)); 7813445Sroot #endif 7829548Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 7833445Sroot #ifdef UPECCDEBUG 7849548Ssam printf("new: %x\n", getmemc(addr)); 7853445Sroot #endif 7869548Ssam byte++; 7879548Ssam i++; 7889580Shelge bit -= 8; 7899548Ssam } 7909548Ssam if (up->upwc == 0) 7919548Ssam return (0); 7929548Ssam npf++; 7939548Ssam reg++; 7949548Ssam break; 7959548Ssam case BSE: 7969548Ssam /* 7979548Ssam * if not in bad sector table, return 0 7989548Ssam */ 7999548Ssam if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) 8009548Ssam return(0); 8019548Ssam /* 8029548Ssam * flag this one as bad 8039548Ssam */ 8049548Ssam bp->b_flags |= B_BAD; 8059548Ssam bp->b_error = npf + 1; 8069548Ssam #ifdef UPECCDEBUG 8079548Ssam printf("BSE: restart at %d\n",npf+1); 8089548Ssam #endif 8099548Ssam bn = st->ncyl * st->nspc -st->nsect - 1 - bn; 8109548Ssam cn = bn / st->nspc; 8119548Ssam sn = bn % st->nspc; 8129548Ssam tn = sn / st->nsect; 8139548Ssam sn %= st->nsect; 8149548Ssam up->upwc = -(512 / sizeof (short)); 8159548Ssam #ifdef UPECCDEBUG 8169548Ssam printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 8179548Ssam #endif 8189548Ssam break; 8199548Ssam case CONT: 8209548Ssam #ifdef UPECCDEBUG 8219548Ssam printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 8229548Ssam #endif 8239548Ssam bp->b_flags &= ~B_BAD; 8249548Ssam up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); 8259548Ssam if (up->upwc == 0) 8269548Ssam return(0); 8279548Ssam break; 828264Sbill } 8297183Sroot if (up->upwc == 0) { 8307183Sroot um->um_tab.b_active = 0; 831264Sbill return (0); 8327183Sroot } 833266Sbill /* 834266Sbill * Have to continue the transfer... clear the drive, 835266Sbill * and compute the position where the transfer is to continue. 836266Sbill * We have completed npf+1 sectors of the transfer already; 837266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 838266Sbill */ 8392629Swnj #ifdef notdef 8402629Swnj up->uper1 = 0; 8412629Swnj up->upcs1 |= UP_GO; 8422629Swnj #else 8432629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 844264Sbill up->updc = cn; 845266Sbill up->upda = (tn << 8) | sn; 8469548Ssam ubaddr = (int)ptob(reg) + o; 847266Sbill up->upba = ubaddr; 848266Sbill cmd = (ubaddr >> 8) & 0x300; 8499548Ssam cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; 8509548Ssam um->um_tab.b_errcnt = 0; 851266Sbill up->upcs1 = cmd; 8522629Swnj #endif 853264Sbill return (1); 854264Sbill } 855286Sbill 856286Sbill /* 857286Sbill * Reset driver after UBA init. 858286Sbill * Cancel software state of all pending transfers 859286Sbill * and restart all units and the controller. 860286Sbill */ 8612395Swnj upreset(uban) 8622931Swnj int uban; 863286Sbill { 8642983Swnj register struct uba_ctlr *um; 8652983Swnj register struct uba_device *ui; 8662395Swnj register sc21, unit; 867286Sbill 8682646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 8692470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 8702470Swnj um->um_alive == 0) 8712395Swnj continue; 8722931Swnj printf(" sc%d", sc21); 8732395Swnj um->um_tab.b_active = 0; 8742395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8752931Swnj up_softc[sc21].sc_recal = 0; 8766346Swnj up_softc[sc21].sc_wticks = 0; 8772571Swnj if (um->um_ubinfo) { 8782571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 8799357Ssam um->um_ubinfo = 0; 8802395Swnj } 8813445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 8822395Swnj for (unit = 0; unit < NUP; unit++) { 8832395Swnj if ((ui = updinfo[unit]) == 0) 8842395Swnj continue; 8852931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 8862395Swnj continue; 8872395Swnj uputab[unit].b_active = 0; 8882395Swnj (void) upustart(ui); 8892395Swnj } 8902395Swnj (void) upstart(um); 891286Sbill } 892286Sbill } 893313Sbill 894313Sbill /* 895313Sbill * Wake up every second and if an interrupt is pending 896313Sbill * but nothing has happened increment a counter. 8972931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 898313Sbill * and begin anew. 899313Sbill */ 900313Sbill upwatch() 901313Sbill { 9022983Swnj register struct uba_ctlr *um; 9032395Swnj register sc21, unit; 9042470Swnj register struct up_softc *sc; 905313Sbill 9062759Swnj timeout(upwatch, (caddr_t)0, hz); 9072646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9082395Swnj um = upminfo[sc21]; 9092470Swnj if (um == 0 || um->um_alive == 0) 9102470Swnj continue; 9112470Swnj sc = &up_softc[sc21]; 9122395Swnj if (um->um_tab.b_active == 0) { 9132395Swnj for (unit = 0; unit < NUP; unit++) 9142629Swnj if (uputab[unit].b_active && 9152629Swnj updinfo[unit]->ui_mi == um) 9162395Swnj goto active; 9172470Swnj sc->sc_wticks = 0; 9182395Swnj continue; 9192395Swnj } 9202931Swnj active: 9212470Swnj sc->sc_wticks++; 9222470Swnj if (sc->sc_wticks >= 20) { 9232470Swnj sc->sc_wticks = 0; 9242931Swnj printf("sc%d: lost interrupt\n", sc21); 9252646Swnj ubareset(um->um_ubanum); 9262395Swnj } 927313Sbill } 928313Sbill } 9292379Swnj 9302379Swnj #define DBSIZE 20 9312379Swnj 9322379Swnj updump(dev) 9332379Swnj dev_t dev; 9342379Swnj { 9352629Swnj struct updevice *upaddr; 9362379Swnj char *start; 9373107Swnj int num, blk, unit; 9382379Swnj struct size *sizes; 9392395Swnj register struct uba_regs *uba; 9402983Swnj register struct uba_device *ui; 9412379Swnj register short *rp; 9422395Swnj struct upst *st; 9436848Ssam register int retry; 9442379Swnj 9452395Swnj unit = minor(dev) >> 3; 9462889Swnj if (unit >= NUP) 9472889Swnj return (ENXIO); 9482470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 9492983Swnj ui = phys(struct uba_device *, updinfo[unit]); 9502889Swnj if (ui->ui_alive == 0) 9512889Swnj return (ENXIO); 9522395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 9532983Swnj ubainit(uba); 9542629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 9556848Ssam DELAY(5000000); 9562379Swnj num = maxfree; 9572379Swnj upaddr->upcs2 = unit; 9582983Swnj DELAY(100); 9596848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 9606848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 9616848Ssam upaddr->upof = UPOF_FMT22; 9626848Ssam retry = 0; 9636848Ssam do { 9646848Ssam DELAY(25); 9656848Ssam if (++retry > 527) 9666848Ssam break; 9676861Ssam } while ((upaddr->upds & UP_RDY) == 0); 9683445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 9692889Swnj return (EFAULT); 9709357Ssam start = 0; 9718489Sroot st = &upst[ui->ui_type]; 9722395Swnj sizes = phys(struct size *, st->sizes); 9732889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 9742889Swnj return (EINVAL); 9752379Swnj while (num > 0) { 9762379Swnj register struct pte *io; 9772379Swnj register int i; 9782379Swnj int cn, sn, tn; 9792379Swnj daddr_t bn; 9802379Swnj 9812379Swnj blk = num > DBSIZE ? DBSIZE : num; 9822395Swnj io = uba->uba_map; 9832379Swnj for (i = 0; i < blk; i++) 9842983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 9852379Swnj *(int *)io = 0; 9862379Swnj bn = dumplo + btop(start); 9872607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 9882607Swnj sn = bn%st->nspc; 9892607Swnj tn = sn/st->nsect; 9902607Swnj sn = sn%st->nsect; 9912379Swnj upaddr->updc = cn; 9922379Swnj rp = (short *) &upaddr->upda; 9932379Swnj *rp = (tn << 8) + sn; 9942379Swnj *--rp = 0; 9952379Swnj *--rp = -blk*NBPG / sizeof (short); 9962629Swnj *--rp = UP_GO|UP_WCOM; 9976848Ssam retry = 0; 9982379Swnj do { 9992379Swnj DELAY(25); 10006848Ssam if (++retry > 527) 10016848Ssam break; 10022629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 10036848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10046861Ssam printf("up%d: not ready", unit); 10056848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10066848Ssam printf("\n"); 10076848Ssam return (EIO); 10086848Ssam } 10096848Ssam printf(" (flakey)\n"); 10106848Ssam } 10113445Sroot if (upaddr->upds&UPDS_ERR) 10122889Swnj return (EIO); 10132379Swnj start += blk*NBPG; 10142379Swnj num -= blk; 10152379Swnj } 10162379Swnj return (0); 10172379Swnj } 10181902Swnj #endif 1019