1*23357Smckusick /* 2*23357Smckusick * Copyright (c) 1982 Regents of the University of California. 3*23357Smckusick * All rights reserved. The Berkeley software License Agreement 4*23357Smckusick * specifies the terms and conditions for redistribution. 5*23357Smckusick * 6*23357Smckusick * @(#)ut.c 6.5 (Berkeley) 06/08/85 7*23357Smckusick */ 84744Swnj 94862Sroot #include "tj.h" 104744Swnj #if NUT > 0 114744Swnj /* 124744Swnj * System Industries Model 9700 Tape Drive 134744Swnj * emulates a TU45 on the UNIBUS 144744Swnj * 154744Swnj * TODO: 164744Swnj * check out attention processing 174744Swnj * try reset code and dump code 184744Swnj */ 199783Ssam #include "../machine/pte.h" 209783Ssam 2117083Sbloom #include "param.h" 2217083Sbloom #include "systm.h" 2317083Sbloom #include "buf.h" 2417083Sbloom #include "conf.h" 2517083Sbloom #include "dir.h" 2617083Sbloom #include "file.h" 2717083Sbloom #include "user.h" 2817083Sbloom #include "map.h" 2917083Sbloom #include "ioctl.h" 3017083Sbloom #include "mtio.h" 3117083Sbloom #include "cmap.h" 3217083Sbloom #include "uio.h" 3317083Sbloom #include "kernel.h" 3418323Sralph #include "tty.h" 354744Swnj 368483Sroot #include "../vax/cpu.h" 3717083Sbloom #include "ubareg.h" 3817083Sbloom #include "ubavar.h" 3917083Sbloom #include "utreg.h" 404744Swnj 414744Swnj struct buf rutbuf[NUT]; /* bufs for raw i/o */ 424744Swnj struct buf cutbuf[NUT]; /* bufs for control operations */ 434744Swnj struct buf tjutab[NTJ]; /* bufs for slave queue headers */ 444744Swnj 454744Swnj struct uba_ctlr *utminfo[NUT]; 464744Swnj struct uba_device *tjdinfo[NTJ]; 474833Swnj int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer(); 484744Swnj u_short utstd[] = { 0772440, 0 }; 494744Swnj struct uba_driver utdriver = 504744Swnj { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 }; 514744Swnj 5211176Ssam #define MASKREG(reg) ((reg)&0xffff) 5311176Ssam 544744Swnj /* bits in minor device */ 554744Swnj #define TJUNIT(dev) (minor(dev)&03) 564744Swnj #define T_NOREWIND 04 574744Swnj #define T_1600BPI 010 584744Swnj #define T_6250BPI 020 594744Swnj short utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI }; 604744Swnj 614744Swnj /* slave to controller mapping table */ 624744Swnj short tjtout[NTJ]; 634744Swnj #define UTUNIT(dev) (tjtout[TJUNIT(dev)]) 644744Swnj 654744Swnj #define INF (daddr_t)1000000L /* a block number that wont exist */ 664744Swnj 674744Swnj struct tj_softc { 684744Swnj char sc_openf; /* exclusive open */ 694744Swnj char sc_lastiow; /* last I/O operation was a write */ 704744Swnj daddr_t sc_blkno; /* next block to transfer */ 714744Swnj daddr_t sc_nxrec; /* next record on tape */ 724744Swnj u_short sc_erreg; /* image of uter */ 734744Swnj u_short sc_dsreg; /* image of utds */ 744746Ssam u_short sc_resid; /* residual from transfer */ 754744Swnj u_short sc_dens; /* sticky selected density */ 764833Swnj daddr_t sc_timo; /* time until timeout expires */ 774833Swnj short sc_tact; /* timeout is active flag */ 7818323Sralph struct tty *sc_ttyp; /* record user's tty for errors */ 794744Swnj } tj_softc[NTJ]; 804744Swnj 814744Swnj /* 824744Swnj * Internal per/slave states found in sc_state 834744Swnj */ 844744Swnj #define SSEEK 1 /* seeking */ 854744Swnj #define SIO 2 /* doing sequential I/O */ 864744Swnj #define SCOM 3 /* sending a control command */ 874744Swnj #define SREW 4 /* doing a rewind op */ 884746Ssam #define SERASE 5 /* erase inter-record gap */ 894746Ssam #define SERASED 6 /* erased inter-record gap */ 904744Swnj 914941Swnj /*ARGSUSED*/ 924744Swnj utprobe(reg) 934744Swnj caddr_t reg; 944744Swnj { 954744Swnj register int br, cvec; 964744Swnj #ifdef lint 974744Swnj br=0; cvec=br; br=cvec; 984941Swnj utintr(0); 994744Swnj #endif 1004746Ssam /* 1016954Sroot * The SI documentation says you must set the RDY bit 1026954Sroot * (even though it's read-only) to force an interrupt. 1034746Ssam */ 1046954Sroot ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY; 1054744Swnj DELAY(10000); 1067405Skre return (sizeof (struct utdevice)); 1074744Swnj } 1084744Swnj 1094744Swnj /*ARGSUSED*/ 1104744Swnj utslave(ui, reg) 1114744Swnj struct uba_device *ui; 1124744Swnj caddr_t reg; 1134744Swnj { 1144744Swnj /* 1154744Swnj * A real TU45 would support the slave present bit 1164744Swnj * int the drive type register, but this thing doesn't, 1174744Swnj * so there's no way to determine if a slave is present or not. 1184744Swnj */ 1194744Swnj return(1); 1204744Swnj } 1214744Swnj 1224744Swnj utattach(ui) 1234744Swnj struct uba_device *ui; 1244744Swnj { 1254744Swnj tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; 1264744Swnj } 1274744Swnj 1284744Swnj /* 1294744Swnj * Open the device with exclusive access. 1304744Swnj */ 1314744Swnj utopen(dev, flag) 1324744Swnj dev_t dev; 1334744Swnj int flag; 1344744Swnj { 1354744Swnj register int tjunit = TJUNIT(dev); 1364744Swnj register struct uba_device *ui; 1374744Swnj register struct tj_softc *sc; 1384744Swnj int olddens, dens; 1395439Sroot register int s; 1404744Swnj 1414744Swnj if (tjunit >= NTJ || (sc = &tj_softc[tjunit])->sc_openf || 1428577Sroot (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 1438577Sroot return (ENXIO); 1444744Swnj olddens = sc->sc_dens; 1458577Sroot dens = sc->sc_dens = 1468577Sroot utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]| 1478577Sroot PDP11FMT|(ui->ui_slave&07); 1484744Swnj get: 1494744Swnj utcommand(dev, UT_SENSE, 1); 1504744Swnj if (sc->sc_dsreg&UTDS_PIP) { 1519174Ssam sleep((caddr_t)&lbolt, PZERO+1); 1524744Swnj goto get; 1534744Swnj } 1544744Swnj sc->sc_dens = olddens; 1554744Swnj if ((sc->sc_dsreg&UTDS_MOL) == 0) { 1564744Swnj uprintf("tj%d: not online\n", tjunit); 1578577Sroot return (EIO); 1584744Swnj } 1594744Swnj if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) { 1604744Swnj uprintf("tj%d: no write ring\n", tjunit); 1618577Sroot return (EIO); 1624744Swnj } 1634744Swnj if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) && 1644744Swnj dens != sc->sc_dens) { 1654744Swnj uprintf("tj%d: can't change density in mid-tape\n", tjunit); 1668577Sroot return (EIO); 1674744Swnj } 1684744Swnj sc->sc_openf = 1; 1694744Swnj sc->sc_blkno = (daddr_t)0; 1704744Swnj sc->sc_nxrec = INF; 1714744Swnj sc->sc_lastiow = 0; 1724744Swnj sc->sc_dens = dens; 17318323Sralph sc->sc_ttyp = u.u_ttyp; 1744746Ssam /* 1754746Ssam * For 6250 bpi take exclusive use of the UNIBUS. 1764746Ssam */ 1774746Ssam ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI; 1785439Sroot s = spl6(); 1794833Swnj if (sc->sc_tact == 0) { 1804833Swnj sc->sc_timo = INF; 1814833Swnj sc->sc_tact = 1; 1824833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 1834833Swnj } 1845439Sroot splx(s); 1858577Sroot return (0); 1864744Swnj } 1874744Swnj 1884744Swnj utclose(dev, flag) 1894744Swnj register dev_t dev; 1904744Swnj register flag; 1914744Swnj { 1924744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 1934744Swnj 1944744Swnj if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) { 1954744Swnj utcommand(dev, UT_WEOF, 1); 1964744Swnj utcommand(dev, UT_WEOF, 1); 1974744Swnj utcommand(dev, UT_SREV, 1); 1984744Swnj } 1994744Swnj if ((minor(dev)&T_NOREWIND) == 0) 2004744Swnj utcommand(dev, UT_REW, 0); 2014744Swnj sc->sc_openf = 0; 2024744Swnj } 2034744Swnj 2044744Swnj utcommand(dev, com, count) 2054744Swnj dev_t dev; 2064744Swnj int com, count; 2074744Swnj { 2084744Swnj register struct buf *bp; 2095439Sroot register int s; 2104744Swnj 2114744Swnj bp = &cutbuf[UTUNIT(dev)]; 2125439Sroot s = spl5(); 2134744Swnj while (bp->b_flags&B_BUSY) { 2144744Swnj if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2154744Swnj break; 2164744Swnj bp->b_flags |= B_WANTED; 2174744Swnj sleep((caddr_t)bp, PRIBIO); 2184744Swnj } 2194744Swnj bp->b_flags = B_BUSY|B_READ; 2205439Sroot splx(s); 2214744Swnj bp->b_dev = dev; 2224744Swnj bp->b_command = com; 2234744Swnj bp->b_repcnt = count; 2244744Swnj bp->b_blkno = 0; 2254744Swnj utstrategy(bp); 2264744Swnj if (count == 0) 2274744Swnj return; 2284744Swnj iowait(bp); 2294744Swnj if (bp->b_flags&B_WANTED) 2304744Swnj wakeup((caddr_t)bp); 2314744Swnj bp->b_flags &= B_ERROR; 2324744Swnj } 2334744Swnj 2344744Swnj /* 2354744Swnj * Queue a tape operation. 2364744Swnj */ 2374744Swnj utstrategy(bp) 2384744Swnj register struct buf *bp; 2394744Swnj { 2404744Swnj int tjunit = TJUNIT(bp->b_dev); 2414744Swnj register struct uba_ctlr *um; 2424744Swnj register struct buf *dp; 2434744Swnj 2444744Swnj /* 2454744Swnj * Put transfer at end of unit queue 2464744Swnj */ 2474744Swnj dp = &tjutab[tjunit]; 2484744Swnj bp->av_forw = NULL; 24917433Skarels um = tjdinfo[tjunit]->ui_mi; 2504744Swnj (void) spl5(); 2514744Swnj if (dp->b_actf == NULL) { 2524744Swnj dp->b_actf = bp; 2534744Swnj /* 2544744Swnj * Transport not active, so... 2554744Swnj * put at end of controller queue 2564744Swnj */ 2574744Swnj dp->b_forw = NULL; 2584744Swnj if (um->um_tab.b_actf == NULL) 2594744Swnj um->um_tab.b_actf = dp; 2604744Swnj else 2614744Swnj um->um_tab.b_actl->b_forw = dp; 2624744Swnj um->um_tab.b_actl = dp; 2634744Swnj } else 2644744Swnj dp->b_actl->av_forw = bp; 2654744Swnj dp->b_actl = bp; 2664744Swnj /* 2674744Swnj * If the controller is not busy, set it going. 2684744Swnj */ 2694746Ssam if (um->um_tab.b_state == 0) 2704744Swnj utstart(um); 2714744Swnj (void) spl0(); 2724744Swnj } 2734744Swnj 2744744Swnj utstart(um) 2754744Swnj register struct uba_ctlr *um; 2764744Swnj { 2774746Ssam register struct utdevice *addr; 2784744Swnj register struct buf *bp, *dp; 2794744Swnj register struct tj_softc *sc; 2804744Swnj struct uba_device *ui; 2814744Swnj int tjunit; 2824744Swnj daddr_t blkno; 2834744Swnj 2844744Swnj loop: 2854744Swnj /* 2864744Swnj * Scan controller queue looking for units with 2874744Swnj * transaction queues to dispatch 2884744Swnj */ 2894744Swnj if ((dp = um->um_tab.b_actf) == NULL) 2904744Swnj return; 2914744Swnj if ((bp = dp->b_actf) == NULL) { 2924744Swnj um->um_tab.b_actf = dp->b_forw; 2934744Swnj goto loop; 2944744Swnj } 2954746Ssam addr = (struct utdevice *)um->um_addr; 2964744Swnj tjunit = TJUNIT(bp->b_dev); 2974744Swnj ui = tjdinfo[tjunit]; 2984744Swnj sc = &tj_softc[tjunit]; 2994744Swnj /* note slave select, density, and format were merged on open */ 3004746Ssam addr->uttc = sc->sc_dens; 3014746Ssam sc->sc_dsreg = addr->utds; 3024746Ssam sc->sc_erreg = addr->uter; 30311176Ssam sc->sc_resid = MASKREG(addr->utfc); 3044744Swnj /* 3054744Swnj * Default is that last command was NOT a write command; 3064744Swnj * if we do a write command we will notice this in utintr(). 3074744Swnj */ 3084744Swnj sc->sc_lastiow = 0; 3094746Ssam if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) { 3104744Swnj /* 3114744Swnj * Have had a hard error on a non-raw tape 3124744Swnj * or the tape unit is now unavailable 3134744Swnj * (e.g. taken off line). 3144744Swnj */ 3154744Swnj bp->b_flags |= B_ERROR; 3164744Swnj goto next; 3174744Swnj } 3184744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 3194744Swnj /* 3204744Swnj * Execute a control operation with the specified 3214744Swnj * count. 3224744Swnj */ 3234744Swnj if (bp->b_command == UT_SENSE) 3244744Swnj goto next; 32511176Ssam if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) { 32611176Ssam bp->b_resid = bp->b_bcount; 32711176Ssam goto next; 32811176Ssam } 3294744Swnj /* 3304744Swnj * Set next state; handle timeouts 3314744Swnj */ 3324833Swnj if (bp->b_command == UT_REW) { 3334746Ssam um->um_tab.b_state = SREW; 3344833Swnj sc->sc_timo = 5*60; 3354833Swnj } else { 3364746Ssam um->um_tab.b_state = SCOM; 3374833Swnj sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60); 3384833Swnj } 3394744Swnj /* NOTE: this depends on the ut command values */ 3404744Swnj if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) 3414746Ssam addr->utfc = -bp->b_repcnt; 3424744Swnj goto dobpcmd; 3434744Swnj } 3444744Swnj /* 3454744Swnj * The following checks boundary conditions for operations 3464744Swnj * on non-raw tapes. On raw tapes the initialization of 3474744Swnj * sc->sc_nxrec by utphys causes them to be skipped normally 3484744Swnj * (except in the case of retries). 3494744Swnj */ 3507382Ssam if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 3514744Swnj /* can't read past end of file */ 3524744Swnj bp->b_flags |= B_ERROR; 3534744Swnj bp->b_error = ENXIO; 3544744Swnj goto next; 3554744Swnj } 3567382Ssam if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) { 3574744Swnj /* read at eof returns 0 count */ 3584744Swnj bp->b_resid = bp->b_bcount; 3594744Swnj clrbuf(bp); 3604744Swnj goto next; 3614744Swnj } 3624744Swnj if ((bp->b_flags&B_READ) == 0) 3637382Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno)+1; 3644744Swnj /* 3654744Swnj * If the tape is correctly positioned, set up all the 3664744Swnj * registers but the csr, and give control over to the 3674744Swnj * UNIBUS adaptor routines, to wait for resources to 3684744Swnj * start I/O. 3694744Swnj */ 3707382Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3714746Ssam addr->utwc = -(((bp->b_bcount)+1)>>1); 3724746Ssam addr->utfc = -bp->b_bcount; 3734744Swnj if ((bp->b_flags&B_READ) == 0) { 3744744Swnj /* 3754744Swnj * On write error retries erase the 3764746Ssam * inter-record gap before rewriting. 3774744Swnj */ 3784746Ssam if (um->um_tab.b_errcnt) { 3794746Ssam if (um->um_tab.b_state != SERASED) { 3804759Swnj um->um_tab.b_state = SERASE; 3814833Swnj sc->sc_timo = 60; 3824746Ssam addr->utcs1 = UT_ERASE|UT_IE|UT_GO; 3834746Ssam return; 3844746Ssam } 3854746Ssam } 38611176Ssam if (addr->utds & UTDS_EOT) { 38711176Ssam bp->b_resid = bp->b_bcount; 38811176Ssam um->um_tab.b_state = 0; 38911176Ssam goto next; 39011176Ssam } 3914746Ssam um->um_cmd = UT_WCOM; 3924744Swnj } else 3934744Swnj um->um_cmd = UT_RCOM; 3944833Swnj sc->sc_timo = 60; 3954746Ssam um->um_tab.b_state = SIO; 3964744Swnj (void) ubago(ui); 3974744Swnj return; 3984744Swnj } 3994744Swnj /* 4004744Swnj * Tape positioned incorrectly; seek forwards or 4014744Swnj * backwards to the correct spot. This happens for 4024744Swnj * raw tapes only on error retries. 4034744Swnj */ 4044746Ssam um->um_tab.b_state = SSEEK; 4057382Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 4067382Ssam addr->utfc = blkno - bdbtofsb(bp->b_blkno); 4074744Swnj bp->b_command = UT_SFORW; 4084744Swnj } else { 4097382Ssam addr->utfc = bdbtofsb(bp->b_blkno) - blkno; 4104744Swnj bp->b_command = UT_SREV; 4114744Swnj } 4124833Swnj sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60); 4134744Swnj 4144744Swnj dobpcmd: 4154744Swnj /* 4164744Swnj * Perform the command setup in bp. 4174744Swnj */ 4184746Ssam addr->utcs1 = bp->b_command|UT_IE|UT_GO; 4194744Swnj return; 4204744Swnj next: 4214744Swnj /* 4224744Swnj * Advance to the next command in the slave queue, 4234744Swnj * posting notice and releasing resources as needed. 4244744Swnj */ 4254744Swnj if (um->um_ubinfo) 4264744Swnj ubadone(um); 4274744Swnj um->um_tab.b_errcnt = 0; 4284744Swnj dp->b_actf = bp->av_forw; 4294744Swnj iodone(bp); 4304744Swnj goto loop; 4314744Swnj } 4324744Swnj 4334744Swnj /* 4344744Swnj * Start operation on controller -- 4354744Swnj * UNIBUS resources have been allocated. 4364744Swnj */ 4374744Swnj utdgo(um) 4384744Swnj register struct uba_ctlr *um; 4394744Swnj { 4404744Swnj register struct utdevice *addr = (struct utdevice *)um->um_addr; 4414744Swnj 4424744Swnj addr->utba = (u_short) um->um_ubinfo; 44311176Ssam addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO; 4444744Swnj } 4454744Swnj 4464744Swnj /* 4474744Swnj * Ut interrupt handler 4484744Swnj */ 4494744Swnj /*ARGSUSED*/ 4504744Swnj utintr(ut11) 4514744Swnj int ut11; 4524744Swnj { 4534744Swnj struct buf *dp; 4544744Swnj register struct buf *bp; 4554744Swnj register struct uba_ctlr *um = utminfo[ut11]; 4564744Swnj register struct utdevice *addr; 4574744Swnj register struct tj_softc *sc; 4584746Ssam u_short tjunit, cs2, cs1; 4594744Swnj register state; 4604744Swnj 4614744Swnj if ((dp = um->um_tab.b_actf) == NULL) 4624744Swnj return; 4634744Swnj bp = dp->b_actf; 4644744Swnj tjunit = TJUNIT(bp->b_dev); 4654744Swnj addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr; 4664744Swnj sc = &tj_softc[tjunit]; 4674744Swnj /* 4684744Swnj * Record status... 4694744Swnj */ 4704877Ssam sc->sc_timo = INF; 4714744Swnj sc->sc_dsreg = addr->utds; 4724744Swnj sc->sc_erreg = addr->uter; 47311176Ssam sc->sc_resid = MASKREG(addr->utfc); 4744746Ssam if ((bp->b_flags&B_READ) == 0) 4754744Swnj sc->sc_lastiow = 1; 4764746Ssam state = um->um_tab.b_state; 4774746Ssam um->um_tab.b_state = 0; 4784744Swnj /* 4794744Swnj * Check for errors... 4804744Swnj */ 4814744Swnj if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) { 4824744Swnj /* 4834759Swnj * To clear the ERR bit, we must issue a drive clear 4844759Swnj * command, and to clear the TRE bit we must set the 4854759Swnj * controller clear bit. 4864759Swnj */ 4874759Swnj cs2 = addr->utcs2; 4884759Swnj if ((cs1 = addr->utcs1)&UT_TRE) 4894759Swnj addr->utcs2 |= UTCS2_CLR; 4904759Swnj /* is this dangerous ?? */ 4914759Swnj while ((addr->utcs1&UT_RDY) == 0) 4924759Swnj ; 4934759Swnj addr->utcs1 = UT_CLEAR|UT_GO; 4944759Swnj /* 49511176Ssam * If we were reading at 1600 or 6250 bpi and the error 49611176Ssam * was corrected, then don't consider this an error. 4974744Swnj */ 49811190Ssam if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) && 49911176Ssam (addr->uttc & UTTC_DEN) != UT_NRZI) { 50018323Sralph tprintf(sc->sc_ttyp, 50111176Ssam "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 50211176Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 50311176Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 50411176Ssam sc->sc_erreg &= ~UTER_COR; 5054744Swnj } 5064744Swnj /* 5074744Swnj * If we were reading from a raw tape and the only error 5084744Swnj * was that the record was too long, then we don't consider 5094744Swnj * this an error. 5104744Swnj */ 5114744Swnj if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5124744Swnj (sc->sc_erreg&UTER_FCE)) 51311176Ssam sc->sc_erreg &= ~UTER_FCE; 51411197Slayer if (sc->sc_erreg == 0) 5154744Swnj goto ignoreerr; 5164744Swnj /* 51711176Ssam * Fix up errors which occur due to backspacing 51811176Ssam * "over" the front of the tape. 5194746Ssam */ 52011176Ssam if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV && 5214746Ssam ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0)) 5224746Ssam goto opdone; 5234746Ssam /* 5244744Swnj * Retry soft errors up to 8 times 5254744Swnj */ 5264744Swnj if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { 5274744Swnj if (++um->um_tab.b_errcnt < 7) { 5284744Swnj sc->sc_blkno++; 5294744Swnj ubadone(um); 5304744Swnj goto opcont; 5314744Swnj } 53211176Ssam } 5334744Swnj /* 53411176Ssam * Hard or non-I/O errors on non-raw tape 53511176Ssam * cause it to close. 53611176Ssam */ 53711176Ssam if (sc->sc_openf > 0 && bp != &rutbuf[UTUNIT(bp->b_dev)]) 53811176Ssam sc->sc_openf = -1; 53911176Ssam /* 5404744Swnj * Couldn't recover error. 5414744Swnj */ 54218323Sralph tprintf(sc->sc_ttyp, 54318323Sralph "ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 5444746Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 5454746Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 5464744Swnj bp->b_flags |= B_ERROR; 5474744Swnj goto opdone; 5484744Swnj } 54911176Ssam 5504744Swnj ignoreerr: 5514744Swnj /* 55211176Ssam * If we hit a tape mark update our position. 55311176Ssam */ 55411176Ssam if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) { 55511176Ssam /* 55611176Ssam * Set blkno and nxrec 55711176Ssam */ 55811176Ssam if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 55911176Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 56011176Ssam sc->sc_nxrec = 56111176Ssam bdbtofsb(bp->b_blkno) - addr->utfc; 56211176Ssam sc->sc_blkno = sc->sc_nxrec; 56311176Ssam } else { 56411176Ssam sc->sc_blkno = 56511176Ssam bdbtofsb(bp->b_blkno) + addr->utfc; 56611176Ssam sc->sc_nxrec = sc->sc_blkno-1; 56711176Ssam } 56811176Ssam } else 56911176Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 57011176Ssam /* 57111176Ssam * Note: if we get a tape mark on a read, the 57211176Ssam * frame count register will be zero, so b_resid 57311176Ssam * will be calculated correctly below. 57411176Ssam */ 57511176Ssam goto opdone; 57611176Ssam } 57711176Ssam /* 5784744Swnj * Advance tape control FSM. 5794744Swnj */ 5804744Swnj switch (state) { 5814744Swnj 5824744Swnj case SIO: /* read/write increments tape block # */ 5834744Swnj sc->sc_blkno++; 5844746Ssam break; 5854744Swnj 58611176Ssam case SCOM: /* motion commands update current position */ 5874744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) 5884744Swnj switch (bp->b_command) { 5894744Swnj 5904744Swnj case UT_SFORW: 5914744Swnj sc->sc_blkno -= bp->b_repcnt; 5924744Swnj break; 5934744Swnj 5944744Swnj case UT_SREV: 5954744Swnj sc->sc_blkno += bp->b_repcnt; 5964744Swnj break; 59711176Ssam 59811176Ssam case UT_REWOFFL: 59911176Ssam addr->utcs1 = UT_CLEAR|UT_GO; 60011176Ssam break; 6014744Swnj } 6024746Ssam break; 6034744Swnj 6044744Swnj case SSEEK: 6057382Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 6064744Swnj goto opcont; 6074744Swnj 6084746Ssam case SERASE: 6094746Ssam /* 6104746Ssam * Completed erase of the inter-record gap due to a 6114746Ssam * write error; now retry the write operation. 6124746Ssam */ 6134746Ssam um->um_tab.b_state = SERASED; 6144746Ssam goto opcont; 6154746Ssam 6164746Ssam case SREW: /* clear attention bit */ 6174746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 6184746Ssam break; 6194746Ssam 6204744Swnj default: 6214746Ssam printf("bad state %d\n", state); 6224744Swnj panic("utintr"); 6234744Swnj } 6244744Swnj 6254744Swnj opdone: 6264744Swnj /* 6274744Swnj * Reset error count and remove 6284744Swnj * from device queue 6294744Swnj */ 6304744Swnj um->um_tab.b_errcnt = 0; 6314746Ssam dp->b_actf = bp->av_forw; 63211176Ssam /* 63311176Ssam * For read command, frame count register contains 63411176Ssam * actual length of tape record. Otherwise, it 63511176Ssam * holds negative residual count. 63611176Ssam */ 63711176Ssam if (state == SIO && um->um_cmd == UT_RCOM) { 63811176Ssam bp->b_resid = 0; 63911176Ssam if (bp->b_bcount > MASKREG(addr->utfc)) 64011176Ssam bp->b_resid = bp->b_bcount - MASKREG(addr->utfc); 64111176Ssam } else 64211176Ssam bp->b_resid = MASKREG(-addr->utfc); 6434744Swnj ubadone(um); 6444744Swnj iodone(bp); 6454744Swnj /* 6464744Swnj * Circulate slave to end of controller queue 6474744Swnj * to give other slaves a chance 6484744Swnj */ 6494744Swnj um->um_tab.b_actf = dp->b_forw; 6504744Swnj if (dp->b_actf) { 6514744Swnj dp->b_forw = NULL; 6524744Swnj if (um->um_tab.b_actf == NULL) 6534744Swnj um->um_tab.b_actf = dp; 6544744Swnj else 6554744Swnj um->um_tab.b_actl->b_forw = dp; 6564744Swnj um->um_tab.b_actl = dp; 6574744Swnj } 6584744Swnj if (um->um_tab.b_actf == 0) 6594744Swnj return; 6604744Swnj opcont: 6614744Swnj utstart(um); 6624744Swnj } 6634744Swnj 6644744Swnj /* 6654833Swnj * Watchdog timer routine. 6664833Swnj */ 6674833Swnj uttimer(dev) 6684833Swnj int dev; 6694833Swnj { 6704833Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 6714846Sroot register short x; 6724833Swnj 6734833Swnj if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) { 6744859Ssam printf("tj%d: lost interrupt\n", TJUNIT(dev)); 6754833Swnj sc->sc_timo = INF; 6764846Sroot x = spl5(); 6774833Swnj utintr(UTUNIT(dev)); 6784846Sroot (void) splx(x); 6794833Swnj } 6804833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 6814833Swnj } 6824833Swnj 6834833Swnj /* 6844744Swnj * Raw interface for a read 6854744Swnj */ 6867736Sroot utread(dev, uio) 6874744Swnj dev_t dev; 6887736Sroot struct uio *uio; 6894744Swnj { 6908167Sroot int errno; 6917736Sroot 6928167Sroot errno = utphys(dev, uio); 6938167Sroot if (errno) 6948167Sroot return (errno); 6958167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys, uio)); 6964744Swnj } 6974744Swnj 6984744Swnj /* 6994744Swnj * Raw interface for a write 7004744Swnj */ 7017847Sroot utwrite(dev, uio) 7027736Sroot dev_t dev; 7037847Sroot struct uio *uio; 7044744Swnj { 7058167Sroot int errno; 7068167Sroot 7078167Sroot errno = utphys(dev, uio); 7088167Sroot if (errno) 7098167Sroot return (errno); 7108167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys, uio)); 7114744Swnj } 7124744Swnj 7134744Swnj /* 7144744Swnj * Check for valid device number dev and update our notion 7154744Swnj * of where we are on the tape 7164744Swnj */ 7177736Sroot utphys(dev, uio) 7184744Swnj dev_t dev; 7197736Sroot struct uio *uio; 7204744Swnj { 7214744Swnj register int tjunit = TJUNIT(dev); 7224744Swnj register struct tj_softc *sc; 7234744Swnj register struct uba_device *ui; 7244744Swnj 7257847Sroot if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 7267847Sroot return (ENXIO); 7274744Swnj sc = &tj_softc[tjunit]; 7287847Sroot sc->sc_blkno = bdbtofsb(uio->uio_offset>>9); 7294746Ssam sc->sc_nxrec = sc->sc_blkno+1; 7307847Sroot return (0); 7314744Swnj } 7324744Swnj 7334744Swnj /*ARGSUSED*/ 7347634Ssam utioctl(dev, cmd, data, flag) 7354744Swnj dev_t dev; 7367634Ssam caddr_t data; 7374744Swnj { 7384744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 7394744Swnj register struct buf *bp = &cutbuf[UTUNIT(dev)]; 7404744Swnj register callcount; 7414744Swnj int fcount; 7427634Ssam struct mtop *mtop; 7437634Ssam struct mtget *mtget; 7444744Swnj /* we depend of the values and order of the MT codes here */ 7454744Swnj static utops[] = 7464744Swnj {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE}; 7474744Swnj 7484744Swnj switch (cmd) { 7494744Swnj 7504744Swnj case MTIOCTOP: 7517634Ssam mtop = (struct mtop *)data; 7527634Ssam switch(mtop->mt_op) { 7534744Swnj 7544744Swnj case MTWEOF: 75511413Ssam case MTFSF: case MTBSF: 75611413Ssam case MTFSR: case MTBSR: 7577634Ssam callcount = mtop->mt_count; 7584744Swnj fcount = 1; 7594744Swnj break; 7604744Swnj 7614744Swnj case MTREW: case MTOFFL: case MTNOP: 7624744Swnj callcount = 1; 7634744Swnj fcount = 1; 7644744Swnj break; 7654744Swnj 7664744Swnj default: 7678577Sroot return (ENXIO); 7684744Swnj } 7698577Sroot if (callcount <= 0 || fcount <= 0) 7708577Sroot return (EINVAL); 7714744Swnj while (--callcount >= 0) { 7727634Ssam utcommand(dev, utops[mtop->mt_op], fcount); 7734744Swnj if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT)) 7744744Swnj break; 7754744Swnj } 7768650Sroot return (geterror(bp)); 7774744Swnj 7784744Swnj case MTIOCGET: 7797634Ssam mtget = (struct mtget *)data; 7807634Ssam mtget->mt_dsreg = sc->sc_dsreg; 7817634Ssam mtget->mt_erreg = sc->sc_erreg; 7827634Ssam mtget->mt_resid = sc->sc_resid; 7837634Ssam mtget->mt_type = MT_ISUT; 7848577Sroot break; 7854744Swnj 7864744Swnj default: 7878577Sroot return (ENXIO); 7884744Swnj } 7898577Sroot return (0); 7904744Swnj } 7914744Swnj 7924744Swnj utreset(uban) 7934744Swnj int uban; 7944744Swnj { 7954744Swnj register struct uba_ctlr *um; 7964744Swnj register ut11, tjunit; 7974744Swnj register struct uba_device *ui; 7984744Swnj register struct buf *dp; 7994744Swnj 8004744Swnj for (ut11 = 0; ut11 < NUT; ut11++) { 8014744Swnj if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || 8024744Swnj um->um_ubanum != uban) 8034744Swnj continue; 8044744Swnj printf(" ut%d", ut11); 8054746Ssam um->um_tab.b_state = 0; 8064744Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8074744Swnj if (um->um_ubinfo) { 8084744Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 8099358Ssam um->um_ubinfo = 0; 8104744Swnj } 8114744Swnj ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; 8124746Ssam ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR; 8134744Swnj for (tjunit = 0; tjunit < NTJ; tjunit++) { 8144744Swnj if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um || 8154744Swnj ui->ui_alive == 0) 8164744Swnj continue; 8174744Swnj dp = &tjutab[tjunit]; 8184746Ssam dp->b_state = 0; 8194744Swnj dp->b_forw = 0; 8204744Swnj if (um->um_tab.b_actf == NULL) 8214744Swnj um->um_tab.b_actf = dp; 8224744Swnj else 8234744Swnj um->um_tab.b_actl->b_forw = dp; 8244744Swnj um->um_tab.b_actl = dp; 8254744Swnj if (tj_softc[tjunit].sc_openf > 0) 8264744Swnj tj_softc[tjunit].sc_openf = -1; 8274744Swnj } 8284744Swnj utstart(um); 8294744Swnj } 8304744Swnj } 8314744Swnj 8324744Swnj /* 8334744Swnj * Do a stand-alone core dump to tape -- 8344744Swnj * from here down, routines are used only in dump context 8354744Swnj */ 8364744Swnj #define DBSIZE 20 8374744Swnj 8384744Swnj utdump() 8394744Swnj { 8404744Swnj register struct uba_device *ui; 8414744Swnj register struct uba_regs *up; 8424746Ssam register struct utdevice *addr; 8434744Swnj int blk, num = maxfree; 8444744Swnj int start = 0; 8454744Swnj 8464744Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8474744Swnj if (tjdinfo[0] == 0) 8484744Swnj return (ENXIO); 8494744Swnj ui = phys(tjdinfo[0], struct uba_device *); 8504744Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8514941Swnj ubainit(up); 8524744Swnj DELAY(1000000); 8534941Swnj addr = (struct utdevice *)ui->ui_physaddr; 8544746Ssam utwait(addr); 8554746Ssam /* 8564746Ssam * Be sure to set the appropriate density here. We use 8574746Ssam * 6250, but maybe it should be done at 1600 to insure the 8584746Ssam * tape can be read by most any other tape drive available. 8594746Ssam */ 8604746Ssam addr->uttc = UT_GCR|PDP11FMT; /* implicit slave 0 or-ed in */ 8614746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 8624744Swnj while (num > 0) { 8634744Swnj blk = num > DBSIZE ? DBSIZE : num; 8644746Ssam utdwrite(start, blk, addr, up); 8654746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8664746Ssam return(EIO); 8674744Swnj start += blk; 8684744Swnj num -= blk; 8694744Swnj } 8704746Ssam uteof(addr); 8714746Ssam uteof(addr); 8724746Ssam utwait(addr); 8734746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8744744Swnj return(EIO); 8754746Ssam addr->utcs1 = UT_REW|UT_GO; 8764744Swnj return (0); 8774744Swnj } 8784744Swnj 8794746Ssam utdwrite(dbuf, num, addr, up) 8804744Swnj register dbuf, num; 8814746Ssam register struct utdevice *addr; 8824744Swnj struct uba_regs *up; 8834744Swnj { 8844744Swnj register struct pte *io; 8854744Swnj register int npf; 8864744Swnj 8874746Ssam utwait(addr); 8884744Swnj io = up->uba_map; 8894744Swnj npf = num + 1; 8904744Swnj while (--npf != 0) 8914744Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 8924744Swnj *(int *)io = 0; 8934746Ssam addr->utwc = -((num*NBPG)>>1); 8944746Ssam addr->utfc = -(num*NBPG); 8954746Ssam addr->utba = 0; 8964746Ssam addr->utcs1 = UT_WCOM|UT_GO; 8974744Swnj } 8984744Swnj 8994746Ssam utwait(addr) 9004746Ssam struct utdevice *addr; 9014744Swnj { 9024744Swnj register s; 9034744Swnj 9044744Swnj do 9054746Ssam s = addr->utds; 9064744Swnj while ((s&UTDS_DRY) == 0); 9074744Swnj } 9084744Swnj 9094746Ssam uteof(addr) 9104746Ssam struct utdevice *addr; 9114744Swnj { 9124744Swnj 9134746Ssam utwait(addr); 9144746Ssam addr->utcs1 = UT_WEOF|UT_GO; 9154744Swnj } 9164744Swnj #endif 917