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*45802Sbostic * @(#)mt.c 7.9 (Berkeley) 12/16/90 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 26*45802Sbostic #include "sys/param.h" 27*45802Sbostic #include "sys/systm.h" 28*45802Sbostic #include "sys/buf.h" 29*45802Sbostic #include "sys/conf.h" 30*45802Sbostic #include "sys/file.h" 31*45802Sbostic #include "sys/user.h" 32*45802Sbostic #include "sys/proc.h" 33*45802Sbostic #include "sys/map.h" 34*45802Sbostic #include "sys/ioctl.h" 35*45802Sbostic #include "sys/mtio.h" 36*45802Sbostic #include "sys/cmap.h" 37*45802Sbostic #include "sys/tty.h" 38*45802Sbostic #include "sys/syslog.h" 394736Swnj 40*45802Sbostic #include "../include/pte.h" 41*45802Sbostic #include "../include/cpu.h" 4217119Sbloom #include "mbareg.h" 4317119Sbloom #include "mbavar.h" 4417119Sbloom #include "mtreg.h" 454736Swnj 4617214Smckusick #define MTTIMEOUT 10000 /* loop limit for controller test */ 4717214Smckusick #define INF 1000000L /* a block number that won't exist */ 4817214Smckusick #define MASKREG(r) ((r) & 0xffff) /* the control registers have 16 bits */ 494736Swnj 5017214Smckusick /* Bits for sc_flags */ 514736Swnj 5217214Smckusick #define H_WRITTEN 01 /* last operation was a write */ 5317214Smckusick #define H_EOT 02 /* end of tape encountered */ 5417214Smckusick #define H_IEOT 04 /* ignore EOT condition */ 554736Swnj 5634221Sbostic int mt_do_readrev = 1; 5717214Smckusick 5817214Smckusick /* Per unit status information */ 5917214Smckusick 604736Swnj struct mu_softc { 6134221Sbostic char sc_openf; /* unit is open if != 0 */ 6234221Sbostic char sc_flags; /* state flags */ 6334221Sbostic daddr_t sc_blkno; /* current physical block number */ 6434221Sbostic daddr_t sc_nxrec; /* firewall input block number */ 6534221Sbostic u_short sc_erreg; /* copy of mter or mtner */ 6634221Sbostic u_short sc_dsreg; /* copy of mtds */ 6734221Sbostic short sc_resid; /* residual function count for ioctl */ 6834221Sbostic short sc_dens; /* density code - MT_GCR or zero */ 6934221Sbostic int sc_i_mtas; /* mtas at slave attach time */ 7034221Sbostic int sc_i_mtner; /* mtner at slave attach time */ 7134221Sbostic int sc_i_mtds; /* mtds at slave attach time */ 7240899Ssklower caddr_t sc_ctty; /* record user's tty for errors */ 7334221Sbostic int sc_blks; /* number of I/O operations since open */ 7434221Sbostic int sc_softerrs; /* number of soft I/O errors since open */ 754736Swnj } mu_softc[NMU]; 764736Swnj 7717214Smckusick struct buf cmtbuf[NMT]; /* tape command buffer structures */ 784736Swnj 7934221Sbostic struct mba_device *mtinfo[NMT]; /* unit to ctlr structures */ 8034221Sbostic struct mba_slave *muinfo[NMU]; /* unit to slave structures */ 8134221Sbostic 8217214Smckusick char mtds_bits[] = MTDS_BITS; /* mtds bit names for error messages */ 8317214Smckusick short mttypes[] = { MBDT_TU78, 0 }; 844736Swnj 8517214Smckusick int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint(); 8617214Smckusick struct mba_driver mtdriver = 8717214Smckusick { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint, 8817214Smckusick mttypes, "mt", "mu", mtinfo }; 8917214Smckusick 9034221Sbostic /* Bits in minor device */ 9134221Sbostic #define MUUNIT(dev) (minor(dev)&03) 9234221Sbostic #define H_NOREWIND 04 9334221Sbostic #define H_6250BPI 010 9417214Smckusick 9534221Sbostic #define MTUNIT(dev) (muinfo[MUUNIT(dev)]->ms_ctlr) 9634221Sbostic 9734221Sbostic void mtcreset(); 9834221Sbostic 994736Swnj /*ARGSUSED*/ 1004736Swnj mtattach(mi) 1014736Swnj struct mba_device *mi; 1024736Swnj { 10334221Sbostic 10434221Sbostic /* void */ 1054736Swnj } 1064736Swnj 1077431Skre mtslave(mi, ms, sn) 1084736Swnj struct mba_device *mi; 1094736Swnj struct mba_slave *ms; 1107431Skre int sn; 1114736Swnj { 1124736Swnj register struct mu_softc *sc = &mu_softc[ms->ms_unit]; 1134736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 11426377Skarels int s = spl5(), rtn = 0, i; 1154736Swnj 11634221Sbostic /* 11734221Sbostic * Just in case the controller is ill, reset it. Then issue 11834221Sbostic * a sense operation and wait about a second for it to respond. 11934221Sbostic */ 12017214Smckusick mtcreset(mtaddr); 1214736Swnj mtaddr->mtas = -1; 1227431Skre mtaddr->mtncs[sn] = MT_SENSE|MT_GO; 12334221Sbostic for (i = MTTIMEOUT; i > 0; i--) { 12417214Smckusick DELAY(50); 12517214Smckusick if (MASKREG(mtaddr->mtas) != 0) 12617214Smckusick break; 12717214Smckusick } 12817214Smckusick sc->sc_i_mtas = mtaddr->mtas; 12917214Smckusick sc->sc_i_mtner = mtaddr->mtner; 13017214Smckusick sc->sc_i_mtds = mtaddr->mtds; 13117214Smckusick 13234221Sbostic /* 13334221Sbostic * If no response, whimper. If wrong response, call it an 13434221Sbostic * unsolicited interrupt and use mtndtint to log and correct. 13534221Sbostic * Otherwise, note whether this slave exists. 13634221Sbostic */ 13734221Sbostic if (i <= 0) 13817214Smckusick printf("mt: controller hung\n"); 13934221Sbostic else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE) 14017214Smckusick (void) mtndtint(mi); 14134654Skarels else if (mtaddr->mtds & MTDS_PRES) { 14234654Skarels muinfo[ms->ms_unit] = ms; 1434736Swnj rtn = 1; 14434654Skarels } 14517214Smckusick 14634221Sbostic /* cancel the interrupt, then wait a little while for it to go away */ 1474736Swnj mtaddr->mtas = mtaddr->mtas; 14817214Smckusick DELAY(10); 1494736Swnj splx(s); 1504736Swnj return (rtn); 1514736Swnj } 1524736Swnj 1534736Swnj mtopen(dev, flag) 1544736Swnj dev_t dev; 1554736Swnj int flag; 1564736Swnj { 1574736Swnj register int muunit; 1584736Swnj register struct mu_softc *sc; 15934221Sbostic register struct mba_slave *ms; 1604736Swnj 1614736Swnj muunit = MUUNIT(dev); 16234221Sbostic if (muunit >= NMU || (ms = muinfo[muunit]) == NULL || 16334221Sbostic ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0) 1648581Sroot return (ENXIO); 16517214Smckusick if ((sc = &mu_softc[muunit])->sc_openf) 16617214Smckusick return (EBUSY); 16734221Sbostic sc->sc_openf = 1; 16817214Smckusick sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0; 1694736Swnj mtcommand(dev, MT_SENSE, 1); 1704736Swnj if ((sc->sc_dsreg & MTDS_ONL) == 0) { 1714736Swnj uprintf("mu%d: not online\n", muunit); 17234221Sbostic sc->sc_openf = 0; 1738581Sroot return (EIO); 1744736Swnj } 17517214Smckusick if ((sc->sc_dsreg & MTDS_AVAIL) == 0) { 17617214Smckusick uprintf("mu%d: not online (port selector)\n", muunit); 17734221Sbostic sc->sc_openf = 0; 17817214Smckusick return (EIO); 17917214Smckusick } 18017214Smckusick if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) { 1814736Swnj uprintf("mu%d: no write ring\n", muunit); 18234221Sbostic sc->sc_openf = 0; 1838581Sroot return (EIO); 1844736Swnj } 18534221Sbostic if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) && 18634221Sbostic (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) { 1874736Swnj uprintf("mu%d: can't change density in mid-tape\n", muunit); 18834221Sbostic sc->sc_openf = 0; 1898581Sroot return (EIO); 1904736Swnj } 1914736Swnj sc->sc_blkno = (daddr_t)0; 19217214Smckusick 19334221Sbostic /* 19434221Sbostic * Since cooked I/O may do a read-ahead before a write, trash 19534221Sbostic * on a tape can make the first write fail. Suppress the first 19634221Sbostic * read-ahead unless definitely doing read-write. 19734221Sbostic */ 19834221Sbostic sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ? 19934221Sbostic (daddr_t)0 : (daddr_t)INF; 2004736Swnj sc->sc_flags = 0; 20134221Sbostic sc->sc_blks = 0; 20234221Sbostic sc->sc_softerrs = 0; 20340899Ssklower sc->sc_ctty = (caddr_t)(u.u_procp->p_flag&SCTTY ? 20440899Ssklower u.u_procp->p_session->s_ttyp : 0); 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; 22340733Skarels return (0); 2244736Swnj } 2254736Swnj 2264736Swnj mtcommand(dev, com, count) 2274736Swnj dev_t dev; 2284736Swnj int com, count; 2294736Swnj { 2304736Swnj register struct buf *bp; 23134221Sbostic int s; 2324736Swnj 2334736Swnj bp = &cmtbuf[MTUNIT(dev)]; 2345437Sroot s = spl5(); 23517214Smckusick while (bp->b_flags & B_BUSY) { 23634221Sbostic if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE)) 2374736Swnj break; 2384736Swnj bp->b_flags |= B_WANTED; 2394736Swnj sleep((caddr_t)bp, PRIBIO); 2404736Swnj } 2414736Swnj bp->b_flags = B_BUSY|B_READ; 2425437Sroot splx(s); 2434736Swnj bp->b_dev = dev; 2444736Swnj bp->b_command = com; 2454736Swnj bp->b_repcnt = count; 2464736Swnj bp->b_blkno = 0; 24717214Smckusick bp->b_error = 0; 2484736Swnj mtstrategy(bp); 2494736Swnj if (count == 0) 2504736Swnj return; 25134221Sbostic biowait(bp); 25217214Smckusick if (bp->b_flags & B_WANTED) 2534736Swnj wakeup((caddr_t)bp); 2544736Swnj bp->b_flags &= B_ERROR; 2554736Swnj } 2564736Swnj 2574736Swnj mtstrategy(bp) 2584736Swnj register struct buf *bp; 2594736Swnj { 2604736Swnj register struct buf *dp; 26134221Sbostic struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)]; 26234221Sbostic int s; 2634736Swnj 26434221Sbostic /* 26534221Sbostic * If this is a data transfer operation, set the resid to a 26634221Sbostic * default value (EOF) to simplify getting it right during 26734221Sbostic * error recovery or bail out. 26834221Sbostic */ 26917214Smckusick if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 27017214Smckusick bp->b_resid = bp->b_bcount; 27117214Smckusick 27234221Sbostic /* 27334221Sbostic * Link this request onto the end of the queue for this 27434221Sbostic * controller, then start I/O if not already active. 27534221Sbostic */ 2764736Swnj bp->av_forw = NULL; 2774736Swnj dp = &mi->mi_tab; 2785437Sroot s = spl5(); 2794736Swnj if (dp->b_actf == NULL) 2804736Swnj dp->b_actf = bp; 2814736Swnj else 2824736Swnj dp->b_actl->av_forw = bp; 2834736Swnj dp->b_actl = bp; 2844736Swnj if (dp->b_active == 0) 2854736Swnj mbustart(mi); 2865437Sroot splx(s); 2874736Swnj } 2884736Swnj 2894736Swnj mtustart(mi) 2904736Swnj register struct mba_device *mi; 2914736Swnj { 29217214Smckusick register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 2934736Swnj register struct buf *bp = mi->mi_tab.b_actf; 2944736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 2954736Swnj daddr_t blkno; 29626377Skarels int count; 2974736Swnj 2984736Swnj if (sc->sc_openf < 0) { 2994736Swnj bp->b_flags |= B_ERROR; 3004736Swnj return (MBU_NEXT); 3014736Swnj } 3024736Swnj if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) { 30334221Sbostic /* 30434221Sbostic * Data transfer. If write at end of tape, 30534221Sbostic * signal "no space" unless suppressed 30634221Sbostic * by MTIOCIEOT. 30734221Sbostic */ 30834221Sbostic if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT && 30934221Sbostic (bp->b_flags & B_READ) == 0) { 3104736Swnj bp->b_flags |= B_ERROR; 31117214Smckusick bp->b_error = ENOSPC; 3124736Swnj return (MBU_NEXT); 3134736Swnj } 31417214Smckusick 31534221Sbostic if (bp->b_flags & B_RAW) { 31634221Sbostic /* raw transfer; never seek */ 31734221Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno); 31834221Sbostic sc->sc_nxrec = sc->sc_blkno + 1; 31934221Sbostic } else { 32017214Smckusick /* seek beyond end of file */ 32117214Smckusick if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 32217214Smckusick bp->b_flags |= B_ERROR; 32317214Smckusick bp->b_error = ENXIO; 32417214Smckusick return (MBU_NEXT); 32517214Smckusick } 32617214Smckusick 32734221Sbostic /* 32834221Sbostic * This should be end of file, but the buffer 32934221Sbostic * system wants a one-block look-ahead. Humor it. 33034221Sbostic */ 33134221Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 33234221Sbostic bp->b_flags & B_READ) { 33334221Sbostic bp->b_resid = bp->b_bcount; 33417214Smckusick clrbuf(bp); 33517214Smckusick return (MBU_NEXT); 33617214Smckusick } 33717214Smckusick 33817214Smckusick /* If writing, mark the next block invalid. */ 33917214Smckusick if ((bp->b_flags & B_READ) == 0) 34017214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 3414736Swnj } 3424736Swnj } else { 34317214Smckusick /* It's a command, do it now. */ 3444736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3454736Swnj (bp->b_repcnt<<8)|bp->b_command|MT_GO; 3464736Swnj return (MBU_STARTED); 3474736Swnj } 34817214Smckusick 34934221Sbostic /* 35034221Sbostic * If raw I/O, or if the tape is positioned correctly for 35134221Sbostic * cooked I/O, set the byte count, unit number and repeat count 35234221Sbostic * then tell the MASSBUS to proceed. Note that a negative 35334221Sbostic * bcount tells mbstart to map the buffer for "read backwards". 35434221Sbostic */ 35534221Sbostic if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3564736Swnj if (mi->mi_tab.b_errcnt == 2) { 35734221Sbostic mtaddr->mtbc = -bp->b_bcount; 3584736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 3594736Swnj } else { 3604736Swnj mtaddr->mtbc = bp->b_bcount; 3614736Swnj mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev); 3624736Swnj } 3634736Swnj return (MBU_DODATA); 3644736Swnj } 36517214Smckusick 36617214Smckusick /* Issue skip operations to position the next block for cooked I/O. */ 36717214Smckusick 3687380Ssam if (blkno < bdbtofsb(bp->b_blkno)) 36934221Sbostic count = bdbtofsb(bp->b_blkno) - blkno; 3704736Swnj else 37134221Sbostic count = blkno - bdbtofsb(bp->b_blkno); 37234221Sbostic if ((unsigned)count > 0377) 37326377Skarels count = 0377; 37426377Skarels mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO; 3754736Swnj return (MBU_STARTED); 3764736Swnj } 3774736Swnj 3784736Swnj mtstart(mi) 3794736Swnj register struct mba_device *mi; 3804736Swnj { 3814736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3824736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 3834736Swnj 3844736Swnj if (bp->b_flags & B_READ) 3854736Swnj if (mi->mi_tab.b_errcnt == 2) 38634221Sbostic return (MT_READREV|MT_GO); 3874736Swnj else 38834221Sbostic return (MT_READ|MT_GO); 3894736Swnj else 39034221Sbostic return (MT_WRITE|sc->sc_dens|MT_GO); 3914736Swnj } 3924736Swnj 3934736Swnj mtdtint(mi, mbsr) 3944736Swnj register struct mba_device *mi; 3954736Swnj int mbsr; 3964736Swnj { 3974736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 3984736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3994736Swnj register struct mu_softc *sc; 40017214Smckusick register int er; 4014736Swnj 40217214Smckusick /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */ 40317214Smckusick if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) { 4044736Swnj printf("mt: wrong unit!\n"); 4054736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 4064736Swnj } 40717214Smckusick 40817214Smckusick er = MASKREG(mtaddr->mter); 4094736Swnj sc = &mu_softc[MUUNIT(bp->b_dev)]; 41017214Smckusick sc->sc_erreg = er; 41117214Smckusick if (bp->b_flags & B_READ) 41217214Smckusick sc->sc_flags &= ~H_WRITTEN; 41317214Smckusick else 4144736Swnj sc->sc_flags |= H_WRITTEN; 41517214Smckusick switch (er & MTER_INTCODE) { 41617214Smckusick 41717214Smckusick case MTER_EOT: 41817214Smckusick sc->sc_flags |= H_EOT; 41917214Smckusick /* fall into MTER_DONE */ 42017214Smckusick 4214736Swnj case MTER_DONE: 42217214Smckusick sc->sc_blkno++; 42317214Smckusick if (mi->mi_tab.b_errcnt == 2) { 42417214Smckusick bp->b_bcount = bp->b_resid; 42517214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 42634221Sbostic if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0) 42717214Smckusick bp->b_flags |= B_ERROR; 42834221Sbostic } else 42917214Smckusick bp->b_resid = 0; 43017214Smckusick break; 43117214Smckusick 43217214Smckusick case MTER_SHRTREC: 43317214Smckusick sc->sc_blkno++; 43417214Smckusick bp->b_bcount = bp->b_resid; 43517214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 43634221Sbostic if ((bp->b_flags & B_RAW) == 0) 43717214Smckusick bp->b_flags |= B_ERROR; 43817214Smckusick break; 43917214Smckusick 44017214Smckusick case MTER_RETRY: 44134221Sbostic /* 44234221Sbostic * Simple re-try. Since resid is always a copy of the 44334221Sbostic * original byte count, use it to restore the count. 44434221Sbostic */ 44517214Smckusick mi->mi_tab.b_errcnt = 1; 44617214Smckusick bp->b_bcount = bp->b_resid; 44734221Sbostic return (MBD_RETRY); 44817214Smckusick 44917214Smckusick case MTER_RDOPP: 45034221Sbostic /* 45134221Sbostic * The controller just decided to read it backwards. 45234221Sbostic * If the controller returns a byte count of zero, 45334221Sbostic * change it to 1, since zero encodes 65536, which 45434221Sbostic * isn't quite what we had in mind. The byte count 45534221Sbostic * may be larger than the size of the input buffer, so 45634221Sbostic * limit the count to the buffer size. After 45734221Sbostic * making the byte count reasonable, set bcount to the 45834221Sbostic * negative of the controller's version of the byte 45934221Sbostic * count so that the start address for the transfer is 46034221Sbostic * set up correctly. 46134221Sbostic */ 46217214Smckusick if (mt_do_readrev) { 46317214Smckusick mi->mi_tab.b_errcnt = 2; 46417214Smckusick if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0) 46517214Smckusick bp->b_bcount = 1; 46617214Smckusick if (bp->b_bcount > bp->b_resid) 46717214Smckusick bp->b_bcount = bp->b_resid; 46817214Smckusick bp->b_bcount = -(bp->b_bcount); 46917214Smckusick return(MBD_RETRY); 47017214Smckusick } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) { 47117214Smckusick sc->sc_blkno++; 47217214Smckusick bp->b_bcount = bp->b_resid; 47317214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 47417214Smckusick bp->b_flags |= B_ERROR; 47517214Smckusick break; 47617214Smckusick } 47717214Smckusick bp->b_flags |= B_ERROR; 47817214Smckusick /* fall into MTER_LONGREC */ 47917214Smckusick 4804736Swnj case MTER_LONGREC: 48117214Smckusick sc->sc_blkno++; 48217214Smckusick bp->b_bcount = bp->b_resid; 4834736Swnj bp->b_resid = 0; 48417214Smckusick bp->b_error = ENOMEM; 48517214Smckusick bp->b_flags |= B_ERROR; 4864736Swnj break; 4874736Swnj 4884736Swnj case MTER_NOTCAP: 4894736Swnj printf("mu%d: blank tape\n", MUUNIT(bp->b_dev)); 4904736Swnj goto err; 4914736Swnj 4924736Swnj case MTER_TM: 49334221Sbostic /* 49434221Sbostic * End of file. Since the default byte count has 49534221Sbostic * already been set, just count the block and proceed. 49634221Sbostic */ 4974736Swnj sc->sc_blkno++; 4984736Swnj err: 49934221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno); 5004736Swnj break; 5014736Swnj 5024736Swnj case MTER_OFFLINE: 5034736Swnj if (sc->sc_openf > 0) { 5044736Swnj sc->sc_openf = -1; 50540899Ssklower tprintf(sc->sc_ctty, "mu%d: offline\n", 50634221Sbostic MUUNIT(bp->b_dev)); 5074736Swnj } 5084736Swnj bp->b_flags |= B_ERROR; 5094736Swnj break; 5104736Swnj 51117214Smckusick case MTER_NOTAVL: 51217214Smckusick if (sc->sc_openf > 0) { 51317214Smckusick sc->sc_openf = -1; 51440899Ssklower tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n", 51518324Sralph MUUNIT(bp->b_dev)); 51617214Smckusick } 51717214Smckusick bp->b_flags |= B_ERROR; 51817214Smckusick break; 51917214Smckusick 5204736Swnj case MTER_FPT: 52140899Ssklower tprintf(sc->sc_ctty, "mu%d: no write ring\n", 52234221Sbostic MUUNIT(bp->b_dev)); 5234736Swnj bp->b_flags |= B_ERROR; 5244736Swnj break; 5254736Swnj 52617214Smckusick case MTER_UNREAD: 52717214Smckusick sc->sc_blkno++; 52817214Smckusick bp->b_bcount = bp->b_resid; 52917214Smckusick bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount); 53017214Smckusick 53134221Sbostic /* code 010 means a garbage record, nothing serious. */ 53234221Sbostic if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) { 53340899Ssklower tprintf(sc->sc_ctty, 53434221Sbostic "mu%d: rn=%d bn=%d unreadable record\n", 53517214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno); 53617214Smckusick bp->b_flags |= B_ERROR; 53717214Smckusick break; 53817214Smckusick } 53917214Smckusick 54034221Sbostic /* 54134221Sbostic * Anything else might be a hardware problem, 54234221Sbostic * fall into the error report. 54334221Sbostic */ 54417214Smckusick 5454736Swnj default: 54634221Sbostic /* 54734221Sbostic * The bits in sc->sc_dsreg are from the last sense 54834221Sbostic * command. To get the most recent copy, you have to 54934221Sbostic * do a sense at interrupt level, which requires nested 55034221Sbostic * error processing. This is a bit messy, so leave 55134221Sbostic * well enough alone. 55234221Sbostic */ 55340899Ssklower tprintf(sc->sc_ctty, "\ 55434221Sbostic mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n", 55517214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 55617214Smckusick mbsr, mbsr_bits, er, 55717214Smckusick MASKREG(sc->sc_dsreg), mtds_bits); 55817214Smckusick #ifdef MTLERRM 55934221Sbostic mtintfail(er); 56017214Smckusick #endif 5614736Swnj bp->b_flags |= B_ERROR; 56217214Smckusick 56334221Sbostic /* 56434221Sbostic * The TM78 manual says to reset the controller after 56534221Sbostic * TM fault B or MASSBUS fault. 56634221Sbostic */ 56734221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 56834221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) 56917214Smckusick mtcreset(mtaddr); 5704736Swnj } 57117214Smckusick 57234221Sbostic /* 57334221Sbostic * Just in case some strange error slipped through (drive off 57434221Sbostic * line during read-reverse error recovery comes to mind), make 57534221Sbostic * sure the byte count is reasonable. 57634221Sbostic */ 57717214Smckusick if (bp->b_bcount < 0) 57817214Smckusick bp->b_bcount = bp->b_resid; 57934221Sbostic 58034221Sbostic if ((bp->b_flags & B_ERROR) == 0) { 58134221Sbostic /* this counts reverse reads as soft errors */ 58234221Sbostic sc->sc_blks++; 58334221Sbostic if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */ 58434221Sbostic sc->sc_softerrs++; 58534221Sbostic } 5864736Swnj return (MBD_DONE); 5874736Swnj } 5884736Swnj 5894736Swnj mtndtint(mi) 5904736Swnj register struct mba_device *mi; 5914736Swnj { 5924736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 5934736Swnj register struct buf *bp = mi->mi_tab.b_actf; 5944736Swnj register struct mu_softc *sc; 59517214Smckusick register int er, fc; 59617214Smckusick int unit; 5974736Swnj 5984736Swnj unit = (mtaddr->mtner >> 8) & 3; 5994736Swnj er = MASKREG(mtaddr->mtner); 60017214Smckusick sc = &mu_softc[unit]; 60117214Smckusick sc->sc_erreg = er; 60217214Smckusick 60317214Smckusick /* Check for unsolicited interrupts. */ 60434221Sbostic if (bp == NULL || unit != MUUNIT(bp->b_dev)) { 60534221Sbostic if ((er & MTER_INTCODE) == MTER_ONLINE) 60634221Sbostic return (MBN_SKIP); 60717214Smckusick 60834221Sbostic printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n", 60934221Sbostic unit, er, MASKREG(sc->sc_dsreg), mtds_bits); 61017214Smckusick #ifdef MTLERRM 61134221Sbostic mtintfail(er); 61217214Smckusick #endif 61334221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 61434221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) { 61534221Sbostic /* 61634221Sbostic * Reset the controller, then set error status 61734221Sbostic * if there was anything active when the fault 61834221Sbostic * occurred. This may shoot an innocent 61934221Sbostic * bystander, but it's better than letting 62034221Sbostic * an error slip through. 62134221Sbostic */ 62234221Sbostic mtcreset(mtaddr); 62334221Sbostic if (bp != NULL) { 62434221Sbostic bp->b_flags |= B_ERROR; 62534221Sbostic return (MBN_DONE); 62617214Smckusick } 62717214Smckusick } 6284736Swnj return (MBN_SKIP); 6294736Swnj } 63017214Smckusick 6314736Swnj fc = (mtaddr->mtncs[unit] >> 8) & 0xff; 6324736Swnj sc->sc_resid = fc; 63317214Smckusick 63434221Sbostic /* 63534221Sbostic * Clear the "written" flag after any operation that changes 63634221Sbostic * the position of the tape. 63734221Sbostic */ 63834221Sbostic if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE) 63917214Smckusick sc->sc_flags &= ~H_WRITTEN; 64017214Smckusick 6414736Swnj switch (er & MTER_INTCODE) { 64217214Smckusick 64317214Smckusick case MTER_EOT: 64417214Smckusick sc->sc_flags |= H_EOT; 64517214Smckusick /* fall into MTER_DONE */ 64617214Smckusick 6474736Swnj case MTER_DONE: 64817214Smckusick /* If this is a command buffer, just update the status. */ 6494736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 6504736Swnj done: 6514736Swnj if (bp->b_command == MT_SENSE) 6524736Swnj sc->sc_dsreg = MASKREG(mtaddr->mtds); 6534736Swnj return (MBN_DONE); 6544736Swnj } 65517214Smckusick 65634221Sbostic /* 65734221Sbostic * It's not a command buffer, must be a cooked I/O 65834221Sbostic * skip operation (perhaps a shaky assumption, but it 65934221Sbostic * wasn't my idea). 66034221Sbostic */ 6617380Ssam if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0) 6626186Ssam sc->sc_blkno -= MIN(0377, -fc); 6634736Swnj else 6646186Ssam sc->sc_blkno += MIN(0377, fc); 6654736Swnj return (MBN_RETRY); 6664736Swnj 66717214Smckusick case MTER_ONLINE: /* ddj -- shouldn't happen but did */ 6684736Swnj case MTER_RWDING: 6694736Swnj return (MBN_SKIP); /* ignore "rewind started" interrupt */ 6704736Swnj 6714736Swnj case MTER_NOTCAP: 67240899Ssklower tprintf(sc->sc_ctty, "mu%d: blank tape\n", MUUNIT(bp->b_dev)); 67317214Smckusick bp->b_flags |= B_ERROR; 67417214Smckusick return (MBN_DONE); 6754736Swnj 6764736Swnj case MTER_TM: 6774736Swnj case MTER_LEOT: 67834221Sbostic /* 67934221Sbostic * For an ioctl skip operation, count a tape mark as 68034221Sbostic * a record. If there's anything left to do, update 68134221Sbostic * the repeat count and re-start the command. 68234221Sbostic */ 68317214Smckusick if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 68417214Smckusick if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0) 68517214Smckusick return (MBN_DONE); 68617214Smckusick else 68717214Smckusick return (MBN_RETRY); 6884736Swnj } else { 68934221Sbostic /* 69034221Sbostic * Cooked I/O again. Just update the books and 69134221Sbostic * wait for someone else to return end of file or 69234221Sbostic * complain about a bad seek. 69334221Sbostic */ 69434221Sbostic if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 69534221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1; 69634221Sbostic sc->sc_blkno = sc->sc_nxrec; 69734221Sbostic } else { 69834221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc; 69934221Sbostic sc->sc_blkno = sc->sc_nxrec + 1; 70034221Sbostic } 7014736Swnj } 7024736Swnj return (MBN_RETRY); 7034736Swnj 7044736Swnj case MTER_FPT: 70540899Ssklower tprintf(sc->sc_ctty, "mu%d: no write ring\n", 70634221Sbostic MUUNIT(bp->b_dev)); 7074736Swnj bp->b_flags |= B_ERROR; 7084736Swnj return (MBN_DONE); 7094736Swnj 7104736Swnj case MTER_OFFLINE: 71117214Smckusick /* If `off line' was intentional, don't complain. */ 71234221Sbostic if (bp == &cmtbuf[MTUNIT(bp->b_dev)] && 71334221Sbostic bp->b_command == MT_UNLOAD) 71417214Smckusick return(MBN_DONE); 7154736Swnj if (sc->sc_openf > 0) { 7164736Swnj sc->sc_openf = -1; 71740899Ssklower tprintf(sc->sc_ctty, "mu%d: offline\n", 71834221Sbostic MUUNIT(bp->b_dev)); 7194736Swnj } 7204736Swnj bp->b_flags |= B_ERROR; 7214736Swnj return (MBN_DONE); 7224736Swnj 72317214Smckusick case MTER_NOTAVL: 72417214Smckusick if (sc->sc_openf > 0) { 72517214Smckusick sc->sc_openf = -1; 72640899Ssklower tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n", 72734221Sbostic MUUNIT(bp->b_dev)); 72817214Smckusick } 72917214Smckusick bp->b_flags |= B_ERROR; 73017214Smckusick return (MBN_DONE); 73117214Smckusick 7324736Swnj case MTER_BOT: 7334736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 7344736Swnj goto done; 73517214Smckusick /* fall through */ 73617214Smckusick 7374736Swnj default: 73840899Ssklower tprintf(sc->sc_ctty, "\ 73934221Sbostic mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n", 74017214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 74117214Smckusick er, MASKREG(sc->sc_dsreg), mtds_bits); 74217214Smckusick #ifdef MTLERRM 74334221Sbostic mtintfail(er); 74417214Smckusick #endif 74534221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 74634221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) 74717214Smckusick mtcreset(mtaddr); /* reset the controller */ 7484736Swnj bp->b_flags |= B_ERROR; 7494736Swnj return (MBN_DONE); 7504736Swnj } 7514736Swnj /* NOTREACHED */ 7524736Swnj } 7534736Swnj 75434221Sbostic void 75534221Sbostic mtcreset(mtaddr) 75617214Smckusick register struct mtdevice *mtaddr; 75717214Smckusick { 75817214Smckusick register int i; 75917214Smckusick 76017214Smckusick mtaddr->mtid = MTID_CLR; /* reset the TM78 */ 76117214Smckusick DELAY(200); 76217214Smckusick for (i = MTTIMEOUT; i > 0; i--) { 76317214Smckusick DELAY(50); /* don't nag */ 76417214Smckusick if ((mtaddr->mtid & MTID_RDY) != 0) 76517214Smckusick return; /* exit when ready */ 76617214Smckusick } 76717214Smckusick printf("mt: controller hung\n"); 76817214Smckusick } 76917214Smckusick 7704736Swnj /*ARGSUSED*/ 7717637Ssam mtioctl(dev, cmd, data, flag) 7724736Swnj dev_t dev; 7734736Swnj int cmd; 7747637Ssam caddr_t data; 7754736Swnj int flag; 7764736Swnj { 7774736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 7784736Swnj register struct buf *bp = &cmtbuf[MTUNIT(dev)]; 77917214Smckusick register struct mtop *mtop; 78017214Smckusick register struct mtget *mtget; 78140909Ssklower int callcount, fcount, error = 0; 78217214Smckusick int op; 78317214Smckusick 78417214Smckusick /* We depend on the values and order of the MT codes here. */ 78517214Smckusick 7864736Swnj static mtops[] = 7874736Swnj {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE}; 7884736Swnj 7894736Swnj switch (cmd) { 7907637Ssam 79117214Smckusick /* tape operation */ 79217214Smckusick 79317214Smckusick case MTIOCTOP: 7948606Sroot mtop = (struct mtop *)data; 7958606Sroot switch (mtop->mt_op) { 7967637Ssam 7974736Swnj case MTWEOF: 7987637Ssam callcount = mtop->mt_count; 7994736Swnj fcount = 1; 8004736Swnj break; 8017637Ssam 8024736Swnj case MTFSF: case MTBSF: 8037637Ssam callcount = mtop->mt_count; 8044736Swnj fcount = 1; 8054736Swnj break; 8067637Ssam 8074736Swnj case MTFSR: case MTBSR: 8084736Swnj callcount = 1; 8097637Ssam fcount = mtop->mt_count; 8104736Swnj break; 8117637Ssam 8124736Swnj case MTREW: case MTOFFL: 8134736Swnj callcount = 1; 8144736Swnj fcount = 1; 8154736Swnj break; 8167637Ssam 8174736Swnj default: 8188581Sroot return (ENXIO); 8194736Swnj } 82034221Sbostic if (callcount <= 0 || fcount <= 0) 8218581Sroot return (EINVAL); 8227637Ssam op = mtops[mtop->mt_op]; 8234736Swnj if (op == MT_WTM) 8244736Swnj op |= sc->sc_dens; 8254736Swnj while (--callcount >= 0) { 82617214Smckusick register int n, fc = fcount; 8274736Swnj 8284736Swnj do { 82917214Smckusick n = MIN(fc, 0xff); 8304736Swnj mtcommand(dev, op, n); 83117214Smckusick n -= sc->sc_resid; 83217214Smckusick fc -= n; 83317214Smckusick switch (mtop->mt_op) { 83417214Smckusick 83517214Smckusick case MTWEOF: 83617214Smckusick sc->sc_blkno += (daddr_t)n; 83717214Smckusick sc->sc_nxrec = sc->sc_blkno - 1; 83817214Smckusick break; 83917214Smckusick 84017214Smckusick case MTOFFL: 84117214Smckusick case MTREW: 84217214Smckusick case MTFSF: 84317214Smckusick sc->sc_blkno = (daddr_t)0; 84417214Smckusick sc->sc_nxrec = (daddr_t)INF; 84517214Smckusick break; 84617214Smckusick 84717214Smckusick case MTBSF: 84817214Smckusick if (sc->sc_resid) { 84917214Smckusick sc->sc_blkno = (daddr_t)0; 85017214Smckusick sc->sc_nxrec = (daddr_t)INF; 85117214Smckusick } else { 85217214Smckusick sc->sc_blkno = (daddr_t)(-1); 85317214Smckusick sc->sc_nxrec = (daddr_t)(-1); 85417214Smckusick } 85517214Smckusick break; 85617214Smckusick 85717214Smckusick case MTFSR: 85817214Smckusick sc->sc_blkno += (daddr_t)n; 85917214Smckusick break; 86017214Smckusick 86117214Smckusick case MTBSR: 86217214Smckusick sc->sc_blkno -= (daddr_t)n; 86317214Smckusick break; 86417214Smckusick } 86517214Smckusick if (sc->sc_resid) 86617214Smckusick break; 86717214Smckusick } while (fc); 86817214Smckusick if (fc) { 86917214Smckusick sc->sc_resid = callcount + fc; 87034221Sbostic if (mtop->mt_op == MTFSR || 87134221Sbostic mtop->mt_op == MTBSR) 87217214Smckusick return (EIO); 87334221Sbostic break; 87417214Smckusick } 87517214Smckusick if (bp->b_flags & B_ERROR) 8764736Swnj break; 8774736Swnj } 87840909Ssklower if (bp->b_flags&B_ERROR) 87940909Ssklower if ((error = bp->b_error)==0) 88040909Ssklower return (EIO); 88140909Ssklower return (error); 8827637Ssam 88317214Smckusick /* tape status */ 8844736Swnj case MTIOCGET: 8857637Ssam mtget = (struct mtget *)data; 8867637Ssam mtget->mt_erreg = sc->sc_erreg; 8877637Ssam mtget->mt_resid = sc->sc_resid; 8884736Swnj mtcommand(dev, MT_SENSE, 1); /* update drive status */ 8897637Ssam mtget->mt_dsreg = sc->sc_dsreg; 8907637Ssam mtget->mt_type = MT_ISMT; 8918581Sroot break; 8927637Ssam 89317214Smckusick /* ignore EOT condition */ 89417214Smckusick case MTIOCIEOT: 89517214Smckusick sc->sc_flags |= H_IEOT; 89617214Smckusick break; 89717214Smckusick 89817214Smckusick /* enable EOT condition */ 89917214Smckusick case MTIOCEEOT: 90017214Smckusick sc->sc_flags &= ~H_IEOT; 90117214Smckusick break; 90217214Smckusick 9034736Swnj default: 9048581Sroot return (ENXIO); 9054736Swnj } 9068581Sroot return (0); 9074736Swnj } 9084736Swnj 9094736Swnj #define DBSIZE 20 9104736Swnj 9114736Swnj mtdump() 9124736Swnj { 9134736Swnj register struct mba_device *mi; 9144736Swnj register struct mba_regs *mp; 9154736Swnj int blk, num; 9164736Swnj int start; 9174736Swnj 9184736Swnj start = 0; 9194736Swnj num = maxfree; 9204736Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 9214736Swnj if (mtinfo[0] == 0) 9224736Swnj return (ENXIO); 9234736Swnj mi = phys(mtinfo[0], struct mba_device *); 9244736Swnj mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 9254736Swnj mp->mba_cr = MBCR_IE; 9266186Ssam #if lint 9278606Sroot blk = 0; num = blk; start = num; blk = start; 9286186Ssam return (0); 9296186Ssam #endif 9306186Ssam #ifdef notyet 9314736Swnj mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive]; 9324736Swnj mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI; 9334736Swnj mtaddr->mtcs1 = MT_DCLR|MT_GO; 9344736Swnj while (num > 0) { 9354736Swnj blk = num > DBSIZE ? DBSIZE : num; 9364736Swnj mtdwrite(start, blk, mtaddr, mp); 9374736Swnj start += blk; 9384736Swnj num -= blk; 9394736Swnj } 9404736Swnj mteof(mtaddr); 9414736Swnj mteof(mtaddr); 9424736Swnj mtwait(mtaddr); 9434736Swnj if (mtaddr->mtds&MTDS_ERR) 9444736Swnj return (EIO); 9454736Swnj mtaddr->mtcs1 = MT_REW|MT_GO; 9464736Swnj return (0); 9474736Swnj } 9484736Swnj 9494736Swnj mtdwrite(dbuf, num, mtaddr, mp) 9504736Swnj register dbuf, num; 9514736Swnj register struct mtdevice *mtaddr; 9524736Swnj struct mba_regs *mp; 9534736Swnj { 9544736Swnj register struct pte *io; 9554736Swnj register int i; 9564736Swnj 9574736Swnj mtwait(mtaddr); 9584736Swnj io = mp->mba_map; 9594736Swnj for (i = 0; i < num; i++) 9604736Swnj *(int *)io++ = dbuf++ | PG_V; 9614736Swnj mtaddr->mtfc = -(num*NBPG); 9624736Swnj mp->mba_sr = -1; 9634736Swnj mp->mba_bcr = -(num*NBPG); 9644736Swnj mp->mba_var = 0; 9654736Swnj mtaddr->mtcs1 = MT_WCOM|MT_GO; 9664736Swnj } 9674736Swnj 9684736Swnj mtwait(mtaddr) 9694736Swnj struct mtdevice *mtaddr; 9704736Swnj { 9714736Swnj register s; 9724736Swnj 9734736Swnj do 9744736Swnj s = mtaddr->mtds; 9754736Swnj while ((s & MTDS_DRY) == 0); 9764736Swnj } 9774736Swnj 9784736Swnj mteof(mtaddr) 9794736Swnj struct mtdevice *mtaddr; 9804736Swnj { 9814736Swnj 9824736Swnj mtwait(mtaddr); 9834736Swnj mtaddr->mtcs1 = MT_WEOF|MT_GO; 9844736Swnj #endif notyet 9854736Swnj } 98617214Smckusick 98717214Smckusick #ifdef MTLERRM 98834221Sbostic /* 98934221Sbostic * Failure messages for each failure code, per interrupt code. 99034221Sbostic * Each table ends with a code of -1 as a default. 99134221Sbostic */ 99234221Sbostic struct fmesg { 99334221Sbostic int f_code; 99434221Sbostic char *f_mesg; 99534221Sbostic }; 99617214Smckusick 99734221Sbostic static char unclass[] = "unclassified failure code"; 99817214Smckusick 99934221Sbostic /* MTER_BOT */ 100034221Sbostic static struct fmesg botmsg[] = { 100134221Sbostic 01, "tape was at BOT", 100234221Sbostic 02, "BOT seen after tape started", 100334221Sbostic 03, "ARA ID detected", 100434221Sbostic -1, unclass 100534221Sbostic }; 100617214Smckusick 100734221Sbostic /* MTER_NOTRDY */ 100834221Sbostic static struct fmesg notrdymsg[] = { 100934221Sbostic 01, "TU on-line but not ready", 101034221Sbostic 02, "fatal error has occurred", 101136548Sbostic 03, "access allowed but not ready", 101234221Sbostic -1, unclass 101334221Sbostic }; 101417214Smckusick 101534221Sbostic /* MTER_NOTCAP */ 101634221Sbostic static struct fmesg notcapmsg[] = { 101734221Sbostic 01, "no record found within 25 feet", 101834221Sbostic 02, "ID burst neither PE nor GCR", 101934221Sbostic 03, "ARA ID not found", 102034221Sbostic 04, "no gap found after ID burst", 102134221Sbostic -1, unclass 102234221Sbostic }; 102317214Smckusick 102434221Sbostic /* MTER_LONGREC */ 102534221Sbostic static struct fmesg longrecmsg[] = { 102634221Sbostic 00, "extended sense data not found", 102734221Sbostic 01, "extended sense data updated", 102834221Sbostic -1, unclass 102934221Sbostic }; 103017214Smckusick 103134221Sbostic /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */ 103234221Sbostic static struct fmesg code22msg[] = { 103334221Sbostic 01, "GCR write error", 103434221Sbostic 02, "GCR read error", 103534221Sbostic 03, "PE read error", 103634221Sbostic 04, "PE write error", 103734221Sbostic 05, "at least 1 bit set in ECCSTA", 103834221Sbostic 06, "PE write error", 103934221Sbostic 07, "GCR write error", 104034221Sbostic 010, "RSTAT contains bad code", 104134221Sbostic 011, "PE write error", 104234221Sbostic 012, "MASSBUS parity error", 104334221Sbostic 013, "invalid data transferred", 104434221Sbostic -1, unclass 104534221Sbostic }; 104617214Smckusick 104734221Sbostic /* MTER_TMFLTA */ 104834221Sbostic static struct fmesg tmfltamsg[] = { 104934221Sbostic 01, "illegal command code", 105034221Sbostic 02, "DT command issued when NDT command active", 105134221Sbostic 03, "WMC error", 105234221Sbostic 04, "RUN not received from MASSBUS controller", 105334221Sbostic 05, "mismatch in command read - function routine", 105434221Sbostic 06, "ECC ROM parity error", 105534221Sbostic 07, "XMC ROM parity error", 105634221Sbostic 010, "mismatch in command read - ID burst command", 105734221Sbostic 011, "mismatch in command read - verify ARA burst command", 105834221Sbostic 012, "mismatch in command read - verify ARA ID command", 105934221Sbostic 013, "mismatch in command read - verify gap command", 106034221Sbostic 014, "mismatch in command read - read id burst command", 106134221Sbostic 015, "mismatch in command read - verify ARA ID command", 106234221Sbostic 016, "mismatch in command read - verify gap command", 106334221Sbostic 017, "mismatch in command read - find gap command", 106434221Sbostic 020, "WMC LEFT failed to set", 106534221Sbostic 021, "XL PE set in INTSTA register", 106634221Sbostic 022, "XMC DONE did not set", 106734221Sbostic 023, "WMC ROM PE or RD PE set in WMCERR register", 106834221Sbostic -1, unclass 106934221Sbostic }; 107017214Smckusick 107134221Sbostic /* MTER_TUFLTA */ 107234221Sbostic static struct fmesg tufltamsg[] = { 107334221Sbostic 01, "TU status parity error", 107434221Sbostic 02, "TU command parity error", 107534221Sbostic 03, "rewinding tape went offline", 107634221Sbostic 04, "tape went not ready during DSE", 107734221Sbostic 05, "TU CMD status changed during DSE", 107834221Sbostic 06, "TU never came up to speed", 107934221Sbostic 07, "TU velocity changed", 108034221Sbostic 010, "TU CMD did not load correctly to start tape motion", 108134221Sbostic 011, "TU CMD did not load correctly to set drive density", 108234221Sbostic 012, "TU CMD did not load correctly to start tape motion to write BOT ID", 108334221Sbostic 013, "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID", 108434221Sbostic 014, "failed to write density ID burst", 108534221Sbostic 015, "failed to write ARA burst", 108634221Sbostic 016, "failed to write ARA ID", 108734221Sbostic 017, "ARA error bit set in MTA status B register", 108834221Sbostic 021, "could not find a gap after ID code was written correctly", 108934221Sbostic 022, "TU CMD did not load correctly to start tape motion to read ID burst", 109034221Sbostic 023, "timeout looking for BOT after detecting ARA ID burst", 109134221Sbostic 024, "failed to write tape mark", 109234221Sbostic 025, "tape never came up to speed while trying to reposition for retry of writing tape mark", 109334221Sbostic 026, "TU CMD did not load correctly to start tape motion in erase gap routine", 109434221Sbostic 027, "could not detect a gap in in erase gap routine", 109534221Sbostic 030, "could not detect a gap after writing record", 109634221Sbostic 031, "read path terminated before entire record was written", 109734221Sbostic 032, "could not find a gap after writing record and read path terminated early", 109834221Sbostic 033, "TU CMD did not load correctly to backup for retry of write tape mark", 109934221Sbostic 034, "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark", 110034221Sbostic 035, "TU CMD did not load correctly to backup to retry a load of BOT ID", 110134221Sbostic 036, "timeout looking for BOT after failing to write BOT ID", 110234221Sbostic 037, "TU velocity changed while writing PE gap before starting to write record", 110334221Sbostic 040, "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst", 110434221Sbostic 041, "TU CMD did not load correctly to set GCR tape density after writing Density ID", 110534221Sbostic 042, "TU CMD did not load correctly to set PE tape density at start of read from BOT", 110634221Sbostic 043, "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst", 110734221Sbostic }; 110817214Smckusick 110934221Sbostic /* MTER_TMFLTB */ 111034221Sbostic static char inlinetest[] = "inline test failed"; 111134221Sbostic static struct fmesg tmfltbmsg[] = { 111234221Sbostic 00, "RST0 interrupt occurred with TM RDY set", 111334221Sbostic 01, "power failed to interrupt", 111434221Sbostic 02, "unknown interrupt on channel 5.5", 111534221Sbostic 03, "unknown interrupt on channel 6.5", 111634221Sbostic 04, "unknown interrupt on channel 7", 111734221Sbostic 05, "unknown interrupt on channel 7.5", 111834221Sbostic 06, "CAS contention retry count expired", 111934221Sbostic 07, "CAS contention error not retryable", 112034221Sbostic 010, "queue error, could not find queue entry", 112134221Sbostic 011, "queue entry already full", 112234221Sbostic 012, "8085 ROM parity error", 112334221Sbostic 013, inlinetest, 112434221Sbostic 013, inlinetest, 112534221Sbostic 014, inlinetest, 112634221Sbostic 015, inlinetest, 112734221Sbostic 016, inlinetest, 112834221Sbostic 017, inlinetest, 112934221Sbostic 020, inlinetest, 113034221Sbostic 021, inlinetest, 113134221Sbostic 022, inlinetest, 113234221Sbostic 023, inlinetest, 113334221Sbostic 024, inlinetest, 113434221Sbostic 025, inlinetest, 113534221Sbostic 026, inlinetest, 113634221Sbostic 027, inlinetest, 113734221Sbostic 030, inlinetest, 113834221Sbostic 031, inlinetest, 113934221Sbostic 032, inlinetest, 114034221Sbostic 033, inlinetest, 114134221Sbostic 034, inlinetest, 114234221Sbostic 035, inlinetest, 114334221Sbostic 036, inlinetest, 114434221Sbostic 037, inlinetest, 114534221Sbostic 040, inlinetest, 114634221Sbostic 041, inlinetest, 114734221Sbostic 042, inlinetest, 114834221Sbostic 043, inlinetest, 114934221Sbostic 044, inlinetest, 115036548Sbostic 045, inlinetest, 115134221Sbostic 046, inlinetest, 115234221Sbostic 047, inlinetest, 115334221Sbostic 050, inlinetest, 115434221Sbostic 051, inlinetest, 115534221Sbostic 052, inlinetest, 115634221Sbostic 053, inlinetest, 115734221Sbostic 054, inlinetest, 115834221Sbostic 055, inlinetest, 115934221Sbostic 056, inlinetest, 116034221Sbostic 057, inlinetest, 116134221Sbostic -1, unclass 116234221Sbostic }; 116317214Smckusick 116434221Sbostic /* MTER_MBFLT */ 116534221Sbostic static struct fmesg mbfltmsg[] = { 116634221Sbostic 01, "control bus parity error", 116734221Sbostic 02, "illegal register referenced", 116834221Sbostic -1, unclass 116934221Sbostic }; 117017214Smckusick 117134221Sbostic /* 117234221Sbostic * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL, 117334221Sbostic * and default: no failure message. 117434221Sbostic */ 117534221Sbostic static struct fmesg nullmsg[] = { 117634221Sbostic -1, "" 117734221Sbostic }; 117817214Smckusick 117934221Sbostic /* 118034221Sbostic * Interrupt code table. 118134221Sbostic */ 118234221Sbostic static struct errmsg { 118334221Sbostic int e_code; 118434221Sbostic char *e_mesg; 118534221Sbostic struct fmesg *e_fmesg; 118634221Sbostic } errmsg[] = { 118734221Sbostic MTER_BOT, "unexpected BOT", botmsg, 118834221Sbostic MTER_LEOT, "unexpected LEOT", nullmsg, 118934221Sbostic MTER_RWDING, "tape rewinding", nullmsg, 119034221Sbostic MTER_NOTRDY, "drive not ready", notrdymsg, 119134221Sbostic MTER_NOTAVL, "drive not available", nullmsg, 119234221Sbostic MTER_NONEX, "unit does not exist", nullmsg, 119334221Sbostic MTER_NOTCAP, "not capable", notcapmsg, 119434221Sbostic MTER_LONGREC, "long record", longrecmsg, 119534221Sbostic MTER_UNREAD, "unreadable record", code22msg, 119634221Sbostic MTER_ERROR, "error", code22msg, 119734221Sbostic MTER_EOTERR, "EOT error", code22msg, 119834221Sbostic MTER_BADTAPE, "tape position lost", code22msg, 119934221Sbostic MTER_TMFLTA, "TM fault A", tmfltamsg, 120034221Sbostic MTER_TUFLTA, "TU fault A", tufltamsg, 120134221Sbostic MTER_TMFLTB, "TM fault B", tmfltbmsg, 120234221Sbostic MTER_MBFLT, "MB fault", mbfltmsg, 120334221Sbostic MTER_KEYFAIL, "keypad entry error", nullmsg, 120434221Sbostic -1, "unclassified error", nullmsg 120534221Sbostic }; 120617214Smckusick 120734221Sbostic /* 120834221Sbostic * Decode an interrupt-time failure. 120934221Sbostic */ 121034221Sbostic mtintfail(erreg) 121134221Sbostic int erreg; 121234221Sbostic { 121334221Sbostic register struct errmsg *e; 121434221Sbostic register struct fmesg *f; 121534221Sbostic register int ecode, fcode; 121617214Smckusick 121734221Sbostic ecode = erreg & MTER_INTCODE; 121834221Sbostic fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT; 121934221Sbostic for (e = errmsg; e->e_code >= 0; e++) 122034221Sbostic if (e->e_code == ecode) 122117214Smckusick break; 122234221Sbostic for (f = e->e_fmesg; f->f_code >= 0; f++) 122334221Sbostic if (f->f_code == fcode) 122417214Smckusick break; 122534221Sbostic printf(" interrupt code = 0%o <%s>\n", ecode, e->e_mesg); 122634221Sbostic printf(" failure code = 0%o <%s>\n", fcode, f->f_mesg); 122717214Smckusick } 122834221Sbostic #endif /* MTLERRM */ 122934221Sbostic #endif /* NMT > 0 */ 1230