1*8577Sroot /* ut.c 4.20 82/10/17 */ 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 */ 134744Swnj #include "../h/param.h" 144744Swnj #include "../h/systm.h" 154744Swnj #include "../h/buf.h" 164744Swnj #include "../h/conf.h" 174744Swnj #include "../h/dir.h" 184744Swnj #include "../h/file.h" 194744Swnj #include "../h/user.h" 204744Swnj #include "../h/map.h" 214744Swnj #include "../h/pte.h" 227634Ssam #include "../h/ioctl.h" 234744Swnj #include "../h/mtio.h" 244744Swnj #include "../h/cmap.h" 257736Sroot #include "../h/uio.h" 264744Swnj 278483Sroot #include "../vax/cpu.h" 288483Sroot #include "../vaxuba/ubareg.h" 298483Sroot #include "../vaxuba/ubavar.h" 308483Sroot #include "../vaxuba/utreg.h" 314744Swnj 324744Swnj struct buf rutbuf[NUT]; /* bufs for raw i/o */ 334744Swnj struct buf cutbuf[NUT]; /* bufs for control operations */ 344744Swnj struct buf tjutab[NTJ]; /* bufs for slave queue headers */ 354744Swnj 364744Swnj struct uba_ctlr *utminfo[NUT]; 374744Swnj struct uba_device *tjdinfo[NTJ]; 384833Swnj int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer(); 394744Swnj u_short utstd[] = { 0772440, 0 }; 404744Swnj struct uba_driver utdriver = 414744Swnj { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 }; 424744Swnj 434744Swnj /* bits in minor device */ 444744Swnj #define TJUNIT(dev) (minor(dev)&03) 454744Swnj #define T_NOREWIND 04 464744Swnj #define T_1600BPI 010 474744Swnj #define T_6250BPI 020 484744Swnj short utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI }; 494744Swnj 504744Swnj /* slave to controller mapping table */ 514744Swnj short tjtout[NTJ]; 524744Swnj #define UTUNIT(dev) (tjtout[TJUNIT(dev)]) 534744Swnj 544744Swnj #define INF (daddr_t)1000000L /* a block number that wont exist */ 554744Swnj 564744Swnj struct tj_softc { 574744Swnj char sc_openf; /* exclusive open */ 584744Swnj char sc_lastiow; /* last I/O operation was a write */ 594744Swnj daddr_t sc_blkno; /* next block to transfer */ 604744Swnj daddr_t sc_nxrec; /* next record on tape */ 614744Swnj u_short sc_erreg; /* image of uter */ 624744Swnj u_short sc_dsreg; /* image of utds */ 634746Ssam u_short sc_resid; /* residual from transfer */ 644744Swnj u_short sc_dens; /* sticky selected density */ 654833Swnj daddr_t sc_timo; /* time until timeout expires */ 664833Swnj short sc_tact; /* timeout is active flag */ 674744Swnj } tj_softc[NTJ]; 684744Swnj 694744Swnj /* 704744Swnj * Internal per/slave states found in sc_state 714744Swnj */ 724744Swnj #define SSEEK 1 /* seeking */ 734744Swnj #define SIO 2 /* doing sequential I/O */ 744744Swnj #define SCOM 3 /* sending a control command */ 754744Swnj #define SREW 4 /* doing a rewind op */ 764746Ssam #define SERASE 5 /* erase inter-record gap */ 774746Ssam #define SERASED 6 /* erased inter-record gap */ 784744Swnj 794941Swnj /*ARGSUSED*/ 804744Swnj utprobe(reg) 814744Swnj caddr_t reg; 824744Swnj { 834744Swnj register int br, cvec; 844744Swnj #ifdef lint 854744Swnj br=0; cvec=br; br=cvec; 864941Swnj utintr(0); 874744Swnj #endif 884746Ssam /* 896954Sroot * The SI documentation says you must set the RDY bit 906954Sroot * (even though it's read-only) to force an interrupt. 914746Ssam */ 926954Sroot ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY; 934744Swnj DELAY(10000); 947405Skre return (sizeof (struct utdevice)); 954744Swnj } 964744Swnj 974744Swnj /*ARGSUSED*/ 984744Swnj utslave(ui, reg) 994744Swnj struct uba_device *ui; 1004744Swnj caddr_t reg; 1014744Swnj { 1024744Swnj /* 1034744Swnj * A real TU45 would support the slave present bit 1044744Swnj * int the drive type register, but this thing doesn't, 1054744Swnj * so there's no way to determine if a slave is present or not. 1064744Swnj */ 1074744Swnj return(1); 1084744Swnj } 1094744Swnj 1104744Swnj utattach(ui) 1114744Swnj struct uba_device *ui; 1124744Swnj { 1134744Swnj tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; 1144744Swnj } 1154744Swnj 1164744Swnj /* 1174744Swnj * Open the device with exclusive access. 1184744Swnj */ 1194744Swnj utopen(dev, flag) 1204744Swnj dev_t dev; 1214744Swnj int flag; 1224744Swnj { 1234744Swnj register int tjunit = TJUNIT(dev); 1244744Swnj register struct uba_device *ui; 1254744Swnj register struct tj_softc *sc; 1264744Swnj int olddens, dens; 1275439Sroot register int s; 1284744Swnj 1294744Swnj if (tjunit >= NTJ || (sc = &tj_softc[tjunit])->sc_openf || 130*8577Sroot (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 131*8577Sroot return (ENXIO); 1324744Swnj olddens = sc->sc_dens; 133*8577Sroot dens = sc->sc_dens = 134*8577Sroot utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]| 135*8577Sroot PDP11FMT|(ui->ui_slave&07); 1364744Swnj get: 1374744Swnj utcommand(dev, UT_SENSE, 1); 1384744Swnj if (sc->sc_dsreg&UTDS_PIP) { 1394744Swnj sleep((caddr_t) &lbolt, PZERO+1); 1404744Swnj goto get; 1414744Swnj } 1424744Swnj sc->sc_dens = olddens; 1434744Swnj if ((sc->sc_dsreg&UTDS_MOL) == 0) { 1444744Swnj uprintf("tj%d: not online\n", tjunit); 145*8577Sroot return (EIO); 1464744Swnj } 1474744Swnj if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) { 1484744Swnj uprintf("tj%d: no write ring\n", tjunit); 149*8577Sroot return (EIO); 1504744Swnj } 1514744Swnj if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) && 1524744Swnj dens != sc->sc_dens) { 1534744Swnj uprintf("tj%d: can't change density in mid-tape\n", tjunit); 154*8577Sroot return (EIO); 1554744Swnj } 1564744Swnj sc->sc_openf = 1; 1574744Swnj sc->sc_blkno = (daddr_t)0; 1584744Swnj sc->sc_nxrec = INF; 1594744Swnj sc->sc_lastiow = 0; 1604744Swnj sc->sc_dens = dens; 1614746Ssam /* 1624746Ssam * For 6250 bpi take exclusive use of the UNIBUS. 1634746Ssam */ 1644746Ssam ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI; 1655439Sroot s = spl6(); 1664833Swnj if (sc->sc_tact == 0) { 1674833Swnj sc->sc_timo = INF; 1684833Swnj sc->sc_tact = 1; 1694833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 1704833Swnj } 1715439Sroot splx(s); 172*8577Sroot return (0); 1734744Swnj } 1744744Swnj 1754744Swnj utclose(dev, flag) 1764744Swnj register dev_t dev; 1774744Swnj register flag; 1784744Swnj { 1794744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 1804744Swnj 1814744Swnj if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) { 1824744Swnj utcommand(dev, UT_WEOF, 1); 1834744Swnj utcommand(dev, UT_WEOF, 1); 1844744Swnj utcommand(dev, UT_SREV, 1); 1854744Swnj } 1864744Swnj if ((minor(dev)&T_NOREWIND) == 0) 1874744Swnj utcommand(dev, UT_REW, 0); 1884744Swnj sc->sc_openf = 0; 1894744Swnj } 1904744Swnj 1914744Swnj utcommand(dev, com, count) 1924744Swnj dev_t dev; 1934744Swnj int com, count; 1944744Swnj { 1954744Swnj register struct buf *bp; 1965439Sroot register int s; 1974744Swnj 1984744Swnj bp = &cutbuf[UTUNIT(dev)]; 1995439Sroot s = spl5(); 2004744Swnj while (bp->b_flags&B_BUSY) { 2014744Swnj if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2024744Swnj break; 2034744Swnj bp->b_flags |= B_WANTED; 2044744Swnj sleep((caddr_t)bp, PRIBIO); 2054744Swnj } 2064744Swnj bp->b_flags = B_BUSY|B_READ; 2075439Sroot splx(s); 2084744Swnj bp->b_dev = dev; 2094744Swnj bp->b_command = com; 2104744Swnj bp->b_repcnt = count; 2114744Swnj bp->b_blkno = 0; 2124744Swnj utstrategy(bp); 2134744Swnj if (count == 0) 2144744Swnj return; 2154744Swnj iowait(bp); 2164744Swnj if (bp->b_flags&B_WANTED) 2174744Swnj wakeup((caddr_t)bp); 2184744Swnj bp->b_flags &= B_ERROR; 2194744Swnj } 2204744Swnj 2214744Swnj /* 2224744Swnj * Queue a tape operation. 2234744Swnj */ 2244744Swnj utstrategy(bp) 2254744Swnj register struct buf *bp; 2264744Swnj { 2274744Swnj int tjunit = TJUNIT(bp->b_dev); 2284744Swnj register struct uba_ctlr *um; 2294744Swnj register struct buf *dp; 2304744Swnj 2314744Swnj /* 2324744Swnj * Put transfer at end of unit queue 2334744Swnj */ 2344744Swnj dp = &tjutab[tjunit]; 2354744Swnj bp->av_forw = NULL; 2364744Swnj (void) spl5(); 2374744Swnj if (dp->b_actf == NULL) { 2384744Swnj dp->b_actf = bp; 2394744Swnj /* 2404744Swnj * Transport not active, so... 2414744Swnj * put at end of controller queue 2424744Swnj */ 2434744Swnj dp->b_forw = NULL; 2444744Swnj um = tjdinfo[tjunit]->ui_mi; 2454744Swnj if (um->um_tab.b_actf == NULL) 2464744Swnj um->um_tab.b_actf = dp; 2474744Swnj else 2484744Swnj um->um_tab.b_actl->b_forw = dp; 2494744Swnj um->um_tab.b_actl = dp; 2504744Swnj } else 2514744Swnj dp->b_actl->av_forw = bp; 2524744Swnj dp->b_actl = bp; 2534744Swnj /* 2544744Swnj * If the controller is not busy, set it going. 2554744Swnj */ 2564746Ssam if (um->um_tab.b_state == 0) 2574744Swnj utstart(um); 2584744Swnj (void) spl0(); 2594744Swnj } 2604744Swnj 2614744Swnj utstart(um) 2624744Swnj register struct uba_ctlr *um; 2634744Swnj { 2644746Ssam register struct utdevice *addr; 2654744Swnj register struct buf *bp, *dp; 2664744Swnj register struct tj_softc *sc; 2674744Swnj struct uba_device *ui; 2684744Swnj int tjunit; 2694744Swnj daddr_t blkno; 2704744Swnj 2714744Swnj loop: 2724744Swnj /* 2734744Swnj * Scan controller queue looking for units with 2744744Swnj * transaction queues to dispatch 2754744Swnj */ 2764744Swnj if ((dp = um->um_tab.b_actf) == NULL) 2774744Swnj return; 2784744Swnj if ((bp = dp->b_actf) == NULL) { 2794744Swnj um->um_tab.b_actf = dp->b_forw; 2804744Swnj goto loop; 2814744Swnj } 2824746Ssam addr = (struct utdevice *)um->um_addr; 2834744Swnj tjunit = TJUNIT(bp->b_dev); 2844744Swnj ui = tjdinfo[tjunit]; 2854744Swnj sc = &tj_softc[tjunit]; 2864744Swnj /* note slave select, density, and format were merged on open */ 2874746Ssam addr->uttc = sc->sc_dens; 2884746Ssam sc->sc_dsreg = addr->utds; 2894746Ssam sc->sc_erreg = addr->uter; 2904746Ssam /* watch this, sports fans */ 2914746Ssam sc->sc_resid = bp->b_flags&B_READ ? 2924746Ssam bp->b_bcount - ((-addr->utfc)&0xffff) : -addr->utwc<<1; 2934744Swnj /* 2944744Swnj * Default is that last command was NOT a write command; 2954744Swnj * if we do a write command we will notice this in utintr(). 2964744Swnj */ 2974744Swnj sc->sc_lastiow = 0; 2984746Ssam if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) { 2994744Swnj /* 3004744Swnj * Have had a hard error on a non-raw tape 3014744Swnj * or the tape unit is now unavailable 3024744Swnj * (e.g. taken off line). 3034744Swnj */ 3044744Swnj bp->b_flags |= B_ERROR; 3054744Swnj goto next; 3064744Swnj } 3074744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 3084744Swnj /* 3094744Swnj * Execute a control operation with the specified 3104744Swnj * count. 3114744Swnj */ 3124744Swnj if (bp->b_command == UT_SENSE) 3134744Swnj goto next; 3144744Swnj /* 3154744Swnj * Set next state; handle timeouts 3164744Swnj */ 3174833Swnj if (bp->b_command == UT_REW) { 3184746Ssam um->um_tab.b_state = SREW; 3194833Swnj sc->sc_timo = 5*60; 3204833Swnj } else { 3214746Ssam um->um_tab.b_state = SCOM; 3224833Swnj sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60); 3234833Swnj } 3244744Swnj /* NOTE: this depends on the ut command values */ 3254744Swnj if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) 3264746Ssam addr->utfc = -bp->b_repcnt; 3274744Swnj goto dobpcmd; 3284744Swnj } 3294744Swnj /* 3304744Swnj * The following checks boundary conditions for operations 3314744Swnj * on non-raw tapes. On raw tapes the initialization of 3324744Swnj * sc->sc_nxrec by utphys causes them to be skipped normally 3334744Swnj * (except in the case of retries). 3344744Swnj */ 3357382Ssam if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 3364744Swnj /* can't read past end of file */ 3374744Swnj bp->b_flags |= B_ERROR; 3384744Swnj bp->b_error = ENXIO; 3394744Swnj goto next; 3404744Swnj } 3417382Ssam if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) { 3424744Swnj /* read at eof returns 0 count */ 3434744Swnj bp->b_resid = bp->b_bcount; 3444744Swnj clrbuf(bp); 3454744Swnj goto next; 3464744Swnj } 3474744Swnj if ((bp->b_flags&B_READ) == 0) 3487382Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno)+1; 3494744Swnj /* 3504744Swnj * If the tape is correctly positioned, set up all the 3514744Swnj * registers but the csr, and give control over to the 3524744Swnj * UNIBUS adaptor routines, to wait for resources to 3534744Swnj * start I/O. 3544744Swnj */ 3557382Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3564746Ssam addr->utwc = -(((bp->b_bcount)+1)>>1); 3574746Ssam addr->utfc = -bp->b_bcount; 3584744Swnj if ((bp->b_flags&B_READ) == 0) { 3594744Swnj /* 3604744Swnj * On write error retries erase the 3614746Ssam * inter-record gap before rewriting. 3624744Swnj */ 3634746Ssam if (um->um_tab.b_errcnt) { 3644746Ssam if (um->um_tab.b_state != SERASED) { 3654759Swnj um->um_tab.b_state = SERASE; 3664833Swnj sc->sc_timo = 60; 3674746Ssam addr->utcs1 = UT_ERASE|UT_IE|UT_GO; 3684746Ssam return; 3694746Ssam } 3704746Ssam } 3714746Ssam um->um_cmd = UT_WCOM; 3724744Swnj } else 3734744Swnj um->um_cmd = UT_RCOM; 3744833Swnj sc->sc_timo = 60; 3754746Ssam um->um_tab.b_state = SIO; 3764744Swnj (void) ubago(ui); 3774744Swnj return; 3784744Swnj } 3794744Swnj /* 3804744Swnj * Tape positioned incorrectly; seek forwards or 3814744Swnj * backwards to the correct spot. This happens for 3824744Swnj * raw tapes only on error retries. 3834744Swnj */ 3844746Ssam um->um_tab.b_state = SSEEK; 3857382Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 3867382Ssam addr->utfc = blkno - bdbtofsb(bp->b_blkno); 3874744Swnj bp->b_command = UT_SFORW; 3884744Swnj } else { 3897382Ssam addr->utfc = bdbtofsb(bp->b_blkno) - blkno; 3904744Swnj bp->b_command = UT_SREV; 3914744Swnj } 3924833Swnj sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60); 3934744Swnj 3944744Swnj dobpcmd: 3954744Swnj /* 3964744Swnj * Perform the command setup in bp. 3974744Swnj */ 3984746Ssam addr->utcs1 = bp->b_command|UT_IE|UT_GO; 3994744Swnj return; 4004744Swnj next: 4014744Swnj /* 4024744Swnj * Advance to the next command in the slave queue, 4034744Swnj * posting notice and releasing resources as needed. 4044744Swnj */ 4054744Swnj if (um->um_ubinfo) 4064744Swnj ubadone(um); 4074744Swnj um->um_tab.b_errcnt = 0; 4084744Swnj dp->b_actf = bp->av_forw; 4094744Swnj iodone(bp); 4104744Swnj goto loop; 4114744Swnj } 4124744Swnj 4134744Swnj /* 4144744Swnj * Start operation on controller -- 4154744Swnj * UNIBUS resources have been allocated. 4164744Swnj */ 4174744Swnj utdgo(um) 4184744Swnj register struct uba_ctlr *um; 4194744Swnj { 4204744Swnj register struct utdevice *addr = (struct utdevice *)um->um_addr; 4214744Swnj 4224744Swnj addr->utba = (u_short) um->um_ubinfo; 4234744Swnj addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x30)|UT_IE|UT_GO; 4244744Swnj } 4254744Swnj 4264744Swnj /* 4274744Swnj * Ut interrupt handler 4284744Swnj */ 4294744Swnj /*ARGSUSED*/ 4304744Swnj utintr(ut11) 4314744Swnj int ut11; 4324744Swnj { 4334744Swnj struct buf *dp; 4344744Swnj register struct buf *bp; 4354744Swnj register struct uba_ctlr *um = utminfo[ut11]; 4364744Swnj register struct utdevice *addr; 4374744Swnj register struct tj_softc *sc; 4384746Ssam u_short tjunit, cs2, cs1; 4394744Swnj register state; 4404744Swnj 4414744Swnj if ((dp = um->um_tab.b_actf) == NULL) 4424744Swnj return; 4434744Swnj bp = dp->b_actf; 4444744Swnj tjunit = TJUNIT(bp->b_dev); 4454744Swnj addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr; 4464744Swnj sc = &tj_softc[tjunit]; 4474744Swnj /* 4484744Swnj * Record status... 4494744Swnj */ 4504877Ssam sc->sc_timo = INF; 4514744Swnj sc->sc_dsreg = addr->utds; 4524744Swnj sc->sc_erreg = addr->uter; 4534746Ssam sc->sc_resid = bp->b_flags&B_READ ? 4544746Ssam bp->b_bcount - (-addr->utfc)&0xffff : -addr->utwc<<1; 4554746Ssam if ((bp->b_flags&B_READ) == 0) 4564744Swnj sc->sc_lastiow = 1; 4574746Ssam state = um->um_tab.b_state; 4584746Ssam um->um_tab.b_state = 0; 4594744Swnj /* 4604744Swnj * Check for errors... 4614744Swnj */ 4624744Swnj if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) { 4634744Swnj /* 4644759Swnj * To clear the ERR bit, we must issue a drive clear 4654759Swnj * command, and to clear the TRE bit we must set the 4664759Swnj * controller clear bit. 4674759Swnj */ 4684759Swnj cs2 = addr->utcs2; 4694759Swnj if ((cs1 = addr->utcs1)&UT_TRE) 4704759Swnj addr->utcs2 |= UTCS2_CLR; 4714759Swnj /* is this dangerous ?? */ 4724759Swnj while ((addr->utcs1&UT_RDY) == 0) 4734759Swnj ; 4744759Swnj addr->utcs1 = UT_CLEAR|UT_GO; 4754759Swnj /* 4764746Ssam * If we hit a tape mark or EOT update our position. 4774744Swnj */ 4784759Swnj if (sc->sc_dsreg&(UTDS_TM|UTDS_EOT)) { 4794744Swnj /* 4804759Swnj * Set blkno and nxrec 4814744Swnj */ 4824744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 4837382Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 4844744Swnj sc->sc_nxrec = 4857382Ssam bdbtofsb(bp->b_blkno) - addr->utfc; 4864744Swnj sc->sc_blkno = sc->sc_nxrec; 4874744Swnj } else { 4884744Swnj sc->sc_blkno = 4897382Ssam bdbtofsb(bp->b_blkno) + addr->utfc; 4904744Swnj sc->sc_nxrec = sc->sc_blkno-1; 4914744Swnj } 4924746Ssam } else 4937382Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 4944744Swnj state = SCOM; /* force completion */ 4954744Swnj /* 4964746Ssam * Stuff so we can unstuff later 4974746Ssam * to get the residual. 4984744Swnj */ 4994746Ssam addr->utwc = (-bp->b_bcount)>>1; 5004744Swnj addr->utfc = -bp->b_bcount; 5014746Ssam if (sc->sc_dsreg&UTDS_EOT) 5024746Ssam goto harderror; 5034744Swnj goto opdone; 5044744Swnj } 5054744Swnj /* 5064744Swnj * If we were reading from a raw tape and the only error 5074744Swnj * was that the record was too long, then we don't consider 5084744Swnj * this an error. 5094744Swnj */ 5104744Swnj if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5114744Swnj (sc->sc_erreg&UTER_FCE)) 5124744Swnj goto ignoreerr; 5134744Swnj /* 5144746Ssam * Fix up errors which occur due to backspacing "over" the 5154746Ssam * front of the tape. 5164746Ssam */ 5174746Ssam if ((sc->sc_dsreg&UTDS_BOT) && 5184746Ssam (bp->b_command == UT_SREV || bp->b_command == UT_SREV) && 5194746Ssam ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0)) 5204746Ssam goto opdone; 5214746Ssam /* 5224744Swnj * Retry soft errors up to 8 times 5234744Swnj */ 5244744Swnj if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { 5254744Swnj if (++um->um_tab.b_errcnt < 7) { 5264744Swnj sc->sc_blkno++; 5274744Swnj ubadone(um); 5284744Swnj goto opcont; 5294744Swnj } 5304744Swnj } else 5314746Ssam harderror: 5324744Swnj /* 5334744Swnj * Hard or non-I/O errors on non-raw tape 5344746Ssam * cause it to close; also, reading off the 5354746Ssam * end of the tape. 5364744Swnj */ 5374746Ssam if (sc->sc_openf > 0 && 5384746Ssam bp != &rutbuf[UTUNIT(bp->b_dev)] || 5394746Ssam sc->sc_dsreg&UTDS_EOT) 5404744Swnj sc->sc_openf = -1; 5414744Swnj /* 5424744Swnj * Couldn't recover error. 5434744Swnj */ 5444746Ssam printf("ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 5454746Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 5464746Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 5474744Swnj bp->b_flags |= B_ERROR; 5484744Swnj goto opdone; 5494744Swnj } 5504744Swnj ignoreerr: 5514744Swnj /* 5524744Swnj * Advance tape control FSM. 5534744Swnj */ 5544744Swnj switch (state) { 5554744Swnj 5564744Swnj case SIO: /* read/write increments tape block # */ 5574744Swnj sc->sc_blkno++; 5584746Ssam break; 5594744Swnj 5604744Swnj case SCOM: /* forw/rev space updates current position */ 5614744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) 5624744Swnj switch (bp->b_command) { 5634744Swnj 5644744Swnj case UT_SFORW: 5654744Swnj sc->sc_blkno -= bp->b_repcnt; 5664744Swnj break; 5674744Swnj 5684744Swnj case UT_SREV: 5694744Swnj sc->sc_blkno += bp->b_repcnt; 5704744Swnj break; 5714744Swnj } 5724746Ssam break; 5734744Swnj 5744744Swnj case SSEEK: 5757382Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 5764744Swnj goto opcont; 5774744Swnj 5784746Ssam case SERASE: 5794746Ssam /* 5804746Ssam * Completed erase of the inter-record gap due to a 5814746Ssam * write error; now retry the write operation. 5824746Ssam */ 5834746Ssam um->um_tab.b_state = SERASED; 5844746Ssam goto opcont; 5854746Ssam 5864746Ssam case SREW: /* clear attention bit */ 5874746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 5884746Ssam break; 5894746Ssam 5904744Swnj default: 5914746Ssam printf("bad state %d\n", state); 5924744Swnj panic("utintr"); 5934744Swnj } 5944744Swnj 5954744Swnj opdone: 5964744Swnj /* 5974744Swnj * Reset error count and remove 5984744Swnj * from device queue 5994744Swnj */ 6004744Swnj um->um_tab.b_errcnt = 0; 6014746Ssam dp->b_actf = bp->av_forw; 6024746Ssam bp->b_resid = bp->b_command&B_READ ? 6034746Ssam bp->b_bcount - ((-addr->utfc)&0xffff) : -addr->utwc<<1; 6044744Swnj ubadone(um); 6054744Swnj iodone(bp); 6064744Swnj /* 6074744Swnj * Circulate slave to end of controller queue 6084744Swnj * to give other slaves a chance 6094744Swnj */ 6104744Swnj um->um_tab.b_actf = dp->b_forw; 6114744Swnj if (dp->b_actf) { 6124744Swnj dp->b_forw = NULL; 6134744Swnj if (um->um_tab.b_actf == NULL) 6144744Swnj um->um_tab.b_actf = dp; 6154744Swnj else 6164744Swnj um->um_tab.b_actl->b_forw = dp; 6174744Swnj um->um_tab.b_actl = dp; 6184744Swnj } 6194744Swnj if (um->um_tab.b_actf == 0) 6204744Swnj return; 6214744Swnj opcont: 6224744Swnj utstart(um); 6234744Swnj } 6244744Swnj 6254744Swnj /* 6264833Swnj * Watchdog timer routine. 6274833Swnj */ 6284833Swnj uttimer(dev) 6294833Swnj int dev; 6304833Swnj { 6314833Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 6324846Sroot register short x; 6334833Swnj 6344833Swnj if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) { 6354859Ssam printf("tj%d: lost interrupt\n", TJUNIT(dev)); 6364833Swnj sc->sc_timo = INF; 6374846Sroot x = spl5(); 6384833Swnj utintr(UTUNIT(dev)); 6394846Sroot (void) splx(x); 6404833Swnj } 6414833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 6424833Swnj } 6434833Swnj 6444833Swnj /* 6454744Swnj * Raw interface for a read 6464744Swnj */ 6477736Sroot utread(dev, uio) 6484744Swnj dev_t dev; 6497736Sroot struct uio *uio; 6504744Swnj { 6518167Sroot int errno; 6527736Sroot 6538167Sroot errno = utphys(dev, uio); 6548167Sroot if (errno) 6558167Sroot return (errno); 6568167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys, uio)); 6574744Swnj } 6584744Swnj 6594744Swnj /* 6604744Swnj * Raw interface for a write 6614744Swnj */ 6627847Sroot utwrite(dev, uio) 6637736Sroot dev_t dev; 6647847Sroot struct uio *uio; 6654744Swnj { 6668167Sroot int errno; 6678167Sroot 6688167Sroot errno = utphys(dev, uio); 6698167Sroot if (errno) 6708167Sroot return (errno); 6718167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys, uio)); 6724744Swnj } 6734744Swnj 6744744Swnj /* 6754744Swnj * Check for valid device number dev and update our notion 6764744Swnj * of where we are on the tape 6774744Swnj */ 6787736Sroot utphys(dev, uio) 6794744Swnj dev_t dev; 6807736Sroot struct uio *uio; 6814744Swnj { 6824744Swnj register int tjunit = TJUNIT(dev); 6834744Swnj register struct tj_softc *sc; 6844744Swnj register struct uba_device *ui; 6854744Swnj 6867847Sroot if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 6877847Sroot return (ENXIO); 6884744Swnj sc = &tj_softc[tjunit]; 6897847Sroot sc->sc_blkno = bdbtofsb(uio->uio_offset>>9); 6904746Ssam sc->sc_nxrec = sc->sc_blkno+1; 6917847Sroot return (0); 6924744Swnj } 6934744Swnj 6944744Swnj /*ARGSUSED*/ 6957634Ssam utioctl(dev, cmd, data, flag) 6964744Swnj dev_t dev; 6977634Ssam caddr_t data; 6984744Swnj { 6994744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 7004744Swnj register struct buf *bp = &cutbuf[UTUNIT(dev)]; 7014744Swnj register callcount; 7024744Swnj int fcount; 7037634Ssam struct mtop *mtop; 7047634Ssam struct mtget *mtget; 7054744Swnj /* we depend of the values and order of the MT codes here */ 7064744Swnj static utops[] = 7074744Swnj {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE}; 7084744Swnj 7094744Swnj switch (cmd) { 7104744Swnj 7114744Swnj case MTIOCTOP: 7127634Ssam mtop = (struct mtop *)data; 7137634Ssam switch(mtop->mt_op) { 7144744Swnj 7154744Swnj case MTWEOF: 7167634Ssam callcount = mtop->mt_count; 7174744Swnj fcount = 1; 7184744Swnj break; 7194744Swnj 7204744Swnj case MTFSF: case MTBSF: 7214744Swnj case MTFSR: case MTBSR: 7224744Swnj callcount = 1; 7237634Ssam fcount = mtop->mt_count; 7244744Swnj break; 7254744Swnj 7264744Swnj case MTREW: case MTOFFL: case MTNOP: 7274744Swnj callcount = 1; 7284744Swnj fcount = 1; 7294744Swnj break; 7304744Swnj 7314744Swnj default: 732*8577Sroot return (ENXIO); 7334744Swnj } 734*8577Sroot if (callcount <= 0 || fcount <= 0) 735*8577Sroot return (EINVAL); 7364744Swnj while (--callcount >= 0) { 7377634Ssam utcommand(dev, utops[mtop->mt_op], fcount); 7384746Ssam /* note this depends on the mtop values */ 7397634Ssam if ((mtop->mt_op >= MTFSF || mtop->mt_op <= MTBSR) && 7404744Swnj bp->b_resid) { 741*8577Sroot return (EIO); 7424744Swnj if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT)) 7434744Swnj break; 7444744Swnj } 745*8577Sroot geterror(bp); /* XXX */ 746*8577Sroot return (u.u_error); /* XXX */ 7474744Swnj 7484744Swnj case MTIOCGET: 7497634Ssam mtget = (struct mtget *)data; 7507634Ssam mtget->mt_dsreg = sc->sc_dsreg; 7517634Ssam mtget->mt_erreg = sc->sc_erreg; 7527634Ssam mtget->mt_resid = sc->sc_resid; 7537634Ssam mtget->mt_type = MT_ISUT; 754*8577Sroot break; 7554744Swnj 7564744Swnj default: 757*8577Sroot return (ENXIO); 7584744Swnj } 759*8577Sroot return (0); 7604744Swnj } 7614744Swnj 7624744Swnj utreset(uban) 7634744Swnj int uban; 7644744Swnj { 7654744Swnj register struct uba_ctlr *um; 7664744Swnj register ut11, tjunit; 7674744Swnj register struct uba_device *ui; 7684744Swnj register struct buf *dp; 7694744Swnj 7704744Swnj for (ut11 = 0; ut11 < NUT; ut11++) { 7714744Swnj if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || 7724744Swnj um->um_ubanum != uban) 7734744Swnj continue; 7744744Swnj printf(" ut%d", ut11); 7754746Ssam um->um_tab.b_state = 0; 7764744Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7774744Swnj if (um->um_ubinfo) { 7784744Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7794744Swnj ubadone(um); 7804744Swnj } 7814744Swnj ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; 7824746Ssam ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR; 7834744Swnj for (tjunit = 0; tjunit < NTJ; tjunit++) { 7844744Swnj if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um || 7854744Swnj ui->ui_alive == 0) 7864744Swnj continue; 7874744Swnj dp = &tjutab[tjunit]; 7884746Ssam dp->b_state = 0; 7894744Swnj dp->b_forw = 0; 7904744Swnj if (um->um_tab.b_actf == NULL) 7914744Swnj um->um_tab.b_actf = dp; 7924744Swnj else 7934744Swnj um->um_tab.b_actl->b_forw = dp; 7944744Swnj um->um_tab.b_actl = dp; 7954744Swnj if (tj_softc[tjunit].sc_openf > 0) 7964744Swnj tj_softc[tjunit].sc_openf = -1; 7974744Swnj } 7984744Swnj utstart(um); 7994744Swnj } 8004744Swnj } 8014744Swnj 8024744Swnj /* 8034744Swnj * Do a stand-alone core dump to tape -- 8044744Swnj * from here down, routines are used only in dump context 8054744Swnj */ 8064744Swnj #define DBSIZE 20 8074744Swnj 8084744Swnj utdump() 8094744Swnj { 8104744Swnj register struct uba_device *ui; 8114744Swnj register struct uba_regs *up; 8124746Ssam register struct utdevice *addr; 8134744Swnj int blk, num = maxfree; 8144744Swnj int start = 0; 8154744Swnj 8164744Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8174744Swnj if (tjdinfo[0] == 0) 8184744Swnj return (ENXIO); 8194744Swnj ui = phys(tjdinfo[0], struct uba_device *); 8204744Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8214941Swnj ubainit(up); 8224744Swnj DELAY(1000000); 8234941Swnj addr = (struct utdevice *)ui->ui_physaddr; 8244746Ssam utwait(addr); 8254746Ssam /* 8264746Ssam * Be sure to set the appropriate density here. We use 8274746Ssam * 6250, but maybe it should be done at 1600 to insure the 8284746Ssam * tape can be read by most any other tape drive available. 8294746Ssam */ 8304746Ssam addr->uttc = UT_GCR|PDP11FMT; /* implicit slave 0 or-ed in */ 8314746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 8324744Swnj while (num > 0) { 8334744Swnj blk = num > DBSIZE ? DBSIZE : num; 8344746Ssam utdwrite(start, blk, addr, up); 8354746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8364746Ssam return(EIO); 8374744Swnj start += blk; 8384744Swnj num -= blk; 8394744Swnj } 8404746Ssam uteof(addr); 8414746Ssam uteof(addr); 8424746Ssam utwait(addr); 8434746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8444744Swnj return(EIO); 8454746Ssam addr->utcs1 = UT_REW|UT_GO; 8464744Swnj return (0); 8474744Swnj } 8484744Swnj 8494746Ssam utdwrite(dbuf, num, addr, up) 8504744Swnj register dbuf, num; 8514746Ssam register struct utdevice *addr; 8524744Swnj struct uba_regs *up; 8534744Swnj { 8544744Swnj register struct pte *io; 8554744Swnj register int npf; 8564744Swnj 8574746Ssam utwait(addr); 8584744Swnj io = up->uba_map; 8594744Swnj npf = num + 1; 8604744Swnj while (--npf != 0) 8614744Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 8624744Swnj *(int *)io = 0; 8634746Ssam addr->utwc = -((num*NBPG)>>1); 8644746Ssam addr->utfc = -(num*NBPG); 8654746Ssam addr->utba = 0; 8664746Ssam addr->utcs1 = UT_WCOM|UT_GO; 8674744Swnj } 8684744Swnj 8694746Ssam utwait(addr) 8704746Ssam struct utdevice *addr; 8714744Swnj { 8724744Swnj register s; 8734744Swnj 8744744Swnj do 8754746Ssam s = addr->utds; 8764744Swnj while ((s&UTDS_DRY) == 0); 8774744Swnj } 8784744Swnj 8794746Ssam uteof(addr) 8804746Ssam struct utdevice *addr; 8814744Swnj { 8824744Swnj 8834746Ssam utwait(addr); 8844746Ssam addr->utcs1 = UT_WEOF|UT_GO; 8854744Swnj } 8864744Swnj #endif 887