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*40733Skarels * @(#)mt.c 7.6 (Berkeley) 04/03/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 2617119Sbloom #include "param.h" 2717119Sbloom #include "systm.h" 2817119Sbloom #include "buf.h" 2917119Sbloom #include "conf.h" 3017119Sbloom #include "file.h" 3117119Sbloom #include "user.h" 3217119Sbloom #include "map.h" 3317119Sbloom #include "ioctl.h" 3417119Sbloom #include "mtio.h" 3517119Sbloom #include "cmap.h" 3618324Sralph #include "tty.h" 3734221Sbostic #include "syslog.h" 384736Swnj 3934221Sbostic #include "../vax/pte.h" 408471Sroot #include "../vax/cpu.h" 4117119Sbloom #include "mbareg.h" 4217119Sbloom #include "mbavar.h" 4317119Sbloom #include "mtreg.h" 444736Swnj 4517214Smckusick #define MTTIMEOUT 10000 /* loop limit for controller test */ 4617214Smckusick #define INF 1000000L /* a block number that won't exist */ 4717214Smckusick #define MASKREG(r) ((r) & 0xffff) /* the control registers have 16 bits */ 484736Swnj 4917214Smckusick /* Bits for sc_flags */ 504736Swnj 5117214Smckusick #define H_WRITTEN 01 /* last operation was a write */ 5217214Smckusick #define H_EOT 02 /* end of tape encountered */ 5317214Smckusick #define H_IEOT 04 /* ignore EOT condition */ 544736Swnj 5534221Sbostic int mt_do_readrev = 1; 5617214Smckusick 5717214Smckusick /* Per unit status information */ 5817214Smckusick 594736Swnj struct mu_softc { 6034221Sbostic char sc_openf; /* unit is open if != 0 */ 6134221Sbostic char sc_flags; /* state flags */ 6234221Sbostic daddr_t sc_blkno; /* current physical block number */ 6334221Sbostic daddr_t sc_nxrec; /* firewall input block number */ 6434221Sbostic u_short sc_erreg; /* copy of mter or mtner */ 6534221Sbostic u_short sc_dsreg; /* copy of mtds */ 6634221Sbostic short sc_resid; /* residual function count for ioctl */ 6734221Sbostic short sc_dens; /* density code - MT_GCR or zero */ 6834221Sbostic int sc_i_mtas; /* mtas at slave attach time */ 6934221Sbostic int sc_i_mtner; /* mtner at slave attach time */ 7034221Sbostic int sc_i_mtds; /* mtds at slave attach time */ 7134221Sbostic struct tty *sc_ttyp; /* record user's tty for errors */ 7234221Sbostic int sc_blks; /* number of I/O operations since open */ 7334221Sbostic int sc_softerrs; /* number of soft I/O errors since open */ 744736Swnj } mu_softc[NMU]; 754736Swnj 7617214Smckusick struct buf cmtbuf[NMT]; /* tape command buffer structures */ 774736Swnj 7834221Sbostic struct mba_device *mtinfo[NMT]; /* unit to ctlr structures */ 7934221Sbostic struct mba_slave *muinfo[NMU]; /* unit to slave structures */ 8034221Sbostic 8117214Smckusick char mtds_bits[] = MTDS_BITS; /* mtds bit names for error messages */ 8217214Smckusick short mttypes[] = { MBDT_TU78, 0 }; 834736Swnj 8417214Smckusick int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint(); 8517214Smckusick struct mba_driver mtdriver = 8617214Smckusick { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint, 8717214Smckusick mttypes, "mt", "mu", mtinfo }; 8817214Smckusick 8934221Sbostic /* Bits in minor device */ 9034221Sbostic #define MUUNIT(dev) (minor(dev)&03) 9134221Sbostic #define H_NOREWIND 04 9234221Sbostic #define H_6250BPI 010 9317214Smckusick 9434221Sbostic #define MTUNIT(dev) (muinfo[MUUNIT(dev)]->ms_ctlr) 9534221Sbostic 9634221Sbostic void mtcreset(); 9734221Sbostic 984736Swnj /*ARGSUSED*/ 994736Swnj mtattach(mi) 1004736Swnj struct mba_device *mi; 1014736Swnj { 10234221Sbostic 10334221Sbostic /* void */ 1044736Swnj } 1054736Swnj 1067431Skre mtslave(mi, ms, sn) 1074736Swnj struct mba_device *mi; 1084736Swnj struct mba_slave *ms; 1097431Skre int sn; 1104736Swnj { 1114736Swnj register struct mu_softc *sc = &mu_softc[ms->ms_unit]; 1124736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 11326377Skarels int s = spl5(), rtn = 0, i; 1144736Swnj 11534221Sbostic /* 11634221Sbostic * Just in case the controller is ill, reset it. Then issue 11734221Sbostic * a sense operation and wait about a second for it to respond. 11834221Sbostic */ 11917214Smckusick mtcreset(mtaddr); 1204736Swnj mtaddr->mtas = -1; 1217431Skre mtaddr->mtncs[sn] = MT_SENSE|MT_GO; 12234221Sbostic for (i = MTTIMEOUT; i > 0; i--) { 12317214Smckusick DELAY(50); 12417214Smckusick if (MASKREG(mtaddr->mtas) != 0) 12517214Smckusick break; 12617214Smckusick } 12717214Smckusick sc->sc_i_mtas = mtaddr->mtas; 12817214Smckusick sc->sc_i_mtner = mtaddr->mtner; 12917214Smckusick sc->sc_i_mtds = mtaddr->mtds; 13017214Smckusick 13134221Sbostic /* 13234221Sbostic * If no response, whimper. If wrong response, call it an 13334221Sbostic * unsolicited interrupt and use mtndtint to log and correct. 13434221Sbostic * Otherwise, note whether this slave exists. 13534221Sbostic */ 13634221Sbostic if (i <= 0) 13717214Smckusick printf("mt: controller hung\n"); 13834221Sbostic else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE) 13917214Smckusick (void) mtndtint(mi); 14034654Skarels else if (mtaddr->mtds & MTDS_PRES) { 14134654Skarels muinfo[ms->ms_unit] = ms; 1424736Swnj rtn = 1; 14334654Skarels } 14417214Smckusick 14534221Sbostic /* cancel the interrupt, then wait a little while for it to go away */ 1464736Swnj mtaddr->mtas = mtaddr->mtas; 14717214Smckusick DELAY(10); 1484736Swnj splx(s); 1494736Swnj return (rtn); 1504736Swnj } 1514736Swnj 1524736Swnj mtopen(dev, flag) 1534736Swnj dev_t dev; 1544736Swnj int flag; 1554736Swnj { 1564736Swnj register int muunit; 1574736Swnj register struct mu_softc *sc; 15834221Sbostic register struct mba_slave *ms; 1594736Swnj 1604736Swnj muunit = MUUNIT(dev); 16134221Sbostic if (muunit >= NMU || (ms = muinfo[muunit]) == NULL || 16234221Sbostic ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0) 1638581Sroot return (ENXIO); 16417214Smckusick if ((sc = &mu_softc[muunit])->sc_openf) 16517214Smckusick return (EBUSY); 16634221Sbostic sc->sc_openf = 1; 16717214Smckusick sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0; 1684736Swnj mtcommand(dev, MT_SENSE, 1); 1694736Swnj if ((sc->sc_dsreg & MTDS_ONL) == 0) { 1704736Swnj uprintf("mu%d: not online\n", muunit); 17134221Sbostic sc->sc_openf = 0; 1728581Sroot return (EIO); 1734736Swnj } 17417214Smckusick if ((sc->sc_dsreg & MTDS_AVAIL) == 0) { 17517214Smckusick uprintf("mu%d: not online (port selector)\n", muunit); 17634221Sbostic sc->sc_openf = 0; 17717214Smckusick return (EIO); 17817214Smckusick } 17917214Smckusick if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) { 1804736Swnj uprintf("mu%d: no write ring\n", muunit); 18134221Sbostic sc->sc_openf = 0; 1828581Sroot return (EIO); 1834736Swnj } 18434221Sbostic if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) && 18534221Sbostic (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) { 1864736Swnj uprintf("mu%d: can't change density in mid-tape\n", muunit); 18734221Sbostic sc->sc_openf = 0; 1888581Sroot return (EIO); 1894736Swnj } 1904736Swnj sc->sc_blkno = (daddr_t)0; 19117214Smckusick 19234221Sbostic /* 19334221Sbostic * Since cooked I/O may do a read-ahead before a write, trash 19434221Sbostic * on a tape can make the first write fail. Suppress the first 19534221Sbostic * read-ahead unless definitely doing read-write. 19634221Sbostic */ 19734221Sbostic sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ? 19834221Sbostic (daddr_t)0 : (daddr_t)INF; 1994736Swnj sc->sc_flags = 0; 20034221Sbostic sc->sc_blks = 0; 20134221Sbostic sc->sc_softerrs = 0; 20218324Sralph sc->sc_ttyp = u.u_ttyp; 2038581Sroot return (0); 2044736Swnj } 2054736Swnj 2064736Swnj mtclose(dev, flag) 2074736Swnj register dev_t dev; 20817214Smckusick register int flag; 2094736Swnj { 2104736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 2114736Swnj 21234221Sbostic if ((flag & (FREAD | FWRITE)) == FWRITE || 21334221Sbostic ((flag & FWRITE) && (sc->sc_flags & H_WRITTEN))) 2144736Swnj mtcommand(dev, MT_CLS|sc->sc_dens, 1); 21517214Smckusick if ((minor(dev) & H_NOREWIND) == 0) 2164736Swnj mtcommand(dev, MT_REW, 0); 21734221Sbostic if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 21834221Sbostic log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n", 21934221Sbostic MUUNIT(dev), sc->sc_softerrs, sc->sc_blks); 2204736Swnj sc->sc_openf = 0; 221*40733Skarels return (0); 2224736Swnj } 2234736Swnj 2244736Swnj mtcommand(dev, com, count) 2254736Swnj dev_t dev; 2264736Swnj int com, count; 2274736Swnj { 2284736Swnj register struct buf *bp; 22934221Sbostic int s; 2304736Swnj 2314736Swnj bp = &cmtbuf[MTUNIT(dev)]; 2325437Sroot s = spl5(); 23317214Smckusick while (bp->b_flags & B_BUSY) { 23434221Sbostic if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE)) 2354736Swnj break; 2364736Swnj bp->b_flags |= B_WANTED; 2374736Swnj sleep((caddr_t)bp, PRIBIO); 2384736Swnj } 2394736Swnj bp->b_flags = B_BUSY|B_READ; 2405437Sroot splx(s); 2414736Swnj bp->b_dev = dev; 2424736Swnj bp->b_command = com; 2434736Swnj bp->b_repcnt = count; 2444736Swnj bp->b_blkno = 0; 24517214Smckusick bp->b_error = 0; 2464736Swnj mtstrategy(bp); 2474736Swnj if (count == 0) 2484736Swnj return; 24934221Sbostic biowait(bp); 25017214Smckusick if (bp->b_flags & B_WANTED) 2514736Swnj wakeup((caddr_t)bp); 2524736Swnj bp->b_flags &= B_ERROR; 2534736Swnj } 2544736Swnj 2554736Swnj mtstrategy(bp) 2564736Swnj register struct buf *bp; 2574736Swnj { 2584736Swnj register struct buf *dp; 25934221Sbostic struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)]; 26034221Sbostic int s; 2614736Swnj 26234221Sbostic /* 26334221Sbostic * If this is a data transfer operation, set the resid to a 26434221Sbostic * default value (EOF) to simplify getting it right during 26534221Sbostic * error recovery or bail out. 26634221Sbostic */ 26717214Smckusick if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 26817214Smckusick bp->b_resid = bp->b_bcount; 26917214Smckusick 27034221Sbostic /* 27134221Sbostic * Link this request onto the end of the queue for this 27234221Sbostic * controller, then start I/O if not already active. 27334221Sbostic */ 2744736Swnj bp->av_forw = NULL; 2754736Swnj dp = &mi->mi_tab; 2765437Sroot s = spl5(); 2774736Swnj if (dp->b_actf == NULL) 2784736Swnj dp->b_actf = bp; 2794736Swnj else 2804736Swnj dp->b_actl->av_forw = bp; 2814736Swnj dp->b_actl = bp; 2824736Swnj if (dp->b_active == 0) 2834736Swnj mbustart(mi); 2845437Sroot splx(s); 2854736Swnj } 2864736Swnj 2874736Swnj mtustart(mi) 2884736Swnj register struct mba_device *mi; 2894736Swnj { 29017214Smckusick register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 2914736Swnj register struct buf *bp = mi->mi_tab.b_actf; 2924736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 2934736Swnj daddr_t blkno; 29426377Skarels int count; 2954736Swnj 2964736Swnj if (sc->sc_openf < 0) { 2974736Swnj bp->b_flags |= B_ERROR; 2984736Swnj return (MBU_NEXT); 2994736Swnj } 3004736Swnj if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) { 30134221Sbostic /* 30234221Sbostic * Data transfer. If write at end of tape, 30334221Sbostic * signal "no space" unless suppressed 30434221Sbostic * by MTIOCIEOT. 30534221Sbostic */ 30634221Sbostic if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT && 30734221Sbostic (bp->b_flags & B_READ) == 0) { 3084736Swnj bp->b_flags |= B_ERROR; 30917214Smckusick bp->b_error = ENOSPC; 3104736Swnj return (MBU_NEXT); 3114736Swnj } 31217214Smckusick 31334221Sbostic if (bp->b_flags & B_RAW) { 31434221Sbostic /* raw transfer; never seek */ 31534221Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno); 31634221Sbostic sc->sc_nxrec = sc->sc_blkno + 1; 31734221Sbostic } else { 31817214Smckusick /* seek beyond end of file */ 31917214Smckusick if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 32017214Smckusick bp->b_flags |= B_ERROR; 32117214Smckusick bp->b_error = ENXIO; 32217214Smckusick return (MBU_NEXT); 32317214Smckusick } 32417214Smckusick 32534221Sbostic /* 32634221Sbostic * This should be end of file, but the buffer 32734221Sbostic * system wants a one-block look-ahead. Humor it. 32834221Sbostic */ 32934221Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 33034221Sbostic bp->b_flags & B_READ) { 33134221Sbostic bp->b_resid = bp->b_bcount; 33217214Smckusick clrbuf(bp); 33317214Smckusick return (MBU_NEXT); 33417214Smckusick } 33517214Smckusick 33617214Smckusick /* If writing, mark the next block invalid. */ 33717214Smckusick if ((bp->b_flags & B_READ) == 0) 33817214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 3394736Swnj } 3404736Swnj } else { 34117214Smckusick /* It's a command, do it now. */ 3424736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3434736Swnj (bp->b_repcnt<<8)|bp->b_command|MT_GO; 3444736Swnj return (MBU_STARTED); 3454736Swnj } 34617214Smckusick 34734221Sbostic /* 34834221Sbostic * If raw I/O, or if the tape is positioned correctly for 34934221Sbostic * cooked I/O, set the byte count, unit number and repeat count 35034221Sbostic * then tell the MASSBUS to proceed. Note that a negative 35134221Sbostic * bcount tells mbstart to map the buffer for "read backwards". 35234221Sbostic */ 35334221Sbostic if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3544736Swnj if (mi->mi_tab.b_errcnt == 2) { 35534221Sbostic mtaddr->mtbc = -bp->b_bcount; 3564736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 3574736Swnj } else { 3584736Swnj mtaddr->mtbc = bp->b_bcount; 3594736Swnj mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev); 3604736Swnj } 3614736Swnj return (MBU_DODATA); 3624736Swnj } 36317214Smckusick 36417214Smckusick /* Issue skip operations to position the next block for cooked I/O. */ 36517214Smckusick 3667380Ssam if (blkno < bdbtofsb(bp->b_blkno)) 36734221Sbostic count = bdbtofsb(bp->b_blkno) - blkno; 3684736Swnj else 36934221Sbostic count = blkno - bdbtofsb(bp->b_blkno); 37034221Sbostic if ((unsigned)count > 0377) 37126377Skarels count = 0377; 37226377Skarels mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO; 3734736Swnj return (MBU_STARTED); 3744736Swnj } 3754736Swnj 3764736Swnj mtstart(mi) 3774736Swnj register struct mba_device *mi; 3784736Swnj { 3794736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3804736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 3814736Swnj 3824736Swnj if (bp->b_flags & B_READ) 3834736Swnj if (mi->mi_tab.b_errcnt == 2) 38434221Sbostic return (MT_READREV|MT_GO); 3854736Swnj else 38634221Sbostic return (MT_READ|MT_GO); 3874736Swnj else 38834221Sbostic return (MT_WRITE|sc->sc_dens|MT_GO); 3894736Swnj } 3904736Swnj 3914736Swnj mtdtint(mi, mbsr) 3924736Swnj register struct mba_device *mi; 3934736Swnj int mbsr; 3944736Swnj { 3954736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 3964736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3974736Swnj register struct mu_softc *sc; 39817214Smckusick register int er; 3994736Swnj 40017214Smckusick /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */ 40117214Smckusick if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) { 4024736Swnj printf("mt: wrong unit!\n"); 4034736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 4044736Swnj } 40517214Smckusick 40617214Smckusick er = MASKREG(mtaddr->mter); 4074736Swnj sc = &mu_softc[MUUNIT(bp->b_dev)]; 40817214Smckusick sc->sc_erreg = er; 40917214Smckusick if (bp->b_flags & B_READ) 41017214Smckusick sc->sc_flags &= ~H_WRITTEN; 41117214Smckusick else 4124736Swnj sc->sc_flags |= H_WRITTEN; 41317214Smckusick switch (er & MTER_INTCODE) { 41417214Smckusick 41517214Smckusick case MTER_EOT: 41617214Smckusick sc->sc_flags |= H_EOT; 41717214Smckusick /* fall into MTER_DONE */ 41817214Smckusick 4194736Swnj case MTER_DONE: 42017214Smckusick sc->sc_blkno++; 42117214Smckusick if (mi->mi_tab.b_errcnt == 2) { 42217214Smckusick bp->b_bcount = bp->b_resid; 42317214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 42434221Sbostic if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0) 42517214Smckusick bp->b_flags |= B_ERROR; 42634221Sbostic } else 42717214Smckusick bp->b_resid = 0; 42817214Smckusick break; 42917214Smckusick 43017214Smckusick case MTER_SHRTREC: 43117214Smckusick sc->sc_blkno++; 43217214Smckusick bp->b_bcount = bp->b_resid; 43317214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 43434221Sbostic if ((bp->b_flags & B_RAW) == 0) 43517214Smckusick bp->b_flags |= B_ERROR; 43617214Smckusick break; 43717214Smckusick 43817214Smckusick case MTER_RETRY: 43934221Sbostic /* 44034221Sbostic * Simple re-try. Since resid is always a copy of the 44134221Sbostic * original byte count, use it to restore the count. 44234221Sbostic */ 44317214Smckusick mi->mi_tab.b_errcnt = 1; 44417214Smckusick bp->b_bcount = bp->b_resid; 44534221Sbostic return (MBD_RETRY); 44617214Smckusick 44717214Smckusick case MTER_RDOPP: 44834221Sbostic /* 44934221Sbostic * The controller just decided to read it backwards. 45034221Sbostic * If the controller returns a byte count of zero, 45134221Sbostic * change it to 1, since zero encodes 65536, which 45234221Sbostic * isn't quite what we had in mind. The byte count 45334221Sbostic * may be larger than the size of the input buffer, so 45434221Sbostic * limit the count to the buffer size. After 45534221Sbostic * making the byte count reasonable, set bcount to the 45634221Sbostic * negative of the controller's version of the byte 45734221Sbostic * count so that the start address for the transfer is 45834221Sbostic * set up correctly. 45934221Sbostic */ 46017214Smckusick if (mt_do_readrev) { 46117214Smckusick mi->mi_tab.b_errcnt = 2; 46217214Smckusick if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0) 46317214Smckusick bp->b_bcount = 1; 46417214Smckusick if (bp->b_bcount > bp->b_resid) 46517214Smckusick bp->b_bcount = bp->b_resid; 46617214Smckusick bp->b_bcount = -(bp->b_bcount); 46717214Smckusick return(MBD_RETRY); 46817214Smckusick } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) { 46917214Smckusick sc->sc_blkno++; 47017214Smckusick bp->b_bcount = bp->b_resid; 47117214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 47217214Smckusick bp->b_flags |= B_ERROR; 47317214Smckusick break; 47417214Smckusick } 47517214Smckusick bp->b_flags |= B_ERROR; 47617214Smckusick /* fall into MTER_LONGREC */ 47717214Smckusick 4784736Swnj case MTER_LONGREC: 47917214Smckusick sc->sc_blkno++; 48017214Smckusick bp->b_bcount = bp->b_resid; 4814736Swnj bp->b_resid = 0; 48217214Smckusick bp->b_error = ENOMEM; 48317214Smckusick bp->b_flags |= B_ERROR; 4844736Swnj break; 4854736Swnj 4864736Swnj case MTER_NOTCAP: 4874736Swnj printf("mu%d: blank tape\n", MUUNIT(bp->b_dev)); 4884736Swnj goto err; 4894736Swnj 4904736Swnj case MTER_TM: 49134221Sbostic /* 49234221Sbostic * End of file. Since the default byte count has 49334221Sbostic * already been set, just count the block and proceed. 49434221Sbostic */ 4954736Swnj sc->sc_blkno++; 4964736Swnj err: 49734221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno); 4984736Swnj break; 4994736Swnj 5004736Swnj case MTER_OFFLINE: 5014736Swnj if (sc->sc_openf > 0) { 5024736Swnj sc->sc_openf = -1; 50334221Sbostic tprintf(sc->sc_ttyp, "mu%d: offline\n", 50434221Sbostic MUUNIT(bp->b_dev)); 5054736Swnj } 5064736Swnj bp->b_flags |= B_ERROR; 5074736Swnj break; 5084736Swnj 50917214Smckusick case MTER_NOTAVL: 51017214Smckusick if (sc->sc_openf > 0) { 51117214Smckusick sc->sc_openf = -1; 51218324Sralph tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", 51318324Sralph MUUNIT(bp->b_dev)); 51417214Smckusick } 51517214Smckusick bp->b_flags |= B_ERROR; 51617214Smckusick break; 51717214Smckusick 5184736Swnj case MTER_FPT: 51934221Sbostic tprintf(sc->sc_ttyp, "mu%d: no write ring\n", 52034221Sbostic MUUNIT(bp->b_dev)); 5214736Swnj bp->b_flags |= B_ERROR; 5224736Swnj break; 5234736Swnj 52417214Smckusick case MTER_UNREAD: 52517214Smckusick sc->sc_blkno++; 52617214Smckusick bp->b_bcount = bp->b_resid; 52717214Smckusick bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount); 52817214Smckusick 52934221Sbostic /* code 010 means a garbage record, nothing serious. */ 53034221Sbostic if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) { 53134221Sbostic tprintf(sc->sc_ttyp, 53234221Sbostic "mu%d: rn=%d bn=%d unreadable record\n", 53317214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno); 53417214Smckusick bp->b_flags |= B_ERROR; 53517214Smckusick break; 53617214Smckusick } 53717214Smckusick 53834221Sbostic /* 53934221Sbostic * Anything else might be a hardware problem, 54034221Sbostic * fall into the error report. 54134221Sbostic */ 54217214Smckusick 5434736Swnj default: 54434221Sbostic /* 54534221Sbostic * The bits in sc->sc_dsreg are from the last sense 54634221Sbostic * command. To get the most recent copy, you have to 54734221Sbostic * do a sense at interrupt level, which requires nested 54834221Sbostic * error processing. This is a bit messy, so leave 54934221Sbostic * well enough alone. 55034221Sbostic */ 55134221Sbostic tprintf(sc->sc_ttyp, "\ 55234221Sbostic mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n", 55317214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 55417214Smckusick mbsr, mbsr_bits, er, 55517214Smckusick MASKREG(sc->sc_dsreg), mtds_bits); 55617214Smckusick #ifdef MTLERRM 55734221Sbostic mtintfail(er); 55817214Smckusick #endif 5594736Swnj bp->b_flags |= B_ERROR; 56017214Smckusick 56134221Sbostic /* 56234221Sbostic * The TM78 manual says to reset the controller after 56334221Sbostic * TM fault B or MASSBUS fault. 56434221Sbostic */ 56534221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 56634221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) 56717214Smckusick mtcreset(mtaddr); 5684736Swnj } 56917214Smckusick 57034221Sbostic /* 57134221Sbostic * Just in case some strange error slipped through (drive off 57234221Sbostic * line during read-reverse error recovery comes to mind), make 57334221Sbostic * sure the byte count is reasonable. 57434221Sbostic */ 57517214Smckusick if (bp->b_bcount < 0) 57617214Smckusick bp->b_bcount = bp->b_resid; 57734221Sbostic 57834221Sbostic if ((bp->b_flags & B_ERROR) == 0) { 57934221Sbostic /* this counts reverse reads as soft errors */ 58034221Sbostic sc->sc_blks++; 58134221Sbostic if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */ 58234221Sbostic sc->sc_softerrs++; 58334221Sbostic } 5844736Swnj return (MBD_DONE); 5854736Swnj } 5864736Swnj 5874736Swnj mtndtint(mi) 5884736Swnj register struct mba_device *mi; 5894736Swnj { 5904736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 5914736Swnj register struct buf *bp = mi->mi_tab.b_actf; 5924736Swnj register struct mu_softc *sc; 59317214Smckusick register int er, fc; 59417214Smckusick int unit; 5954736Swnj 5964736Swnj unit = (mtaddr->mtner >> 8) & 3; 5974736Swnj er = MASKREG(mtaddr->mtner); 59817214Smckusick sc = &mu_softc[unit]; 59917214Smckusick sc->sc_erreg = er; 60017214Smckusick 60117214Smckusick /* Check for unsolicited interrupts. */ 60234221Sbostic if (bp == NULL || unit != MUUNIT(bp->b_dev)) { 60334221Sbostic if ((er & MTER_INTCODE) == MTER_ONLINE) 60434221Sbostic return (MBN_SKIP); 60517214Smckusick 60634221Sbostic printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n", 60734221Sbostic unit, er, MASKREG(sc->sc_dsreg), mtds_bits); 60817214Smckusick #ifdef MTLERRM 60934221Sbostic mtintfail(er); 61017214Smckusick #endif 61134221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 61234221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) { 61334221Sbostic /* 61434221Sbostic * Reset the controller, then set error status 61534221Sbostic * if there was anything active when the fault 61634221Sbostic * occurred. This may shoot an innocent 61734221Sbostic * bystander, but it's better than letting 61834221Sbostic * an error slip through. 61934221Sbostic */ 62034221Sbostic mtcreset(mtaddr); 62134221Sbostic if (bp != NULL) { 62234221Sbostic bp->b_flags |= B_ERROR; 62334221Sbostic return (MBN_DONE); 62417214Smckusick } 62517214Smckusick } 6264736Swnj return (MBN_SKIP); 6274736Swnj } 62817214Smckusick 6294736Swnj fc = (mtaddr->mtncs[unit] >> 8) & 0xff; 6304736Swnj sc->sc_resid = fc; 63117214Smckusick 63234221Sbostic /* 63334221Sbostic * Clear the "written" flag after any operation that changes 63434221Sbostic * the position of the tape. 63534221Sbostic */ 63634221Sbostic if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE) 63717214Smckusick sc->sc_flags &= ~H_WRITTEN; 63817214Smckusick 6394736Swnj switch (er & MTER_INTCODE) { 64017214Smckusick 64117214Smckusick case MTER_EOT: 64217214Smckusick sc->sc_flags |= H_EOT; 64317214Smckusick /* fall into MTER_DONE */ 64417214Smckusick 6454736Swnj case MTER_DONE: 64617214Smckusick /* If this is a command buffer, just update the status. */ 6474736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 6484736Swnj done: 6494736Swnj if (bp->b_command == MT_SENSE) 6504736Swnj sc->sc_dsreg = MASKREG(mtaddr->mtds); 6514736Swnj return (MBN_DONE); 6524736Swnj } 65317214Smckusick 65434221Sbostic /* 65534221Sbostic * It's not a command buffer, must be a cooked I/O 65634221Sbostic * skip operation (perhaps a shaky assumption, but it 65734221Sbostic * wasn't my idea). 65834221Sbostic */ 6597380Ssam if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0) 6606186Ssam sc->sc_blkno -= MIN(0377, -fc); 6614736Swnj else 6626186Ssam sc->sc_blkno += MIN(0377, fc); 6634736Swnj return (MBN_RETRY); 6644736Swnj 66517214Smckusick case MTER_ONLINE: /* ddj -- shouldn't happen but did */ 6664736Swnj case MTER_RWDING: 6674736Swnj return (MBN_SKIP); /* ignore "rewind started" interrupt */ 6684736Swnj 6694736Swnj case MTER_NOTCAP: 67018324Sralph tprintf(sc->sc_ttyp, "mu%d: blank tape\n", MUUNIT(bp->b_dev)); 67117214Smckusick bp->b_flags |= B_ERROR; 67217214Smckusick return (MBN_DONE); 6734736Swnj 6744736Swnj case MTER_TM: 6754736Swnj case MTER_LEOT: 67634221Sbostic /* 67734221Sbostic * For an ioctl skip operation, count a tape mark as 67834221Sbostic * a record. If there's anything left to do, update 67934221Sbostic * the repeat count and re-start the command. 68034221Sbostic */ 68117214Smckusick if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 68217214Smckusick if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0) 68317214Smckusick return (MBN_DONE); 68417214Smckusick else 68517214Smckusick return (MBN_RETRY); 6864736Swnj } else { 68734221Sbostic /* 68834221Sbostic * Cooked I/O again. Just update the books and 68934221Sbostic * wait for someone else to return end of file or 69034221Sbostic * complain about a bad seek. 69134221Sbostic */ 69234221Sbostic if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 69334221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1; 69434221Sbostic sc->sc_blkno = sc->sc_nxrec; 69534221Sbostic } else { 69634221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc; 69734221Sbostic sc->sc_blkno = sc->sc_nxrec + 1; 69834221Sbostic } 6994736Swnj } 7004736Swnj return (MBN_RETRY); 7014736Swnj 7024736Swnj case MTER_FPT: 70334221Sbostic tprintf(sc->sc_ttyp, "mu%d: no write ring\n", 70434221Sbostic MUUNIT(bp->b_dev)); 7054736Swnj bp->b_flags |= B_ERROR; 7064736Swnj return (MBN_DONE); 7074736Swnj 7084736Swnj case MTER_OFFLINE: 70917214Smckusick /* If `off line' was intentional, don't complain. */ 71034221Sbostic if (bp == &cmtbuf[MTUNIT(bp->b_dev)] && 71134221Sbostic bp->b_command == MT_UNLOAD) 71217214Smckusick return(MBN_DONE); 7134736Swnj if (sc->sc_openf > 0) { 7144736Swnj sc->sc_openf = -1; 71534221Sbostic tprintf(sc->sc_ttyp, "mu%d: offline\n", 71634221Sbostic MUUNIT(bp->b_dev)); 7174736Swnj } 7184736Swnj bp->b_flags |= B_ERROR; 7194736Swnj return (MBN_DONE); 7204736Swnj 72117214Smckusick case MTER_NOTAVL: 72217214Smckusick if (sc->sc_openf > 0) { 72317214Smckusick sc->sc_openf = -1; 72434221Sbostic tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", 72534221Sbostic MUUNIT(bp->b_dev)); 72617214Smckusick } 72717214Smckusick bp->b_flags |= B_ERROR; 72817214Smckusick return (MBN_DONE); 72917214Smckusick 7304736Swnj case MTER_BOT: 7314736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 7324736Swnj goto done; 73317214Smckusick /* fall through */ 73417214Smckusick 7354736Swnj default: 73634221Sbostic tprintf(sc->sc_ttyp, "\ 73734221Sbostic mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n", 73817214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 73917214Smckusick er, MASKREG(sc->sc_dsreg), mtds_bits); 74017214Smckusick #ifdef MTLERRM 74134221Sbostic mtintfail(er); 74217214Smckusick #endif 74334221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 74434221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) 74517214Smckusick mtcreset(mtaddr); /* reset the controller */ 7464736Swnj bp->b_flags |= B_ERROR; 7474736Swnj return (MBN_DONE); 7484736Swnj } 7494736Swnj /* NOTREACHED */ 7504736Swnj } 7514736Swnj 75234221Sbostic void 75334221Sbostic mtcreset(mtaddr) 75417214Smckusick register struct mtdevice *mtaddr; 75517214Smckusick { 75617214Smckusick register int i; 75717214Smckusick 75817214Smckusick mtaddr->mtid = MTID_CLR; /* reset the TM78 */ 75917214Smckusick DELAY(200); 76017214Smckusick for (i = MTTIMEOUT; i > 0; i--) { 76117214Smckusick DELAY(50); /* don't nag */ 76217214Smckusick if ((mtaddr->mtid & MTID_RDY) != 0) 76317214Smckusick return; /* exit when ready */ 76417214Smckusick } 76517214Smckusick printf("mt: controller hung\n"); 76617214Smckusick } 76717214Smckusick 7684736Swnj /*ARGSUSED*/ 7697637Ssam mtioctl(dev, cmd, data, flag) 7704736Swnj dev_t dev; 7714736Swnj int cmd; 7727637Ssam caddr_t data; 7734736Swnj int flag; 7744736Swnj { 7754736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 7764736Swnj register struct buf *bp = &cmtbuf[MTUNIT(dev)]; 77717214Smckusick register struct mtop *mtop; 77817214Smckusick register struct mtget *mtget; 77917214Smckusick int callcount, fcount; 78017214Smckusick int op; 78117214Smckusick 78217214Smckusick /* We depend on the values and order of the MT codes here. */ 78317214Smckusick 7844736Swnj static mtops[] = 7854736Swnj {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE}; 7864736Swnj 7874736Swnj switch (cmd) { 7887637Ssam 78917214Smckusick /* tape operation */ 79017214Smckusick 79117214Smckusick case MTIOCTOP: 7928606Sroot mtop = (struct mtop *)data; 7938606Sroot switch (mtop->mt_op) { 7947637Ssam 7954736Swnj case MTWEOF: 7967637Ssam callcount = mtop->mt_count; 7974736Swnj fcount = 1; 7984736Swnj break; 7997637Ssam 8004736Swnj case MTFSF: case MTBSF: 8017637Ssam callcount = mtop->mt_count; 8024736Swnj fcount = 1; 8034736Swnj break; 8047637Ssam 8054736Swnj case MTFSR: case MTBSR: 8064736Swnj callcount = 1; 8077637Ssam fcount = mtop->mt_count; 8084736Swnj break; 8097637Ssam 8104736Swnj case MTREW: case MTOFFL: 8114736Swnj callcount = 1; 8124736Swnj fcount = 1; 8134736Swnj break; 8147637Ssam 8154736Swnj default: 8168581Sroot return (ENXIO); 8174736Swnj } 81834221Sbostic if (callcount <= 0 || fcount <= 0) 8198581Sroot return (EINVAL); 8207637Ssam op = mtops[mtop->mt_op]; 8214736Swnj if (op == MT_WTM) 8224736Swnj op |= sc->sc_dens; 8234736Swnj while (--callcount >= 0) { 82417214Smckusick register int n, fc = fcount; 8254736Swnj 8264736Swnj do { 82717214Smckusick n = MIN(fc, 0xff); 8284736Swnj mtcommand(dev, op, n); 82917214Smckusick n -= sc->sc_resid; 83017214Smckusick fc -= n; 83117214Smckusick switch (mtop->mt_op) { 83217214Smckusick 83317214Smckusick case MTWEOF: 83417214Smckusick sc->sc_blkno += (daddr_t)n; 83517214Smckusick sc->sc_nxrec = sc->sc_blkno - 1; 83617214Smckusick break; 83717214Smckusick 83817214Smckusick case MTOFFL: 83917214Smckusick case MTREW: 84017214Smckusick case MTFSF: 84117214Smckusick sc->sc_blkno = (daddr_t)0; 84217214Smckusick sc->sc_nxrec = (daddr_t)INF; 84317214Smckusick break; 84417214Smckusick 84517214Smckusick case MTBSF: 84617214Smckusick if (sc->sc_resid) { 84717214Smckusick sc->sc_blkno = (daddr_t)0; 84817214Smckusick sc->sc_nxrec = (daddr_t)INF; 84917214Smckusick } else { 85017214Smckusick sc->sc_blkno = (daddr_t)(-1); 85117214Smckusick sc->sc_nxrec = (daddr_t)(-1); 85217214Smckusick } 85317214Smckusick break; 85417214Smckusick 85517214Smckusick case MTFSR: 85617214Smckusick sc->sc_blkno += (daddr_t)n; 85717214Smckusick break; 85817214Smckusick 85917214Smckusick case MTBSR: 86017214Smckusick sc->sc_blkno -= (daddr_t)n; 86117214Smckusick break; 86217214Smckusick } 86317214Smckusick if (sc->sc_resid) 86417214Smckusick break; 86517214Smckusick } while (fc); 86617214Smckusick if (fc) { 86717214Smckusick sc->sc_resid = callcount + fc; 86834221Sbostic if (mtop->mt_op == MTFSR || 86934221Sbostic mtop->mt_op == MTBSR) 87017214Smckusick return (EIO); 87134221Sbostic break; 87217214Smckusick } 87317214Smckusick if (bp->b_flags & B_ERROR) 8744736Swnj break; 8754736Swnj } 8768712Sroot return (geterror(bp)); 8777637Ssam 87817214Smckusick /* tape status */ 8794736Swnj case MTIOCGET: 8807637Ssam mtget = (struct mtget *)data; 8817637Ssam mtget->mt_erreg = sc->sc_erreg; 8827637Ssam mtget->mt_resid = sc->sc_resid; 8834736Swnj mtcommand(dev, MT_SENSE, 1); /* update drive status */ 8847637Ssam mtget->mt_dsreg = sc->sc_dsreg; 8857637Ssam mtget->mt_type = MT_ISMT; 8868581Sroot break; 8877637Ssam 88817214Smckusick /* ignore EOT condition */ 88917214Smckusick case MTIOCIEOT: 89017214Smckusick sc->sc_flags |= H_IEOT; 89117214Smckusick break; 89217214Smckusick 89317214Smckusick /* enable EOT condition */ 89417214Smckusick case MTIOCEEOT: 89517214Smckusick sc->sc_flags &= ~H_IEOT; 89617214Smckusick break; 89717214Smckusick 8984736Swnj default: 8998581Sroot return (ENXIO); 9004736Swnj } 9018581Sroot return (0); 9024736Swnj } 9034736Swnj 9044736Swnj #define DBSIZE 20 9054736Swnj 9064736Swnj mtdump() 9074736Swnj { 9084736Swnj register struct mba_device *mi; 9094736Swnj register struct mba_regs *mp; 9104736Swnj int blk, num; 9114736Swnj int start; 9124736Swnj 9134736Swnj start = 0; 9144736Swnj num = maxfree; 9154736Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 9164736Swnj if (mtinfo[0] == 0) 9174736Swnj return (ENXIO); 9184736Swnj mi = phys(mtinfo[0], struct mba_device *); 9194736Swnj mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 9204736Swnj mp->mba_cr = MBCR_IE; 9216186Ssam #if lint 9228606Sroot blk = 0; num = blk; start = num; blk = start; 9236186Ssam return (0); 9246186Ssam #endif 9256186Ssam #ifdef notyet 9264736Swnj mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive]; 9274736Swnj mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI; 9284736Swnj mtaddr->mtcs1 = MT_DCLR|MT_GO; 9294736Swnj while (num > 0) { 9304736Swnj blk = num > DBSIZE ? DBSIZE : num; 9314736Swnj mtdwrite(start, blk, mtaddr, mp); 9324736Swnj start += blk; 9334736Swnj num -= blk; 9344736Swnj } 9354736Swnj mteof(mtaddr); 9364736Swnj mteof(mtaddr); 9374736Swnj mtwait(mtaddr); 9384736Swnj if (mtaddr->mtds&MTDS_ERR) 9394736Swnj return (EIO); 9404736Swnj mtaddr->mtcs1 = MT_REW|MT_GO; 9414736Swnj return (0); 9424736Swnj } 9434736Swnj 9444736Swnj mtdwrite(dbuf, num, mtaddr, mp) 9454736Swnj register dbuf, num; 9464736Swnj register struct mtdevice *mtaddr; 9474736Swnj struct mba_regs *mp; 9484736Swnj { 9494736Swnj register struct pte *io; 9504736Swnj register int i; 9514736Swnj 9524736Swnj mtwait(mtaddr); 9534736Swnj io = mp->mba_map; 9544736Swnj for (i = 0; i < num; i++) 9554736Swnj *(int *)io++ = dbuf++ | PG_V; 9564736Swnj mtaddr->mtfc = -(num*NBPG); 9574736Swnj mp->mba_sr = -1; 9584736Swnj mp->mba_bcr = -(num*NBPG); 9594736Swnj mp->mba_var = 0; 9604736Swnj mtaddr->mtcs1 = MT_WCOM|MT_GO; 9614736Swnj } 9624736Swnj 9634736Swnj mtwait(mtaddr) 9644736Swnj struct mtdevice *mtaddr; 9654736Swnj { 9664736Swnj register s; 9674736Swnj 9684736Swnj do 9694736Swnj s = mtaddr->mtds; 9704736Swnj while ((s & MTDS_DRY) == 0); 9714736Swnj } 9724736Swnj 9734736Swnj mteof(mtaddr) 9744736Swnj struct mtdevice *mtaddr; 9754736Swnj { 9764736Swnj 9774736Swnj mtwait(mtaddr); 9784736Swnj mtaddr->mtcs1 = MT_WEOF|MT_GO; 9794736Swnj #endif notyet 9804736Swnj } 98117214Smckusick 98217214Smckusick #ifdef MTLERRM 98334221Sbostic /* 98434221Sbostic * Failure messages for each failure code, per interrupt code. 98534221Sbostic * Each table ends with a code of -1 as a default. 98634221Sbostic */ 98734221Sbostic struct fmesg { 98834221Sbostic int f_code; 98934221Sbostic char *f_mesg; 99034221Sbostic }; 99117214Smckusick 99234221Sbostic static char unclass[] = "unclassified failure code"; 99317214Smckusick 99434221Sbostic /* MTER_BOT */ 99534221Sbostic static struct fmesg botmsg[] = { 99634221Sbostic 01, "tape was at BOT", 99734221Sbostic 02, "BOT seen after tape started", 99834221Sbostic 03, "ARA ID detected", 99934221Sbostic -1, unclass 100034221Sbostic }; 100117214Smckusick 100234221Sbostic /* MTER_NOTRDY */ 100334221Sbostic static struct fmesg notrdymsg[] = { 100434221Sbostic 01, "TU on-line but not ready", 100534221Sbostic 02, "fatal error has occurred", 100636548Sbostic 03, "access allowed but not ready", 100734221Sbostic -1, unclass 100834221Sbostic }; 100917214Smckusick 101034221Sbostic /* MTER_NOTCAP */ 101134221Sbostic static struct fmesg notcapmsg[] = { 101234221Sbostic 01, "no record found within 25 feet", 101334221Sbostic 02, "ID burst neither PE nor GCR", 101434221Sbostic 03, "ARA ID not found", 101534221Sbostic 04, "no gap found after ID burst", 101634221Sbostic -1, unclass 101734221Sbostic }; 101817214Smckusick 101934221Sbostic /* MTER_LONGREC */ 102034221Sbostic static struct fmesg longrecmsg[] = { 102134221Sbostic 00, "extended sense data not found", 102234221Sbostic 01, "extended sense data updated", 102334221Sbostic -1, unclass 102434221Sbostic }; 102517214Smckusick 102634221Sbostic /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */ 102734221Sbostic static struct fmesg code22msg[] = { 102834221Sbostic 01, "GCR write error", 102934221Sbostic 02, "GCR read error", 103034221Sbostic 03, "PE read error", 103134221Sbostic 04, "PE write error", 103234221Sbostic 05, "at least 1 bit set in ECCSTA", 103334221Sbostic 06, "PE write error", 103434221Sbostic 07, "GCR write error", 103534221Sbostic 010, "RSTAT contains bad code", 103634221Sbostic 011, "PE write error", 103734221Sbostic 012, "MASSBUS parity error", 103834221Sbostic 013, "invalid data transferred", 103934221Sbostic -1, unclass 104034221Sbostic }; 104117214Smckusick 104234221Sbostic /* MTER_TMFLTA */ 104334221Sbostic static struct fmesg tmfltamsg[] = { 104434221Sbostic 01, "illegal command code", 104534221Sbostic 02, "DT command issued when NDT command active", 104634221Sbostic 03, "WMC error", 104734221Sbostic 04, "RUN not received from MASSBUS controller", 104834221Sbostic 05, "mismatch in command read - function routine", 104934221Sbostic 06, "ECC ROM parity error", 105034221Sbostic 07, "XMC ROM parity error", 105134221Sbostic 010, "mismatch in command read - ID burst command", 105234221Sbostic 011, "mismatch in command read - verify ARA burst command", 105334221Sbostic 012, "mismatch in command read - verify ARA ID command", 105434221Sbostic 013, "mismatch in command read - verify gap command", 105534221Sbostic 014, "mismatch in command read - read id burst command", 105634221Sbostic 015, "mismatch in command read - verify ARA ID command", 105734221Sbostic 016, "mismatch in command read - verify gap command", 105834221Sbostic 017, "mismatch in command read - find gap command", 105934221Sbostic 020, "WMC LEFT failed to set", 106034221Sbostic 021, "XL PE set in INTSTA register", 106134221Sbostic 022, "XMC DONE did not set", 106234221Sbostic 023, "WMC ROM PE or RD PE set in WMCERR register", 106334221Sbostic -1, unclass 106434221Sbostic }; 106517214Smckusick 106634221Sbostic /* MTER_TUFLTA */ 106734221Sbostic static struct fmesg tufltamsg[] = { 106834221Sbostic 01, "TU status parity error", 106934221Sbostic 02, "TU command parity error", 107034221Sbostic 03, "rewinding tape went offline", 107134221Sbostic 04, "tape went not ready during DSE", 107234221Sbostic 05, "TU CMD status changed during DSE", 107334221Sbostic 06, "TU never came up to speed", 107434221Sbostic 07, "TU velocity changed", 107534221Sbostic 010, "TU CMD did not load correctly to start tape motion", 107634221Sbostic 011, "TU CMD did not load correctly to set drive density", 107734221Sbostic 012, "TU CMD did not load correctly to start tape motion to write BOT ID", 107834221Sbostic 013, "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID", 107934221Sbostic 014, "failed to write density ID burst", 108034221Sbostic 015, "failed to write ARA burst", 108134221Sbostic 016, "failed to write ARA ID", 108234221Sbostic 017, "ARA error bit set in MTA status B register", 108334221Sbostic 021, "could not find a gap after ID code was written correctly", 108434221Sbostic 022, "TU CMD did not load correctly to start tape motion to read ID burst", 108534221Sbostic 023, "timeout looking for BOT after detecting ARA ID burst", 108634221Sbostic 024, "failed to write tape mark", 108734221Sbostic 025, "tape never came up to speed while trying to reposition for retry of writing tape mark", 108834221Sbostic 026, "TU CMD did not load correctly to start tape motion in erase gap routine", 108934221Sbostic 027, "could not detect a gap in in erase gap routine", 109034221Sbostic 030, "could not detect a gap after writing record", 109134221Sbostic 031, "read path terminated before entire record was written", 109234221Sbostic 032, "could not find a gap after writing record and read path terminated early", 109334221Sbostic 033, "TU CMD did not load correctly to backup for retry of write tape mark", 109434221Sbostic 034, "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark", 109534221Sbostic 035, "TU CMD did not load correctly to backup to retry a load of BOT ID", 109634221Sbostic 036, "timeout looking for BOT after failing to write BOT ID", 109734221Sbostic 037, "TU velocity changed while writing PE gap before starting to write record", 109834221Sbostic 040, "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst", 109934221Sbostic 041, "TU CMD did not load correctly to set GCR tape density after writing Density ID", 110034221Sbostic 042, "TU CMD did not load correctly to set PE tape density at start of read from BOT", 110134221Sbostic 043, "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst", 110234221Sbostic }; 110317214Smckusick 110434221Sbostic /* MTER_TMFLTB */ 110534221Sbostic static char inlinetest[] = "inline test failed"; 110634221Sbostic static struct fmesg tmfltbmsg[] = { 110734221Sbostic 00, "RST0 interrupt occurred with TM RDY set", 110834221Sbostic 01, "power failed to interrupt", 110934221Sbostic 02, "unknown interrupt on channel 5.5", 111034221Sbostic 03, "unknown interrupt on channel 6.5", 111134221Sbostic 04, "unknown interrupt on channel 7", 111234221Sbostic 05, "unknown interrupt on channel 7.5", 111334221Sbostic 06, "CAS contention retry count expired", 111434221Sbostic 07, "CAS contention error not retryable", 111534221Sbostic 010, "queue error, could not find queue entry", 111634221Sbostic 011, "queue entry already full", 111734221Sbostic 012, "8085 ROM parity error", 111834221Sbostic 013, inlinetest, 111934221Sbostic 013, inlinetest, 112034221Sbostic 014, inlinetest, 112134221Sbostic 015, inlinetest, 112234221Sbostic 016, inlinetest, 112334221Sbostic 017, inlinetest, 112434221Sbostic 020, inlinetest, 112534221Sbostic 021, inlinetest, 112634221Sbostic 022, inlinetest, 112734221Sbostic 023, inlinetest, 112834221Sbostic 024, inlinetest, 112934221Sbostic 025, inlinetest, 113034221Sbostic 026, inlinetest, 113134221Sbostic 027, inlinetest, 113234221Sbostic 030, inlinetest, 113334221Sbostic 031, inlinetest, 113434221Sbostic 032, inlinetest, 113534221Sbostic 033, inlinetest, 113634221Sbostic 034, inlinetest, 113734221Sbostic 035, inlinetest, 113834221Sbostic 036, inlinetest, 113934221Sbostic 037, inlinetest, 114034221Sbostic 040, inlinetest, 114134221Sbostic 041, inlinetest, 114234221Sbostic 042, inlinetest, 114334221Sbostic 043, inlinetest, 114434221Sbostic 044, inlinetest, 114536548Sbostic 045, inlinetest, 114634221Sbostic 046, inlinetest, 114734221Sbostic 047, inlinetest, 114834221Sbostic 050, inlinetest, 114934221Sbostic 051, inlinetest, 115034221Sbostic 052, inlinetest, 115134221Sbostic 053, inlinetest, 115234221Sbostic 054, inlinetest, 115334221Sbostic 055, inlinetest, 115434221Sbostic 056, inlinetest, 115534221Sbostic 057, inlinetest, 115634221Sbostic -1, unclass 115734221Sbostic }; 115817214Smckusick 115934221Sbostic /* MTER_MBFLT */ 116034221Sbostic static struct fmesg mbfltmsg[] = { 116134221Sbostic 01, "control bus parity error", 116234221Sbostic 02, "illegal register referenced", 116334221Sbostic -1, unclass 116434221Sbostic }; 116517214Smckusick 116634221Sbostic /* 116734221Sbostic * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL, 116834221Sbostic * and default: no failure message. 116934221Sbostic */ 117034221Sbostic static struct fmesg nullmsg[] = { 117134221Sbostic -1, "" 117234221Sbostic }; 117317214Smckusick 117434221Sbostic /* 117534221Sbostic * Interrupt code table. 117634221Sbostic */ 117734221Sbostic static struct errmsg { 117834221Sbostic int e_code; 117934221Sbostic char *e_mesg; 118034221Sbostic struct fmesg *e_fmesg; 118134221Sbostic } errmsg[] = { 118234221Sbostic MTER_BOT, "unexpected BOT", botmsg, 118334221Sbostic MTER_LEOT, "unexpected LEOT", nullmsg, 118434221Sbostic MTER_RWDING, "tape rewinding", nullmsg, 118534221Sbostic MTER_NOTRDY, "drive not ready", notrdymsg, 118634221Sbostic MTER_NOTAVL, "drive not available", nullmsg, 118734221Sbostic MTER_NONEX, "unit does not exist", nullmsg, 118834221Sbostic MTER_NOTCAP, "not capable", notcapmsg, 118934221Sbostic MTER_LONGREC, "long record", longrecmsg, 119034221Sbostic MTER_UNREAD, "unreadable record", code22msg, 119134221Sbostic MTER_ERROR, "error", code22msg, 119234221Sbostic MTER_EOTERR, "EOT error", code22msg, 119334221Sbostic MTER_BADTAPE, "tape position lost", code22msg, 119434221Sbostic MTER_TMFLTA, "TM fault A", tmfltamsg, 119534221Sbostic MTER_TUFLTA, "TU fault A", tufltamsg, 119634221Sbostic MTER_TMFLTB, "TM fault B", tmfltbmsg, 119734221Sbostic MTER_MBFLT, "MB fault", mbfltmsg, 119834221Sbostic MTER_KEYFAIL, "keypad entry error", nullmsg, 119934221Sbostic -1, "unclassified error", nullmsg 120034221Sbostic }; 120117214Smckusick 120234221Sbostic /* 120334221Sbostic * Decode an interrupt-time failure. 120434221Sbostic */ 120534221Sbostic mtintfail(erreg) 120634221Sbostic int erreg; 120734221Sbostic { 120834221Sbostic register struct errmsg *e; 120934221Sbostic register struct fmesg *f; 121034221Sbostic register int ecode, fcode; 121117214Smckusick 121234221Sbostic ecode = erreg & MTER_INTCODE; 121334221Sbostic fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT; 121434221Sbostic for (e = errmsg; e->e_code >= 0; e++) 121534221Sbostic if (e->e_code == ecode) 121617214Smckusick break; 121734221Sbostic for (f = e->e_fmesg; f->f_code >= 0; f++) 121834221Sbostic if (f->f_code == fcode) 121917214Smckusick break; 122034221Sbostic printf(" interrupt code = 0%o <%s>\n", ecode, e->e_mesg); 122134221Sbostic printf(" failure code = 0%o <%s>\n", fcode, f->f_mesg); 122217214Smckusick } 122334221Sbostic #endif /* MTLERRM */ 122434221Sbostic #endif /* NMT > 0 */ 1225