1*9357Ssam /* up.c 4.61 82/11/26 */ 2*9357Ssam .f 3264Sbill 41937Swnj #include "up.h" 52646Swnj #if NSC > 0 6264Sbill /* 7*9357Ssam * UNIBUS disk driver with overlapped seeks and ECC recovery. 82889Swnj * 92889Swnj * TODO: 10*9357Ssam * Add bad sector forwarding code 113445Sroot * Check that offset recovery code works 12264Sbill */ 13264Sbill 14264Sbill #include "../h/param.h" 15264Sbill #include "../h/systm.h" 16308Sbill #include "../h/dk.h" 17264Sbill #include "../h/buf.h" 18264Sbill #include "../h/conf.h" 19264Sbill #include "../h/dir.h" 20264Sbill #include "../h/user.h" 21264Sbill #include "../h/map.h" 22420Sbill #include "../h/pte.h" 232571Swnj #include "../h/vm.h" 242379Swnj #include "../h/cmap.h" 25*9357Ssam #include "../h/uio.h" 26264Sbill 27*9357Ssam #include "../vax/cpu.h" 28*9357Ssam #include "../vax/nexus.h" 29*9357Ssam #include "../vaxuba/ubavar.h" 30*9357Ssam #include "../vaxuba/ubareg.h" 31*9357Ssam #include "../vaxuba/upreg.h" 32*9357Ssam 332395Swnj struct up_softc { 342395Swnj int sc_softas; 352607Swnj int sc_ndrive; 362395Swnj int sc_wticks; 372674Swnj int sc_recal; 382646Swnj } up_softc[NSC]; 39275Sbill 402395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 41264Sbill struct size 42264Sbill { 43264Sbill daddr_t nblocks; 44264Sbill int cyloff; 45264Sbill } up_sizes[8] = { 466436Swnj #ifdef ERNIE 476436Swnj 49324, 0, /* A=cyl 0 thru 26 */ 486436Swnj #else 49264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 506436Swnj #endif 51264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 52341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 53264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 54264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 553730Sroot #ifndef NOBADSECT 563730Sroot 81376, 681, /* F=cyl 681 thru 814 */ 573730Sroot 153728, 562, /* G=cyl 562 thru 814 */ 583730Sroot #else 593730Sroot 81472, 681, 603730Sroot 153824, 562, 613730Sroot #endif 62264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 632395Swnj }, fj_sizes[8] = { 642395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 652395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 662395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 672395Swnj 0, 0, 682395Swnj 0, 0, 692395Swnj 0, 0, 702395Swnj 0, 0, 713730Sroot #ifndef NOBADSECT 723730Sroot 213664, 155, /* H=cyl 155 thru 822 */ 733730Sroot #else 743730Sroot 213760, 155, 753730Sroot #endif 766851Ssam }, upam_sizes[8] = { 776305Sroot 15884, 0, /* A=cyl 0 thru 31 */ 786305Sroot 33440, 32, /* B=cyl 32 thru 97 */ 796305Sroot 524288, 0, /* C=cyl 0 thru 1023 */ 806602Ssam 27786, 668, 816602Ssam 27786, 723, 826602Ssam 125440, 778, 836305Sroot 181760, 668, /* G=cyl 668 thru 1022 */ 846305Sroot 291346, 98, /* H=cyl 98 thru 667 */ 85264Sbill }; 862395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 87264Sbill 886346Swnj /* 896346Swnj * On a 780 upSDIST could be 2, but 906346Swnj * in the interest of 750's... 916346Swnj */ 926346Swnj #define _upSDIST 3 /* 1.5 msec */ 932395Swnj #define _upRDIST 4 /* 2.0 msec */ 94264Sbill 952395Swnj int upSDIST = _upSDIST; 962395Swnj int upRDIST = _upRDIST; 972395Swnj 982607Swnj int upprobe(), upslave(), upattach(), updgo(), upintr(); 992983Swnj struct uba_ctlr *upminfo[NSC]; 1002983Swnj struct uba_device *updinfo[NUP]; 1016383Swnj #define UPIPUNITS 8 1026383Swnj struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ 1032395Swnj 1042607Swnj u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; 1052616Swnj struct uba_driver scdriver = 1062607Swnj { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; 1072395Swnj struct buf uputab[NUP]; 1082395Swnj 1092395Swnj struct upst { 1102395Swnj short nsect; 1112395Swnj short ntrak; 1122395Swnj short nspc; 1132395Swnj short ncyl; 1142395Swnj struct size *sizes; 1152395Swnj } upst[] = { 1162607Swnj 32, 19, 32*19, 823, up_sizes, /* 9300/cdc */ 1172607Swnj /* 9300 actually has 815 cylinders... */ 1182395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 1196851Ssam 32, 16, 32*16, 1024, upam_sizes, /* ampex capricorn */ 1202395Swnj }; 1212395Swnj 1222629Swnj u_char up_offset[16] = { 123*9357Ssam UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, 124*9357Ssam UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, 125*9357Ssam UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, 126*9357Ssam 0, 0, 0, 0 1272629Swnj }; 128264Sbill 1292616Swnj struct buf rupbuf[NUP]; 130264Sbill 131264Sbill #define b_cylin b_resid 132264Sbill 133264Sbill #ifdef INTRLVE 134264Sbill daddr_t dkblock(); 135264Sbill #endif 1362395Swnj 1372395Swnj int upwstart, upwatch(); /* Have started guardian */ 1382470Swnj int upseek; 1392681Swnj int upwaitdry; 1402395Swnj 1412395Swnj /*ARGSUSED*/ 1422607Swnj upprobe(reg) 1432395Swnj caddr_t reg; 1442395Swnj { 1452459Swnj register int br, cvec; 1462459Swnj 1472607Swnj #ifdef lint 1482607Swnj br = 0; cvec = br; br = cvec; 1492607Swnj #endif 1502629Swnj ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; 1512607Swnj DELAY(10); 1522629Swnj ((struct updevice *)reg)->upcs1 = 0; 153*9357Ssam return (sizeof (struct updevice)); 1542395Swnj } 1552395Swnj 1562607Swnj upslave(ui, reg) 1572983Swnj struct uba_device *ui; 1582395Swnj caddr_t reg; 1592395Swnj { 1602629Swnj register struct updevice *upaddr = (struct updevice *)reg; 1612395Swnj 1622395Swnj upaddr->upcs1 = 0; /* conservative */ 1632607Swnj upaddr->upcs2 = ui->ui_slave; 1646843Swnj upaddr->upcs1 = UP_NOP|UP_GO; 1653445Sroot if (upaddr->upcs2&UPCS2_NED) { 1662629Swnj upaddr->upcs1 = UP_DCLR|UP_GO; 1672395Swnj return (0); 1682395Swnj } 1692607Swnj return (1); 1702607Swnj } 1712607Swnj 1722607Swnj upattach(ui) 1732983Swnj register struct uba_device *ui; 1742607Swnj { 1752629Swnj register struct updevice *upaddr; 1762607Swnj 1772395Swnj if (upwstart == 0) { 1782759Swnj timeout(upwatch, (caddr_t)0, hz); 1792395Swnj upwstart++; 1802395Swnj } 1812571Swnj if (ui->ui_dk >= 0) 1822571Swnj dk_mspw[ui->ui_dk] = .0000020345; 1832607Swnj upip[ui->ui_ctlr][ui->ui_slave] = ui; 1842607Swnj up_softc[ui->ui_ctlr].sc_ndrive++; 1852629Swnj upaddr = (struct updevice *)ui->ui_addr; 1862629Swnj upaddr->upcs1 = 0; 1872629Swnj upaddr->upcs2 = ui->ui_slave; 1883496Sroot upaddr->uphr = UPHR_MAXTRAK; 1893553Swnj if (upaddr->uphr == 9) 1903496Sroot ui->ui_type = 1; /* fujitsu hack */ 1916305Sroot else if (upaddr->uphr == 15) 1926305Sroot ui->ui_type = 2; /* ampex hack */ 1933496Sroot upaddr->upcs2 = UPCS2_CLR; 194*9357Ssam /* 195*9357Ssam upaddr->uphr = UPHR_MAXCYL; 196*9357Ssam printf("maxcyl %d\n", upaddr->uphr); 197*9357Ssam upaddr->uphr = UPHR_MAXTRAK; 198*9357Ssam printf("maxtrak %d\n", upaddr->uphr); 199*9357Ssam upaddr->uphr = UPHR_MAXSECT; 200*9357Ssam printf("maxsect %d\n", upaddr->uphr); 201*9357Ssam */ 2022395Swnj } 203264Sbill 204264Sbill upstrategy(bp) 2052395Swnj register struct buf *bp; 206264Sbill { 2072983Swnj register struct uba_device *ui; 2082395Swnj register struct upst *st; 2092395Swnj register int unit; 2102470Swnj register struct buf *dp; 2112395Swnj int xunit = minor(bp->b_dev) & 07; 2122470Swnj long bn, sz; 213264Sbill 2142470Swnj sz = (bp->b_bcount+511) >> 9; 215264Sbill unit = dkunit(bp); 2162395Swnj if (unit >= NUP) 2172395Swnj goto bad; 2182395Swnj ui = updinfo[unit]; 2192395Swnj if (ui == 0 || ui->ui_alive == 0) 2202395Swnj goto bad; 2212395Swnj st = &upst[ui->ui_type]; 2222395Swnj if (bp->b_blkno < 0 || 2232395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 2242395Swnj goto bad; 2252395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 2266305Sroot (void) spl5(); 2272470Swnj dp = &uputab[ui->ui_unit]; 2282470Swnj disksort(dp, bp); 2292470Swnj if (dp->b_active == 0) { 2302395Swnj (void) upustart(ui); 2312395Swnj bp = &ui->ui_mi->um_tab; 2322395Swnj if (bp->b_actf && bp->b_active == 0) 2332395Swnj (void) upstart(ui->ui_mi); 234264Sbill } 2356305Sroot (void) spl0(); 2362395Swnj return; 2372395Swnj 2382395Swnj bad: 2392395Swnj bp->b_flags |= B_ERROR; 2402395Swnj iodone(bp); 2412395Swnj return; 242264Sbill } 243264Sbill 2442674Swnj /* 2452674Swnj * Unit start routine. 2462674Swnj * Seek the drive to be where the data is 2472674Swnj * and then generate another interrupt 2482674Swnj * to actually start the transfer. 2492674Swnj * If there is only one drive on the controller, 2502674Swnj * or we are very close to the data, don't 2512674Swnj * bother with the search. If called after 2522674Swnj * searching once, don't bother to look where 2532674Swnj * we are, just queue for transfer (to avoid 2542674Swnj * positioning forever without transferrring.) 2552674Swnj */ 2562395Swnj upustart(ui) 2572983Swnj register struct uba_device *ui; 258264Sbill { 259264Sbill register struct buf *bp, *dp; 2602983Swnj register struct uba_ctlr *um; 2612629Swnj register struct updevice *upaddr; 2622395Swnj register struct upst *st; 263264Sbill daddr_t bn; 2642674Swnj int sn, csn; 2652607Swnj /* 2662607Swnj * The SC21 cancels commands if you just say 2672629Swnj * cs1 = UP_IE 2682607Swnj * so we are cautious about handling of cs1. 2692607Swnj * Also don't bother to clear as bits other than in upintr(). 2702607Swnj */ 2712674Swnj int didie = 0; 2722674Swnj 2732674Swnj if (ui == 0) 2742674Swnj return (0); 2752983Swnj um = ui->ui_mi; 2762395Swnj dk_busy &= ~(1<<ui->ui_dk); 2772395Swnj dp = &uputab[ui->ui_unit]; 278266Sbill if ((bp = dp->b_actf) == NULL) 279268Sbill goto out; 2802674Swnj /* 2812674Swnj * If the controller is active, just remember 2822674Swnj * that this device would like to be positioned... 2832674Swnj * if we tried to position now we would confuse the SC21. 2842674Swnj */ 2852395Swnj if (um->um_tab.b_active) { 2862459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 287275Sbill return (0); 288275Sbill } 2892674Swnj /* 2902674Swnj * If we have already positioned this drive, 2912674Swnj * then just put it on the ready queue. 2922674Swnj */ 293276Sbill if (dp->b_active) 294276Sbill goto done; 295276Sbill dp->b_active = 1; 2962629Swnj upaddr = (struct updevice *)um->um_addr; 2972395Swnj upaddr->upcs2 = ui->ui_slave; 2982674Swnj /* 2992674Swnj * If drive has just come up, 3002674Swnj * setup the pack. 3012674Swnj */ 302*9357Ssam if ((upaddr->upds & UPDS_VV) == 0) { 3032607Swnj /* SHOULD WARN SYSTEM THAT THIS HAPPENED */ 3042629Swnj upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; 3052629Swnj upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; 3063445Sroot upaddr->upof = UPOF_FMT22; 307268Sbill didie = 1; 308264Sbill } 3092674Swnj /* 3102674Swnj * If drive is offline, forget about positioning. 3112674Swnj */ 3123445Sroot if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) 313275Sbill goto done; 3142674Swnj /* 3152674Swnj * If there is only one drive, 3162674Swnj * dont bother searching. 3172674Swnj */ 3182607Swnj if (up_softc[um->um_ctlr].sc_ndrive == 1) 3192607Swnj goto done; 3202674Swnj /* 3212674Swnj * Figure out where this transfer is going to 3222674Swnj * and see if we are close enough to justify not searching. 3232674Swnj */ 3242395Swnj st = &upst[ui->ui_type]; 325264Sbill bn = dkblock(bp); 3262395Swnj sn = bn%st->nspc; 3272395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 3282674Swnj if (bp->b_cylin - upaddr->updc) 329266Sbill goto search; /* Not on-cylinder */ 330275Sbill else if (upseek) 331275Sbill goto done; /* Ok just to be on-cylinder */ 332264Sbill csn = (upaddr->upla>>6) - sn - 1; 333266Sbill if (csn < 0) 3342395Swnj csn += st->nsect; 3352395Swnj if (csn > st->nsect - upRDIST) 336264Sbill goto done; 337264Sbill search: 3382674Swnj upaddr->updc = bp->b_cylin; 3392674Swnj /* 3402674Swnj * Not on cylinder at correct position, 3412674Swnj * seek/search. 3422674Swnj */ 343275Sbill if (upseek) 3442629Swnj upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; 3452470Swnj else { 346275Sbill upaddr->upda = sn; 3472629Swnj upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; 348275Sbill } 349268Sbill didie = 1; 3502674Swnj /* 3512674Swnj * Mark unit busy for iostat. 3522674Swnj */ 3532395Swnj if (ui->ui_dk >= 0) { 3542395Swnj dk_busy |= 1<<ui->ui_dk; 3552395Swnj dk_seek[ui->ui_dk]++; 356264Sbill } 357268Sbill goto out; 358264Sbill done: 3592674Swnj /* 3602674Swnj * Device is ready to go. 3612674Swnj * Put it on the ready queue for the controller 3622674Swnj * (unless its already there.) 3632674Swnj */ 3642629Swnj if (dp->b_active != 2) { 3652629Swnj dp->b_forw = NULL; 3662629Swnj if (um->um_tab.b_actf == NULL) 3672629Swnj um->um_tab.b_actf = dp; 3682629Swnj else 3692629Swnj um->um_tab.b_actl->b_forw = dp; 3702629Swnj um->um_tab.b_actl = dp; 3712629Swnj dp->b_active = 2; 3722629Swnj } 373268Sbill out: 374268Sbill return (didie); 375264Sbill } 376264Sbill 3772674Swnj /* 3782674Swnj * Start up a transfer on a drive. 3792674Swnj */ 3802395Swnj upstart(um) 3812983Swnj register struct uba_ctlr *um; 382264Sbill { 383264Sbill register struct buf *bp, *dp; 3842983Swnj register struct uba_device *ui; 3852629Swnj register struct updevice *upaddr; 3862470Swnj struct upst *st; 387264Sbill daddr_t bn; 3882681Swnj int dn, sn, tn, cmd, waitdry; 389264Sbill 390264Sbill loop: 3912674Swnj /* 3922674Swnj * Pull a request off the controller queue 3932674Swnj */ 3942395Swnj if ((dp = um->um_tab.b_actf) == NULL) 395268Sbill return (0); 396264Sbill if ((bp = dp->b_actf) == NULL) { 3972395Swnj um->um_tab.b_actf = dp->b_forw; 398264Sbill goto loop; 399264Sbill } 4002674Swnj /* 4012674Swnj * Mark controller busy, and 4022674Swnj * determine destination of this request. 4032674Swnj */ 4042395Swnj um->um_tab.b_active++; 4052395Swnj ui = updinfo[dkunit(bp)]; 406264Sbill bn = dkblock(bp); 4072395Swnj dn = ui->ui_slave; 4082395Swnj st = &upst[ui->ui_type]; 4092395Swnj sn = bn%st->nspc; 4102395Swnj tn = sn/st->nsect; 4112395Swnj sn %= st->nsect; 4122629Swnj upaddr = (struct updevice *)ui->ui_addr; 4132674Swnj /* 4142674Swnj * Select drive if not selected already. 4152674Swnj */ 4162674Swnj if ((upaddr->upcs2&07) != dn) 4172674Swnj upaddr->upcs2 = dn; 4182674Swnj /* 4192674Swnj * Check that it is ready and online 4202674Swnj */ 4212681Swnj waitdry = 0; 4223445Sroot while ((upaddr->upds&UPDS_DRY) == 0) { 4237036Swnj printf("up%d: ds wait ds=%o\n",dkunit(bp),upaddr->upds); 4242681Swnj if (++waitdry > 512) 4252681Swnj break; 4262681Swnj upwaitdry++; 4272681Swnj } 4283445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4292931Swnj printf("up%d: not ready", dkunit(bp)); 4303445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 4312607Swnj printf("\n"); 4322395Swnj um->um_tab.b_active = 0; 4332395Swnj um->um_tab.b_errcnt = 0; 434893Sbill dp->b_actf = bp->av_forw; 435893Sbill dp->b_active = 0; 436893Sbill bp->b_flags |= B_ERROR; 437893Sbill iodone(bp); 438893Sbill goto loop; 439893Sbill } 4402674Swnj /* 4412674Swnj * Oh, well, sometimes this 4422674Swnj * happens, for reasons unknown. 4432674Swnj */ 4442629Swnj printf(" (flakey)\n"); 445264Sbill } 4462674Swnj /* 4472674Swnj * Setup for the transfer, and get in the 4482674Swnj * UNIBUS adaptor queue. 4492674Swnj */ 4502424Skre upaddr->updc = bp->b_cylin; 451264Sbill upaddr->upda = (tn << 8) + sn; 452264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 453264Sbill if (bp->b_flags & B_READ) 4542629Swnj cmd = UP_IE|UP_RCOM|UP_GO; 455264Sbill else 4562629Swnj cmd = UP_IE|UP_WCOM|UP_GO; 4572571Swnj um->um_cmd = cmd; 4583107Swnj (void) ubago(ui); 459268Sbill return (1); 460264Sbill } 461264Sbill 4622674Swnj /* 4632674Swnj * Now all ready to go, stuff the registers. 4642674Swnj */ 4652571Swnj updgo(um) 4662983Swnj struct uba_ctlr *um; 4672395Swnj { 4682629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 4692470Swnj 4706953Swnj um->um_tab.b_active = 2; /* should now be 2 */ 4712571Swnj upaddr->upba = um->um_ubinfo; 4722571Swnj upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); 4732395Swnj } 4742395Swnj 4752674Swnj /* 4762674Swnj * Handle a disk interrupt. 4772674Swnj */ 4782707Swnj upintr(sc21) 4792395Swnj register sc21; 480264Sbill { 481264Sbill register struct buf *bp, *dp; 4822983Swnj register struct uba_ctlr *um = upminfo[sc21]; 4832983Swnj register struct uba_device *ui; 4842629Swnj register struct updevice *upaddr = (struct updevice *)um->um_addr; 485264Sbill register unit; 4862470Swnj struct up_softc *sc = &up_softc[um->um_ctlr]; 4872607Swnj int as = (upaddr->upas & 0377) | sc->sc_softas; 4882681Swnj int needie = 1, waitdry; 489264Sbill 4902470Swnj sc->sc_wticks = 0; 4912607Swnj sc->sc_softas = 0; 4922674Swnj /* 4932674Swnj * If controller wasn't transferring, then this is an 4942674Swnj * interrupt for attention status on seeking drives. 4952674Swnj * Just service them. 4962674Swnj */ 4976346Swnj if (um->um_tab.b_active != 2 && !sc->sc_recal) { 4982674Swnj if (upaddr->upcs1 & UP_TRE) 4992674Swnj upaddr->upcs1 = UP_TRE; 5002674Swnj goto doattn; 5012674Swnj } 5026953Swnj um->um_tab.b_active = 1; 5032674Swnj /* 5042674Swnj * Get device and block structures, and a pointer 5052983Swnj * to the uba_device for the drive. Select the drive. 5062674Swnj */ 5072674Swnj dp = um->um_tab.b_actf; 5082674Swnj bp = dp->b_actf; 5092674Swnj ui = updinfo[dkunit(bp)]; 5102674Swnj dk_busy &= ~(1 << ui->ui_dk); 5112674Swnj if ((upaddr->upcs2&07) != ui->ui_slave) 5122395Swnj upaddr->upcs2 = ui->ui_slave; 5132674Swnj /* 5142674Swnj * Check for and process errors on 5152674Swnj * either the drive or the controller. 5162674Swnj */ 5173445Sroot if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { 5182681Swnj waitdry = 0; 5193445Sroot while ((upaddr->upds & UPDS_DRY) == 0) { 5202681Swnj if (++waitdry > 512) 5212681Swnj break; 5222681Swnj upwaitdry++; 5232681Swnj } 5243445Sroot if (upaddr->uper1&UPER1_WLE) { 5252674Swnj /* 5262674Swnj * Give up on write locked devices 5272674Swnj * immediately. 5282674Swnj */ 5292931Swnj printf("up%d: write locked\n", dkunit(bp)); 5302674Swnj bp->b_flags |= B_ERROR; 5312674Swnj } else if (++um->um_tab.b_errcnt > 27) { 5322674Swnj /* 5332674Swnj * After 28 retries (16 without offset, and 5342674Swnj * 12 with offset positioning) give up. 5352674Swnj */ 5362931Swnj harderr(bp, "up"); 537*9357Ssam printf("cs2=%b er1=%b er2=%b\n", 538*9357Ssam upaddr->upcs2, UPCS2_BITS, 539*9357Ssam upaddr->uper1, UPER1_BITS, 540*9357Ssam upaddr->uper2, UPER2_BITS); 5412674Swnj bp->b_flags |= B_ERROR; 5422674Swnj } else { 5432674Swnj /* 5442674Swnj * Retriable error. 5452674Swnj * If a soft ecc, correct it (continuing 5462674Swnj * by returning if necessary. 5472674Swnj * Otherwise fall through and retry the transfer 5482674Swnj */ 5497183Sroot if ((upaddr->uper1&(UPER1_DCK|UPER1_ECH))==UPER1_DCK) { 550*9357Ssam if (upecc(ui)) 5512629Swnj return; 5527183Sroot } else 5537183Sroot um->um_tab.b_active = 0; /* force retry */ 5542674Swnj } 5552674Swnj /* 5562674Swnj * Clear drive error and, every eight attempts, 5572674Swnj * (starting with the fourth) 5582674Swnj * recalibrate to clear the slate. 5592674Swnj */ 5602674Swnj upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 5612674Swnj needie = 0; 5623182Swnj if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { 5632674Swnj upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; 5643160Swnj sc->sc_recal = 0; 5653160Swnj goto nextrecal; 5662674Swnj } 5672674Swnj } 5682674Swnj /* 5693160Swnj * Advance recalibration finite state machine 5703160Swnj * if recalibrate in progress, through 5713160Swnj * RECAL 5723160Swnj * SEEK 5733160Swnj * OFFSET (optional) 5743160Swnj * RETRY 5752674Swnj */ 5763160Swnj switch (sc->sc_recal) { 5773160Swnj 5783160Swnj case 1: 5793160Swnj upaddr->updc = bp->b_cylin; 5803160Swnj upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; 5813160Swnj goto nextrecal; 5823160Swnj case 2: 5833160Swnj if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) 5843160Swnj goto donerecal; 5853445Sroot upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | UPOF_FMT22; 5863160Swnj upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; 5873160Swnj goto nextrecal; 5883160Swnj nextrecal: 5893160Swnj sc->sc_recal++; 5903160Swnj um->um_tab.b_active = 1; 5913160Swnj return; 5923160Swnj donerecal: 5933160Swnj case 3: 5942674Swnj sc->sc_recal = 0; 5953160Swnj um->um_tab.b_active = 0; 5963160Swnj break; 5972674Swnj } 5982674Swnj /* 5992674Swnj * If still ``active'', then don't need any more retries. 6002674Swnj */ 6012674Swnj if (um->um_tab.b_active) { 6022674Swnj /* 6032674Swnj * If we were offset positioning, 6042674Swnj * return to centerline. 6052674Swnj */ 6062674Swnj if (um->um_tab.b_errcnt >= 16) { 6073445Sroot upaddr->upof = UPOF_FMT22; 6082674Swnj upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; 6093445Sroot while (upaddr->upds & UPDS_PIP) 6102674Swnj DELAY(25); 611268Sbill needie = 0; 612264Sbill } 6132674Swnj um->um_tab.b_active = 0; 6142674Swnj um->um_tab.b_errcnt = 0; 6152674Swnj um->um_tab.b_actf = dp->b_forw; 6162674Swnj dp->b_active = 0; 6172674Swnj dp->b_errcnt = 0; 6182674Swnj dp->b_actf = bp->av_forw; 6192674Swnj bp->b_resid = (-upaddr->upwc * sizeof(short)); 6202674Swnj iodone(bp); 6212674Swnj /* 6222674Swnj * If this unit has more work to do, 6232674Swnj * then start it up right away. 6242674Swnj */ 6252674Swnj if (dp->b_actf) 6262674Swnj if (upustart(ui)) 627268Sbill needie = 0; 628264Sbill } 6292674Swnj as &= ~(1<<ui->ui_slave); 6303403Swnj /* 6313403Swnj * Release unibus resources and flush data paths. 6323403Swnj */ 6333403Swnj ubadone(um); 6342674Swnj doattn: 6352674Swnj /* 6362674Swnj * Process other units which need attention. 6372674Swnj * For each unit which needs attention, call 6382674Swnj * the unit start routine to place the slave 6392674Swnj * on the controller device queue. 6402674Swnj */ 6413160Swnj while (unit = ffs(as)) { 6423160Swnj unit--; /* was 1 origin */ 6433160Swnj as &= ~(1<<unit); 6443160Swnj upaddr->upas = 1<<unit; 6456383Swnj if (unit < UPIPUNITS && upustart(upip[sc21][unit])) 6463160Swnj needie = 0; 6473160Swnj } 6482674Swnj /* 6492674Swnj * If the controller is not transferring, but 6502674Swnj * there are devices ready to transfer, start 6512674Swnj * the controller. 6522674Swnj */ 6532395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 6542395Swnj if (upstart(um)) 655268Sbill needie = 0; 656275Sbill if (needie) 6572629Swnj upaddr->upcs1 = UP_IE; 658264Sbill } 659264Sbill 660*9357Ssam upread(dev, uio) 6612616Swnj dev_t dev; 662*9357Ssam struct uio *uio; 663264Sbill { 6642616Swnj register int unit = minor(dev) >> 3; 6652470Swnj 6662616Swnj if (unit >= NUP) 667*9357Ssam return (ENXIO); 668*9357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_READ, minphys, uio)); 669264Sbill } 670264Sbill 671*9357Ssam upwrite(dev, uio) 6722616Swnj dev_t dev; 673*9357Ssam struct uio *uio; 674264Sbill { 6752616Swnj register int unit = minor(dev) >> 3; 6762470Swnj 6772616Swnj if (unit >= NUP) 678*9357Ssam return (ENXIO); 679*9357Ssam return (physio(upstrategy, &rupbuf[unit], dev, B_WRITE, minphys, uio)); 680264Sbill } 681264Sbill 682266Sbill /* 683266Sbill * Correct an ECC error, and restart the i/o to complete 684266Sbill * the transfer if necessary. This is quite complicated because 685266Sbill * the transfer may be going to an odd memory address base and/or 686266Sbill * across a page boundary. 687266Sbill */ 688*9357Ssam upecc(ui) 6892983Swnj register struct uba_device *ui; 690264Sbill { 6912629Swnj register struct updevice *up = (struct updevice *)ui->ui_addr; 6922395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 6932983Swnj register struct uba_ctlr *um = ui->ui_mi; 6942395Swnj register struct upst *st; 6952395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 696266Sbill register int i; 697264Sbill caddr_t addr; 698266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 699264Sbill int bn, cn, tn, sn; 700264Sbill 701264Sbill /* 702266Sbill * Npf is the number of sectors transferred before the sector 703266Sbill * containing the ECC error, and reg is the UBA register 704266Sbill * mapping (the first part of) the transfer. 705266Sbill * O is offset within a memory page of the first byte transferred. 706264Sbill */ 707*9357Ssam npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 7082571Swnj reg = btop(um->um_ubinfo&0x3ffff) + npf; 709264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 7102983Swnj printf("up%d%c: soft ecc sn%d\n", dkunit(bp), 7112889Swnj 'a'+(minor(bp->b_dev)&07), bp->b_blkno + npf); 712264Sbill mask = up->upec2; 7133445Sroot #ifdef UPECCDEBUG 7143403Swnj printf("npf %d reg %x o %d mask %o pos %d\n", npf, reg, o, mask, 7153403Swnj up->upec1); 7163445Sroot #endif 717*9357Ssam /* 718*9357Ssam * Flush the buffered data path, and compute the 719*9357Ssam * byte and bit position of the error. The variable i 720*9357Ssam * is the byte offset in the transfer, the variable byte 721*9357Ssam * is the offset from a page boundary in main memory. 722*9357Ssam */ 7232725Swnj ubapurge(um); 724*9357Ssam i = up->upec1 - 1; /* -1 makes 0 origin */ 725*9357Ssam bit = i&07; 726*9357Ssam i = (i&~07)>>3; 727*9357Ssam byte = i + o; 728266Sbill /* 729*9357Ssam * Correct while possible bits remain of mask. Since mask 730*9357Ssam * contains 11 bits, we continue while the bit offset is > -11. 731*9357Ssam * Also watch out for end of this block and the end of the whole 732*9357Ssam * transfer. 733266Sbill */ 734*9357Ssam while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 735*9357Ssam addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 736*9357Ssam (byte & PGOFSET); 7373445Sroot #ifdef UPECCDEBUG 738*9357Ssam printf("addr %x map reg %x\n", 739*9357Ssam addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); 740*9357Ssam printf("old: %x, ", getmemc(addr)); 7413445Sroot #endif 742*9357Ssam putmemc(addr, getmemc(addr)^(mask<<bit)); 7433445Sroot #ifdef UPECCDEBUG 744*9357Ssam printf("new: %x\n", getmemc(addr)); 7453445Sroot #endif 746*9357Ssam byte++; 747*9357Ssam i++; 748*9357Ssam bit -= 8; 749264Sbill } 7507183Sroot if (up->upwc == 0) { 7517183Sroot um->um_tab.b_active = 0; 752264Sbill return (0); 7537183Sroot } 754266Sbill /* 755266Sbill * Have to continue the transfer... clear the drive, 756266Sbill * and compute the position where the transfer is to continue. 757266Sbill * We have completed npf+1 sectors of the transfer already; 758266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 759266Sbill */ 7602629Swnj #ifdef notdef 7612629Swnj up->uper1 = 0; 7622629Swnj up->upcs1 |= UP_GO; 7632629Swnj #else 7642629Swnj up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; 765*9357Ssam bn = dkblock(bp); 766*9357Ssam st = &upst[ui->ui_type]; 767*9357Ssam cn = bp->b_cylin; 768*9357Ssam sn = bn%st->nspc + npf + 1; 769*9357Ssam tn = sn/st->nsect; 770*9357Ssam sn %= st->nsect; 771*9357Ssam cn += tn/st->ntrak; 772*9357Ssam tn %= st->ntrak; 773264Sbill up->updc = cn; 774266Sbill up->upda = (tn << 8) | sn; 775*9357Ssam ubaddr = (int)ptob(reg+1) + o; 776266Sbill up->upba = ubaddr; 777266Sbill cmd = (ubaddr >> 8) & 0x300; 778*9357Ssam cmd |= UP_IE|UP_GO|UP_RCOM; 779*9357Ssam um->um_tab.b_active = 2; /* continuing transfer ... */ 780266Sbill up->upcs1 = cmd; 7812629Swnj #endif 782264Sbill return (1); 783264Sbill } 784286Sbill 785286Sbill /* 786286Sbill * Reset driver after UBA init. 787286Sbill * Cancel software state of all pending transfers 788286Sbill * and restart all units and the controller. 789286Sbill */ 7902395Swnj upreset(uban) 7912931Swnj int uban; 792286Sbill { 7932983Swnj register struct uba_ctlr *um; 7942983Swnj register struct uba_device *ui; 7952395Swnj register sc21, unit; 796286Sbill 7972646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 7982470Swnj if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || 7992470Swnj um->um_alive == 0) 8002395Swnj continue; 8012931Swnj printf(" sc%d", sc21); 8022395Swnj um->um_tab.b_active = 0; 8032395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8042931Swnj up_softc[sc21].sc_recal = 0; 8056346Swnj up_softc[sc21].sc_wticks = 0; 8062571Swnj if (um->um_ubinfo) { 8072571Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 808*9357Ssam um->um_ubinfo = 0; 8092395Swnj } 8103445Sroot ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; 8112395Swnj for (unit = 0; unit < NUP; unit++) { 8122395Swnj if ((ui = updinfo[unit]) == 0) 8132395Swnj continue; 8142931Swnj if (ui->ui_alive == 0 || ui->ui_mi != um) 8152395Swnj continue; 8162395Swnj uputab[unit].b_active = 0; 8172395Swnj (void) upustart(ui); 8182395Swnj } 8192395Swnj (void) upstart(um); 820286Sbill } 821286Sbill } 822313Sbill 823313Sbill /* 824313Sbill * Wake up every second and if an interrupt is pending 825313Sbill * but nothing has happened increment a counter. 8262931Swnj * If nothing happens for 20 seconds, reset the UNIBUS 827313Sbill * and begin anew. 828313Sbill */ 829313Sbill upwatch() 830313Sbill { 8312983Swnj register struct uba_ctlr *um; 8322395Swnj register sc21, unit; 8332470Swnj register struct up_softc *sc; 834313Sbill 8352759Swnj timeout(upwatch, (caddr_t)0, hz); 8362646Swnj for (sc21 = 0; sc21 < NSC; sc21++) { 8372395Swnj um = upminfo[sc21]; 8382470Swnj if (um == 0 || um->um_alive == 0) 8392470Swnj continue; 8402470Swnj sc = &up_softc[sc21]; 8412395Swnj if (um->um_tab.b_active == 0) { 8422395Swnj for (unit = 0; unit < NUP; unit++) 8432629Swnj if (uputab[unit].b_active && 8442629Swnj updinfo[unit]->ui_mi == um) 8452395Swnj goto active; 8462470Swnj sc->sc_wticks = 0; 8472395Swnj continue; 8482395Swnj } 8492931Swnj active: 8502470Swnj sc->sc_wticks++; 8512470Swnj if (sc->sc_wticks >= 20) { 8522470Swnj sc->sc_wticks = 0; 8532931Swnj printf("sc%d: lost interrupt\n", sc21); 8542646Swnj ubareset(um->um_ubanum); 8552395Swnj } 856313Sbill } 857313Sbill } 8582379Swnj 8592379Swnj #define DBSIZE 20 8602379Swnj 8612379Swnj updump(dev) 8622379Swnj dev_t dev; 8632379Swnj { 8642629Swnj struct updevice *upaddr; 8652379Swnj char *start; 8663107Swnj int num, blk, unit; 8672379Swnj struct size *sizes; 8682395Swnj register struct uba_regs *uba; 8692983Swnj register struct uba_device *ui; 8702379Swnj register short *rp; 8712395Swnj struct upst *st; 8726848Ssam register int retry; 8732379Swnj 8742395Swnj unit = minor(dev) >> 3; 8752889Swnj if (unit >= NUP) 8762889Swnj return (ENXIO); 8772470Swnj #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) 8782983Swnj ui = phys(struct uba_device *, updinfo[unit]); 8792889Swnj if (ui->ui_alive == 0) 8802889Swnj return (ENXIO); 8812395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 8822983Swnj ubainit(uba); 8832629Swnj upaddr = (struct updevice *)ui->ui_physaddr; 8846848Ssam DELAY(5000000); 8852379Swnj num = maxfree; 8862379Swnj upaddr->upcs2 = unit; 8872983Swnj DELAY(100); 8886848Ssam upaddr->upcs1 = UP_DCLR|UP_GO; 8896848Ssam upaddr->upcs1 = UP_PRESET|UP_GO; 8906848Ssam upaddr->upof = UPOF_FMT22; 8916848Ssam retry = 0; 8926848Ssam do { 8936848Ssam DELAY(25); 8946848Ssam if (++retry > 527) 8956848Ssam break; 8966861Ssam } while ((upaddr->upds & UP_RDY) == 0); 8973445Sroot if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) 8982889Swnj return (EFAULT); 899*9357Ssam start = 0; 9008489Sroot st = &upst[ui->ui_type]; 9012395Swnj sizes = phys(struct size *, st->sizes); 9022889Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) 9032889Swnj return (EINVAL); 9042379Swnj while (num > 0) { 9052379Swnj register struct pte *io; 9062379Swnj register int i; 9072379Swnj int cn, sn, tn; 9082379Swnj daddr_t bn; 9092379Swnj 9102379Swnj blk = num > DBSIZE ? DBSIZE : num; 9112395Swnj io = uba->uba_map; 9122379Swnj for (i = 0; i < blk; i++) 9132983Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; 9142379Swnj *(int *)io = 0; 9152379Swnj bn = dumplo + btop(start); 9162607Swnj cn = bn/st->nspc + sizes[minor(dev)&07].cyloff; 9172607Swnj sn = bn%st->nspc; 9182607Swnj tn = sn/st->nsect; 9192607Swnj sn = sn%st->nsect; 9202379Swnj upaddr->updc = cn; 9212379Swnj rp = (short *) &upaddr->upda; 9222379Swnj *rp = (tn << 8) + sn; 9232379Swnj *--rp = 0; 9242379Swnj *--rp = -blk*NBPG / sizeof (short); 9252629Swnj *--rp = UP_GO|UP_WCOM; 9266848Ssam retry = 0; 9272379Swnj do { 9282379Swnj DELAY(25); 9296848Ssam if (++retry > 527) 9306848Ssam break; 9312629Swnj } while ((upaddr->upcs1 & UP_RDY) == 0); 9326848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 9336861Ssam printf("up%d: not ready", unit); 9346848Ssam if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { 9356848Ssam printf("\n"); 9366848Ssam return (EIO); 9376848Ssam } 9386848Ssam printf(" (flakey)\n"); 9396848Ssam } 9403445Sroot if (upaddr->upds&UPDS_ERR) 9412889Swnj return (EIO); 9422379Swnj start += blk*NBPG; 9432379Swnj num -= blk; 9442379Swnj } 9452379Swnj return (0); 9462379Swnj } 9471902Swnj #endif 948