1*2424Skre /* up.c 4.14 81/02/15 */ 2264Sbill 31937Swnj #include "up.h" 42395Swnj #if NSC21 > 0 5264Sbill /* 6885Sbill * UNIBUS disk driver with overlapped seeks and ECC recovery. 7264Sbill */ 81756Sbill #define DELAY(N) { register int d; d = N; while (--d > 0); } 9264Sbill 10264Sbill #include "../h/param.h" 11264Sbill #include "../h/systm.h" 122395Swnj #include "../h/cpu.h" 132395Swnj #include "../h/nexus.h" 14308Sbill #include "../h/dk.h" 15264Sbill #include "../h/buf.h" 16264Sbill #include "../h/conf.h" 17264Sbill #include "../h/dir.h" 18264Sbill #include "../h/user.h" 19264Sbill #include "../h/map.h" 20420Sbill #include "../h/pte.h" 21264Sbill #include "../h/mba.h" 22264Sbill #include "../h/mtpr.h" 23264Sbill #include "../h/uba.h" 24264Sbill #include "../h/vm.h" 252379Swnj #include "../h/cmap.h" 26264Sbill 272379Swnj #include "../h/upreg.h" 28264Sbill 292395Swnj struct up_softc { 302395Swnj int sc_softas; 312395Swnj int sc_seek; 322395Swnj int sc_info; 332395Swnj int sc_wticks; 34*2424Skre /* struct uba_minfo sc_minfo; */ 352395Swnj } up_softc[NSC21]; 36275Sbill 372395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 38264Sbill struct size 39264Sbill { 40264Sbill daddr_t nblocks; 41264Sbill int cyloff; 42264Sbill } up_sizes[8] = { 43264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 44264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 45341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 46264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 47264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 48264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 49264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 50264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 512395Swnj }, fj_sizes[8] = { 522395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 532395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 542395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 552395Swnj 0, 0, 562395Swnj 0, 0, 572395Swnj 0, 0, 582395Swnj 0, 0, 592395Swnj 213760, 155, /* H=cyl 155 thru 822 */ 60264Sbill }; 612395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 62264Sbill 632395Swnj #define _upSDIST 2 /* 1.0 msec */ 642395Swnj #define _upRDIST 4 /* 2.0 msec */ 65264Sbill 662395Swnj int upSDIST = _upSDIST; 672395Swnj int upRDIST = _upRDIST; 682395Swnj 692395Swnj int upcntrlr(), upslave(), updgo(), upintr(); 702395Swnj struct uba_minfo *upminfo[NSC21]; 712395Swnj struct uba_dinfo *updinfo[NUP]; 722395Swnj struct uba_minfo up_minfo[NSC21]; 732395Swnj /* there is no reason for this to be a global structure, it 742395Swnj is only known/used locally, it would be better combined 752395Swnj with up_softc - but that would mean I would have to alter 762395Swnj more than I want to just now. Similarly, there is no longer 772395Swnj any real need for upminfo, but the code still uses it so ... 782395Swnj */ 792395Swnj 80*2424Skre extern u_short upstd[]; 812395Swnj struct uba_driver updriver = 82*2424Skre { upcntrlr, upslave, updgo, 4, 0, upstd, "up", updinfo }; 832395Swnj struct buf uputab[NUP]; 842395Swnj 852395Swnj struct upst { 862395Swnj short nsect; 872395Swnj short ntrak; 882395Swnj short nspc; 892395Swnj short ncyl; 902395Swnj struct size *sizes; 912395Swnj } upst[] = { 922395Swnj 32, 19, 32*19, 815, up_sizes, /* 9300 */ 932395Swnj 32, 19, 32*19, 823, up_sizes, /* so cdc will boot */ 942395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 952395Swnj }; 962395Swnj 97264Sbill int up_offset[16] = 98264Sbill { 99264Sbill P400, M400, P400, M400, 100264Sbill P800, M800, P800, M800, 101264Sbill P1200, M1200, P1200, M1200, 102264Sbill 0, 0, 0, 0, 103264Sbill }; 104264Sbill 1052395Swnj struct buf rupbuf; /* GROT */ 106264Sbill 107264Sbill #define b_cylin b_resid 108264Sbill 109264Sbill #ifdef INTRLVE 110264Sbill daddr_t dkblock(); 111264Sbill #endif 1122395Swnj 1132395Swnj int upwstart, upwatch(); /* Have started guardian */ 1142395Swnj 1152395Swnj /*ARGSUSED*/ 1162395Swnj upcntrlr(um, reg) 1172395Swnj struct uba_minfo *um; 1182395Swnj caddr_t reg; 1192395Swnj { 1202395Swnj ((struct device *)reg)->upcs1 |= (IE|RDY); 1212395Swnj return(1); /* just assume it is us (for now) */ 1222395Swnj } 1232395Swnj 1242395Swnj upslave(ui, reg, slaveno, uban) 1252395Swnj struct uba_dinfo *ui; 1262395Swnj caddr_t reg; 1272395Swnj { 1282395Swnj register struct device *upaddr = (struct device *)reg; 1292395Swnj register struct uba_minfo *um; 1302395Swnj register int sc21; 1312395Swnj 1322395Swnj upaddr->upcs1 = 0; /* conservative */ 1332395Swnj upaddr->upcs2 = slaveno; 1342395Swnj if (upaddr->upcs2&NED) { 1352395Swnj upaddr->upcs1 = DCLR|GO; 1362395Swnj return (0); 1372395Swnj } 1382395Swnj /*** we should check device type (return 0 if we don't like it) ***/ 1392395Swnj /*** and set type index in ui->ui_type, but we KNOW all we are ***/ 1402395Swnj /*** going to see at the minute is a 9300, and the index for a ***/ 1412395Swnj /*** 9300 is 0, which is the value already in ui->ui_type, so ..***/ 1422395Swnj 1432395Swnj um = &up_minfo[0]; 1442395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 1452395Swnj if (um->um_alive == 0) { /* this is a new ctrlr */ 1462395Swnj um->um_addr = reg; 1472395Swnj um->um_ubanum = uban; 1482395Swnj um->um_num = sc21; /* not needed after up_softc 1492395Swnj combined with um ??? */ 1502395Swnj um->um_alive = 1; 1512395Swnj upminfo[sc21] = um; /* just till upminfo vanishes */ 1522395Swnj goto found; 1532395Swnj } 1542395Swnj if (um->um_addr == reg && um->um_ubanum == uban) 1552395Swnj goto found; 1562395Swnj um++; 1572395Swnj } 1582395Swnj return(0); /* too many sc21's */ 1592395Swnj 1602395Swnj found: 1612395Swnj ui->ui_mi = um; 1622395Swnj 1632395Swnj if (upwstart == 0) { 1642395Swnj timeout(upwatch, (caddr_t)0, HZ); 1652395Swnj upwstart++; 1662395Swnj } 1672395Swnj return (1); 1682395Swnj } 169264Sbill 170264Sbill /* 1712395Swnj dk_mspw[UPDK_N+unit] = .0000020345; 1722395Swnj */ 1732395Swnj 174264Sbill upstrategy(bp) 1752395Swnj register struct buf *bp; 176264Sbill { 1772395Swnj register struct uba_dinfo *ui; 1782395Swnj register struct uba_minfo *um; 1792395Swnj register struct upst *st; 1802395Swnj register int unit; 1812395Swnj int xunit = minor(bp->b_dev) & 07; 182264Sbill long sz, bn; 183264Sbill 184264Sbill sz = bp->b_bcount; 185264Sbill sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */ 186264Sbill unit = dkunit(bp); 1872395Swnj if (unit >= NUP) 1882395Swnj goto bad; 1892395Swnj ui = updinfo[unit]; 1902395Swnj if (ui == 0 || ui->ui_alive == 0) 1912395Swnj goto bad; 1922395Swnj st = &upst[ui->ui_type]; 1932395Swnj if (bp->b_blkno < 0 || 1942395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1952395Swnj goto bad; 1962395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 197264Sbill (void) spl5(); 1982395Swnj disksort(&uputab[ui->ui_unit], bp); 1992395Swnj if (uputab[ui->ui_unit].b_active == 0) { 2002395Swnj (void) upustart(ui); 2012395Swnj bp = &ui->ui_mi->um_tab; 2022395Swnj if (bp->b_actf && bp->b_active == 0) 2032395Swnj (void) upstart(ui->ui_mi); 204264Sbill } 205264Sbill (void) spl0(); 2062395Swnj return; 2072395Swnj 2082395Swnj bad: 2092395Swnj bp->b_flags |= B_ERROR; 2102395Swnj iodone(bp); 2112395Swnj return; 212264Sbill } 213264Sbill 2142395Swnj upustart(ui) 2152395Swnj register struct uba_dinfo *ui; 216264Sbill { 217264Sbill register struct buf *bp, *dp; 2182395Swnj register struct uba_minfo *um; 2192395Swnj register struct device *upaddr; 2202395Swnj register struct upst *st; 221264Sbill daddr_t bn; 222264Sbill int sn, cn, csn; 223268Sbill int didie = 0; 224264Sbill 2252395Swnj /* SC21 cancels commands if you say cs1 = IE, so dont */ 2262395Swnj /* being ultra-cautious, we clear as bits only in upintr() */ 2272395Swnj dk_busy &= ~(1<<ui->ui_dk); 2282395Swnj dp = &uputab[ui->ui_unit]; 229266Sbill if ((bp = dp->b_actf) == NULL) 230268Sbill goto out; 2312395Swnj /* dont confuse controller by giving SEARCH while dt in progress */ 2322395Swnj um = ui->ui_mi; 2332395Swnj if (um->um_tab.b_active) { 2342395Swnj up_softc[um->um_num].sc_softas |= 1<<ui->ui_slave; 235275Sbill return (0); 236275Sbill } 237276Sbill if (dp->b_active) 238276Sbill goto done; 239276Sbill dp->b_active = 1; 2402395Swnj upaddr = (struct device *)um->um_addr; 2412395Swnj upaddr->upcs2 = ui->ui_slave; 242266Sbill if ((upaddr->upds & VV) == 0) { 243266Sbill upaddr->upcs1 = IE|DCLR|GO; 244264Sbill upaddr->upcs1 = IE|PRESET|GO; 245264Sbill upaddr->upof = FMT22; 246268Sbill didie = 1; 247264Sbill } 248264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 249275Sbill goto done; 2502395Swnj st = &upst[ui->ui_type]; 251264Sbill bn = dkblock(bp); 252264Sbill cn = bp->b_cylin; 2532395Swnj sn = bn%st->nspc; 2542395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 255266Sbill if (cn - upaddr->updc) 256266Sbill goto search; /* Not on-cylinder */ 2572395Swnj /**** WHAT SHOULD THIS BE NOW ??? 258275Sbill else if (upseek) 259275Sbill goto done; /* Ok just to be on-cylinder */ 260264Sbill csn = (upaddr->upla>>6) - sn - 1; 261266Sbill if (csn < 0) 2622395Swnj csn += st->nsect; 2632395Swnj if (csn > st->nsect - upRDIST) 264264Sbill goto done; 265264Sbill search: 266264Sbill upaddr->updc = cn; 2672395Swnj /*** ANOTHER OCCURRENCE 268275Sbill if (upseek) 269275Sbill upaddr->upcs1 = IE|SEEK|GO; 2702395Swnj else ****/ { 271275Sbill upaddr->upda = sn; 272275Sbill upaddr->upcs1 = IE|SEARCH|GO; 273275Sbill } 274268Sbill didie = 1; 2752395Swnj if (ui->ui_dk >= 0) { 2762395Swnj dk_busy |= 1<<ui->ui_dk; 2772395Swnj dk_seek[ui->ui_dk]++; 278264Sbill } 279268Sbill goto out; 280264Sbill done: 281264Sbill dp->b_forw = NULL; 2822395Swnj if (um->um_tab.b_actf == NULL) 2832395Swnj um->um_tab.b_actf = dp; 284264Sbill else 2852395Swnj um->um_tab.b_actl->b_forw = dp; 2862395Swnj um->um_tab.b_actl = dp; 287268Sbill out: 288268Sbill return (didie); 289264Sbill } 290264Sbill 2912395Swnj upstart(um) 2922395Swnj register struct uba_minfo *um; 293264Sbill { 294264Sbill register struct buf *bp, *dp; 2952395Swnj register struct uba_dinfo *ui; 296264Sbill register unit; 297264Sbill register struct device *upaddr; 2982395Swnj register struct upst *st; 299264Sbill daddr_t bn; 300*2424Skre int dn, sn, tn, cmd; 301264Sbill 302264Sbill loop: 3032395Swnj if ((dp = um->um_tab.b_actf) == NULL) 304268Sbill return (0); 305264Sbill if ((bp = dp->b_actf) == NULL) { 3062395Swnj um->um_tab.b_actf = dp->b_forw; 307264Sbill goto loop; 308264Sbill } 309266Sbill /* 310266Sbill * Mark the controller busy, and multi-part disk address. 311266Sbill * Select the unit on which the i/o is to take place. 312266Sbill */ 3132395Swnj um->um_tab.b_active++; 3142395Swnj ui = updinfo[dkunit(bp)]; 315264Sbill bn = dkblock(bp); 3162395Swnj dn = ui->ui_slave; 3172395Swnj st = &upst[ui->ui_type]; 3182395Swnj sn = bn%st->nspc; 3192395Swnj tn = sn/st->nsect; 3202395Swnj sn %= st->nsect; 3212395Swnj upaddr = (struct device *)ui->ui_addr; 3221756Sbill if ((upaddr->upcs2 & 07) != dn) 323264Sbill upaddr->upcs2 = dn; 3242395Swnj up_softc[um->um_num].sc_info = 3252395Swnj ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP|UBA_CANTWAIT); 326266Sbill /* 327266Sbill * If drive is not present and on-line, then 328266Sbill * get rid of this with an error and loop to get 329266Sbill * rid of the rest of its queued requests. 330266Sbill * (Then on to any other ready drives.) 331266Sbill */ 332264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 333893Sbill printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds); 334893Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 335893Sbill printf("-- hard\n"); 3362395Swnj um->um_tab.b_active = 0; 3372395Swnj um->um_tab.b_errcnt = 0; 338893Sbill dp->b_actf = bp->av_forw; 339893Sbill dp->b_active = 0; 340893Sbill bp->b_flags |= B_ERROR; 341893Sbill iodone(bp); 342893Sbill /* A funny place to do this ... */ 343*2424Skre ubarelse(ui->ui_ubanum, &up_softc[um->um_num].sc_info); 344893Sbill goto loop; 345893Sbill } 346893Sbill printf("-- came back\n"); 347264Sbill } 348266Sbill /* 349266Sbill * If this is a retry, then with the 16'th retry we 350266Sbill * begin to try offsetting the heads to recover the data. 351266Sbill */ 3522395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 3532395Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | FMT22; 354266Sbill upaddr->upcs1 = IE|OFFSET|GO; 355266Sbill while (upaddr->upds & PIP) 356264Sbill DELAY(25); 357264Sbill } 358266Sbill /* 359266Sbill * Now set up the transfer, retrieving the high 360266Sbill * 2 bits of the UNIBUS address from the information 361266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 362266Sbill */ 363*2424Skre upaddr->updc = bp->b_cylin; 364264Sbill upaddr->upda = (tn << 8) + sn; 3652395Swnj upaddr->upba = up_softc[um->um_num].sc_info; 366264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 3672395Swnj cmd = (up_softc[um->um_num].sc_info >> 8) & 0x300; 368264Sbill if (bp->b_flags & B_READ) 369266Sbill cmd |= IE|RCOM|GO; 370264Sbill else 371266Sbill cmd |= IE|WCOM|GO; 372266Sbill upaddr->upcs1 = cmd; 373266Sbill /* 374266Sbill * This is a controller busy situation. 3751945Swnj * Record in dk slot NUP+UPDK_N (after last drive) 376266Sbill * unless there aren't that many slots reserved for 377266Sbill * us in which case we record this as a drive busy 378266Sbill * (if there is room for that). 379266Sbill */ 3802395Swnj unit = ui->ui_dk; 3812395Swnj dk_busy |= 1<<unit; 3822395Swnj dk_xfer[unit]++; 3832395Swnj dk_wds[unit] += bp->b_bcount>>6; 384268Sbill return (1); 385264Sbill } 386264Sbill 3872395Swnj updgo() 3882395Swnj { 3892395Swnj } 3902395Swnj 391264Sbill /* 392264Sbill * Handle a device interrupt. 393264Sbill * 394264Sbill * If the transferring drive needs attention, service it 395264Sbill * retrying on error or beginning next transfer. 396264Sbill * Service all other ready drives, calling ustart to transfer 3972395Swnj * their blocks to the ready queue in um->um_tab, and then restart 398264Sbill * the controller if there is anything to do. 399264Sbill */ 4002395Swnj upintr(sc21) 4012395Swnj register sc21; 402264Sbill { 403264Sbill register struct buf *bp, *dp; 4042395Swnj register struct uba_minfo *um = upminfo[sc21]; 4052395Swnj register struct uba_dinfo *ui; 4062395Swnj register struct device *upaddr = (struct device *)um->um_addr; 407264Sbill register unit; 408264Sbill int as = upaddr->upas & 0377; 409268Sbill int needie = 1; 410264Sbill 411276Sbill (void) spl6(); 4122395Swnj up_softc[um->um_num].sc_wticks = 0; 4132395Swnj if (um->um_tab.b_active) { 414266Sbill if ((upaddr->upcs1 & RDY) == 0) { 415272Sbill printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1, 416272Sbill upaddr->upds, upaddr->upwc); 4172395Swnj printf("as=%d act %d %d %d\n", as, um->um_tab.b_active, 418341Sbill uputab[0].b_active, uputab[1].b_active); 419269Sbill } 4202395Swnj dp = um->um_tab.b_actf; 421264Sbill bp = dp->b_actf; 4222395Swnj ui = updinfo[dkunit(bp)]; 4232395Swnj dk_busy &= ~(1 << ui->ui_dk); 4242395Swnj upaddr->upcs2 = ui->ui_slave; 425885Sbill if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) { 4261829Sbill int cs2; 427266Sbill while ((upaddr->upds & DRY) == 0) 428264Sbill DELAY(25); 4292395Swnj if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE) 430264Sbill bp->b_flags |= B_ERROR; 431264Sbill else 4322395Swnj um->um_tab.b_active = 0; /* force retry */ 4332395Swnj if (um->um_tab.b_errcnt > 27) { 4341829Sbill cs2 = (int)upaddr->upcs2; 4352395Swnj deverror(bp, cs2, (int)upaddr->uper1); 4362395Swnj } 4372395Swnj if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui)) 438266Sbill return; 439264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 440268Sbill needie = 0; 4412395Swnj if ((um->um_tab.b_errcnt&07) == 4) { 442264Sbill upaddr->upcs1 = RECAL|GO|IE; 443264Sbill while(upaddr->upds & PIP) 444264Sbill DELAY(25); 445264Sbill } 4462395Swnj if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) { 4471829Sbill printf("FLAKEY UP "); 4482395Swnj ubareset(um->um_ubanum); 4491829Sbill return; 4501829Sbill } 451264Sbill } 4522395Swnj if (um->um_tab.b_active) { 4532395Swnj if (um->um_tab.b_errcnt >= 16) { 454266Sbill upaddr->upcs1 = RTC|GO|IE; 455266Sbill while (upaddr->upds & PIP) 456264Sbill DELAY(25); 457268Sbill needie = 0; 458264Sbill } 4592395Swnj um->um_tab.b_active = 0; 4602395Swnj um->um_tab.b_errcnt = 0; 4612395Swnj um->um_tab.b_actf = dp->b_forw; 462264Sbill dp->b_active = 0; 463264Sbill dp->b_errcnt = 0; 464264Sbill dp->b_actf = bp->av_forw; 465266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 466275Sbill if (bp->b_resid) 467341Sbill printf("resid %d ds %o er? %o %o %o\n", 468341Sbill bp->b_resid, upaddr->upds, 469275Sbill upaddr->uper1, upaddr->uper2, upaddr->uper3); 470264Sbill iodone(bp); 4712395Swnj if (dp->b_actf) 4722395Swnj if (upustart(ui)) 473268Sbill needie = 0; 474264Sbill } 4752395Swnj up_softc[um->um_num].sc_softas &= ~(1<<ui->ui_slave); 476*2424Skre ubarelse(ui->ui_ubanum, &up_softc[um->um_num].sc_info); 477273Sbill } else { 4781756Sbill if (upaddr->upcs1 & TRE) 479264Sbill upaddr->upcs1 = TRE; 480264Sbill } 4812395Swnj as |= up_softc[um->um_num].sc_softas; 4822395Swnj for (unit = 0; unit < NUP; unit++) { 4832395Swnj if ((ui = updinfo[unit]) == 0 || ui->ui_mi != um) 4842395Swnj continue; 4852395Swnj if (as & (1<<unit)) { 4861756Sbill if (as & (1<<unit)) 487267Sbill upaddr->upas = 1<<unit; 4882395Swnj if (upustart(ui)) 489273Sbill needie = 0; 490273Sbill } 4912395Swnj } 4922395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 4932395Swnj if (upstart(um)) 494268Sbill needie = 0; 495275Sbill if (needie) 496266Sbill upaddr->upcs1 = IE; 497264Sbill } 498264Sbill 499264Sbill upread(dev) 500264Sbill { 501264Sbill physio(upstrategy, &rupbuf, dev, B_READ, minphys); 502264Sbill } 503264Sbill 504264Sbill upwrite(dev) 505264Sbill { 506264Sbill physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); 507264Sbill } 508264Sbill 509266Sbill /* 510266Sbill * Correct an ECC error, and restart the i/o to complete 511266Sbill * the transfer if necessary. This is quite complicated because 512266Sbill * the transfer may be going to an odd memory address base and/or 513266Sbill * across a page boundary. 514266Sbill */ 5152395Swnj upecc(ui) 5162395Swnj register struct uba_dinfo *ui; 517264Sbill { 5182395Swnj register struct device *up = (struct device *)ui->ui_addr; 5192395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 5202395Swnj register struct uba_minfo *um = ui->ui_mi; 5212395Swnj register struct upst *st; 5222395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 523266Sbill register int i; 524264Sbill caddr_t addr; 525266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 526264Sbill int bn, cn, tn, sn; 527264Sbill 528264Sbill /* 529266Sbill * Npf is the number of sectors transferred before the sector 530266Sbill * containing the ECC error, and reg is the UBA register 531266Sbill * mapping (the first part of) the transfer. 532266Sbill * O is offset within a memory page of the first byte transferred. 533264Sbill */ 534266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 5352395Swnj reg = btop(up_softc[um->um_num].sc_info&0x3ffff) + npf; 536264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 537264Sbill printf("%D ", bp->b_blkno+npf); 538264Sbill prdev("ECC", bp->b_dev); 539264Sbill mask = up->upec2; 540264Sbill if (mask == 0) { 541266Sbill up->upof = FMT22; /* == RTC ???? */ 542264Sbill return (0); 543264Sbill } 544266Sbill /* 545266Sbill * Flush the buffered data path, and compute the 546266Sbill * byte and bit position of the error. The variable i 547266Sbill * is the byte offset in the transfer, the variable byte 548266Sbill * is the offset from a page boundary in main memory. 549266Sbill */ 5502395Swnj ubp->uba_dpr[(up_softc[um->um_num].sc_info>>28)&0x0f] |= UBA_BNE; 551266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 552266Sbill bit = i&07; 553266Sbill i = (i&~07)>>3; 554264Sbill byte = i + o; 555266Sbill /* 556266Sbill * Correct while possible bits remain of mask. Since mask 557266Sbill * contains 11 bits, we continue while the bit offset is > -11. 558266Sbill * Also watch out for end of this block and the end of the whole 559266Sbill * transfer. 560266Sbill */ 561266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 562266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 563266Sbill (byte & PGOFSET); 564266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 565266Sbill byte++; 566266Sbill i++; 567266Sbill bit -= 8; 568264Sbill } 5692395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 570264Sbill if (up->upwc == 0) 571264Sbill return (0); 572266Sbill /* 573266Sbill * Have to continue the transfer... clear the drive, 574266Sbill * and compute the position where the transfer is to continue. 575266Sbill * We have completed npf+1 sectors of the transfer already; 576266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 577266Sbill */ 578266Sbill up->upcs1 = TRE|IE|DCLR|GO; 579264Sbill bn = dkblock(bp); 5802395Swnj st = &upst[ui->ui_type]; 581264Sbill cn = bp->b_cylin; 5822395Swnj sn = bn%st->nspc + npf + 1; 5832395Swnj tn = sn/st->nsect; 5842395Swnj sn %= st->nsect; 5852395Swnj cn += tn/st->ntrak; 5862395Swnj tn %= st->ntrak; 587264Sbill up->updc = cn; 588266Sbill up->upda = (tn << 8) | sn; 589266Sbill ubaddr = (int)ptob(reg+1) + o; 590266Sbill up->upba = ubaddr; 591266Sbill cmd = (ubaddr >> 8) & 0x300; 592266Sbill cmd |= IE|GO|RCOM; 593266Sbill up->upcs1 = cmd; 594264Sbill return (1); 595264Sbill } 596286Sbill 597286Sbill /* 598286Sbill * Reset driver after UBA init. 599286Sbill * Cancel software state of all pending transfers 600286Sbill * and restart all units and the controller. 601286Sbill */ 6022395Swnj upreset(uban) 603286Sbill { 6042395Swnj register struct uba_minfo *um; 6052395Swnj register struct uba_dinfo *ui; 6062395Swnj register sc21, unit; 607*2424Skre int any = 0; 608286Sbill 6092395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 6102395Swnj if ((um = upminfo[sc21]) == 0) 6112395Swnj continue; 6122395Swnj if (um->um_ubanum != uban) 6132395Swnj continue; 6142395Swnj if (!um->um_alive) 6152395Swnj continue; 616*2424Skre if (any == 0) { 617*2424Skre printf(" up"); 618*2424Skre DELAY(15000000); /* give it time to self-test */ 619*2424Skre any++; 620*2424Skre } 6212395Swnj um->um_tab.b_active = 0; 6222395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 6232395Swnj if (up_softc[um->um_num].sc_info) { 6242395Swnj printf("<%d>", (up_softc[um->um_num].sc_info>>28)&0xf); 625*2424Skre ubarelse(um->um_ubanum, &up_softc[um->um_num].sc_info); 6262395Swnj } 6272395Swnj ((struct device *)(um->um_addr))->upcs2 = CLR; 6282395Swnj for (unit = 0; unit < NUP; unit++) { 6292395Swnj if ((ui = updinfo[unit]) == 0) 6302395Swnj continue; 6312395Swnj if (ui->ui_alive == 0) 6322395Swnj continue; 6332395Swnj uputab[unit].b_active = 0; 6342395Swnj (void) upustart(ui); 6352395Swnj } 6362395Swnj (void) upstart(um); 637286Sbill } 638286Sbill } 639313Sbill 640313Sbill /* 641313Sbill * Wake up every second and if an interrupt is pending 642313Sbill * but nothing has happened increment a counter. 643313Sbill * If nothing happens for 20 seconds, reset the controller 644313Sbill * and begin anew. 645313Sbill */ 646313Sbill upwatch() 647313Sbill { 6482395Swnj register struct uba_minfo *um; 6492395Swnj register sc21, unit; 650313Sbill 6511783Sbill timeout(upwatch, (caddr_t)0, HZ); 6522395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 6532395Swnj um = upminfo[sc21]; 6542395Swnj if (um->um_tab.b_active == 0) { 6552395Swnj for (unit = 0; unit < NUP; unit++) 6562395Swnj if (updinfo[unit]->ui_mi == um && 6572395Swnj uputab[unit].b_active) 6582395Swnj goto active; 6592395Swnj up_softc[sc21].sc_wticks = 0; 6602395Swnj continue; 6612395Swnj } 6622395Swnj active: 6632395Swnj up_softc[sc21].sc_wticks++; 6642395Swnj if (up_softc[sc21].sc_wticks >= 20) { 6652395Swnj up_softc[sc21].sc_wticks = 0; 6662395Swnj printf("LOST INTERRUPT RESET"); 6672395Swnj upreset(um->um_ubanum); 6682395Swnj printf("\n"); 6692395Swnj } 670313Sbill } 671313Sbill } 6722379Swnj 6732379Swnj #define DBSIZE 20 6742379Swnj 6752379Swnj updump(dev) 6762379Swnj dev_t dev; 6772379Swnj { 6782379Swnj struct device *upaddr; 6792379Swnj char *start; 6802379Swnj int num, blk, unit, nsect, ntrak, nspc; 6812379Swnj struct size *sizes; 6822395Swnj register struct uba_regs *uba; 6832395Swnj register struct uba_dinfo *ui; 6842379Swnj register short *rp; 6852395Swnj struct upst *st; 6862379Swnj 6872395Swnj unit = minor(dev) >> 3; 6882395Swnj if (unit >= NUP) { 6892395Swnj printf("bad unit\n"); 6902395Swnj return (-1); 6912395Swnj } 6922395Swnj #define phys1(cast, addr) ((cast)((int)addr & 0x7fffffff)) 6932395Swnj #define phys(cast, addr) phys1(cast, phys1(cast *, &addr)) 6942395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 6952395Swnj if (ui->ui_alive == 0) { 6962395Swnj printf("dna\n"); 6972395Swnj return(-1); 6982395Swnj } 6992395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 7002395Swnj #if VAX780 7012395Swnj if (cpu == VAX_780) { 7022395Swnj uba->uba_cr = UBA_ADINIT; 7032395Swnj uba->uba_cr = UBA_IFS|UBA_BRIE|UBA_USEFIE|UBA_SUEFIE; 7042395Swnj while ((uba->uba_cnfgr & UBA_UBIC) == 0) 7052395Swnj ; 7062395Swnj } 7071809Sbill #endif 7082379Swnj DELAY(1000000); 7092395Swnj upaddr = (struct device *)ui->ui_physaddr; 7102395Swnj while ((upaddr->upcs1&DVA) == 0) 7112379Swnj ; 7122379Swnj num = maxfree; 7132379Swnj start = 0; 7142379Swnj upaddr->upcs2 = unit; 7152379Swnj if ((upaddr->upds & VV) == 0) { 7162379Swnj upaddr->upcs1 = DCLR|GO; 7172379Swnj upaddr->upcs1 = PRESET|GO; 7182379Swnj upaddr->upof = FMT22; 7192379Swnj } 7202379Swnj if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 7212379Swnj printf("up !DPR || !MOL\n"); 7222379Swnj return (-1); 7232379Swnj } 7242395Swnj st = phys1(struct upst *, &upst[ui->ui_type]); 7252395Swnj nsect = st->nsect; 7262395Swnj ntrak = st->ntrak; 7272395Swnj sizes = phys(struct size *, st->sizes); 7282379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 7292395Swnj printf("oor\n"); 7302379Swnj return (-1); 7312379Swnj } 7322395Swnj nspc = st->nspc; 7332379Swnj while (num > 0) { 7342379Swnj register struct pte *io; 7352379Swnj register int i; 7362379Swnj int cn, sn, tn; 7372379Swnj daddr_t bn; 7382379Swnj 7392379Swnj blk = num > DBSIZE ? DBSIZE : num; 7402395Swnj io = uba->uba_map; 7412379Swnj for (i = 0; i < blk; i++) 7422395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 7432379Swnj *(int *)io = 0; 7442379Swnj bn = dumplo + btop(start); 7452379Swnj cn = bn/nspc + sizes[minor(dev)&07].cyloff; 7462379Swnj sn = bn%nspc; 7472379Swnj tn = sn/nsect; 7482379Swnj sn = sn%nsect; 7492379Swnj upaddr->updc = cn; 7502379Swnj rp = (short *) &upaddr->upda; 7512379Swnj *rp = (tn << 8) + sn; 7522379Swnj *--rp = 0; 7532379Swnj *--rp = -blk*NBPG / sizeof (short); 7542379Swnj *--rp = GO|WCOM; 7552379Swnj do { 7562379Swnj DELAY(25); 7572379Swnj } while ((upaddr->upcs1 & RDY) == 0); 7582379Swnj if (upaddr->upcs1&ERR) { 7592379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 7602379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 7612379Swnj return (-1); 7622379Swnj } 7632379Swnj start += blk*NBPG; 7642379Swnj num -= blk; 7652379Swnj } 7662379Swnj return (0); 7672379Swnj } 7681902Swnj #endif 769