1*2395Swnj /* up.c 4.13 81/02/10 */ 2264Sbill 31937Swnj #include "up.h" 4*2395Swnj #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" 12*2395Swnj #include "../h/cpu.h" 13*2395Swnj #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 29*2395Swnj struct up_softc { 30*2395Swnj int sc_softas; 31*2395Swnj int sc_seek; 32*2395Swnj int sc_info; 33*2395Swnj int sc_wticks; 34*2395Swnj } up_softc[NSC21]; 35275Sbill 36*2395Swnj /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */ 37264Sbill struct size 38264Sbill { 39264Sbill daddr_t nblocks; 40264Sbill int cyloff; 41264Sbill } up_sizes[8] = { 42264Sbill 15884, 0, /* A=cyl 0 thru 26 */ 43264Sbill 33440, 27, /* B=cyl 27 thru 81 */ 44341Sbill 495520, 0, /* C=cyl 0 thru 814 */ 45264Sbill 15884, 562, /* D=cyl 562 thru 588 */ 46264Sbill 55936, 589, /* E=cyl 589 thru 680 */ 47264Sbill 81472, 681, /* F=cyl 681 thru 814 */ 48264Sbill 153824, 562, /* G=cyl 562 thru 814 */ 49264Sbill 291346, 82, /* H=cyl 82 thru 561 */ 50*2395Swnj }, fj_sizes[8] = { 51*2395Swnj 15884, 0, /* A=cyl 0 thru 49 */ 52*2395Swnj 33440, 50, /* B=cyl 50 thru 154 */ 53*2395Swnj 263360, 0, /* C=cyl 0 thru 822 */ 54*2395Swnj 0, 0, 55*2395Swnj 0, 0, 56*2395Swnj 0, 0, 57*2395Swnj 0, 0, 58*2395Swnj 213760, 155, /* H=cyl 155 thru 822 */ 59264Sbill }; 60*2395Swnj /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */ 61264Sbill 62*2395Swnj #define _upSDIST 2 /* 1.0 msec */ 63*2395Swnj #define _upRDIST 4 /* 2.0 msec */ 64264Sbill 65*2395Swnj int upSDIST = _upSDIST; 66*2395Swnj int upRDIST = _upRDIST; 67*2395Swnj 68*2395Swnj int upcntrlr(), upslave(), updgo(), upintr(); 69*2395Swnj struct uba_minfo *upminfo[NSC21]; 70*2395Swnj struct uba_dinfo *updinfo[NUP]; 71*2395Swnj struct uba_minfo up_minfo[NSC21]; 72*2395Swnj /* there is no reason for this to be a global structure, it 73*2395Swnj is only known/used locally, it would be better combined 74*2395Swnj with up_softc - but that would mean I would have to alter 75*2395Swnj more than I want to just now. Similarly, there is no longer 76*2395Swnj any real need for upminfo, but the code still uses it so ... 77*2395Swnj */ 78*2395Swnj 79*2395Swnj u_short upstd[] = { 0 }; 80*2395Swnj int (*upivec[])() = { upintr, 0 }; 81*2395Swnj struct uba_driver updriver = 82*2395Swnj { upcntrlr, upslave, updgo, 4, 0, upstd, updinfo, upivec }; 83*2395Swnj struct buf uputab[NUP]; 84*2395Swnj 85*2395Swnj struct upst { 86*2395Swnj short nsect; 87*2395Swnj short ntrak; 88*2395Swnj short nspc; 89*2395Swnj short ncyl; 90*2395Swnj struct size *sizes; 91*2395Swnj } upst[] = { 92*2395Swnj 32, 19, 32*19, 815, up_sizes, /* 9300 */ 93*2395Swnj 32, 19, 32*19, 823, up_sizes, /* so cdc will boot */ 94*2395Swnj 32, 10, 32*10, 823, fj_sizes, /* fujitsu 160m */ 95*2395Swnj }; 96*2395Swnj 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 105*2395Swnj struct buf rupbuf; /* GROT */ 106264Sbill 107264Sbill #define b_cylin b_resid 108264Sbill 109264Sbill #ifdef INTRLVE 110264Sbill daddr_t dkblock(); 111264Sbill #endif 112*2395Swnj 113*2395Swnj int upwstart, upwatch(); /* Have started guardian */ 114*2395Swnj 115*2395Swnj /*ARGSUSED*/ 116*2395Swnj upcntrlr(um, reg) 117*2395Swnj struct uba_minfo *um; 118*2395Swnj caddr_t reg; 119*2395Swnj { 120*2395Swnj ((struct device *)reg)->upcs1 |= (IE|RDY); 121*2395Swnj return(1); /* just assume it is us (for now) */ 122*2395Swnj } 123*2395Swnj 124*2395Swnj upslave(ui, reg, slaveno, uban) 125*2395Swnj struct uba_dinfo *ui; 126*2395Swnj caddr_t reg; 127*2395Swnj { 128*2395Swnj register struct device *upaddr = (struct device *)reg; 129*2395Swnj register struct uba_minfo *um; 130*2395Swnj register int sc21; 131*2395Swnj 132*2395Swnj upaddr->upcs1 = 0; /* conservative */ 133*2395Swnj upaddr->upcs2 = slaveno; 134*2395Swnj if (upaddr->upcs2&NED) { 135*2395Swnj upaddr->upcs1 = DCLR|GO; 136*2395Swnj return (0); 137*2395Swnj } 138*2395Swnj /*** we should check device type (return 0 if we don't like it) ***/ 139*2395Swnj /*** and set type index in ui->ui_type, but we KNOW all we are ***/ 140*2395Swnj /*** going to see at the minute is a 9300, and the index for a ***/ 141*2395Swnj /*** 9300 is 0, which is the value already in ui->ui_type, so ..***/ 142*2395Swnj 143*2395Swnj um = &up_minfo[0]; 144*2395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 145*2395Swnj if (um->um_alive == 0) { /* this is a new ctrlr */ 146*2395Swnj um->um_addr = reg; 147*2395Swnj um->um_ubanum = uban; 148*2395Swnj um->um_num = sc21; /* not needed after up_softc 149*2395Swnj combined with um ??? */ 150*2395Swnj um->um_alive = 1; 151*2395Swnj upminfo[sc21] = um; /* just till upminfo vanishes */ 152*2395Swnj goto found; 153*2395Swnj } 154*2395Swnj if (um->um_addr == reg && um->um_ubanum == uban) 155*2395Swnj goto found; 156*2395Swnj um++; 157*2395Swnj } 158*2395Swnj return(0); /* too many sc21's */ 159*2395Swnj 160*2395Swnj found: 161*2395Swnj ui->ui_mi = um; 162*2395Swnj 163*2395Swnj if (upwstart == 0) { 164*2395Swnj timeout(upwatch, (caddr_t)0, HZ); 165*2395Swnj upwstart++; 166*2395Swnj } 167*2395Swnj return (1); 168*2395Swnj } 169264Sbill 170264Sbill /* 171*2395Swnj dk_mspw[UPDK_N+unit] = .0000020345; 172*2395Swnj */ 173*2395Swnj 174264Sbill upstrategy(bp) 175*2395Swnj register struct buf *bp; 176264Sbill { 177*2395Swnj register struct uba_dinfo *ui; 178*2395Swnj register struct uba_minfo *um; 179*2395Swnj register struct upst *st; 180*2395Swnj register int unit; 181*2395Swnj 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); 187*2395Swnj if (unit >= NUP) 188*2395Swnj goto bad; 189*2395Swnj ui = updinfo[unit]; 190*2395Swnj if (ui == 0 || ui->ui_alive == 0) 191*2395Swnj goto bad; 192*2395Swnj st = &upst[ui->ui_type]; 193*2395Swnj if (bp->b_blkno < 0 || 194*2395Swnj (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks) 195*2395Swnj goto bad; 196*2395Swnj bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff; 197264Sbill (void) spl5(); 198*2395Swnj disksort(&uputab[ui->ui_unit], bp); 199*2395Swnj if (uputab[ui->ui_unit].b_active == 0) { 200*2395Swnj (void) upustart(ui); 201*2395Swnj bp = &ui->ui_mi->um_tab; 202*2395Swnj if (bp->b_actf && bp->b_active == 0) 203*2395Swnj (void) upstart(ui->ui_mi); 204264Sbill } 205264Sbill (void) spl0(); 206*2395Swnj return; 207*2395Swnj 208*2395Swnj bad: 209*2395Swnj bp->b_flags |= B_ERROR; 210*2395Swnj iodone(bp); 211*2395Swnj return; 212264Sbill } 213264Sbill 214*2395Swnj upustart(ui) 215*2395Swnj register struct uba_dinfo *ui; 216264Sbill { 217264Sbill register struct buf *bp, *dp; 218*2395Swnj register struct uba_minfo *um; 219*2395Swnj register struct device *upaddr; 220*2395Swnj register struct upst *st; 221264Sbill daddr_t bn; 222264Sbill int sn, cn, csn; 223268Sbill int didie = 0; 224264Sbill 225*2395Swnj /* SC21 cancels commands if you say cs1 = IE, so dont */ 226*2395Swnj /* being ultra-cautious, we clear as bits only in upintr() */ 227*2395Swnj dk_busy &= ~(1<<ui->ui_dk); 228*2395Swnj dp = &uputab[ui->ui_unit]; 229266Sbill if ((bp = dp->b_actf) == NULL) 230268Sbill goto out; 231*2395Swnj /* dont confuse controller by giving SEARCH while dt in progress */ 232*2395Swnj um = ui->ui_mi; 233*2395Swnj if (um->um_tab.b_active) { 234*2395Swnj 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; 240*2395Swnj upaddr = (struct device *)um->um_addr; 241*2395Swnj 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; 250*2395Swnj st = &upst[ui->ui_type]; 251264Sbill bn = dkblock(bp); 252264Sbill cn = bp->b_cylin; 253*2395Swnj sn = bn%st->nspc; 254*2395Swnj sn = (sn + st->nsect - upSDIST) % st->nsect; 255266Sbill if (cn - upaddr->updc) 256266Sbill goto search; /* Not on-cylinder */ 257*2395Swnj /**** 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) 262*2395Swnj csn += st->nsect; 263*2395Swnj if (csn > st->nsect - upRDIST) 264264Sbill goto done; 265264Sbill search: 266264Sbill upaddr->updc = cn; 267*2395Swnj /*** ANOTHER OCCURRENCE 268275Sbill if (upseek) 269275Sbill upaddr->upcs1 = IE|SEEK|GO; 270*2395Swnj else ****/ { 271275Sbill upaddr->upda = sn; 272275Sbill upaddr->upcs1 = IE|SEARCH|GO; 273275Sbill } 274268Sbill didie = 1; 275*2395Swnj if (ui->ui_dk >= 0) { 276*2395Swnj dk_busy |= 1<<ui->ui_dk; 277*2395Swnj dk_seek[ui->ui_dk]++; 278264Sbill } 279268Sbill goto out; 280264Sbill done: 281264Sbill dp->b_forw = NULL; 282*2395Swnj if (um->um_tab.b_actf == NULL) 283*2395Swnj um->um_tab.b_actf = dp; 284264Sbill else 285*2395Swnj um->um_tab.b_actl->b_forw = dp; 286*2395Swnj um->um_tab.b_actl = dp; 287268Sbill out: 288268Sbill return (didie); 289264Sbill } 290264Sbill 291*2395Swnj upstart(um) 292*2395Swnj register struct uba_minfo *um; 293264Sbill { 294264Sbill register struct buf *bp, *dp; 295*2395Swnj register struct uba_dinfo *ui; 296264Sbill register unit; 297264Sbill register struct device *upaddr; 298*2395Swnj register struct upst *st; 299264Sbill daddr_t bn; 300266Sbill int dn, sn, tn, cn, cmd; 301264Sbill 302264Sbill loop: 303*2395Swnj if ((dp = um->um_tab.b_actf) == NULL) 304268Sbill return (0); 305264Sbill if ((bp = dp->b_actf) == NULL) { 306*2395Swnj 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 */ 313*2395Swnj um->um_tab.b_active++; 314*2395Swnj ui = updinfo[dkunit(bp)]; 315264Sbill bn = dkblock(bp); 316*2395Swnj dn = ui->ui_slave; 317*2395Swnj st = &upst[ui->ui_type]; 318*2395Swnj sn = bn%st->nspc; 319*2395Swnj tn = sn/st->nsect; 320*2395Swnj sn %= st->nsect; 321*2395Swnj upaddr = (struct device *)ui->ui_addr; 3221756Sbill if ((upaddr->upcs2 & 07) != dn) 323264Sbill upaddr->upcs2 = dn; 324*2395Swnj up_softc[um->um_num].sc_info = 325*2395Swnj 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"); 336*2395Swnj um->um_tab.b_active = 0; 337*2395Swnj 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*2395Swnj ubarelse(&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 */ 352*2395Swnj if (um->um_tab.b_errcnt >= 16 && (bp->b_flags&B_READ) != 0) { 353*2395Swnj 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 */ 363264Sbill upaddr->updc = cn; 364264Sbill upaddr->upda = (tn << 8) + sn; 365*2395Swnj upaddr->upba = up_softc[um->um_num].sc_info; 366264Sbill upaddr->upwc = -bp->b_bcount / sizeof (short); 367*2395Swnj 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 */ 380*2395Swnj unit = ui->ui_dk; 381*2395Swnj dk_busy |= 1<<unit; 382*2395Swnj dk_xfer[unit]++; 383*2395Swnj dk_wds[unit] += bp->b_bcount>>6; 384268Sbill return (1); 385264Sbill } 386264Sbill 387*2395Swnj updgo() 388*2395Swnj { 389*2395Swnj } 390*2395Swnj 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 397*2395Swnj * their blocks to the ready queue in um->um_tab, and then restart 398264Sbill * the controller if there is anything to do. 399264Sbill */ 400*2395Swnj upintr(sc21) 401*2395Swnj register sc21; 402264Sbill { 403264Sbill register struct buf *bp, *dp; 404*2395Swnj register struct uba_minfo *um = upminfo[sc21]; 405*2395Swnj register struct uba_dinfo *ui; 406*2395Swnj 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(); 412*2395Swnj up_softc[um->um_num].sc_wticks = 0; 413*2395Swnj 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); 417*2395Swnj printf("as=%d act %d %d %d\n", as, um->um_tab.b_active, 418341Sbill uputab[0].b_active, uputab[1].b_active); 419269Sbill } 420*2395Swnj dp = um->um_tab.b_actf; 421264Sbill bp = dp->b_actf; 422*2395Swnj ui = updinfo[dkunit(bp)]; 423*2395Swnj dk_busy &= ~(1 << ui->ui_dk); 424*2395Swnj 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); 429*2395Swnj if (++um->um_tab.b_errcnt > 28 || upaddr->uper1&WLE) 430264Sbill bp->b_flags |= B_ERROR; 431264Sbill else 432*2395Swnj um->um_tab.b_active = 0; /* force retry */ 433*2395Swnj if (um->um_tab.b_errcnt > 27) { 4341829Sbill cs2 = (int)upaddr->upcs2; 435*2395Swnj deverror(bp, cs2, (int)upaddr->uper1); 436*2395Swnj } 437*2395Swnj if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(ui)) 438266Sbill return; 439264Sbill upaddr->upcs1 = TRE|IE|DCLR|GO; 440268Sbill needie = 0; 441*2395Swnj if ((um->um_tab.b_errcnt&07) == 4) { 442264Sbill upaddr->upcs1 = RECAL|GO|IE; 443264Sbill while(upaddr->upds & PIP) 444264Sbill DELAY(25); 445264Sbill } 446*2395Swnj if (um->um_tab.b_errcnt == 28 && cs2&(NEM|MXF)) { 4471829Sbill printf("FLAKEY UP "); 448*2395Swnj ubareset(um->um_ubanum); 4491829Sbill return; 4501829Sbill } 451264Sbill } 452*2395Swnj if (um->um_tab.b_active) { 453*2395Swnj 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 } 459*2395Swnj um->um_tab.b_active = 0; 460*2395Swnj um->um_tab.b_errcnt = 0; 461*2395Swnj 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); 471*2395Swnj if (dp->b_actf) 472*2395Swnj if (upustart(ui)) 473268Sbill needie = 0; 474264Sbill } 475*2395Swnj up_softc[um->um_num].sc_softas &= ~(1<<ui->ui_slave); 476*2395Swnj ubarelse(&up_softc[um->um_num].sc_info); 477273Sbill } else { 4781756Sbill if (upaddr->upcs1 & TRE) 479264Sbill upaddr->upcs1 = TRE; 480264Sbill } 481*2395Swnj as |= up_softc[um->um_num].sc_softas; 482*2395Swnj for (unit = 0; unit < NUP; unit++) { 483*2395Swnj if ((ui = updinfo[unit]) == 0 || ui->ui_mi != um) 484*2395Swnj continue; 485*2395Swnj if (as & (1<<unit)) { 4861756Sbill if (as & (1<<unit)) 487267Sbill upaddr->upas = 1<<unit; 488*2395Swnj if (upustart(ui)) 489273Sbill needie = 0; 490273Sbill } 491*2395Swnj } 492*2395Swnj if (um->um_tab.b_actf && um->um_tab.b_active == 0) 493*2395Swnj 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 */ 515*2395Swnj upecc(ui) 516*2395Swnj register struct uba_dinfo *ui; 517264Sbill { 518*2395Swnj register struct device *up = (struct device *)ui->ui_addr; 519*2395Swnj register struct buf *bp = uputab[ui->ui_unit].b_actf; 520*2395Swnj register struct uba_minfo *um = ui->ui_mi; 521*2395Swnj register struct upst *st; 522*2395Swnj 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; 535*2395Swnj 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 */ 550*2395Swnj 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 } 569*2395Swnj 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); 580*2395Swnj st = &upst[ui->ui_type]; 581264Sbill cn = bp->b_cylin; 582*2395Swnj sn = bn%st->nspc + npf + 1; 583*2395Swnj tn = sn/st->nsect; 584*2395Swnj sn %= st->nsect; 585*2395Swnj cn += tn/st->ntrak; 586*2395Swnj 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 */ 602*2395Swnj upreset(uban) 603286Sbill { 604*2395Swnj register struct uba_minfo *um; 605*2395Swnj register struct uba_dinfo *ui; 606*2395Swnj register sc21, unit; 607286Sbill 608*2395Swnj /* we should really delay the printf & DELAY till we know 609*2395Swnj * that there is at least one sc21 on this UBA, but then 610*2395Swnj * we would have to remember we had done it before, or the 611*2395Swnj * msg would come twice(or whatever) - but perhaps that 612*2395Swnj * wouldn't be such a bad thing - too many delays would 613*2395Swnj * be annoying however 614*2395Swnj */ 615286Sbill printf(" up"); 6161829Sbill DELAY(15000000); /* give it time to self-test */ 617*2395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 618*2395Swnj if ((um = upminfo[sc21]) == 0) 619*2395Swnj continue; 620*2395Swnj if (um->um_ubanum != uban) 621*2395Swnj continue; 622*2395Swnj if (!um->um_alive) 623*2395Swnj continue; 624*2395Swnj um->um_tab.b_active = 0; 625*2395Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 626*2395Swnj if (up_softc[um->um_num].sc_info) { 627*2395Swnj printf("<%d>", (up_softc[um->um_num].sc_info>>28)&0xf); 628*2395Swnj ubarelse(&up_softc[um->um_num].sc_info); 629*2395Swnj } 630*2395Swnj ((struct device *)(um->um_addr))->upcs2 = CLR; 631*2395Swnj for (unit = 0; unit < NUP; unit++) { 632*2395Swnj if ((ui = updinfo[unit]) == 0) 633*2395Swnj continue; 634*2395Swnj if (ui->ui_alive == 0) 635*2395Swnj continue; 636*2395Swnj uputab[unit].b_active = 0; 637*2395Swnj (void) upustart(ui); 638*2395Swnj } 639*2395Swnj (void) upstart(um); 640286Sbill } 641286Sbill } 642313Sbill 643313Sbill /* 644313Sbill * Wake up every second and if an interrupt is pending 645313Sbill * but nothing has happened increment a counter. 646313Sbill * If nothing happens for 20 seconds, reset the controller 647313Sbill * and begin anew. 648313Sbill */ 649313Sbill upwatch() 650313Sbill { 651*2395Swnj register struct uba_minfo *um; 652*2395Swnj register sc21, unit; 653313Sbill 6541783Sbill timeout(upwatch, (caddr_t)0, HZ); 655*2395Swnj for (sc21 = 0; sc21 < NSC21; sc21++) { 656*2395Swnj um = upminfo[sc21]; 657*2395Swnj if (um->um_tab.b_active == 0) { 658*2395Swnj for (unit = 0; unit < NUP; unit++) 659*2395Swnj if (updinfo[unit]->ui_mi == um && 660*2395Swnj uputab[unit].b_active) 661*2395Swnj goto active; 662*2395Swnj up_softc[sc21].sc_wticks = 0; 663*2395Swnj continue; 664*2395Swnj } 665*2395Swnj active: 666*2395Swnj up_softc[sc21].sc_wticks++; 667*2395Swnj if (up_softc[sc21].sc_wticks >= 20) { 668*2395Swnj up_softc[sc21].sc_wticks = 0; 669*2395Swnj printf("LOST INTERRUPT RESET"); 670*2395Swnj upreset(um->um_ubanum); 671*2395Swnj printf("\n"); 672*2395Swnj } 673313Sbill } 674313Sbill } 6752379Swnj 6762379Swnj #define DBSIZE 20 6772379Swnj 6782379Swnj updump(dev) 6792379Swnj dev_t dev; 6802379Swnj { 6812379Swnj struct device *upaddr; 6822379Swnj char *start; 6832379Swnj int num, blk, unit, nsect, ntrak, nspc; 6842379Swnj struct size *sizes; 685*2395Swnj register struct uba_regs *uba; 686*2395Swnj register struct uba_dinfo *ui; 6872379Swnj register short *rp; 688*2395Swnj struct upst *st; 6892379Swnj int bdp; 6902379Swnj 691*2395Swnj unit = minor(dev) >> 3; 692*2395Swnj if (unit >= NUP) { 693*2395Swnj printf("bad unit\n"); 694*2395Swnj return (-1); 695*2395Swnj } 696*2395Swnj #define phys1(cast, addr) ((cast)((int)addr & 0x7fffffff)) 697*2395Swnj #define phys(cast, addr) phys1(cast, phys1(cast *, &addr)) 698*2395Swnj ui = phys(struct uba_dinfo *, updinfo[unit]); 699*2395Swnj if (ui->ui_alive == 0) { 700*2395Swnj printf("dna\n"); 701*2395Swnj return(-1); 702*2395Swnj } 703*2395Swnj uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; 704*2395Swnj #if VAX780 705*2395Swnj if (cpu == VAX_780) { 706*2395Swnj uba->uba_cr = UBA_ADINIT; 707*2395Swnj uba->uba_cr = UBA_IFS|UBA_BRIE|UBA_USEFIE|UBA_SUEFIE; 708*2395Swnj while ((uba->uba_cnfgr & UBA_UBIC) == 0) 709*2395Swnj ; 710*2395Swnj } 7111809Sbill #endif 7122379Swnj DELAY(1000000); 713*2395Swnj upaddr = (struct device *)ui->ui_physaddr; 714*2395Swnj while ((upaddr->upcs1&DVA) == 0) 7152379Swnj ; 7162379Swnj num = maxfree; 7172379Swnj start = 0; 7182379Swnj upaddr->upcs2 = unit; 7192379Swnj if ((upaddr->upds & VV) == 0) { 7202379Swnj upaddr->upcs1 = DCLR|GO; 7212379Swnj upaddr->upcs1 = PRESET|GO; 7222379Swnj upaddr->upof = FMT22; 7232379Swnj } 7242379Swnj if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { 7252379Swnj printf("up !DPR || !MOL\n"); 7262379Swnj return (-1); 7272379Swnj } 728*2395Swnj st = phys1(struct upst *, &upst[ui->ui_type]); 729*2395Swnj nsect = st->nsect; 730*2395Swnj ntrak = st->ntrak; 731*2395Swnj sizes = phys(struct size *, st->sizes); 7322379Swnj if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks) { 733*2395Swnj printf("oor\n"); 7342379Swnj return (-1); 7352379Swnj } 736*2395Swnj nspc = st->nspc; 7372379Swnj while (num > 0) { 7382379Swnj register struct pte *io; 7392379Swnj register int i; 7402379Swnj int cn, sn, tn; 7412379Swnj daddr_t bn; 7422379Swnj 7432379Swnj blk = num > DBSIZE ? DBSIZE : num; 7442379Swnj bdp = 1; /* trick pcc */ 745*2395Swnj uba->uba_dpr[bdp] |= UBA_BNE; 746*2395Swnj io = uba->uba_map; 7472379Swnj for (i = 0; i < blk; i++) 748*2395Swnj *(int *)io++ = (btop(start)+i) | (1<<21) | UBA_MRV; 7492379Swnj *(int *)io = 0; 7502379Swnj bn = dumplo + btop(start); 7512379Swnj cn = bn/nspc + sizes[minor(dev)&07].cyloff; 7522379Swnj sn = bn%nspc; 7532379Swnj tn = sn/nsect; 7542379Swnj sn = sn%nsect; 7552379Swnj upaddr->updc = cn; 7562379Swnj rp = (short *) &upaddr->upda; 7572379Swnj *rp = (tn << 8) + sn; 7582379Swnj *--rp = 0; 7592379Swnj *--rp = -blk*NBPG / sizeof (short); 7602379Swnj *--rp = GO|WCOM; 7612379Swnj do { 7622379Swnj DELAY(25); 7632379Swnj } while ((upaddr->upcs1 & RDY) == 0); 7642379Swnj if (upaddr->upcs1&ERR) { 7652379Swnj printf("up dump dsk err: (%d,%d,%d) cs1=%x, er1=%x\n", 7662379Swnj cn, tn, sn, upaddr->upcs1, upaddr->uper1); 7672379Swnj return (-1); 7682379Swnj } 7692379Swnj start += blk*NBPG; 7702379Swnj num -= blk; 7712379Swnj } 7722379Swnj bdp = 1; /* crud to fool c compiler */ 773*2395Swnj uba->uba_dpr[bdp] |= UBA_BNE; 7742379Swnj return (0); 7752379Swnj } 7761902Swnj #endif 777