1*2459Swnj /* up.c 4.15 81/02/16 */ 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; 342424Skre /* 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 73*2459Swnj u_short upstd[] = { 0776700, 0774400, 0776300 }; 742395Swnj struct uba_driver updriver = 75*2459Swnj { upcntrlr, upslave, updgo, 0, upstd, "up", updinfo, upminfo }; 762395Swnj struct buf uputab[NUP]; 772395Swnj 782395Swnj struct upst { 792395Swnj short nsect; 802395Swnj short ntrak; 812395Swnj short nspc; 822395Swnj short ncyl; 832395Swnj struct size *sizes; 842395Swnj } upst[] = { 852395Swnj 32, 19, 32*19, 815, up_sizes, /* 9300 */ 862395Swnj 32, 19, 32*19, 823, up_sizes, /* so cdc will boot */ 872395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 882395Swnj }; 892395Swnj 90264Sbill int up_offset[16] = 91264Sbill { 92264Sbill P400, M400, P400, M400, 93264Sbill P800, M800, P800, M800, 94264Sbill P1200, M1200, P1200, M1200, 95264Sbill 0, 0, 0, 0, 96264Sbill }; 97264Sbill 982395Swnj struct buf rupbuf; /* GROT */ 99264Sbill 100264Sbill #define b_cylin b_resid 101264Sbill 102264Sbill #ifdef INTRLVE 103264Sbill daddr_t dkblock(); 104264Sbill #endif 1052395Swnj 1062395Swnj int upwstart, upwatch(); /* Have started guardian */ 1072395Swnj 1082395Swnj /*ARGSUSED*/ 1092395Swnj upcntrlr(um, reg) 1102395Swnj struct uba_minfo *um; 1112395Swnj caddr_t reg; 1122395Swnj { 113*2459Swnj register int br, cvec; 114*2459Swnj 1152395Swnj ((struct device *)reg)->upcs1 |= (IE|RDY); 116*2459Swnj return (1); 1172395Swnj } 1182395Swnj 119*2459Swnj upslave(ui, reg, slaveno) 1202395Swnj struct uba_dinfo *ui; 1212395Swnj caddr_t reg; 1222395Swnj { 1232395Swnj register struct device *upaddr = (struct device *)reg; 1242395Swnj 1252395Swnj upaddr->upcs1 = 0; /* conservative */ 1262395Swnj upaddr->upcs2 = slaveno; 1272395Swnj if (upaddr->upcs2&NED) { 1282395Swnj upaddr->upcs1 = DCLR|GO; 1292395Swnj return (0); 1302395Swnj } 1312395Swnj if (upwstart == 0) { 1322395Swnj timeout(upwatch, (caddr_t)0, HZ); 1332395Swnj upwstart++; 1342395Swnj } 1352395Swnj return (1); 1362395Swnj } 137264Sbill 138264Sbill /* 1392395Swnj dk_mspw[UPDK_N+unit] = .0000020345; 1402395Swnj */ 1412395Swnj 142264Sbill upstrategy(bp) 1432395Swnj register struct buf *bp; 144264Sbill { 1452395Swnj register struct uba_dinfo *ui; 1462395Swnj register struct uba_minfo *um; 1472395Swnj register struct upst *st; 1482395Swnj register int unit; 1492395Swnj int xunit = minor(bp->b_dev) & 07; 150264Sbill long sz, bn; 151264Sbill 152264Sbill sz = bp->b_bcount; 153264Sbill sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */ 154264Sbill unit = dkunit(bp); 1552395Swnj if (unit >= NUP) 1562395Swnj goto bad; 1572395Swnj ui = updinfo[unit]; 1582395Swnj if (ui == 0 || ui->ui_alive == 0) 1592395Swnj goto bad; 1602395Swnj st = &upst[ui->ui_type]; 1612395Swnj if (bp->b_blkno < 0 || 1622395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 1632395Swnj goto bad; 1642395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 165264Sbill (void) spl5(); 1662395Swnj disksort(&uputab[ui->ui_unit], bp); 1672395Swnj if (uputab[ui->ui_unit].b_active == 0) { 1682395Swnj (void) upustart(ui); 1692395Swnj bp = &ui->ui_mi->um_tab; 1702395Swnj if (bp->b_actf && bp->b_active == 0) 1712395Swnj (void) upstart(ui->ui_mi); 172264Sbill } 173264Sbill (void) spl0(); 1742395Swnj return; 1752395Swnj 1762395Swnj bad: 1772395Swnj bp->b_flags |= B_ERROR; 1782395Swnj iodone(bp); 1792395Swnj return; 180264Sbill } 181264Sbill 1822395Swnj upustart(ui) 1832395Swnj register struct uba_dinfo *ui; 184264Sbill { 185264Sbill register struct buf *bp, *dp; 1862395Swnj register struct uba_minfo *um; 1872395Swnj register struct device *upaddr; 1882395Swnj register struct upst *st; 189264Sbill daddr_t bn; 190264Sbill int sn, cn, csn; 191268Sbill int didie = 0; 192264Sbill 1932395Swnj /* SC21 cancels commands if you say cs1 = IE, so dont */ 1942395Swnj /* being ultra-cautious, we clear as bits only in upintr() */ 1952395Swnj dk_busy &= ~(1<<ui->ui_dk); 1962395Swnj dp = &uputab[ui->ui_unit]; 197266Sbill if ((bp = dp->b_actf) == NULL) 198268Sbill goto out; 1992395Swnj /* dont confuse controller by giving SEARCH while dt in progress */ 2002395Swnj um = ui->ui_mi; 2012395Swnj if (um->um_tab.b_active) { 202*2459Swnj up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; 203275Sbill return (0); 204275Sbill } 205276Sbill if (dp->b_active) 206276Sbill goto done; 207276Sbill dp->b_active = 1; 2082395Swnj upaddr = (struct device *)um->um_addr; 2092395Swnj upaddr->upcs2 = ui->ui_slave; 210266Sbill if ((upaddr->upds & VV) == 0) { 211266Sbill upaddr->upcs1 = IE|DCLR|GO; 212264Sbill upaddr->upcs1 = IE|PRESET|GO; 213264Sbill upaddr->upof = FMT22; 214268Sbill didie = 1; 215264Sbill } 216264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) 217275Sbill goto done; 2182395Swnj st = &upst[ui->ui_type]; 219264Sbill bn = dkblock(bp); 220264Sbill cn = bp->b_cylin; 2212395Swnj sn = bn%st->nspc; 2222395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 223266Sbill if (cn - upaddr->updc) 224266Sbill goto search; /* Not on-cylinder */ 2252395Swnj /**** WHAT SHOULD THIS BE NOW ??? 226275Sbill else if (upseek) 227275Sbill goto done; /* Ok just to be on-cylinder */ 228264Sbill csn = (upaddr->upla>>6) - sn - 1; 229266Sbill if (csn < 0) 2302395Swnj csn += st->nsect; 2312395Swnj if (csn > st->nsect - upRDIST) 232264Sbill goto done; 233264Sbill search: 234264Sbill upaddr->updc = cn; 2352395Swnj /*** ANOTHER OCCURRENCE 236275Sbill if (upseek) 237275Sbill upaddr->upcs1 = IE|SEEK|GO; 2382395Swnj else ****/ { 239275Sbill upaddr->upda = sn; 240275Sbill upaddr->upcs1 = IE|SEARCH|GO; 241275Sbill } 242268Sbill didie = 1; 2432395Swnj if (ui->ui_dk >= 0) { 2442395Swnj dk_busy |= 1<<ui->ui_dk; 2452395Swnj dk_seek[ui->ui_dk]++; 246264Sbill } 247268Sbill goto out; 248264Sbill done: 249264Sbill dp->b_forw = NULL; 2502395Swnj if (um->um_tab.b_actf == NULL) 2512395Swnj um->um_tab.b_actf = dp; 252264Sbill else 2532395Swnj um->um_tab.b_actl->b_forw = dp; 2542395Swnj um->um_tab.b_actl = dp; 255268Sbill out: 256268Sbill return (didie); 257264Sbill } 258264Sbill 2592395Swnj upstart(um) 2602395Swnj register struct uba_minfo *um; 261264Sbill { 262264Sbill register struct buf *bp, *dp; 2632395Swnj register struct uba_dinfo *ui; 264264Sbill register unit; 265264Sbill register struct device *upaddr; 2662395Swnj register struct upst *st; 267264Sbill daddr_t bn; 2682424Skre int dn, sn, tn, cmd; 269264Sbill 270264Sbill loop: 2712395Swnj if ((dp = um->um_tab.b_actf) == NULL) 272268Sbill return (0); 273264Sbill if ((bp = dp->b_actf) == NULL) { 2742395Swnj um->um_tab.b_actf = dp->b_forw; 275264Sbill goto loop; 276264Sbill } 277266Sbill /* 278266Sbill * Mark the controller busy, and multi-part disk address. 279266Sbill * Select the unit on which the i/o is to take place. 280266Sbill */ 2812395Swnj um->um_tab.b_active++; 2822395Swnj ui = updinfo[dkunit(bp)]; 283264Sbill bn = dkblock(bp); 2842395Swnj dn = ui->ui_slave; 2852395Swnj st = &upst[ui->ui_type]; 2862395Swnj sn = bn%st->nspc; 2872395Swnj tn = sn/st->nsect; 2882395Swnj sn %= st->nsect; 2892395Swnj upaddr = (struct device *)ui->ui_addr; 2901756Sbill if ((upaddr->upcs2 & 07) != dn) 291264Sbill upaddr->upcs2 = dn; 292*2459Swnj up_softc[um->um_ctlr].sc_info = 2932395Swnj ubasetup(ui->ui_ubanum, bp, UBA_NEEDBDP|UBA_CANTWAIT); 294266Sbill /* 295266Sbill * If drive is not present and on-line, then 296266Sbill * get rid of this with an error and loop to get 297266Sbill * rid of the rest of its queued requests. 298266Sbill * (Then on to any other ready drives.) 299266Sbill */ 300264Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 301893Sbill printf("!DPR || !MOL, unit %d, ds %o", dn, upaddr->upds); 302893Sbill if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 303893Sbill printf("-- hard\n"); 3042395Swnj um->um_tab.b_active = 0; 3052395Swnj um->um_tab.b_errcnt = 0; 306893Sbill dp->b_actf = bp->av_forw; 307893Sbill dp->b_active = 0; 308893Sbill bp->b_flags |= B_ERROR; 309893Sbill iodone(bp); 310893Sbill /* A funny place to do this ... */ 311*2459Swnj ubarelse(ui->ui_ubanum, &up_softc[um->um_ctlr].sc_info); 312893Sbill goto loop; 313893Sbill } 314893Sbill printf("-- came back\n"); 315264Sbill } 316266Sbill /* 317266Sbill * If this is a retry, then with the 16'th retry we 318266Sbill * begin to try offsetting the heads to recover the data. 319266Sbill */ 3202395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 3212395Swnj upaddr->upof = up_offset[um->um_tab.b_errcnt & 017] | FMT22; 322266Sbill upaddr->upcs1 = IE|OFFSET|GO; 323266Sbill while (upaddr->upds & PIP) 324264Sbill DELAY(25); 325264Sbill } 326266Sbill /* 327266Sbill * Now set up the transfer, retrieving the high 328266Sbill * 2 bits of the UNIBUS address from the information 329266Sbill * returned by ubasetup() for the cs1 register bits 8 and 9. 330266Sbill */ 3312424Skre upaddr->updc = bp->b_cylin; 332264Sbill upaddr->upda = (tn << 8) + sn; 333*2459Swnj upaddr->upba = up_softc[um->um_ctlr].sc_info; 334264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 335*2459Swnj cmd = (up_softc[um->um_ctlr].sc_info >> 8) & 0x300; 336264Sbill if (bp->b_flags & B_READ) 337266Sbill cmd |= IE|RCOM|GO; 338264Sbill else 339266Sbill cmd |= IE|WCOM|GO; 340266Sbill upaddr->upcs1 = cmd; 341266Sbill /* 342266Sbill * This is a controller busy situation. 3431945Swnj * Record in dk slot NUP+UPDK_N (after last drive) 344266Sbill * unless there aren't that many slots reserved for 345266Sbill * us in which case we record this as a drive busy 346266Sbill * (if there is room for that). 347266Sbill */ 3482395Swnj unit = ui->ui_dk; 3492395Swnj dk_busy |= 1<<unit; 3502395Swnj dk_xfer[unit]++; 3512395Swnj dk_wds[unit] += bp->b_bcount>>6; 352268Sbill return (1); 353264Sbill } 354264Sbill 3552395Swnj updgo() 3562395Swnj { 3572395Swnj } 3582395Swnj 359264Sbill /* 360264Sbill * Handle a device interrupt. 361264Sbill * 362264Sbill * If the transferring drive needs attention, service it 363264Sbill * retrying on error or beginning next transfer. 364264Sbill * Service all other ready drives, calling ustart to transfer 3652395Swnj * their blocks to the ready queue in um->um_tab, and then restart 366264Sbill * the controller if there is anything to do. 367264Sbill */ 3682395Swnj upintr(sc21) 3692395Swnj register sc21; 370264Sbill { 371264Sbill register struct buf *bp, *dp; 3722395Swnj register struct uba_minfo *um = upminfo[sc21]; 3732395Swnj register struct uba_dinfo *ui; 3742395Swnj register struct device *upaddr = (struct device *)um->um_addr; 375264Sbill register unit; 376264Sbill int as = upaddr->upas & 0377; 377268Sbill int needie = 1; 378264Sbill 379276Sbill (void) spl6(); 380*2459Swnj up_softc[um->um_ctlr].sc_wticks = 0; 3812395Swnj if (um->um_tab.b_active) { 382266Sbill if ((upaddr->upcs1 & RDY) == 0) { 383272Sbill printf("!RDY: cs1 %o, ds %o, wc %d\n", upaddr->upcs1, 384272Sbill upaddr->upds, upaddr->upwc); 3852395Swnj printf("as=%d act %d %d %d\n", as, um->um_tab.b_active, 386341Sbill uputab[0].b_active, uputab[1].b_active); 387269Sbill } 3882395Swnj dp = um->um_tab.b_actf; 389264Sbill bp = dp->b_actf; 3902395Swnj ui = updinfo[dkunit(bp)]; 3912395Swnj dk_busy &= ~(1 << ui->ui_dk); 3922395Swnj upaddr->upcs2 = ui->ui_slave; 393885Sbill if ((upaddr->upds&ERR) || (upaddr->upcs1&TRE)) { 3941829Sbill int cs2; 395266Sbill while ((upaddr->upds & DRY) == 0) 396264Sbill DELAY(25); 3972395Swnj if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE) 398264Sbill bp->b_flags |= B_ERROR; 399264Sbill else 4002395Swnj um->um_tab.b_active = 0; /* force retry */ 4012395Swnj if (um->um_tab.b_errcnt > 27) { 4021829Sbill cs2 = (int)upaddr->upcs2; 4032395Swnj deverror(bp, cs2, (int)upaddr->uper1); 4042395Swnj } 4052395Swnj if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui)) 406266Sbill return; 407264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 408268Sbill needie = 0; 4092395Swnj if ((um->um_tab.b_errcnt&07) == 4) { 410264Sbill upaddr->upcs1 = RECAL|GO|IE; 411264Sbill while(upaddr->upds & PIP) 412264Sbill DELAY(25); 413264Sbill } 4142395Swnj if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) { 4151829Sbill printf("FLAKEY UP "); 4162395Swnj ubareset(um->um_ubanum); 4171829Sbill return; 4181829Sbill } 419264Sbill } 4202395Swnj if (um->um_tab.b_active) { 4212395Swnj if (um->um_tab.b_errcnt >= 16) { 422266Sbill upaddr->upcs1 = RTC|GO|IE; 423266Sbill while (upaddr->upds & PIP) 424264Sbill DELAY(25); 425268Sbill needie = 0; 426264Sbill } 4272395Swnj um->um_tab.b_active = 0; 4282395Swnj um->um_tab.b_errcnt = 0; 4292395Swnj um->um_tab.b_actf = dp->b_forw; 430264Sbill dp->b_active = 0; 431264Sbill dp->b_errcnt = 0; 432264Sbill dp->b_actf = bp->av_forw; 433266Sbill bp->b_resid = (-upaddr->upwc * sizeof(short)); 434275Sbill if (bp->b_resid) 435341Sbill printf("resid %d ds %o er? %o %o %o\n", 436341Sbill bp->b_resid, upaddr->upds, 437275Sbill upaddr->uper1, upaddr->uper2, upaddr->uper3); 438264Sbill iodone(bp); 4392395Swnj if (dp->b_actf) 4402395Swnj if (upustart(ui)) 441268Sbill needie = 0; 442264Sbill } 443*2459Swnj up_softc[um->um_ctlr].sc_softas &= ~(1<<ui->ui_slave); 444*2459Swnj ubarelse(ui->ui_ubanum, &up_softc[um->um_ctlr].sc_info); 445273Sbill } else { 4461756Sbill if (upaddr->upcs1 & TRE) 447264Sbill upaddr->upcs1 = TRE; 448264Sbill } 449*2459Swnj as |= up_softc[um->um_ctlr].sc_softas; 4502395Swnj for (unit = 0; unit < NUP; unit++) { 4512395Swnj if ((ui = updinfo[unit]) == 0 || ui->ui_mi != um) 4522395Swnj continue; 4532395Swnj if (as & (1<<unit)) { 4541756Sbill if (as & (1<<unit)) 455267Sbill upaddr->upas = 1<<unit; 4562395Swnj if (upustart(ui)) 457273Sbill needie = 0; 458273Sbill } 4592395Swnj } 4602395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 4612395Swnj if (upstart(um)) 462268Sbill needie = 0; 463275Sbill if (needie) 464266Sbill upaddr->upcs1 = IE; 465264Sbill } 466264Sbill 467264Sbill upread(dev) 468264Sbill { 469264Sbill physio(upstrategy, &rupbuf, dev, B_READ, minphys); 470264Sbill } 471264Sbill 472264Sbill upwrite(dev) 473264Sbill { 474264Sbill physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); 475264Sbill } 476264Sbill 477266Sbill /* 478266Sbill * Correct an ECC error, and restart the i/o to complete 479266Sbill * the transfer if necessary. This is quite complicated because 480266Sbill * the transfer may be going to an odd memory address base and/or 481266Sbill * across a page boundary. 482266Sbill */ 4832395Swnj upecc(ui) 4842395Swnj register struct uba_dinfo *ui; 485264Sbill { 4862395Swnj register struct device *up = (struct device *)ui->ui_addr; 4872395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 4882395Swnj register struct uba_minfo *um = ui->ui_mi; 4892395Swnj register struct upst *st; 4902395Swnj struct uba_regs *ubp = ui->ui_hd->uh_uba; 491266Sbill register int i; 492264Sbill caddr_t addr; 493266Sbill int reg, bit, byte, npf, mask, o, cmd, ubaddr; 494264Sbill int bn, cn, tn, sn; 495264Sbill 496264Sbill /* 497266Sbill * Npf is the number of sectors transferred before the sector 498266Sbill * containing the ECC error, and reg is the UBA register 499266Sbill * mapping (the first part of) the transfer. 500266Sbill * O is offset within a memory page of the first byte transferred. 501264Sbill */ 502266Sbill npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; 503*2459Swnj reg = btop(up_softc[um->um_ctlr].sc_info&0x3ffff) + npf; 504264Sbill o = (int)bp->b_un.b_addr & PGOFSET; 505264Sbill printf("%D ", bp->b_blkno+npf); 506264Sbill prdev("ECC", bp->b_dev); 507264Sbill mask = up->upec2; 508264Sbill if (mask == 0) { 509266Sbill up->upof = FMT22; /* == RTC ???? */ 510264Sbill return (0); 511264Sbill } 512266Sbill /* 513266Sbill * Flush the buffered data path, and compute the 514266Sbill * byte and bit position of the error. The variable i 515266Sbill * is the byte offset in the transfer, the variable byte 516266Sbill * is the offset from a page boundary in main memory. 517266Sbill */ 518*2459Swnj ubp->uba_dpr[(up_softc[um->um_ctlr].sc_info>>28)&0x0f] |= UBA_BNE; 519266Sbill i = up->upec1 - 1; /* -1 makes 0 origin */ 520266Sbill bit = i&07; 521266Sbill i = (i&~07)>>3; 522264Sbill byte = i + o; 523266Sbill /* 524266Sbill * Correct while possible bits remain of mask. Since mask 525266Sbill * contains 11 bits, we continue while the bit offset is > -11. 526266Sbill * Also watch out for end of this block and the end of the whole 527266Sbill * transfer. 528266Sbill */ 529266Sbill while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { 530266Sbill addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ 531266Sbill (byte & PGOFSET); 532266Sbill putmemc(addr, getmemc(addr)^(mask<<bit)); 533266Sbill byte++; 534266Sbill i++; 535266Sbill bit -= 8; 536264Sbill } 5372395Swnj um->um_tab.b_active++; /* Either complete or continuing... */ 538264Sbill if (up->upwc == 0) 539264Sbill return (0); 540266Sbill /* 541266Sbill * Have to continue the transfer... clear the drive, 542266Sbill * and compute the position where the transfer is to continue. 543266Sbill * We have completed npf+1 sectors of the transfer already; 544266Sbill * restart at offset o of next sector (i.e. in UBA register reg+1). 545266Sbill */ 546266Sbill up->upcs1 = TRE|IE|DCLR|GO; 547264Sbill bn = dkblock(bp); 5482395Swnj st = &upst[ui->ui_type]; 549264Sbill cn = bp->b_cylin; 5502395Swnj sn = bn%st->nspc + npf + 1; 5512395Swnj tn = sn/st->nsect; 5522395Swnj sn %= st->nsect; 5532395Swnj cn += tn/st->ntrak; 5542395Swnj tn %= st->ntrak; 555264Sbill up->updc = cn; 556266Sbill up->upda = (tn << 8) | sn; 557266Sbill ubaddr = (int)ptob(reg+1) + o; 558266Sbill up->upba = ubaddr; 559266Sbill cmd = (ubaddr >> 8) & 0x300; 560266Sbill cmd |= IE|GO|RCOM; 561266Sbill up->upcs1 = cmd; 562264Sbill return (1); 563264Sbill } 564286Sbill 565286Sbill /* 566286Sbill * Reset driver after UBA init. 567286Sbill * Cancel software state of all pending transfers 568286Sbill * and restart all units and the controller. 569286Sbill */ 5702395Swnj upreset(uban) 571286Sbill { 5722395Swnj register struct uba_minfo *um; 5732395Swnj register struct uba_dinfo *ui; 5742395Swnj register sc21, unit; 5752424Skre int any = 0; 576286Sbill 5772395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 5782395Swnj if ((um = upminfo[sc21]) == 0) 5792395Swnj continue; 5802395Swnj if (um->um_ubanum != uban) 5812395Swnj continue; 5822395Swnj if (!um->um_alive) 5832395Swnj continue; 5842424Skre if (any == 0) { 5852424Skre printf(" up"); 5862424Skre DELAY(15000000); /* give it time to self-test */ 5872424Skre any++; 5882424Skre } 5892395Swnj um->um_tab.b_active = 0; 5902395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 591*2459Swnj if (up_softc[um->um_ctlr].sc_info) { 592*2459Swnj printf("<%d>", (up_softc[um->um_ctlr].sc_info>>28)&0xf); 593*2459Swnj ubarelse(um->um_ubanum, &up_softc[um->um_ctlr].sc_info); 5942395Swnj } 5952395Swnj ((struct device *)(um->um_addr))->upcs2 = CLR; 5962395Swnj for (unit = 0; unit < NUP; unit++) { 5972395Swnj if ((ui = updinfo[unit]) == 0) 5982395Swnj continue; 5992395Swnj if (ui->ui_alive == 0) 6002395Swnj continue; 6012395Swnj uputab[unit].b_active = 0; 6022395Swnj (void) upustart(ui); 6032395Swnj } 6042395Swnj (void) upstart(um); 605286Sbill } 606286Sbill } 607313Sbill 608313Sbill /* 609313Sbill * Wake up every second and if an interrupt is pending 610313Sbill * but nothing has happened increment a counter. 611313Sbill * If nothing happens for 20 seconds, reset the controller 612313Sbill * and begin anew. 613313Sbill */ 614313Sbill upwatch() 615313Sbill { 6162395Swnj register struct uba_minfo *um; 6172395Swnj register sc21, unit; 618313Sbill 6191783Sbill timeout(upwatch, (caddr_t)0, HZ); 6202395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 6212395Swnj um = upminfo[sc21]; 6222395Swnj if (um->um_tab.b_active == 0) { 6232395Swnj for (unit = 0; unit < NUP; unit++) 6242395Swnj if (updinfo[unit]->ui_mi == um && 6252395Swnj uputab[unit].b_active) 6262395Swnj goto active; 6272395Swnj up_softc[sc21].sc_wticks = 0; 6282395Swnj continue; 6292395Swnj } 6302395Swnj active: 6312395Swnj up_softc[sc21].sc_wticks++; 6322395Swnj if (up_softc[sc21].sc_wticks >= 20) { 6332395Swnj up_softc[sc21].sc_wticks = 0; 6342395Swnj printf("LOST INTERRUPT RESET"); 6352395Swnj upreset(um->um_ubanum); 6362395Swnj printf("\n"); 6372395Swnj } 638313Sbill } 639313Sbill } 6402379Swnj 6412379Swnj #define DBSIZE 20 6422379Swnj 6432379Swnj updump(dev) 6442379Swnj dev_t dev; 6452379Swnj { 6462379Swnj struct device *upaddr; 6472379Swnj char *start; 6482379Swnj int num, blk, unit, nsect, ntrak, nspc; 6492379Swnj struct size *sizes; 6502395Swnj register struct uba_regs *uba; 6512395Swnj register struct uba_dinfo *ui; 6522379Swnj register short *rp; 6532395Swnj struct upst *st; 6542379Swnj 6552395Swnj unit = minor(dev) >> 3; 6562395Swnj if (unit >= NUP) { 6572395Swnj printf("bad unit\n"); 6582395Swnj return (-1); 6592395Swnj } 6602395Swnj #define phys1(cast, addr) ((cast)((int)addr & 0x7fffffff)) 6612395Swnj #define phys(cast, addr) phys1(cast, phys1(cast *, &addr)) 6622395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 6632395Swnj if (ui->ui_alive == 0) { 6642395Swnj printf("dna\n"); 6652395Swnj return(-1); 6662395Swnj } 6672395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 6682395Swnj #if VAX780 6692395Swnj if (cpu == VAX_780) { 6702395Swnj uba->uba_cr = UBA_ADINIT; 6712395Swnj uba->uba_cr = UBA_IFS|UBA_BRIE|UBA_USEFIE|UBA_SUEFIE; 6722395Swnj while ((uba->uba_cnfgr & UBA_UBIC) == 0) 6732395Swnj ; 6742395Swnj } 6751809Sbill #endif 6762379Swnj DELAY(1000000); 6772395Swnj upaddr = (struct device *)ui->ui_physaddr; 6782395Swnj while ((upaddr->upcs1&DVA) == 0) 6792379Swnj ; 6802379Swnj num = maxfree; 6812379Swnj start = 0; 6822379Swnj upaddr->upcs2 = unit; 6832379Swnj if ((upaddr->upds & VV) == 0) { 6842379Swnj upaddr->upcs1 = DCLR|GO; 6852379Swnj upaddr->upcs1 = PRESET|GO; 6862379Swnj upaddr->upof = FMT22; 6872379Swnj } 6882379Swnj if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 6892379Swnj printf("up !DPR || !MOL\n"); 6902379Swnj return (-1); 6912379Swnj } 6922395Swnj st = phys1(struct upst *, &upst[ui->ui_type]); 6932395Swnj nsect = st->nsect; 6942395Swnj ntrak = st->ntrak; 6952395Swnj sizes = phys(struct size *, st->sizes); 6962379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 6972395Swnj printf("oor\n"); 6982379Swnj return (-1); 6992379Swnj } 7002395Swnj nspc = st->nspc; 7012379Swnj while (num > 0) { 7022379Swnj register struct pte *io; 7032379Swnj register int i; 7042379Swnj int cn, sn, tn; 7052379Swnj daddr_t bn; 7062379Swnj 7072379Swnj blk = num > DBSIZE ? DBSIZE : num; 7082395Swnj io = uba->uba_map; 7092379Swnj for (i = 0; i < blk; i++) 7102395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 7112379Swnj *(int *)io = 0; 7122379Swnj bn = dumplo + btop(start); 7132379Swnj cn = bn/nspc + sizes[minor(dev)&07].cyloff; 7142379Swnj sn = bn%nspc; 7152379Swnj tn = sn/nsect; 7162379Swnj sn = sn%nsect; 7172379Swnj upaddr->updc = cn; 7182379Swnj rp = (short *) &upaddr->upda; 7192379Swnj *rp = (tn << 8) + sn; 7202379Swnj *--rp = 0; 7212379Swnj *--rp = -blk*NBPG / sizeof (short); 7222379Swnj *--rp = GO|WCOM; 7232379Swnj do { 7242379Swnj DELAY(25); 7252379Swnj } while ((upaddr->upcs1 & RDY) == 0); 7262379Swnj if (upaddr->upcs1&ERR) { 7272379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 7282379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 7292379Swnj return (-1); 7302379Swnj } 7312379Swnj start += blk*NBPG; 7322379Swnj num -= blk; 7332379Swnj } 7342379Swnj return (0); 7352379Swnj } 7361902Swnj #endif 737