1*11176Ssam /* ut.c 4.26 83/02/20 */ 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 154744Swnj #include "../h/param.h" 164744Swnj #include "../h/systm.h" 174744Swnj #include "../h/buf.h" 184744Swnj #include "../h/conf.h" 194744Swnj #include "../h/dir.h" 204744Swnj #include "../h/file.h" 214744Swnj #include "../h/user.h" 224744Swnj #include "../h/map.h" 237634Ssam #include "../h/ioctl.h" 244744Swnj #include "../h/mtio.h" 254744Swnj #include "../h/cmap.h" 267736Sroot #include "../h/uio.h" 279565Ssam #include "../h/kernel.h" 284744Swnj 298483Sroot #include "../vax/cpu.h" 308483Sroot #include "../vaxuba/ubareg.h" 318483Sroot #include "../vaxuba/ubavar.h" 328483Sroot #include "../vaxuba/utreg.h" 334744Swnj 344744Swnj struct buf rutbuf[NUT]; /* bufs for raw i/o */ 354744Swnj struct buf cutbuf[NUT]; /* bufs for control operations */ 364744Swnj struct buf tjutab[NTJ]; /* bufs for slave queue headers */ 374744Swnj 384744Swnj struct uba_ctlr *utminfo[NUT]; 394744Swnj struct uba_device *tjdinfo[NTJ]; 404833Swnj int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer(); 414744Swnj u_short utstd[] = { 0772440, 0 }; 424744Swnj struct uba_driver utdriver = 434744Swnj { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 }; 444744Swnj 45*11176Ssam #define MASKREG(reg) ((reg)&0xffff) 46*11176Ssam 474744Swnj /* bits in minor device */ 484744Swnj #define TJUNIT(dev) (minor(dev)&03) 494744Swnj #define T_NOREWIND 04 504744Swnj #define T_1600BPI 010 514744Swnj #define T_6250BPI 020 524744Swnj short utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI }; 534744Swnj 544744Swnj /* slave to controller mapping table */ 554744Swnj short tjtout[NTJ]; 564744Swnj #define UTUNIT(dev) (tjtout[TJUNIT(dev)]) 574744Swnj 584744Swnj #define INF (daddr_t)1000000L /* a block number that wont exist */ 594744Swnj 604744Swnj struct tj_softc { 614744Swnj char sc_openf; /* exclusive open */ 624744Swnj char sc_lastiow; /* last I/O operation was a write */ 634744Swnj daddr_t sc_blkno; /* next block to transfer */ 644744Swnj daddr_t sc_nxrec; /* next record on tape */ 654744Swnj u_short sc_erreg; /* image of uter */ 664744Swnj u_short sc_dsreg; /* image of utds */ 674746Ssam u_short sc_resid; /* residual from transfer */ 684744Swnj u_short sc_dens; /* sticky selected density */ 694833Swnj daddr_t sc_timo; /* time until timeout expires */ 704833Swnj short sc_tact; /* timeout is active flag */ 714744Swnj } tj_softc[NTJ]; 724744Swnj 734744Swnj /* 744744Swnj * Internal per/slave states found in sc_state 754744Swnj */ 764744Swnj #define SSEEK 1 /* seeking */ 774744Swnj #define SIO 2 /* doing sequential I/O */ 784744Swnj #define SCOM 3 /* sending a control command */ 794744Swnj #define SREW 4 /* doing a rewind op */ 804746Ssam #define SERASE 5 /* erase inter-record gap */ 814746Ssam #define SERASED 6 /* erased inter-record gap */ 824744Swnj 834941Swnj /*ARGSUSED*/ 844744Swnj utprobe(reg) 854744Swnj caddr_t reg; 864744Swnj { 874744Swnj register int br, cvec; 884744Swnj #ifdef lint 894744Swnj br=0; cvec=br; br=cvec; 904941Swnj utintr(0); 914744Swnj #endif 924746Ssam /* 936954Sroot * The SI documentation says you must set the RDY bit 946954Sroot * (even though it's read-only) to force an interrupt. 954746Ssam */ 966954Sroot ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY; 974744Swnj DELAY(10000); 987405Skre return (sizeof (struct utdevice)); 994744Swnj } 1004744Swnj 1014744Swnj /*ARGSUSED*/ 1024744Swnj utslave(ui, reg) 1034744Swnj struct uba_device *ui; 1044744Swnj caddr_t reg; 1054744Swnj { 1064744Swnj /* 1074744Swnj * A real TU45 would support the slave present bit 1084744Swnj * int the drive type register, but this thing doesn't, 1094744Swnj * so there's no way to determine if a slave is present or not. 1104744Swnj */ 1114744Swnj return(1); 1124744Swnj } 1134744Swnj 1144744Swnj utattach(ui) 1154744Swnj struct uba_device *ui; 1164744Swnj { 1174744Swnj tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; 1184744Swnj } 1194744Swnj 1204744Swnj /* 1214744Swnj * Open the device with exclusive access. 1224744Swnj */ 1234744Swnj utopen(dev, flag) 1244744Swnj dev_t dev; 1254744Swnj int flag; 1264744Swnj { 1274744Swnj register int tjunit = TJUNIT(dev); 1284744Swnj register struct uba_device *ui; 1294744Swnj register struct tj_softc *sc; 1304744Swnj int olddens, dens; 1315439Sroot register int s; 1324744Swnj 1334744Swnj if (tjunit >= NTJ || (sc = &tj_softc[tjunit])->sc_openf || 1348577Sroot (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 1358577Sroot return (ENXIO); 1364744Swnj olddens = sc->sc_dens; 1378577Sroot dens = sc->sc_dens = 1388577Sroot utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]| 1398577Sroot PDP11FMT|(ui->ui_slave&07); 1404744Swnj get: 1414744Swnj utcommand(dev, UT_SENSE, 1); 1424744Swnj if (sc->sc_dsreg&UTDS_PIP) { 1439174Ssam sleep((caddr_t)&lbolt, PZERO+1); 1444744Swnj goto get; 1454744Swnj } 1464744Swnj sc->sc_dens = olddens; 1474744Swnj if ((sc->sc_dsreg&UTDS_MOL) == 0) { 1484744Swnj uprintf("tj%d: not online\n", tjunit); 1498577Sroot return (EIO); 1504744Swnj } 1514744Swnj if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) { 1524744Swnj uprintf("tj%d: no write ring\n", tjunit); 1538577Sroot return (EIO); 1544744Swnj } 1554744Swnj if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) && 1564744Swnj dens != sc->sc_dens) { 1574744Swnj uprintf("tj%d: can't change density in mid-tape\n", tjunit); 1588577Sroot return (EIO); 1594744Swnj } 1604744Swnj sc->sc_openf = 1; 1614744Swnj sc->sc_blkno = (daddr_t)0; 1624744Swnj sc->sc_nxrec = INF; 1634744Swnj sc->sc_lastiow = 0; 1644744Swnj sc->sc_dens = dens; 1654746Ssam /* 1664746Ssam * For 6250 bpi take exclusive use of the UNIBUS. 1674746Ssam */ 1684746Ssam ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI; 1695439Sroot s = spl6(); 1704833Swnj if (sc->sc_tact == 0) { 1714833Swnj sc->sc_timo = INF; 1724833Swnj sc->sc_tact = 1; 1734833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 1744833Swnj } 1755439Sroot splx(s); 1768577Sroot return (0); 1774744Swnj } 1784744Swnj 1794744Swnj utclose(dev, flag) 1804744Swnj register dev_t dev; 1814744Swnj register flag; 1824744Swnj { 1834744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 1844744Swnj 1854744Swnj if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) { 1864744Swnj utcommand(dev, UT_WEOF, 1); 1874744Swnj utcommand(dev, UT_WEOF, 1); 1884744Swnj utcommand(dev, UT_SREV, 1); 1894744Swnj } 1904744Swnj if ((minor(dev)&T_NOREWIND) == 0) 1914744Swnj utcommand(dev, UT_REW, 0); 1924744Swnj sc->sc_openf = 0; 1934744Swnj } 1944744Swnj 1954744Swnj utcommand(dev, com, count) 1964744Swnj dev_t dev; 1974744Swnj int com, count; 1984744Swnj { 1994744Swnj register struct buf *bp; 2005439Sroot register int s; 2014744Swnj 2024744Swnj bp = &cutbuf[UTUNIT(dev)]; 2035439Sroot s = spl5(); 2044744Swnj while (bp->b_flags&B_BUSY) { 2054744Swnj if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2064744Swnj break; 2074744Swnj bp->b_flags |= B_WANTED; 2084744Swnj sleep((caddr_t)bp, PRIBIO); 2094744Swnj } 2104744Swnj bp->b_flags = B_BUSY|B_READ; 2115439Sroot splx(s); 2124744Swnj bp->b_dev = dev; 2134744Swnj bp->b_command = com; 2144744Swnj bp->b_repcnt = count; 2154744Swnj bp->b_blkno = 0; 2164744Swnj utstrategy(bp); 2174744Swnj if (count == 0) 2184744Swnj return; 2194744Swnj iowait(bp); 2204744Swnj if (bp->b_flags&B_WANTED) 2214744Swnj wakeup((caddr_t)bp); 2224744Swnj bp->b_flags &= B_ERROR; 2234744Swnj } 2244744Swnj 2254744Swnj /* 2264744Swnj * Queue a tape operation. 2274744Swnj */ 2284744Swnj utstrategy(bp) 2294744Swnj register struct buf *bp; 2304744Swnj { 2314744Swnj int tjunit = TJUNIT(bp->b_dev); 2324744Swnj register struct uba_ctlr *um; 2334744Swnj register struct buf *dp; 2344744Swnj 2354744Swnj /* 2364744Swnj * Put transfer at end of unit queue 2374744Swnj */ 2384744Swnj dp = &tjutab[tjunit]; 2394744Swnj bp->av_forw = NULL; 2404744Swnj (void) spl5(); 2414744Swnj if (dp->b_actf == NULL) { 2424744Swnj dp->b_actf = bp; 2434744Swnj /* 2444744Swnj * Transport not active, so... 2454744Swnj * put at end of controller queue 2464744Swnj */ 2474744Swnj dp->b_forw = NULL; 2484744Swnj um = tjdinfo[tjunit]->ui_mi; 2494744Swnj if (um->um_tab.b_actf == NULL) 2504744Swnj um->um_tab.b_actf = dp; 2514744Swnj else 2524744Swnj um->um_tab.b_actl->b_forw = dp; 2534744Swnj um->um_tab.b_actl = dp; 2544744Swnj } else 2554744Swnj dp->b_actl->av_forw = bp; 2564744Swnj dp->b_actl = bp; 2574744Swnj /* 2584744Swnj * If the controller is not busy, set it going. 2594744Swnj */ 2604746Ssam if (um->um_tab.b_state == 0) 2614744Swnj utstart(um); 2624744Swnj (void) spl0(); 2634744Swnj } 2644744Swnj 2654744Swnj utstart(um) 2664744Swnj register struct uba_ctlr *um; 2674744Swnj { 2684746Ssam register struct utdevice *addr; 2694744Swnj register struct buf *bp, *dp; 2704744Swnj register struct tj_softc *sc; 2714744Swnj struct uba_device *ui; 2724744Swnj int tjunit; 2734744Swnj daddr_t blkno; 2744744Swnj 2754744Swnj loop: 2764744Swnj /* 2774744Swnj * Scan controller queue looking for units with 2784744Swnj * transaction queues to dispatch 2794744Swnj */ 2804744Swnj if ((dp = um->um_tab.b_actf) == NULL) 2814744Swnj return; 2824744Swnj if ((bp = dp->b_actf) == NULL) { 2834744Swnj um->um_tab.b_actf = dp->b_forw; 2844744Swnj goto loop; 2854744Swnj } 2864746Ssam addr = (struct utdevice *)um->um_addr; 2874744Swnj tjunit = TJUNIT(bp->b_dev); 2884744Swnj ui = tjdinfo[tjunit]; 2894744Swnj sc = &tj_softc[tjunit]; 2904744Swnj /* note slave select, density, and format were merged on open */ 2914746Ssam addr->uttc = sc->sc_dens; 2924746Ssam sc->sc_dsreg = addr->utds; 2934746Ssam sc->sc_erreg = addr->uter; 294*11176Ssam sc->sc_resid = MASKREG(addr->utfc); 2954744Swnj /* 2964744Swnj * Default is that last command was NOT a write command; 2974744Swnj * if we do a write command we will notice this in utintr(). 2984744Swnj */ 2994744Swnj sc->sc_lastiow = 0; 3004746Ssam if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) { 3014744Swnj /* 3024744Swnj * Have had a hard error on a non-raw tape 3034744Swnj * or the tape unit is now unavailable 3044744Swnj * (e.g. taken off line). 3054744Swnj */ 3064744Swnj bp->b_flags |= B_ERROR; 3074744Swnj goto next; 3084744Swnj } 3094744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 3104744Swnj /* 3114744Swnj * Execute a control operation with the specified 3124744Swnj * count. 3134744Swnj */ 3144744Swnj if (bp->b_command == UT_SENSE) 3154744Swnj goto next; 316*11176Ssam if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) { 317*11176Ssam bp->b_resid = bp->b_bcount; 318*11176Ssam goto next; 319*11176Ssam } 3204744Swnj /* 3214744Swnj * Set next state; handle timeouts 3224744Swnj */ 3234833Swnj if (bp->b_command == UT_REW) { 3244746Ssam um->um_tab.b_state = SREW; 3254833Swnj sc->sc_timo = 5*60; 3264833Swnj } else { 3274746Ssam um->um_tab.b_state = SCOM; 3284833Swnj sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60); 3294833Swnj } 3304744Swnj /* NOTE: this depends on the ut command values */ 3314744Swnj if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) 3324746Ssam addr->utfc = -bp->b_repcnt; 3334744Swnj goto dobpcmd; 3344744Swnj } 3354744Swnj /* 3364744Swnj * The following checks boundary conditions for operations 3374744Swnj * on non-raw tapes. On raw tapes the initialization of 3384744Swnj * sc->sc_nxrec by utphys causes them to be skipped normally 3394744Swnj * (except in the case of retries). 3404744Swnj */ 3417382Ssam if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 3424744Swnj /* can't read past end of file */ 3434744Swnj bp->b_flags |= B_ERROR; 3444744Swnj bp->b_error = ENXIO; 3454744Swnj goto next; 3464744Swnj } 3477382Ssam if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) { 3484744Swnj /* read at eof returns 0 count */ 3494744Swnj bp->b_resid = bp->b_bcount; 3504744Swnj clrbuf(bp); 3514744Swnj goto next; 3524744Swnj } 3534744Swnj if ((bp->b_flags&B_READ) == 0) 3547382Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno)+1; 3554744Swnj /* 3564744Swnj * If the tape is correctly positioned, set up all the 3574744Swnj * registers but the csr, and give control over to the 3584744Swnj * UNIBUS adaptor routines, to wait for resources to 3594744Swnj * start I/O. 3604744Swnj */ 3617382Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3624746Ssam addr->utwc = -(((bp->b_bcount)+1)>>1); 3634746Ssam addr->utfc = -bp->b_bcount; 3644744Swnj if ((bp->b_flags&B_READ) == 0) { 3654744Swnj /* 3664744Swnj * On write error retries erase the 3674746Ssam * inter-record gap before rewriting. 3684744Swnj */ 3694746Ssam if (um->um_tab.b_errcnt) { 3704746Ssam if (um->um_tab.b_state != SERASED) { 3714759Swnj um->um_tab.b_state = SERASE; 3724833Swnj sc->sc_timo = 60; 3734746Ssam addr->utcs1 = UT_ERASE|UT_IE|UT_GO; 3744746Ssam return; 3754746Ssam } 3764746Ssam } 377*11176Ssam if (addr->utds & UTDS_EOT) { 378*11176Ssam bp->b_resid = bp->b_bcount; 379*11176Ssam um->um_tab.b_state = 0; 380*11176Ssam goto next; 381*11176Ssam } 3824746Ssam um->um_cmd = UT_WCOM; 3834744Swnj } else 3844744Swnj um->um_cmd = UT_RCOM; 3854833Swnj sc->sc_timo = 60; 3864746Ssam um->um_tab.b_state = SIO; 3874744Swnj (void) ubago(ui); 3884744Swnj return; 3894744Swnj } 3904744Swnj /* 3914744Swnj * Tape positioned incorrectly; seek forwards or 3924744Swnj * backwards to the correct spot. This happens for 3934744Swnj * raw tapes only on error retries. 3944744Swnj */ 3954746Ssam um->um_tab.b_state = SSEEK; 3967382Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 3977382Ssam addr->utfc = blkno - bdbtofsb(bp->b_blkno); 3984744Swnj bp->b_command = UT_SFORW; 3994744Swnj } else { 4007382Ssam addr->utfc = bdbtofsb(bp->b_blkno) - blkno; 4014744Swnj bp->b_command = UT_SREV; 4024744Swnj } 4034833Swnj sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60); 4044744Swnj 4054744Swnj dobpcmd: 4064744Swnj /* 4074744Swnj * Perform the command setup in bp. 4084744Swnj */ 4094746Ssam addr->utcs1 = bp->b_command|UT_IE|UT_GO; 4104744Swnj return; 4114744Swnj next: 4124744Swnj /* 4134744Swnj * Advance to the next command in the slave queue, 4144744Swnj * posting notice and releasing resources as needed. 4154744Swnj */ 4164744Swnj if (um->um_ubinfo) 4174744Swnj ubadone(um); 4184744Swnj um->um_tab.b_errcnt = 0; 4194744Swnj dp->b_actf = bp->av_forw; 4204744Swnj iodone(bp); 4214744Swnj goto loop; 4224744Swnj } 4234744Swnj 4244744Swnj /* 4254744Swnj * Start operation on controller -- 4264744Swnj * UNIBUS resources have been allocated. 4274744Swnj */ 4284744Swnj utdgo(um) 4294744Swnj register struct uba_ctlr *um; 4304744Swnj { 4314744Swnj register struct utdevice *addr = (struct utdevice *)um->um_addr; 4324744Swnj 4334744Swnj addr->utba = (u_short) um->um_ubinfo; 434*11176Ssam addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO; 4354744Swnj } 4364744Swnj 4374744Swnj /* 4384744Swnj * Ut interrupt handler 4394744Swnj */ 4404744Swnj /*ARGSUSED*/ 4414744Swnj utintr(ut11) 4424744Swnj int ut11; 4434744Swnj { 4444744Swnj struct buf *dp; 4454744Swnj register struct buf *bp; 4464744Swnj register struct uba_ctlr *um = utminfo[ut11]; 4474744Swnj register struct utdevice *addr; 4484744Swnj register struct tj_softc *sc; 4494746Ssam u_short tjunit, cs2, cs1; 4504744Swnj register state; 4514744Swnj 4524744Swnj if ((dp = um->um_tab.b_actf) == NULL) 4534744Swnj return; 4544744Swnj bp = dp->b_actf; 4554744Swnj tjunit = TJUNIT(bp->b_dev); 4564744Swnj addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr; 4574744Swnj sc = &tj_softc[tjunit]; 4584744Swnj /* 4594744Swnj * Record status... 4604744Swnj */ 4614877Ssam sc->sc_timo = INF; 4624744Swnj sc->sc_dsreg = addr->utds; 4634744Swnj sc->sc_erreg = addr->uter; 464*11176Ssam sc->sc_resid = MASKREG(addr->utfc); 4654746Ssam if ((bp->b_flags&B_READ) == 0) 4664744Swnj sc->sc_lastiow = 1; 4674746Ssam state = um->um_tab.b_state; 4684746Ssam um->um_tab.b_state = 0; 4694744Swnj /* 4704744Swnj * Check for errors... 4714744Swnj */ 4724744Swnj if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) { 4734744Swnj /* 4744759Swnj * To clear the ERR bit, we must issue a drive clear 4754759Swnj * command, and to clear the TRE bit we must set the 4764759Swnj * controller clear bit. 4774759Swnj */ 4784759Swnj cs2 = addr->utcs2; 4794759Swnj if ((cs1 = addr->utcs1)&UT_TRE) 4804759Swnj addr->utcs2 |= UTCS2_CLR; 4814759Swnj /* is this dangerous ?? */ 4824759Swnj while ((addr->utcs1&UT_RDY) == 0) 4834759Swnj ; 4844759Swnj addr->utcs1 = UT_CLEAR|UT_GO; 4854759Swnj /* 486*11176Ssam * If we were reading at 1600 or 6250 bpi and the error 487*11176Ssam * was corrected, then don't consider this an error. 4884744Swnj */ 489*11176Ssam if (sc->sc_errreg & UTER_COR && (bp->b_flags & B_READ) && 490*11176Ssam (addr->uttc & UTTC_DEN) != UT_NRZI) { 491*11176Ssam printf( 492*11176Ssam "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 493*11176Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 494*11176Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 495*11176Ssam sc->sc_erreg &= ~UTER_COR; 4964744Swnj } 4974744Swnj /* 4984744Swnj * If we were reading from a raw tape and the only error 4994744Swnj * was that the record was too long, then we don't consider 5004744Swnj * this an error. 5014744Swnj */ 5024744Swnj if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5034744Swnj (sc->sc_erreg&UTER_FCE)) 504*11176Ssam sc->sc_erreg &= ~UTER_FCE; 505*11176Ssam if (sc->sc_errreg == 0) 5064744Swnj goto ignoreerr; 5074744Swnj /* 508*11176Ssam * Fix up errors which occur due to backspacing 509*11176Ssam * "over" the front of the tape. 5104746Ssam */ 511*11176Ssam if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV && 5124746Ssam ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0)) 5134746Ssam goto opdone; 5144746Ssam /* 5154744Swnj * Retry soft errors up to 8 times 5164744Swnj */ 5174744Swnj if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { 5184744Swnj if (++um->um_tab.b_errcnt < 7) { 5194744Swnj sc->sc_blkno++; 5204744Swnj ubadone(um); 5214744Swnj goto opcont; 5224744Swnj } 523*11176Ssam } 5244744Swnj /* 525*11176Ssam * Hard or non-I/O errors on non-raw tape 526*11176Ssam * cause it to close. 527*11176Ssam */ 528*11176Ssam if (sc->sc_openf > 0 && bp != &rutbuf[UTUNIT(bp->b_dev)]) 529*11176Ssam sc->sc_openf = -1; 530*11176Ssam /* 5314744Swnj * Couldn't recover error. 5324744Swnj */ 5334746Ssam printf("ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 5344746Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 5354746Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 5364744Swnj bp->b_flags |= B_ERROR; 5374744Swnj goto opdone; 5384744Swnj } 539*11176Ssam 5404744Swnj ignoreerr: 5414744Swnj /* 542*11176Ssam * If we hit a tape mark update our position. 543*11176Ssam */ 544*11176Ssam if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) { 545*11176Ssam /* 546*11176Ssam * Set blkno and nxrec 547*11176Ssam */ 548*11176Ssam if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 549*11176Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 550*11176Ssam sc->sc_nxrec = 551*11176Ssam bdbtofsb(bp->b_blkno) - addr->utfc; 552*11176Ssam sc->sc_blkno = sc->sc_nxrec; 553*11176Ssam } else { 554*11176Ssam sc->sc_blkno = 555*11176Ssam bdbtofsb(bp->b_blkno) + addr->utfc; 556*11176Ssam sc->sc_nxrec = sc->sc_blkno-1; 557*11176Ssam } 558*11176Ssam } else 559*11176Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 560*11176Ssam /* 561*11176Ssam * Note: if we get a tape mark on a read, the 562*11176Ssam * frame count register will be zero, so b_resid 563*11176Ssam * will be calculated correctly below. 564*11176Ssam */ 565*11176Ssam goto opdone; 566*11176Ssam } 567*11176Ssam /* 5684744Swnj * Advance tape control FSM. 5694744Swnj */ 5704744Swnj switch (state) { 5714744Swnj 5724744Swnj case SIO: /* read/write increments tape block # */ 5734744Swnj sc->sc_blkno++; 5744746Ssam break; 5754744Swnj 576*11176Ssam case SCOM: /* motion commands update current position */ 5774744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) 5784744Swnj switch (bp->b_command) { 5794744Swnj 5804744Swnj case UT_SFORW: 5814744Swnj sc->sc_blkno -= bp->b_repcnt; 5824744Swnj break; 5834744Swnj 5844744Swnj case UT_SREV: 5854744Swnj sc->sc_blkno += bp->b_repcnt; 5864744Swnj break; 587*11176Ssam 588*11176Ssam case UT_REWOFFL: 589*11176Ssam addr->utcs1 = UT_CLEAR|UT_GO; 590*11176Ssam break; 5914744Swnj } 5924746Ssam break; 5934744Swnj 5944744Swnj case SSEEK: 5957382Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 5964744Swnj goto opcont; 5974744Swnj 5984746Ssam case SERASE: 5994746Ssam /* 6004746Ssam * Completed erase of the inter-record gap due to a 6014746Ssam * write error; now retry the write operation. 6024746Ssam */ 6034746Ssam um->um_tab.b_state = SERASED; 6044746Ssam goto opcont; 6054746Ssam 6064746Ssam case SREW: /* clear attention bit */ 6074746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 6084746Ssam break; 6094746Ssam 6104744Swnj default: 6114746Ssam printf("bad state %d\n", state); 6124744Swnj panic("utintr"); 6134744Swnj } 6144744Swnj 6154744Swnj opdone: 6164744Swnj /* 6174744Swnj * Reset error count and remove 6184744Swnj * from device queue 6194744Swnj */ 6204744Swnj um->um_tab.b_errcnt = 0; 6214746Ssam dp->b_actf = bp->av_forw; 622*11176Ssam /* 623*11176Ssam * For read command, frame count register contains 624*11176Ssam * actual length of tape record. Otherwise, it 625*11176Ssam * holds negative residual count. 626*11176Ssam */ 627*11176Ssam if (state == SIO && um->um_cmd == UT_RCOM) { 628*11176Ssam bp->b_resid = 0; 629*11176Ssam if (bp->b_bcount > MASKREG(addr->utfc)) 630*11176Ssam bp->b_resid = bp->b_bcount - MASKREG(addr->utfc); 631*11176Ssam } else 632*11176Ssam bp->b_resid = MASKREG(-addr->utfc); 6334744Swnj ubadone(um); 6344744Swnj iodone(bp); 6354744Swnj /* 6364744Swnj * Circulate slave to end of controller queue 6374744Swnj * to give other slaves a chance 6384744Swnj */ 6394744Swnj um->um_tab.b_actf = dp->b_forw; 6404744Swnj if (dp->b_actf) { 6414744Swnj dp->b_forw = NULL; 6424744Swnj if (um->um_tab.b_actf == NULL) 6434744Swnj um->um_tab.b_actf = dp; 6444744Swnj else 6454744Swnj um->um_tab.b_actl->b_forw = dp; 6464744Swnj um->um_tab.b_actl = dp; 6474744Swnj } 6484744Swnj if (um->um_tab.b_actf == 0) 6494744Swnj return; 6504744Swnj opcont: 6514744Swnj utstart(um); 6524744Swnj } 6534744Swnj 6544744Swnj /* 6554833Swnj * Watchdog timer routine. 6564833Swnj */ 6574833Swnj uttimer(dev) 6584833Swnj int dev; 6594833Swnj { 6604833Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 6614846Sroot register short x; 6624833Swnj 6634833Swnj if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) { 6644859Ssam printf("tj%d: lost interrupt\n", TJUNIT(dev)); 6654833Swnj sc->sc_timo = INF; 6664846Sroot x = spl5(); 6674833Swnj utintr(UTUNIT(dev)); 6684846Sroot (void) splx(x); 6694833Swnj } 6704833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 6714833Swnj } 6724833Swnj 6734833Swnj /* 6744744Swnj * Raw interface for a read 6754744Swnj */ 6767736Sroot utread(dev, uio) 6774744Swnj dev_t dev; 6787736Sroot struct uio *uio; 6794744Swnj { 6808167Sroot int errno; 6817736Sroot 6828167Sroot errno = utphys(dev, uio); 6838167Sroot if (errno) 6848167Sroot return (errno); 6858167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys, uio)); 6864744Swnj } 6874744Swnj 6884744Swnj /* 6894744Swnj * Raw interface for a write 6904744Swnj */ 6917847Sroot utwrite(dev, uio) 6927736Sroot dev_t dev; 6937847Sroot struct uio *uio; 6944744Swnj { 6958167Sroot int errno; 6968167Sroot 6978167Sroot errno = utphys(dev, uio); 6988167Sroot if (errno) 6998167Sroot return (errno); 7008167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys, uio)); 7014744Swnj } 7024744Swnj 7034744Swnj /* 7044744Swnj * Check for valid device number dev and update our notion 7054744Swnj * of where we are on the tape 7064744Swnj */ 7077736Sroot utphys(dev, uio) 7084744Swnj dev_t dev; 7097736Sroot struct uio *uio; 7104744Swnj { 7114744Swnj register int tjunit = TJUNIT(dev); 7124744Swnj register struct tj_softc *sc; 7134744Swnj register struct uba_device *ui; 7144744Swnj 7157847Sroot if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 7167847Sroot return (ENXIO); 7174744Swnj sc = &tj_softc[tjunit]; 7187847Sroot sc->sc_blkno = bdbtofsb(uio->uio_offset>>9); 7194746Ssam sc->sc_nxrec = sc->sc_blkno+1; 7207847Sroot return (0); 7214744Swnj } 7224744Swnj 7234744Swnj /*ARGSUSED*/ 7247634Ssam utioctl(dev, cmd, data, flag) 7254744Swnj dev_t dev; 7267634Ssam caddr_t data; 7274744Swnj { 7284744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 7294744Swnj register struct buf *bp = &cutbuf[UTUNIT(dev)]; 7304744Swnj register callcount; 7314744Swnj int fcount; 7327634Ssam struct mtop *mtop; 7337634Ssam struct mtget *mtget; 7344744Swnj /* we depend of the values and order of the MT codes here */ 7354744Swnj static utops[] = 7364744Swnj {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE}; 7374744Swnj 7384744Swnj switch (cmd) { 7394744Swnj 7404744Swnj case MTIOCTOP: 7417634Ssam mtop = (struct mtop *)data; 7427634Ssam switch(mtop->mt_op) { 7434744Swnj 7444744Swnj case MTWEOF: 7457634Ssam callcount = mtop->mt_count; 7464744Swnj fcount = 1; 7474744Swnj break; 7484744Swnj 7494744Swnj case MTFSF: case MTBSF: 7504744Swnj case MTFSR: case MTBSR: 7514744Swnj callcount = 1; 7527634Ssam fcount = mtop->mt_count; 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); 7674746Ssam /* note this depends on the mtop values */ 768*11176Ssam if ((mtop->mt_op >= MTFSF && mtop->mt_op <= MTBSR) && 7699174Ssam bp->b_resid) 7708577Sroot return (EIO); 7714744Swnj if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT)) 7724744Swnj break; 7734744Swnj } 7748650Sroot return (geterror(bp)); 7754744Swnj 7764744Swnj case MTIOCGET: 7777634Ssam mtget = (struct mtget *)data; 7787634Ssam mtget->mt_dsreg = sc->sc_dsreg; 7797634Ssam mtget->mt_erreg = sc->sc_erreg; 7807634Ssam mtget->mt_resid = sc->sc_resid; 7817634Ssam mtget->mt_type = MT_ISUT; 7828577Sroot break; 7834744Swnj 7844744Swnj default: 7858577Sroot return (ENXIO); 7864744Swnj } 7878577Sroot return (0); 7884744Swnj } 7894744Swnj 7904744Swnj utreset(uban) 7914744Swnj int uban; 7924744Swnj { 7934744Swnj register struct uba_ctlr *um; 7944744Swnj register ut11, tjunit; 7954744Swnj register struct uba_device *ui; 7964744Swnj register struct buf *dp; 7974744Swnj 7984744Swnj for (ut11 = 0; ut11 < NUT; ut11++) { 7994744Swnj if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || 8004744Swnj um->um_ubanum != uban) 8014744Swnj continue; 8024744Swnj printf(" ut%d", ut11); 8034746Ssam um->um_tab.b_state = 0; 8044744Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8054744Swnj if (um->um_ubinfo) { 8064744Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 8079358Ssam um->um_ubinfo = 0; 8084744Swnj } 8094744Swnj ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; 8104746Ssam ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR; 8114744Swnj for (tjunit = 0; tjunit < NTJ; tjunit++) { 8124744Swnj if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um || 8134744Swnj ui->ui_alive == 0) 8144744Swnj continue; 8154744Swnj dp = &tjutab[tjunit]; 8164746Ssam dp->b_state = 0; 8174744Swnj dp->b_forw = 0; 8184744Swnj if (um->um_tab.b_actf == NULL) 8194744Swnj um->um_tab.b_actf = dp; 8204744Swnj else 8214744Swnj um->um_tab.b_actl->b_forw = dp; 8224744Swnj um->um_tab.b_actl = dp; 8234744Swnj if (tj_softc[tjunit].sc_openf > 0) 8244744Swnj tj_softc[tjunit].sc_openf = -1; 8254744Swnj } 8264744Swnj utstart(um); 8274744Swnj } 8284744Swnj } 8294744Swnj 8304744Swnj /* 8314744Swnj * Do a stand-alone core dump to tape -- 8324744Swnj * from here down, routines are used only in dump context 8334744Swnj */ 8344744Swnj #define DBSIZE 20 8354744Swnj 8364744Swnj utdump() 8374744Swnj { 8384744Swnj register struct uba_device *ui; 8394744Swnj register struct uba_regs *up; 8404746Ssam register struct utdevice *addr; 8414744Swnj int blk, num = maxfree; 8424744Swnj int start = 0; 8434744Swnj 8444744Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8454744Swnj if (tjdinfo[0] == 0) 8464744Swnj return (ENXIO); 8474744Swnj ui = phys(tjdinfo[0], struct uba_device *); 8484744Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8494941Swnj ubainit(up); 8504744Swnj DELAY(1000000); 8514941Swnj addr = (struct utdevice *)ui->ui_physaddr; 8524746Ssam utwait(addr); 8534746Ssam /* 8544746Ssam * Be sure to set the appropriate density here. We use 8554746Ssam * 6250, but maybe it should be done at 1600 to insure the 8564746Ssam * tape can be read by most any other tape drive available. 8574746Ssam */ 8584746Ssam addr->uttc = UT_GCR|PDP11FMT; /* implicit slave 0 or-ed in */ 8594746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 8604744Swnj while (num > 0) { 8614744Swnj blk = num > DBSIZE ? DBSIZE : num; 8624746Ssam utdwrite(start, blk, addr, up); 8634746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8644746Ssam return(EIO); 8654744Swnj start += blk; 8664744Swnj num -= blk; 8674744Swnj } 8684746Ssam uteof(addr); 8694746Ssam uteof(addr); 8704746Ssam utwait(addr); 8714746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8724744Swnj return(EIO); 8734746Ssam addr->utcs1 = UT_REW|UT_GO; 8744744Swnj return (0); 8754744Swnj } 8764744Swnj 8774746Ssam utdwrite(dbuf, num, addr, up) 8784744Swnj register dbuf, num; 8794746Ssam register struct utdevice *addr; 8804744Swnj struct uba_regs *up; 8814744Swnj { 8824744Swnj register struct pte *io; 8834744Swnj register int npf; 8844744Swnj 8854746Ssam utwait(addr); 8864744Swnj io = up->uba_map; 8874744Swnj npf = num + 1; 8884744Swnj while (--npf != 0) 8894744Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 8904744Swnj *(int *)io = 0; 8914746Ssam addr->utwc = -((num*NBPG)>>1); 8924746Ssam addr->utfc = -(num*NBPG); 8934746Ssam addr->utba = 0; 8944746Ssam addr->utcs1 = UT_WCOM|UT_GO; 8954744Swnj } 8964744Swnj 8974746Ssam utwait(addr) 8984746Ssam struct utdevice *addr; 8994744Swnj { 9004744Swnj register s; 9014744Swnj 9024744Swnj do 9034746Ssam s = addr->utds; 9044744Swnj while ((s&UTDS_DRY) == 0); 9054744Swnj } 9064744Swnj 9074746Ssam uteof(addr) 9084746Ssam struct utdevice *addr; 9094744Swnj { 9104744Swnj 9114746Ssam utwait(addr); 9124746Ssam addr->utcs1 = UT_WEOF|UT_GO; 9134744Swnj } 9144744Swnj #endif 915