123315Smckusick /* 229271Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323315Smckusick * All rights reserved. The Berkeley software License Agreement 423315Smckusick * specifies the terms and conditions for redistribution. 523315Smckusick * 6*36548Sbostic * @(#)mt.c 7.4 (Berkeley) 01/14/89 723315Smckusick */ 84736Swnj 94736Swnj #include "mu.h" 104736Swnj #if NMT > 0 114736Swnj /* 124736Swnj * TM78/TU78 tape driver 134736Swnj * 1417214Smckusick * Original author - ? 1517214Smckusick * Most error recovery bug fixes - ggs (ulysses!ggs) 1634221Sbostic * `read reverse' error recovery - ggs (ulysses!ggs) 174736Swnj * 1817214Smckusick * OPTIONS: 1917214Smckusick * MTLERRM - Long error message text - twd, Brown University 2017214Smckusick * 214736Swnj * TODO: 2217214Smckusick * Add odd byte count kludge from VMS driver (?) 2317214Smckusick * Write dump routine 244736Swnj */ 2517214Smckusick 2617119Sbloom #include "param.h" 2717119Sbloom #include "systm.h" 2817119Sbloom #include "buf.h" 2917119Sbloom #include "conf.h" 3017119Sbloom #include "dir.h" 3117119Sbloom #include "file.h" 3217119Sbloom #include "user.h" 3317119Sbloom #include "map.h" 3417119Sbloom #include "ioctl.h" 3517119Sbloom #include "mtio.h" 3617119Sbloom #include "cmap.h" 3717119Sbloom #include "uio.h" 3818324Sralph #include "tty.h" 3934221Sbostic #include "syslog.h" 404736Swnj 4134221Sbostic #include "../vax/pte.h" 428471Sroot #include "../vax/cpu.h" 4317119Sbloom #include "mbareg.h" 4417119Sbloom #include "mbavar.h" 4517119Sbloom #include "mtreg.h" 464736Swnj 4717214Smckusick #define MTTIMEOUT 10000 /* loop limit for controller test */ 4817214Smckusick #define INF 1000000L /* a block number that won't exist */ 4917214Smckusick #define MASKREG(r) ((r) & 0xffff) /* the control registers have 16 bits */ 504736Swnj 5117214Smckusick /* Bits for sc_flags */ 524736Swnj 5317214Smckusick #define H_WRITTEN 01 /* last operation was a write */ 5417214Smckusick #define H_EOT 02 /* end of tape encountered */ 5517214Smckusick #define H_IEOT 04 /* ignore EOT condition */ 564736Swnj 5734221Sbostic int mt_do_readrev = 1; 5817214Smckusick 5917214Smckusick /* Per unit status information */ 6017214Smckusick 614736Swnj struct mu_softc { 6234221Sbostic char sc_openf; /* unit is open if != 0 */ 6334221Sbostic char sc_flags; /* state flags */ 6434221Sbostic daddr_t sc_blkno; /* current physical block number */ 6534221Sbostic daddr_t sc_nxrec; /* firewall input block number */ 6634221Sbostic u_short sc_erreg; /* copy of mter or mtner */ 6734221Sbostic u_short sc_dsreg; /* copy of mtds */ 6834221Sbostic short sc_resid; /* residual function count for ioctl */ 6934221Sbostic short sc_dens; /* density code - MT_GCR or zero */ 7034221Sbostic int sc_i_mtas; /* mtas at slave attach time */ 7134221Sbostic int sc_i_mtner; /* mtner at slave attach time */ 7234221Sbostic int sc_i_mtds; /* mtds at slave attach time */ 7334221Sbostic struct tty *sc_ttyp; /* record user's tty for errors */ 7434221Sbostic int sc_blks; /* number of I/O operations since open */ 7534221Sbostic int sc_softerrs; /* number of soft I/O errors since open */ 764736Swnj } mu_softc[NMU]; 774736Swnj 7817214Smckusick struct buf cmtbuf[NMT]; /* tape command buffer structures */ 794736Swnj 8034221Sbostic struct mba_device *mtinfo[NMT]; /* unit to ctlr structures */ 8134221Sbostic struct mba_slave *muinfo[NMU]; /* unit to slave structures */ 8234221Sbostic 8317214Smckusick char mtds_bits[] = MTDS_BITS; /* mtds bit names for error messages */ 8417214Smckusick short mttypes[] = { MBDT_TU78, 0 }; 854736Swnj 8617214Smckusick int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint(); 8717214Smckusick struct mba_driver mtdriver = 8817214Smckusick { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint, 8917214Smckusick mttypes, "mt", "mu", mtinfo }; 9017214Smckusick 9134221Sbostic /* Bits in minor device */ 9234221Sbostic #define MUUNIT(dev) (minor(dev)&03) 9334221Sbostic #define H_NOREWIND 04 9434221Sbostic #define H_6250BPI 010 9517214Smckusick 9634221Sbostic #define MTUNIT(dev) (muinfo[MUUNIT(dev)]->ms_ctlr) 9734221Sbostic 9834221Sbostic void mtcreset(); 9934221Sbostic 1004736Swnj /*ARGSUSED*/ 1014736Swnj mtattach(mi) 1024736Swnj struct mba_device *mi; 1034736Swnj { 10434221Sbostic 10534221Sbostic /* void */ 1064736Swnj } 1074736Swnj 1087431Skre mtslave(mi, ms, sn) 1094736Swnj struct mba_device *mi; 1104736Swnj struct mba_slave *ms; 1117431Skre int sn; 1124736Swnj { 1134736Swnj register struct mu_softc *sc = &mu_softc[ms->ms_unit]; 1144736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 11526377Skarels int s = spl5(), rtn = 0, i; 1164736Swnj 11734221Sbostic /* 11834221Sbostic * Just in case the controller is ill, reset it. Then issue 11934221Sbostic * a sense operation and wait about a second for it to respond. 12034221Sbostic */ 12117214Smckusick mtcreset(mtaddr); 1224736Swnj mtaddr->mtas = -1; 1237431Skre mtaddr->mtncs[sn] = MT_SENSE|MT_GO; 12434221Sbostic for (i = MTTIMEOUT; i > 0; i--) { 12517214Smckusick DELAY(50); 12617214Smckusick if (MASKREG(mtaddr->mtas) != 0) 12717214Smckusick break; 12817214Smckusick } 12917214Smckusick sc->sc_i_mtas = mtaddr->mtas; 13017214Smckusick sc->sc_i_mtner = mtaddr->mtner; 13117214Smckusick sc->sc_i_mtds = mtaddr->mtds; 13217214Smckusick 13334221Sbostic /* 13434221Sbostic * If no response, whimper. If wrong response, call it an 13534221Sbostic * unsolicited interrupt and use mtndtint to log and correct. 13634221Sbostic * Otherwise, note whether this slave exists. 13734221Sbostic */ 13834221Sbostic if (i <= 0) 13917214Smckusick printf("mt: controller hung\n"); 14034221Sbostic else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE) 14117214Smckusick (void) mtndtint(mi); 14234654Skarels else if (mtaddr->mtds & MTDS_PRES) { 14334654Skarels muinfo[ms->ms_unit] = ms; 1444736Swnj rtn = 1; 14534654Skarels } 14617214Smckusick 14734221Sbostic /* cancel the interrupt, then wait a little while for it to go away */ 1484736Swnj mtaddr->mtas = mtaddr->mtas; 14917214Smckusick DELAY(10); 1504736Swnj splx(s); 1514736Swnj return (rtn); 1524736Swnj } 1534736Swnj 1544736Swnj mtopen(dev, flag) 1554736Swnj dev_t dev; 1564736Swnj int flag; 1574736Swnj { 1584736Swnj register int muunit; 1594736Swnj register struct mu_softc *sc; 16034221Sbostic register struct mba_slave *ms; 1614736Swnj 1624736Swnj muunit = MUUNIT(dev); 16334221Sbostic if (muunit >= NMU || (ms = muinfo[muunit]) == NULL || 16434221Sbostic ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0) 1658581Sroot return (ENXIO); 16617214Smckusick if ((sc = &mu_softc[muunit])->sc_openf) 16717214Smckusick return (EBUSY); 16834221Sbostic sc->sc_openf = 1; 16917214Smckusick sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0; 1704736Swnj mtcommand(dev, MT_SENSE, 1); 1714736Swnj if ((sc->sc_dsreg & MTDS_ONL) == 0) { 1724736Swnj uprintf("mu%d: not online\n", muunit); 17334221Sbostic sc->sc_openf = 0; 1748581Sroot return (EIO); 1754736Swnj } 17617214Smckusick if ((sc->sc_dsreg & MTDS_AVAIL) == 0) { 17717214Smckusick uprintf("mu%d: not online (port selector)\n", muunit); 17834221Sbostic sc->sc_openf = 0; 17917214Smckusick return (EIO); 18017214Smckusick } 18117214Smckusick if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) { 1824736Swnj uprintf("mu%d: no write ring\n", muunit); 18334221Sbostic sc->sc_openf = 0; 1848581Sroot return (EIO); 1854736Swnj } 18634221Sbostic if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) && 18734221Sbostic (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) { 1884736Swnj uprintf("mu%d: can't change density in mid-tape\n", muunit); 18934221Sbostic sc->sc_openf = 0; 1908581Sroot return (EIO); 1914736Swnj } 1924736Swnj sc->sc_blkno = (daddr_t)0; 19317214Smckusick 19434221Sbostic /* 19534221Sbostic * Since cooked I/O may do a read-ahead before a write, trash 19634221Sbostic * on a tape can make the first write fail. Suppress the first 19734221Sbostic * read-ahead unless definitely doing read-write. 19834221Sbostic */ 19934221Sbostic sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ? 20034221Sbostic (daddr_t)0 : (daddr_t)INF; 2014736Swnj sc->sc_flags = 0; 20234221Sbostic sc->sc_blks = 0; 20334221Sbostic sc->sc_softerrs = 0; 20418324Sralph sc->sc_ttyp = u.u_ttyp; 2058581Sroot return (0); 2064736Swnj } 2074736Swnj 2084736Swnj mtclose(dev, flag) 2094736Swnj register dev_t dev; 21017214Smckusick register int flag; 2114736Swnj { 2124736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 2134736Swnj 21434221Sbostic if ((flag & (FREAD | FWRITE)) == FWRITE || 21534221Sbostic ((flag & FWRITE) && (sc->sc_flags & H_WRITTEN))) 2164736Swnj mtcommand(dev, MT_CLS|sc->sc_dens, 1); 21717214Smckusick if ((minor(dev) & H_NOREWIND) == 0) 2184736Swnj mtcommand(dev, MT_REW, 0); 21934221Sbostic if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 22034221Sbostic log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n", 22134221Sbostic MUUNIT(dev), sc->sc_softerrs, sc->sc_blks); 2224736Swnj sc->sc_openf = 0; 2234736Swnj } 2244736Swnj 2254736Swnj mtcommand(dev, com, count) 2264736Swnj dev_t dev; 2274736Swnj int com, count; 2284736Swnj { 2294736Swnj register struct buf *bp; 23034221Sbostic int s; 2314736Swnj 2324736Swnj bp = &cmtbuf[MTUNIT(dev)]; 2335437Sroot s = spl5(); 23417214Smckusick while (bp->b_flags & B_BUSY) { 23534221Sbostic if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE)) 2364736Swnj break; 2374736Swnj bp->b_flags |= B_WANTED; 2384736Swnj sleep((caddr_t)bp, PRIBIO); 2394736Swnj } 2404736Swnj bp->b_flags = B_BUSY|B_READ; 2415437Sroot splx(s); 2424736Swnj bp->b_dev = dev; 2434736Swnj bp->b_command = com; 2444736Swnj bp->b_repcnt = count; 2454736Swnj bp->b_blkno = 0; 24617214Smckusick bp->b_error = 0; 2474736Swnj mtstrategy(bp); 2484736Swnj if (count == 0) 2494736Swnj return; 25034221Sbostic biowait(bp); 25117214Smckusick if (bp->b_flags & B_WANTED) 2524736Swnj wakeup((caddr_t)bp); 2534736Swnj bp->b_flags &= B_ERROR; 2544736Swnj } 2554736Swnj 2564736Swnj mtstrategy(bp) 2574736Swnj register struct buf *bp; 2584736Swnj { 2594736Swnj register struct buf *dp; 26034221Sbostic struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)]; 26134221Sbostic int s; 2624736Swnj 26334221Sbostic /* 26434221Sbostic * If this is a data transfer operation, set the resid to a 26534221Sbostic * default value (EOF) to simplify getting it right during 26634221Sbostic * error recovery or bail out. 26734221Sbostic */ 26817214Smckusick if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 26917214Smckusick bp->b_resid = bp->b_bcount; 27017214Smckusick 27134221Sbostic /* 27234221Sbostic * Link this request onto the end of the queue for this 27334221Sbostic * controller, then start I/O if not already active. 27434221Sbostic */ 2754736Swnj bp->av_forw = NULL; 2764736Swnj dp = &mi->mi_tab; 2775437Sroot s = spl5(); 2784736Swnj if (dp->b_actf == NULL) 2794736Swnj dp->b_actf = bp; 2804736Swnj else 2814736Swnj dp->b_actl->av_forw = bp; 2824736Swnj dp->b_actl = bp; 2834736Swnj if (dp->b_active == 0) 2844736Swnj mbustart(mi); 2855437Sroot splx(s); 2864736Swnj } 2874736Swnj 2884736Swnj mtustart(mi) 2894736Swnj register struct mba_device *mi; 2904736Swnj { 29117214Smckusick register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 2924736Swnj register struct buf *bp = mi->mi_tab.b_actf; 2934736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 2944736Swnj daddr_t blkno; 29526377Skarels int count; 2964736Swnj 2974736Swnj if (sc->sc_openf < 0) { 2984736Swnj bp->b_flags |= B_ERROR; 2994736Swnj return (MBU_NEXT); 3004736Swnj } 3014736Swnj if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) { 30234221Sbostic /* 30334221Sbostic * Data transfer. If write at end of tape, 30434221Sbostic * signal "no space" unless suppressed 30534221Sbostic * by MTIOCIEOT. 30634221Sbostic */ 30734221Sbostic if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT && 30834221Sbostic (bp->b_flags & B_READ) == 0) { 3094736Swnj bp->b_flags |= B_ERROR; 31017214Smckusick bp->b_error = ENOSPC; 3114736Swnj return (MBU_NEXT); 3124736Swnj } 31317214Smckusick 31434221Sbostic if (bp->b_flags & B_RAW) { 31534221Sbostic /* raw transfer; never seek */ 31634221Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno); 31734221Sbostic sc->sc_nxrec = sc->sc_blkno + 1; 31834221Sbostic } else { 31917214Smckusick /* seek beyond end of file */ 32017214Smckusick if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 32117214Smckusick bp->b_flags |= B_ERROR; 32217214Smckusick bp->b_error = ENXIO; 32317214Smckusick return (MBU_NEXT); 32417214Smckusick } 32517214Smckusick 32634221Sbostic /* 32734221Sbostic * This should be end of file, but the buffer 32834221Sbostic * system wants a one-block look-ahead. Humor it. 32934221Sbostic */ 33034221Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 33134221Sbostic bp->b_flags & B_READ) { 33234221Sbostic bp->b_resid = bp->b_bcount; 33317214Smckusick clrbuf(bp); 33417214Smckusick return (MBU_NEXT); 33517214Smckusick } 33617214Smckusick 33717214Smckusick /* If writing, mark the next block invalid. */ 33817214Smckusick if ((bp->b_flags & B_READ) == 0) 33917214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 3404736Swnj } 3414736Swnj } else { 34217214Smckusick /* It's a command, do it now. */ 3434736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3444736Swnj (bp->b_repcnt<<8)|bp->b_command|MT_GO; 3454736Swnj return (MBU_STARTED); 3464736Swnj } 34717214Smckusick 34834221Sbostic /* 34934221Sbostic * If raw I/O, or if the tape is positioned correctly for 35034221Sbostic * cooked I/O, set the byte count, unit number and repeat count 35134221Sbostic * then tell the MASSBUS to proceed. Note that a negative 35234221Sbostic * bcount tells mbstart to map the buffer for "read backwards". 35334221Sbostic */ 35434221Sbostic if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3554736Swnj if (mi->mi_tab.b_errcnt == 2) { 35634221Sbostic mtaddr->mtbc = -bp->b_bcount; 3574736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 3584736Swnj } else { 3594736Swnj mtaddr->mtbc = bp->b_bcount; 3604736Swnj mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev); 3614736Swnj } 3624736Swnj return (MBU_DODATA); 3634736Swnj } 36417214Smckusick 36517214Smckusick /* Issue skip operations to position the next block for cooked I/O. */ 36617214Smckusick 3677380Ssam if (blkno < bdbtofsb(bp->b_blkno)) 36834221Sbostic count = bdbtofsb(bp->b_blkno) - blkno; 3694736Swnj else 37034221Sbostic count = blkno - bdbtofsb(bp->b_blkno); 37134221Sbostic if ((unsigned)count > 0377) 37226377Skarels count = 0377; 37326377Skarels mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO; 3744736Swnj return (MBU_STARTED); 3754736Swnj } 3764736Swnj 3774736Swnj mtstart(mi) 3784736Swnj register struct mba_device *mi; 3794736Swnj { 3804736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3814736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 3824736Swnj 3834736Swnj if (bp->b_flags & B_READ) 3844736Swnj if (mi->mi_tab.b_errcnt == 2) 38534221Sbostic return (MT_READREV|MT_GO); 3864736Swnj else 38734221Sbostic return (MT_READ|MT_GO); 3884736Swnj else 38934221Sbostic return (MT_WRITE|sc->sc_dens|MT_GO); 3904736Swnj } 3914736Swnj 3924736Swnj mtdtint(mi, mbsr) 3934736Swnj register struct mba_device *mi; 3944736Swnj int mbsr; 3954736Swnj { 3964736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 3974736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3984736Swnj register struct mu_softc *sc; 39917214Smckusick register int er; 4004736Swnj 40117214Smckusick /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */ 40217214Smckusick if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) { 4034736Swnj printf("mt: wrong unit!\n"); 4044736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 4054736Swnj } 40617214Smckusick 40717214Smckusick er = MASKREG(mtaddr->mter); 4084736Swnj sc = &mu_softc[MUUNIT(bp->b_dev)]; 40917214Smckusick sc->sc_erreg = er; 41017214Smckusick if (bp->b_flags & B_READ) 41117214Smckusick sc->sc_flags &= ~H_WRITTEN; 41217214Smckusick else 4134736Swnj sc->sc_flags |= H_WRITTEN; 41417214Smckusick switch (er & MTER_INTCODE) { 41517214Smckusick 41617214Smckusick case MTER_EOT: 41717214Smckusick sc->sc_flags |= H_EOT; 41817214Smckusick /* fall into MTER_DONE */ 41917214Smckusick 4204736Swnj case MTER_DONE: 42117214Smckusick sc->sc_blkno++; 42217214Smckusick if (mi->mi_tab.b_errcnt == 2) { 42317214Smckusick bp->b_bcount = bp->b_resid; 42417214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 42534221Sbostic if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0) 42617214Smckusick bp->b_flags |= B_ERROR; 42734221Sbostic } else 42817214Smckusick bp->b_resid = 0; 42917214Smckusick break; 43017214Smckusick 43117214Smckusick case MTER_SHRTREC: 43217214Smckusick sc->sc_blkno++; 43317214Smckusick bp->b_bcount = bp->b_resid; 43417214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 43534221Sbostic if ((bp->b_flags & B_RAW) == 0) 43617214Smckusick bp->b_flags |= B_ERROR; 43717214Smckusick break; 43817214Smckusick 43917214Smckusick case MTER_RETRY: 44034221Sbostic /* 44134221Sbostic * Simple re-try. Since resid is always a copy of the 44234221Sbostic * original byte count, use it to restore the count. 44334221Sbostic */ 44417214Smckusick mi->mi_tab.b_errcnt = 1; 44517214Smckusick bp->b_bcount = bp->b_resid; 44634221Sbostic return (MBD_RETRY); 44717214Smckusick 44817214Smckusick case MTER_RDOPP: 44934221Sbostic /* 45034221Sbostic * The controller just decided to read it backwards. 45134221Sbostic * If the controller returns a byte count of zero, 45234221Sbostic * change it to 1, since zero encodes 65536, which 45334221Sbostic * isn't quite what we had in mind. The byte count 45434221Sbostic * may be larger than the size of the input buffer, so 45534221Sbostic * limit the count to the buffer size. After 45634221Sbostic * making the byte count reasonable, set bcount to the 45734221Sbostic * negative of the controller's version of the byte 45834221Sbostic * count so that the start address for the transfer is 45934221Sbostic * set up correctly. 46034221Sbostic */ 46117214Smckusick if (mt_do_readrev) { 46217214Smckusick mi->mi_tab.b_errcnt = 2; 46317214Smckusick if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0) 46417214Smckusick bp->b_bcount = 1; 46517214Smckusick if (bp->b_bcount > bp->b_resid) 46617214Smckusick bp->b_bcount = bp->b_resid; 46717214Smckusick bp->b_bcount = -(bp->b_bcount); 46817214Smckusick return(MBD_RETRY); 46917214Smckusick } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) { 47017214Smckusick sc->sc_blkno++; 47117214Smckusick bp->b_bcount = bp->b_resid; 47217214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 47317214Smckusick bp->b_flags |= B_ERROR; 47417214Smckusick break; 47517214Smckusick } 47617214Smckusick bp->b_flags |= B_ERROR; 47717214Smckusick /* fall into MTER_LONGREC */ 47817214Smckusick 4794736Swnj case MTER_LONGREC: 48017214Smckusick sc->sc_blkno++; 48117214Smckusick bp->b_bcount = bp->b_resid; 4824736Swnj bp->b_resid = 0; 48317214Smckusick bp->b_error = ENOMEM; 48417214Smckusick bp->b_flags |= B_ERROR; 4854736Swnj break; 4864736Swnj 4874736Swnj case MTER_NOTCAP: 4884736Swnj printf("mu%d: blank tape\n", MUUNIT(bp->b_dev)); 4894736Swnj goto err; 4904736Swnj 4914736Swnj case MTER_TM: 49234221Sbostic /* 49334221Sbostic * End of file. Since the default byte count has 49434221Sbostic * already been set, just count the block and proceed. 49534221Sbostic */ 4964736Swnj sc->sc_blkno++; 4974736Swnj err: 49834221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno); 4994736Swnj break; 5004736Swnj 5014736Swnj case MTER_OFFLINE: 5024736Swnj if (sc->sc_openf > 0) { 5034736Swnj sc->sc_openf = -1; 50434221Sbostic tprintf(sc->sc_ttyp, "mu%d: offline\n", 50534221Sbostic MUUNIT(bp->b_dev)); 5064736Swnj } 5074736Swnj bp->b_flags |= B_ERROR; 5084736Swnj break; 5094736Swnj 51017214Smckusick case MTER_NOTAVL: 51117214Smckusick if (sc->sc_openf > 0) { 51217214Smckusick sc->sc_openf = -1; 51318324Sralph tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", 51418324Sralph MUUNIT(bp->b_dev)); 51517214Smckusick } 51617214Smckusick bp->b_flags |= B_ERROR; 51717214Smckusick break; 51817214Smckusick 5194736Swnj case MTER_FPT: 52034221Sbostic tprintf(sc->sc_ttyp, "mu%d: no write ring\n", 52134221Sbostic MUUNIT(bp->b_dev)); 5224736Swnj bp->b_flags |= B_ERROR; 5234736Swnj break; 5244736Swnj 52517214Smckusick case MTER_UNREAD: 52617214Smckusick sc->sc_blkno++; 52717214Smckusick bp->b_bcount = bp->b_resid; 52817214Smckusick bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount); 52917214Smckusick 53034221Sbostic /* code 010 means a garbage record, nothing serious. */ 53134221Sbostic if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) { 53234221Sbostic tprintf(sc->sc_ttyp, 53334221Sbostic "mu%d: rn=%d bn=%d unreadable record\n", 53417214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno); 53517214Smckusick bp->b_flags |= B_ERROR; 53617214Smckusick break; 53717214Smckusick } 53817214Smckusick 53934221Sbostic /* 54034221Sbostic * Anything else might be a hardware problem, 54134221Sbostic * fall into the error report. 54234221Sbostic */ 54317214Smckusick 5444736Swnj default: 54534221Sbostic /* 54634221Sbostic * The bits in sc->sc_dsreg are from the last sense 54734221Sbostic * command. To get the most recent copy, you have to 54834221Sbostic * do a sense at interrupt level, which requires nested 54934221Sbostic * error processing. This is a bit messy, so leave 55034221Sbostic * well enough alone. 55134221Sbostic */ 55234221Sbostic tprintf(sc->sc_ttyp, "\ 55334221Sbostic mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n", 55417214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 55517214Smckusick mbsr, mbsr_bits, er, 55617214Smckusick MASKREG(sc->sc_dsreg), mtds_bits); 55717214Smckusick #ifdef MTLERRM 55834221Sbostic mtintfail(er); 55917214Smckusick #endif 5604736Swnj bp->b_flags |= B_ERROR; 56117214Smckusick 56234221Sbostic /* 56334221Sbostic * The TM78 manual says to reset the controller after 56434221Sbostic * TM fault B or MASSBUS fault. 56534221Sbostic */ 56634221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 56734221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) 56817214Smckusick mtcreset(mtaddr); 5694736Swnj } 57017214Smckusick 57134221Sbostic /* 57234221Sbostic * Just in case some strange error slipped through (drive off 57334221Sbostic * line during read-reverse error recovery comes to mind), make 57434221Sbostic * sure the byte count is reasonable. 57534221Sbostic */ 57617214Smckusick if (bp->b_bcount < 0) 57717214Smckusick bp->b_bcount = bp->b_resid; 57834221Sbostic 57934221Sbostic if ((bp->b_flags & B_ERROR) == 0) { 58034221Sbostic /* this counts reverse reads as soft errors */ 58134221Sbostic sc->sc_blks++; 58234221Sbostic if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */ 58334221Sbostic sc->sc_softerrs++; 58434221Sbostic } 5854736Swnj return (MBD_DONE); 5864736Swnj } 5874736Swnj 5884736Swnj mtndtint(mi) 5894736Swnj register struct mba_device *mi; 5904736Swnj { 5914736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 5924736Swnj register struct buf *bp = mi->mi_tab.b_actf; 5934736Swnj register struct mu_softc *sc; 59417214Smckusick register int er, fc; 59517214Smckusick int unit; 5964736Swnj 5974736Swnj unit = (mtaddr->mtner >> 8) & 3; 5984736Swnj er = MASKREG(mtaddr->mtner); 59917214Smckusick sc = &mu_softc[unit]; 60017214Smckusick sc->sc_erreg = er; 60117214Smckusick 60217214Smckusick /* Check for unsolicited interrupts. */ 60334221Sbostic if (bp == NULL || unit != MUUNIT(bp->b_dev)) { 60434221Sbostic if ((er & MTER_INTCODE) == MTER_ONLINE) 60534221Sbostic return (MBN_SKIP); 60617214Smckusick 60734221Sbostic printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n", 60834221Sbostic unit, er, MASKREG(sc->sc_dsreg), mtds_bits); 60917214Smckusick #ifdef MTLERRM 61034221Sbostic mtintfail(er); 61117214Smckusick #endif 61234221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 61334221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) { 61434221Sbostic /* 61534221Sbostic * Reset the controller, then set error status 61634221Sbostic * if there was anything active when the fault 61734221Sbostic * occurred. This may shoot an innocent 61834221Sbostic * bystander, but it's better than letting 61934221Sbostic * an error slip through. 62034221Sbostic */ 62134221Sbostic mtcreset(mtaddr); 62234221Sbostic if (bp != NULL) { 62334221Sbostic bp->b_flags |= B_ERROR; 62434221Sbostic return (MBN_DONE); 62517214Smckusick } 62617214Smckusick } 6274736Swnj return (MBN_SKIP); 6284736Swnj } 62917214Smckusick 6304736Swnj fc = (mtaddr->mtncs[unit] >> 8) & 0xff; 6314736Swnj sc->sc_resid = fc; 63217214Smckusick 63334221Sbostic /* 63434221Sbostic * Clear the "written" flag after any operation that changes 63534221Sbostic * the position of the tape. 63634221Sbostic */ 63734221Sbostic if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE) 63817214Smckusick sc->sc_flags &= ~H_WRITTEN; 63917214Smckusick 6404736Swnj switch (er & MTER_INTCODE) { 64117214Smckusick 64217214Smckusick case MTER_EOT: 64317214Smckusick sc->sc_flags |= H_EOT; 64417214Smckusick /* fall into MTER_DONE */ 64517214Smckusick 6464736Swnj case MTER_DONE: 64717214Smckusick /* If this is a command buffer, just update the status. */ 6484736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 6494736Swnj done: 6504736Swnj if (bp->b_command == MT_SENSE) 6514736Swnj sc->sc_dsreg = MASKREG(mtaddr->mtds); 6524736Swnj return (MBN_DONE); 6534736Swnj } 65417214Smckusick 65534221Sbostic /* 65634221Sbostic * It's not a command buffer, must be a cooked I/O 65734221Sbostic * skip operation (perhaps a shaky assumption, but it 65834221Sbostic * wasn't my idea). 65934221Sbostic */ 6607380Ssam if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0) 6616186Ssam sc->sc_blkno -= MIN(0377, -fc); 6624736Swnj else 6636186Ssam sc->sc_blkno += MIN(0377, fc); 6644736Swnj return (MBN_RETRY); 6654736Swnj 66617214Smckusick case MTER_ONLINE: /* ddj -- shouldn't happen but did */ 6674736Swnj case MTER_RWDING: 6684736Swnj return (MBN_SKIP); /* ignore "rewind started" interrupt */ 6694736Swnj 6704736Swnj case MTER_NOTCAP: 67118324Sralph tprintf(sc->sc_ttyp, "mu%d: blank tape\n", MUUNIT(bp->b_dev)); 67217214Smckusick bp->b_flags |= B_ERROR; 67317214Smckusick return (MBN_DONE); 6744736Swnj 6754736Swnj case MTER_TM: 6764736Swnj case MTER_LEOT: 67734221Sbostic /* 67834221Sbostic * For an ioctl skip operation, count a tape mark as 67934221Sbostic * a record. If there's anything left to do, update 68034221Sbostic * the repeat count and re-start the command. 68134221Sbostic */ 68217214Smckusick if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 68317214Smckusick if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0) 68417214Smckusick return (MBN_DONE); 68517214Smckusick else 68617214Smckusick return (MBN_RETRY); 6874736Swnj } else { 68834221Sbostic /* 68934221Sbostic * Cooked I/O again. Just update the books and 69034221Sbostic * wait for someone else to return end of file or 69134221Sbostic * complain about a bad seek. 69234221Sbostic */ 69334221Sbostic if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 69434221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1; 69534221Sbostic sc->sc_blkno = sc->sc_nxrec; 69634221Sbostic } else { 69734221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc; 69834221Sbostic sc->sc_blkno = sc->sc_nxrec + 1; 69934221Sbostic } 7004736Swnj } 7014736Swnj return (MBN_RETRY); 7024736Swnj 7034736Swnj case MTER_FPT: 70434221Sbostic tprintf(sc->sc_ttyp, "mu%d: no write ring\n", 70534221Sbostic MUUNIT(bp->b_dev)); 7064736Swnj bp->b_flags |= B_ERROR; 7074736Swnj return (MBN_DONE); 7084736Swnj 7094736Swnj case MTER_OFFLINE: 71017214Smckusick /* If `off line' was intentional, don't complain. */ 71134221Sbostic if (bp == &cmtbuf[MTUNIT(bp->b_dev)] && 71234221Sbostic bp->b_command == MT_UNLOAD) 71317214Smckusick return(MBN_DONE); 7144736Swnj if (sc->sc_openf > 0) { 7154736Swnj sc->sc_openf = -1; 71634221Sbostic tprintf(sc->sc_ttyp, "mu%d: offline\n", 71734221Sbostic MUUNIT(bp->b_dev)); 7184736Swnj } 7194736Swnj bp->b_flags |= B_ERROR; 7204736Swnj return (MBN_DONE); 7214736Swnj 72217214Smckusick case MTER_NOTAVL: 72317214Smckusick if (sc->sc_openf > 0) { 72417214Smckusick sc->sc_openf = -1; 72534221Sbostic tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", 72634221Sbostic MUUNIT(bp->b_dev)); 72717214Smckusick } 72817214Smckusick bp->b_flags |= B_ERROR; 72917214Smckusick return (MBN_DONE); 73017214Smckusick 7314736Swnj case MTER_BOT: 7324736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 7334736Swnj goto done; 73417214Smckusick /* fall through */ 73517214Smckusick 7364736Swnj default: 73734221Sbostic tprintf(sc->sc_ttyp, "\ 73834221Sbostic mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n", 73917214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 74017214Smckusick er, MASKREG(sc->sc_dsreg), mtds_bits); 74117214Smckusick #ifdef MTLERRM 74234221Sbostic mtintfail(er); 74317214Smckusick #endif 74434221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 74534221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) 74617214Smckusick mtcreset(mtaddr); /* reset the controller */ 7474736Swnj bp->b_flags |= B_ERROR; 7484736Swnj return (MBN_DONE); 7494736Swnj } 7504736Swnj /* NOTREACHED */ 7514736Swnj } 7524736Swnj 75334221Sbostic void 75434221Sbostic mtcreset(mtaddr) 75517214Smckusick register struct mtdevice *mtaddr; 75617214Smckusick { 75717214Smckusick register int i; 75817214Smckusick 75917214Smckusick mtaddr->mtid = MTID_CLR; /* reset the TM78 */ 76017214Smckusick DELAY(200); 76117214Smckusick for (i = MTTIMEOUT; i > 0; i--) { 76217214Smckusick DELAY(50); /* don't nag */ 76317214Smckusick if ((mtaddr->mtid & MTID_RDY) != 0) 76417214Smckusick return; /* exit when ready */ 76517214Smckusick } 76617214Smckusick printf("mt: controller hung\n"); 76717214Smckusick } 76817214Smckusick 7694736Swnj /*ARGSUSED*/ 7707637Ssam mtioctl(dev, cmd, data, flag) 7714736Swnj dev_t dev; 7724736Swnj int cmd; 7737637Ssam caddr_t data; 7744736Swnj int flag; 7754736Swnj { 7764736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 7774736Swnj register struct buf *bp = &cmtbuf[MTUNIT(dev)]; 77817214Smckusick register struct mtop *mtop; 77917214Smckusick register struct mtget *mtget; 78017214Smckusick int callcount, fcount; 78117214Smckusick int op; 78217214Smckusick 78317214Smckusick /* We depend on the values and order of the MT codes here. */ 78417214Smckusick 7854736Swnj static mtops[] = 7864736Swnj {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE}; 7874736Swnj 7884736Swnj switch (cmd) { 7897637Ssam 79017214Smckusick /* tape operation */ 79117214Smckusick 79217214Smckusick case MTIOCTOP: 7938606Sroot mtop = (struct mtop *)data; 7948606Sroot switch (mtop->mt_op) { 7957637Ssam 7964736Swnj case MTWEOF: 7977637Ssam callcount = mtop->mt_count; 7984736Swnj fcount = 1; 7994736Swnj break; 8007637Ssam 8014736Swnj case MTFSF: case MTBSF: 8027637Ssam callcount = mtop->mt_count; 8034736Swnj fcount = 1; 8044736Swnj break; 8057637Ssam 8064736Swnj case MTFSR: case MTBSR: 8074736Swnj callcount = 1; 8087637Ssam fcount = mtop->mt_count; 8094736Swnj break; 8107637Ssam 8114736Swnj case MTREW: case MTOFFL: 8124736Swnj callcount = 1; 8134736Swnj fcount = 1; 8144736Swnj break; 8157637Ssam 8164736Swnj default: 8178581Sroot return (ENXIO); 8184736Swnj } 81934221Sbostic if (callcount <= 0 || fcount <= 0) 8208581Sroot return (EINVAL); 8217637Ssam op = mtops[mtop->mt_op]; 8224736Swnj if (op == MT_WTM) 8234736Swnj op |= sc->sc_dens; 8244736Swnj while (--callcount >= 0) { 82517214Smckusick register int n, fc = fcount; 8264736Swnj 8274736Swnj do { 82817214Smckusick n = MIN(fc, 0xff); 8294736Swnj mtcommand(dev, op, n); 83017214Smckusick n -= sc->sc_resid; 83117214Smckusick fc -= n; 83217214Smckusick switch (mtop->mt_op) { 83317214Smckusick 83417214Smckusick case MTWEOF: 83517214Smckusick sc->sc_blkno += (daddr_t)n; 83617214Smckusick sc->sc_nxrec = sc->sc_blkno - 1; 83717214Smckusick break; 83817214Smckusick 83917214Smckusick case MTOFFL: 84017214Smckusick case MTREW: 84117214Smckusick case MTFSF: 84217214Smckusick sc->sc_blkno = (daddr_t)0; 84317214Smckusick sc->sc_nxrec = (daddr_t)INF; 84417214Smckusick break; 84517214Smckusick 84617214Smckusick case MTBSF: 84717214Smckusick if (sc->sc_resid) { 84817214Smckusick sc->sc_blkno = (daddr_t)0; 84917214Smckusick sc->sc_nxrec = (daddr_t)INF; 85017214Smckusick } else { 85117214Smckusick sc->sc_blkno = (daddr_t)(-1); 85217214Smckusick sc->sc_nxrec = (daddr_t)(-1); 85317214Smckusick } 85417214Smckusick break; 85517214Smckusick 85617214Smckusick case MTFSR: 85717214Smckusick sc->sc_blkno += (daddr_t)n; 85817214Smckusick break; 85917214Smckusick 86017214Smckusick case MTBSR: 86117214Smckusick sc->sc_blkno -= (daddr_t)n; 86217214Smckusick break; 86317214Smckusick } 86417214Smckusick if (sc->sc_resid) 86517214Smckusick break; 86617214Smckusick } while (fc); 86717214Smckusick if (fc) { 86817214Smckusick sc->sc_resid = callcount + fc; 86934221Sbostic if (mtop->mt_op == MTFSR || 87034221Sbostic mtop->mt_op == MTBSR) 87117214Smckusick return (EIO); 87234221Sbostic break; 87317214Smckusick } 87417214Smckusick if (bp->b_flags & B_ERROR) 8754736Swnj break; 8764736Swnj } 8778712Sroot return (geterror(bp)); 8787637Ssam 87917214Smckusick /* tape status */ 8804736Swnj case MTIOCGET: 8817637Ssam mtget = (struct mtget *)data; 8827637Ssam mtget->mt_erreg = sc->sc_erreg; 8837637Ssam mtget->mt_resid = sc->sc_resid; 8844736Swnj mtcommand(dev, MT_SENSE, 1); /* update drive status */ 8857637Ssam mtget->mt_dsreg = sc->sc_dsreg; 8867637Ssam mtget->mt_type = MT_ISMT; 8878581Sroot break; 8887637Ssam 88917214Smckusick /* ignore EOT condition */ 89017214Smckusick case MTIOCIEOT: 89117214Smckusick sc->sc_flags |= H_IEOT; 89217214Smckusick break; 89317214Smckusick 89417214Smckusick /* enable EOT condition */ 89517214Smckusick case MTIOCEEOT: 89617214Smckusick sc->sc_flags &= ~H_IEOT; 89717214Smckusick break; 89817214Smckusick 8994736Swnj default: 9008581Sroot return (ENXIO); 9014736Swnj } 9028581Sroot return (0); 9034736Swnj } 9044736Swnj 9054736Swnj #define DBSIZE 20 9064736Swnj 9074736Swnj mtdump() 9084736Swnj { 9094736Swnj register struct mba_device *mi; 9104736Swnj register struct mba_regs *mp; 9114736Swnj int blk, num; 9124736Swnj int start; 9134736Swnj 9144736Swnj start = 0; 9154736Swnj num = maxfree; 9164736Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 9174736Swnj if (mtinfo[0] == 0) 9184736Swnj return (ENXIO); 9194736Swnj mi = phys(mtinfo[0], struct mba_device *); 9204736Swnj mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 9214736Swnj mp->mba_cr = MBCR_IE; 9226186Ssam #if lint 9238606Sroot blk = 0; num = blk; start = num; blk = start; 9246186Ssam return (0); 9256186Ssam #endif 9266186Ssam #ifdef notyet 9274736Swnj mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive]; 9284736Swnj mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI; 9294736Swnj mtaddr->mtcs1 = MT_DCLR|MT_GO; 9304736Swnj while (num > 0) { 9314736Swnj blk = num > DBSIZE ? DBSIZE : num; 9324736Swnj mtdwrite(start, blk, mtaddr, mp); 9334736Swnj start += blk; 9344736Swnj num -= blk; 9354736Swnj } 9364736Swnj mteof(mtaddr); 9374736Swnj mteof(mtaddr); 9384736Swnj mtwait(mtaddr); 9394736Swnj if (mtaddr->mtds&MTDS_ERR) 9404736Swnj return (EIO); 9414736Swnj mtaddr->mtcs1 = MT_REW|MT_GO; 9424736Swnj return (0); 9434736Swnj } 9444736Swnj 9454736Swnj mtdwrite(dbuf, num, mtaddr, mp) 9464736Swnj register dbuf, num; 9474736Swnj register struct mtdevice *mtaddr; 9484736Swnj struct mba_regs *mp; 9494736Swnj { 9504736Swnj register struct pte *io; 9514736Swnj register int i; 9524736Swnj 9534736Swnj mtwait(mtaddr); 9544736Swnj io = mp->mba_map; 9554736Swnj for (i = 0; i < num; i++) 9564736Swnj *(int *)io++ = dbuf++ | PG_V; 9574736Swnj mtaddr->mtfc = -(num*NBPG); 9584736Swnj mp->mba_sr = -1; 9594736Swnj mp->mba_bcr = -(num*NBPG); 9604736Swnj mp->mba_var = 0; 9614736Swnj mtaddr->mtcs1 = MT_WCOM|MT_GO; 9624736Swnj } 9634736Swnj 9644736Swnj mtwait(mtaddr) 9654736Swnj struct mtdevice *mtaddr; 9664736Swnj { 9674736Swnj register s; 9684736Swnj 9694736Swnj do 9704736Swnj s = mtaddr->mtds; 9714736Swnj while ((s & MTDS_DRY) == 0); 9724736Swnj } 9734736Swnj 9744736Swnj mteof(mtaddr) 9754736Swnj struct mtdevice *mtaddr; 9764736Swnj { 9774736Swnj 9784736Swnj mtwait(mtaddr); 9794736Swnj mtaddr->mtcs1 = MT_WEOF|MT_GO; 9804736Swnj #endif notyet 9814736Swnj } 98217214Smckusick 98317214Smckusick #ifdef MTLERRM 98434221Sbostic /* 98534221Sbostic * Failure messages for each failure code, per interrupt code. 98634221Sbostic * Each table ends with a code of -1 as a default. 98734221Sbostic */ 98834221Sbostic struct fmesg { 98934221Sbostic int f_code; 99034221Sbostic char *f_mesg; 99134221Sbostic }; 99217214Smckusick 99334221Sbostic static char unclass[] = "unclassified failure code"; 99417214Smckusick 99534221Sbostic /* MTER_BOT */ 99634221Sbostic static struct fmesg botmsg[] = { 99734221Sbostic 01, "tape was at BOT", 99834221Sbostic 02, "BOT seen after tape started", 99934221Sbostic 03, "ARA ID detected", 100034221Sbostic -1, unclass 100134221Sbostic }; 100217214Smckusick 100334221Sbostic /* MTER_NOTRDY */ 100434221Sbostic static struct fmesg notrdymsg[] = { 100534221Sbostic 01, "TU on-line but not ready", 100634221Sbostic 02, "fatal error has occurred", 1007*36548Sbostic 03, "access allowed but not ready", 100834221Sbostic -1, unclass 100934221Sbostic }; 101017214Smckusick 101134221Sbostic /* MTER_NOTCAP */ 101234221Sbostic static struct fmesg notcapmsg[] = { 101334221Sbostic 01, "no record found within 25 feet", 101434221Sbostic 02, "ID burst neither PE nor GCR", 101534221Sbostic 03, "ARA ID not found", 101634221Sbostic 04, "no gap found after ID burst", 101734221Sbostic -1, unclass 101834221Sbostic }; 101917214Smckusick 102034221Sbostic /* MTER_LONGREC */ 102134221Sbostic static struct fmesg longrecmsg[] = { 102234221Sbostic 00, "extended sense data not found", 102334221Sbostic 01, "extended sense data updated", 102434221Sbostic -1, unclass 102534221Sbostic }; 102617214Smckusick 102734221Sbostic /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */ 102834221Sbostic static struct fmesg code22msg[] = { 102934221Sbostic 01, "GCR write error", 103034221Sbostic 02, "GCR read error", 103134221Sbostic 03, "PE read error", 103234221Sbostic 04, "PE write error", 103334221Sbostic 05, "at least 1 bit set in ECCSTA", 103434221Sbostic 06, "PE write error", 103534221Sbostic 07, "GCR write error", 103634221Sbostic 010, "RSTAT contains bad code", 103734221Sbostic 011, "PE write error", 103834221Sbostic 012, "MASSBUS parity error", 103934221Sbostic 013, "invalid data transferred", 104034221Sbostic -1, unclass 104134221Sbostic }; 104217214Smckusick 104334221Sbostic /* MTER_TMFLTA */ 104434221Sbostic static struct fmesg tmfltamsg[] = { 104534221Sbostic 01, "illegal command code", 104634221Sbostic 02, "DT command issued when NDT command active", 104734221Sbostic 03, "WMC error", 104834221Sbostic 04, "RUN not received from MASSBUS controller", 104934221Sbostic 05, "mismatch in command read - function routine", 105034221Sbostic 06, "ECC ROM parity error", 105134221Sbostic 07, "XMC ROM parity error", 105234221Sbostic 010, "mismatch in command read - ID burst command", 105334221Sbostic 011, "mismatch in command read - verify ARA burst command", 105434221Sbostic 012, "mismatch in command read - verify ARA ID command", 105534221Sbostic 013, "mismatch in command read - verify gap command", 105634221Sbostic 014, "mismatch in command read - read id burst command", 105734221Sbostic 015, "mismatch in command read - verify ARA ID command", 105834221Sbostic 016, "mismatch in command read - verify gap command", 105934221Sbostic 017, "mismatch in command read - find gap command", 106034221Sbostic 020, "WMC LEFT failed to set", 106134221Sbostic 021, "XL PE set in INTSTA register", 106234221Sbostic 022, "XMC DONE did not set", 106334221Sbostic 023, "WMC ROM PE or RD PE set in WMCERR register", 106434221Sbostic -1, unclass 106534221Sbostic }; 106617214Smckusick 106734221Sbostic /* MTER_TUFLTA */ 106834221Sbostic static struct fmesg tufltamsg[] = { 106934221Sbostic 01, "TU status parity error", 107034221Sbostic 02, "TU command parity error", 107134221Sbostic 03, "rewinding tape went offline", 107234221Sbostic 04, "tape went not ready during DSE", 107334221Sbostic 05, "TU CMD status changed during DSE", 107434221Sbostic 06, "TU never came up to speed", 107534221Sbostic 07, "TU velocity changed", 107634221Sbostic 010, "TU CMD did not load correctly to start tape motion", 107734221Sbostic 011, "TU CMD did not load correctly to set drive density", 107834221Sbostic 012, "TU CMD did not load correctly to start tape motion to write BOT ID", 107934221Sbostic 013, "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID", 108034221Sbostic 014, "failed to write density ID burst", 108134221Sbostic 015, "failed to write ARA burst", 108234221Sbostic 016, "failed to write ARA ID", 108334221Sbostic 017, "ARA error bit set in MTA status B register", 108434221Sbostic 021, "could not find a gap after ID code was written correctly", 108534221Sbostic 022, "TU CMD did not load correctly to start tape motion to read ID burst", 108634221Sbostic 023, "timeout looking for BOT after detecting ARA ID burst", 108734221Sbostic 024, "failed to write tape mark", 108834221Sbostic 025, "tape never came up to speed while trying to reposition for retry of writing tape mark", 108934221Sbostic 026, "TU CMD did not load correctly to start tape motion in erase gap routine", 109034221Sbostic 027, "could not detect a gap in in erase gap routine", 109134221Sbostic 030, "could not detect a gap after writing record", 109234221Sbostic 031, "read path terminated before entire record was written", 109334221Sbostic 032, "could not find a gap after writing record and read path terminated early", 109434221Sbostic 033, "TU CMD did not load correctly to backup for retry of write tape mark", 109534221Sbostic 034, "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark", 109634221Sbostic 035, "TU CMD did not load correctly to backup to retry a load of BOT ID", 109734221Sbostic 036, "timeout looking for BOT after failing to write BOT ID", 109834221Sbostic 037, "TU velocity changed while writing PE gap before starting to write record", 109934221Sbostic 040, "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst", 110034221Sbostic 041, "TU CMD did not load correctly to set GCR tape density after writing Density ID", 110134221Sbostic 042, "TU CMD did not load correctly to set PE tape density at start of read from BOT", 110234221Sbostic 043, "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst", 110334221Sbostic }; 110417214Smckusick 110534221Sbostic /* MTER_TMFLTB */ 110634221Sbostic static char inlinetest[] = "inline test failed"; 110734221Sbostic static struct fmesg tmfltbmsg[] = { 110834221Sbostic 00, "RST0 interrupt occurred with TM RDY set", 110934221Sbostic 01, "power failed to interrupt", 111034221Sbostic 02, "unknown interrupt on channel 5.5", 111134221Sbostic 03, "unknown interrupt on channel 6.5", 111234221Sbostic 04, "unknown interrupt on channel 7", 111334221Sbostic 05, "unknown interrupt on channel 7.5", 111434221Sbostic 06, "CAS contention retry count expired", 111534221Sbostic 07, "CAS contention error not retryable", 111634221Sbostic 010, "queue error, could not find queue entry", 111734221Sbostic 011, "queue entry already full", 111834221Sbostic 012, "8085 ROM parity error", 111934221Sbostic 013, inlinetest, 112034221Sbostic 013, inlinetest, 112134221Sbostic 014, inlinetest, 112234221Sbostic 015, inlinetest, 112334221Sbostic 016, inlinetest, 112434221Sbostic 017, inlinetest, 112534221Sbostic 020, inlinetest, 112634221Sbostic 021, inlinetest, 112734221Sbostic 022, inlinetest, 112834221Sbostic 023, inlinetest, 112934221Sbostic 024, inlinetest, 113034221Sbostic 025, inlinetest, 113134221Sbostic 026, inlinetest, 113234221Sbostic 027, inlinetest, 113334221Sbostic 030, inlinetest, 113434221Sbostic 031, inlinetest, 113534221Sbostic 032, inlinetest, 113634221Sbostic 033, inlinetest, 113734221Sbostic 034, inlinetest, 113834221Sbostic 035, inlinetest, 113934221Sbostic 036, inlinetest, 114034221Sbostic 037, inlinetest, 114134221Sbostic 040, inlinetest, 114234221Sbostic 041, inlinetest, 114334221Sbostic 042, inlinetest, 114434221Sbostic 043, inlinetest, 114534221Sbostic 044, inlinetest, 1146*36548Sbostic 045, inlinetest, 114734221Sbostic 046, inlinetest, 114834221Sbostic 047, inlinetest, 114934221Sbostic 050, inlinetest, 115034221Sbostic 051, inlinetest, 115134221Sbostic 052, inlinetest, 115234221Sbostic 053, inlinetest, 115334221Sbostic 054, inlinetest, 115434221Sbostic 055, inlinetest, 115534221Sbostic 056, inlinetest, 115634221Sbostic 057, inlinetest, 115734221Sbostic -1, unclass 115834221Sbostic }; 115917214Smckusick 116034221Sbostic /* MTER_MBFLT */ 116134221Sbostic static struct fmesg mbfltmsg[] = { 116234221Sbostic 01, "control bus parity error", 116334221Sbostic 02, "illegal register referenced", 116434221Sbostic -1, unclass 116534221Sbostic }; 116617214Smckusick 116734221Sbostic /* 116834221Sbostic * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL, 116934221Sbostic * and default: no failure message. 117034221Sbostic */ 117134221Sbostic static struct fmesg nullmsg[] = { 117234221Sbostic -1, "" 117334221Sbostic }; 117417214Smckusick 117534221Sbostic /* 117634221Sbostic * Interrupt code table. 117734221Sbostic */ 117834221Sbostic static struct errmsg { 117934221Sbostic int e_code; 118034221Sbostic char *e_mesg; 118134221Sbostic struct fmesg *e_fmesg; 118234221Sbostic } errmsg[] = { 118334221Sbostic MTER_BOT, "unexpected BOT", botmsg, 118434221Sbostic MTER_LEOT, "unexpected LEOT", nullmsg, 118534221Sbostic MTER_RWDING, "tape rewinding", nullmsg, 118634221Sbostic MTER_NOTRDY, "drive not ready", notrdymsg, 118734221Sbostic MTER_NOTAVL, "drive not available", nullmsg, 118834221Sbostic MTER_NONEX, "unit does not exist", nullmsg, 118934221Sbostic MTER_NOTCAP, "not capable", notcapmsg, 119034221Sbostic MTER_LONGREC, "long record", longrecmsg, 119134221Sbostic MTER_UNREAD, "unreadable record", code22msg, 119234221Sbostic MTER_ERROR, "error", code22msg, 119334221Sbostic MTER_EOTERR, "EOT error", code22msg, 119434221Sbostic MTER_BADTAPE, "tape position lost", code22msg, 119534221Sbostic MTER_TMFLTA, "TM fault A", tmfltamsg, 119634221Sbostic MTER_TUFLTA, "TU fault A", tufltamsg, 119734221Sbostic MTER_TMFLTB, "TM fault B", tmfltbmsg, 119834221Sbostic MTER_MBFLT, "MB fault", mbfltmsg, 119934221Sbostic MTER_KEYFAIL, "keypad entry error", nullmsg, 120034221Sbostic -1, "unclassified error", nullmsg 120134221Sbostic }; 120217214Smckusick 120334221Sbostic /* 120434221Sbostic * Decode an interrupt-time failure. 120534221Sbostic */ 120634221Sbostic mtintfail(erreg) 120734221Sbostic int erreg; 120834221Sbostic { 120934221Sbostic register struct errmsg *e; 121034221Sbostic register struct fmesg *f; 121134221Sbostic register int ecode, fcode; 121217214Smckusick 121334221Sbostic ecode = erreg & MTER_INTCODE; 121434221Sbostic fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT; 121534221Sbostic for (e = errmsg; e->e_code >= 0; e++) 121634221Sbostic if (e->e_code == ecode) 121717214Smckusick break; 121834221Sbostic for (f = e->e_fmesg; f->f_code >= 0; f++) 121934221Sbostic if (f->f_code == fcode) 122017214Smckusick break; 122134221Sbostic printf(" interrupt code = 0%o <%s>\n", ecode, e->e_mesg); 122234221Sbostic printf(" failure code = 0%o <%s>\n", fcode, f->f_mesg); 122317214Smckusick } 122434221Sbostic #endif /* MTLERRM */ 122534221Sbostic #endif /* NMT > 0 */ 1226