1*7183Sroot /* up.c 4.55 82/06/14 */ 2264Sbill 31937Swnj #include "up.h" 42646Swnj #if NSC > 0 5264Sbill /* 6885Sbill * UNIBUS disk driver with overlapped seeks and ECC recovery. 72889Swnj * 82889Swnj * TODO: 92889Swnj * Add bad sector forwarding code 103445Sroot * Check that offset recovery code works 11264Sbill */ 12264Sbill 13264Sbill #include "../h/param.h" 14264Sbill #include "../h/systm.h" 152395Swnj #include "../h/cpu.h" 162395Swnj #include "../h/nexus.h" 17308Sbill #include "../h/dk.h" 18264Sbill #include "../h/buf.h" 19264Sbill #include "../h/conf.h" 20264Sbill #include "../h/dir.h" 21264Sbill #include "../h/user.h" 22264Sbill #include "../h/map.h" 23420Sbill #include "../h/pte.h" 24264Sbill #include "../h/mtpr.h" 252571Swnj #include "../h/vm.h" 262983Swnj #include "../h/ubavar.h" 272983Swnj #include "../h/ubareg.h" 282379Swnj #include "../h/cmap.h" 29264Sbill 302379Swnj #include "../h/upreg.h" 31264Sbill 322395Swnj struct up_softc { 332395Swnj int sc_softas; 342607Swnj int sc_ndrive; 352395Swnj int sc_wticks; 362674Swnj int sc_recal; 372646Swnj } up_softc[NSC]; 38275Sbill 392395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 40264Sbill struct size 41264Sbill { 42264Sbill daddr_t nblocks; 43264Sbill int cyloff; 44264Sbill } up_sizes[8] = { 456436Swnj #ifdef ERNIE 466436Swnj 49324, 0, /* A=cyl 0 thru 26 */ 476436Swnj #else 48264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 496436Swnj #endif 50264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 51341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 52264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 53264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 543730Sroot #ifndef NOBADSECT 553730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 563730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 573730Sroot #else 583730Sroot 81472, 681, 593730Sroot 153824, 562, 603730Sroot #endif 61264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 622395Swnj }, fj_sizes[8] = { 632395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 642395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 652395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 662395Swnj 0, 0, 672395Swnj 0, 0, 682395Swnj 0, 0, 692395Swnj 0, 0, 703730Sroot #ifndef NOBADSECT 713730Sroot 213664, 155, /* H=cyl 155 thru 822 */ 723730Sroot #else 733730Sroot 213760, 155, 743730Sroot #endif 756851Ssam }, upam_sizes[8] = { 766305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 776305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 786305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 796602Ssam 27786, 668, 806602Ssam 27786, 723, 816602Ssam 125440, 778, 826305Sroot 181760, 668, /* G=cyl 668 thru 1022 */ 836305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 84264Sbill }; 852395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 86264Sbill 876346Swnj /* 886346Swnj * On a 780 upSDIST could be 2, but 896346Swnj * in the interest of 750's... 906346Swnj */ 916346Swnj #define _upSDIST 3 /* 1.5 msec */ 922395Swnj #define _upRDIST 4 /* 2.0 msec */ 93264Sbill 942395Swnj int upSDIST = _upSDIST; 952395Swnj int upRDIST = _upRDIST; 962395Swnj 972607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 982983Swnj struct uba_ctlr *upminfo[NSC]; 992983Swnj struct uba_device *updinfo[NUP]; 1006383Swnj #define UPIPUNITS 8 1016383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 1022395Swnj 1032607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 1042616Swnj struct uba_driver scdriver = 1052607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 1062395Swnj struct buf uputab[NUP]; 1072395Swnj 1082395Swnj struct upst { 1092395Swnj short nsect; 1102395Swnj short ntrak; 1112395Swnj short nspc; 1122395Swnj short ncyl; 1132395Swnj struct size *sizes; 1142395Swnj } upst[] = { 1152607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 1162607Swnj /* 9300 actually has 815 cylinders... */ 1172395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 1186851Ssam 32, 16, 32*16, 1024, upam_sizes, /* ampex capricorn */ 1192395Swnj }; 1202395Swnj 1212629Swnj u_char up_offset[16] = { 1223445Sroot UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 1233445Sroot UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 1243445Sroot UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 1253445Sroot 0, 0, 0, 0 1262629Swnj }; 127264Sbill 1282616Swnj struct buf rupbuf[NUP]; 129264Sbill 130264Sbill #define b_cylin b_resid 131264Sbill 132264Sbill #ifdef INTRLVE 133264Sbill daddr_t dkblock(); 134264Sbill #endif 1352395Swnj 1362395Swnj int upwstart, upwatch(); /* Have started guardian */ 1372470Swnj int upseek; 1382681Swnj int upwaitdry; 1392395Swnj 1402395Swnj /*ARGSUSED*/ 1412607Swnj upprobe(reg) 1422395Swnj caddr_t reg; 1432395Swnj { 1442459Swnj register int br, cvec; 1452459Swnj 1462607Swnj #ifdef lint 1472607Swnj br = 0; cvec = br; br = cvec; 1482607Swnj #endif 1492629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1502607Swnj DELAY(10); 1512629Swnj ((struct updevice *)reg)->upcs1 = 0; 1522459Swnj return (1); 1532395Swnj } 1542395Swnj 1552607Swnj upslave(ui, reg) 1562983Swnj struct uba_device *ui; 1572395Swnj caddr_t reg; 1582395Swnj { 1592629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1602395Swnj 1612395Swnj upaddr->upcs1 = 0; /* conservative */ 1622607Swnj upaddr->upcs2 = ui->ui_slave; 1636843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1643445Sroot if (upaddr->upcs2&UPCS2_NED) { 1652629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1662395Swnj return (0); 1672395Swnj } 1682607Swnj return (1); 1692607Swnj } 1702607Swnj 1712607Swnj upattach(ui) 1722983Swnj register struct uba_device *ui; 1732607Swnj { 1742629Swnj register struct updevice *upaddr; 1752607Swnj 1762395Swnj if (upwstart == 0) { 1772759Swnj timeout(upwatch, (caddr_t)0, hz); 1782395Swnj upwstart++; 1792395Swnj } 1802571Swnj if (ui->ui_dk >= 0) 1812571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1822607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1832607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1842629Swnj upaddr = (struct updevice *)ui->ui_addr; 1852629Swnj upaddr->upcs1 = 0; 1862629Swnj upaddr->upcs2 = ui->ui_slave; 1873496Sroot upaddr->uphr = UPHR_MAXTRAK; 1883553Swnj if (upaddr->uphr == 9) 1893496Sroot ui->ui_type = 1; /* fujitsu hack */ 1906305Sroot else if (upaddr->uphr == 15) 1916305Sroot ui->ui_type = 2; /* ampex hack */ 1923496Sroot upaddr->upcs2 = UPCS2_CLR; 1933496Sroot /* 1943496Sroot upaddr->uphr = UPHR_MAXCYL; 1953496Sroot printf("maxcyl %d\n", upaddr->uphr); 1963496Sroot upaddr->uphr = UPHR_MAXTRAK; 1973496Sroot printf("maxtrak %d\n", upaddr->uphr); 1983496Sroot upaddr->uphr = UPHR_MAXSECT; 1993496Sroot printf("maxsect %d\n", upaddr->uphr); 2003496Sroot */ 2012395Swnj } 202264Sbill 203264Sbill upstrategy(bp) 2042395Swnj register struct buf *bp; 205264Sbill { 2062983Swnj register struct uba_device *ui; 2072395Swnj register struct upst *st; 2082395Swnj register int unit; 2092470Swnj register struct buf *dp; 2102395Swnj int xunit = minor(bp->b_dev) & 07; 2112470Swnj long bn, sz; 212264Sbill 2132470Swnj sz = (bp->b_bcount+511) >> 9; 214264Sbill unit = dkunit(bp); 2152395Swnj if (unit >= NUP) 2162395Swnj goto bad; 2172395Swnj ui = updinfo[unit]; 2182395Swnj if (ui == 0 || ui->ui_alive == 0) 2192395Swnj goto bad; 2202395Swnj st = &upst[ui->ui_type]; 2212395Swnj if (bp->b_blkno < 0 || 2222395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2232395Swnj goto bad; 2242395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2256305Sroot (void) spl5(); 2262470Swnj dp = &uputab[ui->ui_unit]; 2272470Swnj disksort(dp, bp); 2282470Swnj if (dp->b_active == 0) { 2292395Swnj (void) upustart(ui); 2302395Swnj bp = &ui->ui_mi->um_tab; 2312395Swnj if (bp->b_actf && bp->b_active == 0) 2322395Swnj (void) upstart(ui->ui_mi); 233264Sbill } 2346305Sroot (void) spl0(); 2352395Swnj return; 2362395Swnj 2372395Swnj bad: 2382395Swnj bp->b_flags |= B_ERROR; 2392395Swnj iodone(bp); 2402395Swnj return; 241264Sbill } 242264Sbill 2432674Swnj /* 2442674Swnj * Unit start routine. 2452674Swnj * Seek the drive to be where the data is 2462674Swnj * and then generate another interrupt 2472674Swnj * to actually start the transfer. 2482674Swnj * If there is only one drive on the controller, 2492674Swnj * or we are very close to the data, don't 2502674Swnj * bother with the search. If called after 2512674Swnj * searching once, don't bother to look where 2522674Swnj * we are, just queue for transfer (to avoid 2532674Swnj * positioning forever without transferrring.) 2542674Swnj */ 2552395Swnj upustart(ui) 2562983Swnj register struct uba_device *ui; 257264Sbill { 258264Sbill register struct buf *bp, *dp; 2592983Swnj register struct uba_ctlr *um; 2602629Swnj register struct updevice *upaddr; 2612395Swnj register struct upst *st; 262264Sbill daddr_t bn; 2632674Swnj int sn, csn; 2642607Swnj /* 2652607Swnj * The SC21 cancels commands if you just say 2662629Swnj * cs1 = UP_IE 2672607Swnj * so we are cautious about handling of cs1. 2682607Swnj * Also don't bother to clear as bits other than in upintr(). 2692607Swnj */ 2702674Swnj int didie = 0; 2712674Swnj 2722674Swnj if (ui == 0) 2732674Swnj return (0); 2742983Swnj um = ui->ui_mi; 2752395Swnj dk_busy &= ~(1<<ui->ui_dk); 2762395Swnj dp = &uputab[ui->ui_unit]; 277266Sbill if ((bp = dp->b_actf) == NULL) 278268Sbill goto out; 2792674Swnj /* 2802674Swnj * If the controller is active, just remember 2812674Swnj * that this device would like to be positioned... 2822674Swnj * if we tried to position now we would confuse the SC21. 2832674Swnj */ 2842395Swnj if (um->um_tab.b_active) { 2852459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 286275Sbill return (0); 287275Sbill } 2882674Swnj /* 2892674Swnj * If we have already positioned this drive, 2902674Swnj * then just put it on the ready queue. 2912674Swnj */ 292276Sbill if (dp->b_active) 293276Sbill goto done; 294276Sbill dp->b_active = 1; 2952629Swnj upaddr = (struct updevice *)um->um_addr; 2962395Swnj upaddr->upcs2 = ui->ui_slave; 2972674Swnj /* 2982674Swnj * If drive has just come up, 2992674Swnj * setup the pack. 3002674Swnj */ 3013445Sroot if ((upaddr->upds & UPDS_VV) == 0) { 3022607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3032629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3042629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3053445Sroot upaddr->upof = UPOF_FMT22; 306268Sbill didie = 1; 307264Sbill } 3082674Swnj /* 3092674Swnj * If drive is offline, forget about positioning. 3102674Swnj */ 3113445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 312275Sbill goto done; 3132674Swnj /* 3142674Swnj * If there is only one drive, 3152674Swnj * dont bother searching. 3162674Swnj */ 3172607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3182607Swnj goto done; 3192674Swnj /* 3202674Swnj * Figure out where this transfer is going to 3212674Swnj * and see if we are close enough to justify not searching. 3222674Swnj */ 3232395Swnj st = &upst[ui->ui_type]; 324264Sbill bn = dkblock(bp); 3252395Swnj sn = bn%st->nspc; 3262395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 3272674Swnj if (bp->b_cylin - upaddr->updc) 328266Sbill goto search; /* Not on-cylinder */ 329275Sbill else if (upseek) 330275Sbill goto done; /* Ok just to be on-cylinder */ 331264Sbill csn = (upaddr->upla>>6) - sn - 1; 332266Sbill if (csn < 0) 3332395Swnj csn += st->nsect; 3342395Swnj if (csn > st->nsect - upRDIST) 335264Sbill goto done; 336264Sbill search: 3372674Swnj upaddr->updc = bp->b_cylin; 3382674Swnj /* 3392674Swnj * Not on cylinder at correct position, 3402674Swnj * seek/search. 3412674Swnj */ 342275Sbill if (upseek) 3432629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3442470Swnj else { 345275Sbill upaddr->upda = sn; 3462629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 347275Sbill } 348268Sbill didie = 1; 3492674Swnj /* 3502674Swnj * Mark unit busy for iostat. 3512674Swnj */ 3522395Swnj if (ui->ui_dk >= 0) { 3532395Swnj dk_busy |= 1<<ui->ui_dk; 3542395Swnj dk_seek[ui->ui_dk]++; 355264Sbill } 356268Sbill goto out; 357264Sbill done: 3582674Swnj /* 3592674Swnj * Device is ready to go. 3602674Swnj * Put it on the ready queue for the controller 3612674Swnj * (unless its already there.) 3622674Swnj */ 3632629Swnj if (dp->b_active != 2) { 3642629Swnj dp->b_forw = NULL; 3652629Swnj if (um->um_tab.b_actf == NULL) 3662629Swnj um->um_tab.b_actf = dp; 3672629Swnj else 3682629Swnj um->um_tab.b_actl->b_forw = dp; 3692629Swnj um->um_tab.b_actl = dp; 3702629Swnj dp->b_active = 2; 3712629Swnj } 372268Sbill out: 373268Sbill return (didie); 374264Sbill } 375264Sbill 3762674Swnj /* 3772674Swnj * Start up a transfer on a drive. 3782674Swnj */ 3792395Swnj upstart(um) 3802983Swnj register struct uba_ctlr *um; 381264Sbill { 382264Sbill register struct buf *bp, *dp; 3832983Swnj register struct uba_device *ui; 3842629Swnj register struct updevice *upaddr; 3852470Swnj struct upst *st; 386264Sbill daddr_t bn; 3872681Swnj int dn, sn, tn, cmd, waitdry; 388264Sbill 389264Sbill loop: 3902674Swnj /* 3912674Swnj * Pull a request off the controller queue 3922674Swnj */ 3932395Swnj if ((dp = um->um_tab.b_actf) == NULL) 394268Sbill return (0); 395264Sbill if ((bp = dp->b_actf) == NULL) { 3962395Swnj um->um_tab.b_actf = dp->b_forw; 397264Sbill goto loop; 398264Sbill } 3992674Swnj /* 4002674Swnj * Mark controller busy, and 4012674Swnj * determine destination of this request. 4022674Swnj */ 4032395Swnj um->um_tab.b_active++; 4042395Swnj ui = updinfo[dkunit(bp)]; 405264Sbill bn = dkblock(bp); 4062395Swnj dn = ui->ui_slave; 4072395Swnj st = &upst[ui->ui_type]; 4082395Swnj sn = bn%st->nspc; 4092395Swnj tn = sn/st->nsect; 4102395Swnj sn %= st->nsect; 4112629Swnj upaddr = (struct updevice *)ui->ui_addr; 4122674Swnj /* 4132674Swnj * Select drive if not selected already. 4142674Swnj */ 4152674Swnj if ((upaddr->upcs2&07) != dn) 4162674Swnj upaddr->upcs2 = dn; 4172674Swnj /* 4182674Swnj * Check that it is ready and online 4192674Swnj */ 4202681Swnj waitdry = 0; 4213445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4227036Swnj printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds); 4232681Swnj if (++waitdry > 512) 4242681Swnj break; 4252681Swnj upwaitdry++; 4262681Swnj } 4273445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4282931Swnj printf("up%d: not ready", dkunit(bp)); 4293445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4302607Swnj printf("\n"); 4312395Swnj um->um_tab.b_active = 0; 4322395Swnj um->um_tab.b_errcnt = 0; 433893Sbill dp->b_actf = bp->av_forw; 434893Sbill dp->b_active = 0; 435893Sbill bp->b_flags |= B_ERROR; 436893Sbill iodone(bp); 437893Sbill goto loop; 438893Sbill } 4392674Swnj /* 4402674Swnj * Oh, well, sometimes this 4412674Swnj * happens, for reasons unknown. 4422674Swnj */ 4432629Swnj printf(" (flakey)\n"); 444264Sbill } 4452674Swnj /* 4462674Swnj * Setup for the transfer, and get in the 4472674Swnj * UNIBUS adaptor queue. 4482674Swnj */ 4492424Skre upaddr->updc = bp->b_cylin; 450264Sbill upaddr->upda = (tn << 8) + sn; 451264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 452264Sbill if (bp->b_flags & B_READ) 4532629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 454264Sbill else 4552629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4562571Swnj um->um_cmd = cmd; 4573107Swnj (void) ubago(ui); 458268Sbill return (1); 459264Sbill } 460264Sbill 4612674Swnj /* 4622674Swnj * Now all ready to go, stuff the registers. 4632674Swnj */ 4642571Swnj updgo(um) 4652983Swnj struct uba_ctlr *um; 4662395Swnj { 4672629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4682470Swnj 4696953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 4702571Swnj upaddr->upba = um->um_ubinfo; 4712571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4722395Swnj } 4732395Swnj 4742674Swnj /* 4752674Swnj * Handle a disk interrupt. 4762674Swnj */ 4772707Swnj upintr(sc21) 4782395Swnj register sc21; 479264Sbill { 480264Sbill register struct buf *bp, *dp; 4812983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4822983Swnj register struct uba_device *ui; 4832629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 484264Sbill register unit; 4852470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4862607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4872681Swnj int needie = 1, waitdry; 488264Sbill 4892470Swnj sc->sc_wticks = 0; 4902607Swnj sc->sc_softas = 0; 4912674Swnj /* 4922674Swnj * If controller wasn't transferring, then this is an 4932674Swnj * interrupt for attention status on seeking drives. 4942674Swnj * Just service them. 4952674Swnj */ 4966346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 4972674Swnj if (upaddr->upcs1 & UP_TRE) 4982674Swnj upaddr->upcs1 = UP_TRE; 4992674Swnj goto doattn; 5002674Swnj } 5016953Swnj um->um_tab.b_active = 1; 5022674Swnj /* 5032674Swnj * Get device and block structures, and a pointer 5042983Swnj * to the uba_device for the drive. Select the drive. 5052674Swnj */ 5062674Swnj dp = um->um_tab.b_actf; 5072674Swnj bp = dp->b_actf; 5082674Swnj ui = updinfo[dkunit(bp)]; 5092674Swnj dk_busy &= ~(1 << ui->ui_dk); 5102674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5112395Swnj upaddr->upcs2 = ui->ui_slave; 5122674Swnj /* 5132674Swnj * Check for and process errors on 5142674Swnj * either the drive or the controller. 5152674Swnj */ 5163445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5172681Swnj waitdry = 0; 5183445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5192681Swnj if (++waitdry > 512) 5202681Swnj break; 5212681Swnj upwaitdry++; 5222681Swnj } 5233445Sroot if (upaddr->uper1&UPER1_WLE) { 5242674Swnj /* 5252674Swnj * Give up on write locked devices 5262674Swnj * immediately. 5272674Swnj */ 5282931Swnj printf("up%d: write locked\n", dkunit(bp)); 5292674Swnj bp->b_flags |= B_ERROR; 5302674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5312674Swnj /* 5322674Swnj * After 28 retries (16 without offset, and 5332674Swnj * 12 with offset positioning) give up. 5342674Swnj */ 5352931Swnj harderr(bp, "up"); 5362931Swnj printf("cs2=%b er1=%b er2=%b\n", 5372785Swnj upaddr->upcs2, UPCS2_BITS, 5382785Swnj upaddr->uper1, UPER1_BITS, 5392785Swnj upaddr->uper2, UPER2_BITS); 5402674Swnj bp->b_flags |= B_ERROR; 5412674Swnj } else { 5422674Swnj /* 5432674Swnj * Retriable error. 5442674Swnj * If a soft ecc, correct it (continuing 5452674Swnj * by returning if necessary. 5462674Swnj * Otherwise fall through and retry the transfer 5472674Swnj */ 548*7183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 5492629Swnj if (upecc(ui)) 5502629Swnj return; 551*7183Sroot } else 552*7183Sroot um->um_tab.b_active = 0; /* force retry */ 5532674Swnj } 5542674Swnj /* 5552674Swnj * Clear drive error and, every eight attempts, 5562674Swnj * (starting with the fourth) 5572674Swnj * recalibrate to clear the slate. 5582674Swnj */ 5592674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5602674Swnj needie = 0; 5613182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5622674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5633160Swnj sc->sc_recal = 0; 5643160Swnj goto nextrecal; 5652674Swnj } 5662674Swnj } 5672674Swnj /* 5683160Swnj * Advance recalibration finite state machine 5693160Swnj * if recalibrate in progress, through 5703160Swnj * RECAL 5713160Swnj * SEEK 5723160Swnj * OFFSET (optional) 5733160Swnj * RETRY 5742674Swnj */ 5753160Swnj switch (sc->sc_recal) { 5763160Swnj 5773160Swnj case 1: 5783160Swnj upaddr->updc = bp->b_cylin; 5793160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 5803160Swnj goto nextrecal; 5813160Swnj case 2: 5823160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 5833160Swnj goto donerecal; 5843445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 5853160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 5863160Swnj goto nextrecal; 5873160Swnj nextrecal: 5883160Swnj sc->sc_recal++; 5893160Swnj um->um_tab.b_active = 1; 5903160Swnj return; 5913160Swnj donerecal: 5923160Swnj case 3: 5932674Swnj sc->sc_recal = 0; 5943160Swnj um->um_tab.b_active = 0; 5953160Swnj break; 5962674Swnj } 5972674Swnj /* 5982674Swnj * If still ``active'', then don't need any more retries. 5992674Swnj */ 6002674Swnj if (um->um_tab.b_active) { 6012674Swnj /* 6022674Swnj * If we were offset positioning, 6032674Swnj * return to centerline. 6042674Swnj */ 6052674Swnj if (um->um_tab.b_errcnt >= 16) { 6063445Sroot upaddr->upof = UPOF_FMT22; 6072674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6083445Sroot while (upaddr->upds & UPDS_PIP) 6092674Swnj DELAY(25); 610268Sbill needie = 0; 611264Sbill } 6122674Swnj um->um_tab.b_active = 0; 6132674Swnj um->um_tab.b_errcnt = 0; 6142674Swnj um->um_tab.b_actf = dp->b_forw; 6152674Swnj dp->b_active = 0; 6162674Swnj dp->b_errcnt = 0; 6172674Swnj dp->b_actf = bp->av_forw; 6182674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6192674Swnj iodone(bp); 6202674Swnj /* 6212674Swnj * If this unit has more work to do, 6222674Swnj * then start it up right away. 6232674Swnj */ 6242674Swnj if (dp->b_actf) 6252674Swnj if (upustart(ui)) 626268Sbill needie = 0; 627264Sbill } 6282674Swnj as &= ~(1<<ui->ui_slave); 6293403Swnj /* 6303403Swnj * Release unibus resources and flush data paths. 6313403Swnj */ 6323403Swnj ubadone(um); 6332674Swnj doattn: 6342674Swnj /* 6352674Swnj * Process other units which need attention. 6362674Swnj * For each unit which needs attention, call 6372674Swnj * the unit start routine to place the slave 6382674Swnj * on the controller device queue. 6392674Swnj */ 6403160Swnj while (unit = ffs(as)) { 6413160Swnj unit--; /* was 1 origin */ 6423160Swnj as &= ~(1<<unit); 6433160Swnj upaddr->upas = 1<<unit; 6446383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 6453160Swnj needie = 0; 6463160Swnj } 6472674Swnj /* 6482674Swnj * If the controller is not transferring, but 6492674Swnj * there are devices ready to transfer, start 6502674Swnj * the controller. 6512674Swnj */ 6522395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6532395Swnj if (upstart(um)) 654268Sbill needie = 0; 655275Sbill if (needie) 6562629Swnj upaddr->upcs1 = UP_IE; 657264Sbill } 658264Sbill 659264Sbill upread(dev) 6602616Swnj dev_t dev; 661264Sbill { 6622616Swnj register int unit = minor(dev) >> 3; 6632470Swnj 6642616Swnj if (unit >= NUP) 6652616Swnj u.u_error = ENXIO; 6662616Swnj else 6672616Swnj physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys); 668264Sbill } 669264Sbill 670264Sbill upwrite(dev) 6712616Swnj dev_t dev; 672264Sbill { 6732616Swnj register int unit = minor(dev) >> 3; 6742470Swnj 6752616Swnj if (unit >= NUP) 6762616Swnj u.u_error = ENXIO; 6772616Swnj else 6782616Swnj physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys); 679264Sbill } 680264Sbill 681266Sbill /* 682266Sbill * Correct an ECC error, and restart the i/o to complete 683266Sbill * the transfer if necessary. This is quite complicated because 684266Sbill * the transfer may be going to an odd memory address base and/or 685266Sbill * across a page boundary. 686266Sbill */ 6872395Swnj upecc(ui) 6882983Swnj register struct uba_device *ui; 689264Sbill { 6902629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6912395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6922983Swnj register struct uba_ctlr *um = ui->ui_mi; 6932395Swnj register struct upst *st; 6942395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 695266Sbill register int i; 696264Sbill caddr_t addr; 697266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 698264Sbill int bn, cn, tn, sn; 699264Sbill 700264Sbill /* 701266Sbill * Npf is the number of sectors transferred before the sector 702266Sbill * containing the ECC error, and reg is the UBA register 703266Sbill * mapping (the first part of) the transfer. 704266Sbill * O is offset within a memory page of the first byte transferred. 705264Sbill */ 706266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 7072571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 708264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 7092983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 7102889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 711264Sbill mask = up->upec2; 7123445Sroot #ifdef UPECCDEBUG 7133403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7143403Swnj up->upec1); 7153445Sroot #endif 716266Sbill /* 717266Sbill * Flush the buffered data path, and compute the 718266Sbill * byte and bit position of the error. The variable i 719266Sbill * is the byte offset in the transfer, the variable byte 720266Sbill * is the offset from a page boundary in main memory. 721266Sbill */ 7222725Swnj ubapurge(um); 723266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 724266Sbill bit = i&07; 725266Sbill i = (i&~07)>>3; 726264Sbill byte = i + o; 727266Sbill /* 728266Sbill * Correct while possible bits remain of mask. Since mask 729266Sbill * contains 11 bits, we continue while the bit offset is > -11. 730266Sbill * Also watch out for end of this block and the end of the whole 731266Sbill * transfer. 732266Sbill */ 733266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 734266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 735266Sbill (byte & PGOFSET); 7363445Sroot #ifdef UPECCDEBUG 7373403Swnj printf("addr %x map reg %x\n", 7383403Swnj addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 7393403Swnj printf("old: %x, ", getmemc(addr)); 7403445Sroot #endif 741266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 7423445Sroot #ifdef UPECCDEBUG 7433403Swnj printf("new: %x\n", getmemc(addr)); 7443445Sroot #endif 745266Sbill byte++; 746266Sbill i++; 747266Sbill bit -= 8; 748264Sbill } 749*7183Sroot if (up->upwc == 0) { 750*7183Sroot um->um_tab.b_active = 0; 751264Sbill return (0); 752*7183Sroot } 753266Sbill /* 754266Sbill * Have to continue the transfer... clear the drive, 755266Sbill * and compute the position where the transfer is to continue. 756266Sbill * We have completed npf+1 sectors of the transfer already; 757266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 758266Sbill */ 7592629Swnj #ifdef notdef 7602629Swnj up->uper1 = 0; 7612629Swnj up->upcs1 |= UP_GO; 7622629Swnj #else 7632629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 764264Sbill bn = dkblock(bp); 7652395Swnj st = &upst[ui->ui_type]; 766264Sbill cn = bp->b_cylin; 7672395Swnj sn = bn%st->nspc + npf + 1; 7682395Swnj tn = sn/st->nsect; 7692395Swnj sn %= st->nsect; 7702395Swnj cn += tn/st->ntrak; 7712395Swnj tn %= st->ntrak; 772264Sbill up->updc = cn; 773266Sbill up->upda = (tn << 8) | sn; 774266Sbill ubaddr = (int)ptob(reg+1) + o; 775266Sbill up->upba = ubaddr; 776266Sbill cmd = (ubaddr >> 8) & 0x300; 7772629Swnj cmd |= UP_IE|UP_GO|UP_RCOM; 7786953Swnj um->um_tab.b_active = 2; /* continuing transfer ... */ 779266Sbill up->upcs1 = cmd; 7802629Swnj #endif 781264Sbill return (1); 782264Sbill } 783286Sbill 784286Sbill /* 785286Sbill * Reset driver after UBA init. 786286Sbill * Cancel software state of all pending transfers 787286Sbill * and restart all units and the controller. 788286Sbill */ 7892395Swnj upreset(uban) 7902931Swnj int uban; 791286Sbill { 7922983Swnj register struct uba_ctlr *um; 7932983Swnj register struct uba_device *ui; 7942395Swnj register sc21, unit; 795286Sbill 7962646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7972470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7982470Swnj um->um_alive == 0) 7992395Swnj continue; 8002931Swnj printf(" sc%d", sc21); 8012395Swnj um->um_tab.b_active = 0; 8022395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8032931Swnj up_softc[sc21].sc_recal = 0; 8046346Swnj up_softc[sc21].sc_wticks = 0; 8052571Swnj if (um->um_ubinfo) { 8062571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 8072616Swnj ubadone(um); 8082395Swnj } 8093445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 8102395Swnj for (unit = 0; unit < NUP; unit++) { 8112395Swnj if ((ui = updinfo[unit]) == 0) 8122395Swnj continue; 8132931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 8142395Swnj continue; 8152395Swnj uputab[unit].b_active = 0; 8162395Swnj (void) upustart(ui); 8172395Swnj } 8182395Swnj (void) upstart(um); 819286Sbill } 820286Sbill } 821313Sbill 822313Sbill /* 823313Sbill * Wake up every second and if an interrupt is pending 824313Sbill * but nothing has happened increment a counter. 8252931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 826313Sbill * and begin anew. 827313Sbill */ 828313Sbill upwatch() 829313Sbill { 8302983Swnj register struct uba_ctlr *um; 8312395Swnj register sc21, unit; 8322470Swnj register struct up_softc *sc; 833313Sbill 8342759Swnj timeout(upwatch, (caddr_t)0, hz); 8352646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 8362395Swnj um = upminfo[sc21]; 8372470Swnj if (um == 0 || um->um_alive == 0) 8382470Swnj continue; 8392470Swnj sc = &up_softc[sc21]; 8402395Swnj if (um->um_tab.b_active == 0) { 8412395Swnj for (unit = 0; unit < NUP; unit++) 8422629Swnj if (uputab[unit].b_active && 8432629Swnj updinfo[unit]->ui_mi == um) 8442395Swnj goto active; 8452470Swnj sc->sc_wticks = 0; 8462395Swnj continue; 8472395Swnj } 8482931Swnj active: 8492470Swnj sc->sc_wticks++; 8502470Swnj if (sc->sc_wticks >= 20) { 8512470Swnj sc->sc_wticks = 0; 8522931Swnj printf("sc%d: lost interrupt\n", sc21); 8532646Swnj ubareset(um->um_ubanum); 8542395Swnj } 855313Sbill } 856313Sbill } 8572379Swnj 8582379Swnj #define DBSIZE 20 8592379Swnj 8602379Swnj updump(dev) 8612379Swnj dev_t dev; 8622379Swnj { 8632629Swnj struct updevice *upaddr; 8642379Swnj char *start; 8653107Swnj int num, blk, unit; 8662379Swnj struct size *sizes; 8672395Swnj register struct uba_regs *uba; 8682983Swnj register struct uba_device *ui; 8692379Swnj register short *rp; 8702395Swnj struct upst *st; 8716848Ssam register int retry; 8722379Swnj 8732395Swnj unit = minor(dev) >> 3; 8742889Swnj if (unit >= NUP) 8752889Swnj return (ENXIO); 8762470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8772983Swnj ui = phys(struct uba_device *, updinfo[unit]); 8782889Swnj if (ui->ui_alive == 0) 8792889Swnj return (ENXIO); 8802395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8812983Swnj ubainit(uba); 8822629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8836848Ssam DELAY(5000000); 8842379Swnj num = maxfree; 8852379Swnj upaddr->upcs2 = unit; 8862983Swnj DELAY(100); 8876848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 8886848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 8896848Ssam upaddr->upof = UPOF_FMT22; 8906848Ssam retry = 0; 8916848Ssam do { 8926848Ssam DELAY(25); 8936848Ssam if (++retry > 527) 8946848Ssam break; 8956861Ssam } while ((upaddr->upds & UP_RDY) == 0); 8963445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 8972889Swnj return (EFAULT); 8986848Ssam start = 0; 8992470Swnj st = &upst[ui->ui_type]; 9002395Swnj sizes = phys(struct size *, st->sizes); 9012889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 9022889Swnj return (EINVAL); 9032379Swnj while (num > 0) { 9042379Swnj register struct pte *io; 9052379Swnj register int i; 9062379Swnj int cn, sn, tn; 9072379Swnj daddr_t bn; 9082379Swnj 9092379Swnj blk = num > DBSIZE ? DBSIZE : num; 9102395Swnj io = uba->uba_map; 9112379Swnj for (i = 0; i < blk; i++) 9122983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 9132379Swnj *(int *)io = 0; 9142379Swnj bn = dumplo + btop(start); 9152607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 9162607Swnj sn = bn%st->nspc; 9172607Swnj tn = sn/st->nsect; 9182607Swnj sn = sn%st->nsect; 9192379Swnj upaddr->updc = cn; 9202379Swnj rp = (short *) &upaddr->upda; 9212379Swnj *rp = (tn << 8) + sn; 9222379Swnj *--rp = 0; 9232379Swnj *--rp = -blk*NBPG / sizeof (short); 9242629Swnj *--rp = UP_GO|UP_WCOM; 9256848Ssam retry = 0; 9262379Swnj do { 9272379Swnj DELAY(25); 9286848Ssam if (++retry > 527) 9296848Ssam break; 9302629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 9316848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 9326861Ssam printf("up%d: not ready", unit); 9336848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 9346848Ssam printf("\n"); 9356848Ssam return (EIO); 9366848Ssam } 9376848Ssam printf(" (flakey)\n"); 9386848Ssam } 9393445Sroot if (upaddr->upds&UPDS_ERR) 9402889Swnj return (EIO); 9412379Swnj start += blk*NBPG; 9422379Swnj num -= blk; 9432379Swnj } 9442379Swnj return (0); 9452379Swnj } 9461902Swnj #endif 947