1*4744Swnj /* ut.c 4.1 81/11/04 */ 2*4744Swnj 3*4744Swnj #include "ut.h" 4*4744Swnj #if NUT > 0 5*4744Swnj #define UTDEBUG 1 6*4744Swnj /* 7*4744Swnj * System Industries Model 9700 Tape Drive 8*4744Swnj * emulates a TU45 on the UNIBUS 9*4744Swnj * 10*4744Swnj * TODO: 11*4744Swnj * check out attention processing 12*4744Swnj * try reset code and dump code 13*4744Swnj */ 14*4744Swnj #include "../h/param.h" 15*4744Swnj #include "../h/systm.h" 16*4744Swnj #include "../h/buf.h" 17*4744Swnj #include "../h/conf.h" 18*4744Swnj #include "../h/dir.h" 19*4744Swnj #include "../h/file.h" 20*4744Swnj #include "../h/user.h" 21*4744Swnj #include "../h/map.h" 22*4744Swnj #include "../h/pte.h" 23*4744Swnj #include "../h/ubareg.h" 24*4744Swnj #include "../h/ubavar.h" 25*4744Swnj #include "../h/mtio.h" 26*4744Swnj #include "../h/ioctl.h" 27*4744Swnj #include "../h/cmap.h" 28*4744Swnj #include "../h/cpu.h" 29*4744Swnj 30*4744Swnj #include "../h/utreg.h" 31*4744Swnj 32*4744Swnj struct buf rutbuf[NUT]; /* bufs for raw i/o */ 33*4744Swnj struct buf cutbuf[NUT]; /* bufs for control operations */ 34*4744Swnj struct buf tjutab[NTJ]; /* bufs for slave queue headers */ 35*4744Swnj 36*4744Swnj struct uba_ctlr *utminfo[NUT]; 37*4744Swnj struct uba_device *tjdinfo[NTJ]; 38*4744Swnj int utprobe(), utslave(), utattach(), utdgo(); 39*4744Swnj u_short utstd[] = { 0772440, 0 }; 40*4744Swnj struct uba_driver utdriver = 41*4744Swnj { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 }; 42*4744Swnj 43*4744Swnj /* bits in minor device */ 44*4744Swnj #define TJUNIT(dev) (minor(dev)&03) 45*4744Swnj #define T_NOREWIND 04 46*4744Swnj #define T_1600BPI 010 47*4744Swnj #define T_6250BPI 020 48*4744Swnj short utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI }; 49*4744Swnj 50*4744Swnj /* slave to controller mapping table */ 51*4744Swnj short tjtout[NTJ]; 52*4744Swnj #define UTUNIT(dev) (tjtout[TJUNIT(dev)]) 53*4744Swnj 54*4744Swnj #define INF (daddr_t)1000000L /* a block number that wont exist */ 55*4744Swnj 56*4744Swnj struct tj_softc { 57*4744Swnj char sc_openf; /* exclusive open */ 58*4744Swnj char sc_lastiow; /* last I/O operation was a write */ 59*4744Swnj daddr_t sc_blkno; /* next block to transfer */ 60*4744Swnj daddr_t sc_nxrec; /* next record on tape */ 61*4744Swnj u_short sc_erreg; /* image of uter */ 62*4744Swnj u_short sc_dsreg; /* image of utds */ 63*4744Swnj short sc_resid; /* residual from transfer */ 64*4744Swnj u_short sc_dens; /* sticky selected density */ 65*4744Swnj } tj_softc[NTJ]; 66*4744Swnj 67*4744Swnj /* 68*4744Swnj * Internal per/slave states found in sc_state 69*4744Swnj */ 70*4744Swnj #define SSEEK 1 /* seeking */ 71*4744Swnj #define SIO 2 /* doing sequential I/O */ 72*4744Swnj #define SCOM 3 /* sending a control command */ 73*4744Swnj #define SREW 4 /* doing a rewind op */ 74*4744Swnj 75*4744Swnj #if UTDEBUG 76*4744Swnj int utdebug; 77*4744Swnj #define printd if (utdebug) printf 78*4744Swnj #else 79*4744Swnj #define printd 80*4744Swnj #endif 81*4744Swnj 82*4744Swnj /* 83*4744Swnj * A NOP should get an interrupt back, if the 84*4744Swnj * device is there. 85*4744Swnj */ 86*4744Swnj utprobe(reg) 87*4744Swnj caddr_t reg; 88*4744Swnj { 89*4744Swnj register int br, cvec; 90*4744Swnj #ifdef lint 91*4744Swnj br=0; cvec=br; br=cvec; 92*4744Swnj #endif 93*4744Swnj ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_GO; 94*4744Swnj DELAY(10000); 95*4744Swnj ((struct utdevice *) reg)->utcs1 = UT_CLEAR|UT_GO; 96*4744Swnj return(1); 97*4744Swnj } 98*4744Swnj 99*4744Swnj /*ARGSUSED*/ 100*4744Swnj utslave(ui, reg) 101*4744Swnj struct uba_device *ui; 102*4744Swnj caddr_t reg; 103*4744Swnj { 104*4744Swnj /* 105*4744Swnj * A real TU45 would support the slave present bit 106*4744Swnj * int the drive type register, but this thing doesn't, 107*4744Swnj * so there's no way to determine if a slave is present or not. 108*4744Swnj */ 109*4744Swnj return(1); 110*4744Swnj } 111*4744Swnj 112*4744Swnj utattach(ui) 113*4744Swnj struct uba_device *ui; 114*4744Swnj { 115*4744Swnj tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; 116*4744Swnj } 117*4744Swnj 118*4744Swnj /* 119*4744Swnj * Open the device with exclusive access. 120*4744Swnj */ 121*4744Swnj utopen(dev, flag) 122*4744Swnj dev_t dev; 123*4744Swnj int flag; 124*4744Swnj { 125*4744Swnj register int tjunit = TJUNIT(dev); 126*4744Swnj register struct uba_device *ui; 127*4744Swnj register struct tj_softc *sc; 128*4744Swnj int olddens, dens; 129*4744Swnj 130*4744Swnj if (tjunit >= NTJ || (sc = &tj_softc[tjunit])->sc_openf || 131*4744Swnj (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) { 132*4744Swnj u.u_error = ENXIO; 133*4744Swnj return; 134*4744Swnj } 135*4744Swnj olddens = sc->sc_dens; 136*4744Swnj dens = sc->sc_dens = utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]| 137*4744Swnj PDP11FMT|(ui->ui_slave&07); 138*4744Swnj get: 139*4744Swnj utcommand(dev, UT_SENSE, 1); 140*4744Swnj if (sc->sc_dsreg&UTDS_PIP) { 141*4744Swnj sleep((caddr_t) &lbolt, PZERO+1); 142*4744Swnj goto get; 143*4744Swnj } 144*4744Swnj sc->sc_dens = olddens; 145*4744Swnj if ((sc->sc_dsreg&UTDS_MOL) == 0) { 146*4744Swnj uprintf("tj%d: not online\n", tjunit); 147*4744Swnj u.u_error = EIO; 148*4744Swnj return; 149*4744Swnj } 150*4744Swnj if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) { 151*4744Swnj uprintf("tj%d: no write ring\n", tjunit); 152*4744Swnj u.u_error = EIO; 153*4744Swnj return; 154*4744Swnj } 155*4744Swnj if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) && 156*4744Swnj dens != sc->sc_dens) { 157*4744Swnj uprintf("tj%d: can't change density in mid-tape\n", tjunit); 158*4744Swnj u.u_error = EIO; 159*4744Swnj return; 160*4744Swnj } 161*4744Swnj sc->sc_openf = 1; 162*4744Swnj sc->sc_blkno = (daddr_t)0; 163*4744Swnj sc->sc_nxrec = INF; 164*4744Swnj sc->sc_lastiow = 0; 165*4744Swnj sc->sc_dens = dens; 166*4744Swnj } 167*4744Swnj 168*4744Swnj utclose(dev, flag) 169*4744Swnj register dev_t dev; 170*4744Swnj register flag; 171*4744Swnj { 172*4744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 173*4744Swnj 174*4744Swnj if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) { 175*4744Swnj utcommand(dev, UT_WEOF, 1); 176*4744Swnj utcommand(dev, UT_WEOF, 1); 177*4744Swnj utcommand(dev, UT_SREV, 1); 178*4744Swnj } 179*4744Swnj if ((minor(dev)&T_NOREWIND) == 0) 180*4744Swnj utcommand(dev, UT_REW, 0); 181*4744Swnj sc->sc_openf = 0; 182*4744Swnj } 183*4744Swnj 184*4744Swnj utcommand(dev, com, count) 185*4744Swnj dev_t dev; 186*4744Swnj int com, count; 187*4744Swnj { 188*4744Swnj register struct buf *bp; 189*4744Swnj 190*4744Swnj bp = &cutbuf[UTUNIT(dev)]; 191*4744Swnj (void) spl5(); 192*4744Swnj while (bp->b_flags&B_BUSY) { 193*4744Swnj if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 194*4744Swnj break; 195*4744Swnj bp->b_flags |= B_WANTED; 196*4744Swnj sleep((caddr_t)bp, PRIBIO); 197*4744Swnj } 198*4744Swnj bp->b_flags = B_BUSY|B_READ; 199*4744Swnj (void) spl0(); 200*4744Swnj bp->b_dev = dev; 201*4744Swnj bp->b_command = com; 202*4744Swnj bp->b_repcnt = count; 203*4744Swnj bp->b_blkno = 0; 204*4744Swnj utstrategy(bp); 205*4744Swnj if (count == 0) 206*4744Swnj return; 207*4744Swnj iowait(bp); 208*4744Swnj if (bp->b_flags&B_WANTED) 209*4744Swnj wakeup((caddr_t)bp); 210*4744Swnj bp->b_flags &= B_ERROR; 211*4744Swnj } 212*4744Swnj 213*4744Swnj /* 214*4744Swnj * Queue a tape operation. 215*4744Swnj */ 216*4744Swnj utstrategy(bp) 217*4744Swnj register struct buf *bp; 218*4744Swnj { 219*4744Swnj int tjunit = TJUNIT(bp->b_dev); 220*4744Swnj register struct uba_ctlr *um; 221*4744Swnj register struct buf *dp; 222*4744Swnj 223*4744Swnj /* 224*4744Swnj * Put transfer at end of unit queue 225*4744Swnj */ 226*4744Swnj dp = &tjutab[tjunit]; 227*4744Swnj bp->av_forw = NULL; 228*4744Swnj (void) spl5(); 229*4744Swnj if (dp->b_actf == NULL) { 230*4744Swnj dp->b_actf = bp; 231*4744Swnj /* 232*4744Swnj * Transport not active, so... 233*4744Swnj * put at end of controller queue 234*4744Swnj */ 235*4744Swnj dp->b_forw = NULL; 236*4744Swnj um = tjdinfo[tjunit]->ui_mi; 237*4744Swnj if (um->um_tab.b_actf == NULL) 238*4744Swnj um->um_tab.b_actf = dp; 239*4744Swnj else 240*4744Swnj um->um_tab.b_actl->b_forw = dp; 241*4744Swnj um->um_tab.b_actl = dp; 242*4744Swnj } else 243*4744Swnj dp->b_actl->av_forw = bp; 244*4744Swnj dp->b_actl = bp; 245*4744Swnj /* 246*4744Swnj * If the controller is not busy, set it going. 247*4744Swnj */ 248*4744Swnj if (um->um_tab.b_active == 0) 249*4744Swnj utstart(um); 250*4744Swnj (void) spl0(); 251*4744Swnj } 252*4744Swnj 253*4744Swnj utstart(um) 254*4744Swnj register struct uba_ctlr *um; 255*4744Swnj { 256*4744Swnj register struct utdevice *utaddr; 257*4744Swnj register struct buf *bp, *dp; 258*4744Swnj register struct tj_softc *sc; 259*4744Swnj struct uba_device *ui; 260*4744Swnj int tjunit; 261*4744Swnj daddr_t blkno; 262*4744Swnj 263*4744Swnj loop: 264*4744Swnj /* 265*4744Swnj * Scan controller queue looking for units with 266*4744Swnj * transaction queues to dispatch 267*4744Swnj */ 268*4744Swnj if ((dp = um->um_tab.b_actf) == NULL) 269*4744Swnj return; 270*4744Swnj if ((bp = dp->b_actf) == NULL) { 271*4744Swnj um->um_tab.b_actf = dp->b_forw; 272*4744Swnj goto loop; 273*4744Swnj } 274*4744Swnj utaddr = (struct utdevice *)um->um_addr; 275*4744Swnj tjunit = TJUNIT(bp->b_dev); 276*4744Swnj ui = tjdinfo[tjunit]; 277*4744Swnj sc = &tj_softc[tjunit]; 278*4744Swnj /* note slave select, density, and format were merged on open */ 279*4744Swnj utaddr->uttc = sc->sc_dens; 280*4744Swnj sc->sc_dsreg = utaddr->utds; 281*4744Swnj sc->sc_erreg = utaddr->uter; 282*4744Swnj sc->sc_resid = utaddr->utwc; 283*4744Swnj /* 284*4744Swnj * Default is that last command was NOT a write command; 285*4744Swnj * if we do a write command we will notice this in utintr(). 286*4744Swnj */ 287*4744Swnj sc->sc_lastiow = 0; 288*4744Swnj printd("utstart: openf=%d ds=%b\n", sc->sc_openf, utaddr->utds, 289*4744Swnj UTDS_BITS); 290*4744Swnj if (sc->sc_openf < 0 || (utaddr->utds&UTDS_MOL) == 0) { 291*4744Swnj /* 292*4744Swnj * Have had a hard error on a non-raw tape 293*4744Swnj * or the tape unit is now unavailable 294*4744Swnj * (e.g. taken off line). 295*4744Swnj */ 296*4744Swnj bp->b_flags |= B_ERROR; 297*4744Swnj goto next; 298*4744Swnj } 299*4744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 300*4744Swnj /* 301*4744Swnj * Execute a control operation with the specified 302*4744Swnj * count. 303*4744Swnj */ 304*4744Swnj if (bp->b_command == UT_SENSE) 305*4744Swnj goto next; 306*4744Swnj /* 307*4744Swnj * Set next state; handle timeouts 308*4744Swnj */ 309*4744Swnj if (bp->b_command == UT_REW) 310*4744Swnj um->um_tab.b_active = SREW; 311*4744Swnj else 312*4744Swnj um->um_tab.b_active = SCOM; 313*4744Swnj /* NOTE: this depends on the ut command values */ 314*4744Swnj if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) 315*4744Swnj utaddr->utfc = bp->b_repcnt; 316*4744Swnj goto dobpcmd; 317*4744Swnj } 318*4744Swnj /* 319*4744Swnj * The following checks boundary conditions for operations 320*4744Swnj * on non-raw tapes. On raw tapes the initialization of 321*4744Swnj * sc->sc_nxrec by utphys causes them to be skipped normally 322*4744Swnj * (except in the case of retries). 323*4744Swnj */ 324*4744Swnj if (dbtofsb(bp->b_blkno) > sc->sc_nxrec) { 325*4744Swnj /* can't read past end of file */ 326*4744Swnj bp->b_flags |= B_ERROR; 327*4744Swnj bp->b_error = ENXIO; 328*4744Swnj goto next; 329*4744Swnj } 330*4744Swnj if (dbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) { 331*4744Swnj /* read at eof returns 0 count */ 332*4744Swnj bp->b_resid = bp->b_bcount; 333*4744Swnj clrbuf(bp); 334*4744Swnj goto next; 335*4744Swnj } 336*4744Swnj if ((bp->b_flags&B_READ) == 0) 337*4744Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno)+1; 338*4744Swnj /* 339*4744Swnj * If the tape is correctly positioned, set up all the 340*4744Swnj * registers but the csr, and give control over to the 341*4744Swnj * UNIBUS adaptor routines, to wait for resources to 342*4744Swnj * start I/O. 343*4744Swnj */ 344*4744Swnj if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) { 345*4744Swnj utaddr->utwc = -(((bp->b_bcount)+1)>>1); 346*4744Swnj if ((bp->b_flags&B_READ) == 0) { 347*4744Swnj /* 348*4744Swnj * On write error retries erase the 349*4744Swnj * inter-record gap 350*4744Swnj */ 351*4744Swnj if (um->um_tab.b_errcnt) 352*4744Swnj um->um_cmd = UT_ERASE; 353*4744Swnj else 354*4744Swnj um->um_cmd = UT_WCOM; 355*4744Swnj } else 356*4744Swnj um->um_cmd = UT_RCOM; 357*4744Swnj um->um_tab.b_active = SIO; 358*4744Swnj (void) ubago(ui); 359*4744Swnj return; 360*4744Swnj } 361*4744Swnj /* 362*4744Swnj * Tape positioned incorrectly; seek forwards or 363*4744Swnj * backwards to the correct spot. This happens for 364*4744Swnj * raw tapes only on error retries. 365*4744Swnj */ 366*4744Swnj printd("utstart: seek, blkno=%d dbtofsb=%d\n", blkno, 367*4744Swnj dbtofsb(bp->b_blkno)); 368*4744Swnj um->um_tab.b_active = SSEEK; 369*4744Swnj if (blkno < dbtofsb(bp->b_blkno)) { 370*4744Swnj utaddr->utfc = blkno - dbtofsb(bp->b_blkno); 371*4744Swnj bp->b_command = UT_SFORW; 372*4744Swnj } else { 373*4744Swnj utaddr->utfc = dbtofsb(bp->b_blkno) - blkno; 374*4744Swnj bp->b_command = UT_SREV; 375*4744Swnj } 376*4744Swnj 377*4744Swnj dobpcmd: 378*4744Swnj /* 379*4744Swnj * Perform the command setup in bp. 380*4744Swnj */ 381*4744Swnj printd("utstart: dobpcmd\n"); 382*4744Swnj utaddr->utcs1 = bp->b_command|UT_IE|UT_GO; 383*4744Swnj return; 384*4744Swnj next: 385*4744Swnj /* 386*4744Swnj * Advance to the next command in the slave queue, 387*4744Swnj * posting notice and releasing resources as needed. 388*4744Swnj */ 389*4744Swnj printd("utstart: next\n"); 390*4744Swnj if (um->um_ubinfo) 391*4744Swnj ubadone(um); 392*4744Swnj um->um_tab.b_errcnt = 0; 393*4744Swnj dp->b_actf = bp->av_forw; 394*4744Swnj iodone(bp); 395*4744Swnj goto loop; 396*4744Swnj } 397*4744Swnj 398*4744Swnj /* 399*4744Swnj * Start operation on controller -- 400*4744Swnj * UNIBUS resources have been allocated. 401*4744Swnj */ 402*4744Swnj utdgo(um) 403*4744Swnj register struct uba_ctlr *um; 404*4744Swnj { 405*4744Swnj register struct utdevice *addr = (struct utdevice *)um->um_addr; 406*4744Swnj 407*4744Swnj addr->utba = (u_short) um->um_ubinfo; 408*4744Swnj addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x30)|UT_IE|UT_GO; 409*4744Swnj printd("utdgo: cs1=%b\n", addr->utcs1, UT_BITS); 410*4744Swnj } 411*4744Swnj 412*4744Swnj /* 413*4744Swnj * Ut interrupt handler 414*4744Swnj */ 415*4744Swnj /*ARGSUSED*/ 416*4744Swnj utintr(ut11) 417*4744Swnj int ut11; 418*4744Swnj { 419*4744Swnj struct buf *dp; 420*4744Swnj register struct buf *bp; 421*4744Swnj register struct uba_ctlr *um = utminfo[ut11]; 422*4744Swnj register struct utdevice *addr; 423*4744Swnj register struct tj_softc *sc; 424*4744Swnj int tjunit; 425*4744Swnj register state; 426*4744Swnj 427*4744Swnj if ((dp = um->um_tab.b_actf) == NULL) 428*4744Swnj return; 429*4744Swnj bp = dp->b_actf; 430*4744Swnj tjunit = TJUNIT(bp->b_dev); 431*4744Swnj addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr; 432*4744Swnj sc = &tj_softc[tjunit]; 433*4744Swnj /* 434*4744Swnj * Record status... 435*4744Swnj */ 436*4744Swnj sc->sc_dsreg = addr->utds; 437*4744Swnj sc->sc_erreg = addr->uter; 438*4744Swnj sc->sc_resid = addr->utwc; 439*4744Swnj printd("utintr: state=%d cs1=%b cs2=%b ds=%b er=%b\n", 440*4744Swnj um->um_tab.b_active, 441*4744Swnj ((struct utdevice *) addr)->utcs1, UT_BITS, 442*4744Swnj ((struct utdevice *) addr)->utcs2, UTCS2_BITS, 443*4744Swnj ((struct utdevice *) addr)->utds, UTDS_BITS, 444*4744Swnj ((struct utdevice *) addr)->uter, UTER_BITS); 445*4744Swnj /* 446*4744Swnj * Check for stray attentions from slaves going online, offline, 447*4744Swnj * or a completing rewind. (The rewind started interrupt 448*4744Swnj * satisfied the requestor of the rewind.) 449*4744Swnj */ 450*4744Swnj if (((addr->utcs1&(UT_SC|UT_TRE)) == UT_SC) && 451*4744Swnj (addr->utds&UTDS_ERR) == 0) { 452*4744Swnj addr->utas = 0xff; /* writing a 1 clears attention */ 453*4744Swnj /* 454*4744Swnj * If we're doing a rewind and we're at the beginning 455*4744Swnj * of tape, then the attention and the rewind 456*4744Swnj * command may complete at the same time -- resulting in only 457*4744Swnj * one interrupt. In this case, simulate things to look like 458*4744Swnj * the attention was the command complete. 459*4744Swnj */ 460*4744Swnj if (bp->b_command != UT_REW && bp->b_command != UT_REWOFFL) 461*4744Swnj return; 462*4744Swnj if ((addr->utds&UTDS_BOT) == 0) 463*4744Swnj return; 464*4744Swnj um->um_tab.b_active = SCOM; 465*4744Swnj } 466*4744Swnj if((bp->b_flags&B_READ) == 0) 467*4744Swnj sc->sc_lastiow = 1; 468*4744Swnj state = um->um_tab.b_active; 469*4744Swnj um->um_tab.b_active = 0; 470*4744Swnj /* 471*4744Swnj * Check for errors... 472*4744Swnj */ 473*4744Swnj if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) { 474*4744Swnj #ifdef notdef 475*4744Swnj /* 476*4744Swnj * if this bit were emulated, it would allow us to wait 477*4744Swnj * for the transport to settle 478*4744Swnj */ 479*4744Swnj while (addr->utds&UTDS_SDWN) 480*4744Swnj ; 481*4744Swnj #endif 482*4744Swnj /* 483*4744Swnj * If we hit the end of tape, update our position 484*4744Swnj */ 485*4744Swnj if (addr->utds&UTDS_EOT) { 486*4744Swnj /* 487*4744Swnj * Set blkno and nxrec on sensing end of tape. 488*4744Swnj */ 489*4744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 490*4744Swnj if (sc->sc_blkno > dbtofsb(bp->b_blkno)) { 491*4744Swnj /* reversing */ 492*4744Swnj sc->sc_nxrec = 493*4744Swnj dbtofsb(bp->b_blkno) - addr->utfc; 494*4744Swnj sc->sc_blkno = sc->sc_nxrec; 495*4744Swnj } else { 496*4744Swnj /* spacing forward */ 497*4744Swnj sc->sc_blkno = 498*4744Swnj dbtofsb(bp->b_blkno) + addr->utfc; 499*4744Swnj sc->sc_nxrec = sc->sc_blkno-1; 500*4744Swnj } 501*4744Swnj } else /* eof on read */ 502*4744Swnj sc->sc_nxrec = dbtofsb(bp->b_blkno); 503*4744Swnj state = SCOM; /* force completion */ 504*4744Swnj addr->utcs1 = UT_CLEAR|UT_GO; 505*4744Swnj /* 506*4744Swnj * Stuff fc so that it will be unstuffed correctly 507*4744Swnj * later to get the residual. 508*4744Swnj */ 509*4744Swnj addr->utfc = -bp->b_bcount; 510*4744Swnj goto opdone; 511*4744Swnj } 512*4744Swnj addr->utcs1 = UT_CLEAR|UT_GO; /* must clear ERR bit */ 513*4744Swnj /* 514*4744Swnj * If we were reading from a raw tape and the only error 515*4744Swnj * was that the record was too long, then we don't consider 516*4744Swnj * this an error. 517*4744Swnj */ 518*4744Swnj if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 519*4744Swnj (sc->sc_erreg&UTER_FCE)) 520*4744Swnj goto ignoreerr; 521*4744Swnj /* 522*4744Swnj * Retry soft errors up to 8 times 523*4744Swnj */ 524*4744Swnj if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { 525*4744Swnj if (++um->um_tab.b_errcnt < 7) { 526*4744Swnj sc->sc_blkno++; 527*4744Swnj ubadone(um); 528*4744Swnj goto opcont; 529*4744Swnj } 530*4744Swnj } else 531*4744Swnj /* 532*4744Swnj * Hard or non-I/O errors on non-raw tape 533*4744Swnj * cause it to close. 534*4744Swnj */ 535*4744Swnj if (sc->sc_openf > 0 && bp != &rutbuf[UTUNIT(bp->b_dev)]) 536*4744Swnj sc->sc_openf = -1; 537*4744Swnj /* 538*4744Swnj * Couldn't recover error. 539*4744Swnj */ 540*4744Swnj printf("ut%d: hard error bn%d er=%b cs2=%b\n", tjunit, 541*4744Swnj bp->b_blkno, sc->sc_erreg, UTER_BITS, 542*4744Swnj addr->utcs2, UTCS2_BITS); 543*4744Swnj bp->b_flags |= B_ERROR; 544*4744Swnj goto opdone; 545*4744Swnj } 546*4744Swnj ignoreerr: 547*4744Swnj /* 548*4744Swnj * Advance tape control FSM. 549*4744Swnj */ 550*4744Swnj switch (state) { 551*4744Swnj 552*4744Swnj case SIO: /* read/write increments tape block # */ 553*4744Swnj sc->sc_blkno++; 554*4744Swnj goto opdone; 555*4744Swnj 556*4744Swnj case SCOM: /* forw/rev space updates current position */ 557*4744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) 558*4744Swnj switch (bp->b_command) { 559*4744Swnj 560*4744Swnj case UT_SFORW: 561*4744Swnj sc->sc_blkno -= bp->b_repcnt; 562*4744Swnj break; 563*4744Swnj 564*4744Swnj case UT_SREV: 565*4744Swnj sc->sc_blkno += bp->b_repcnt; 566*4744Swnj break; 567*4744Swnj } 568*4744Swnj goto opdone; 569*4744Swnj 570*4744Swnj case SSEEK: 571*4744Swnj sc->sc_blkno = dbtofsb(bp->b_blkno); 572*4744Swnj goto opcont; 573*4744Swnj 574*4744Swnj default: 575*4744Swnj panic("utintr"); 576*4744Swnj } 577*4744Swnj 578*4744Swnj opdone: 579*4744Swnj /* 580*4744Swnj * Reset error count and remove 581*4744Swnj * from device queue 582*4744Swnj */ 583*4744Swnj um->um_tab.b_errcnt = 0; 584*4744Swnj dp->b_actf = bp->b_forw; 585*4744Swnj ubadone(um); 586*4744Swnj iodone(bp); 587*4744Swnj /* 588*4744Swnj * Circulate slave to end of controller queue 589*4744Swnj * to give other slaves a chance 590*4744Swnj */ 591*4744Swnj um->um_tab.b_actf = dp->b_forw; 592*4744Swnj if (dp->b_actf) { 593*4744Swnj dp->b_forw = NULL; 594*4744Swnj if (um->um_tab.b_actf == NULL) 595*4744Swnj um->um_tab.b_actf = dp; 596*4744Swnj else 597*4744Swnj um->um_tab.b_actl->b_forw = dp; 598*4744Swnj um->um_tab.b_actl = dp; 599*4744Swnj } 600*4744Swnj if (um->um_tab.b_actf == 0) 601*4744Swnj return; 602*4744Swnj opcont: 603*4744Swnj utstart(um); 604*4744Swnj } 605*4744Swnj 606*4744Swnj /* 607*4744Swnj * Raw interface for a read 608*4744Swnj */ 609*4744Swnj utread(dev) 610*4744Swnj dev_t dev; 611*4744Swnj { 612*4744Swnj utphys(dev); 613*4744Swnj if (u.u_error) 614*4744Swnj return; 615*4744Swnj physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys); 616*4744Swnj } 617*4744Swnj 618*4744Swnj /* 619*4744Swnj * Raw interface for a write 620*4744Swnj */ 621*4744Swnj utwrite(dev) 622*4744Swnj { 623*4744Swnj utphys(dev); 624*4744Swnj if (u.u_error) 625*4744Swnj return; 626*4744Swnj physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys); 627*4744Swnj } 628*4744Swnj 629*4744Swnj /* 630*4744Swnj * Check for valid device number dev and update our notion 631*4744Swnj * of where we are on the tape 632*4744Swnj */ 633*4744Swnj utphys(dev) 634*4744Swnj dev_t dev; 635*4744Swnj { 636*4744Swnj register int tjunit = TJUNIT(dev); 637*4744Swnj register struct tj_softc *sc; 638*4744Swnj register struct uba_device *ui; 639*4744Swnj register daddr_t a; 640*4744Swnj 641*4744Swnj if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) { 642*4744Swnj u.u_error = ENXIO; 643*4744Swnj return; 644*4744Swnj } 645*4744Swnj a = u.u_offset >> 9; 646*4744Swnj sc = &tj_softc[tjunit]; 647*4744Swnj sc->sc_blkno = dbtofsb(a); 648*4744Swnj sc->sc_nxrec = dbtofsb(a)+1; 649*4744Swnj } 650*4744Swnj 651*4744Swnj /*ARGSUSED*/ 652*4744Swnj utioctl(dev, cmd, addr, flag) 653*4744Swnj dev_t dev; 654*4744Swnj caddr_t addr; 655*4744Swnj { 656*4744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 657*4744Swnj register struct buf *bp = &cutbuf[UTUNIT(dev)]; 658*4744Swnj register callcount; 659*4744Swnj int fcount; 660*4744Swnj struct mtop mtop; 661*4744Swnj struct mtget mtget; 662*4744Swnj /* we depend of the values and order of the MT codes here */ 663*4744Swnj static utops[] = 664*4744Swnj {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE}; 665*4744Swnj 666*4744Swnj switch (cmd) { 667*4744Swnj 668*4744Swnj case MTIOCTOP: 669*4744Swnj if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) { 670*4744Swnj u.u_error = EFAULT; 671*4744Swnj return; 672*4744Swnj } 673*4744Swnj switch(mtop.mt_op) { 674*4744Swnj 675*4744Swnj case MTWEOF: 676*4744Swnj callcount = mtop.mt_count; 677*4744Swnj fcount = 1; 678*4744Swnj break; 679*4744Swnj 680*4744Swnj case MTFSF: case MTBSF: 681*4744Swnj case MTFSR: case MTBSR: 682*4744Swnj callcount = 1; 683*4744Swnj fcount = mtop.mt_count; 684*4744Swnj break; 685*4744Swnj 686*4744Swnj case MTREW: case MTOFFL: case MTNOP: 687*4744Swnj callcount = 1; 688*4744Swnj fcount = 1; 689*4744Swnj break; 690*4744Swnj 691*4744Swnj default: 692*4744Swnj u.u_error = ENXIO; 693*4744Swnj return; 694*4744Swnj } 695*4744Swnj if (callcount <= 0 || fcount <= 0) { 696*4744Swnj u.u_error = ENXIO; 697*4744Swnj return; 698*4744Swnj } 699*4744Swnj while (--callcount >= 0) { 700*4744Swnj utcommand(dev, utops[mtop.mt_op], fcount); 701*4744Swnj if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) && 702*4744Swnj bp->b_resid) { 703*4744Swnj u.u_error = EIO; 704*4744Swnj break; 705*4744Swnj } 706*4744Swnj if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT)) 707*4744Swnj break; 708*4744Swnj } 709*4744Swnj geterror(bp); 710*4744Swnj return; 711*4744Swnj 712*4744Swnj case MTIOCGET: 713*4744Swnj mtget.mt_dsreg = sc->sc_dsreg; 714*4744Swnj mtget.mt_erreg = sc->sc_erreg; 715*4744Swnj mtget.mt_resid = sc->sc_resid; 716*4744Swnj mtget.mt_type = MT_ISUT; 717*4744Swnj if (copyout((caddr_t)&mtget, addr, sizeof(mtget))) 718*4744Swnj u.u_error = EFAULT; 719*4744Swnj return; 720*4744Swnj 721*4744Swnj default: 722*4744Swnj u.u_error = ENXIO; 723*4744Swnj } 724*4744Swnj } 725*4744Swnj 726*4744Swnj utreset(uban) 727*4744Swnj int uban; 728*4744Swnj { 729*4744Swnj register struct uba_ctlr *um; 730*4744Swnj register ut11, tjunit; 731*4744Swnj register struct uba_device *ui; 732*4744Swnj register struct buf *dp; 733*4744Swnj 734*4744Swnj for (ut11 = 0; ut11 < NUT; ut11++) { 735*4744Swnj if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || 736*4744Swnj um->um_ubanum != uban) 737*4744Swnj continue; 738*4744Swnj printf(" ut%d", ut11); 739*4744Swnj um->um_tab.b_active = 0; 740*4744Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 741*4744Swnj if (um->um_ubinfo) { 742*4744Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 743*4744Swnj ubadone(um); 744*4744Swnj } 745*4744Swnj ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; 746*4744Swnj for (tjunit = 0; tjunit < NTJ; tjunit++) { 747*4744Swnj if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um || 748*4744Swnj ui->ui_alive == 0) 749*4744Swnj continue; 750*4744Swnj dp = &tjutab[tjunit]; 751*4744Swnj dp->b_active = 0; 752*4744Swnj dp->b_forw = 0; 753*4744Swnj if (um->um_tab.b_actf == NULL) 754*4744Swnj um->um_tab.b_actf = dp; 755*4744Swnj else 756*4744Swnj um->um_tab.b_actl->b_forw = dp; 757*4744Swnj um->um_tab.b_actl = dp; 758*4744Swnj if (tj_softc[tjunit].sc_openf > 0) 759*4744Swnj tj_softc[tjunit].sc_openf = -1; 760*4744Swnj } 761*4744Swnj utstart(um); 762*4744Swnj } 763*4744Swnj } 764*4744Swnj 765*4744Swnj /* 766*4744Swnj * Do a stand-alone core dump to tape -- 767*4744Swnj * from here down, routines are used only in dump context 768*4744Swnj */ 769*4744Swnj #define DBSIZE 20 770*4744Swnj 771*4744Swnj utdump() 772*4744Swnj { 773*4744Swnj register struct uba_device *ui; 774*4744Swnj register struct uba_regs *up; 775*4744Swnj register struct utdevice *utaddr; 776*4744Swnj int blk, num = maxfree; 777*4744Swnj int start = 0; 778*4744Swnj 779*4744Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 780*4744Swnj if (tjdinfo[0] == 0) 781*4744Swnj return (ENXIO); 782*4744Swnj ui = phys(tjdinfo[0], struct uba_device *); 783*4744Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 784*4744Swnj ubainit(); 785*4744Swnj DELAY(1000000); 786*4744Swnj utwait(utaddr); 787*4744Swnj utaddr = (struct utdevice *)ui->ui_physaddr; 788*4744Swnj /* do it at 1600 bpi so tape can be read on other machines */ 789*4744Swnj utaddr->uttc = UT_PE|PDP11FMT; /* implicit slave 0 or-ed in */ 790*4744Swnj utaddr->utcs1 = UT_CLEAR|UT_GO; 791*4744Swnj while (num > 0) { 792*4744Swnj blk = num > DBSIZE ? DBSIZE : num; 793*4744Swnj utdwrite(start, blk, utaddr, up); 794*4744Swnj start += blk; 795*4744Swnj num -= blk; 796*4744Swnj } 797*4744Swnj uteof(utaddr); 798*4744Swnj uteof(utaddr); 799*4744Swnj utwait(utaddr); 800*4744Swnj if (utaddr->utds&UTDS_ERR) 801*4744Swnj return(EIO); 802*4744Swnj utaddr->utcs1 = UT_REW|UT_GO; 803*4744Swnj return (0); 804*4744Swnj } 805*4744Swnj 806*4744Swnj utdwrite(dbuf, num, utaddr, up) 807*4744Swnj register dbuf, num; 808*4744Swnj register struct utdevice *utaddr; 809*4744Swnj struct uba_regs *up; 810*4744Swnj { 811*4744Swnj register struct pte *io; 812*4744Swnj register int npf; 813*4744Swnj 814*4744Swnj utwait(utaddr); 815*4744Swnj io = up->uba_map; 816*4744Swnj npf = num + 1; 817*4744Swnj while (--npf != 0) 818*4744Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 819*4744Swnj *(int *)io = 0; 820*4744Swnj utaddr->utwc = -((num*NBPG)<<1); 821*4744Swnj utaddr->utba = 0; 822*4744Swnj utaddr->utcs1 = UT_WCOM|UT_GO; 823*4744Swnj } 824*4744Swnj 825*4744Swnj utwait(utaddr) 826*4744Swnj struct utdevice *utaddr; 827*4744Swnj { 828*4744Swnj register s; 829*4744Swnj 830*4744Swnj do 831*4744Swnj s = utaddr->utds; 832*4744Swnj while ((s&UTDS_DRY) == 0); 833*4744Swnj } 834*4744Swnj 835*4744Swnj uteof(utaddr) 836*4744Swnj struct utdevice *utaddr; 837*4744Swnj { 838*4744Swnj 839*4744Swnj utwait(utaddr); 840*4744Swnj utaddr->utcs1 = UT_WEOF|UT_GO; 841*4744Swnj } 842*4744Swnj #endif 843