1*8489Sroot /* up.c 4.45.1.1 82/10/10 */ 2264Sbill 31937Swnj #include "up.h" 42646Swnj #if NSC > 0 5264Sbill /* 6*8489Sroot * UNIBUS disk driver with: 7*8489Sroot * overlapped seeks, 8*8489Sroot * ECC recovery, and 9*8489Sroot * bad sector forwarding. 102889Swnj * 112889Swnj * TODO: 123445Sroot * Check that offset recovery code works 13264Sbill */ 14264Sbill 15264Sbill #include "../h/param.h" 16264Sbill #include "../h/systm.h" 17*8489Sroot #include "../h/cpu.h" 18*8489Sroot #include "../h/nexus.h" 19308Sbill #include "../h/dk.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" 25420Sbill #include "../h/pte.h" 26*8489Sroot #include "../h/mtpr.h" 272571Swnj #include "../h/vm.h" 28*8489Sroot #include "../h/ubavar.h" 29*8489Sroot #include "../h/ubareg.h" 302379Swnj #include "../h/cmap.h" 31*8489Sroot #include "../h/dkbad.h" 32*8489Sroot #include "../h/upreg.h" 33264Sbill 342395Swnj struct up_softc { 352395Swnj int sc_softas; 362607Swnj int sc_ndrive; 372395Swnj int sc_wticks; 382674Swnj int sc_recal; 392646Swnj } up_softc[NSC]; 40275Sbill 412395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 42264Sbill struct size 43264Sbill { 44264Sbill daddr_t nblocks; 45264Sbill int cyloff; 46264Sbill } up_sizes[8] = { 476436Swnj #ifdef ERNIE 486436Swnj 49324, 0, /* A=cyl 0 thru 26 */ 496436Swnj #else 50264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 516436Swnj #endif 52264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 53341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 54264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 55264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 563730Sroot #ifndef NOBADSECT 573730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 583730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 593730Sroot #else 603730Sroot 81472, 681, 613730Sroot 153824, 562, 623730Sroot #endif 63264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 642395Swnj }, fj_sizes[8] = { 652395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 662395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 672395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 682395Swnj 0, 0, 692395Swnj 0, 0, 702395Swnj 0, 0, 712395Swnj 0, 0, 723730Sroot #ifndef NOBADSECT 733730Sroot 213664, 155, /* H=cyl 155 thru 822 */ 743730Sroot #else 753730Sroot 213760, 155, 763730Sroot #endif 776851Ssam }, upam_sizes[8] = { 786305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 796305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 806305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 816602Ssam 27786, 668, 826602Ssam 27786, 723, 836602Ssam 125440, 778, 846305Sroot 181760, 668, /* G=cyl 668 thru 1022 */ 856305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 86264Sbill }; 872395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 88264Sbill 896346Swnj /* 906346Swnj * On a 780 upSDIST could be 2, but 916346Swnj * in the interest of 750's... 926346Swnj */ 936346Swnj #define _upSDIST 3 /* 1.5 msec */ 942395Swnj #define _upRDIST 4 /* 2.0 msec */ 95264Sbill 962395Swnj int upSDIST = _upSDIST; 972395Swnj int upRDIST = _upRDIST; 982395Swnj 992607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 1002983Swnj struct uba_ctlr *upminfo[NSC]; 1012983Swnj struct uba_device *updinfo[NUP]; 1026383Swnj #define UPIPUNITS 8 1036383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 1042395Swnj 1052607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 1062616Swnj struct uba_driver scdriver = 1072607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 1082395Swnj struct buf uputab[NUP]; 109*8489Sroot char upinit[NUP]; 1102395Swnj 1112395Swnj struct upst { 1122395Swnj short nsect; 1132395Swnj short ntrak; 1142395Swnj short nspc; 1152395Swnj short ncyl; 1162395Swnj struct size *sizes; 1172395Swnj } upst[] = { 1182607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 1192607Swnj /* 9300 actually has 815 cylinders... */ 1202395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 1216851Ssam 32, 16, 32*16, 1024, upam_sizes, /* ampex capricorn */ 1222395Swnj }; 1232395Swnj 1242629Swnj u_char up_offset[16] = { 125*8489Sroot UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 126*8489Sroot UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 127*8489Sroot UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 128*8489Sroot 0, 0, 0, 0 1292629Swnj }; 130264Sbill 1312616Swnj struct buf rupbuf[NUP]; 132*8489Sroot #ifndef NOBADSECT 133*8489Sroot struct buf bupbuf[NUP]; 134*8489Sroot struct dkbad upbad[NUP]; 135*8489Sroot #endif 136264Sbill 137264Sbill #define b_cylin b_resid 138264Sbill 139264Sbill #ifdef INTRLVE 140264Sbill daddr_t dkblock(); 141264Sbill #endif 1422395Swnj 1432395Swnj int upwstart, upwatch(); /* Have started guardian */ 1442470Swnj int upseek; 1452681Swnj int upwaitdry; 1462395Swnj 1472395Swnj /*ARGSUSED*/ 1482607Swnj upprobe(reg) 1492395Swnj caddr_t reg; 1502395Swnj { 1512459Swnj register int br, cvec; 1522459Swnj 1532607Swnj #ifdef lint 1542607Swnj br = 0; cvec = br; br = cvec; 1552607Swnj #endif 1562629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1572607Swnj DELAY(10); 1582629Swnj ((struct updevice *)reg)->upcs1 = 0; 159*8489Sroot return (1); 1602395Swnj } 1612395Swnj 1622607Swnj upslave(ui, reg) 1632983Swnj struct uba_device *ui; 1642395Swnj caddr_t reg; 1652395Swnj { 1662629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1672395Swnj 1682395Swnj upaddr->upcs1 = 0; /* conservative */ 1692607Swnj upaddr->upcs2 = ui->ui_slave; 1706843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1713445Sroot if (upaddr->upcs2&UPCS2_NED) { 1722629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1732395Swnj return (0); 1742395Swnj } 1752607Swnj return (1); 1762607Swnj } 1772607Swnj 1782607Swnj upattach(ui) 1792983Swnj register struct uba_device *ui; 1802607Swnj { 1812629Swnj register struct updevice *upaddr; 1822607Swnj 1832395Swnj if (upwstart == 0) { 1842759Swnj timeout(upwatch, (caddr_t)0, hz); 1852395Swnj upwstart++; 1862395Swnj } 1872571Swnj if (ui->ui_dk >= 0) 1882571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1892607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1902607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1912629Swnj upaddr = (struct updevice *)ui->ui_addr; 1922629Swnj upaddr->upcs1 = 0; 1932629Swnj upaddr->upcs2 = ui->ui_slave; 1943496Sroot upaddr->uphr = UPHR_MAXTRAK; 1953553Swnj if (upaddr->uphr == 9) 1963496Sroot ui->ui_type = 1; /* fujitsu hack */ 1976305Sroot else if (upaddr->uphr == 15) 1986305Sroot ui->ui_type = 2; /* ampex hack */ 1993496Sroot upaddr->upcs2 = UPCS2_CLR; 2002395Swnj } 201264Sbill 202264Sbill upstrategy(bp) 2032395Swnj register struct buf *bp; 204264Sbill { 2052983Swnj register struct uba_device *ui; 2062395Swnj register struct upst *st; 2072395Swnj register int unit; 2082470Swnj register struct buf *dp; 2092395Swnj int xunit = minor(bp->b_dev) & 07; 2102470Swnj long bn, sz; 211264Sbill 2122470Swnj sz = (bp->b_bcount+511) >> 9; 213264Sbill unit = dkunit(bp); 2142395Swnj if (unit >= NUP) 2152395Swnj goto bad; 2162395Swnj ui = updinfo[unit]; 2172395Swnj if (ui == 0 || ui->ui_alive == 0) 2182395Swnj goto bad; 2192395Swnj st = &upst[ui->ui_type]; 2202395Swnj if (bp->b_blkno < 0 || 2212395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2222395Swnj goto bad; 2232395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2246305Sroot (void) spl5(); 2252470Swnj dp = &uputab[ui->ui_unit]; 2262470Swnj disksort(dp, bp); 2272470Swnj if (dp->b_active == 0) { 2282395Swnj (void) upustart(ui); 2292395Swnj bp = &ui->ui_mi->um_tab; 2302395Swnj if (bp->b_actf && bp->b_active == 0) 2312395Swnj (void) upstart(ui->ui_mi); 232264Sbill } 2336305Sroot (void) spl0(); 2342395Swnj return; 2352395Swnj 2362395Swnj bad: 2372395Swnj bp->b_flags |= B_ERROR; 2382395Swnj iodone(bp); 2392395Swnj return; 240264Sbill } 241264Sbill 2422674Swnj /* 2432674Swnj * Unit start routine. 2442674Swnj * Seek the drive to be where the data is 2452674Swnj * and then generate another interrupt 2462674Swnj * to actually start the transfer. 2472674Swnj * If there is only one drive on the controller, 2482674Swnj * or we are very close to the data, don't 2492674Swnj * bother with the search. If called after 2502674Swnj * searching once, don't bother to look where 2512674Swnj * we are, just queue for transfer (to avoid 2522674Swnj * positioning forever without transferrring.) 2532674Swnj */ 2542395Swnj upustart(ui) 2552983Swnj register struct uba_device *ui; 256264Sbill { 257264Sbill register struct buf *bp, *dp; 2582983Swnj register struct uba_ctlr *um; 2592629Swnj register struct updevice *upaddr; 2602395Swnj register struct upst *st; 261264Sbill daddr_t bn; 2622674Swnj int sn, csn; 2632607Swnj /* 2642607Swnj * The SC21 cancels commands if you just say 2652629Swnj * cs1 = UP_IE 2662607Swnj * so we are cautious about handling of cs1. 2672607Swnj * Also don't bother to clear as bits other than in upintr(). 2682607Swnj */ 2692674Swnj int didie = 0; 2702674Swnj 2712674Swnj if (ui == 0) 2722674Swnj return (0); 2732983Swnj um = ui->ui_mi; 2742395Swnj dk_busy &= ~(1<<ui->ui_dk); 2752395Swnj dp = &uputab[ui->ui_unit]; 276266Sbill if ((bp = dp->b_actf) == NULL) 277268Sbill goto out; 2782674Swnj /* 2792674Swnj * If the controller is active, just remember 2802674Swnj * that this device would like to be positioned... 2812674Swnj * if we tried to position now we would confuse the SC21. 2822674Swnj */ 2832395Swnj if (um->um_tab.b_active) { 2842459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 285275Sbill return (0); 286275Sbill } 2872674Swnj /* 2882674Swnj * If we have already positioned this drive, 2892674Swnj * then just put it on the ready queue. 2902674Swnj */ 291276Sbill if (dp->b_active) 292276Sbill goto done; 293276Sbill dp->b_active = 1; 2942629Swnj upaddr = (struct updevice *)um->um_addr; 2952395Swnj upaddr->upcs2 = ui->ui_slave; 2962674Swnj /* 2972674Swnj * If drive has just come up, 2982674Swnj * setup the pack. 2992674Swnj */ 300*8489Sroot if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { 301*8489Sroot #ifndef NOBADSECT 302*8489Sroot struct buf *bbp = &bupbuf[ui->ui_unit]; 303*8489Sroot #endif 3042607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 305*8489Sroot upinit[ui->ui_unit] = 1; 3062629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3072629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3083445Sroot upaddr->upof = UPOF_FMT22; 309268Sbill didie = 1; 310*8489Sroot #ifndef NOBADSECT 311*8489Sroot st = &upst[ui->ui_type]; 312*8489Sroot bbp->b_flags = B_READ|B_BUSY; 313*8489Sroot bbp->b_dev = bp->b_dev; 314*8489Sroot bbp->b_bcount = 512; 315*8489Sroot bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; 316*8489Sroot bbp->b_blkno = st->ncyl * st->nspc - st->nsect; 317*8489Sroot bbp->b_cylin = st->ncyl - 1; 318*8489Sroot dp->b_actf = bbp; 319*8489Sroot bbp->av_forw = bp; 320*8489Sroot bp = bbp; 321*8489Sroot #endif 322264Sbill } 3232674Swnj /* 3242674Swnj * If drive is offline, forget about positioning. 3252674Swnj */ 3263445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 327275Sbill goto done; 3282674Swnj /* 3292674Swnj * If there is only one drive, 3302674Swnj * dont bother searching. 3312674Swnj */ 3322607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3332607Swnj goto done; 3342674Swnj /* 3352674Swnj * Figure out where this transfer is going to 3362674Swnj * and see if we are close enough to justify not searching. 3372674Swnj */ 3382395Swnj st = &upst[ui->ui_type]; 339264Sbill bn = dkblock(bp); 3402395Swnj sn = bn%st->nspc; 3412395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 3422674Swnj if (bp->b_cylin - upaddr->updc) 343266Sbill goto search; /* Not on-cylinder */ 344275Sbill else if (upseek) 345275Sbill goto done; /* Ok just to be on-cylinder */ 346264Sbill csn = (upaddr->upla>>6) - sn - 1; 347266Sbill if (csn < 0) 3482395Swnj csn += st->nsect; 3492395Swnj if (csn > st->nsect - upRDIST) 350264Sbill goto done; 351264Sbill search: 3522674Swnj upaddr->updc = bp->b_cylin; 3532674Swnj /* 3542674Swnj * Not on cylinder at correct position, 3552674Swnj * seek/search. 3562674Swnj */ 357275Sbill if (upseek) 3582629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3592470Swnj else { 360275Sbill upaddr->upda = sn; 3612629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 362275Sbill } 363268Sbill didie = 1; 3642674Swnj /* 3652674Swnj * Mark unit busy for iostat. 3662674Swnj */ 3672395Swnj if (ui->ui_dk >= 0) { 3682395Swnj dk_busy |= 1<<ui->ui_dk; 3692395Swnj dk_seek[ui->ui_dk]++; 370264Sbill } 371268Sbill goto out; 372264Sbill done: 3732674Swnj /* 3742674Swnj * Device is ready to go. 3752674Swnj * Put it on the ready queue for the controller 3762674Swnj * (unless its already there.) 3772674Swnj */ 3782629Swnj if (dp->b_active != 2) { 3792629Swnj dp->b_forw = NULL; 3802629Swnj if (um->um_tab.b_actf == NULL) 3812629Swnj um->um_tab.b_actf = dp; 3822629Swnj else 3832629Swnj um->um_tab.b_actl->b_forw = dp; 3842629Swnj um->um_tab.b_actl = dp; 3852629Swnj dp->b_active = 2; 3862629Swnj } 387268Sbill out: 388268Sbill return (didie); 389264Sbill } 390264Sbill 3912674Swnj /* 3922674Swnj * Start up a transfer on a drive. 3932674Swnj */ 3942395Swnj upstart(um) 3952983Swnj register struct uba_ctlr *um; 396264Sbill { 397264Sbill register struct buf *bp, *dp; 3982983Swnj register struct uba_device *ui; 3992629Swnj register struct updevice *upaddr; 4002470Swnj struct upst *st; 401264Sbill daddr_t bn; 4022681Swnj int dn, sn, tn, cmd, waitdry; 403264Sbill 404264Sbill loop: 4052674Swnj /* 4062674Swnj * Pull a request off the controller queue 4072674Swnj */ 4082395Swnj if ((dp = um->um_tab.b_actf) == NULL) 409268Sbill return (0); 410264Sbill if ((bp = dp->b_actf) == NULL) { 4112395Swnj um->um_tab.b_actf = dp->b_forw; 412264Sbill goto loop; 413264Sbill } 4142674Swnj /* 4152674Swnj * Mark controller busy, and 4162674Swnj * determine destination of this request. 4172674Swnj */ 4182395Swnj um->um_tab.b_active++; 4192395Swnj ui = updinfo[dkunit(bp)]; 420264Sbill bn = dkblock(bp); 4212395Swnj dn = ui->ui_slave; 4222395Swnj st = &upst[ui->ui_type]; 4232395Swnj sn = bn%st->nspc; 4242395Swnj tn = sn/st->nsect; 4252395Swnj sn %= st->nsect; 4262629Swnj upaddr = (struct updevice *)ui->ui_addr; 4272674Swnj /* 4282674Swnj * Select drive if not selected already. 4292674Swnj */ 4302674Swnj if ((upaddr->upcs2&07) != dn) 4312674Swnj upaddr->upcs2 = dn; 4322674Swnj /* 4332674Swnj * Check that it is ready and online 4342674Swnj */ 4352681Swnj waitdry = 0; 4363445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4377036Swnj printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds); 4382681Swnj if (++waitdry > 512) 4392681Swnj break; 4402681Swnj upwaitdry++; 4412681Swnj } 4423445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4432931Swnj printf("up%d: not ready", dkunit(bp)); 4443445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4452607Swnj printf("\n"); 4462395Swnj um->um_tab.b_active = 0; 4472395Swnj um->um_tab.b_errcnt = 0; 448893Sbill dp->b_actf = bp->av_forw; 449893Sbill dp->b_active = 0; 450893Sbill bp->b_flags |= B_ERROR; 451893Sbill iodone(bp); 452893Sbill goto loop; 453893Sbill } 4542674Swnj /* 4552674Swnj * Oh, well, sometimes this 4562674Swnj * happens, for reasons unknown. 4572674Swnj */ 4582629Swnj printf(" (flakey)\n"); 459264Sbill } 4602674Swnj /* 4612674Swnj * Setup for the transfer, and get in the 4622674Swnj * UNIBUS adaptor queue. 4632674Swnj */ 4642424Skre upaddr->updc = bp->b_cylin; 465264Sbill upaddr->upda = (tn << 8) + sn; 466264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 467264Sbill if (bp->b_flags & B_READ) 4682629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 469264Sbill else 4702629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4712571Swnj um->um_cmd = cmd; 4723107Swnj (void) ubago(ui); 473268Sbill return (1); 474264Sbill } 475264Sbill 4762674Swnj /* 4772674Swnj * Now all ready to go, stuff the registers. 4782674Swnj */ 4792571Swnj updgo(um) 4802983Swnj struct uba_ctlr *um; 4812395Swnj { 4822629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4832470Swnj 4846953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 4852571Swnj upaddr->upba = um->um_ubinfo; 4862571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4872395Swnj } 4882395Swnj 4892674Swnj /* 4902674Swnj * Handle a disk interrupt. 4912674Swnj */ 4922707Swnj upintr(sc21) 4932395Swnj register sc21; 494264Sbill { 495264Sbill register struct buf *bp, *dp; 4962983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4972983Swnj register struct uba_device *ui; 4982629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 499264Sbill register unit; 5002470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 5012607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 5022681Swnj int needie = 1, waitdry; 503264Sbill 5042470Swnj sc->sc_wticks = 0; 5052607Swnj sc->sc_softas = 0; 5062674Swnj /* 5072674Swnj * If controller wasn't transferring, then this is an 5082674Swnj * interrupt for attention status on seeking drives. 5092674Swnj * Just service them. 5102674Swnj */ 5116346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 5122674Swnj if (upaddr->upcs1 & UP_TRE) 5132674Swnj upaddr->upcs1 = UP_TRE; 5142674Swnj goto doattn; 5152674Swnj } 5166953Swnj um->um_tab.b_active = 1; 5172674Swnj /* 5182674Swnj * Get device and block structures, and a pointer 5192983Swnj * to the uba_device for the drive. Select the drive. 5202674Swnj */ 5212674Swnj dp = um->um_tab.b_actf; 5222674Swnj bp = dp->b_actf; 5232674Swnj ui = updinfo[dkunit(bp)]; 5242674Swnj dk_busy &= ~(1 << ui->ui_dk); 5252674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5262395Swnj upaddr->upcs2 = ui->ui_slave; 527*8489Sroot #ifndef NOBADSECT 528*8489Sroot if (bp->b_flags&B_BAD) { 529*8489Sroot if (upecc(ui, CONT)) 530*8489Sroot return; 531*8489Sroot } 532*8489Sroot #endif 5332674Swnj /* 5342674Swnj * Check for and process errors on 5352674Swnj * either the drive or the controller. 5362674Swnj */ 5373445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5382681Swnj waitdry = 0; 5393445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5402681Swnj if (++waitdry > 512) 5412681Swnj break; 5422681Swnj upwaitdry++; 5432681Swnj } 5443445Sroot if (upaddr->uper1&UPER1_WLE) { 5452674Swnj /* 5462674Swnj * Give up on write locked devices 5472674Swnj * immediately. 5482674Swnj */ 5492931Swnj printf("up%d: write locked\n", dkunit(bp)); 5502674Swnj bp->b_flags |= B_ERROR; 5512674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5522674Swnj /* 5532674Swnj * After 28 retries (16 without offset, and 5542674Swnj * 12 with offset positioning) give up. 5552674Swnj */ 556*8489Sroot hard: 5572931Swnj harderr(bp, "up"); 558*8489Sroot printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", 559*8489Sroot upaddr->updc, ((upaddr->upda)>>8)&077, 560*8489Sroot (upaddr->upda)&037, 561*8489Sroot upaddr->upcs2, UPCS2_BITS, 562*8489Sroot upaddr->uper1, UPER1_BITS, 563*8489Sroot upaddr->uper2, UPER2_BITS); 5642674Swnj bp->b_flags |= B_ERROR; 565*8489Sroot } else if (upaddr->uper2 & UPER2_BSE) { 566*8489Sroot #ifndef NOBADSECT 567*8489Sroot if (upecc(ui, BSE)) 568*8489Sroot return; 569*8489Sroot else 570*8489Sroot #endif 571*8489Sroot goto hard; 5722674Swnj } else { 5732674Swnj /* 5742674Swnj * Retriable error. 5752674Swnj * If a soft ecc, correct it (continuing 5762674Swnj * by returning if necessary. 5772674Swnj * Otherwise fall through and retry the transfer 5782674Swnj */ 5797183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 580*8489Sroot if (upecc(ui, ECC)) 5812629Swnj return; 5827183Sroot } else 5837183Sroot um->um_tab.b_active = 0; /* force retry */ 5842674Swnj } 5852674Swnj /* 5862674Swnj * Clear drive error and, every eight attempts, 5872674Swnj * (starting with the fourth) 5882674Swnj * recalibrate to clear the slate. 5892674Swnj */ 5902674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5912674Swnj needie = 0; 5923182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5932674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5943160Swnj sc->sc_recal = 0; 5953160Swnj goto nextrecal; 5962674Swnj } 5972674Swnj } 5982674Swnj /* 5993160Swnj * Advance recalibration finite state machine 6003160Swnj * if recalibrate in progress, through 6013160Swnj * RECAL 6023160Swnj * SEEK 6033160Swnj * OFFSET (optional) 6043160Swnj * RETRY 6052674Swnj */ 6063160Swnj switch (sc->sc_recal) { 6073160Swnj 6083160Swnj case 1: 6093160Swnj upaddr->updc = bp->b_cylin; 6103160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 6113160Swnj goto nextrecal; 6123160Swnj case 2: 6133160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 6143160Swnj goto donerecal; 6153445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 6163160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 6173160Swnj goto nextrecal; 6183160Swnj nextrecal: 6193160Swnj sc->sc_recal++; 6203160Swnj um->um_tab.b_active = 1; 6213160Swnj return; 6223160Swnj donerecal: 6233160Swnj case 3: 6242674Swnj sc->sc_recal = 0; 6253160Swnj um->um_tab.b_active = 0; 6263160Swnj break; 6272674Swnj } 6282674Swnj /* 6292674Swnj * If still ``active'', then don't need any more retries. 6302674Swnj */ 6312674Swnj if (um->um_tab.b_active) { 6322674Swnj /* 6332674Swnj * If we were offset positioning, 6342674Swnj * return to centerline. 6352674Swnj */ 6362674Swnj if (um->um_tab.b_errcnt >= 16) { 6373445Sroot upaddr->upof = UPOF_FMT22; 6382674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6393445Sroot while (upaddr->upds & UPDS_PIP) 6402674Swnj DELAY(25); 641268Sbill needie = 0; 642264Sbill } 6432674Swnj um->um_tab.b_active = 0; 6442674Swnj um->um_tab.b_errcnt = 0; 6452674Swnj um->um_tab.b_actf = dp->b_forw; 6462674Swnj dp->b_active = 0; 6472674Swnj dp->b_errcnt = 0; 6482674Swnj dp->b_actf = bp->av_forw; 6492674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6502674Swnj iodone(bp); 6512674Swnj /* 6522674Swnj * If this unit has more work to do, 6532674Swnj * then start it up right away. 6542674Swnj */ 6552674Swnj if (dp->b_actf) 6562674Swnj if (upustart(ui)) 657268Sbill needie = 0; 658264Sbill } 6592674Swnj as &= ~(1<<ui->ui_slave); 6603403Swnj /* 6613403Swnj * Release unibus resources and flush data paths. 6623403Swnj */ 6633403Swnj ubadone(um); 6642674Swnj doattn: 6652674Swnj /* 6662674Swnj * Process other units which need attention. 6672674Swnj * For each unit which needs attention, call 6682674Swnj * the unit start routine to place the slave 6692674Swnj * on the controller device queue. 6702674Swnj */ 6713160Swnj while (unit = ffs(as)) { 6723160Swnj unit--; /* was 1 origin */ 6733160Swnj as &= ~(1<<unit); 6743160Swnj upaddr->upas = 1<<unit; 6756383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 6763160Swnj needie = 0; 6773160Swnj } 6782674Swnj /* 6792674Swnj * If the controller is not transferring, but 6802674Swnj * there are devices ready to transfer, start 6812674Swnj * the controller. 6822674Swnj */ 6832395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6842395Swnj if (upstart(um)) 685268Sbill needie = 0; 686275Sbill if (needie) 6872629Swnj upaddr->upcs1 = UP_IE; 688264Sbill } 689264Sbill 690*8489Sroot upread(dev) 6912616Swnj dev_t dev; 692264Sbill { 6932616Swnj register int unit = minor(dev) >> 3; 6942470Swnj 6952616Swnj if (unit >= NUP) 696*8489Sroot u.u_error = ENXIO; 697*8489Sroot else 698*8489Sroot physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 699264Sbill } 700264Sbill 701*8489Sroot upwrite(dev) 7022616Swnj dev_t dev; 703264Sbill { 7042616Swnj register int unit = minor(dev) >> 3; 7052470Swnj 7062616Swnj if (unit >= NUP) 707*8489Sroot u.u_error = ENXIO; 708*8489Sroot else 709*8489Sroot physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 710264Sbill } 711264Sbill 712266Sbill /* 713266Sbill * Correct an ECC error, and restart the i/o to complete 714266Sbill * the transfer if necessary. This is quite complicated because 715266Sbill * the transfer may be going to an odd memory address base and/or 716266Sbill * across a page boundary. 717266Sbill */ 718*8489Sroot upecc(ui, flag) 7192983Swnj register struct uba_device *ui; 720*8489Sroot int flag; 721264Sbill { 7222629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 7232395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 7242983Swnj register struct uba_ctlr *um = ui->ui_mi; 7252395Swnj register struct upst *st; 7262395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 727266Sbill register int i; 728264Sbill caddr_t addr; 729266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 730264Sbill int bn, cn, tn, sn; 731264Sbill 732264Sbill /* 733266Sbill * Npf is the number of sectors transferred before the sector 734266Sbill * containing the ECC error, and reg is the UBA register 735266Sbill * mapping (the first part of) the transfer. 736266Sbill * O is offset within a memory page of the first byte transferred. 737264Sbill */ 738*8489Sroot #ifndef NOBADSECT 739*8489Sroot if (flag == CONT) 740*8489Sroot npf = bp->b_error; 741*8489Sroot else 742*8489Sroot #endif 743*8489Sroot npf = btop((up->upwc * sizeof(short)) + bp->b_bcount); 7442571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 745264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 7462983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 7472889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 748264Sbill mask = up->upec2; 7493445Sroot #ifdef UPECCDEBUG 7503403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7513403Swnj up->upec1); 7523445Sroot #endif 753*8489Sroot bn = dkblock(bp); 754*8489Sroot st = &upst[ui->ui_type]; 755*8489Sroot cn = bp->b_cylin; 756*8489Sroot sn = bn%st->nspc + npf; 757*8489Sroot tn = sn/st->nsect; 758*8489Sroot sn %= st->nsect; 759*8489Sroot cn += tn/st->ntrak; 760*8489Sroot tn %= st->ntrak; 7612725Swnj ubapurge(um); 762*8489Sroot um->um_tab.b_active=2; 763266Sbill /* 764*8489Sroot * action taken depends on the flag 765266Sbill */ 766*8489Sroot switch(flag){ 767*8489Sroot case ECC: 768*8489Sroot npf--; 769*8489Sroot reg--; 770*8489Sroot mask = up->upec2; 771*8489Sroot printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 772*8489Sroot 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 773*8489Sroot /* 774*8489Sroot * Flush the buffered data path, and compute the 775*8489Sroot * byte and bit position of the error. The variable i 776*8489Sroot * is the byte offset in the transfer, the variable byte 777*8489Sroot * is the offset from a page boundary in main memory. 778*8489Sroot */ 779*8489Sroot i = up->upec1 - 1; /* -1 makes 0 origin */ 780*8489Sroot bit = i&07; 781*8489Sroot i = (i&~07)>>3; 782*8489Sroot byte = i + o; 783*8489Sroot /* 784*8489Sroot * Correct while possible bits remain of mask. Since mask 785*8489Sroot * contains 11 bits, we continue while the bit offset is > -11. 786*8489Sroot * Also watch out for end of this block and the end of the whole 787*8489Sroot * transfer. 788*8489Sroot */ 789*8489Sroot while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 790*8489Sroot addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 791*8489Sroot (byte & PGOFSET); 7923445Sroot #ifdef UPECCDEBUG 793*8489Sroot printf("addr %x map reg %x\n", 794*8489Sroot addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 795*8489Sroot printf("old: %x, ", getmemc(addr)); 7963445Sroot #endif 797*8489Sroot putmemc(addr, getmemc(addr)^(mask<<bit)); 7983445Sroot #ifdef UPECCDEBUG 799*8489Sroot printf("new: %x\n", getmemc(addr)); 8003445Sroot #endif 801*8489Sroot byte++; 802*8489Sroot i++; 803*8489Sroot } 804*8489Sroot if (up->upwc == 0) 805*8489Sroot return (0); 806*8489Sroot npf++; 807*8489Sroot reg++; 808*8489Sroot break; 809*8489Sroot #ifndef NOBADSECT 810*8489Sroot case BSE: 811*8489Sroot /* 812*8489Sroot * if not in bad sector table, return 0 813*8489Sroot */ 814*8489Sroot if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) 815*8489Sroot return(0); 816*8489Sroot /* 817*8489Sroot * flag this one as bad 818*8489Sroot */ 819*8489Sroot bp->b_flags |= B_BAD; 820*8489Sroot bp->b_error = npf + 1; 821*8489Sroot #ifdef UPECCDEBUG 822*8489Sroot printf("BSE: restart at %d\n",npf+1); 823*8489Sroot #endif 824*8489Sroot bn = st->ncyl * st->nspc -st->nsect - 1 - bn; 825*8489Sroot cn = bn / st->nspc; 826*8489Sroot sn = bn % st->nspc; 827*8489Sroot tn = sn / st->nsect; 828*8489Sroot sn %= st->nsect; 829*8489Sroot up->upwc = -(512 / sizeof (short)); 830*8489Sroot #ifdef UPECCDEBUG 831*8489Sroot printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 832*8489Sroot #endif 833*8489Sroot break; 834*8489Sroot case CONT: 835*8489Sroot #ifdef UPECCDEBUG 836*8489Sroot printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 837*8489Sroot #endif 838*8489Sroot bp->b_flags &= ~B_BAD; 839*8489Sroot up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); 840*8489Sroot if (up->upwc == 0) 841*8489Sroot return(0); 842*8489Sroot break; 843*8489Sroot #endif 844264Sbill } 8457183Sroot if (up->upwc == 0) { 8467183Sroot um->um_tab.b_active = 0; 847264Sbill return (0); 8487183Sroot } 849266Sbill /* 850266Sbill * Have to continue the transfer... clear the drive, 851266Sbill * and compute the position where the transfer is to continue. 852266Sbill * We have completed npf+1 sectors of the transfer already; 853266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 854266Sbill */ 8552629Swnj #ifdef notdef 8562629Swnj up->uper1 = 0; 8572629Swnj up->upcs1 |= UP_GO; 8582629Swnj #else 8592629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 860264Sbill up->updc = cn; 861266Sbill up->upda = (tn << 8) | sn; 862*8489Sroot ubaddr = (int)ptob(reg) + o; 863266Sbill up->upba = ubaddr; 864266Sbill cmd = (ubaddr >> 8) & 0x300; 865*8489Sroot cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; 866*8489Sroot um->um_tab.b_errcnt = 0; 867266Sbill up->upcs1 = cmd; 8682629Swnj #endif 869264Sbill return (1); 870264Sbill } 871286Sbill 872286Sbill /* 873286Sbill * Reset driver after UBA init. 874286Sbill * Cancel software state of all pending transfers 875286Sbill * and restart all units and the controller. 876286Sbill */ 8772395Swnj upreset(uban) 8782931Swnj int uban; 879286Sbill { 8802983Swnj register struct uba_ctlr *um; 8812983Swnj register struct uba_device *ui; 8822395Swnj register sc21, unit; 883286Sbill 8842646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 8852470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 8862470Swnj um->um_alive == 0) 8872395Swnj continue; 8882931Swnj printf(" sc%d", sc21); 8892395Swnj um->um_tab.b_active = 0; 8902395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8912931Swnj up_softc[sc21].sc_recal = 0; 8926346Swnj up_softc[sc21].sc_wticks = 0; 8932571Swnj if (um->um_ubinfo) { 8942571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 8952616Swnj ubadone(um); 8962395Swnj } 8973445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 8982395Swnj for (unit = 0; unit < NUP; unit++) { 8992395Swnj if ((ui = updinfo[unit]) == 0) 9002395Swnj continue; 9012931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 9022395Swnj continue; 9032395Swnj uputab[unit].b_active = 0; 9042395Swnj (void) upustart(ui); 9052395Swnj } 9062395Swnj (void) upstart(um); 907286Sbill } 908286Sbill } 909313Sbill 910313Sbill /* 911313Sbill * Wake up every second and if an interrupt is pending 912313Sbill * but nothing has happened increment a counter. 9132931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 914313Sbill * and begin anew. 915313Sbill */ 916313Sbill upwatch() 917313Sbill { 9182983Swnj register struct uba_ctlr *um; 9192395Swnj register sc21, unit; 9202470Swnj register struct up_softc *sc; 921313Sbill 9222759Swnj timeout(upwatch, (caddr_t)0, hz); 9232646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9242395Swnj um = upminfo[sc21]; 9252470Swnj if (um == 0 || um->um_alive == 0) 9262470Swnj continue; 9272470Swnj sc = &up_softc[sc21]; 9282395Swnj if (um->um_tab.b_active == 0) { 9292395Swnj for (unit = 0; unit < NUP; unit++) 9302629Swnj if (uputab[unit].b_active && 9312629Swnj updinfo[unit]->ui_mi == um) 9322395Swnj goto active; 9332470Swnj sc->sc_wticks = 0; 9342395Swnj continue; 9352395Swnj } 9362931Swnj active: 9372470Swnj sc->sc_wticks++; 9382470Swnj if (sc->sc_wticks >= 20) { 9392470Swnj sc->sc_wticks = 0; 9402931Swnj printf("sc%d: lost interrupt\n", sc21); 9412646Swnj ubareset(um->um_ubanum); 9422395Swnj } 943313Sbill } 944313Sbill } 9452379Swnj 9462379Swnj #define DBSIZE 20 9472379Swnj 9482379Swnj updump(dev) 9492379Swnj dev_t dev; 9502379Swnj { 9512629Swnj struct updevice *upaddr; 9522379Swnj char *start; 9533107Swnj int num, blk, unit; 9542379Swnj struct size *sizes; 9552395Swnj register struct uba_regs *uba; 9562983Swnj register struct uba_device *ui; 9572379Swnj register short *rp; 9582395Swnj struct upst *st; 9596848Ssam register int retry; 9602379Swnj 9612395Swnj unit = minor(dev) >> 3; 9622889Swnj if (unit >= NUP) 9632889Swnj return (ENXIO); 9642470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 9652983Swnj ui = phys(struct uba_device *, updinfo[unit]); 9662889Swnj if (ui->ui_alive == 0) 9672889Swnj return (ENXIO); 9682395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 9692983Swnj ubainit(uba); 9702629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 9716848Ssam DELAY(5000000); 9722379Swnj num = maxfree; 9732379Swnj upaddr->upcs2 = unit; 9742983Swnj DELAY(100); 9756848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 9766848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 9776848Ssam upaddr->upof = UPOF_FMT22; 9786848Ssam retry = 0; 9796848Ssam do { 9806848Ssam DELAY(25); 9816848Ssam if (++retry > 527) 9826848Ssam break; 9836861Ssam } while ((upaddr->upds & UP_RDY) == 0); 9843445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 9852889Swnj return (EFAULT); 986*8489Sroot st = &upst[ui->ui_type]; 9876848Ssam start = 0; 9882395Swnj sizes = phys(struct size *, st->sizes); 9892889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 9902889Swnj return (EINVAL); 9912379Swnj while (num > 0) { 9922379Swnj register struct pte *io; 9932379Swnj register int i; 9942379Swnj int cn, sn, tn; 9952379Swnj daddr_t bn; 9962379Swnj 9972379Swnj blk = num > DBSIZE ? DBSIZE : num; 9982395Swnj io = uba->uba_map; 9992379Swnj for (i = 0; i < blk; i++) 10002983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 10012379Swnj *(int *)io = 0; 10022379Swnj bn = dumplo + btop(start); 10032607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 10042607Swnj sn = bn%st->nspc; 10052607Swnj tn = sn/st->nsect; 10062607Swnj sn = sn%st->nsect; 10072379Swnj upaddr->updc = cn; 10082379Swnj rp = (short *) &upaddr->upda; 10092379Swnj *rp = (tn << 8) + sn; 10102379Swnj *--rp = 0; 10112379Swnj *--rp = -blk*NBPG / sizeof (short); 10122629Swnj *--rp = UP_GO|UP_WCOM; 10136848Ssam retry = 0; 10142379Swnj do { 10152379Swnj DELAY(25); 10166848Ssam if (++retry > 527) 10176848Ssam break; 10182629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 10196848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10206861Ssam printf("up%d: not ready", unit); 10216848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10226848Ssam printf("\n"); 10236848Ssam return (EIO); 10246848Ssam } 10256848Ssam printf(" (flakey)\n"); 10266848Ssam } 10273445Sroot if (upaddr->upds&UPDS_ERR) 10282889Swnj return (EIO); 10292379Swnj start += blk*NBPG; 10302379Swnj num -= blk; 10312379Swnj } 10322379Swnj return (0); 10332379Swnj } 10341902Swnj #endif 1035