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*34221Sbostic * @(#)mt.c 7.2 (Berkeley) 05/06/88 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) 16*34221Sbostic * `read reverse' error recovery - ggs (ulysses!ggs) 174736Swnj * 1817214Smckusick * OPTIONS: 1917214Smckusick * MTLERRM - Long error message text - twd, Brown University 2017214Smckusick * 214736Swnj * TODO: 2217214Smckusick * Add odd byte count kludge from VMS driver (?) 2317214Smckusick * Write dump routine 244736Swnj */ 2517214Smckusick 2617119Sbloom #include "param.h" 2717119Sbloom #include "systm.h" 2817119Sbloom #include "buf.h" 2917119Sbloom #include "conf.h" 3017119Sbloom #include "dir.h" 3117119Sbloom #include "file.h" 3217119Sbloom #include "user.h" 3317119Sbloom #include "map.h" 3417119Sbloom #include "ioctl.h" 3517119Sbloom #include "mtio.h" 3617119Sbloom #include "cmap.h" 3717119Sbloom #include "uio.h" 3818324Sralph #include "tty.h" 39*34221Sbostic #include "syslog.h" 404736Swnj 41*34221Sbostic #include "../vax/pte.h" 428471Sroot #include "../vax/cpu.h" 4317119Sbloom #include "mbareg.h" 4417119Sbloom #include "mbavar.h" 4517119Sbloom #include "mtreg.h" 464736Swnj 4717214Smckusick #define MTTIMEOUT 10000 /* loop limit for controller test */ 4817214Smckusick #define INF 1000000L /* a block number that won't exist */ 4917214Smckusick #define MASKREG(r) ((r) & 0xffff) /* the control registers have 16 bits */ 504736Swnj 5117214Smckusick /* Bits for sc_flags */ 524736Swnj 5317214Smckusick #define H_WRITTEN 01 /* last operation was a write */ 5417214Smckusick #define H_EOT 02 /* end of tape encountered */ 5517214Smckusick #define H_IEOT 04 /* ignore EOT condition */ 564736Swnj 57*34221Sbostic int mt_do_readrev = 1; 5817214Smckusick 5917214Smckusick /* Per unit status information */ 6017214Smckusick 614736Swnj struct mu_softc { 62*34221Sbostic char sc_openf; /* unit is open if != 0 */ 63*34221Sbostic char sc_flags; /* state flags */ 64*34221Sbostic daddr_t sc_blkno; /* current physical block number */ 65*34221Sbostic daddr_t sc_nxrec; /* firewall input block number */ 66*34221Sbostic u_short sc_erreg; /* copy of mter or mtner */ 67*34221Sbostic u_short sc_dsreg; /* copy of mtds */ 68*34221Sbostic short sc_resid; /* residual function count for ioctl */ 69*34221Sbostic short sc_dens; /* density code - MT_GCR or zero */ 70*34221Sbostic int sc_i_mtas; /* mtas at slave attach time */ 71*34221Sbostic int sc_i_mtner; /* mtner at slave attach time */ 72*34221Sbostic int sc_i_mtds; /* mtds at slave attach time */ 73*34221Sbostic struct tty *sc_ttyp; /* record user's tty for errors */ 74*34221Sbostic int sc_blks; /* number of I/O operations since open */ 75*34221Sbostic int sc_softerrs; /* number of soft I/O errors since open */ 764736Swnj } mu_softc[NMU]; 774736Swnj 7817214Smckusick struct buf cmtbuf[NMT]; /* tape command buffer structures */ 794736Swnj 80*34221Sbostic struct mba_device *mtinfo[NMT]; /* unit to ctlr structures */ 81*34221Sbostic struct mba_slave *muinfo[NMU]; /* unit to slave structures */ 82*34221Sbostic 8317214Smckusick char mtds_bits[] = MTDS_BITS; /* mtds bit names for error messages */ 8417214Smckusick short mttypes[] = { MBDT_TU78, 0 }; 854736Swnj 8617214Smckusick int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint(); 8717214Smckusick struct mba_driver mtdriver = 8817214Smckusick { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint, 8917214Smckusick mttypes, "mt", "mu", mtinfo }; 9017214Smckusick 91*34221Sbostic /* Bits in minor device */ 92*34221Sbostic #define MUUNIT(dev) (minor(dev)&03) 93*34221Sbostic #define H_NOREWIND 04 94*34221Sbostic #define H_6250BPI 010 9517214Smckusick 96*34221Sbostic #define MTUNIT(dev) (muinfo[MUUNIT(dev)]->ms_ctlr) 97*34221Sbostic 98*34221Sbostic void mtcreset(); 99*34221Sbostic 1004736Swnj /*ARGSUSED*/ 1014736Swnj mtattach(mi) 1024736Swnj struct mba_device *mi; 1034736Swnj { 104*34221Sbostic 105*34221Sbostic /* void */ 1064736Swnj } 1074736Swnj 1087431Skre mtslave(mi, ms, sn) 1094736Swnj struct mba_device *mi; 1104736Swnj struct mba_slave *ms; 1117431Skre int sn; 1124736Swnj { 1134736Swnj register struct mu_softc *sc = &mu_softc[ms->ms_unit]; 1144736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 11526377Skarels int s = spl5(), rtn = 0, i; 1164736Swnj 117*34221Sbostic /* 118*34221Sbostic * Just in case the controller is ill, reset it. Then issue 119*34221Sbostic * a sense operation and wait about a second for it to respond. 120*34221Sbostic */ 12117214Smckusick mtcreset(mtaddr); 1224736Swnj mtaddr->mtas = -1; 1237431Skre mtaddr->mtncs[sn] = MT_SENSE|MT_GO; 124*34221Sbostic for (i = MTTIMEOUT; i > 0; i--) { 12517214Smckusick DELAY(50); 12617214Smckusick if (MASKREG(mtaddr->mtas) != 0) 12717214Smckusick break; 12817214Smckusick } 12917214Smckusick sc->sc_i_mtas = mtaddr->mtas; 13017214Smckusick sc->sc_i_mtner = mtaddr->mtner; 13117214Smckusick sc->sc_i_mtds = mtaddr->mtds; 13217214Smckusick 133*34221Sbostic /* 134*34221Sbostic * If no response, whimper. If wrong response, call it an 135*34221Sbostic * unsolicited interrupt and use mtndtint to log and correct. 136*34221Sbostic * Otherwise, note whether this slave exists. 137*34221Sbostic */ 138*34221Sbostic if (i <= 0) 13917214Smckusick printf("mt: controller hung\n"); 140*34221Sbostic else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE) 14117214Smckusick (void) mtndtint(mi); 142*34221Sbostic else if (mtaddr->mtds & MTDS_PRES) 1434736Swnj rtn = 1; 14417214Smckusick 145*34221Sbostic /* 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; 158*34221Sbostic register struct mba_slave *ms; 1594736Swnj 1604736Swnj muunit = MUUNIT(dev); 161*34221Sbostic if (muunit >= NMU || (ms = muinfo[muunit]) == NULL || 162*34221Sbostic 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); 166*34221Sbostic 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); 171*34221Sbostic 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); 176*34221Sbostic 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); 181*34221Sbostic sc->sc_openf = 0; 1828581Sroot return (EIO); 1834736Swnj } 184*34221Sbostic if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) && 185*34221Sbostic (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) { 1864736Swnj uprintf("mu%d: can't change density in mid-tape\n", muunit); 187*34221Sbostic sc->sc_openf = 0; 1888581Sroot return (EIO); 1894736Swnj } 1904736Swnj sc->sc_blkno = (daddr_t)0; 19117214Smckusick 192*34221Sbostic /* 193*34221Sbostic * Since cooked I/O may do a read-ahead before a write, trash 194*34221Sbostic * on a tape can make the first write fail. Suppress the first 195*34221Sbostic * read-ahead unless definitely doing read-write. 196*34221Sbostic */ 197*34221Sbostic sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ? 198*34221Sbostic (daddr_t)0 : (daddr_t)INF; 1994736Swnj sc->sc_flags = 0; 200*34221Sbostic sc->sc_blks = 0; 201*34221Sbostic 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 212*34221Sbostic if ((flag & (FREAD | FWRITE)) == FWRITE || 213*34221Sbostic ((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); 217*34221Sbostic if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100) 218*34221Sbostic log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n", 219*34221Sbostic MUUNIT(dev), sc->sc_softerrs, sc->sc_blks); 2204736Swnj sc->sc_openf = 0; 2214736Swnj } 2224736Swnj 2234736Swnj mtcommand(dev, com, count) 2244736Swnj dev_t dev; 2254736Swnj int com, count; 2264736Swnj { 2274736Swnj register struct buf *bp; 228*34221Sbostic int s; 2294736Swnj 2304736Swnj bp = &cmtbuf[MTUNIT(dev)]; 2315437Sroot s = spl5(); 23217214Smckusick while (bp->b_flags & B_BUSY) { 233*34221Sbostic if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE)) 2344736Swnj break; 2354736Swnj bp->b_flags |= B_WANTED; 2364736Swnj sleep((caddr_t)bp, PRIBIO); 2374736Swnj } 2384736Swnj bp->b_flags = B_BUSY|B_READ; 2395437Sroot splx(s); 2404736Swnj bp->b_dev = dev; 2414736Swnj bp->b_command = com; 2424736Swnj bp->b_repcnt = count; 2434736Swnj bp->b_blkno = 0; 24417214Smckusick bp->b_error = 0; 2454736Swnj mtstrategy(bp); 2464736Swnj if (count == 0) 2474736Swnj return; 248*34221Sbostic biowait(bp); 24917214Smckusick if (bp->b_flags & B_WANTED) 2504736Swnj wakeup((caddr_t)bp); 2514736Swnj bp->b_flags &= B_ERROR; 2524736Swnj } 2534736Swnj 2544736Swnj mtstrategy(bp) 2554736Swnj register struct buf *bp; 2564736Swnj { 2574736Swnj register struct buf *dp; 258*34221Sbostic struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)]; 259*34221Sbostic int s; 2604736Swnj 261*34221Sbostic /* 262*34221Sbostic * If this is a data transfer operation, set the resid to a 263*34221Sbostic * default value (EOF) to simplify getting it right during 264*34221Sbostic * error recovery or bail out. 265*34221Sbostic */ 26617214Smckusick if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 26717214Smckusick bp->b_resid = bp->b_bcount; 26817214Smckusick 269*34221Sbostic /* 270*34221Sbostic * Link this request onto the end of the queue for this 271*34221Sbostic * controller, then start I/O if not already active. 272*34221Sbostic */ 2734736Swnj bp->av_forw = NULL; 2744736Swnj dp = &mi->mi_tab; 2755437Sroot s = spl5(); 2764736Swnj if (dp->b_actf == NULL) 2774736Swnj dp->b_actf = bp; 2784736Swnj else 2794736Swnj dp->b_actl->av_forw = bp; 2804736Swnj dp->b_actl = bp; 2814736Swnj if (dp->b_active == 0) 2824736Swnj mbustart(mi); 2835437Sroot splx(s); 2844736Swnj } 2854736Swnj 2864736Swnj mtustart(mi) 2874736Swnj register struct mba_device *mi; 2884736Swnj { 28917214Smckusick register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 2904736Swnj register struct buf *bp = mi->mi_tab.b_actf; 2914736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 2924736Swnj daddr_t blkno; 29326377Skarels int count; 2944736Swnj 2954736Swnj if (sc->sc_openf < 0) { 2964736Swnj bp->b_flags |= B_ERROR; 2974736Swnj return (MBU_NEXT); 2984736Swnj } 2994736Swnj if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) { 300*34221Sbostic /* 301*34221Sbostic * Data transfer. If write at end of tape, 302*34221Sbostic * signal "no space" unless suppressed 303*34221Sbostic * by MTIOCIEOT. 304*34221Sbostic */ 305*34221Sbostic if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT && 306*34221Sbostic (bp->b_flags & B_READ) == 0) { 3074736Swnj bp->b_flags |= B_ERROR; 30817214Smckusick bp->b_error = ENOSPC; 3094736Swnj return (MBU_NEXT); 3104736Swnj } 31117214Smckusick 312*34221Sbostic if (bp->b_flags & B_RAW) { 313*34221Sbostic /* raw transfer; never seek */ 314*34221Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno); 315*34221Sbostic sc->sc_nxrec = sc->sc_blkno + 1; 316*34221Sbostic } else { 31717214Smckusick /* seek beyond end of file */ 31817214Smckusick if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 31917214Smckusick bp->b_flags |= B_ERROR; 32017214Smckusick bp->b_error = ENXIO; 32117214Smckusick return (MBU_NEXT); 32217214Smckusick } 32317214Smckusick 324*34221Sbostic /* 325*34221Sbostic * This should be end of file, but the buffer 326*34221Sbostic * system wants a one-block look-ahead. Humor it. 327*34221Sbostic */ 328*34221Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec && 329*34221Sbostic bp->b_flags & B_READ) { 330*34221Sbostic bp->b_resid = bp->b_bcount; 33117214Smckusick clrbuf(bp); 33217214Smckusick return (MBU_NEXT); 33317214Smckusick } 33417214Smckusick 33517214Smckusick /* If writing, mark the next block invalid. */ 33617214Smckusick if ((bp->b_flags & B_READ) == 0) 33717214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 3384736Swnj } 3394736Swnj } else { 34017214Smckusick /* It's a command, do it now. */ 3414736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3424736Swnj (bp->b_repcnt<<8)|bp->b_command|MT_GO; 3434736Swnj return (MBU_STARTED); 3444736Swnj } 34517214Smckusick 346*34221Sbostic /* 347*34221Sbostic * If raw I/O, or if the tape is positioned correctly for 348*34221Sbostic * cooked I/O, set the byte count, unit number and repeat count 349*34221Sbostic * then tell the MASSBUS to proceed. Note that a negative 350*34221Sbostic * bcount tells mbstart to map the buffer for "read backwards". 351*34221Sbostic */ 352*34221Sbostic if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) { 3534736Swnj if (mi->mi_tab.b_errcnt == 2) { 354*34221Sbostic mtaddr->mtbc = -bp->b_bcount; 3554736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 3564736Swnj } else { 3574736Swnj mtaddr->mtbc = bp->b_bcount; 3584736Swnj mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev); 3594736Swnj } 3604736Swnj return (MBU_DODATA); 3614736Swnj } 36217214Smckusick 36317214Smckusick /* Issue skip operations to position the next block for cooked I/O. */ 36417214Smckusick 3657380Ssam if (blkno < bdbtofsb(bp->b_blkno)) 366*34221Sbostic count = bdbtofsb(bp->b_blkno) - blkno; 3674736Swnj else 368*34221Sbostic count = blkno - bdbtofsb(bp->b_blkno); 369*34221Sbostic if ((unsigned)count > 0377) 37026377Skarels count = 0377; 37126377Skarels mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO; 3724736Swnj return (MBU_STARTED); 3734736Swnj } 3744736Swnj 3754736Swnj mtstart(mi) 3764736Swnj register struct mba_device *mi; 3774736Swnj { 3784736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3794736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 3804736Swnj 3814736Swnj if (bp->b_flags & B_READ) 3824736Swnj if (mi->mi_tab.b_errcnt == 2) 383*34221Sbostic return (MT_READREV|MT_GO); 3844736Swnj else 385*34221Sbostic return (MT_READ|MT_GO); 3864736Swnj else 387*34221Sbostic return (MT_WRITE|sc->sc_dens|MT_GO); 3884736Swnj } 3894736Swnj 3904736Swnj mtdtint(mi, mbsr) 3914736Swnj register struct mba_device *mi; 3924736Swnj int mbsr; 3934736Swnj { 3944736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 3954736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3964736Swnj register struct mu_softc *sc; 39717214Smckusick register int er; 3984736Swnj 39917214Smckusick /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */ 40017214Smckusick if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) { 4014736Swnj printf("mt: wrong unit!\n"); 4024736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 4034736Swnj } 40417214Smckusick 40517214Smckusick er = MASKREG(mtaddr->mter); 4064736Swnj sc = &mu_softc[MUUNIT(bp->b_dev)]; 40717214Smckusick sc->sc_erreg = er; 40817214Smckusick if (bp->b_flags & B_READ) 40917214Smckusick sc->sc_flags &= ~H_WRITTEN; 41017214Smckusick else 4114736Swnj sc->sc_flags |= H_WRITTEN; 41217214Smckusick switch (er & MTER_INTCODE) { 41317214Smckusick 41417214Smckusick case MTER_EOT: 41517214Smckusick sc->sc_flags |= H_EOT; 41617214Smckusick /* fall into MTER_DONE */ 41717214Smckusick 4184736Swnj case MTER_DONE: 41917214Smckusick sc->sc_blkno++; 42017214Smckusick if (mi->mi_tab.b_errcnt == 2) { 42117214Smckusick bp->b_bcount = bp->b_resid; 42217214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 423*34221Sbostic if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0) 42417214Smckusick bp->b_flags |= B_ERROR; 425*34221Sbostic } else 42617214Smckusick bp->b_resid = 0; 42717214Smckusick break; 42817214Smckusick 42917214Smckusick case MTER_SHRTREC: 43017214Smckusick sc->sc_blkno++; 43117214Smckusick bp->b_bcount = bp->b_resid; 43217214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 433*34221Sbostic if ((bp->b_flags & B_RAW) == 0) 43417214Smckusick bp->b_flags |= B_ERROR; 43517214Smckusick break; 43617214Smckusick 43717214Smckusick case MTER_RETRY: 438*34221Sbostic /* 439*34221Sbostic * Simple re-try. Since resid is always a copy of the 440*34221Sbostic * original byte count, use it to restore the count. 441*34221Sbostic */ 44217214Smckusick mi->mi_tab.b_errcnt = 1; 44317214Smckusick bp->b_bcount = bp->b_resid; 444*34221Sbostic return (MBD_RETRY); 44517214Smckusick 44617214Smckusick case MTER_RDOPP: 447*34221Sbostic /* 448*34221Sbostic * The controller just decided to read it backwards. 449*34221Sbostic * If the controller returns a byte count of zero, 450*34221Sbostic * change it to 1, since zero encodes 65536, which 451*34221Sbostic * isn't quite what we had in mind. The byte count 452*34221Sbostic * may be larger than the size of the input buffer, so 453*34221Sbostic * limit the count to the buffer size. After 454*34221Sbostic * making the byte count reasonable, set bcount to the 455*34221Sbostic * negative of the controller's version of the byte 456*34221Sbostic * count so that the start address for the transfer is 457*34221Sbostic * set up correctly. 458*34221Sbostic */ 45917214Smckusick if (mt_do_readrev) { 46017214Smckusick mi->mi_tab.b_errcnt = 2; 46117214Smckusick if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0) 46217214Smckusick bp->b_bcount = 1; 46317214Smckusick if (bp->b_bcount > bp->b_resid) 46417214Smckusick bp->b_bcount = bp->b_resid; 46517214Smckusick bp->b_bcount = -(bp->b_bcount); 46617214Smckusick return(MBD_RETRY); 46717214Smckusick } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) { 46817214Smckusick sc->sc_blkno++; 46917214Smckusick bp->b_bcount = bp->b_resid; 47017214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 47117214Smckusick bp->b_flags |= B_ERROR; 47217214Smckusick break; 47317214Smckusick } 47417214Smckusick bp->b_flags |= B_ERROR; 47517214Smckusick /* fall into MTER_LONGREC */ 47617214Smckusick 4774736Swnj case MTER_LONGREC: 47817214Smckusick sc->sc_blkno++; 47917214Smckusick bp->b_bcount = bp->b_resid; 4804736Swnj bp->b_resid = 0; 48117214Smckusick bp->b_error = ENOMEM; 48217214Smckusick bp->b_flags |= B_ERROR; 4834736Swnj break; 4844736Swnj 4854736Swnj case MTER_NOTCAP: 4864736Swnj printf("mu%d: blank tape\n", MUUNIT(bp->b_dev)); 4874736Swnj goto err; 4884736Swnj 4894736Swnj case MTER_TM: 490*34221Sbostic /* 491*34221Sbostic * End of file. Since the default byte count has 492*34221Sbostic * already been set, just count the block and proceed. 493*34221Sbostic */ 4944736Swnj sc->sc_blkno++; 4954736Swnj err: 496*34221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno); 4974736Swnj break; 4984736Swnj 4994736Swnj case MTER_OFFLINE: 5004736Swnj if (sc->sc_openf > 0) { 5014736Swnj sc->sc_openf = -1; 502*34221Sbostic tprintf(sc->sc_ttyp, "mu%d: offline\n", 503*34221Sbostic MUUNIT(bp->b_dev)); 5044736Swnj } 5054736Swnj bp->b_flags |= B_ERROR; 5064736Swnj break; 5074736Swnj 50817214Smckusick case MTER_NOTAVL: 50917214Smckusick if (sc->sc_openf > 0) { 51017214Smckusick sc->sc_openf = -1; 51118324Sralph tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", 51218324Sralph MUUNIT(bp->b_dev)); 51317214Smckusick } 51417214Smckusick bp->b_flags |= B_ERROR; 51517214Smckusick break; 51617214Smckusick 5174736Swnj case MTER_FPT: 518*34221Sbostic tprintf(sc->sc_ttyp, "mu%d: no write ring\n", 519*34221Sbostic MUUNIT(bp->b_dev)); 5204736Swnj bp->b_flags |= B_ERROR; 5214736Swnj break; 5224736Swnj 52317214Smckusick case MTER_UNREAD: 52417214Smckusick sc->sc_blkno++; 52517214Smckusick bp->b_bcount = bp->b_resid; 52617214Smckusick bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount); 52717214Smckusick 528*34221Sbostic /* code 010 means a garbage record, nothing serious. */ 529*34221Sbostic if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) { 530*34221Sbostic tprintf(sc->sc_ttyp, 531*34221Sbostic "mu%d: rn=%d bn=%d unreadable record\n", 53217214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno); 53317214Smckusick bp->b_flags |= B_ERROR; 53417214Smckusick break; 53517214Smckusick } 53617214Smckusick 537*34221Sbostic /* 538*34221Sbostic * Anything else might be a hardware problem, 539*34221Sbostic * fall into the error report. 540*34221Sbostic */ 54117214Smckusick 5424736Swnj default: 543*34221Sbostic /* 544*34221Sbostic * The bits in sc->sc_dsreg are from the last sense 545*34221Sbostic * command. To get the most recent copy, you have to 546*34221Sbostic * do a sense at interrupt level, which requires nested 547*34221Sbostic * error processing. This is a bit messy, so leave 548*34221Sbostic * well enough alone. 549*34221Sbostic */ 550*34221Sbostic tprintf(sc->sc_ttyp, "\ 551*34221Sbostic mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n", 55217214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 55317214Smckusick mbsr, mbsr_bits, er, 55417214Smckusick MASKREG(sc->sc_dsreg), mtds_bits); 55517214Smckusick #ifdef MTLERRM 556*34221Sbostic mtintfail(er); 55717214Smckusick #endif 5584736Swnj bp->b_flags |= B_ERROR; 55917214Smckusick 560*34221Sbostic /* 561*34221Sbostic * The TM78 manual says to reset the controller after 562*34221Sbostic * TM fault B or MASSBUS fault. 563*34221Sbostic */ 564*34221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 565*34221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) 56617214Smckusick mtcreset(mtaddr); 5674736Swnj } 56817214Smckusick 569*34221Sbostic /* 570*34221Sbostic * Just in case some strange error slipped through (drive off 571*34221Sbostic * line during read-reverse error recovery comes to mind), make 572*34221Sbostic * sure the byte count is reasonable. 573*34221Sbostic */ 57417214Smckusick if (bp->b_bcount < 0) 57517214Smckusick bp->b_bcount = bp->b_resid; 576*34221Sbostic 577*34221Sbostic if ((bp->b_flags & B_ERROR) == 0) { 578*34221Sbostic /* this counts reverse reads as soft errors */ 579*34221Sbostic sc->sc_blks++; 580*34221Sbostic if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */ 581*34221Sbostic sc->sc_softerrs++; 582*34221Sbostic } 5834736Swnj return (MBD_DONE); 5844736Swnj } 5854736Swnj 5864736Swnj mtndtint(mi) 5874736Swnj register struct mba_device *mi; 5884736Swnj { 5894736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 5904736Swnj register struct buf *bp = mi->mi_tab.b_actf; 5914736Swnj register struct mu_softc *sc; 59217214Smckusick register int er, fc; 59317214Smckusick int unit; 5944736Swnj 5954736Swnj unit = (mtaddr->mtner >> 8) & 3; 5964736Swnj er = MASKREG(mtaddr->mtner); 59717214Smckusick sc = &mu_softc[unit]; 59817214Smckusick sc->sc_erreg = er; 59917214Smckusick 60017214Smckusick /* Check for unsolicited interrupts. */ 601*34221Sbostic if (bp == NULL || unit != MUUNIT(bp->b_dev)) { 602*34221Sbostic if ((er & MTER_INTCODE) == MTER_ONLINE) 603*34221Sbostic return (MBN_SKIP); 60417214Smckusick 605*34221Sbostic printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n", 606*34221Sbostic unit, er, MASKREG(sc->sc_dsreg), mtds_bits); 60717214Smckusick #ifdef MTLERRM 608*34221Sbostic mtintfail(er); 60917214Smckusick #endif 610*34221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 611*34221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) { 612*34221Sbostic /* 613*34221Sbostic * Reset the controller, then set error status 614*34221Sbostic * if there was anything active when the fault 615*34221Sbostic * occurred. This may shoot an innocent 616*34221Sbostic * bystander, but it's better than letting 617*34221Sbostic * an error slip through. 618*34221Sbostic */ 619*34221Sbostic mtcreset(mtaddr); 620*34221Sbostic if (bp != NULL) { 621*34221Sbostic bp->b_flags |= B_ERROR; 622*34221Sbostic return (MBN_DONE); 62317214Smckusick } 62417214Smckusick } 6254736Swnj return (MBN_SKIP); 6264736Swnj } 62717214Smckusick 6284736Swnj fc = (mtaddr->mtncs[unit] >> 8) & 0xff; 6294736Swnj sc->sc_resid = fc; 63017214Smckusick 631*34221Sbostic /* 632*34221Sbostic * Clear the "written" flag after any operation that changes 633*34221Sbostic * the position of the tape. 634*34221Sbostic */ 635*34221Sbostic if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE) 63617214Smckusick sc->sc_flags &= ~H_WRITTEN; 63717214Smckusick 6384736Swnj switch (er & MTER_INTCODE) { 63917214Smckusick 64017214Smckusick case MTER_EOT: 64117214Smckusick sc->sc_flags |= H_EOT; 64217214Smckusick /* fall into MTER_DONE */ 64317214Smckusick 6444736Swnj case MTER_DONE: 64517214Smckusick /* If this is a command buffer, just update the status. */ 6464736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 6474736Swnj done: 6484736Swnj if (bp->b_command == MT_SENSE) 6494736Swnj sc->sc_dsreg = MASKREG(mtaddr->mtds); 6504736Swnj return (MBN_DONE); 6514736Swnj } 65217214Smckusick 653*34221Sbostic /* 654*34221Sbostic * It's not a command buffer, must be a cooked I/O 655*34221Sbostic * skip operation (perhaps a shaky assumption, but it 656*34221Sbostic * wasn't my idea). 657*34221Sbostic */ 6587380Ssam if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0) 6596186Ssam sc->sc_blkno -= MIN(0377, -fc); 6604736Swnj else 6616186Ssam sc->sc_blkno += MIN(0377, fc); 6624736Swnj return (MBN_RETRY); 6634736Swnj 66417214Smckusick case MTER_ONLINE: /* ddj -- shouldn't happen but did */ 6654736Swnj case MTER_RWDING: 6664736Swnj return (MBN_SKIP); /* ignore "rewind started" interrupt */ 6674736Swnj 6684736Swnj case MTER_NOTCAP: 66918324Sralph tprintf(sc->sc_ttyp, "mu%d: blank tape\n", MUUNIT(bp->b_dev)); 67017214Smckusick bp->b_flags |= B_ERROR; 67117214Smckusick return (MBN_DONE); 6724736Swnj 6734736Swnj case MTER_TM: 6744736Swnj case MTER_LEOT: 675*34221Sbostic /* 676*34221Sbostic * For an ioctl skip operation, count a tape mark as 677*34221Sbostic * a record. If there's anything left to do, update 678*34221Sbostic * the repeat count and re-start the command. 679*34221Sbostic */ 68017214Smckusick if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 68117214Smckusick if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0) 68217214Smckusick return (MBN_DONE); 68317214Smckusick else 68417214Smckusick return (MBN_RETRY); 6854736Swnj } else { 686*34221Sbostic /* 687*34221Sbostic * Cooked I/O again. Just update the books and 688*34221Sbostic * wait for someone else to return end of file or 689*34221Sbostic * complain about a bad seek. 690*34221Sbostic */ 691*34221Sbostic if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 692*34221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1; 693*34221Sbostic sc->sc_blkno = sc->sc_nxrec; 694*34221Sbostic } else { 695*34221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc; 696*34221Sbostic sc->sc_blkno = sc->sc_nxrec + 1; 697*34221Sbostic } 6984736Swnj } 6994736Swnj return (MBN_RETRY); 7004736Swnj 7014736Swnj case MTER_FPT: 702*34221Sbostic tprintf(sc->sc_ttyp, "mu%d: no write ring\n", 703*34221Sbostic MUUNIT(bp->b_dev)); 7044736Swnj bp->b_flags |= B_ERROR; 7054736Swnj return (MBN_DONE); 7064736Swnj 7074736Swnj case MTER_OFFLINE: 70817214Smckusick /* If `off line' was intentional, don't complain. */ 709*34221Sbostic if (bp == &cmtbuf[MTUNIT(bp->b_dev)] && 710*34221Sbostic bp->b_command == MT_UNLOAD) 71117214Smckusick return(MBN_DONE); 7124736Swnj if (sc->sc_openf > 0) { 7134736Swnj sc->sc_openf = -1; 714*34221Sbostic tprintf(sc->sc_ttyp, "mu%d: offline\n", 715*34221Sbostic MUUNIT(bp->b_dev)); 7164736Swnj } 7174736Swnj bp->b_flags |= B_ERROR; 7184736Swnj return (MBN_DONE); 7194736Swnj 72017214Smckusick case MTER_NOTAVL: 72117214Smckusick if (sc->sc_openf > 0) { 72217214Smckusick sc->sc_openf = -1; 723*34221Sbostic tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", 724*34221Sbostic MUUNIT(bp->b_dev)); 72517214Smckusick } 72617214Smckusick bp->b_flags |= B_ERROR; 72717214Smckusick return (MBN_DONE); 72817214Smckusick 7294736Swnj case MTER_BOT: 7304736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 7314736Swnj goto done; 73217214Smckusick /* fall through */ 73317214Smckusick 7344736Swnj default: 735*34221Sbostic tprintf(sc->sc_ttyp, "\ 736*34221Sbostic mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n", 73717214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 73817214Smckusick er, MASKREG(sc->sc_dsreg), mtds_bits); 73917214Smckusick #ifdef MTLERRM 740*34221Sbostic mtintfail(er); 74117214Smckusick #endif 742*34221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB || 743*34221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) 74417214Smckusick mtcreset(mtaddr); /* reset the controller */ 7454736Swnj bp->b_flags |= B_ERROR; 7464736Swnj return (MBN_DONE); 7474736Swnj } 7484736Swnj /* NOTREACHED */ 7494736Swnj } 7504736Swnj 751*34221Sbostic void 752*34221Sbostic mtcreset(mtaddr) 75317214Smckusick register struct mtdevice *mtaddr; 75417214Smckusick { 75517214Smckusick register int i; 75617214Smckusick 75717214Smckusick mtaddr->mtid = MTID_CLR; /* reset the TM78 */ 75817214Smckusick DELAY(200); 75917214Smckusick for (i = MTTIMEOUT; i > 0; i--) { 76017214Smckusick DELAY(50); /* don't nag */ 76117214Smckusick if ((mtaddr->mtid & MTID_RDY) != 0) 76217214Smckusick return; /* exit when ready */ 76317214Smckusick } 76417214Smckusick printf("mt: controller hung\n"); 76517214Smckusick } 76617214Smckusick 7674736Swnj /*ARGSUSED*/ 7687637Ssam mtioctl(dev, cmd, data, flag) 7694736Swnj dev_t dev; 7704736Swnj int cmd; 7717637Ssam caddr_t data; 7724736Swnj int flag; 7734736Swnj { 7744736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 7754736Swnj register struct buf *bp = &cmtbuf[MTUNIT(dev)]; 77617214Smckusick register struct mtop *mtop; 77717214Smckusick register struct mtget *mtget; 77817214Smckusick int callcount, fcount; 77917214Smckusick int op; 78017214Smckusick 78117214Smckusick /* We depend on the values and order of the MT codes here. */ 78217214Smckusick 7834736Swnj static mtops[] = 7844736Swnj {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE}; 7854736Swnj 7864736Swnj switch (cmd) { 7877637Ssam 78817214Smckusick /* tape operation */ 78917214Smckusick 79017214Smckusick case MTIOCTOP: 7918606Sroot mtop = (struct mtop *)data; 7928606Sroot switch (mtop->mt_op) { 7937637Ssam 7944736Swnj case MTWEOF: 7957637Ssam callcount = mtop->mt_count; 7964736Swnj fcount = 1; 7974736Swnj break; 7987637Ssam 7994736Swnj case MTFSF: case MTBSF: 8007637Ssam callcount = mtop->mt_count; 8014736Swnj fcount = 1; 8024736Swnj break; 8037637Ssam 8044736Swnj case MTFSR: case MTBSR: 8054736Swnj callcount = 1; 8067637Ssam fcount = mtop->mt_count; 8074736Swnj break; 8087637Ssam 8094736Swnj case MTREW: case MTOFFL: 8104736Swnj callcount = 1; 8114736Swnj fcount = 1; 8124736Swnj break; 8137637Ssam 8144736Swnj default: 8158581Sroot return (ENXIO); 8164736Swnj } 817*34221Sbostic if (callcount <= 0 || fcount <= 0) 8188581Sroot return (EINVAL); 8197637Ssam op = mtops[mtop->mt_op]; 8204736Swnj if (op == MT_WTM) 8214736Swnj op |= sc->sc_dens; 8224736Swnj while (--callcount >= 0) { 82317214Smckusick register int n, fc = fcount; 8244736Swnj 8254736Swnj do { 82617214Smckusick n = MIN(fc, 0xff); 8274736Swnj mtcommand(dev, op, n); 82817214Smckusick n -= sc->sc_resid; 82917214Smckusick fc -= n; 83017214Smckusick switch (mtop->mt_op) { 83117214Smckusick 83217214Smckusick case MTWEOF: 83317214Smckusick sc->sc_blkno += (daddr_t)n; 83417214Smckusick sc->sc_nxrec = sc->sc_blkno - 1; 83517214Smckusick break; 83617214Smckusick 83717214Smckusick case MTOFFL: 83817214Smckusick case MTREW: 83917214Smckusick case MTFSF: 84017214Smckusick sc->sc_blkno = (daddr_t)0; 84117214Smckusick sc->sc_nxrec = (daddr_t)INF; 84217214Smckusick break; 84317214Smckusick 84417214Smckusick case MTBSF: 84517214Smckusick if (sc->sc_resid) { 84617214Smckusick sc->sc_blkno = (daddr_t)0; 84717214Smckusick sc->sc_nxrec = (daddr_t)INF; 84817214Smckusick } else { 84917214Smckusick sc->sc_blkno = (daddr_t)(-1); 85017214Smckusick sc->sc_nxrec = (daddr_t)(-1); 85117214Smckusick } 85217214Smckusick break; 85317214Smckusick 85417214Smckusick case MTFSR: 85517214Smckusick sc->sc_blkno += (daddr_t)n; 85617214Smckusick break; 85717214Smckusick 85817214Smckusick case MTBSR: 85917214Smckusick sc->sc_blkno -= (daddr_t)n; 86017214Smckusick break; 86117214Smckusick } 86217214Smckusick if (sc->sc_resid) 86317214Smckusick break; 86417214Smckusick } while (fc); 86517214Smckusick if (fc) { 86617214Smckusick sc->sc_resid = callcount + fc; 867*34221Sbostic if (mtop->mt_op == MTFSR || 868*34221Sbostic mtop->mt_op == MTBSR) 86917214Smckusick return (EIO); 870*34221Sbostic break; 87117214Smckusick } 87217214Smckusick if (bp->b_flags & B_ERROR) 8734736Swnj break; 8744736Swnj } 8758712Sroot return (geterror(bp)); 8767637Ssam 87717214Smckusick /* tape status */ 8784736Swnj case MTIOCGET: 8797637Ssam mtget = (struct mtget *)data; 8807637Ssam mtget->mt_erreg = sc->sc_erreg; 8817637Ssam mtget->mt_resid = sc->sc_resid; 8824736Swnj mtcommand(dev, MT_SENSE, 1); /* update drive status */ 8837637Ssam mtget->mt_dsreg = sc->sc_dsreg; 8847637Ssam mtget->mt_type = MT_ISMT; 8858581Sroot break; 8867637Ssam 88717214Smckusick /* ignore EOT condition */ 88817214Smckusick case MTIOCIEOT: 88917214Smckusick sc->sc_flags |= H_IEOT; 89017214Smckusick break; 89117214Smckusick 89217214Smckusick /* enable EOT condition */ 89317214Smckusick case MTIOCEEOT: 89417214Smckusick sc->sc_flags &= ~H_IEOT; 89517214Smckusick break; 89617214Smckusick 8974736Swnj default: 8988581Sroot return (ENXIO); 8994736Swnj } 9008581Sroot return (0); 9014736Swnj } 9024736Swnj 9034736Swnj #define DBSIZE 20 9044736Swnj 9054736Swnj mtdump() 9064736Swnj { 9074736Swnj register struct mba_device *mi; 9084736Swnj register struct mba_regs *mp; 9094736Swnj int blk, num; 9104736Swnj int start; 9114736Swnj 9124736Swnj start = 0; 9134736Swnj num = maxfree; 9144736Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 9154736Swnj if (mtinfo[0] == 0) 9164736Swnj return (ENXIO); 9174736Swnj mi = phys(mtinfo[0], struct mba_device *); 9184736Swnj mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 9194736Swnj mp->mba_cr = MBCR_IE; 9206186Ssam #if lint 9218606Sroot blk = 0; num = blk; start = num; blk = start; 9226186Ssam return (0); 9236186Ssam #endif 9246186Ssam #ifdef notyet 9254736Swnj mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive]; 9264736Swnj mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI; 9274736Swnj mtaddr->mtcs1 = MT_DCLR|MT_GO; 9284736Swnj while (num > 0) { 9294736Swnj blk = num > DBSIZE ? DBSIZE : num; 9304736Swnj mtdwrite(start, blk, mtaddr, mp); 9314736Swnj start += blk; 9324736Swnj num -= blk; 9334736Swnj } 9344736Swnj mteof(mtaddr); 9354736Swnj mteof(mtaddr); 9364736Swnj mtwait(mtaddr); 9374736Swnj if (mtaddr->mtds&MTDS_ERR) 9384736Swnj return (EIO); 9394736Swnj mtaddr->mtcs1 = MT_REW|MT_GO; 9404736Swnj return (0); 9414736Swnj } 9424736Swnj 9434736Swnj mtdwrite(dbuf, num, mtaddr, mp) 9444736Swnj register dbuf, num; 9454736Swnj register struct mtdevice *mtaddr; 9464736Swnj struct mba_regs *mp; 9474736Swnj { 9484736Swnj register struct pte *io; 9494736Swnj register int i; 9504736Swnj 9514736Swnj mtwait(mtaddr); 9524736Swnj io = mp->mba_map; 9534736Swnj for (i = 0; i < num; i++) 9544736Swnj *(int *)io++ = dbuf++ | PG_V; 9554736Swnj mtaddr->mtfc = -(num*NBPG); 9564736Swnj mp->mba_sr = -1; 9574736Swnj mp->mba_bcr = -(num*NBPG); 9584736Swnj mp->mba_var = 0; 9594736Swnj mtaddr->mtcs1 = MT_WCOM|MT_GO; 9604736Swnj } 9614736Swnj 9624736Swnj mtwait(mtaddr) 9634736Swnj struct mtdevice *mtaddr; 9644736Swnj { 9654736Swnj register s; 9664736Swnj 9674736Swnj do 9684736Swnj s = mtaddr->mtds; 9694736Swnj while ((s & MTDS_DRY) == 0); 9704736Swnj } 9714736Swnj 9724736Swnj mteof(mtaddr) 9734736Swnj struct mtdevice *mtaddr; 9744736Swnj { 9754736Swnj 9764736Swnj mtwait(mtaddr); 9774736Swnj mtaddr->mtcs1 = MT_WEOF|MT_GO; 9784736Swnj #endif notyet 9794736Swnj } 98017214Smckusick 98117214Smckusick #ifdef MTLERRM 982*34221Sbostic /* 983*34221Sbostic * Failure messages for each failure code, per interrupt code. 984*34221Sbostic * Each table ends with a code of -1 as a default. 985*34221Sbostic */ 986*34221Sbostic struct fmesg { 987*34221Sbostic int f_code; 988*34221Sbostic char *f_mesg; 989*34221Sbostic }; 99017214Smckusick 991*34221Sbostic static char unclass[] = "unclassified failure code"; 99217214Smckusick 993*34221Sbostic /* MTER_BOT */ 994*34221Sbostic static struct fmesg botmsg[] = { 995*34221Sbostic 01, "tape was at BOT", 996*34221Sbostic 02, "BOT seen after tape started", 997*34221Sbostic 03, "ARA ID detected", 998*34221Sbostic -1, unclass 999*34221Sbostic }; 100017214Smckusick 1001*34221Sbostic /* MTER_NOTRDY */ 1002*34221Sbostic static struct fmesg notrdymsg[] = { 1003*34221Sbostic 01, "TU on-line but not ready", 1004*34221Sbostic 02, "fatal error has occurred", 1005*34221Sbostic 03, "access allowed by not really" 1006*34221Sbostic -1, unclass 1007*34221Sbostic }; 100817214Smckusick 1009*34221Sbostic /* MTER_NOTCAP */ 1010*34221Sbostic static struct fmesg notcapmsg[] = { 1011*34221Sbostic 01, "no record found within 25 feet", 1012*34221Sbostic 02, "ID burst neither PE nor GCR", 1013*34221Sbostic 03, "ARA ID not found", 1014*34221Sbostic 04, "no gap found after ID burst", 1015*34221Sbostic -1, unclass 1016*34221Sbostic }; 101717214Smckusick 1018*34221Sbostic /* MTER_LONGREC */ 1019*34221Sbostic static struct fmesg longrecmsg[] = { 1020*34221Sbostic 00, "extended sense data not found", 1021*34221Sbostic 01, "extended sense data updated", 1022*34221Sbostic -1, unclass 1023*34221Sbostic }; 102417214Smckusick 1025*34221Sbostic /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */ 1026*34221Sbostic static struct fmesg code22msg[] = { 1027*34221Sbostic 01, "GCR write error", 1028*34221Sbostic 02, "GCR read error", 1029*34221Sbostic 03, "PE read error", 1030*34221Sbostic 04, "PE write error", 1031*34221Sbostic 05, "at least 1 bit set in ECCSTA", 1032*34221Sbostic 06, "PE write error", 1033*34221Sbostic 07, "GCR write error", 1034*34221Sbostic 010, "RSTAT contains bad code", 1035*34221Sbostic 011, "PE write error", 1036*34221Sbostic 012, "MASSBUS parity error", 1037*34221Sbostic 013, "invalid data transferred", 1038*34221Sbostic -1, unclass 1039*34221Sbostic }; 104017214Smckusick 1041*34221Sbostic /* MTER_TMFLTA */ 1042*34221Sbostic static struct fmesg tmfltamsg[] = { 1043*34221Sbostic 01, "illegal command code", 1044*34221Sbostic 02, "DT command issued when NDT command active", 1045*34221Sbostic 03, "WMC error", 1046*34221Sbostic 04, "RUN not received from MASSBUS controller", 1047*34221Sbostic 05, "mismatch in command read - function routine", 1048*34221Sbostic 06, "ECC ROM parity error", 1049*34221Sbostic 07, "XMC ROM parity error", 1050*34221Sbostic 010, "mismatch in command read - ID burst command", 1051*34221Sbostic 011, "mismatch in command read - verify ARA burst command", 1052*34221Sbostic 012, "mismatch in command read - verify ARA ID command", 1053*34221Sbostic 013, "mismatch in command read - verify gap command", 1054*34221Sbostic 014, "mismatch in command read - read id burst command", 1055*34221Sbostic 015, "mismatch in command read - verify ARA ID command", 1056*34221Sbostic 016, "mismatch in command read - verify gap command", 1057*34221Sbostic 017, "mismatch in command read - find gap command", 1058*34221Sbostic 020, "WMC LEFT failed to set", 1059*34221Sbostic 021, "XL PE set in INTSTA register", 1060*34221Sbostic 022, "XMC DONE did not set", 1061*34221Sbostic 023, "WMC ROM PE or RD PE set in WMCERR register", 1062*34221Sbostic -1, unclass 1063*34221Sbostic }; 106417214Smckusick 1065*34221Sbostic /* MTER_TUFLTA */ 1066*34221Sbostic static struct fmesg tufltamsg[] = { 1067*34221Sbostic 01, "TU status parity error", 1068*34221Sbostic 02, "TU command parity error", 1069*34221Sbostic 03, "rewinding tape went offline", 1070*34221Sbostic 04, "tape went not ready during DSE", 1071*34221Sbostic 05, "TU CMD status changed during DSE", 1072*34221Sbostic 06, "TU never came up to speed", 1073*34221Sbostic 07, "TU velocity changed", 1074*34221Sbostic 010, "TU CMD did not load correctly to start tape motion", 1075*34221Sbostic 011, "TU CMD did not load correctly to set drive density", 1076*34221Sbostic 012, "TU CMD did not load correctly to start tape motion to write BOT ID", 1077*34221Sbostic 013, "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID", 1078*34221Sbostic 014, "failed to write density ID burst", 1079*34221Sbostic 015, "failed to write ARA burst", 1080*34221Sbostic 016, "failed to write ARA ID", 1081*34221Sbostic 017, "ARA error bit set in MTA status B register", 1082*34221Sbostic 021, "could not find a gap after ID code was written correctly", 1083*34221Sbostic 022, "TU CMD did not load correctly to start tape motion to read ID burst", 1084*34221Sbostic 023, "timeout looking for BOT after detecting ARA ID burst", 1085*34221Sbostic 024, "failed to write tape mark", 1086*34221Sbostic 025, "tape never came up to speed while trying to reposition for retry of writing tape mark", 1087*34221Sbostic 026, "TU CMD did not load correctly to start tape motion in erase gap routine", 1088*34221Sbostic 027, "could not detect a gap in in erase gap routine", 1089*34221Sbostic 030, "could not detect a gap after writing record", 1090*34221Sbostic 031, "read path terminated before entire record was written", 1091*34221Sbostic 032, "could not find a gap after writing record and read path terminated early", 1092*34221Sbostic 033, "TU CMD did not load correctly to backup for retry of write tape mark", 1093*34221Sbostic 034, "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark", 1094*34221Sbostic 035, "TU CMD did not load correctly to backup to retry a load of BOT ID", 1095*34221Sbostic 036, "timeout looking for BOT after failing to write BOT ID", 1096*34221Sbostic 037, "TU velocity changed while writing PE gap before starting to write record", 1097*34221Sbostic 040, "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst", 1098*34221Sbostic 041, "TU CMD did not load correctly to set GCR tape density after writing Density ID", 1099*34221Sbostic 042, "TU CMD did not load correctly to set PE tape density at start of read from BOT", 1100*34221Sbostic 043, "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst", 1101*34221Sbostic }; 110217214Smckusick 1103*34221Sbostic /* MTER_TMFLTB */ 1104*34221Sbostic static char inlinetest[] = "inline test failed"; 1105*34221Sbostic static struct fmesg tmfltbmsg[] = { 1106*34221Sbostic 00, "RST0 interrupt occurred with TM RDY set", 1107*34221Sbostic 01, "power failed to interrupt", 1108*34221Sbostic 02, "unknown interrupt on channel 5.5", 1109*34221Sbostic 03, "unknown interrupt on channel 6.5", 1110*34221Sbostic 04, "unknown interrupt on channel 7", 1111*34221Sbostic 05, "unknown interrupt on channel 7.5", 1112*34221Sbostic 06, "CAS contention retry count expired", 1113*34221Sbostic 07, "CAS contention error not retryable", 1114*34221Sbostic 010, "queue error, could not find queue entry", 1115*34221Sbostic 011, "queue entry already full", 1116*34221Sbostic 012, "8085 ROM parity error", 1117*34221Sbostic 013, inlinetest, 1118*34221Sbostic 013, inlinetest, 1119*34221Sbostic 014, inlinetest, 1120*34221Sbostic 015, inlinetest, 1121*34221Sbostic 016, inlinetest, 1122*34221Sbostic 017, inlinetest, 1123*34221Sbostic 020, inlinetest, 1124*34221Sbostic 021, inlinetest, 1125*34221Sbostic 022, inlinetest, 1126*34221Sbostic 023, inlinetest, 1127*34221Sbostic 024, inlinetest, 1128*34221Sbostic 025, inlinetest, 1129*34221Sbostic 026, inlinetest, 1130*34221Sbostic 027, inlinetest, 1131*34221Sbostic 030, inlinetest, 1132*34221Sbostic 031, inlinetest, 1133*34221Sbostic 032, inlinetest, 1134*34221Sbostic 033, inlinetest, 1135*34221Sbostic 034, inlinetest, 1136*34221Sbostic 035, inlinetest, 1137*34221Sbostic 036, inlinetest, 1138*34221Sbostic 037, inlinetest, 1139*34221Sbostic 040, inlinetest, 1140*34221Sbostic 041, inlinetest, 1141*34221Sbostic 042, inlinetest, 1142*34221Sbostic 043, inlinetest, 1143*34221Sbostic 044, inlinetest, 1144*34221Sbostic 045, inlinetest 1145*34221Sbostic 046, inlinetest, 1146*34221Sbostic 047, inlinetest, 1147*34221Sbostic 050, inlinetest, 1148*34221Sbostic 051, inlinetest, 1149*34221Sbostic 052, inlinetest, 1150*34221Sbostic 053, inlinetest, 1151*34221Sbostic 054, inlinetest, 1152*34221Sbostic 055, inlinetest, 1153*34221Sbostic 056, inlinetest, 1154*34221Sbostic 057, inlinetest, 1155*34221Sbostic -1, unclass 1156*34221Sbostic }; 115717214Smckusick 1158*34221Sbostic /* MTER_MBFLT */ 1159*34221Sbostic static struct fmesg mbfltmsg[] = { 1160*34221Sbostic 01, "control bus parity error", 1161*34221Sbostic 02, "illegal register referenced", 1162*34221Sbostic -1, unclass 1163*34221Sbostic }; 116417214Smckusick 1165*34221Sbostic /* 1166*34221Sbostic * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL, 1167*34221Sbostic * and default: no failure message. 1168*34221Sbostic */ 1169*34221Sbostic static struct fmesg nullmsg[] = { 1170*34221Sbostic -1, "" 1171*34221Sbostic }; 117217214Smckusick 1173*34221Sbostic /* 1174*34221Sbostic * Interrupt code table. 1175*34221Sbostic */ 1176*34221Sbostic static struct errmsg { 1177*34221Sbostic int e_code; 1178*34221Sbostic char *e_mesg; 1179*34221Sbostic struct fmesg *e_fmesg; 1180*34221Sbostic } errmsg[] = { 1181*34221Sbostic MTER_BOT, "unexpected BOT", botmsg, 1182*34221Sbostic MTER_LEOT, "unexpected LEOT", nullmsg, 1183*34221Sbostic MTER_RWDING, "tape rewinding", nullmsg, 1184*34221Sbostic MTER_NOTRDY, "drive not ready", notrdymsg, 1185*34221Sbostic MTER_NOTAVL, "drive not available", nullmsg, 1186*34221Sbostic MTER_NONEX, "unit does not exist", nullmsg, 1187*34221Sbostic MTER_NOTCAP, "not capable", notcapmsg, 1188*34221Sbostic MTER_LONGREC, "long record", longrecmsg, 1189*34221Sbostic MTER_UNREAD, "unreadable record", code22msg, 1190*34221Sbostic MTER_ERROR, "error", code22msg, 1191*34221Sbostic MTER_EOTERR, "EOT error", code22msg, 1192*34221Sbostic MTER_BADTAPE, "tape position lost", code22msg, 1193*34221Sbostic MTER_TMFLTA, "TM fault A", tmfltamsg, 1194*34221Sbostic MTER_TUFLTA, "TU fault A", tufltamsg, 1195*34221Sbostic MTER_TMFLTB, "TM fault B", tmfltbmsg, 1196*34221Sbostic MTER_MBFLT, "MB fault", mbfltmsg, 1197*34221Sbostic MTER_KEYFAIL, "keypad entry error", nullmsg, 1198*34221Sbostic -1, "unclassified error", nullmsg 1199*34221Sbostic }; 120017214Smckusick 1201*34221Sbostic /* 1202*34221Sbostic * Decode an interrupt-time failure. 1203*34221Sbostic */ 1204*34221Sbostic mtintfail(erreg) 1205*34221Sbostic int erreg; 1206*34221Sbostic { 1207*34221Sbostic register struct errmsg *e; 1208*34221Sbostic register struct fmesg *f; 1209*34221Sbostic register int ecode, fcode; 121017214Smckusick 1211*34221Sbostic ecode = erreg & MTER_INTCODE; 1212*34221Sbostic fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT; 1213*34221Sbostic for (e = errmsg; e->e_code >= 0; e++) 1214*34221Sbostic if (e->e_code == ecode) 121517214Smckusick break; 1216*34221Sbostic for (f = e->e_fmesg; f->f_code >= 0; f++) 1217*34221Sbostic if (f->f_code == fcode) 121817214Smckusick break; 1219*34221Sbostic printf(" interrupt code = 0%o <%s>\n", ecode, e->e_mesg); 1220*34221Sbostic printf(" failure code = 0%o <%s>\n", fcode, f->f_mesg); 122117214Smckusick } 1222*34221Sbostic #endif /* MTLERRM */ 1223*34221Sbostic #endif /* NMT > 0 */ 1224