1*9782Ssam /* up.c 4.64 82/12/17 */ 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 */ 14*9782Ssam #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 */ 43264Sbill struct size 44264Sbill { 45264Sbill daddr_t nblocks; 46264Sbill int cyloff; 47264Sbill } up_sizes[8] = { 486436Swnj #ifdef ERNIE 496436Swnj 49324, 0, /* A=cyl 0 thru 26 */ 506436Swnj #else 51264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 526436Swnj #endif 53264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 54341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 55264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 56264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 573730Sroot #ifndef NOBADSECT 583730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 593730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 603730Sroot #else 613730Sroot 81472, 681, 623730Sroot 153824, 562, 633730Sroot #endif 64264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 652395Swnj }, fj_sizes[8] = { 662395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 672395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 682395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 692395Swnj 0, 0, 702395Swnj 0, 0, 712395Swnj 0, 0, 722395Swnj 0, 0, 733730Sroot #ifndef NOBADSECT 743730Sroot 213664, 155, /* H=cyl 155 thru 822 */ 753730Sroot #else 763730Sroot 213760, 155, 773730Sroot #endif 786851Ssam }, upam_sizes[8] = { 796305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 806305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 816305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 826602Ssam 27786, 668, 836602Ssam 27786, 723, 846602Ssam 125440, 778, 856305Sroot 181760, 668, /* G=cyl 668 thru 1022 */ 866305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 87264Sbill }; 882395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 89264Sbill 906346Swnj /* 916346Swnj * On a 780 upSDIST could be 2, but 926346Swnj * in the interest of 750's... 936346Swnj */ 946346Swnj #define _upSDIST 3 /* 1.5 msec */ 952395Swnj #define _upRDIST 4 /* 2.0 msec */ 96264Sbill 972395Swnj int upSDIST = _upSDIST; 982395Swnj int upRDIST = _upRDIST; 992395Swnj 1002607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 1012983Swnj struct uba_ctlr *upminfo[NSC]; 1022983Swnj struct uba_device *updinfo[NUP]; 1036383Swnj #define UPIPUNITS 8 1046383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 1052395Swnj 1062607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 1072616Swnj struct uba_driver scdriver = 1082607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 1092395Swnj struct buf uputab[NUP]; 1109548Ssam char upinit[NUP]; 1112395Swnj 1122395Swnj struct upst { 1132395Swnj short nsect; 1142395Swnj short ntrak; 1152395Swnj short nspc; 1162395Swnj short ncyl; 1172395Swnj struct size *sizes; 1182395Swnj } upst[] = { 1192607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 1202607Swnj /* 9300 actually has 815 cylinders... */ 1212395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 1226851Ssam 32, 16, 32*16, 1024, upam_sizes, /* ampex capricorn */ 1232395Swnj }; 1242395Swnj 1252629Swnj u_char up_offset[16] = { 1269548Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1279548Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1289548Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1299548Ssam 0, 0, 0, 0 1302629Swnj }; 131264Sbill 1322616Swnj struct buf rupbuf[NUP]; 1339548Ssam #ifndef NOBADSECT 1349548Ssam struct buf bupbuf[NUP]; 1359548Ssam struct dkbad upbad[NUP]; 1369548Ssam #endif 137264Sbill 138264Sbill #define b_cylin b_resid 139264Sbill 140264Sbill #ifdef INTRLVE 141264Sbill daddr_t dkblock(); 142264Sbill #endif 1432395Swnj 1442395Swnj int upwstart, upwatch(); /* Have started guardian */ 1452470Swnj int upseek; 1462681Swnj int upwaitdry; 1472395Swnj 1482395Swnj /*ARGSUSED*/ 1492607Swnj upprobe(reg) 1502395Swnj caddr_t reg; 1512395Swnj { 1522459Swnj register int br, cvec; 1532459Swnj 1542607Swnj #ifdef lint 1552607Swnj br = 0; cvec = br; br = cvec; 1562607Swnj #endif 1572629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1582607Swnj DELAY(10); 1592629Swnj ((struct updevice *)reg)->upcs1 = 0; 1609357Ssam return (sizeof (struct updevice)); 1612395Swnj } 1622395Swnj 1632607Swnj upslave(ui, reg) 1642983Swnj struct uba_device *ui; 1652395Swnj caddr_t reg; 1662395Swnj { 1672629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1682395Swnj 1692395Swnj upaddr->upcs1 = 0; /* conservative */ 1702607Swnj upaddr->upcs2 = ui->ui_slave; 1716843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1723445Sroot if (upaddr->upcs2&UPCS2_NED) { 1732629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1742395Swnj return (0); 1752395Swnj } 1762607Swnj return (1); 1772607Swnj } 1782607Swnj 1792607Swnj upattach(ui) 1802983Swnj register struct uba_device *ui; 1812607Swnj { 1822629Swnj register struct updevice *upaddr; 1832607Swnj 1842395Swnj if (upwstart == 0) { 1852759Swnj timeout(upwatch, (caddr_t)0, hz); 1862395Swnj upwstart++; 1872395Swnj } 1882571Swnj if (ui->ui_dk >= 0) 1892571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1902607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1912607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1922629Swnj upaddr = (struct updevice *)ui->ui_addr; 1932629Swnj upaddr->upcs1 = 0; 1942629Swnj upaddr->upcs2 = ui->ui_slave; 1953496Sroot upaddr->uphr = UPHR_MAXTRAK; 1963553Swnj if (upaddr->uphr == 9) 1973496Sroot ui->ui_type = 1; /* fujitsu hack */ 1986305Sroot else if (upaddr->uphr == 15) 1996305Sroot ui->ui_type = 2; /* ampex hack */ 2003496Sroot upaddr->upcs2 = UPCS2_CLR; 2012395Swnj } 202264Sbill 2039548Ssam upopen(dev) 2049548Ssam dev_t dev; 2059548Ssam { 2069548Ssam register int unit = minor(dev) >> 3; 2079548Ssam register struct uba_device *ui; 2089548Ssam 2099548Ssam if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) 2109548Ssam return (ENXIO); 2119548Ssam return (0); 2129548Ssam } 2139548Ssam 214264Sbill upstrategy(bp) 2152395Swnj register struct buf *bp; 216264Sbill { 2172983Swnj register struct uba_device *ui; 2182395Swnj register struct upst *st; 2192395Swnj register int unit; 2202470Swnj register struct buf *dp; 2212395Swnj int xunit = minor(bp->b_dev) & 07; 2222470Swnj long bn, sz; 223264Sbill 2242470Swnj sz = (bp->b_bcount+511) >> 9; 225264Sbill unit = dkunit(bp); 2262395Swnj if (unit >= NUP) 2272395Swnj goto bad; 2282395Swnj ui = updinfo[unit]; 2292395Swnj if (ui == 0 || ui->ui_alive == 0) 2302395Swnj goto bad; 2312395Swnj st = &upst[ui->ui_type]; 2322395Swnj if (bp->b_blkno < 0 || 2332395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2342395Swnj goto bad; 2352395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2366305Sroot (void) spl5(); 2372470Swnj dp = &uputab[ui->ui_unit]; 2382470Swnj disksort(dp, bp); 2392470Swnj if (dp->b_active == 0) { 2402395Swnj (void) upustart(ui); 2412395Swnj bp = &ui->ui_mi->um_tab; 2422395Swnj if (bp->b_actf && bp->b_active == 0) 2432395Swnj (void) upstart(ui->ui_mi); 244264Sbill } 2456305Sroot (void) spl0(); 2462395Swnj return; 2472395Swnj 2482395Swnj bad: 2492395Swnj bp->b_flags |= B_ERROR; 2502395Swnj iodone(bp); 2512395Swnj return; 252264Sbill } 253264Sbill 2542674Swnj /* 2552674Swnj * Unit start routine. 2562674Swnj * Seek the drive to be where the data is 2572674Swnj * and then generate another interrupt 2582674Swnj * to actually start the transfer. 2592674Swnj * If there is only one drive on the controller, 2602674Swnj * or we are very close to the data, don't 2612674Swnj * bother with the search. If called after 2622674Swnj * searching once, don't bother to look where 2632674Swnj * we are, just queue for transfer (to avoid 2642674Swnj * positioning forever without transferrring.) 2652674Swnj */ 2662395Swnj upustart(ui) 2672983Swnj register struct uba_device *ui; 268264Sbill { 269264Sbill register struct buf *bp, *dp; 2702983Swnj register struct uba_ctlr *um; 2712629Swnj register struct updevice *upaddr; 2722395Swnj register struct upst *st; 273264Sbill daddr_t bn; 2742674Swnj int sn, csn; 2752607Swnj /* 2762607Swnj * The SC21 cancels commands if you just say 2772629Swnj * cs1 = UP_IE 2782607Swnj * so we are cautious about handling of cs1. 2792607Swnj * Also don't bother to clear as bits other than in upintr(). 2802607Swnj */ 2812674Swnj int didie = 0; 2822674Swnj 2832674Swnj if (ui == 0) 2842674Swnj return (0); 2852983Swnj um = ui->ui_mi; 2862395Swnj dk_busy &= ~(1<<ui->ui_dk); 2872395Swnj dp = &uputab[ui->ui_unit]; 288266Sbill if ((bp = dp->b_actf) == NULL) 289268Sbill goto out; 2902674Swnj /* 2912674Swnj * If the controller is active, just remember 2922674Swnj * that this device would like to be positioned... 2932674Swnj * if we tried to position now we would confuse the SC21. 2942674Swnj */ 2952395Swnj if (um->um_tab.b_active) { 2962459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 297275Sbill return (0); 298275Sbill } 2992674Swnj /* 3002674Swnj * If we have already positioned this drive, 3012674Swnj * then just put it on the ready queue. 3022674Swnj */ 303276Sbill if (dp->b_active) 304276Sbill goto done; 305276Sbill dp->b_active = 1; 3062629Swnj upaddr = (struct updevice *)um->um_addr; 3072395Swnj upaddr->upcs2 = ui->ui_slave; 3082674Swnj /* 3092674Swnj * If drive has just come up, 3102674Swnj * setup the pack. 3112674Swnj */ 3129548Ssam if ((upaddr->upds & UPDS_VV) == 0 || upinit[ui->ui_unit] == 0) { 3139548Ssam #ifndef NOBADSECT 3149548Ssam struct buf *bbp = &bupbuf[ui->ui_unit]; 3159548Ssam #endif 3162607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3179548Ssam upinit[ui->ui_unit] = 1; 3182629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3192629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3203445Sroot upaddr->upof = UPOF_FMT22; 321268Sbill didie = 1; 3229548Ssam #ifndef NOBADSECT 3239548Ssam st = &upst[ui->ui_type]; 3249548Ssam bbp->b_flags = B_READ|B_BUSY; 3259548Ssam bbp->b_dev = bp->b_dev; 3269548Ssam bbp->b_bcount = 512; 3279548Ssam bbp->b_un.b_addr = (caddr_t)&upbad[ui->ui_unit]; 3289548Ssam bbp->b_blkno = st->ncyl * st->nspc - st->nsect; 3299548Ssam bbp->b_cylin = st->ncyl - 1; 3309548Ssam dp->b_actf = bbp; 3319548Ssam bbp->av_forw = bp; 3329548Ssam bp = bbp; 3339548Ssam #endif 334264Sbill } 3352674Swnj /* 3362674Swnj * If drive is offline, forget about positioning. 3372674Swnj */ 3383445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 339275Sbill goto done; 3402674Swnj /* 3412674Swnj * If there is only one drive, 3422674Swnj * dont bother searching. 3432674Swnj */ 3442607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3452607Swnj goto done; 3462674Swnj /* 3472674Swnj * Figure out where this transfer is going to 3482674Swnj * and see if we are close enough to justify not searching. 3492674Swnj */ 3502395Swnj st = &upst[ui->ui_type]; 351264Sbill bn = dkblock(bp); 3522395Swnj sn = bn%st->nspc; 3532395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 3542674Swnj if (bp->b_cylin - upaddr->updc) 355266Sbill goto search; /* Not on-cylinder */ 356275Sbill else if (upseek) 357275Sbill goto done; /* Ok just to be on-cylinder */ 358264Sbill csn = (upaddr->upla>>6) - sn - 1; 359266Sbill if (csn < 0) 3602395Swnj csn += st->nsect; 3612395Swnj if (csn > st->nsect - upRDIST) 362264Sbill goto done; 363264Sbill search: 3642674Swnj upaddr->updc = bp->b_cylin; 3652674Swnj /* 3662674Swnj * Not on cylinder at correct position, 3672674Swnj * seek/search. 3682674Swnj */ 369275Sbill if (upseek) 3702629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3712470Swnj else { 372275Sbill upaddr->upda = sn; 3732629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 374275Sbill } 375268Sbill didie = 1; 3762674Swnj /* 3772674Swnj * Mark unit busy for iostat. 3782674Swnj */ 3792395Swnj if (ui->ui_dk >= 0) { 3802395Swnj dk_busy |= 1<<ui->ui_dk; 3812395Swnj dk_seek[ui->ui_dk]++; 382264Sbill } 383268Sbill goto out; 384264Sbill done: 3852674Swnj /* 3862674Swnj * Device is ready to go. 3872674Swnj * Put it on the ready queue for the controller 3882674Swnj * (unless its already there.) 3892674Swnj */ 3902629Swnj if (dp->b_active != 2) { 3912629Swnj dp->b_forw = NULL; 3922629Swnj if (um->um_tab.b_actf == NULL) 3932629Swnj um->um_tab.b_actf = dp; 3942629Swnj else 3952629Swnj um->um_tab.b_actl->b_forw = dp; 3962629Swnj um->um_tab.b_actl = dp; 3972629Swnj dp->b_active = 2; 3982629Swnj } 399268Sbill out: 400268Sbill return (didie); 401264Sbill } 402264Sbill 4032674Swnj /* 4042674Swnj * Start up a transfer on a drive. 4052674Swnj */ 4062395Swnj upstart(um) 4072983Swnj register struct uba_ctlr *um; 408264Sbill { 409264Sbill register struct buf *bp, *dp; 4102983Swnj register struct uba_device *ui; 4112629Swnj register struct updevice *upaddr; 4122470Swnj struct upst *st; 413264Sbill daddr_t bn; 4142681Swnj int dn, sn, tn, cmd, waitdry; 415264Sbill 416264Sbill loop: 4172674Swnj /* 4182674Swnj * Pull a request off the controller queue 4192674Swnj */ 4202395Swnj if ((dp = um->um_tab.b_actf) == NULL) 421268Sbill return (0); 422264Sbill if ((bp = dp->b_actf) == NULL) { 4232395Swnj um->um_tab.b_actf = dp->b_forw; 424264Sbill goto loop; 425264Sbill } 4262674Swnj /* 4272674Swnj * Mark controller busy, and 4282674Swnj * determine destination of this request. 4292674Swnj */ 4302395Swnj um->um_tab.b_active++; 4312395Swnj ui = updinfo[dkunit(bp)]; 432264Sbill bn = dkblock(bp); 4332395Swnj dn = ui->ui_slave; 4342395Swnj st = &upst[ui->ui_type]; 4352395Swnj sn = bn%st->nspc; 4362395Swnj tn = sn/st->nsect; 4372395Swnj sn %= st->nsect; 4382629Swnj upaddr = (struct updevice *)ui->ui_addr; 4392674Swnj /* 4402674Swnj * Select drive if not selected already. 4412674Swnj */ 4422674Swnj if ((upaddr->upcs2&07) != dn) 4432674Swnj upaddr->upcs2 = dn; 4442674Swnj /* 4452674Swnj * Check that it is ready and online 4462674Swnj */ 4472681Swnj waitdry = 0; 4483445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4497036Swnj printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds); 4502681Swnj if (++waitdry > 512) 4512681Swnj break; 4522681Swnj upwaitdry++; 4532681Swnj } 4543445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4552931Swnj printf("up%d: not ready", dkunit(bp)); 4563445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4572607Swnj printf("\n"); 4582395Swnj um->um_tab.b_active = 0; 4592395Swnj um->um_tab.b_errcnt = 0; 460893Sbill dp->b_actf = bp->av_forw; 461893Sbill dp->b_active = 0; 462893Sbill bp->b_flags |= B_ERROR; 463893Sbill iodone(bp); 464893Sbill goto loop; 465893Sbill } 4662674Swnj /* 4672674Swnj * Oh, well, sometimes this 4682674Swnj * happens, for reasons unknown. 4692674Swnj */ 4702629Swnj printf(" (flakey)\n"); 471264Sbill } 4722674Swnj /* 4732674Swnj * Setup for the transfer, and get in the 4742674Swnj * UNIBUS adaptor queue. 4752674Swnj */ 4762424Skre upaddr->updc = bp->b_cylin; 477264Sbill upaddr->upda = (tn << 8) + sn; 478264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 479264Sbill if (bp->b_flags & B_READ) 4802629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 481264Sbill else 4822629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4832571Swnj um->um_cmd = cmd; 4843107Swnj (void) ubago(ui); 485268Sbill return (1); 486264Sbill } 487264Sbill 4882674Swnj /* 4892674Swnj * Now all ready to go, stuff the registers. 4902674Swnj */ 4912571Swnj updgo(um) 4922983Swnj struct uba_ctlr *um; 4932395Swnj { 4942629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4952470Swnj 4966953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 4972571Swnj upaddr->upba = um->um_ubinfo; 4982571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4992395Swnj } 5002395Swnj 5012674Swnj /* 5022674Swnj * Handle a disk interrupt. 5032674Swnj */ 5042707Swnj upintr(sc21) 5052395Swnj register sc21; 506264Sbill { 507264Sbill register struct buf *bp, *dp; 5082983Swnj register struct uba_ctlr *um = upminfo[sc21]; 5092983Swnj register struct uba_device *ui; 5102629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 511264Sbill register unit; 5122470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 5132607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 5142681Swnj int needie = 1, waitdry; 515264Sbill 5162470Swnj sc->sc_wticks = 0; 5172607Swnj sc->sc_softas = 0; 5182674Swnj /* 5192674Swnj * If controller wasn't transferring, then this is an 5202674Swnj * interrupt for attention status on seeking drives. 5212674Swnj * Just service them. 5222674Swnj */ 5236346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 5242674Swnj if (upaddr->upcs1 & UP_TRE) 5252674Swnj upaddr->upcs1 = UP_TRE; 5262674Swnj goto doattn; 5272674Swnj } 5286953Swnj um->um_tab.b_active = 1; 5292674Swnj /* 5302674Swnj * Get device and block structures, and a pointer 5312983Swnj * to the uba_device for the drive. Select the drive. 5322674Swnj */ 5332674Swnj dp = um->um_tab.b_actf; 5342674Swnj bp = dp->b_actf; 5352674Swnj ui = updinfo[dkunit(bp)]; 5362674Swnj dk_busy &= ~(1 << ui->ui_dk); 5372674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5382395Swnj upaddr->upcs2 = ui->ui_slave; 5399548Ssam #ifndef NOBADSECT 5409548Ssam if (bp->b_flags&B_BAD) { 5419548Ssam if (upecc(ui, CONT)) 5429548Ssam return; 5439548Ssam } 5449548Ssam #endif 5452674Swnj /* 5462674Swnj * Check for and process errors on 5472674Swnj * either the drive or the controller. 5482674Swnj */ 5493445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5502681Swnj waitdry = 0; 5513445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5522681Swnj if (++waitdry > 512) 5532681Swnj break; 5542681Swnj upwaitdry++; 5552681Swnj } 5563445Sroot if (upaddr->uper1&UPER1_WLE) { 5572674Swnj /* 5582674Swnj * Give up on write locked devices 5592674Swnj * immediately. 5602674Swnj */ 5612931Swnj printf("up%d: write locked\n", dkunit(bp)); 5622674Swnj bp->b_flags |= B_ERROR; 5632674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5642674Swnj /* 5652674Swnj * After 28 retries (16 without offset, and 5662674Swnj * 12 with offset positioning) give up. 5672674Swnj */ 5689548Ssam hard: 5692931Swnj harderr(bp, "up"); 5709548Ssam printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b\n", 5719548Ssam upaddr->updc, ((upaddr->upda)>>8)&077, 5729548Ssam (upaddr->upda)&037, 5739548Ssam upaddr->upcs2, UPCS2_BITS, 5749548Ssam upaddr->uper1, UPER1_BITS, 5759548Ssam upaddr->uper2, UPER2_BITS); 5762674Swnj bp->b_flags |= B_ERROR; 5779548Ssam } else if (upaddr->uper2 & UPER2_BSE) { 5789548Ssam #ifndef NOBADSECT 5799548Ssam if (upecc(ui, BSE)) 5809548Ssam return; 5819548Ssam else 5829548Ssam #endif 5839548Ssam goto hard; 5842674Swnj } else { 5852674Swnj /* 5862674Swnj * Retriable error. 5872674Swnj * If a soft ecc, correct it (continuing 5882674Swnj * by returning if necessary. 5892674Swnj * Otherwise fall through and retry the transfer 5902674Swnj */ 5917183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 5929548Ssam if (upecc(ui, ECC)) 5932629Swnj return; 5947183Sroot } else 5957183Sroot um->um_tab.b_active = 0; /* force retry */ 5962674Swnj } 5972674Swnj /* 5982674Swnj * Clear drive error and, every eight attempts, 5992674Swnj * (starting with the fourth) 6002674Swnj * recalibrate to clear the slate. 6012674Swnj */ 6022674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 6032674Swnj needie = 0; 6043182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 6052674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 6063160Swnj sc->sc_recal = 0; 6073160Swnj goto nextrecal; 6082674Swnj } 6092674Swnj } 6102674Swnj /* 6113160Swnj * Advance recalibration finite state machine 6123160Swnj * if recalibrate in progress, through 6133160Swnj * RECAL 6143160Swnj * SEEK 6153160Swnj * OFFSET (optional) 6163160Swnj * RETRY 6172674Swnj */ 6183160Swnj switch (sc->sc_recal) { 6193160Swnj 6203160Swnj case 1: 6213160Swnj upaddr->updc = bp->b_cylin; 6223160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 6233160Swnj goto nextrecal; 6243160Swnj case 2: 6253160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 6263160Swnj goto donerecal; 6273445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 6283160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 6293160Swnj goto nextrecal; 6303160Swnj nextrecal: 6313160Swnj sc->sc_recal++; 6323160Swnj um->um_tab.b_active = 1; 6333160Swnj return; 6343160Swnj donerecal: 6353160Swnj case 3: 6362674Swnj sc->sc_recal = 0; 6373160Swnj um->um_tab.b_active = 0; 6383160Swnj break; 6392674Swnj } 6402674Swnj /* 6412674Swnj * If still ``active'', then don't need any more retries. 6422674Swnj */ 6432674Swnj if (um->um_tab.b_active) { 6442674Swnj /* 6452674Swnj * If we were offset positioning, 6462674Swnj * return to centerline. 6472674Swnj */ 6482674Swnj if (um->um_tab.b_errcnt >= 16) { 6493445Sroot upaddr->upof = UPOF_FMT22; 6502674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6513445Sroot while (upaddr->upds & UPDS_PIP) 6522674Swnj DELAY(25); 653268Sbill needie = 0; 654264Sbill } 6552674Swnj um->um_tab.b_active = 0; 6562674Swnj um->um_tab.b_errcnt = 0; 6572674Swnj um->um_tab.b_actf = dp->b_forw; 6582674Swnj dp->b_active = 0; 6592674Swnj dp->b_errcnt = 0; 6602674Swnj dp->b_actf = bp->av_forw; 6612674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6622674Swnj iodone(bp); 6632674Swnj /* 6642674Swnj * If this unit has more work to do, 6652674Swnj * then start it up right away. 6662674Swnj */ 6672674Swnj if (dp->b_actf) 6682674Swnj if (upustart(ui)) 669268Sbill needie = 0; 670264Sbill } 6712674Swnj as &= ~(1<<ui->ui_slave); 6723403Swnj /* 6733403Swnj * Release unibus resources and flush data paths. 6743403Swnj */ 6753403Swnj ubadone(um); 6762674Swnj doattn: 6772674Swnj /* 6782674Swnj * Process other units which need attention. 6792674Swnj * For each unit which needs attention, call 6802674Swnj * the unit start routine to place the slave 6812674Swnj * on the controller device queue. 6822674Swnj */ 6833160Swnj while (unit = ffs(as)) { 6843160Swnj unit--; /* was 1 origin */ 6853160Swnj as &= ~(1<<unit); 6863160Swnj upaddr->upas = 1<<unit; 6876383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 6883160Swnj needie = 0; 6893160Swnj } 6902674Swnj /* 6912674Swnj * If the controller is not transferring, but 6922674Swnj * there are devices ready to transfer, start 6932674Swnj * the controller. 6942674Swnj */ 6952395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6962395Swnj if (upstart(um)) 697268Sbill needie = 0; 698275Sbill if (needie) 6992629Swnj upaddr->upcs1 = UP_IE; 700264Sbill } 701264Sbill 7029357Ssam upread(dev, uio) 7032616Swnj dev_t dev; 7049357Ssam struct uio *uio; 705264Sbill { 7062616Swnj register int unit = minor(dev) >> 3; 7072470Swnj 7082616Swnj if (unit >= NUP) 7099357Ssam return (ENXIO); 7109357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio)); 711264Sbill } 712264Sbill 7139357Ssam upwrite(dev, uio) 7142616Swnj dev_t dev; 7159357Ssam struct uio *uio; 716264Sbill { 7172616Swnj register int unit = minor(dev) >> 3; 7182470Swnj 7192616Swnj if (unit >= NUP) 7209357Ssam return (ENXIO); 7219357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio)); 722264Sbill } 723264Sbill 724266Sbill /* 725266Sbill * Correct an ECC error, and restart the i/o to complete 726266Sbill * the transfer if necessary. This is quite complicated because 727266Sbill * the transfer may be going to an odd memory address base and/or 728266Sbill * across a page boundary. 729266Sbill */ 7309548Ssam upecc(ui, flag) 7312983Swnj register struct uba_device *ui; 7329548Ssam int flag; 733264Sbill { 7342629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 7352395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 7362983Swnj register struct uba_ctlr *um = ui->ui_mi; 7372395Swnj register struct upst *st; 7382395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 739266Sbill register int i; 740264Sbill caddr_t addr; 741266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 742264Sbill int bn, cn, tn, sn; 743264Sbill 744264Sbill /* 745266Sbill * Npf is the number of sectors transferred before the sector 746266Sbill * containing the ECC error, and reg is the UBA register 747266Sbill * mapping (the first part of) the transfer. 748266Sbill * O is offset within a memory page of the first byte transferred. 749264Sbill */ 7509548Ssam #ifndef NOBADSECT 7519548Ssam if (flag == CONT) 7529548Ssam npf = bp->b_error; 7539548Ssam else 7549548Ssam #endif 7559548Ssam npf = btop((up->upwc * sizeof(short)) + bp->b_bcount); 7562571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 757264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 7582983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 7592889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 760264Sbill mask = up->upec2; 7613445Sroot #ifdef UPECCDEBUG 7623403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7633403Swnj up->upec1); 7643445Sroot #endif 7659548Ssam bn = dkblock(bp); 7669548Ssam st = &upst[ui->ui_type]; 7679548Ssam cn = bp->b_cylin; 7689548Ssam sn = bn%st->nspc + npf; 7699548Ssam tn = sn/st->nsect; 7709548Ssam sn %= st->nsect; 7719548Ssam cn += tn/st->ntrak; 7729548Ssam tn %= st->ntrak; 7732725Swnj ubapurge(um); 7749548Ssam um->um_tab.b_active=2; 775266Sbill /* 7769548Ssam * action taken depends on the flag 777266Sbill */ 7789548Ssam switch(flag){ 7799548Ssam case ECC: 7809548Ssam npf--; 7819548Ssam reg--; 7829548Ssam mask = up->upec2; 7839548Ssam printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 7849548Ssam 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 7859548Ssam /* 7869548Ssam * Flush the buffered data path, and compute the 7879548Ssam * byte and bit position of the error. The variable i 7889548Ssam * is the byte offset in the transfer, the variable byte 7899548Ssam * is the offset from a page boundary in main memory. 7909548Ssam */ 7919548Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 7929548Ssam bit = i&07; 7939548Ssam i = (i&~07)>>3; 7949548Ssam byte = i + o; 7959548Ssam /* 7969548Ssam * Correct while possible bits remain of mask. Since mask 7979548Ssam * contains 11 bits, we continue while the bit offset is > -11. 7989548Ssam * Also watch out for end of this block and the end of the whole 7999548Ssam * transfer. 8009548Ssam */ 8019548Ssam while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 8029548Ssam addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 8039548Ssam (byte & PGOFSET); 8043445Sroot #ifdef UPECCDEBUG 8059548Ssam printf("addr %x map reg %x\n", 8069548Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 8079548Ssam printf("old: %x, ", getmemc(addr)); 8083445Sroot #endif 8099548Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 8103445Sroot #ifdef UPECCDEBUG 8119548Ssam printf("new: %x\n", getmemc(addr)); 8123445Sroot #endif 8139548Ssam byte++; 8149548Ssam i++; 8159580Shelge bit -= 8; 8169548Ssam } 8179548Ssam if (up->upwc == 0) 8189548Ssam return (0); 8199548Ssam npf++; 8209548Ssam reg++; 8219548Ssam break; 8229548Ssam #ifndef NOBADSECT 8239548Ssam case BSE: 8249548Ssam /* 8259548Ssam * if not in bad sector table, return 0 8269548Ssam */ 8279548Ssam if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) 8289548Ssam return(0); 8299548Ssam /* 8309548Ssam * flag this one as bad 8319548Ssam */ 8329548Ssam bp->b_flags |= B_BAD; 8339548Ssam bp->b_error = npf + 1; 8349548Ssam #ifdef UPECCDEBUG 8359548Ssam printf("BSE: restart at %d\n",npf+1); 8369548Ssam #endif 8379548Ssam bn = st->ncyl * st->nspc -st->nsect - 1 - bn; 8389548Ssam cn = bn / st->nspc; 8399548Ssam sn = bn % st->nspc; 8409548Ssam tn = sn / st->nsect; 8419548Ssam sn %= st->nsect; 8429548Ssam up->upwc = -(512 / sizeof (short)); 8439548Ssam #ifdef UPECCDEBUG 8449548Ssam printf("revector to cn %d tn %d sn %d\n", cn, tn, sn); 8459548Ssam #endif 8469548Ssam break; 8479548Ssam case CONT: 8489548Ssam #ifdef UPECCDEBUG 8499548Ssam printf("upecc, CONT: bn %d cn %d tn %d sn %d\n", bn, cn, tn, sn); 8509548Ssam #endif 8519548Ssam bp->b_flags &= ~B_BAD; 8529548Ssam up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); 8539548Ssam if (up->upwc == 0) 8549548Ssam return(0); 8559548Ssam break; 8569548Ssam #endif 857264Sbill } 8587183Sroot if (up->upwc == 0) { 8597183Sroot um->um_tab.b_active = 0; 860264Sbill return (0); 8617183Sroot } 862266Sbill /* 863266Sbill * Have to continue the transfer... clear the drive, 864266Sbill * and compute the position where the transfer is to continue. 865266Sbill * We have completed npf+1 sectors of the transfer already; 866266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 867266Sbill */ 8682629Swnj #ifdef notdef 8692629Swnj up->uper1 = 0; 8702629Swnj up->upcs1 |= UP_GO; 8712629Swnj #else 8722629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 873264Sbill up->updc = cn; 874266Sbill up->upda = (tn << 8) | sn; 8759548Ssam ubaddr = (int)ptob(reg) + o; 876266Sbill up->upba = ubaddr; 877266Sbill cmd = (ubaddr >> 8) & 0x300; 8789548Ssam cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; 8799548Ssam um->um_tab.b_errcnt = 0; 880266Sbill up->upcs1 = cmd; 8812629Swnj #endif 882264Sbill return (1); 883264Sbill } 884286Sbill 885286Sbill /* 886286Sbill * Reset driver after UBA init. 887286Sbill * Cancel software state of all pending transfers 888286Sbill * and restart all units and the controller. 889286Sbill */ 8902395Swnj upreset(uban) 8912931Swnj int uban; 892286Sbill { 8932983Swnj register struct uba_ctlr *um; 8942983Swnj register struct uba_device *ui; 8952395Swnj register sc21, unit; 896286Sbill 8972646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 8982470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 8992470Swnj um->um_alive == 0) 9002395Swnj continue; 9012931Swnj printf(" sc%d", sc21); 9022395Swnj um->um_tab.b_active = 0; 9032395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 9042931Swnj up_softc[sc21].sc_recal = 0; 9056346Swnj up_softc[sc21].sc_wticks = 0; 9062571Swnj if (um->um_ubinfo) { 9072571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 9089357Ssam um->um_ubinfo = 0; 9092395Swnj } 9103445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 9112395Swnj for (unit = 0; unit < NUP; unit++) { 9122395Swnj if ((ui = updinfo[unit]) == 0) 9132395Swnj continue; 9142931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 9152395Swnj continue; 9162395Swnj uputab[unit].b_active = 0; 9172395Swnj (void) upustart(ui); 9182395Swnj } 9192395Swnj (void) upstart(um); 920286Sbill } 921286Sbill } 922313Sbill 923313Sbill /* 924313Sbill * Wake up every second and if an interrupt is pending 925313Sbill * but nothing has happened increment a counter. 9262931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 927313Sbill * and begin anew. 928313Sbill */ 929313Sbill upwatch() 930313Sbill { 9312983Swnj register struct uba_ctlr *um; 9322395Swnj register sc21, unit; 9332470Swnj register struct up_softc *sc; 934313Sbill 9352759Swnj timeout(upwatch, (caddr_t)0, hz); 9362646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 9372395Swnj um = upminfo[sc21]; 9382470Swnj if (um == 0 || um->um_alive == 0) 9392470Swnj continue; 9402470Swnj sc = &up_softc[sc21]; 9412395Swnj if (um->um_tab.b_active == 0) { 9422395Swnj for (unit = 0; unit < NUP; unit++) 9432629Swnj if (uputab[unit].b_active && 9442629Swnj updinfo[unit]->ui_mi == um) 9452395Swnj goto active; 9462470Swnj sc->sc_wticks = 0; 9472395Swnj continue; 9482395Swnj } 9492931Swnj active: 9502470Swnj sc->sc_wticks++; 9512470Swnj if (sc->sc_wticks >= 20) { 9522470Swnj sc->sc_wticks = 0; 9532931Swnj printf("sc%d: lost interrupt\n", sc21); 9542646Swnj ubareset(um->um_ubanum); 9552395Swnj } 956313Sbill } 957313Sbill } 9582379Swnj 9592379Swnj #define DBSIZE 20 9602379Swnj 9612379Swnj updump(dev) 9622379Swnj dev_t dev; 9632379Swnj { 9642629Swnj struct updevice *upaddr; 9652379Swnj char *start; 9663107Swnj int num, blk, unit; 9672379Swnj struct size *sizes; 9682395Swnj register struct uba_regs *uba; 9692983Swnj register struct uba_device *ui; 9702379Swnj register short *rp; 9712395Swnj struct upst *st; 9726848Ssam register int retry; 9732379Swnj 9742395Swnj unit = minor(dev) >> 3; 9752889Swnj if (unit >= NUP) 9762889Swnj return (ENXIO); 9772470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 9782983Swnj ui = phys(struct uba_device *, updinfo[unit]); 9792889Swnj if (ui->ui_alive == 0) 9802889Swnj return (ENXIO); 9812395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 9822983Swnj ubainit(uba); 9832629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 9846848Ssam DELAY(5000000); 9852379Swnj num = maxfree; 9862379Swnj upaddr->upcs2 = unit; 9872983Swnj DELAY(100); 9886848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 9896848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 9906848Ssam upaddr->upof = UPOF_FMT22; 9916848Ssam retry = 0; 9926848Ssam do { 9936848Ssam DELAY(25); 9946848Ssam if (++retry > 527) 9956848Ssam break; 9966861Ssam } while ((upaddr->upds & UP_RDY) == 0); 9973445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 9982889Swnj return (EFAULT); 9999357Ssam start = 0; 10008489Sroot st = &upst[ui->ui_type]; 10012395Swnj sizes = phys(struct size *, st->sizes); 10022889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 10032889Swnj return (EINVAL); 10042379Swnj while (num > 0) { 10052379Swnj register struct pte *io; 10062379Swnj register int i; 10072379Swnj int cn, sn, tn; 10082379Swnj daddr_t bn; 10092379Swnj 10102379Swnj blk = num > DBSIZE ? DBSIZE : num; 10112395Swnj io = uba->uba_map; 10122379Swnj for (i = 0; i < blk; i++) 10132983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 10142379Swnj *(int *)io = 0; 10152379Swnj bn = dumplo + btop(start); 10162607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 10172607Swnj sn = bn%st->nspc; 10182607Swnj tn = sn/st->nsect; 10192607Swnj sn = sn%st->nsect; 10202379Swnj upaddr->updc = cn; 10212379Swnj rp = (short *) &upaddr->upda; 10222379Swnj *rp = (tn << 8) + sn; 10232379Swnj *--rp = 0; 10242379Swnj *--rp = -blk*NBPG / sizeof (short); 10252629Swnj *--rp = UP_GO|UP_WCOM; 10266848Ssam retry = 0; 10272379Swnj do { 10282379Swnj DELAY(25); 10296848Ssam if (++retry > 527) 10306848Ssam break; 10312629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 10326848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10336861Ssam printf("up%d: not ready", unit); 10346848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 10356848Ssam printf("\n"); 10366848Ssam return (EIO); 10376848Ssam } 10386848Ssam printf(" (flakey)\n"); 10396848Ssam } 10403445Sroot if (upaddr->upds&UPDS_ERR) 10412889Swnj return (EIO); 10422379Swnj start += blk*NBPG; 10432379Swnj num -= blk; 10442379Swnj } 10452379Swnj return (0); 10462379Swnj } 10471902Swnj #endif 1048