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*30917Skarels * @(#)ut.c 7.2 (Berkeley) 04/17/87 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 "dir.h" 2417083Sbloom #include "file.h" 2517083Sbloom #include "user.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" 33*30917Skarels #include "syslog.h" 344744Swnj 35*30917Skarels #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 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 */ 79*30917Skarels int sc_blks; /* number of I/O operations since open */ 80*30917Skarels int sc_softerrs; /* number of soft I/O errors since open */ 814744Swnj } tj_softc[NTJ]; 824744Swnj 834744Swnj /* 844744Swnj * Internal per/slave states found in sc_state 854744Swnj */ 864744Swnj #define SSEEK 1 /* seeking */ 874744Swnj #define SIO 2 /* doing sequential I/O */ 884744Swnj #define SCOM 3 /* sending a control command */ 894744Swnj #define SREW 4 /* doing a rewind op */ 904746Ssam #define SERASE 5 /* erase inter-record gap */ 914746Ssam #define SERASED 6 /* erased inter-record gap */ 924744Swnj 934941Swnj /*ARGSUSED*/ 944744Swnj utprobe(reg) 954744Swnj caddr_t reg; 964744Swnj { 974744Swnj register int br, cvec; 984744Swnj #ifdef lint 994744Swnj br=0; cvec=br; br=cvec; 1004941Swnj utintr(0); 1014744Swnj #endif 1024746Ssam /* 1036954Sroot * The SI documentation says you must set the RDY bit 1046954Sroot * (even though it's read-only) to force an interrupt. 1054746Ssam */ 1066954Sroot ((struct utdevice *) reg)->utcs1 = UT_IE|UT_NOP|UT_RDY; 1074744Swnj DELAY(10000); 1087405Skre return (sizeof (struct utdevice)); 1094744Swnj } 1104744Swnj 1114744Swnj /*ARGSUSED*/ 1124744Swnj utslave(ui, reg) 1134744Swnj struct uba_device *ui; 1144744Swnj caddr_t reg; 1154744Swnj { 1164744Swnj /* 1174744Swnj * A real TU45 would support the slave present bit 1184744Swnj * int the drive type register, but this thing doesn't, 1194744Swnj * so there's no way to determine if a slave is present or not. 1204744Swnj */ 1214744Swnj return(1); 1224744Swnj } 1234744Swnj 1244744Swnj utattach(ui) 1254744Swnj struct uba_device *ui; 1264744Swnj { 1274744Swnj tjtout[ui->ui_unit] = ui->ui_mi->um_ctlr; 1284744Swnj } 1294744Swnj 1304744Swnj /* 1314744Swnj * Open the device with exclusive access. 1324744Swnj */ 1334744Swnj utopen(dev, flag) 1344744Swnj dev_t dev; 1354744Swnj int flag; 1364744Swnj { 1374744Swnj register int tjunit = TJUNIT(dev); 1384744Swnj register struct uba_device *ui; 1394744Swnj register struct tj_softc *sc; 1404744Swnj int olddens, dens; 1415439Sroot register int s; 1424744Swnj 14325053Skarels if (tjunit >= NTJ || (ui = tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 1448577Sroot return (ENXIO); 14525053Skarels if ((sc = &tj_softc[tjunit])->sc_openf) 14625053Skarels return (EBUSY); 147*30917Skarels sc->sc_openf = 1; 1484744Swnj olddens = sc->sc_dens; 1498577Sroot dens = sc->sc_dens = 1508577Sroot utdens[(minor(dev)&(T_1600BPI|T_6250BPI))>>3]| 1518577Sroot PDP11FMT|(ui->ui_slave&07); 1524744Swnj get: 1534744Swnj utcommand(dev, UT_SENSE, 1); 1544744Swnj if (sc->sc_dsreg&UTDS_PIP) { 1559174Ssam sleep((caddr_t)&lbolt, PZERO+1); 1564744Swnj goto get; 1574744Swnj } 1584744Swnj sc->sc_dens = olddens; 1594744Swnj if ((sc->sc_dsreg&UTDS_MOL) == 0) { 160*30917Skarels sc->sc_openf = 0; 1614744Swnj uprintf("tj%d: not online\n", tjunit); 1628577Sroot return (EIO); 1634744Swnj } 1644744Swnj if ((flag&FWRITE) && (sc->sc_dsreg&UTDS_WRL)) { 165*30917Skarels sc->sc_openf = 0; 1664744Swnj uprintf("tj%d: no write ring\n", tjunit); 1678577Sroot return (EIO); 1684744Swnj } 1694744Swnj if ((sc->sc_dsreg&UTDS_BOT) == 0 && (flag&FWRITE) && 1704744Swnj dens != sc->sc_dens) { 171*30917Skarels sc->sc_openf = 0; 1724744Swnj uprintf("tj%d: can't change density in mid-tape\n", tjunit); 1738577Sroot return (EIO); 1744744Swnj } 1754744Swnj sc->sc_blkno = (daddr_t)0; 1764744Swnj sc->sc_nxrec = INF; 1774744Swnj sc->sc_lastiow = 0; 178*30917Skarels sc->sc_blks = 0; 179*30917Skarels sc->sc_softerrs = 0; 1804744Swnj sc->sc_dens = dens; 18118323Sralph sc->sc_ttyp = u.u_ttyp; 1824746Ssam /* 1834746Ssam * For 6250 bpi take exclusive use of the UNIBUS. 1844746Ssam */ 1854746Ssam ui->ui_driver->ud_xclu = (dens&(T_1600BPI|T_6250BPI)) == T_6250BPI; 18626374Skarels s = splclock(); 1874833Swnj if (sc->sc_tact == 0) { 1884833Swnj sc->sc_timo = INF; 1894833Swnj sc->sc_tact = 1; 1904833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 1914833Swnj } 1925439Sroot splx(s); 1938577Sroot return (0); 1944744Swnj } 1954744Swnj 1964744Swnj utclose(dev, flag) 1974744Swnj register dev_t dev; 1984744Swnj register flag; 1994744Swnj { 2004744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 2014744Swnj 2024744Swnj if (flag == FWRITE || ((flag&FWRITE) && sc->sc_lastiow)) { 2034744Swnj utcommand(dev, UT_WEOF, 1); 2044744Swnj utcommand(dev, UT_WEOF, 1); 2054744Swnj utcommand(dev, UT_SREV, 1); 2064744Swnj } 2074744Swnj if ((minor(dev)&T_NOREWIND) == 0) 2084744Swnj utcommand(dev, UT_REW, 0); 209*30917Skarels if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 210*30917Skarels log(LOG_INFO, "tj%d: %d soft errors in %d blocks\n", 211*30917Skarels TJUNIT(dev), sc->sc_softerrs, sc->sc_blks); 2124744Swnj sc->sc_openf = 0; 2134744Swnj } 2144744Swnj 2154744Swnj utcommand(dev, com, count) 2164744Swnj dev_t dev; 2174744Swnj int com, count; 2184744Swnj { 2194744Swnj register struct buf *bp; 2205439Sroot register int s; 2214744Swnj 2224744Swnj bp = &cutbuf[UTUNIT(dev)]; 2235439Sroot s = spl5(); 2244744Swnj while (bp->b_flags&B_BUSY) { 2254744Swnj if(bp->b_repcnt == 0 && (bp->b_flags&B_DONE)) 2264744Swnj break; 2274744Swnj bp->b_flags |= B_WANTED; 2284744Swnj sleep((caddr_t)bp, PRIBIO); 2294744Swnj } 2304744Swnj bp->b_flags = B_BUSY|B_READ; 2315439Sroot splx(s); 2324744Swnj bp->b_dev = dev; 2334744Swnj bp->b_command = com; 2344744Swnj bp->b_repcnt = count; 2354744Swnj bp->b_blkno = 0; 2364744Swnj utstrategy(bp); 2374744Swnj if (count == 0) 2384744Swnj return; 2394744Swnj iowait(bp); 2404744Swnj if (bp->b_flags&B_WANTED) 2414744Swnj wakeup((caddr_t)bp); 2424744Swnj bp->b_flags &= B_ERROR; 2434744Swnj } 2444744Swnj 2454744Swnj /* 2464744Swnj * Queue a tape operation. 2474744Swnj */ 2484744Swnj utstrategy(bp) 2494744Swnj register struct buf *bp; 2504744Swnj { 2514744Swnj int tjunit = TJUNIT(bp->b_dev); 2524744Swnj register struct uba_ctlr *um; 2534744Swnj register struct buf *dp; 2544744Swnj 2554744Swnj /* 2564744Swnj * Put transfer at end of unit queue 2574744Swnj */ 2584744Swnj dp = &tjutab[tjunit]; 2594744Swnj bp->av_forw = NULL; 26017433Skarels um = tjdinfo[tjunit]->ui_mi; 2614744Swnj (void) spl5(); 2624744Swnj if (dp->b_actf == NULL) { 2634744Swnj dp->b_actf = bp; 2644744Swnj /* 2654744Swnj * Transport not active, so... 2664744Swnj * put at end of controller queue 2674744Swnj */ 2684744Swnj dp->b_forw = NULL; 2694744Swnj if (um->um_tab.b_actf == NULL) 2704744Swnj um->um_tab.b_actf = dp; 2714744Swnj else 2724744Swnj um->um_tab.b_actl->b_forw = dp; 2734744Swnj um->um_tab.b_actl = dp; 2744744Swnj } else 2754744Swnj dp->b_actl->av_forw = bp; 2764744Swnj dp->b_actl = bp; 2774744Swnj /* 2784744Swnj * If the controller is not busy, set it going. 2794744Swnj */ 2804746Ssam if (um->um_tab.b_state == 0) 2814744Swnj utstart(um); 2824744Swnj (void) spl0(); 2834744Swnj } 2844744Swnj 2854744Swnj utstart(um) 2864744Swnj register struct uba_ctlr *um; 2874744Swnj { 2884746Ssam register struct utdevice *addr; 2894744Swnj register struct buf *bp, *dp; 2904744Swnj register struct tj_softc *sc; 2914744Swnj struct uba_device *ui; 2924744Swnj int tjunit; 2934744Swnj daddr_t blkno; 2944744Swnj 2954744Swnj loop: 2964744Swnj /* 2974744Swnj * Scan controller queue looking for units with 2984744Swnj * transaction queues to dispatch 2994744Swnj */ 3004744Swnj if ((dp = um->um_tab.b_actf) == NULL) 3014744Swnj return; 3024744Swnj if ((bp = dp->b_actf) == NULL) { 3034744Swnj um->um_tab.b_actf = dp->b_forw; 3044744Swnj goto loop; 3054744Swnj } 3064746Ssam addr = (struct utdevice *)um->um_addr; 3074744Swnj tjunit = TJUNIT(bp->b_dev); 3084744Swnj ui = tjdinfo[tjunit]; 3094744Swnj sc = &tj_softc[tjunit]; 3104744Swnj /* note slave select, density, and format were merged on open */ 3114746Ssam addr->uttc = sc->sc_dens; 3124746Ssam sc->sc_dsreg = addr->utds; 3134746Ssam sc->sc_erreg = addr->uter; 31411176Ssam sc->sc_resid = MASKREG(addr->utfc); 3154744Swnj /* 3164744Swnj * Default is that last command was NOT a write command; 3174744Swnj * if we do a write command we will notice this in utintr(). 3184744Swnj */ 3194744Swnj sc->sc_lastiow = 0; 3204746Ssam if (sc->sc_openf < 0 || (addr->utds&UTDS_MOL) == 0) { 3214744Swnj /* 3224744Swnj * Have had a hard error on a non-raw tape 3234744Swnj * or the tape unit is now unavailable 3244744Swnj * (e.g. taken off line). 3254744Swnj */ 3264744Swnj bp->b_flags |= B_ERROR; 3274744Swnj goto next; 3284744Swnj } 3294744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 3304744Swnj /* 3314744Swnj * Execute a control operation with the specified 3324744Swnj * count. 3334744Swnj */ 3344744Swnj if (bp->b_command == UT_SENSE) 3354744Swnj goto next; 33611176Ssam if (bp->b_command == UT_SFORW && (addr->utds & UTDS_EOT)) { 33711176Ssam bp->b_resid = bp->b_bcount; 33811176Ssam goto next; 33911176Ssam } 3404744Swnj /* 3414744Swnj * Set next state; handle timeouts 3424744Swnj */ 3434833Swnj if (bp->b_command == UT_REW) { 3444746Ssam um->um_tab.b_state = SREW; 3454833Swnj sc->sc_timo = 5*60; 3464833Swnj } else { 3474746Ssam um->um_tab.b_state = SCOM; 3484833Swnj sc->sc_timo = imin(imax(10*(int)-bp->b_repcnt,60),5*60); 3494833Swnj } 3504744Swnj /* NOTE: this depends on the ut command values */ 3514744Swnj if (bp->b_command >= UT_SFORW && bp->b_command <= UT_SREVF) 3524746Ssam addr->utfc = -bp->b_repcnt; 3534744Swnj goto dobpcmd; 3544744Swnj } 3554744Swnj /* 3564744Swnj * The following checks boundary conditions for operations 3574744Swnj * on non-raw tapes. On raw tapes the initialization of 3584744Swnj * sc->sc_nxrec by utphys causes them to be skipped normally 3594744Swnj * (except in the case of retries). 3604744Swnj */ 3617382Ssam if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 3624744Swnj /* can't read past end of file */ 3634744Swnj bp->b_flags |= B_ERROR; 3644744Swnj bp->b_error = ENXIO; 3654744Swnj goto next; 3664744Swnj } 3677382Ssam if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && (bp->b_flags&B_READ)) { 3684744Swnj /* read at eof returns 0 count */ 3694744Swnj bp->b_resid = bp->b_bcount; 3704744Swnj clrbuf(bp); 3714744Swnj goto next; 3724744Swnj } 3734744Swnj if ((bp->b_flags&B_READ) == 0) 3747382Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno)+1; 3754744Swnj /* 3764744Swnj * If the tape is correctly positioned, set up all the 3774744Swnj * registers but the csr, and give control over to the 3784744Swnj * UNIBUS adaptor routines, to wait for resources to 3794744Swnj * start I/O. 3804744Swnj */ 3817382Ssam if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3824746Ssam addr->utwc = -(((bp->b_bcount)+1)>>1); 3834746Ssam addr->utfc = -bp->b_bcount; 3844744Swnj if ((bp->b_flags&B_READ) == 0) { 3854744Swnj /* 3864744Swnj * On write error retries erase the 3874746Ssam * inter-record gap before rewriting. 3884744Swnj */ 3894746Ssam if (um->um_tab.b_errcnt) { 3904746Ssam if (um->um_tab.b_state != SERASED) { 3914759Swnj um->um_tab.b_state = SERASE; 3924833Swnj sc->sc_timo = 60; 3934746Ssam addr->utcs1 = UT_ERASE|UT_IE|UT_GO; 3944746Ssam return; 3954746Ssam } 3964746Ssam } 39711176Ssam if (addr->utds & UTDS_EOT) { 39811176Ssam bp->b_resid = bp->b_bcount; 39911176Ssam um->um_tab.b_state = 0; 40011176Ssam goto next; 40111176Ssam } 4024746Ssam um->um_cmd = UT_WCOM; 4034744Swnj } else 4044744Swnj um->um_cmd = UT_RCOM; 4054833Swnj sc->sc_timo = 60; 4064746Ssam um->um_tab.b_state = SIO; 4074744Swnj (void) ubago(ui); 4084744Swnj return; 4094744Swnj } 4104744Swnj /* 4114744Swnj * Tape positioned incorrectly; seek forwards or 4124744Swnj * backwards to the correct spot. This happens for 4134744Swnj * raw tapes only on error retries. 4144744Swnj */ 4154746Ssam um->um_tab.b_state = SSEEK; 4167382Ssam if (blkno < bdbtofsb(bp->b_blkno)) { 4177382Ssam addr->utfc = blkno - bdbtofsb(bp->b_blkno); 4184744Swnj bp->b_command = UT_SFORW; 4194744Swnj } else { 4207382Ssam addr->utfc = bdbtofsb(bp->b_blkno) - blkno; 4214744Swnj bp->b_command = UT_SREV; 4224744Swnj } 4234833Swnj sc->sc_timo = imin(imax(10 * -addr->utfc, 60), 5*60); 4244744Swnj 4254744Swnj dobpcmd: 4264744Swnj /* 4274744Swnj * Perform the command setup in bp. 4284744Swnj */ 4294746Ssam addr->utcs1 = bp->b_command|UT_IE|UT_GO; 4304744Swnj return; 4314744Swnj next: 4324744Swnj /* 4334744Swnj * Advance to the next command in the slave queue, 4344744Swnj * posting notice and releasing resources as needed. 4354744Swnj */ 4364744Swnj if (um->um_ubinfo) 4374744Swnj ubadone(um); 4384744Swnj um->um_tab.b_errcnt = 0; 4394744Swnj dp->b_actf = bp->av_forw; 4404744Swnj iodone(bp); 4414744Swnj goto loop; 4424744Swnj } 4434744Swnj 4444744Swnj /* 4454744Swnj * Start operation on controller -- 4464744Swnj * UNIBUS resources have been allocated. 4474744Swnj */ 4484744Swnj utdgo(um) 4494744Swnj register struct uba_ctlr *um; 4504744Swnj { 4514744Swnj register struct utdevice *addr = (struct utdevice *)um->um_addr; 4524744Swnj 4534744Swnj addr->utba = (u_short) um->um_ubinfo; 45411176Ssam addr->utcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300)|UT_IE|UT_GO; 4554744Swnj } 4564744Swnj 4574744Swnj /* 4584744Swnj * Ut interrupt handler 4594744Swnj */ 4604744Swnj /*ARGSUSED*/ 4614744Swnj utintr(ut11) 4624744Swnj int ut11; 4634744Swnj { 4644744Swnj struct buf *dp; 4654744Swnj register struct buf *bp; 4664744Swnj register struct uba_ctlr *um = utminfo[ut11]; 4674744Swnj register struct utdevice *addr; 4684744Swnj register struct tj_softc *sc; 4694746Ssam u_short tjunit, cs2, cs1; 4704744Swnj register state; 4714744Swnj 4724744Swnj if ((dp = um->um_tab.b_actf) == NULL) 4734744Swnj return; 4744744Swnj bp = dp->b_actf; 4754744Swnj tjunit = TJUNIT(bp->b_dev); 4764744Swnj addr = (struct utdevice *)tjdinfo[tjunit]->ui_addr; 4774744Swnj sc = &tj_softc[tjunit]; 4784744Swnj /* 4794744Swnj * Record status... 4804744Swnj */ 4814877Ssam sc->sc_timo = INF; 4824744Swnj sc->sc_dsreg = addr->utds; 4834744Swnj sc->sc_erreg = addr->uter; 48411176Ssam sc->sc_resid = MASKREG(addr->utfc); 4854746Ssam if ((bp->b_flags&B_READ) == 0) 4864744Swnj sc->sc_lastiow = 1; 4874746Ssam state = um->um_tab.b_state; 4884746Ssam um->um_tab.b_state = 0; 4894744Swnj /* 4904744Swnj * Check for errors... 4914744Swnj */ 4924744Swnj if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) { 4934744Swnj /* 4944759Swnj * To clear the ERR bit, we must issue a drive clear 4954759Swnj * command, and to clear the TRE bit we must set the 4964759Swnj * controller clear bit. 4974759Swnj */ 4984759Swnj cs2 = addr->utcs2; 4994759Swnj if ((cs1 = addr->utcs1)&UT_TRE) 5004759Swnj addr->utcs2 |= UTCS2_CLR; 5014759Swnj /* is this dangerous ?? */ 5024759Swnj while ((addr->utcs1&UT_RDY) == 0) 5034759Swnj ; 5044759Swnj addr->utcs1 = UT_CLEAR|UT_GO; 5054759Swnj /* 50611176Ssam * If we were reading at 1600 or 6250 bpi and the error 50711176Ssam * was corrected, then don't consider this an error. 5084744Swnj */ 50911190Ssam if (sc->sc_erreg & UTER_COR && (bp->b_flags & B_READ) && 51011176Ssam (addr->uttc & UTTC_DEN) != UT_NRZI) { 51118323Sralph tprintf(sc->sc_ttyp, 51211176Ssam "ut%d: soft error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 51311176Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 51411176Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 51511176Ssam sc->sc_erreg &= ~UTER_COR; 5164744Swnj } 5174744Swnj /* 5184744Swnj * If we were reading from a raw tape and the only error 5194744Swnj * was that the record was too long, then we don't consider 5204744Swnj * this an error. 5214744Swnj */ 5224744Swnj if (bp == &rutbuf[UTUNIT(bp->b_dev)] && (bp->b_flags&B_READ) && 5234744Swnj (sc->sc_erreg&UTER_FCE)) 52411176Ssam sc->sc_erreg &= ~UTER_FCE; 52511197Slayer if (sc->sc_erreg == 0) 5264744Swnj goto ignoreerr; 5274744Swnj /* 52811176Ssam * Fix up errors which occur due to backspacing 52911176Ssam * "over" the front of the tape. 5304746Ssam */ 53111176Ssam if ((sc->sc_dsreg & UTDS_BOT) && bp->b_command == UT_SREV && 5324746Ssam ((sc->sc_erreg &= ~(UTER_NEF|UTER_FCE)) == 0)) 5334746Ssam goto opdone; 5344746Ssam /* 5354744Swnj * Retry soft errors up to 8 times 5364744Swnj */ 5374744Swnj if ((sc->sc_erreg&UTER_HARD) == 0 && state == SIO) { 5384744Swnj if (++um->um_tab.b_errcnt < 7) { 5394744Swnj sc->sc_blkno++; 5404744Swnj ubadone(um); 5414744Swnj goto opcont; 5424744Swnj } 54311176Ssam } 5444744Swnj /* 54511176Ssam * Hard or non-I/O errors on non-raw tape 54611176Ssam * cause it to close. 54711176Ssam */ 54811176Ssam if (sc->sc_openf > 0 && bp != &rutbuf[UTUNIT(bp->b_dev)]) 54911176Ssam sc->sc_openf = -1; 55011176Ssam /* 5514744Swnj * Couldn't recover error. 5524744Swnj */ 55318323Sralph tprintf(sc->sc_ttyp, 55418323Sralph "ut%d: hard error bn%d cs1=%b er=%b cs2=%b ds=%b\n", 5554746Ssam tjunit, bp->b_blkno, cs1, UT_BITS, sc->sc_erreg, 5564746Ssam UTER_BITS, cs2, UTCS2_BITS, sc->sc_dsreg, UTDS_BITS); 5574744Swnj bp->b_flags |= B_ERROR; 5584744Swnj goto opdone; 5594744Swnj } 56011176Ssam 5614744Swnj ignoreerr: 5624744Swnj /* 56311176Ssam * If we hit a tape mark update our position. 56411176Ssam */ 56511176Ssam if (sc->sc_dsreg & UTDS_TM && bp->b_flags & B_READ) { 56611176Ssam /* 56711176Ssam * Set blkno and nxrec 56811176Ssam */ 56911176Ssam if (bp == &cutbuf[UTUNIT(bp->b_dev)]) { 57011176Ssam if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 57111176Ssam sc->sc_nxrec = 57211176Ssam bdbtofsb(bp->b_blkno) - addr->utfc; 57311176Ssam sc->sc_blkno = sc->sc_nxrec; 57411176Ssam } else { 57511176Ssam sc->sc_blkno = 57611176Ssam bdbtofsb(bp->b_blkno) + addr->utfc; 57711176Ssam sc->sc_nxrec = sc->sc_blkno-1; 57811176Ssam } 57911176Ssam } else 58011176Ssam sc->sc_nxrec = bdbtofsb(bp->b_blkno); 58111176Ssam /* 58211176Ssam * Note: if we get a tape mark on a read, the 58311176Ssam * frame count register will be zero, so b_resid 58411176Ssam * will be calculated correctly below. 58511176Ssam */ 58611176Ssam goto opdone; 58711176Ssam } 58811176Ssam /* 5894744Swnj * Advance tape control FSM. 5904744Swnj */ 5914744Swnj switch (state) { 5924744Swnj 5934744Swnj case SIO: /* read/write increments tape block # */ 5944744Swnj sc->sc_blkno++; 595*30917Skarels sc->sc_blks++; 596*30917Skarels if (um->um_tab.b_errcnt) 597*30917Skarels sc->sc_softerrs++; 5984746Ssam break; 5994744Swnj 60011176Ssam case SCOM: /* motion commands update current position */ 6014744Swnj if (bp == &cutbuf[UTUNIT(bp->b_dev)]) 60226296Skarels switch ((int)bp->b_command) { 6034744Swnj 6044744Swnj case UT_SFORW: 6054744Swnj sc->sc_blkno -= bp->b_repcnt; 6064744Swnj break; 6074744Swnj 6084744Swnj case UT_SREV: 6094744Swnj sc->sc_blkno += bp->b_repcnt; 6104744Swnj break; 61111176Ssam 61211176Ssam case UT_REWOFFL: 61311176Ssam addr->utcs1 = UT_CLEAR|UT_GO; 61411176Ssam break; 6154744Swnj } 6164746Ssam break; 6174744Swnj 6184744Swnj case SSEEK: 6197382Ssam sc->sc_blkno = bdbtofsb(bp->b_blkno); 6204744Swnj goto opcont; 6214744Swnj 6224746Ssam case SERASE: 6234746Ssam /* 6244746Ssam * Completed erase of the inter-record gap due to a 6254746Ssam * write error; now retry the write operation. 6264746Ssam */ 6274746Ssam um->um_tab.b_state = SERASED; 6284746Ssam goto opcont; 6294746Ssam 6304746Ssam case SREW: /* clear attention bit */ 6314746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 6324746Ssam break; 6334746Ssam 6344744Swnj default: 6354746Ssam printf("bad state %d\n", state); 6364744Swnj panic("utintr"); 6374744Swnj } 6384744Swnj 6394744Swnj opdone: 6404744Swnj /* 6414744Swnj * Reset error count and remove 6424744Swnj * from device queue 6434744Swnj */ 6444744Swnj um->um_tab.b_errcnt = 0; 6454746Ssam dp->b_actf = bp->av_forw; 64611176Ssam /* 64711176Ssam * For read command, frame count register contains 64811176Ssam * actual length of tape record. Otherwise, it 64911176Ssam * holds negative residual count. 65011176Ssam */ 65111176Ssam if (state == SIO && um->um_cmd == UT_RCOM) { 65211176Ssam bp->b_resid = 0; 65311176Ssam if (bp->b_bcount > MASKREG(addr->utfc)) 65411176Ssam bp->b_resid = bp->b_bcount - MASKREG(addr->utfc); 65511176Ssam } else 65611176Ssam bp->b_resid = MASKREG(-addr->utfc); 6574744Swnj ubadone(um); 6584744Swnj iodone(bp); 6594744Swnj /* 6604744Swnj * Circulate slave to end of controller queue 6614744Swnj * to give other slaves a chance 6624744Swnj */ 6634744Swnj um->um_tab.b_actf = dp->b_forw; 6644744Swnj if (dp->b_actf) { 6654744Swnj dp->b_forw = NULL; 6664744Swnj if (um->um_tab.b_actf == NULL) 6674744Swnj um->um_tab.b_actf = dp; 6684744Swnj else 6694744Swnj um->um_tab.b_actl->b_forw = dp; 6704744Swnj um->um_tab.b_actl = dp; 6714744Swnj } 6724744Swnj if (um->um_tab.b_actf == 0) 6734744Swnj return; 6744744Swnj opcont: 6754744Swnj utstart(um); 6764744Swnj } 6774744Swnj 6784744Swnj /* 6794833Swnj * Watchdog timer routine. 6804833Swnj */ 6814833Swnj uttimer(dev) 6824833Swnj int dev; 6834833Swnj { 6844833Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 6854846Sroot register short x; 6864833Swnj 6874833Swnj if (sc->sc_timo != INF && (sc->sc_timo -= 5) < 0) { 6884859Ssam printf("tj%d: lost interrupt\n", TJUNIT(dev)); 6894833Swnj sc->sc_timo = INF; 6904846Sroot x = spl5(); 6914833Swnj utintr(UTUNIT(dev)); 6924846Sroot (void) splx(x); 6934833Swnj } 6944833Swnj timeout(uttimer, (caddr_t)dev, 5*hz); 6954833Swnj } 6964833Swnj 6974833Swnj /* 6984744Swnj * Raw interface for a read 6994744Swnj */ 7007736Sroot utread(dev, uio) 7014744Swnj dev_t dev; 7027736Sroot struct uio *uio; 7034744Swnj { 7048167Sroot int errno; 7057736Sroot 7068167Sroot errno = utphys(dev, uio); 7078167Sroot if (errno) 7088167Sroot return (errno); 7098167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_READ, minphys, uio)); 7104744Swnj } 7114744Swnj 7124744Swnj /* 7134744Swnj * Raw interface for a write 7144744Swnj */ 7157847Sroot utwrite(dev, uio) 7167736Sroot dev_t dev; 7177847Sroot struct uio *uio; 7184744Swnj { 7198167Sroot int errno; 7208167Sroot 7218167Sroot errno = utphys(dev, uio); 7228167Sroot if (errno) 7238167Sroot return (errno); 7248167Sroot return (physio(utstrategy, &rutbuf[UTUNIT(dev)], dev, B_WRITE, minphys, uio)); 7254744Swnj } 7264744Swnj 7274744Swnj /* 7284744Swnj * Check for valid device number dev and update our notion 7294744Swnj * of where we are on the tape 7304744Swnj */ 7317736Sroot utphys(dev, uio) 7324744Swnj dev_t dev; 7337736Sroot struct uio *uio; 7344744Swnj { 7354744Swnj register int tjunit = TJUNIT(dev); 7364744Swnj register struct tj_softc *sc; 7374744Swnj register struct uba_device *ui; 7384744Swnj 7397847Sroot if (tjunit >= NTJ || (ui=tjdinfo[tjunit]) == 0 || ui->ui_alive == 0) 7407847Sroot return (ENXIO); 7414744Swnj sc = &tj_softc[tjunit]; 7427847Sroot sc->sc_blkno = bdbtofsb(uio->uio_offset>>9); 7434746Ssam sc->sc_nxrec = sc->sc_blkno+1; 7447847Sroot return (0); 7454744Swnj } 7464744Swnj 7474744Swnj /*ARGSUSED*/ 7487634Ssam utioctl(dev, cmd, data, flag) 7494744Swnj dev_t dev; 7507634Ssam caddr_t data; 7514744Swnj { 7524744Swnj register struct tj_softc *sc = &tj_softc[TJUNIT(dev)]; 7534744Swnj register struct buf *bp = &cutbuf[UTUNIT(dev)]; 7544744Swnj register callcount; 7554744Swnj int fcount; 7567634Ssam struct mtop *mtop; 7577634Ssam struct mtget *mtget; 7584744Swnj /* we depend of the values and order of the MT codes here */ 7594744Swnj static utops[] = 7604744Swnj {UT_WEOF,UT_SFORWF,UT_SREVF,UT_SFORW,UT_SREV,UT_REW,UT_REWOFFL,UT_SENSE}; 7614744Swnj 7624744Swnj switch (cmd) { 7634744Swnj 7644744Swnj case MTIOCTOP: 7657634Ssam mtop = (struct mtop *)data; 7667634Ssam switch(mtop->mt_op) { 7674744Swnj 7684744Swnj case MTWEOF: 76911413Ssam case MTFSF: case MTBSF: 77011413Ssam case MTFSR: case MTBSR: 7717634Ssam callcount = mtop->mt_count; 7724744Swnj fcount = 1; 7734744Swnj break; 7744744Swnj 7754744Swnj case MTREW: case MTOFFL: case MTNOP: 7764744Swnj callcount = 1; 7774744Swnj fcount = 1; 7784744Swnj break; 7794744Swnj 7804744Swnj default: 7818577Sroot return (ENXIO); 7824744Swnj } 7838577Sroot if (callcount <= 0 || fcount <= 0) 7848577Sroot return (EINVAL); 7854744Swnj while (--callcount >= 0) { 7867634Ssam utcommand(dev, utops[mtop->mt_op], fcount); 7874744Swnj if ((bp->b_flags&B_ERROR) || (sc->sc_dsreg&UTDS_BOT)) 7884744Swnj break; 7894744Swnj } 7908650Sroot return (geterror(bp)); 7914744Swnj 7924744Swnj case MTIOCGET: 7937634Ssam mtget = (struct mtget *)data; 7947634Ssam mtget->mt_dsreg = sc->sc_dsreg; 7957634Ssam mtget->mt_erreg = sc->sc_erreg; 7967634Ssam mtget->mt_resid = sc->sc_resid; 7977634Ssam mtget->mt_type = MT_ISUT; 7988577Sroot break; 7994744Swnj 8004744Swnj default: 8018577Sroot return (ENXIO); 8024744Swnj } 8038577Sroot return (0); 8044744Swnj } 8054744Swnj 8064744Swnj utreset(uban) 8074744Swnj int uban; 8084744Swnj { 8094744Swnj register struct uba_ctlr *um; 8104744Swnj register ut11, tjunit; 8114744Swnj register struct uba_device *ui; 8124744Swnj register struct buf *dp; 8134744Swnj 8144744Swnj for (ut11 = 0; ut11 < NUT; ut11++) { 8154744Swnj if ((um = utminfo[ut11]) == 0 || um->um_alive == 0 || 8164744Swnj um->um_ubanum != uban) 8174744Swnj continue; 8184744Swnj printf(" ut%d", ut11); 8194746Ssam um->um_tab.b_state = 0; 8204744Swnj um->um_tab.b_actf = um->um_tab.b_actl = 0; 8214744Swnj if (um->um_ubinfo) { 8224744Swnj printf("<%d>", (um->um_ubinfo>>28)&0xf); 8239358Ssam um->um_ubinfo = 0; 8244744Swnj } 8254744Swnj ((struct utdevice *)(um->um_addr))->utcs1 = UT_CLEAR|UT_GO; 8264746Ssam ((struct utdevice *)(um->um_addr))->utcs2 |= UTCS2_CLR; 8274744Swnj for (tjunit = 0; tjunit < NTJ; tjunit++) { 8284744Swnj if ((ui = tjdinfo[tjunit]) == 0 || ui->ui_mi != um || 8294744Swnj ui->ui_alive == 0) 8304744Swnj continue; 8314744Swnj dp = &tjutab[tjunit]; 8324746Ssam dp->b_state = 0; 8334744Swnj dp->b_forw = 0; 8344744Swnj if (um->um_tab.b_actf == NULL) 8354744Swnj um->um_tab.b_actf = dp; 8364744Swnj else 8374744Swnj um->um_tab.b_actl->b_forw = dp; 8384744Swnj um->um_tab.b_actl = dp; 8394744Swnj if (tj_softc[tjunit].sc_openf > 0) 8404744Swnj tj_softc[tjunit].sc_openf = -1; 8414744Swnj } 8424744Swnj utstart(um); 8434744Swnj } 8444744Swnj } 8454744Swnj 8464744Swnj /* 8474744Swnj * Do a stand-alone core dump to tape -- 8484744Swnj * from here down, routines are used only in dump context 8494744Swnj */ 8504744Swnj #define DBSIZE 20 8514744Swnj 8524744Swnj utdump() 8534744Swnj { 8544744Swnj register struct uba_device *ui; 8554744Swnj register struct uba_regs *up; 8564746Ssam register struct utdevice *addr; 8574744Swnj int blk, num = maxfree; 8584744Swnj int start = 0; 8594744Swnj 8604744Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 8614744Swnj if (tjdinfo[0] == 0) 8624744Swnj return (ENXIO); 8634744Swnj ui = phys(tjdinfo[0], struct uba_device *); 8644744Swnj up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba; 8654941Swnj ubainit(up); 8664744Swnj DELAY(1000000); 8674941Swnj addr = (struct utdevice *)ui->ui_physaddr; 8684746Ssam utwait(addr); 8694746Ssam /* 8704746Ssam * Be sure to set the appropriate density here. We use 8714746Ssam * 6250, but maybe it should be done at 1600 to insure the 8724746Ssam * tape can be read by most any other tape drive available. 8734746Ssam */ 8744746Ssam addr->uttc = UT_GCR|PDP11FMT; /* implicit slave 0 or-ed in */ 8754746Ssam addr->utcs1 = UT_CLEAR|UT_GO; 8764744Swnj while (num > 0) { 8774744Swnj blk = num > DBSIZE ? DBSIZE : num; 8784746Ssam utdwrite(start, blk, addr, up); 8794746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8804746Ssam return(EIO); 8814744Swnj start += blk; 8824744Swnj num -= blk; 8834744Swnj } 8844746Ssam uteof(addr); 8854746Ssam uteof(addr); 8864746Ssam utwait(addr); 8874746Ssam if ((addr->utds&UTDS_ERR) || (addr->utcs1&UT_TRE)) 8884744Swnj return(EIO); 8894746Ssam addr->utcs1 = UT_REW|UT_GO; 8904744Swnj return (0); 8914744Swnj } 8924744Swnj 8934746Ssam utdwrite(dbuf, num, addr, up) 8944744Swnj register dbuf, num; 8954746Ssam register struct utdevice *addr; 8964744Swnj struct uba_regs *up; 8974744Swnj { 8984744Swnj register struct pte *io; 8994744Swnj register int npf; 9004744Swnj 9014746Ssam utwait(addr); 9024744Swnj io = up->uba_map; 9034744Swnj npf = num + 1; 9044744Swnj while (--npf != 0) 9054744Swnj *(int *)io++ = (dbuf++ | (1<<UBAMR_DPSHIFT) | UBAMR_MRV); 9064744Swnj *(int *)io = 0; 9074746Ssam addr->utwc = -((num*NBPG)>>1); 9084746Ssam addr->utfc = -(num*NBPG); 9094746Ssam addr->utba = 0; 9104746Ssam addr->utcs1 = UT_WCOM|UT_GO; 9114744Swnj } 9124744Swnj 9134746Ssam utwait(addr) 9144746Ssam struct utdevice *addr; 9154744Swnj { 9164744Swnj register s; 9174744Swnj 9184744Swnj do 9194746Ssam s = addr->utds; 9204744Swnj while ((s&UTDS_DRY) == 0); 9214744Swnj } 9224744Swnj 9234746Ssam uteof(addr) 9244746Ssam struct utdevice *addr; 9254744Swnj { 9264744Swnj 9274746Ssam utwait(addr); 9284746Ssam addr->utcs1 = UT_WEOF|UT_GO; 9294744Swnj } 9304744Swnj #endif 931