1*18323Sralph /* ut.c 6.4 85/03/13 */ 24744Swnj 34862Sroot #include "tj.h" 44744Swnj #if NUT > 0 54744Swnj /* 64744Swnj * System Industries Model 9700 Tape Drive 74744Swnj * emulates a TU45 on the UNIBUS 84744Swnj * 94744Swnj * TODO: 104744Swnj * check out attention processing 114744Swnj * try reset code and dump code 124744Swnj */ 139783Ssam #include "../machine/pte.h" 149783Ssam 1517083Sbloom #include "param.h" 1617083Sbloom #include "systm.h" 1717083Sbloom #include "buf.h" 1817083Sbloom #include "conf.h" 1917083Sbloom #include "dir.h" 2017083Sbloom #include "file.h" 2117083Sbloom #include "user.h" 2217083Sbloom #include "map.h" 2317083Sbloom #include "ioctl.h" 2417083Sbloom #include "mtio.h" 2517083Sbloom #include "cmap.h" 2617083Sbloom #include "uio.h" 2717083Sbloom #include "kernel.h" 28*18323Sralph #include "tty.h" 294744Swnj 308483Sroot #include "../vax/cpu.h" 3117083Sbloom #include "ubareg.h" 3217083Sbloom #include "ubavar.h" 3317083Sbloom #include "utreg.h" 344744Swnj 354744Swnj struct buf rutbuf[NUT]; /* bufs for raw i/o */ 364744Swnj struct buf cutbuf[NUT]; /* bufs for control operations */ 374744Swnj struct buf tjutab[NTJ]; /* bufs for slave queue headers */ 384744Swnj 394744Swnj struct uba_ctlr *utminfo[NUT]; 404744Swnj struct uba_device *tjdinfo[NTJ]; 414833Swnj int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer(); 424744Swnj u_short utstd[] = { 0772440, 0 }; 434744Swnj struct uba_driver utdriver = 444744Swnj { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 }; 454744Swnj 4611176Ssam #define MASKREG(reg) ((reg)&0xffff) 4711176Ssam 484744Swnj /* bits in minor device */ 494744Swnj #define TJUNIT(dev) (minor(dev)&03) 504744Swnj #define T_NOREWIND 04 514744Swnj #define T_1600BPI 010 524744Swnj #define T_6250BPI 020 534744Swnj short utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI }; 544744Swnj 554744Swnj /* slave to controller mapping table */ 564744Swnj short tjtout[NTJ]; 574744Swnj #define UTUNIT(dev) (tjtout[TJUNIT(dev)]) 584744Swnj 594744Swnj #define INF (daddr_t)1000000L /* a block number that wont exist */ 604744Swnj 614744Swnj struct tj_softc { 624744Swnj char sc_openf; /* exclusive open */ 634744Swnj char sc_lastiow; /* last I/O operation was a write */ 644744Swnj daddr_t sc_blkno; /* next block to transfer */ 654744Swnj daddr_t sc_nxrec; /* next record on tape */ 664744Swnj u_short sc_erreg; /* image of uter */ 674744Swnj u_short sc_dsreg; /* image of utds */ 684746Ssam u_short sc_resid; /* residual from transfer */ 694744Swnj u_short sc_dens; /* sticky selected density */ 704833Swnj daddr_t sc_timo; /* time until timeout expires */ 714833Swnj short sc_tact; /* timeout is active flag */ 72*18323Sralph struct tty *sc_ttyp; /* record user's tty for errors */ 734744Swnj } tj_softc[NTJ]; 744744Swnj 754744Swnj /* 764744Swnj * Internal per/slave states found in sc_state 774744Swnj */ 784744Swnj #define SSEEK 1 /* seeking */ 794744Swnj #define SIO 2 /* doing sequential I/O */ 804744Swnj #define SCOM 3 /* sending a control command */ 814744Swnj #define SREW 4 /* doing a rewind op */ 824746Ssam #define SERASE 5 /* erase inter-record gap */ 834746Ssam #define SERASED 6 /* erased inter-record gap */ 844744Swnj 854941Swnj /*ARGSUSED*/ 864744Swnj utprobe(reg) 874744Swnj caddr_t reg; 884744Swnj { 894744Swnj register int br, cvec; 904744Swnj #ifdef lint 914744Swnj br=0; cvec=br; br=cvec; 924941Swnj utintr(0); 934744Swnj #endif 944746Ssam /* 956954Sroot * The SI documentation says you must set the RDY bit 966954Sroot * (even though it's read-only) to force an interrupt. 974746Ssam */ 986954Sroot ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY; 994744Swnj DELAY(10000); 1007405Skre return (sizeof (struct utdevice)); 1014744Swnj } 1024744Swnj 1034744Swnj /*ARGSUSED*/ 1044744Swnj utslave(ui, reg) 1054744Swnj struct uba_device *ui; 1064744Swnj caddr_t reg; 1074744Swnj { 1084744Swnj /* 1094744Swnj * A real TU45 would support the slave present bit 1104744Swnj * int the drive type register, but this thing doesn't, 1114744Swnj * so there's no way to determine if a slave is present or not. 1124744Swnj */ 1134744Swnj return(1); 1144744Swnj } 1154744Swnj 1164744Swnj utattach(ui) 1174744Swnj struct uba_device *ui; 1184744Swnj { 1194744Swnj tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; 1204744Swnj } 1214744Swnj 1224744Swnj /* 1234744Swnj * Open the device with exclusive access. 1244744Swnj */ 1254744Swnj utopen(dev, flag) 1264744Swnj dev_t dev; 1274744Swnj int flag; 1284744Swnj { 1294744Swnj register int tjunit = TJUNIT(dev); 1304744Swnj register struct uba_device *ui; 1314744Swnj register struct tj_softc *sc; 1324744Swnj int olddens, dens; 1335439Sroot register int s; 1344744Swnj 1354744Swnj if (tjunit >= NTJ || (sc = &tj_softc[tjunit])->sc_openf || 1368577Sroot (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 1378577Sroot return (ENXIO); 1384744Swnj olddens = sc->sc_dens; 1398577Sroot dens = sc->sc_dens = 1408577Sroot utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]| 1418577Sroot PDP11FMT|(ui->ui_slave&07); 1424744Swnj get: 1434744Swnj utcommand(dev, UT_SENSE, 1); 1444744Swnj if (sc->sc_dsreg&UTDS_PIP) { 1459174Ssam sleep((caddr_t)&lbolt, PZERO+1); 1464744Swnj goto get; 1474744Swnj } 1484744Swnj sc->sc_dens = olddens; 1494744Swnj if ((sc->sc_dsreg&UTDS_MOL) == 0) { 1504744Swnj uprintf("tj%d: not online\n", tjunit); 1518577Sroot return (EIO); 1524744Swnj } 1534744Swnj if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) { 1544744Swnj uprintf("tj%d: no write ring\n", tjunit); 1558577Sroot return (EIO); 1564744Swnj } 1574744Swnj if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) && 1584744Swnj dens != sc->sc_dens) { 1594744Swnj uprintf("tj%d: can't change density in mid-tape\n", tjunit); 1608577Sroot return (EIO); 1614744Swnj } 1624744Swnj sc->sc_openf = 1; 1634744Swnj sc->sc_blkno = (daddr_t)0; 1644744Swnj sc->sc_nxrec = INF; 1654744Swnj sc->sc_lastiow = 0; 1664744Swnj sc->sc_dens = dens; 167*18323Sralph sc->sc_ttyp = u.u_ttyp; 1684746Ssam /* 1694746Ssam * For 6250 bpi take exclusive use of the UNIBUS. 1704746Ssam */ 1714746Ssam ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI; 1725439Sroot s = spl6(); 1734833Swnj if (sc->sc_tact == 0) { 1744833Swnj sc->sc_timo = INF; 1754833Swnj sc->sc_tact = 1; 1764833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 1774833Swnj } 1785439Sroot splx(s); 1798577Sroot return (0); 1804744Swnj } 1814744Swnj 1824744Swnj utclose(dev, flag) 1834744Swnj register dev_t dev; 1844744Swnj register flag; 1854744Swnj { 1864744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 1874744Swnj 1884744Swnj if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) { 1894744Swnj utcommand(dev, UT_WEOF, 1); 1904744Swnj utcommand(dev, UT_WEOF, 1); 1914744Swnj utcommand(dev, UT_SREV, 1); 1924744Swnj } 1934744Swnj if ((minor(dev)&T_NOREWIND) == 0) 1944744Swnj utcommand(dev, UT_REW, 0); 1954744Swnj sc->sc_openf = 0; 1964744Swnj } 1974744Swnj 1984744Swnj utcommand(dev, com, count) 1994744Swnj dev_t dev; 2004744Swnj int com, count; 2014744Swnj { 2024744Swnj register struct buf *bp; 2035439Sroot register int s; 2044744Swnj 2054744Swnj bp = &cutbuf[UTUNIT(dev)]; 2065439Sroot s = spl5(); 2074744Swnj while (bp->b_flags&B_BUSY) { 2084744Swnj if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2094744Swnj break; 2104744Swnj bp->b_flags |= B_WANTED; 2114744Swnj sleep((caddr_t)bp, PRIBIO); 2124744Swnj } 2134744Swnj bp->b_flags = B_BUSY|B_READ; 2145439Sroot splx(s); 2154744Swnj bp->b_dev = dev; 2164744Swnj bp->b_command = com; 2174744Swnj bp->b_repcnt = count; 2184744Swnj bp->b_blkno = 0; 2194744Swnj utstrategy(bp); 2204744Swnj if (count == 0) 2214744Swnj return; 2224744Swnj iowait(bp); 2234744Swnj if (bp->b_flags&B_WANTED) 2244744Swnj wakeup((caddr_t)bp); 2254744Swnj bp->b_flags &= B_ERROR; 2264744Swnj } 2274744Swnj 2284744Swnj /* 2294744Swnj * Queue a tape operation. 2304744Swnj */ 2314744Swnj utstrategy(bp) 2324744Swnj register struct buf *bp; 2334744Swnj { 2344744Swnj int tjunit = TJUNIT(bp->b_dev); 2354744Swnj register struct uba_ctlr *um; 2364744Swnj register struct buf *dp; 2374744Swnj 2384744Swnj /* 2394744Swnj * Put transfer at end of unit queue 2404744Swnj */ 2414744Swnj dp = &tjutab[tjunit]; 2424744Swnj bp->av_forw = NULL; 24317433Skarels um = tjdinfo[tjunit]->ui_mi; 2444744Swnj (void) spl5(); 2454744Swnj if (dp->b_actf == NULL) { 2464744Swnj dp->b_actf = bp; 2474744Swnj /* 2484744Swnj * Transport not active, so... 2494744Swnj * put at end of controller queue 2504744Swnj */ 2514744Swnj dp->b_forw = NULL; 2524744Swnj if (um->um_tab.b_actf == NULL) 2534744Swnj um->um_tab.b_actf = dp; 2544744Swnj else 2554744Swnj um->um_tab.b_actl->b_forw = dp; 2564744Swnj um->um_tab.b_actl = dp; 2574744Swnj } else 2584744Swnj dp->b_actl->av_forw = bp; 2594744Swnj dp->b_actl = bp; 2604744Swnj /* 2614744Swnj * If the controller is not busy, set it going. 2624744Swnj */ 2634746Ssam if (um->um_tab.b_state == 0) 2644744Swnj utstart(um); 2654744Swnj (void) spl0(); 2664744Swnj } 2674744Swnj 2684744Swnj utstart(um) 2694744Swnj register struct uba_ctlr *um; 2704744Swnj { 2714746Ssam register struct utdevice *addr; 2724744Swnj register struct buf *bp, *dp; 2734744Swnj register struct tj_softc *sc; 2744744Swnj struct uba_device *ui; 2754744Swnj int tjunit; 2764744Swnj daddr_t blkno; 2774744Swnj 2784744Swnj loop: 2794744Swnj /* 2804744Swnj * Scan controller queue looking for units with 2814744Swnj * transaction queues to dispatch 2824744Swnj */ 2834744Swnj if ((dp = um->um_tab.b_actf) == NULL) 2844744Swnj return; 2854744Swnj if ((bp = dp->b_actf) == NULL) { 2864744Swnj um->um_tab.b_actf = dp->b_forw; 2874744Swnj goto loop; 2884744Swnj } 2894746Ssam addr = (struct utdevice *)um->um_addr; 2904744Swnj tjunit = TJUNIT(bp->b_dev); 2914744Swnj ui = tjdinfo[tjunit]; 2924744Swnj sc = &tj_softc[tjunit]; 2934744Swnj /* note slave select, density, and format were merged on open */ 2944746Ssam addr->uttc = sc->sc_dens; 2954746Ssam sc->sc_dsreg = addr->utds; 2964746Ssam sc->sc_erreg = addr->uter; 29711176Ssam sc->sc_resid = MASKREG(addr->utfc); 2984744Swnj /* 2994744Swnj * Default is that last command was NOT a write command; 3004744Swnj * if we do a write command we will notice this in utintr(). 3014744Swnj */ 3024744Swnj sc->sc_lastiow = 0; 3034746Ssam if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) { 3044744Swnj /* 3054744Swnj * Have had a hard error on a non-raw tape 3064744Swnj * or the tape unit is now unavailable 3074744Swnj * (e.g. taken off line). 3084744Swnj */ 3094744Swnj bp->b_flags |= B_ERROR; 3104744Swnj goto next; 3114744Swnj } 3124744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 3134744Swnj /* 3144744Swnj * Execute a control operation with the specified 3154744Swnj * count. 3164744Swnj */ 3174744Swnj if (bp->b_command == UT_SENSE) 3184744Swnj goto next; 31911176Ssam if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) { 32011176Ssam bp->b_resid = bp->b_bcount; 32111176Ssam goto next; 32211176Ssam } 3234744Swnj /* 3244744Swnj * Set next state; handle timeouts 3254744Swnj */ 3264833Swnj if (bp->b_command == UT_REW) { 3274746Ssam um->um_tab.b_state = SREW; 3284833Swnj sc->sc_timo = 5*60; 3294833Swnj } else { 3304746Ssam um->um_tab.b_state = SCOM; 3314833Swnj sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60); 3324833Swnj } 3334744Swnj /* NOTE: this depends on the ut command values */ 3344744Swnj if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) 3354746Ssam addr->utfc = -bp->b_repcnt; 3364744Swnj goto dobpcmd; 3374744Swnj } 3384744Swnj /* 3394744Swnj * The following checks boundary conditions for operations 3404744Swnj * on non-raw tapes. On raw tapes the initialization of 3414744Swnj * sc->sc_nxrec by utphys causes them to be skipped normally 3424744Swnj * (except in the case of retries). 3434744Swnj */ 3447382Ssam if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 3454744Swnj /* can't read past end of file */ 3464744Swnj bp->b_flags |= B_ERROR; 3474744Swnj bp->b_error = ENXIO; 3484744Swnj goto next; 3494744Swnj } 3507382Ssam if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) { 3514744Swnj /* read at eof returns 0 count */ 3524744Swnj bp->b_resid = bp->b_bcount; 3534744Swnj clrbuf(bp); 3544744Swnj goto next; 3554744Swnj } 3564744Swnj if ((bp->b_flags&B_READ) == 0) 3577382Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno)+1; 3584744Swnj /* 3594744Swnj * If the tape is correctly positioned, set up all the 3604744Swnj * registers but the csr, and give control over to the 3614744Swnj * UNIBUS adaptor routines, to wait for resources to 3624744Swnj * start I/O. 3634744Swnj */ 3647382Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3654746Ssam addr->utwc = -(((bp->b_bcount)+1)>>1); 3664746Ssam addr->utfc = -bp->b_bcount; 3674744Swnj if ((bp->b_flags&B_READ) == 0) { 3684744Swnj /* 3694744Swnj * On write error retries erase the 3704746Ssam * inter-record gap before rewriting. 3714744Swnj */ 3724746Ssam if (um->um_tab.b_errcnt) { 3734746Ssam if (um->um_tab.b_state != SERASED) { 3744759Swnj um->um_tab.b_state = SERASE; 3754833Swnj sc->sc_timo = 60; 3764746Ssam addr->utcs1 = UT_ERASE|UT_IE|UT_GO; 3774746Ssam return; 3784746Ssam } 3794746Ssam } 38011176Ssam if (addr->utds & UTDS_EOT) { 38111176Ssam bp->b_resid = bp->b_bcount; 38211176Ssam um->um_tab.b_state = 0; 38311176Ssam goto next; 38411176Ssam } 3854746Ssam um->um_cmd = UT_WCOM; 3864744Swnj } else 3874744Swnj um->um_cmd = UT_RCOM; 3884833Swnj sc->sc_timo = 60; 3894746Ssam um->um_tab.b_state = SIO; 3904744Swnj (void) ubago(ui); 3914744Swnj return; 3924744Swnj } 3934744Swnj /* 3944744Swnj * Tape positioned incorrectly; seek forwards or 3954744Swnj * backwards to the correct spot. This happens for 3964744Swnj * raw tapes only on error retries. 3974744Swnj */ 3984746Ssam um->um_tab.b_state = SSEEK; 3997382Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 4007382Ssam addr->utfc = blkno - bdbtofsb(bp->b_blkno); 4014744Swnj bp->b_command = UT_SFORW; 4024744Swnj } else { 4037382Ssam addr->utfc = bdbtofsb(bp->b_blkno) - blkno; 4044744Swnj bp->b_command = UT_SREV; 4054744Swnj } 4064833Swnj sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60); 4074744Swnj 4084744Swnj dobpcmd: 4094744Swnj /* 4104744Swnj * Perform the command setup in bp. 4114744Swnj */ 4124746Ssam addr->utcs1 = bp->b_command|UT_IE|UT_GO; 4134744Swnj return; 4144744Swnj next: 4154744Swnj /* 4164744Swnj * Advance to the next command in the slave queue, 4174744Swnj * posting notice and releasing resources as needed. 4184744Swnj */ 4194744Swnj if (um->um_ubinfo) 4204744Swnj ubadone(um); 4214744Swnj um->um_tab.b_errcnt = 0; 4224744Swnj dp->b_actf = bp->av_forw; 4234744Swnj iodone(bp); 4244744Swnj goto loop; 4254744Swnj } 4264744Swnj 4274744Swnj /* 4284744Swnj * Start operation on controller -- 4294744Swnj * UNIBUS resources have been allocated. 4304744Swnj */ 4314744Swnj utdgo(um) 4324744Swnj register struct uba_ctlr *um; 4334744Swnj { 4344744Swnj register struct utdevice *addr = (struct utdevice *)um->um_addr; 4354744Swnj 4364744Swnj addr->utba = (u_short) um->um_ubinfo; 43711176Ssam addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO; 4384744Swnj } 4394744Swnj 4404744Swnj /* 4414744Swnj * Ut interrupt handler 4424744Swnj */ 4434744Swnj /*ARGSUSED*/ 4444744Swnj utintr(ut11) 4454744Swnj int ut11; 4464744Swnj { 4474744Swnj struct buf *dp; 4484744Swnj register struct buf *bp; 4494744Swnj register struct uba_ctlr *um = utminfo[ut11]; 4504744Swnj register struct utdevice *addr; 4514744Swnj register struct tj_softc *sc; 4524746Ssam u_short tjunit, cs2, cs1; 4534744Swnj register state; 4544744Swnj 4554744Swnj if ((dp = um->um_tab.b_actf) == NULL) 4564744Swnj return; 4574744Swnj bp = dp->b_actf; 4584744Swnj tjunit = TJUNIT(bp->b_dev); 4594744Swnj addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr; 4604744Swnj sc = &tj_softc[tjunit]; 4614744Swnj /* 4624744Swnj * Record status... 4634744Swnj */ 4644877Ssam sc->sc_timo = INF; 4654744Swnj sc->sc_dsreg = addr->utds; 4664744Swnj sc->sc_erreg = addr->uter; 46711176Ssam sc->sc_resid = MASKREG(addr->utfc); 4684746Ssam if ((bp->b_flags&B_READ) == 0) 4694744Swnj sc->sc_lastiow = 1; 4704746Ssam state = um->um_tab.b_state; 4714746Ssam um->um_tab.b_state = 0; 4724744Swnj /* 4734744Swnj * Check for errors... 4744744Swnj */ 4754744Swnj if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) { 4764744Swnj /* 4774759Swnj * To clear the ERR bit, we must issue a drive clear 4784759Swnj * command, and to clear the TRE bit we must set the 4794759Swnj * controller clear bit. 4804759Swnj */ 4814759Swnj cs2 = addr->utcs2; 4824759Swnj if ((cs1 = addr->utcs1)&UT_TRE) 4834759Swnj addr->utcs2 |= UTCS2_CLR; 4844759Swnj /* is this dangerous ?? */ 4854759Swnj while ((addr->utcs1&UT_RDY) == 0) 4864759Swnj ; 4874759Swnj addr->utcs1 = UT_CLEAR|UT_GO; 4884759Swnj /* 48911176Ssam * If we were reading at 1600 or 6250 bpi and the error 49011176Ssam * was corrected, then don't consider this an error. 4914744Swnj */ 49211190Ssam if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) && 49311176Ssam (addr->uttc & UTTC_DEN) != UT_NRZI) { 494*18323Sralph tprintf(sc->sc_ttyp, 49511176Ssam "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 49611176Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 49711176Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 49811176Ssam sc->sc_erreg &= ~UTER_COR; 4994744Swnj } 5004744Swnj /* 5014744Swnj * If we were reading from a raw tape and the only error 5024744Swnj * was that the record was too long, then we don't consider 5034744Swnj * this an error. 5044744Swnj */ 5054744Swnj if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5064744Swnj (sc->sc_erreg&UTER_FCE)) 50711176Ssam sc->sc_erreg &= ~UTER_FCE; 50811197Slayer if (sc->sc_erreg == 0) 5094744Swnj goto ignoreerr; 5104744Swnj /* 51111176Ssam * Fix up errors which occur due to backspacing 51211176Ssam * "over" the front of the tape. 5134746Ssam */ 51411176Ssam if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV && 5154746Ssam ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0)) 5164746Ssam goto opdone; 5174746Ssam /* 5184744Swnj * Retry soft errors up to 8 times 5194744Swnj */ 5204744Swnj if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { 5214744Swnj if (++um->um_tab.b_errcnt < 7) { 5224744Swnj sc->sc_blkno++; 5234744Swnj ubadone(um); 5244744Swnj goto opcont; 5254744Swnj } 52611176Ssam } 5274744Swnj /* 52811176Ssam * Hard or non-I/O errors on non-raw tape 52911176Ssam * cause it to close. 53011176Ssam */ 53111176Ssam if (sc->sc_openf > 0 && bp != &rutbuf[UTUNIT(bp->b_dev)]) 53211176Ssam sc->sc_openf = -1; 53311176Ssam /* 5344744Swnj * Couldn't recover error. 5354744Swnj */ 536*18323Sralph tprintf(sc->sc_ttyp, 537*18323Sralph "ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 5384746Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 5394746Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 5404744Swnj bp->b_flags |= B_ERROR; 5414744Swnj goto opdone; 5424744Swnj } 54311176Ssam 5444744Swnj ignoreerr: 5454744Swnj /* 54611176Ssam * If we hit a tape mark update our position. 54711176Ssam */ 54811176Ssam if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) { 54911176Ssam /* 55011176Ssam * Set blkno and nxrec 55111176Ssam */ 55211176Ssam if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 55311176Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 55411176Ssam sc->sc_nxrec = 55511176Ssam bdbtofsb(bp->b_blkno) - addr->utfc; 55611176Ssam sc->sc_blkno = sc->sc_nxrec; 55711176Ssam } else { 55811176Ssam sc->sc_blkno = 55911176Ssam bdbtofsb(bp->b_blkno) + addr->utfc; 56011176Ssam sc->sc_nxrec = sc->sc_blkno-1; 56111176Ssam } 56211176Ssam } else 56311176Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 56411176Ssam /* 56511176Ssam * Note: if we get a tape mark on a read, the 56611176Ssam * frame count register will be zero, so b_resid 56711176Ssam * will be calculated correctly below. 56811176Ssam */ 56911176Ssam goto opdone; 57011176Ssam } 57111176Ssam /* 5724744Swnj * Advance tape control FSM. 5734744Swnj */ 5744744Swnj switch (state) { 5754744Swnj 5764744Swnj case SIO: /* read/write increments tape block # */ 5774744Swnj sc->sc_blkno++; 5784746Ssam break; 5794744Swnj 58011176Ssam case SCOM: /* motion commands update current position */ 5814744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) 5824744Swnj switch (bp->b_command) { 5834744Swnj 5844744Swnj case UT_SFORW: 5854744Swnj sc->sc_blkno -= bp->b_repcnt; 5864744Swnj break; 5874744Swnj 5884744Swnj case UT_SREV: 5894744Swnj sc->sc_blkno += bp->b_repcnt; 5904744Swnj break; 59111176Ssam 59211176Ssam case UT_REWOFFL: 59311176Ssam addr->utcs1 = UT_CLEAR|UT_GO; 59411176Ssam break; 5954744Swnj } 5964746Ssam break; 5974744Swnj 5984744Swnj case SSEEK: 5997382Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 6004744Swnj goto opcont; 6014744Swnj 6024746Ssam case SERASE: 6034746Ssam /* 6044746Ssam * Completed erase of the inter-record gap due to a 6054746Ssam * write error; now retry the write operation. 6064746Ssam */ 6074746Ssam um->um_tab.b_state = SERASED; 6084746Ssam goto opcont; 6094746Ssam 6104746Ssam case SREW: /* clear attention bit */ 6114746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 6124746Ssam break; 6134746Ssam 6144744Swnj default: 6154746Ssam printf("bad state %d\n", state); 6164744Swnj panic("utintr"); 6174744Swnj } 6184744Swnj 6194744Swnj opdone: 6204744Swnj /* 6214744Swnj * Reset error count and remove 6224744Swnj * from device queue 6234744Swnj */ 6244744Swnj um->um_tab.b_errcnt = 0; 6254746Ssam dp->b_actf = bp->av_forw; 62611176Ssam /* 62711176Ssam * For read command, frame count register contains 62811176Ssam * actual length of tape record. Otherwise, it 62911176Ssam * holds negative residual count. 63011176Ssam */ 63111176Ssam if (state == SIO && um->um_cmd == UT_RCOM) { 63211176Ssam bp->b_resid = 0; 63311176Ssam if (bp->b_bcount > MASKREG(addr->utfc)) 63411176Ssam bp->b_resid = bp->b_bcount - MASKREG(addr->utfc); 63511176Ssam } else 63611176Ssam bp->b_resid = MASKREG(-addr->utfc); 6374744Swnj ubadone(um); 6384744Swnj iodone(bp); 6394744Swnj /* 6404744Swnj * Circulate slave to end of controller queue 6414744Swnj * to give other slaves a chance 6424744Swnj */ 6434744Swnj um->um_tab.b_actf = dp->b_forw; 6444744Swnj if (dp->b_actf) { 6454744Swnj dp->b_forw = NULL; 6464744Swnj if (um->um_tab.b_actf == NULL) 6474744Swnj um->um_tab.b_actf = dp; 6484744Swnj else 6494744Swnj um->um_tab.b_actl->b_forw = dp; 6504744Swnj um->um_tab.b_actl = dp; 6514744Swnj } 6524744Swnj if (um->um_tab.b_actf == 0) 6534744Swnj return; 6544744Swnj opcont: 6554744Swnj utstart(um); 6564744Swnj } 6574744Swnj 6584744Swnj /* 6594833Swnj * Watchdog timer routine. 6604833Swnj */ 6614833Swnj uttimer(dev) 6624833Swnj int dev; 6634833Swnj { 6644833Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 6654846Sroot register short x; 6664833Swnj 6674833Swnj if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) { 6684859Ssam printf("tj%d: lost interrupt\n", TJUNIT(dev)); 6694833Swnj sc->sc_timo = INF; 6704846Sroot x = spl5(); 6714833Swnj utintr(UTUNIT(dev)); 6724846Sroot (void) splx(x); 6734833Swnj } 6744833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 6754833Swnj } 6764833Swnj 6774833Swnj /* 6784744Swnj * Raw interface for a read 6794744Swnj */ 6807736Sroot utread(dev, uio) 6814744Swnj dev_t dev; 6827736Sroot struct uio *uio; 6834744Swnj { 6848167Sroot int errno; 6857736Sroot 6868167Sroot errno = utphys(dev, uio); 6878167Sroot if (errno) 6888167Sroot return (errno); 6898167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys, uio)); 6904744Swnj } 6914744Swnj 6924744Swnj /* 6934744Swnj * Raw interface for a write 6944744Swnj */ 6957847Sroot utwrite(dev, uio) 6967736Sroot dev_t dev; 6977847Sroot struct uio *uio; 6984744Swnj { 6998167Sroot int errno; 7008167Sroot 7018167Sroot errno = utphys(dev, uio); 7028167Sroot if (errno) 7038167Sroot return (errno); 7048167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys, uio)); 7054744Swnj } 7064744Swnj 7074744Swnj /* 7084744Swnj * Check for valid device number dev and update our notion 7094744Swnj * of where we are on the tape 7104744Swnj */ 7117736Sroot utphys(dev, uio) 7124744Swnj dev_t dev; 7137736Sroot struct uio *uio; 7144744Swnj { 7154744Swnj register int tjunit = TJUNIT(dev); 7164744Swnj register struct tj_softc *sc; 7174744Swnj register struct uba_device *ui; 7184744Swnj 7197847Sroot if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 7207847Sroot return (ENXIO); 7214744Swnj sc = &tj_softc[tjunit]; 7227847Sroot sc->sc_blkno = bdbtofsb(uio->uio_offset>>9); 7234746Ssam sc->sc_nxrec = sc->sc_blkno+1; 7247847Sroot return (0); 7254744Swnj } 7264744Swnj 7274744Swnj /*ARGSUSED*/ 7287634Ssam utioctl(dev, cmd, data, flag) 7294744Swnj dev_t dev; 7307634Ssam caddr_t data; 7314744Swnj { 7324744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 7334744Swnj register struct buf *bp = &cutbuf[UTUNIT(dev)]; 7344744Swnj register callcount; 7354744Swnj int fcount; 7367634Ssam struct mtop *mtop; 7377634Ssam struct mtget *mtget; 7384744Swnj /* we depend of the values and order of the MT codes here */ 7394744Swnj static utops[] = 7404744Swnj {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE}; 7414744Swnj 7424744Swnj switch (cmd) { 7434744Swnj 7444744Swnj case MTIOCTOP: 7457634Ssam mtop = (struct mtop *)data; 7467634Ssam switch(mtop->mt_op) { 7474744Swnj 7484744Swnj case MTWEOF: 74911413Ssam case MTFSF: case MTBSF: 75011413Ssam case MTFSR: case MTBSR: 7517634Ssam callcount = mtop->mt_count; 7524744Swnj fcount = 1; 7534744Swnj break; 7544744Swnj 7554744Swnj case MTREW: case MTOFFL: case MTNOP: 7564744Swnj callcount = 1; 7574744Swnj fcount = 1; 7584744Swnj break; 7594744Swnj 7604744Swnj default: 7618577Sroot return (ENXIO); 7624744Swnj } 7638577Sroot if (callcount <= 0 || fcount <= 0) 7648577Sroot return (EINVAL); 7654744Swnj while (--callcount >= 0) { 7667634Ssam utcommand(dev, utops[mtop->mt_op], fcount); 7674744Swnj if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT)) 7684744Swnj break; 7694744Swnj } 7708650Sroot return (geterror(bp)); 7714744Swnj 7724744Swnj case MTIOCGET: 7737634Ssam mtget = (struct mtget *)data; 7747634Ssam mtget->mt_dsreg = sc->sc_dsreg; 7757634Ssam mtget->mt_erreg = sc->sc_erreg; 7767634Ssam mtget->mt_resid = sc->sc_resid; 7777634Ssam mtget->mt_type = MT_ISUT; 7788577Sroot break; 7794744Swnj 7804744Swnj default: 7818577Sroot return (ENXIO); 7824744Swnj } 7838577Sroot return (0); 7844744Swnj } 7854744Swnj 7864744Swnj utreset(uban) 7874744Swnj int uban; 7884744Swnj { 7894744Swnj register struct uba_ctlr *um; 7904744Swnj register ut11, tjunit; 7914744Swnj register struct uba_device *ui; 7924744Swnj register struct buf *dp; 7934744Swnj 7944744Swnj for (ut11 = 0; ut11 < NUT; ut11++) { 7954744Swnj if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || 7964744Swnj um->um_ubanum != uban) 7974744Swnj continue; 7984744Swnj printf(" ut%d", ut11); 7994746Ssam um->um_tab.b_state = 0; 8004744Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8014744Swnj if (um->um_ubinfo) { 8024744Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 8039358Ssam um->um_ubinfo = 0; 8044744Swnj } 8054744Swnj ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; 8064746Ssam ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR; 8074744Swnj for (tjunit = 0; tjunit < NTJ; tjunit++) { 8084744Swnj if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um || 8094744Swnj ui->ui_alive == 0) 8104744Swnj continue; 8114744Swnj dp = &tjutab[tjunit]; 8124746Ssam dp->b_state = 0; 8134744Swnj dp->b_forw = 0; 8144744Swnj if (um->um_tab.b_actf == NULL) 8154744Swnj um->um_tab.b_actf = dp; 8164744Swnj else 8174744Swnj um->um_tab.b_actl->b_forw = dp; 8184744Swnj um->um_tab.b_actl = dp; 8194744Swnj if (tj_softc[tjunit].sc_openf > 0) 8204744Swnj tj_softc[tjunit].sc_openf = -1; 8214744Swnj } 8224744Swnj utstart(um); 8234744Swnj } 8244744Swnj } 8254744Swnj 8264744Swnj /* 8274744Swnj * Do a stand-alone core dump to tape -- 8284744Swnj * from here down, routines are used only in dump context 8294744Swnj */ 8304744Swnj #define DBSIZE 20 8314744Swnj 8324744Swnj utdump() 8334744Swnj { 8344744Swnj register struct uba_device *ui; 8354744Swnj register struct uba_regs *up; 8364746Ssam register struct utdevice *addr; 8374744Swnj int blk, num = maxfree; 8384744Swnj int start = 0; 8394744Swnj 8404744Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8414744Swnj if (tjdinfo[0] == 0) 8424744Swnj return (ENXIO); 8434744Swnj ui = phys(tjdinfo[0], struct uba_device *); 8444744Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8454941Swnj ubainit(up); 8464744Swnj DELAY(1000000); 8474941Swnj addr = (struct utdevice *)ui->ui_physaddr; 8484746Ssam utwait(addr); 8494746Ssam /* 8504746Ssam * Be sure to set the appropriate density here. We use 8514746Ssam * 6250, but maybe it should be done at 1600 to insure the 8524746Ssam * tape can be read by most any other tape drive available. 8534746Ssam */ 8544746Ssam addr->uttc = UT_GCR|PDP11FMT; /* implicit slave 0 or-ed in */ 8554746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 8564744Swnj while (num > 0) { 8574744Swnj blk = num > DBSIZE ? DBSIZE : num; 8584746Ssam utdwrite(start, blk, addr, up); 8594746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8604746Ssam return(EIO); 8614744Swnj start += blk; 8624744Swnj num -= blk; 8634744Swnj } 8644746Ssam uteof(addr); 8654746Ssam uteof(addr); 8664746Ssam utwait(addr); 8674746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8684744Swnj return(EIO); 8694746Ssam addr->utcs1 = UT_REW|UT_GO; 8704744Swnj return (0); 8714744Swnj } 8724744Swnj 8734746Ssam utdwrite(dbuf, num, addr, up) 8744744Swnj register dbuf, num; 8754746Ssam register struct utdevice *addr; 8764744Swnj struct uba_regs *up; 8774744Swnj { 8784744Swnj register struct pte *io; 8794744Swnj register int npf; 8804744Swnj 8814746Ssam utwait(addr); 8824744Swnj io = up->uba_map; 8834744Swnj npf = num + 1; 8844744Swnj while (--npf != 0) 8854744Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 8864744Swnj *(int *)io = 0; 8874746Ssam addr->utwc = -((num*NBPG)>>1); 8884746Ssam addr->utfc = -(num*NBPG); 8894746Ssam addr->utba = 0; 8904746Ssam addr->utcs1 = UT_WCOM|UT_GO; 8914744Swnj } 8924744Swnj 8934746Ssam utwait(addr) 8944746Ssam struct utdevice *addr; 8954744Swnj { 8964744Swnj register s; 8974744Swnj 8984744Swnj do 8994746Ssam s = addr->utds; 9004744Swnj while ((s&UTDS_DRY) == 0); 9014744Swnj } 9024744Swnj 9034746Ssam uteof(addr) 9044746Ssam struct utdevice *addr; 9054744Swnj { 9064744Swnj 9074746Ssam utwait(addr); 9084746Ssam addr->utcs1 = UT_WEOF|UT_GO; 9094744Swnj } 9104744Swnj #endif 911