123357Smckusick /* 229255Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323357Smckusick * All rights reserved. The Berkeley software License Agreement 423357Smckusick * specifies the terms and conditions for redistribution. 523357Smckusick * 6*40911Ssklower * @(#)ut.c 7.9 (Berkeley) 04/12/90 723357Smckusick */ 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 */ 1917083Sbloom #include "param.h" 2017083Sbloom #include "systm.h" 2117083Sbloom #include "buf.h" 2217083Sbloom #include "conf.h" 2317083Sbloom #include "file.h" 2417083Sbloom #include "user.h" 2540906Ssklower #include "proc.h" 2617083Sbloom #include "map.h" 2717083Sbloom #include "ioctl.h" 2817083Sbloom #include "mtio.h" 2917083Sbloom #include "cmap.h" 3017083Sbloom #include "uio.h" 3117083Sbloom #include "kernel.h" 3218323Sralph #include "tty.h" 3330917Skarels #include "syslog.h" 344744Swnj 3537511Smckusick #include "machine/pte.h" 368483Sroot #include "../vax/cpu.h" 3717083Sbloom #include "ubareg.h" 3817083Sbloom #include "ubavar.h" 3917083Sbloom #include "utreg.h" 404744Swnj 414744Swnj struct buf cutbuf[NUT]; /* bufs for control operations */ 424744Swnj struct buf tjutab[NTJ]; /* bufs for slave queue headers */ 434744Swnj 444744Swnj struct uba_ctlr *utminfo[NUT]; 454744Swnj struct uba_device *tjdinfo[NTJ]; 464833Swnj int utprobe(), utslave(), utattach(), utdgo(), utintr(), uttimer(); 474744Swnj u_short utstd[] = { 0772440, 0 }; 484744Swnj struct uba_driver utdriver = 494744Swnj { utprobe, utslave, utattach, utdgo, utstd, "tj", tjdinfo, "ut", utminfo, 0 }; 504744Swnj 5111176Ssam #define MASKREG(reg) ((reg)&0xffff) 5211176Ssam 534744Swnj /* bits in minor device */ 544744Swnj #define TJUNIT(dev) (minor(dev)&03) 554744Swnj #define T_NOREWIND 04 564744Swnj #define T_1600BPI 010 574744Swnj #define T_6250BPI 020 584744Swnj short utdens[] = { UT_NRZI, UT_PE, UT_GCR, UT_NRZI }; 594744Swnj 604744Swnj /* slave to controller mapping table */ 614744Swnj short tjtout[NTJ]; 624744Swnj #define UTUNIT(dev) (tjtout[TJUNIT(dev)]) 634744Swnj 644744Swnj #define INF (daddr_t)1000000L /* a block number that wont exist */ 654744Swnj 664744Swnj struct tj_softc { 674744Swnj char sc_openf; /* exclusive open */ 684744Swnj char sc_lastiow; /* last I/O operation was a write */ 694744Swnj daddr_t sc_blkno; /* next block to transfer */ 704744Swnj daddr_t sc_nxrec; /* next record on tape */ 714744Swnj u_short sc_erreg; /* image of uter */ 724744Swnj u_short sc_dsreg; /* image of utds */ 734746Ssam u_short sc_resid; /* residual from transfer */ 744744Swnj u_short sc_dens; /* sticky selected density */ 754833Swnj daddr_t sc_timo; /* time until timeout expires */ 764833Swnj short sc_tact; /* timeout is active flag */ 7740045Smarc caddr_t sc_ctty; /* user's controlling tty (vnode) */ 7830917Skarels int sc_blks; /* number of I/O operations since open */ 7930917Skarels int sc_softerrs; /* number of soft I/O errors since open */ 804744Swnj } tj_softc[NTJ]; 814744Swnj 824744Swnj /* 834744Swnj * Internal per/slave states found in sc_state 844744Swnj */ 854744Swnj #define SSEEK 1 /* seeking */ 864744Swnj #define SIO 2 /* doing sequential I/O */ 874744Swnj #define SCOM 3 /* sending a control command */ 884744Swnj #define SREW 4 /* doing a rewind op */ 894746Ssam #define SERASE 5 /* erase inter-record gap */ 904746Ssam #define SERASED 6 /* erased inter-record gap */ 914744Swnj 924941Swnj /*ARGSUSED*/ 934744Swnj utprobe(reg) 944744Swnj caddr_t reg; 954744Swnj { 964744Swnj register int br, cvec; 974744Swnj #ifdef lint 984744Swnj br=0; cvec=br; br=cvec; 994941Swnj utintr(0); 1004744Swnj #endif 1014746Ssam /* 1026954Sroot * The SI documentation says you must set the RDY bit 1036954Sroot * (even though it's read-only) to force an interrupt. 1044746Ssam */ 1056954Sroot ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY; 1064744Swnj DELAY(10000); 1077405Skre return (sizeof (struct utdevice)); 1084744Swnj } 1094744Swnj 1104744Swnj /*ARGSUSED*/ 1114744Swnj utslave(ui, reg) 1124744Swnj struct uba_device *ui; 1134744Swnj caddr_t reg; 1144744Swnj { 1154744Swnj /* 1164744Swnj * A real TU45 would support the slave present bit 1174744Swnj * int the drive type register, but this thing doesn't, 1184744Swnj * so there's no way to determine if a slave is present or not. 1194744Swnj */ 1204744Swnj return(1); 1214744Swnj } 1224744Swnj 1234744Swnj utattach(ui) 1244744Swnj struct uba_device *ui; 1254744Swnj { 1264744Swnj tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; 1274744Swnj } 1284744Swnj 1294744Swnj /* 1304744Swnj * Open the device with exclusive access. 1314744Swnj */ 1324744Swnj utopen(dev, flag) 1334744Swnj dev_t dev; 1344744Swnj int flag; 1354744Swnj { 1364744Swnj register int tjunit = TJUNIT(dev); 1374744Swnj register struct uba_device *ui; 1384744Swnj register struct tj_softc *sc; 13940725Skarels int olddens, dens, error; 1405439Sroot register int s; 1414744Swnj 14225053Skarels if (tjunit >= NTJ || (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 1438577Sroot return (ENXIO); 14425053Skarels if ((sc = &tj_softc[tjunit])->sc_openf) 14525053Skarels return (EBUSY); 14630917Skarels sc->sc_openf = 1; 1474744Swnj olddens = sc->sc_dens; 1488577Sroot dens = sc->sc_dens = 1498577Sroot utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]| 1508577Sroot PDP11FMT|(ui->ui_slave&07); 1514744Swnj get: 1524744Swnj utcommand(dev, UT_SENSE, 1); 1534744Swnj if (sc->sc_dsreg&UTDS_PIP) { 15440725Skarels if (error = tsleep((caddr_t)&lbolt, (PZERO+1) | PCATCH, 15540725Skarels devopn, 0)) 15640725Skarels return (error); 1574744Swnj goto get; 1584744Swnj } 1594744Swnj sc->sc_dens = olddens; 1604744Swnj if ((sc->sc_dsreg&UTDS_MOL) == 0) { 16130917Skarels sc->sc_openf = 0; 1624744Swnj uprintf("tj%d: not online\n", tjunit); 1638577Sroot return (EIO); 1644744Swnj } 1654744Swnj if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) { 16630917Skarels sc->sc_openf = 0; 1674744Swnj uprintf("tj%d: no write ring\n", tjunit); 1688577Sroot return (EIO); 1694744Swnj } 1704744Swnj if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) && 1714744Swnj dens != sc->sc_dens) { 17230917Skarels sc->sc_openf = 0; 1734744Swnj uprintf("tj%d: can't change density in mid-tape\n", tjunit); 1748577Sroot return (EIO); 1754744Swnj } 1764744Swnj sc->sc_blkno = (daddr_t)0; 1774744Swnj sc->sc_nxrec = INF; 1784744Swnj sc->sc_lastiow = 0; 17930917Skarels sc->sc_blks = 0; 18030917Skarels sc->sc_softerrs = 0; 1814744Swnj sc->sc_dens = dens; 18240045Smarc sc->sc_ctty = (caddr_t)(u.u_procp->p_flag&SCTTY ? 18340045Smarc u.u_procp->p_session->s_ttyvp : 0); 1844746Ssam /* 1854746Ssam * For 6250 bpi take exclusive use of the UNIBUS. 1864746Ssam */ 1874746Ssam ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI; 18826374Skarels s = splclock(); 1894833Swnj if (sc->sc_tact == 0) { 1904833Swnj sc->sc_timo = INF; 1914833Swnj sc->sc_tact = 1; 1924833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 1934833Swnj } 1945439Sroot splx(s); 1958577Sroot return (0); 1964744Swnj } 1974744Swnj 1984744Swnj utclose(dev, flag) 1994744Swnj register dev_t dev; 2004744Swnj register flag; 2014744Swnj { 2024744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 2034744Swnj 2044744Swnj if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) { 2054744Swnj utcommand(dev, UT_WEOF, 1); 2064744Swnj utcommand(dev, UT_WEOF, 1); 2074744Swnj utcommand(dev, UT_SREV, 1); 2084744Swnj } 2094744Swnj if ((minor(dev)&T_NOREWIND) == 0) 2104744Swnj utcommand(dev, UT_REW, 0); 21130917Skarels if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 21230917Skarels log(LOG_INFO, "tj%d: %d soft errors in %d blocks\n", 21330917Skarels TJUNIT(dev), sc->sc_softerrs, sc->sc_blks); 2144744Swnj sc->sc_openf = 0; 21540725Skarels return (0); 2164744Swnj } 2174744Swnj 2184744Swnj utcommand(dev, com, count) 2194744Swnj dev_t dev; 2204744Swnj int com, count; 2214744Swnj { 2224744Swnj register struct buf *bp; 2235439Sroot register int s; 2244744Swnj 2254744Swnj bp = &cutbuf[UTUNIT(dev)]; 2265439Sroot s = spl5(); 2274744Swnj while (bp->b_flags&B_BUSY) { 2284744Swnj if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2294744Swnj break; 2304744Swnj bp->b_flags |= B_WANTED; 2314744Swnj sleep((caddr_t)bp, PRIBIO); 2324744Swnj } 2334744Swnj bp->b_flags = B_BUSY|B_READ; 2345439Sroot splx(s); 2354744Swnj bp->b_dev = dev; 2364744Swnj bp->b_command = com; 2374744Swnj bp->b_repcnt = count; 2384744Swnj bp->b_blkno = 0; 2394744Swnj utstrategy(bp); 2404744Swnj if (count == 0) 2414744Swnj return; 2424744Swnj iowait(bp); 2434744Swnj if (bp->b_flags&B_WANTED) 2444744Swnj wakeup((caddr_t)bp); 2454744Swnj bp->b_flags &= B_ERROR; 2464744Swnj } 2474744Swnj 2484744Swnj /* 2494744Swnj * Queue a tape operation. 2504744Swnj */ 2514744Swnj utstrategy(bp) 2524744Swnj register struct buf *bp; 2534744Swnj { 2544744Swnj int tjunit = TJUNIT(bp->b_dev); 2554744Swnj register struct uba_ctlr *um; 2564744Swnj register struct buf *dp; 25734218Sbostic int s; 2584744Swnj 2594744Swnj /* 2604744Swnj * Put transfer at end of unit queue 2614744Swnj */ 2624744Swnj dp = &tjutab[tjunit]; 2634744Swnj bp->av_forw = NULL; 26417433Skarels um = tjdinfo[tjunit]->ui_mi; 26534218Sbostic s = spl5(); 2664744Swnj if (dp->b_actf == NULL) { 2674744Swnj dp->b_actf = bp; 2684744Swnj /* 2694744Swnj * Transport not active, so... 2704744Swnj * put at end of controller queue 2714744Swnj */ 2724744Swnj dp->b_forw = NULL; 2734744Swnj if (um->um_tab.b_actf == NULL) 2744744Swnj um->um_tab.b_actf = dp; 2754744Swnj else 2764744Swnj um->um_tab.b_actl->b_forw = dp; 2774744Swnj um->um_tab.b_actl = dp; 2784744Swnj } else 2794744Swnj dp->b_actl->av_forw = bp; 2804744Swnj dp->b_actl = bp; 2814744Swnj /* 2824744Swnj * If the controller is not busy, set it going. 2834744Swnj */ 2844746Ssam if (um->um_tab.b_state == 0) 2854744Swnj utstart(um); 28634218Sbostic splx(s); 2874744Swnj } 2884744Swnj 2894744Swnj utstart(um) 2904744Swnj register struct uba_ctlr *um; 2914744Swnj { 2924746Ssam register struct utdevice *addr; 2934744Swnj register struct buf *bp, *dp; 2944744Swnj register struct tj_softc *sc; 2954744Swnj struct uba_device *ui; 2964744Swnj int tjunit; 2974744Swnj daddr_t blkno; 2984744Swnj 2994744Swnj loop: 3004744Swnj /* 3014744Swnj * Scan controller queue looking for units with 3024744Swnj * transaction queues to dispatch 3034744Swnj */ 3044744Swnj if ((dp = um->um_tab.b_actf) == NULL) 3054744Swnj return; 3064744Swnj if ((bp = dp->b_actf) == NULL) { 3074744Swnj um->um_tab.b_actf = dp->b_forw; 3084744Swnj goto loop; 3094744Swnj } 3104746Ssam addr = (struct utdevice *)um->um_addr; 3114744Swnj tjunit = TJUNIT(bp->b_dev); 3124744Swnj ui = tjdinfo[tjunit]; 3134744Swnj sc = &tj_softc[tjunit]; 3144744Swnj /* note slave select, density, and format were merged on open */ 3154746Ssam addr->uttc = sc->sc_dens; 3164746Ssam sc->sc_dsreg = addr->utds; 3174746Ssam sc->sc_erreg = addr->uter; 31811176Ssam sc->sc_resid = MASKREG(addr->utfc); 3194744Swnj /* 3204744Swnj * Default is that last command was NOT a write command; 3214744Swnj * if we do a write command we will notice this in utintr(). 3224744Swnj */ 3234744Swnj sc->sc_lastiow = 0; 3244746Ssam if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) { 3254744Swnj /* 3264744Swnj * Have had a hard error on a non-raw tape 3274744Swnj * or the tape unit is now unavailable 3284744Swnj * (e.g. taken off line). 3294744Swnj */ 3304744Swnj bp->b_flags |= B_ERROR; 3314744Swnj goto next; 3324744Swnj } 3334744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 3344744Swnj /* 3354744Swnj * Execute a control operation with the specified 3364744Swnj * count. 3374744Swnj */ 3384744Swnj if (bp->b_command == UT_SENSE) 3394744Swnj goto next; 34011176Ssam if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) { 34111176Ssam bp->b_resid = bp->b_bcount; 34211176Ssam goto next; 34311176Ssam } 3444744Swnj /* 3454744Swnj * Set next state; handle timeouts 3464744Swnj */ 3474833Swnj if (bp->b_command == UT_REW) { 3484746Ssam um->um_tab.b_state = SREW; 3494833Swnj sc->sc_timo = 5*60; 3504833Swnj } else { 3514746Ssam um->um_tab.b_state = SCOM; 3524833Swnj sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60); 3534833Swnj } 3544744Swnj /* NOTE: this depends on the ut command values */ 3554744Swnj if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) 3564746Ssam addr->utfc = -bp->b_repcnt; 3574744Swnj goto dobpcmd; 3584744Swnj } 3594744Swnj /* 36034218Sbostic * For raw I/O, save the current block 36134218Sbostic * number in case we have to retry. 3624744Swnj */ 36334218Sbostic if (bp->b_flags & B_RAW) { 36434218Sbostic if (um->um_tab.b_errcnt == 0) { 36534218Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno); 36634218Sbostic sc->sc_nxrec = sc->sc_blkno + 1; 36734218Sbostic } 3684744Swnj } 36934218Sbostic else { 37034218Sbostic /* 37134218Sbostic * Handle boundary cases for operation 37234218Sbostic * on non-raw tapes. 37334218Sbostic */ 37434218Sbostic if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 37534218Sbostic /* can't read past end of file */ 37634218Sbostic bp->b_flags |= B_ERROR; 37734218Sbostic bp->b_error = ENXIO; 37834218Sbostic goto next; 37934218Sbostic } 38034218Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 38134218Sbostic (bp->b_flags&B_READ)) { 38234218Sbostic /* 38334218Sbostic * Reading at end of file returns 0 bytes. 38434218Sbostic */ 38534218Sbostic bp->b_resid = bp->b_bcount; 38634218Sbostic clrbuf(bp); 38734218Sbostic goto next; 38834218Sbostic } 38934218Sbostic if ((bp->b_flags&B_READ) == 0) 39034218Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 3914744Swnj } 3924744Swnj /* 3934744Swnj * If the tape is correctly positioned, set up all the 3944744Swnj * registers but the csr, and give control over to the 3954744Swnj * UNIBUS adaptor routines, to wait for resources to 3964744Swnj * start I/O. 3974744Swnj */ 3987382Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3994746Ssam addr->utwc = -(((bp->b_bcount)+1)>>1); 4004746Ssam addr->utfc = -bp->b_bcount; 4014744Swnj if ((bp->b_flags&B_READ) == 0) { 4024744Swnj /* 4034744Swnj * On write error retries erase the 4044746Ssam * inter-record gap before rewriting. 4054744Swnj */ 4064746Ssam if (um->um_tab.b_errcnt) { 4074746Ssam if (um->um_tab.b_state != SERASED) { 4084759Swnj um->um_tab.b_state = SERASE; 4094833Swnj sc->sc_timo = 60; 4104746Ssam addr->utcs1 = UT_ERASE|UT_IE|UT_GO; 4114746Ssam return; 4124746Ssam } 4134746Ssam } 41411176Ssam if (addr->utds & UTDS_EOT) { 41511176Ssam bp->b_resid = bp->b_bcount; 41611176Ssam um->um_tab.b_state = 0; 41711176Ssam goto next; 41811176Ssam } 4194746Ssam um->um_cmd = UT_WCOM; 4204744Swnj } else 4214744Swnj um->um_cmd = UT_RCOM; 4224833Swnj sc->sc_timo = 60; 4234746Ssam um->um_tab.b_state = SIO; 4244744Swnj (void) ubago(ui); 4254744Swnj return; 4264744Swnj } 4274744Swnj /* 4284744Swnj * Tape positioned incorrectly; seek forwards or 4294744Swnj * backwards to the correct spot. This happens for 4304744Swnj * raw tapes only on error retries. 4314744Swnj */ 4324746Ssam um->um_tab.b_state = SSEEK; 4337382Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 4347382Ssam addr->utfc = blkno - bdbtofsb(bp->b_blkno); 4354744Swnj bp->b_command = UT_SFORW; 4364744Swnj } else { 4377382Ssam addr->utfc = bdbtofsb(bp->b_blkno) - blkno; 4384744Swnj bp->b_command = UT_SREV; 4394744Swnj } 4404833Swnj sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60); 4414744Swnj 4424744Swnj dobpcmd: 4434744Swnj /* 4444744Swnj * Perform the command setup in bp. 4454744Swnj */ 4464746Ssam addr->utcs1 = bp->b_command|UT_IE|UT_GO; 4474744Swnj return; 4484744Swnj next: 4494744Swnj /* 4504744Swnj * Advance to the next command in the slave queue, 4514744Swnj * posting notice and releasing resources as needed. 4524744Swnj */ 4534744Swnj if (um->um_ubinfo) 4544744Swnj ubadone(um); 4554744Swnj um->um_tab.b_errcnt = 0; 4564744Swnj dp->b_actf = bp->av_forw; 4574744Swnj iodone(bp); 4584744Swnj goto loop; 4594744Swnj } 4604744Swnj 4614744Swnj /* 4624744Swnj * Start operation on controller -- 4634744Swnj * UNIBUS resources have been allocated. 4644744Swnj */ 4654744Swnj utdgo(um) 4664744Swnj register struct uba_ctlr *um; 4674744Swnj { 4684744Swnj register struct utdevice *addr = (struct utdevice *)um->um_addr; 4694744Swnj 4704744Swnj addr->utba = (u_short) um->um_ubinfo; 47111176Ssam addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO; 4724744Swnj } 4734744Swnj 4744744Swnj /* 4754744Swnj * Ut interrupt handler 4764744Swnj */ 4774744Swnj /*ARGSUSED*/ 4784744Swnj utintr(ut11) 4794744Swnj int ut11; 4804744Swnj { 4814744Swnj struct buf *dp; 4824744Swnj register struct buf *bp; 4834744Swnj register struct uba_ctlr *um = utminfo[ut11]; 4844744Swnj register struct utdevice *addr; 4854744Swnj register struct tj_softc *sc; 4864746Ssam u_short tjunit, cs2, cs1; 4874744Swnj register state; 4884744Swnj 4894744Swnj if ((dp = um->um_tab.b_actf) == NULL) 4904744Swnj return; 4914744Swnj bp = dp->b_actf; 4924744Swnj tjunit = TJUNIT(bp->b_dev); 4934744Swnj addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr; 4944744Swnj sc = &tj_softc[tjunit]; 4954744Swnj /* 4964744Swnj * Record status... 4974744Swnj */ 4984877Ssam sc->sc_timo = INF; 4994744Swnj sc->sc_dsreg = addr->utds; 5004744Swnj sc->sc_erreg = addr->uter; 50111176Ssam sc->sc_resid = MASKREG(addr->utfc); 5024746Ssam if ((bp->b_flags&B_READ) == 0) 5034744Swnj sc->sc_lastiow = 1; 5044746Ssam state = um->um_tab.b_state; 5054746Ssam um->um_tab.b_state = 0; 5064744Swnj /* 5074744Swnj * Check for errors... 5084744Swnj */ 5094744Swnj if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) { 5104744Swnj /* 5114759Swnj * To clear the ERR bit, we must issue a drive clear 5124759Swnj * command, and to clear the TRE bit we must set the 5134759Swnj * controller clear bit. 5144759Swnj */ 5154759Swnj cs2 = addr->utcs2; 5164759Swnj if ((cs1 = addr->utcs1)&UT_TRE) 5174759Swnj addr->utcs2 |= UTCS2_CLR; 5184759Swnj /* is this dangerous ?? */ 5194759Swnj while ((addr->utcs1&UT_RDY) == 0) 5204759Swnj ; 5214759Swnj addr->utcs1 = UT_CLEAR|UT_GO; 5224759Swnj /* 52311176Ssam * If we were reading at 1600 or 6250 bpi and the error 52411176Ssam * was corrected, then don't consider this an error. 5254744Swnj */ 52611190Ssam if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) && 52711176Ssam (addr->uttc & UTTC_DEN) != UT_NRZI) { 52840045Smarc tprintf(sc->sc_ctty, 52911176Ssam "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 53011176Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 53111176Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 53211176Ssam sc->sc_erreg &= ~UTER_COR; 5334744Swnj } 5344744Swnj /* 5354744Swnj * If we were reading from a raw tape and the only error 5364744Swnj * was that the record was too long, then we don't consider 5374744Swnj * this an error. 5384744Swnj */ 53934218Sbostic if ((bp->b_flags & (B_READ|B_RAW)) == (B_READ|B_RAW) && 5404744Swnj (sc->sc_erreg&UTER_FCE)) 54111176Ssam sc->sc_erreg &= ~UTER_FCE; 54211197Slayer if (sc->sc_erreg == 0) 5434744Swnj goto ignoreerr; 5444744Swnj /* 54511176Ssam * Fix up errors which occur due to backspacing 54611176Ssam * "over" the front of the tape. 5474746Ssam */ 54811176Ssam if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV && 5494746Ssam ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0)) 5504746Ssam goto opdone; 5514746Ssam /* 5524744Swnj * Retry soft errors up to 8 times 5534744Swnj */ 5544744Swnj if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { 5554744Swnj if (++um->um_tab.b_errcnt < 7) { 5564744Swnj sc->sc_blkno++; 5574744Swnj ubadone(um); 5584744Swnj goto opcont; 5594744Swnj } 56011176Ssam } 5614744Swnj /* 56211176Ssam * Hard or non-I/O errors on non-raw tape 56311176Ssam * cause it to close. 56411176Ssam */ 56534218Sbostic if ((bp->b_flags&B_RAW) == 0 && sc->sc_openf > 0) 56611176Ssam sc->sc_openf = -1; 56711176Ssam /* 5684744Swnj * Couldn't recover error. 5694744Swnj */ 57040045Smarc tprintf(sc->sc_ctty, 57118323Sralph "ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 5724746Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 5734746Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 5744744Swnj bp->b_flags |= B_ERROR; 5754744Swnj goto opdone; 5764744Swnj } 57711176Ssam 5784744Swnj ignoreerr: 5794744Swnj /* 58011176Ssam * If we hit a tape mark update our position. 58111176Ssam */ 58211176Ssam if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) { 58311176Ssam /* 58411176Ssam * Set blkno and nxrec 58511176Ssam */ 58611176Ssam if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 58711176Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 58811176Ssam sc->sc_nxrec = 58911176Ssam bdbtofsb(bp->b_blkno) - addr->utfc; 59011176Ssam sc->sc_blkno = sc->sc_nxrec; 59111176Ssam } else { 59211176Ssam sc->sc_blkno = 59311176Ssam bdbtofsb(bp->b_blkno) + addr->utfc; 59411176Ssam sc->sc_nxrec = sc->sc_blkno-1; 59511176Ssam } 59611176Ssam } else 59711176Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 59811176Ssam /* 59911176Ssam * Note: if we get a tape mark on a read, the 60011176Ssam * frame count register will be zero, so b_resid 60111176Ssam * will be calculated correctly below. 60211176Ssam */ 60311176Ssam goto opdone; 60411176Ssam } 60511176Ssam /* 6064744Swnj * Advance tape control FSM. 6074744Swnj */ 6084744Swnj switch (state) { 6094744Swnj 6104744Swnj case SIO: /* read/write increments tape block # */ 6114744Swnj sc->sc_blkno++; 61230917Skarels sc->sc_blks++; 61330917Skarels if (um->um_tab.b_errcnt) 61430917Skarels sc->sc_softerrs++; 6154746Ssam break; 6164744Swnj 61711176Ssam case SCOM: /* motion commands update current position */ 6184744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) 61926296Skarels switch ((int)bp->b_command) { 6204744Swnj 6214744Swnj case UT_SFORW: 6224744Swnj sc->sc_blkno -= bp->b_repcnt; 6234744Swnj break; 6244744Swnj 6254744Swnj case UT_SREV: 6264744Swnj sc->sc_blkno += bp->b_repcnt; 6274744Swnj break; 62811176Ssam 62911176Ssam case UT_REWOFFL: 63011176Ssam addr->utcs1 = UT_CLEAR|UT_GO; 63111176Ssam break; 6324744Swnj } 6334746Ssam break; 6344744Swnj 6354744Swnj case SSEEK: 6367382Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 6374744Swnj goto opcont; 6384744Swnj 6394746Ssam case SERASE: 6404746Ssam /* 6414746Ssam * Completed erase of the inter-record gap due to a 6424746Ssam * write error; now retry the write operation. 6434746Ssam */ 6444746Ssam um->um_tab.b_state = SERASED; 6454746Ssam goto opcont; 6464746Ssam 6474746Ssam case SREW: /* clear attention bit */ 6484746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 6494746Ssam break; 6504746Ssam 6514744Swnj default: 6524746Ssam printf("bad state %d\n", state); 6534744Swnj panic("utintr"); 6544744Swnj } 6554744Swnj 6564744Swnj opdone: 6574744Swnj /* 6584744Swnj * Reset error count and remove 6594744Swnj * from device queue 6604744Swnj */ 6614744Swnj um->um_tab.b_errcnt = 0; 6624746Ssam dp->b_actf = bp->av_forw; 66311176Ssam /* 66411176Ssam * For read command, frame count register contains 66511176Ssam * actual length of tape record. Otherwise, it 66611176Ssam * holds negative residual count. 66711176Ssam */ 66811176Ssam if (state == SIO && um->um_cmd == UT_RCOM) { 66911176Ssam bp->b_resid = 0; 67011176Ssam if (bp->b_bcount > MASKREG(addr->utfc)) 67111176Ssam bp->b_resid = bp->b_bcount - MASKREG(addr->utfc); 67211176Ssam } else 67311176Ssam bp->b_resid = MASKREG(-addr->utfc); 6744744Swnj ubadone(um); 6754744Swnj iodone(bp); 6764744Swnj /* 6774744Swnj * Circulate slave to end of controller queue 6784744Swnj * to give other slaves a chance 6794744Swnj */ 6804744Swnj um->um_tab.b_actf = dp->b_forw; 6814744Swnj if (dp->b_actf) { 6824744Swnj dp->b_forw = NULL; 6834744Swnj if (um->um_tab.b_actf == NULL) 6844744Swnj um->um_tab.b_actf = dp; 6854744Swnj else 6864744Swnj um->um_tab.b_actl->b_forw = dp; 6874744Swnj um->um_tab.b_actl = dp; 6884744Swnj } 6894744Swnj if (um->um_tab.b_actf == 0) 6904744Swnj return; 6914744Swnj opcont: 6924744Swnj utstart(um); 6934744Swnj } 6944744Swnj 6954744Swnj /* 6964833Swnj * Watchdog timer routine. 6974833Swnj */ 6984833Swnj uttimer(dev) 6994833Swnj int dev; 7004833Swnj { 7014833Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 7024846Sroot register short x; 7034833Swnj 7044833Swnj if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) { 7054859Ssam printf("tj%d: lost interrupt\n", TJUNIT(dev)); 7064833Swnj sc->sc_timo = INF; 7074846Sroot x = spl5(); 7084833Swnj utintr(UTUNIT(dev)); 7094846Sroot (void) splx(x); 7104833Swnj } 7114833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 7124833Swnj } 7134833Swnj 7144744Swnj /*ARGSUSED*/ 7157634Ssam utioctl(dev, cmd, data, flag) 7164744Swnj dev_t dev; 7177634Ssam caddr_t data; 7184744Swnj { 7194744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 7204744Swnj register struct buf *bp = &cutbuf[UTUNIT(dev)]; 7214744Swnj register callcount; 722*40911Ssklower int fcount, error = 0; 7237634Ssam struct mtop *mtop; 7247634Ssam struct mtget *mtget; 7254744Swnj /* we depend of the values and order of the MT codes here */ 7264744Swnj static utops[] = 7274744Swnj {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE}; 7284744Swnj 7294744Swnj switch (cmd) { 7304744Swnj 7314744Swnj case MTIOCTOP: 7327634Ssam mtop = (struct mtop *)data; 7337634Ssam switch(mtop->mt_op) { 7344744Swnj 7354744Swnj case MTWEOF: 73611413Ssam case MTFSF: case MTBSF: 73711413Ssam case MTFSR: case MTBSR: 7387634Ssam callcount = mtop->mt_count; 7394744Swnj fcount = 1; 7404744Swnj break; 7414744Swnj 7424744Swnj case MTREW: case MTOFFL: case MTNOP: 7434744Swnj callcount = 1; 7444744Swnj fcount = 1; 7454744Swnj break; 7464744Swnj 7474744Swnj default: 7488577Sroot return (ENXIO); 7494744Swnj } 7508577Sroot if (callcount <= 0 || fcount <= 0) 7518577Sroot return (EINVAL); 7524744Swnj while (--callcount >= 0) { 7537634Ssam utcommand(dev, utops[mtop->mt_op], fcount); 7544744Swnj if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT)) 7554744Swnj break; 7564744Swnj } 757*40911Ssklower if (bp->b_flags&B_ERROR) 758*40911Ssklower if ((error = bp->b_error)==0) 759*40911Ssklower return (EIO); 760*40911Ssklower return (error); 7614744Swnj 7624744Swnj case MTIOCGET: 7637634Ssam mtget = (struct mtget *)data; 7647634Ssam mtget->mt_dsreg = sc->sc_dsreg; 7657634Ssam mtget->mt_erreg = sc->sc_erreg; 7667634Ssam mtget->mt_resid = sc->sc_resid; 7677634Ssam mtget->mt_type = MT_ISUT; 7688577Sroot break; 7694744Swnj 7704744Swnj default: 7718577Sroot return (ENXIO); 7724744Swnj } 7738577Sroot return (0); 7744744Swnj } 7754744Swnj 7764744Swnj utreset(uban) 7774744Swnj int uban; 7784744Swnj { 7794744Swnj register struct uba_ctlr *um; 7804744Swnj register ut11, tjunit; 7814744Swnj register struct uba_device *ui; 7824744Swnj register struct buf *dp; 7834744Swnj 7844744Swnj for (ut11 = 0; ut11 < NUT; ut11++) { 7854744Swnj if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || 7864744Swnj um->um_ubanum != uban) 7874744Swnj continue; 7884744Swnj printf(" ut%d", ut11); 7894746Ssam um->um_tab.b_state = 0; 7904744Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 7914744Swnj if (um->um_ubinfo) { 7924744Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 7939358Ssam um->um_ubinfo = 0; 7944744Swnj } 7954744Swnj ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; 7964746Ssam ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR; 7974744Swnj for (tjunit = 0; tjunit < NTJ; tjunit++) { 7984744Swnj if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um || 7994744Swnj ui->ui_alive == 0) 8004744Swnj continue; 8014744Swnj dp = &tjutab[tjunit]; 8024746Ssam dp->b_state = 0; 8034744Swnj dp->b_forw = 0; 8044744Swnj if (um->um_tab.b_actf == NULL) 8054744Swnj um->um_tab.b_actf = dp; 8064744Swnj else 8074744Swnj um->um_tab.b_actl->b_forw = dp; 8084744Swnj um->um_tab.b_actl = dp; 8094744Swnj if (tj_softc[tjunit].sc_openf > 0) 8104744Swnj tj_softc[tjunit].sc_openf = -1; 8114744Swnj } 8124744Swnj utstart(um); 8134744Swnj } 8144744Swnj } 8154744Swnj 8164744Swnj /* 8174744Swnj * Do a stand-alone core dump to tape -- 8184744Swnj * from here down, routines are used only in dump context 8194744Swnj */ 8204744Swnj #define DBSIZE 20 8214744Swnj 8224744Swnj utdump() 8234744Swnj { 8244744Swnj register struct uba_device *ui; 8254744Swnj register struct uba_regs *up; 8264746Ssam register struct utdevice *addr; 8274744Swnj int blk, num = maxfree; 8284744Swnj int start = 0; 8294744Swnj 8304744Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8314744Swnj if (tjdinfo[0] == 0) 8324744Swnj return (ENXIO); 8334744Swnj ui = phys(tjdinfo[0], struct uba_device *); 8344744Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8354941Swnj ubainit(up); 8364744Swnj DELAY(1000000); 8374941Swnj addr = (struct utdevice *)ui->ui_physaddr; 8384746Ssam utwait(addr); 8394746Ssam /* 8404746Ssam * Be sure to set the appropriate density here. We use 8414746Ssam * 6250, but maybe it should be done at 1600 to insure the 8424746Ssam * tape can be read by most any other tape drive available. 8434746Ssam */ 8444746Ssam addr->uttc = UT_GCR|PDP11FMT; /* implicit slave 0 or-ed in */ 8454746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 8464744Swnj while (num > 0) { 8474744Swnj blk = num > DBSIZE ? DBSIZE : num; 8484746Ssam utdwrite(start, blk, addr, up); 8494746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8504746Ssam return(EIO); 8514744Swnj start += blk; 8524744Swnj num -= blk; 8534744Swnj } 8544746Ssam uteof(addr); 8554746Ssam uteof(addr); 8564746Ssam utwait(addr); 8574746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8584744Swnj return(EIO); 8594746Ssam addr->utcs1 = UT_REW|UT_GO; 8604744Swnj return (0); 8614744Swnj } 8624744Swnj 8634746Ssam utdwrite(dbuf, num, addr, up) 8644744Swnj register dbuf, num; 8654746Ssam register struct utdevice *addr; 8664744Swnj struct uba_regs *up; 8674744Swnj { 8684744Swnj register struct pte *io; 8694744Swnj register int npf; 8704744Swnj 8714746Ssam utwait(addr); 8724744Swnj io = up->uba_map; 8734744Swnj npf = num + 1; 8744744Swnj while (--npf != 0) 8754744Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 8764744Swnj *(int *)io = 0; 8774746Ssam addr->utwc = -((num*NBPG)>>1); 8784746Ssam addr->utfc = -(num*NBPG); 8794746Ssam addr->utba = 0; 8804746Ssam addr->utcs1 = UT_WCOM|UT_GO; 8814744Swnj } 8824744Swnj 8834746Ssam utwait(addr) 8844746Ssam struct utdevice *addr; 8854744Swnj { 8864744Swnj register s; 8874744Swnj 8884744Swnj do 8894746Ssam s = addr->utds; 8904744Swnj while ((s&UTDS_DRY) == 0); 8914744Swnj } 8924744Swnj 8934746Ssam uteof(addr) 8944746Ssam struct utdevice *addr; 8954744Swnj { 8964744Swnj 8974746Ssam utwait(addr); 8984746Ssam addr->utcs1 = UT_WEOF|UT_GO; 8994744Swnj } 9004744Swnj #endif 901