123315Smckusick /* 223315Smckusick * Copyright (c) 1982 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*26377Skarels * @(#)mt.c 6.6 (Berkeley) 02/23/86 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) 164736Swnj * 1717214Smckusick * OPTIONS: 1817214Smckusick * MTLERRM - Long error message text - twd, Brown University 1917214Smckusick * MTRDREV - `read reverse' error recovery - ggs (ulysses!ggs) 2017214Smckusick * 214736Swnj * TODO: 2217214Smckusick * Add odd byte count kludge from VMS driver (?) 2317214Smckusick * Write dump routine 244736Swnj */ 2517214Smckusick 269789Ssam #include "../machine/pte.h" 279789Ssam 2817119Sbloom #include "param.h" 2917119Sbloom #include "systm.h" 3017119Sbloom #include "buf.h" 3117119Sbloom #include "conf.h" 3217119Sbloom #include "dir.h" 3317119Sbloom #include "file.h" 3417119Sbloom #include "user.h" 3517119Sbloom #include "map.h" 3617119Sbloom #include "ioctl.h" 3717119Sbloom #include "mtio.h" 3817119Sbloom #include "cmap.h" 3917119Sbloom #include "uio.h" 4018324Sralph #include "tty.h" 414736Swnj 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 5717214Smckusick /* Bits in minor device */ 5817214Smckusick 594736Swnj #define MUUNIT(dev) (minor(dev)&03) 604736Swnj #define H_NOREWIND 04 6117214Smckusick #define H_6250BPI 010 624736Swnj 634736Swnj #define MTUNIT(dev) (mutomt[MUUNIT(dev)]) 644736Swnj 6517214Smckusick #ifdef MTRDREV 6617214Smckusick int mt_do_readrev = 1; 6717214Smckusick #else 6817214Smckusick int mt_do_readrev = 0; 6917214Smckusick #endif 704736Swnj 7117214Smckusick /* Per unit status information */ 7217214Smckusick 734736Swnj struct mu_softc { 7417214Smckusick char sc_openf; /* unit is open if != 0 */ 7517214Smckusick char sc_flags; /* state flags */ 7617214Smckusick daddr_t sc_blkno; /* current physical block number */ 7717214Smckusick daddr_t sc_nxrec; /* firewall input block number */ 7817214Smckusick u_short sc_erreg; /* copy of mter or mtner */ 7917214Smckusick u_short sc_dsreg; /* copy of mtds */ 8017214Smckusick short sc_resid; /* residual function count for ioctl */ 8117214Smckusick short sc_dens; /* density code - MT_GCR or zero */ 8217214Smckusick struct mba_device *sc_mi; /* massbus structure for unit */ 8317214Smckusick int sc_slave; /* slave number for unit */ 8417214Smckusick int sc_i_mtas; /* mtas at slave attach time */ 8517214Smckusick int sc_i_mtner; /* mtner at slave attach time */ 8617214Smckusick int sc_i_mtds; /* mtds at slave attach time */ 8717214Smckusick #ifdef MTLERRM 8817214Smckusick char *sc_mesg; /* text for interrupt type code */ 8917214Smckusick char *sc_fmesg; /* text for tape error code */ 9017214Smckusick #endif 9118324Sralph struct tty *sc_ttyp; /* record user's tty for errors */ 924736Swnj } mu_softc[NMU]; 934736Swnj 9417214Smckusick struct buf rmtbuf[NMT]; /* data transfer buffer structures */ 9517214Smckusick struct buf cmtbuf[NMT]; /* tape command buffer structures */ 964736Swnj 9717214Smckusick struct mba_device *mtinfo[NMT]; /* unit massbus structure pointers */ 9817214Smckusick short mutomt[NMU]; /* tape unit to controller number map */ 9917214Smckusick char mtds_bits[] = MTDS_BITS; /* mtds bit names for error messages */ 10017214Smckusick short mttypes[] = { MBDT_TU78, 0 }; 1014736Swnj 10217214Smckusick int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint(); 10317214Smckusick struct mba_driver mtdriver = 10417214Smckusick { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint, 10517214Smckusick mttypes, "mt", "mu", mtinfo }; 10617214Smckusick 10717214Smckusick void mtcreset(); 10817214Smckusick 1094736Swnj /*ARGSUSED*/ 1104736Swnj mtattach(mi) 1114736Swnj struct mba_device *mi; 1124736Swnj { 1134736Swnj } 1144736Swnj 1157431Skre mtslave(mi, ms, sn) 1164736Swnj struct mba_device *mi; 1174736Swnj struct mba_slave *ms; 1187431Skre int sn; 1194736Swnj { 1204736Swnj register struct mu_softc *sc = &mu_softc[ms->ms_unit]; 1214736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 122*26377Skarels int s = spl5(), rtn = 0, i; 1234736Swnj 12417214Smckusick /* Just in case the controller is ill, reset it. Then issue */ 12517214Smckusick /* a sense operation and wait about a second for it to respond. */ 12617214Smckusick 12717214Smckusick mtcreset(mtaddr); 1284736Swnj mtaddr->mtas = -1; 1297431Skre mtaddr->mtncs[sn] = MT_SENSE|MT_GO; 13017214Smckusick for (i = MTTIMEOUT; i> 0; i--) { 13117214Smckusick DELAY(50); 13217214Smckusick if (MASKREG(mtaddr->mtas) != 0) 13317214Smckusick break; 13417214Smckusick } 13517214Smckusick sc->sc_i_mtas = mtaddr->mtas; 13617214Smckusick sc->sc_i_mtner = mtaddr->mtner; 13717214Smckusick sc->sc_i_mtds = mtaddr->mtds; 13817214Smckusick 13917214Smckusick /* If no response, whimper. If wrong response, call it an */ 14017214Smckusick /* unsolicited interrupt and use mtndtint to log and correct. */ 14117214Smckusick /* Otherwise, note whether this slave exists. */ 14217214Smckusick 14317214Smckusick if (i <= 0) { 14417214Smckusick printf("mt: controller hung\n"); 14517214Smckusick } else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE) { 14617214Smckusick (void) mtndtint(mi); 14717214Smckusick } else if (mtaddr->mtds & MTDS_PRES) { 1484736Swnj sc->sc_mi = mi; 1497431Skre sc->sc_slave = sn; 1504736Swnj mutomt[ms->ms_unit] = mi->mi_unit; 1514736Swnj rtn = 1; 1524736Swnj } 15317214Smckusick 15417214Smckusick /* Cancel the interrupt, then wait a little while for it to go away. */ 15517214Smckusick 1564736Swnj mtaddr->mtas = mtaddr->mtas; 15717214Smckusick DELAY(10); 1584736Swnj splx(s); 1594736Swnj return (rtn); 1604736Swnj } 1614736Swnj 1624736Swnj mtopen(dev, flag) 1634736Swnj dev_t dev; 1644736Swnj int flag; 1654736Swnj { 1664736Swnj register int muunit; 1674736Swnj register struct mba_device *mi; 1684736Swnj register struct mu_softc *sc; 1694736Swnj 1704736Swnj muunit = MUUNIT(dev); 17117214Smckusick if ( (muunit >= NMU) 17217214Smckusick || ((mi = mtinfo[MTUNIT(dev)]) == 0) 17317214Smckusick || (mi->mi_alive == 0) ) 1748581Sroot return (ENXIO); 17517214Smckusick if ((sc = &mu_softc[muunit])->sc_openf) 17617214Smckusick return (EBUSY); 17717214Smckusick sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0; 1784736Swnj mtcommand(dev, MT_SENSE, 1); 1794736Swnj if ((sc->sc_dsreg & MTDS_ONL) == 0) { 1804736Swnj uprintf("mu%d: not online\n", muunit); 1818581Sroot return (EIO); 1824736Swnj } 18317214Smckusick if ((sc->sc_dsreg & MTDS_AVAIL) == 0) { 18417214Smckusick uprintf("mu%d: not online (port selector)\n", muunit); 18517214Smckusick return (EIO); 18617214Smckusick } 18717214Smckusick if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) { 1884736Swnj uprintf("mu%d: no write ring\n", muunit); 1898581Sroot return (EIO); 1904736Swnj } 19117214Smckusick if ( ((sc->sc_dsreg & MTDS_BOT) == 0) 19217214Smckusick && (flag & FWRITE) 19317214Smckusick && ( ( (sc->sc_dens == MT_GCR) 19417214Smckusick && (sc->sc_dsreg & MTDS_PE) ) 19517214Smckusick || ( (sc->sc_dens != MT_GCR) 19617214Smckusick && ((sc->sc_dsreg & MTDS_PE) == 0)))) { 1974736Swnj uprintf("mu%d: can't change density in mid-tape\n", muunit); 1988581Sroot return (EIO); 1994736Swnj } 2004736Swnj sc->sc_openf = 1; 2014736Swnj sc->sc_blkno = (daddr_t)0; 20217214Smckusick 20317214Smckusick /* Since cooked I/O may do a read-ahead before a write, trash */ 20417214Smckusick /* on a tape can make the first write fail. Suppress the first */ 20517214Smckusick /* read-ahead unless definitely doing read-write */ 20617214Smckusick 20717214Smckusick sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) 20817214Smckusick ? (daddr_t)0 20917214Smckusick : (daddr_t)INF; 2104736Swnj sc->sc_flags = 0; 21118324Sralph sc->sc_ttyp = u.u_ttyp; 2128581Sroot return (0); 2134736Swnj } 2144736Swnj 2154736Swnj mtclose(dev, flag) 2164736Swnj register dev_t dev; 21717214Smckusick register int flag; 2184736Swnj { 2194736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 2204736Swnj 22117214Smckusick if ( ((flag & (FREAD | FWRITE)) == FWRITE) 22217214Smckusick || ( (flag & FWRITE) 22317214Smckusick && (sc->sc_flags & H_WRITTEN) )) 2244736Swnj mtcommand(dev, MT_CLS|sc->sc_dens, 1); 22517214Smckusick if ((minor(dev) & H_NOREWIND) == 0) 2264736Swnj mtcommand(dev, MT_REW, 0); 2274736Swnj sc->sc_openf = 0; 2284736Swnj } 2294736Swnj 2304736Swnj mtcommand(dev, com, count) 2314736Swnj dev_t dev; 2324736Swnj int com, count; 2334736Swnj { 2344736Swnj register struct buf *bp; 2355437Sroot register int s; 2364736Swnj 2374736Swnj bp = &cmtbuf[MTUNIT(dev)]; 2385437Sroot s = spl5(); 23917214Smckusick while (bp->b_flags & B_BUSY) { 24017214Smckusick if((bp->b_repcnt == 0) && (bp->b_flags & B_DONE)) 2414736Swnj break; 2424736Swnj bp->b_flags |= B_WANTED; 2434736Swnj sleep((caddr_t)bp, PRIBIO); 2444736Swnj } 2454736Swnj bp->b_flags = B_BUSY|B_READ; 2465437Sroot splx(s); 2474736Swnj bp->b_dev = dev; 2484736Swnj bp->b_command = com; 2494736Swnj bp->b_repcnt = count; 2504736Swnj bp->b_blkno = 0; 25117214Smckusick bp->b_error = 0; 2524736Swnj mtstrategy(bp); 2534736Swnj if (count == 0) 2544736Swnj return; 2554736Swnj iowait(bp); 25617214Smckusick if (bp->b_flags & B_WANTED) 2574736Swnj wakeup((caddr_t)bp); 2584736Swnj bp->b_flags &= B_ERROR; 2594736Swnj } 2604736Swnj 2614736Swnj mtstrategy(bp) 2624736Swnj register struct buf *bp; 2634736Swnj { 2644736Swnj register struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)]; 2654736Swnj register struct buf *dp; 2665437Sroot register int s; 2674736Swnj 26817214Smckusick /* If this is a data transfer operation, set the resid to a */ 26917214Smckusick /* default value (EOF) to simplify getting it right during */ 27017214Smckusick /* error recovery or bail out. */ 27117214Smckusick 27217214Smckusick if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 27317214Smckusick bp->b_resid = bp->b_bcount; 27417214Smckusick 27517214Smckusick /* Link this request onto the end of the queue for this */ 27617214Smckusick /* controller, then start I/O if not already active. */ 27717214Smckusick 2784736Swnj bp->av_forw = NULL; 2794736Swnj dp = &mi->mi_tab; 2805437Sroot s = spl5(); 2814736Swnj if (dp->b_actf == NULL) 2824736Swnj dp->b_actf = bp; 2834736Swnj else 2844736Swnj dp->b_actl->av_forw = bp; 2854736Swnj dp->b_actl = bp; 2864736Swnj if (dp->b_active == 0) 2874736Swnj mbustart(mi); 2885437Sroot splx(s); 2894736Swnj } 2904736Swnj 2914736Swnj mtustart(mi) 2924736Swnj register struct mba_device *mi; 2934736Swnj { 29417214Smckusick register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 2954736Swnj register struct buf *bp = mi->mi_tab.b_actf; 2964736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 2974736Swnj daddr_t blkno; 298*26377Skarels int count; 2994736Swnj 3004736Swnj if (sc->sc_openf < 0) { 3014736Swnj bp->b_flags |= B_ERROR; 3024736Swnj return (MBU_NEXT); 3034736Swnj } 3044736Swnj if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) { 30517214Smckusick 30617214Smckusick /* Signal "no space" if out of tape unless suppressed */ 30717214Smckusick /* by MTIOCIEOT. */ 30817214Smckusick 30917214Smckusick if ( ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT) 31017214Smckusick && ((bp->b_flags & B_READ) == 0) ) { 3114736Swnj bp->b_flags |= B_ERROR; 31217214Smckusick bp->b_error = ENOSPC; 3134736Swnj return (MBU_NEXT); 3144736Swnj } 31517214Smckusick 31617214Smckusick /* special case tests for cooked mode */ 31717214Smckusick 31817214Smckusick if (bp != &rmtbuf[MTUNIT(bp->b_dev)]) { 31917214Smckusick 32017214Smckusick /* seek beyond end of file */ 32117214Smckusick 32217214Smckusick if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 32317214Smckusick bp->b_flags |= B_ERROR; 32417214Smckusick bp->b_error = ENXIO; 32517214Smckusick return (MBU_NEXT); 32617214Smckusick } 32717214Smckusick 32817214Smckusick /* This should be end of file, but the buffer */ 32917214Smckusick /* system wants a one-block look-ahead. Humor it. */ 33017214Smckusick 33117214Smckusick if ( (bdbtofsb(bp->b_blkno) == sc->sc_nxrec) 33217214Smckusick && (bp->b_flags & B_READ) ) { 33317214Smckusick clrbuf(bp); 33417214Smckusick return (MBU_NEXT); 33517214Smckusick } 33617214Smckusick 33717214Smckusick /* If writing, mark the next block invalid. */ 33817214Smckusick 33917214Smckusick if ((bp->b_flags & B_READ) == 0) 34017214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 3414736Swnj } 3424736Swnj } else { 34317214Smckusick 34417214Smckusick /* It's a command, do it now. */ 34517214Smckusick 3464736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3474736Swnj (bp->b_repcnt<<8)|bp->b_command|MT_GO; 3484736Swnj return (MBU_STARTED); 3494736Swnj } 35017214Smckusick 35117214Smckusick /* If raw I/O, or if the tape is positioned correctly for */ 35217214Smckusick /* cooked I/O, set the byte count, unit number and repeat count */ 35317214Smckusick /* then tell the MASSBUS to proceed. Note that a negative */ 35417214Smckusick /* bcount tells mbstart to map the buffer for "read backwards". */ 35517214Smckusick 35617214Smckusick if ( (bp == &rmtbuf[MTUNIT(bp->b_dev)]) 35717214Smckusick || ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) ) { 3584736Swnj if (mi->mi_tab.b_errcnt == 2) { 35917214Smckusick mtaddr->mtbc = -(bp->b_bcount); 3604736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 3614736Swnj } else { 3624736Swnj mtaddr->mtbc = bp->b_bcount; 3634736Swnj mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev); 3644736Swnj } 3654736Swnj return (MBU_DODATA); 3664736Swnj } 36717214Smckusick 36817214Smckusick /* Issue skip operations to position the next block for cooked I/O. */ 36917214Smckusick 3707380Ssam if (blkno < bdbtofsb(bp->b_blkno)) 371*26377Skarels count = (unsigned)(bdbtofsb(bp->b_blkno) - blkno); 3724736Swnj else 373*26377Skarels count = (unsigned)(blkno - bdbtofsb(bp->b_blkno)); 374*26377Skarels if (count > 0377) 375*26377Skarels count = 0377; 376*26377Skarels mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO; 3774736Swnj return (MBU_STARTED); 3784736Swnj } 3794736Swnj 3804736Swnj mtstart(mi) 3814736Swnj register struct mba_device *mi; 3824736Swnj { 3834736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3844736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 3854736Swnj 3864736Swnj if (bp->b_flags & B_READ) 3874736Swnj if (mi->mi_tab.b_errcnt == 2) 3884736Swnj return(MT_READREV|MT_GO); 3894736Swnj else 3904736Swnj return(MT_READ|MT_GO); 3914736Swnj else 3924736Swnj return(MT_WRITE|sc->sc_dens|MT_GO); 3934736Swnj } 3944736Swnj 3954736Swnj mtdtint(mi, mbsr) 3964736Swnj register struct mba_device *mi; 3974736Swnj int mbsr; 3984736Swnj { 3994736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 4004736Swnj register struct buf *bp = mi->mi_tab.b_actf; 4014736Swnj register struct mu_softc *sc; 40217214Smckusick register int er; 4034736Swnj 40417214Smckusick /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */ 40517214Smckusick 40617214Smckusick if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) { 4074736Swnj printf("mt: wrong unit!\n"); 4084736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 4094736Swnj } 41017214Smckusick 41117214Smckusick er = MASKREG(mtaddr->mter); 4124736Swnj sc = &mu_softc[MUUNIT(bp->b_dev)]; 41317214Smckusick sc->sc_erreg = er; 41417214Smckusick if (bp->b_flags & B_READ) 41517214Smckusick sc->sc_flags &= ~H_WRITTEN; 41617214Smckusick else 4174736Swnj sc->sc_flags |= H_WRITTEN; 41817214Smckusick switch (er & MTER_INTCODE) { 41917214Smckusick 42017214Smckusick case MTER_EOT: 42117214Smckusick sc->sc_flags |= H_EOT; 42217214Smckusick 42317214Smckusick /* fall into MTER_DONE */ 42417214Smckusick 4254736Swnj case MTER_DONE: 42617214Smckusick sc->sc_blkno++; 42717214Smckusick if (mi->mi_tab.b_errcnt == 2) { 42817214Smckusick bp->b_bcount = bp->b_resid; 42917214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 43017214Smckusick if ( (bp->b_resid > 0) 43117214Smckusick && (bp != &rmtbuf[MTUNIT(bp->b_dev)]) ) 43217214Smckusick bp->b_flags |= B_ERROR; 43317214Smckusick } else { 43417214Smckusick bp->b_resid = 0; 43517214Smckusick } 43617214Smckusick break; 43717214Smckusick 43817214Smckusick case MTER_SHRTREC: 43917214Smckusick sc->sc_blkno++; 44017214Smckusick bp->b_bcount = bp->b_resid; 44117214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 44217214Smckusick if (bp != &rmtbuf[MTUNIT(bp->b_dev)]) 44317214Smckusick bp->b_flags |= B_ERROR; 44417214Smckusick break; 44517214Smckusick 44617214Smckusick case MTER_RETRY: 44717214Smckusick 44817214Smckusick /* Simple re-try. Since resid is always a copy of the */ 44917214Smckusick /* original byte count, use it to restore the count. */ 45017214Smckusick 45117214Smckusick mi->mi_tab.b_errcnt = 1; 45217214Smckusick bp->b_bcount = bp->b_resid; 45317214Smckusick return(MBD_RETRY); 45417214Smckusick 45517214Smckusick case MTER_RDOPP: 45617214Smckusick 45717214Smckusick /* The controller just decided to read it backwards. */ 45817214Smckusick /* If the controller returns a byte count of zero, */ 45917214Smckusick /* change it to 1, since zero encodes 65536, which */ 46017214Smckusick /* isn't quite what we had in mind. The byte count */ 46117214Smckusick /* may be larger than the size of the input buffer, so */ 46217214Smckusick /* limit the count to the buffer size. After */ 46317214Smckusick /* making the byte count reasonable, set bcount to the */ 46417214Smckusick /* negative of the controller's version of the byte */ 46517214Smckusick /* count so that the start address for the transfer is */ 46617214Smckusick /* set up correctly. */ 46717214Smckusick 46817214Smckusick if (mt_do_readrev) { 46917214Smckusick mi->mi_tab.b_errcnt = 2; 47017214Smckusick if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0) 47117214Smckusick bp->b_bcount = 1; 47217214Smckusick if (bp->b_bcount > bp->b_resid) 47317214Smckusick bp->b_bcount = bp->b_resid; 47417214Smckusick bp->b_bcount = -(bp->b_bcount); 47517214Smckusick return(MBD_RETRY); 47617214Smckusick } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) { 47717214Smckusick sc->sc_blkno++; 47817214Smckusick bp->b_bcount = bp->b_resid; 47917214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 48017214Smckusick bp->b_flags |= B_ERROR; 48117214Smckusick break; 48217214Smckusick } 48317214Smckusick bp->b_flags |= B_ERROR; 48417214Smckusick 48517214Smckusick /* fall into MTER_LONGREC */ 48617214Smckusick 4874736Swnj case MTER_LONGREC: 48817214Smckusick sc->sc_blkno++; 48917214Smckusick bp->b_bcount = bp->b_resid; 4904736Swnj bp->b_resid = 0; 49117214Smckusick bp->b_error = ENOMEM; 49217214Smckusick bp->b_flags |= B_ERROR; 4934736Swnj break; 4944736Swnj 4954736Swnj case MTER_NOTCAP: 4964736Swnj printf("mu%d: blank tape\n", MUUNIT(bp->b_dev)); 4974736Swnj goto err; 4984736Swnj 4994736Swnj case MTER_TM: 50017214Smckusick 50117214Smckusick /* End of file. Since the default byte count has */ 50217214Smckusick /* already been set, just count the block and proceed. */ 50317214Smckusick 5044736Swnj sc->sc_blkno++; 5054736Swnj err: 5064736Swnj if (bp != &rmtbuf[MTUNIT(bp->b_dev)]) 50717214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno); 5084736Swnj break; 5094736Swnj 5104736Swnj case MTER_OFFLINE: 5114736Swnj if (sc->sc_openf > 0) { 5124736Swnj sc->sc_openf = -1; 51318324Sralph tprintf(sc->sc_ttyp, "mu%d: offline\n", MUUNIT(bp->b_dev)); 5144736Swnj } 5154736Swnj bp->b_flags |= B_ERROR; 5164736Swnj break; 5174736Swnj 51817214Smckusick case MTER_NOTAVL: 51917214Smckusick if (sc->sc_openf > 0) { 52017214Smckusick sc->sc_openf = -1; 52118324Sralph tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", 52218324Sralph MUUNIT(bp->b_dev)); 52317214Smckusick } 52417214Smckusick bp->b_flags |= B_ERROR; 52517214Smckusick break; 52617214Smckusick 5274736Swnj case MTER_FPT: 52818324Sralph tprintf(sc->sc_ttyp, "mu%d: no write ring\n", MUUNIT(bp->b_dev)); 5294736Swnj bp->b_flags |= B_ERROR; 5304736Swnj break; 5314736Swnj 53217214Smckusick case MTER_UNREAD: 53317214Smckusick sc->sc_blkno++; 53417214Smckusick bp->b_bcount = bp->b_resid; 53517214Smckusick bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount); 53617214Smckusick 53717214Smckusick /* Code 010 means a garbage record, nothing serious. */ 53817214Smckusick 53917214Smckusick if (((er & MTER_FAILCODE) >> 10) == 010) { 54018324Sralph tprintf(sc->sc_ttyp, "mu%d: rn=%d bn=%d unreadable record\n", 54117214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno); 54217214Smckusick bp->b_flags |= B_ERROR; 54317214Smckusick break; 54417214Smckusick } 54517214Smckusick 54617214Smckusick /* Anything else might be a hardware problem, */ 54717214Smckusick /* fall into the error report. */ 54817214Smckusick 5494736Swnj default: 55017214Smckusick 55117214Smckusick /* The bits in sc->sc_dsreg are from the last sense */ 55217214Smckusick /* command. To get the most recent copy, you have to */ 55317214Smckusick /* do a sense at interrupt level, which requires nested */ 55417214Smckusick /* error processing. This is a bit messy, so leave */ 55517214Smckusick /* well enough alone. */ 55617214Smckusick 55718324Sralph tprintf(sc->sc_ttyp, "mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=%o (octal) ds=%b\n", 55817214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 55917214Smckusick mbsr, mbsr_bits, er, 56017214Smckusick MASKREG(sc->sc_dsreg), mtds_bits); 56117214Smckusick #ifdef MTLERRM 56217214Smckusick mtintfail(sc); 56317214Smckusick printf(" interrupt code = %o (octal) <%s>\n failure code = %o (octal) <%s>\n", 56417214Smckusick er & MTER_INTCODE, sc->sc_mesg, 56517214Smckusick (er & MTER_FAILCODE) >> 10, sc->sc_fmesg); 56617214Smckusick #endif 5674736Swnj bp->b_flags |= B_ERROR; 56817214Smckusick 56917214Smckusick /* The TM78 manual says to reset the controller after */ 57017214Smckusick /* TM fault B or MASSBUS fault. */ 57117214Smckusick 57217214Smckusick if ( ((er & MTER_INTCODE) == MTER_TMFLTB) 57317214Smckusick || ((er & MTER_INTCODE) == MTER_MBFLT) ) { 57417214Smckusick mtcreset(mtaddr); 57517214Smckusick } 5764736Swnj } 57717214Smckusick 57817214Smckusick /* Just in case some strange error slipped through, (drive off */ 57917214Smckusick /* line during read-reverse error recovery comes to mind) make */ 58017214Smckusick /* sure the byte count is reasonable. */ 58117214Smckusick 58217214Smckusick if (bp->b_bcount < 0) 58317214Smckusick bp->b_bcount = bp->b_resid; 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. */ 60217214Smckusick 6034736Swnj if (bp == 0 || unit != MUUNIT(bp->b_dev)) { /* consistency check */ 60417214Smckusick if ((er & MTER_INTCODE) != MTER_ONLINE) { 60517214Smckusick printf("mt: unit %d unexpected interrupt (non data transfer) er=%o (octal) ds=%b\n", 60617214Smckusick unit, er, MASKREG(sc->sc_dsreg), mtds_bits); 60717214Smckusick #ifdef MTLERRM 60817214Smckusick mtintfail(sc); 60917214Smckusick printf(" interrupt code = %o (octal) <%s>\n failure code = %o (octal) <%s>\n", 61017214Smckusick er & MTER_INTCODE, sc->sc_mesg, 61117214Smckusick (er & MTER_FAILCODE) >> 10, sc->sc_fmesg); 61217214Smckusick #endif 61317214Smckusick if ( ((er & MTER_INTCODE) == MTER_TMFLTB) 61417214Smckusick || ((er & MTER_INTCODE) == MTER_MBFLT) ) { 61517214Smckusick 61617214Smckusick /* Reset the controller, then set error */ 61717214Smckusick /* status if there was anything active */ 61817214Smckusick /* when the fault occurred. This may */ 61917214Smckusick /* shoot an innocent bystander, but */ 62017214Smckusick /* it's better than letting an error */ 62117214Smckusick /* slip through. */ 62217214Smckusick 62317214Smckusick mtcreset(mtaddr); 62417214Smckusick if (bp != 0) { 62517214Smckusick bp->b_flags |= B_ERROR; 62617214Smckusick return (MBN_DONE); 62717214Smckusick } 62817214Smckusick } 62917214Smckusick } 6304736Swnj return (MBN_SKIP); 6314736Swnj } 6324736Swnj if (bp == 0) 6334736Swnj return (MBN_SKIP); 63417214Smckusick 6354736Swnj fc = (mtaddr->mtncs[unit] >> 8) & 0xff; 6364736Swnj sc->sc_resid = fc; 63717214Smckusick 63817214Smckusick /* Clear the "written" flag after any operation that changes */ 63917214Smckusick /* the position of the tape. */ 64017214Smckusick 64117214Smckusick if ( (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 64217214Smckusick || (bp->b_command != MT_SENSE) ) 64317214Smckusick sc->sc_flags &= ~H_WRITTEN; 64417214Smckusick 6454736Swnj switch (er & MTER_INTCODE) { 64617214Smckusick 64717214Smckusick case MTER_EOT: 64817214Smckusick sc->sc_flags |= H_EOT; 64917214Smckusick 65017214Smckusick /* fall into MTER_DONE */ 65117214Smckusick 6524736Swnj case MTER_DONE: 65317214Smckusick 65417214Smckusick /* If this is a command buffer, just update the status. */ 65517214Smckusick 6564736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 6574736Swnj done: 6584736Swnj if (bp->b_command == MT_SENSE) 6594736Swnj sc->sc_dsreg = MASKREG(mtaddr->mtds); 6604736Swnj return (MBN_DONE); 6614736Swnj } 66217214Smckusick 66317214Smckusick /* It's not a command buffer, must be a cooked I/O */ 66417214Smckusick /* skip operation (perhaps a shaky assumption, but it */ 66517214Smckusick /* wasn't my idea). */ 66617214Smckusick 6677380Ssam if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0) 6686186Ssam sc->sc_blkno -= MIN(0377, -fc); 6694736Swnj else 6706186Ssam sc->sc_blkno += MIN(0377, fc); 6714736Swnj return (MBN_RETRY); 6724736Swnj 67317214Smckusick case MTER_ONLINE: /* ddj -- shouldn't happen but did */ 6744736Swnj case MTER_RWDING: 6754736Swnj return (MBN_SKIP); /* ignore "rewind started" interrupt */ 6764736Swnj 6774736Swnj case MTER_NOTCAP: 67818324Sralph tprintf(sc->sc_ttyp, "mu%d: blank tape\n", MUUNIT(bp->b_dev)); 67917214Smckusick bp->b_flags |= B_ERROR; 68017214Smckusick return (MBN_DONE); 6814736Swnj 6824736Swnj case MTER_TM: 6834736Swnj case MTER_LEOT: 68417214Smckusick 68517214Smckusick /* For an ioctl skip operation, count a tape mark as */ 68617214Smckusick /* a record. If there's anything left to do, update */ 68717214Smckusick /* the repeat count and re-start the command. */ 68817214Smckusick 68917214Smckusick if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 69017214Smckusick if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0) 69117214Smckusick return (MBN_DONE); 69217214Smckusick else 69317214Smckusick return (MBN_RETRY); 69417214Smckusick 69517214Smckusick /* Cooked I/O again. Just update the books and wait */ 69617214Smckusick /* for someone else to return end of file or complain */ 69717214Smckusick /* about a bad seek. */ 69817214Smckusick 69917214Smckusick } else if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 70017214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1; 7014736Swnj sc->sc_blkno = sc->sc_nxrec; 7024736Swnj } else { 70317214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc; 70417214Smckusick sc->sc_blkno = sc->sc_nxrec + 1; 7054736Swnj } 7064736Swnj return (MBN_RETRY); 7074736Swnj 7084736Swnj case MTER_FPT: 70918324Sralph tprintf(sc->sc_ttyp, "mu%d: no write ring\n", MUUNIT(bp->b_dev)); 7104736Swnj bp->b_flags |= B_ERROR; 7114736Swnj return (MBN_DONE); 7124736Swnj 7134736Swnj case MTER_OFFLINE: 71417214Smckusick 71517214Smckusick /* If `off line' was intentional, don't complain. */ 71617214Smckusick 71717214Smckusick if ( (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 71817214Smckusick && (bp->b_command == MT_UNLOAD) ) 71917214Smckusick return(MBN_DONE); 7204736Swnj if (sc->sc_openf > 0) { 7214736Swnj sc->sc_openf = -1; 72218324Sralph tprintf(sc->sc_ttyp, "mu%d: offline\n", MUUNIT(bp->b_dev)); 7234736Swnj } 7244736Swnj bp->b_flags |= B_ERROR; 7254736Swnj return (MBN_DONE); 7264736Swnj 72717214Smckusick case MTER_NOTAVL: 72817214Smckusick if (sc->sc_openf > 0) { 72917214Smckusick sc->sc_openf = -1; 73018324Sralph tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", MUUNIT(bp->b_dev)); 73117214Smckusick } 73217214Smckusick bp->b_flags |= B_ERROR; 73317214Smckusick return (MBN_DONE); 73417214Smckusick 7354736Swnj case MTER_BOT: 7364736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 7374736Swnj goto done; 7384736Swnj 73917214Smckusick /* fall through */ 74017214Smckusick 7414736Swnj default: 74218324Sralph tprintf(sc->sc_ttyp, "mu%d: hard error (non data transfer) rn=%d bn=%d er=%o (octal) ds=%b\n", 74317214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 74417214Smckusick er, MASKREG(sc->sc_dsreg), mtds_bits); 74517214Smckusick #ifdef MTLERRM 74617214Smckusick mtintfail(sc); 74717214Smckusick printf(" interrupt code = %o (octal) <%s>\n failure code = %o (octal) <%s>\n", 74817214Smckusick (er & MTER_INTCODE), sc->sc_mesg, 74917214Smckusick (er & MTER_FAILCODE) >> 10, sc->sc_fmesg); 75017214Smckusick #endif 75117214Smckusick if ( ((er & MTER_INTCODE) == MTER_TMFLTB) 75217214Smckusick || ((er & MTER_INTCODE) == MTER_MBFLT) ) { 75317214Smckusick mtcreset(mtaddr); /* reset the controller */ 75417214Smckusick } 7554736Swnj bp->b_flags |= B_ERROR; 7564736Swnj return (MBN_DONE); 7574736Swnj } 7584736Swnj /* NOTREACHED */ 7594736Swnj } 7604736Swnj 76117214Smckusick void mtcreset(mtaddr) 76217214Smckusick register struct mtdevice *mtaddr; 76317214Smckusick { 76417214Smckusick register int i; 76517214Smckusick 76617214Smckusick mtaddr->mtid = MTID_CLR; /* reset the TM78 */ 76717214Smckusick DELAY(200); 76817214Smckusick for (i = MTTIMEOUT; i > 0; i--) { 76917214Smckusick DELAY(50); /* don't nag */ 77017214Smckusick if ((mtaddr->mtid & MTID_RDY) != 0) 77117214Smckusick return; /* exit when ready */ 77217214Smckusick } 77317214Smckusick printf("mt: controller hung\n"); 77417214Smckusick } 77517214Smckusick 7767740Sroot mtread(dev, uio) 7774736Swnj dev_t dev; 7787740Sroot struct uio *uio; 7794736Swnj { 7808158Sroot int errno; 7814736Swnj 7828158Sroot errno = mtphys(dev, uio); 7838158Sroot if (errno) 7848158Sroot return (errno); 7858158Sroot return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_READ, minphys, uio)); 7864736Swnj } 7874736Swnj 78817214Smckusick 7897833Sroot mtwrite(dev, uio) 7907833Sroot dev_t dev; 7917833Sroot struct uio *uio; 7924736Swnj { 7938158Sroot int errno; 7944736Swnj 7958158Sroot errno = mtphys(dev, uio); 7968158Sroot if (errno) 7978158Sroot return (errno); 7988158Sroot return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_WRITE, minphys, uio)); 7994736Swnj } 8004736Swnj 8017740Sroot mtphys(dev, uio) 8024736Swnj dev_t dev; 8037740Sroot struct uio *uio; 8044736Swnj { 8054736Swnj register int mtunit; 80617214Smckusick struct mba_device *mi; 80717214Smckusick register int bsize = uio->uio_iov->iov_len; 8084736Swnj 8094736Swnj mtunit = MTUNIT(dev); 81017214Smckusick if ( (mtunit >= NMT) 81117214Smckusick || ((mi = mtinfo[mtunit]) == 0) 81217214Smckusick || (mi->mi_alive == 0) ) 8137740Sroot return (ENXIO); 81417214Smckusick if ( (bsize > 0xffff) /* controller limit */ 81517214Smckusick || (bsize <= 0) ) /* ambiguous */ 81617214Smckusick return (EINVAL); 8177740Sroot return (0); 8184736Swnj } 8194736Swnj 8204736Swnj /*ARGSUSED*/ 8217637Ssam mtioctl(dev, cmd, data, flag) 8224736Swnj dev_t dev; 8234736Swnj int cmd; 8247637Ssam caddr_t data; 8254736Swnj int flag; 8264736Swnj { 8274736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 8284736Swnj register struct buf *bp = &cmtbuf[MTUNIT(dev)]; 82917214Smckusick register struct mtop *mtop; 83017214Smckusick register struct mtget *mtget; 83117214Smckusick int callcount, fcount; 83217214Smckusick int op; 83317214Smckusick 83417214Smckusick /* We depend on the values and order of the MT codes here. */ 83517214Smckusick 8364736Swnj static mtops[] = 8374736Swnj {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE}; 8384736Swnj 8394736Swnj switch (cmd) { 8407637Ssam 84117214Smckusick /* tape operation */ 84217214Smckusick 84317214Smckusick case MTIOCTOP: 8448606Sroot mtop = (struct mtop *)data; 8458606Sroot switch (mtop->mt_op) { 8467637Ssam 8474736Swnj case MTWEOF: 8487637Ssam callcount = mtop->mt_count; 8494736Swnj fcount = 1; 8504736Swnj break; 8517637Ssam 8524736Swnj case MTFSF: case MTBSF: 8537637Ssam callcount = mtop->mt_count; 8544736Swnj fcount = 1; 8554736Swnj break; 8567637Ssam 8574736Swnj case MTFSR: case MTBSR: 8584736Swnj callcount = 1; 8597637Ssam fcount = mtop->mt_count; 8604736Swnj break; 8617637Ssam 8624736Swnj case MTREW: case MTOFFL: 8634736Swnj callcount = 1; 8644736Swnj fcount = 1; 8654736Swnj break; 8667637Ssam 8674736Swnj default: 8688581Sroot return (ENXIO); 8694736Swnj } 87017214Smckusick if ((callcount <= 0) || (fcount <= 0)) 8718581Sroot return (EINVAL); 8727637Ssam op = mtops[mtop->mt_op]; 8734736Swnj if (op == MT_WTM) 8744736Swnj op |= sc->sc_dens; 8754736Swnj while (--callcount >= 0) { 87617214Smckusick register int n, fc = fcount; 8774736Swnj 8784736Swnj do { 87917214Smckusick n = MIN(fc, 0xff); 8804736Swnj mtcommand(dev, op, n); 88117214Smckusick n -= sc->sc_resid; 88217214Smckusick fc -= n; 88317214Smckusick switch (mtop->mt_op) { 88417214Smckusick 88517214Smckusick case MTWEOF: 88617214Smckusick sc->sc_blkno += (daddr_t)n; 88717214Smckusick sc->sc_nxrec = sc->sc_blkno - 1; 88817214Smckusick break; 88917214Smckusick 89017214Smckusick case MTOFFL: 89117214Smckusick case MTREW: 89217214Smckusick case MTFSF: 89317214Smckusick sc->sc_blkno = (daddr_t)0; 89417214Smckusick sc->sc_nxrec = (daddr_t)INF; 89517214Smckusick break; 89617214Smckusick 89717214Smckusick case MTBSF: 89817214Smckusick if (sc->sc_resid) { 89917214Smckusick sc->sc_blkno = (daddr_t)0; 90017214Smckusick sc->sc_nxrec = (daddr_t)INF; 90117214Smckusick } else { 90217214Smckusick sc->sc_blkno = (daddr_t)(-1); 90317214Smckusick sc->sc_nxrec = (daddr_t)(-1); 90417214Smckusick } 90517214Smckusick break; 90617214Smckusick 90717214Smckusick case MTFSR: 90817214Smckusick sc->sc_blkno += (daddr_t)n; 90917214Smckusick break; 91017214Smckusick 91117214Smckusick case MTBSR: 91217214Smckusick sc->sc_blkno -= (daddr_t)n; 91317214Smckusick break; 91417214Smckusick } 91517214Smckusick if (sc->sc_resid) 91617214Smckusick break; 91717214Smckusick } while (fc); 91817214Smckusick if (fc) { 91917214Smckusick sc->sc_resid = callcount + fc; 92017214Smckusick if ( (mtop->mt_op == MTFSR) 92117214Smckusick || (mtop->mt_op == MTBSR) ) 92217214Smckusick return (EIO); 92317214Smckusick else 92417214Smckusick break; 92517214Smckusick } 92617214Smckusick if (bp->b_flags & B_ERROR) 9274736Swnj break; 9284736Swnj } 9298712Sroot return (geterror(bp)); 9307637Ssam 93117214Smckusick /* tape status */ 93217214Smckusick 9334736Swnj case MTIOCGET: 9347637Ssam mtget = (struct mtget *)data; 9357637Ssam mtget->mt_erreg = sc->sc_erreg; 9367637Ssam mtget->mt_resid = sc->sc_resid; 9374736Swnj mtcommand(dev, MT_SENSE, 1); /* update drive status */ 9387637Ssam mtget->mt_dsreg = sc->sc_dsreg; 9397637Ssam mtget->mt_type = MT_ISMT; 9408581Sroot break; 9417637Ssam 94217214Smckusick /* ignore EOT condition */ 94317214Smckusick 94417214Smckusick case MTIOCIEOT: 94517214Smckusick sc->sc_flags |= H_IEOT; 94617214Smckusick break; 94717214Smckusick 94817214Smckusick /* enable EOT condition */ 94917214Smckusick 95017214Smckusick case MTIOCEEOT: 95117214Smckusick sc->sc_flags &= ~H_IEOT; 95217214Smckusick break; 95317214Smckusick 9544736Swnj default: 9558581Sroot return (ENXIO); 9564736Swnj } 9578581Sroot return (0); 9584736Swnj } 9594736Swnj 9604736Swnj #define DBSIZE 20 9614736Swnj 9624736Swnj mtdump() 9634736Swnj { 9644736Swnj register struct mba_device *mi; 9654736Swnj register struct mba_regs *mp; 9664736Swnj int blk, num; 9674736Swnj int start; 9684736Swnj 9694736Swnj start = 0; 9704736Swnj num = maxfree; 9714736Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 9724736Swnj if (mtinfo[0] == 0) 9734736Swnj return (ENXIO); 9744736Swnj mi = phys(mtinfo[0], struct mba_device *); 9754736Swnj mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 9764736Swnj mp->mba_cr = MBCR_IE; 9776186Ssam #if lint 9788606Sroot blk = 0; num = blk; start = num; blk = start; 9796186Ssam return (0); 9806186Ssam #endif 9816186Ssam #ifdef notyet 9824736Swnj mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive]; 9834736Swnj mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI; 9844736Swnj mtaddr->mtcs1 = MT_DCLR|MT_GO; 9854736Swnj while (num > 0) { 9864736Swnj blk = num > DBSIZE ? DBSIZE : num; 9874736Swnj mtdwrite(start, blk, mtaddr, mp); 9884736Swnj start += blk; 9894736Swnj num -= blk; 9904736Swnj } 9914736Swnj mteof(mtaddr); 9924736Swnj mteof(mtaddr); 9934736Swnj mtwait(mtaddr); 9944736Swnj if (mtaddr->mtds&MTDS_ERR) 9954736Swnj return (EIO); 9964736Swnj mtaddr->mtcs1 = MT_REW|MT_GO; 9974736Swnj return (0); 9984736Swnj } 9994736Swnj 10004736Swnj mtdwrite(dbuf, num, mtaddr, mp) 10014736Swnj register dbuf, num; 10024736Swnj register struct mtdevice *mtaddr; 10034736Swnj struct mba_regs *mp; 10044736Swnj { 10054736Swnj register struct pte *io; 10064736Swnj register int i; 10074736Swnj 10084736Swnj mtwait(mtaddr); 10094736Swnj io = mp->mba_map; 10104736Swnj for (i = 0; i < num; i++) 10114736Swnj *(int *)io++ = dbuf++ | PG_V; 10124736Swnj mtaddr->mtfc = -(num*NBPG); 10134736Swnj mp->mba_sr = -1; 10144736Swnj mp->mba_bcr = -(num*NBPG); 10154736Swnj mp->mba_var = 0; 10164736Swnj mtaddr->mtcs1 = MT_WCOM|MT_GO; 10174736Swnj } 10184736Swnj 10194736Swnj mtwait(mtaddr) 10204736Swnj struct mtdevice *mtaddr; 10214736Swnj { 10224736Swnj register s; 10234736Swnj 10244736Swnj do 10254736Swnj s = mtaddr->mtds; 10264736Swnj while ((s & MTDS_DRY) == 0); 10274736Swnj } 10284736Swnj 10294736Swnj mteof(mtaddr) 10304736Swnj struct mtdevice *mtaddr; 10314736Swnj { 10324736Swnj 10334736Swnj mtwait(mtaddr); 10344736Swnj mtaddr->mtcs1 = MT_WEOF|MT_GO; 10354736Swnj #endif notyet 10364736Swnj } 103717214Smckusick 103817214Smckusick #ifdef MTLERRM 103917214Smckusick mtintfail(sc) 104017214Smckusick register struct mu_softc *sc; 104117214Smckusick { 104217214Smckusick switch (sc->sc_erreg & MTER_INTCODE) { 104317214Smckusick 104417214Smckusick /* unexpected BOT detected */ 104517214Smckusick 104617214Smckusick case MTER_BOT: 104717214Smckusick sc->sc_mesg = "unexpected BOT"; 104817214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 104917214Smckusick case 01: 105017214Smckusick sc->sc_fmesg = "tape was at BOT"; 105117214Smckusick break; 105217214Smckusick case 02: 105317214Smckusick sc->sc_fmesg = "BOT seen after tape started"; 105417214Smckusick break; 105517214Smckusick case 03: 105617214Smckusick sc->sc_fmesg = "ARA ID detected"; 105717214Smckusick break; 105817214Smckusick default: 105917214Smckusick sc->sc_fmesg = "unclassified failure code"; 106017214Smckusick } 106117214Smckusick break; 106217214Smckusick 106317214Smckusick /* unexpected LEOT detected */ 106417214Smckusick 106517214Smckusick case MTER_LEOT: 106617214Smckusick sc->sc_mesg = "unexpected LEOT"; 106717214Smckusick sc->sc_fmesg = ""; 106817214Smckusick break; 106917214Smckusick 107017214Smckusick /* rewinding */ 107117214Smckusick 107217214Smckusick case MTER_RWDING: 107317214Smckusick sc->sc_mesg = "tape rewinding"; 107417214Smckusick sc->sc_fmesg = ""; 107517214Smckusick break; 107617214Smckusick 107717214Smckusick /* not ready */ 107817214Smckusick 107917214Smckusick case MTER_NOTRDY: 108017214Smckusick sc->sc_mesg = "drive not ready"; 108117214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 108217214Smckusick case 01: 108317214Smckusick sc->sc_fmesg = "TU on-line but not ready"; 108417214Smckusick break; 108517214Smckusick case 02: 108617214Smckusick sc->sc_fmesg = "fatal error has occurred"; 108717214Smckusick break; 108817214Smckusick case 03: 108917214Smckusick sc->sc_fmesg = "access allowed but not really"; 109017214Smckusick break; 109117214Smckusick default: 109217214Smckusick sc->sc_fmesg = "unclassified failure code"; 109317214Smckusick } 109417214Smckusick break; 109517214Smckusick 109617214Smckusick /* not available */ 109717214Smckusick 109817214Smckusick case MTER_NOTAVL: 109917214Smckusick sc->sc_mesg = "drive not available"; 110017214Smckusick sc->sc_fmesg = ""; 110117214Smckusick break; 110217214Smckusick 110317214Smckusick /* unit does not exist */ 110417214Smckusick 110517214Smckusick case MTER_NONEX: 110617214Smckusick sc->sc_mesg = "unit does not exist"; 110717214Smckusick sc->sc_fmesg = ""; 110817214Smckusick break; 110917214Smckusick 111017214Smckusick /* not capable */ 111117214Smckusick 111217214Smckusick case MTER_NOTCAP: 111317214Smckusick sc->sc_mesg = "not capable"; 111417214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 111517214Smckusick case 01: 111617214Smckusick sc->sc_fmesg = "no record found within 25 feet"; 111717214Smckusick break; 111817214Smckusick case 02: 111917214Smckusick sc->sc_fmesg = "ID burst neither PE nor GCR"; 112017214Smckusick break; 112117214Smckusick case 03: 112217214Smckusick sc->sc_fmesg = "ARA ID not found"; 112317214Smckusick break; 112417214Smckusick case 04: 112517214Smckusick sc->sc_fmesg = "no gap found after ID burst"; 112617214Smckusick break; 112717214Smckusick default: 112817214Smckusick sc->sc_fmesg = "unclassified failure code"; 112917214Smckusick } 113017214Smckusick break; 113117214Smckusick 113217214Smckusick /* long tape record */ 113317214Smckusick 113417214Smckusick case MTER_LONGREC: 113517214Smckusick sc->sc_mesg = "long record"; 113617214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 113717214Smckusick case 00: 113817214Smckusick sc->sc_fmesg = "extended sense data not found"; 113917214Smckusick break; 114017214Smckusick case 01: 114117214Smckusick sc->sc_fmesg = "extended sense data updated"; 114217214Smckusick break; 114317214Smckusick default: 114417214Smckusick sc->sc_fmesg = "unclassified failure code"; 114517214Smckusick } 114617214Smckusick break; 114717214Smckusick 114817214Smckusick /* unreadable */ 114917214Smckusick 115017214Smckusick case MTER_UNREAD: 115117214Smckusick sc->sc_mesg = "unreadable record"; 115217214Smckusick goto code22; 115317214Smckusick 115417214Smckusick /* error */ 115517214Smckusick 115617214Smckusick case MTER_ERROR: 115717214Smckusick sc->sc_mesg = "error"; 115817214Smckusick goto code22; 115917214Smckusick 116017214Smckusick /* EOT error */ 116117214Smckusick 116217214Smckusick case MTER_EOTERR: 116317214Smckusick sc->sc_mesg = "EOT error"; 116417214Smckusick goto code22; 116517214Smckusick 116617214Smckusick /* tape position lost */ 116717214Smckusick 116817214Smckusick case MTER_BADTAPE: 116917214Smckusick sc->sc_mesg = "bad tape"; 117017214Smckusick code22: 117117214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 117217214Smckusick case 01: 117317214Smckusick sc->sc_fmesg = "GCR write error"; 117417214Smckusick break; 117517214Smckusick case 02: 117617214Smckusick sc->sc_fmesg = "GCR read error"; 117717214Smckusick break; 117817214Smckusick case 03: 117917214Smckusick sc->sc_fmesg = "PE read error"; 118017214Smckusick break; 118117214Smckusick case 04: 118217214Smckusick sc->sc_fmesg = "PE write error"; 118317214Smckusick break; 118417214Smckusick case 05: 118517214Smckusick sc->sc_fmesg = "at least 1 bit set in ECCSTA"; 118617214Smckusick break; 118717214Smckusick case 06: 118817214Smckusick sc->sc_fmesg = "PE write error"; 118917214Smckusick break; 119017214Smckusick case 07: 119117214Smckusick sc->sc_fmesg = "GCR write error"; 119217214Smckusick break; 119317214Smckusick case 010: 119417214Smckusick sc->sc_fmesg = "RSTAT contains bad code"; 119517214Smckusick break; 119617214Smckusick case 011: 119717214Smckusick sc->sc_fmesg = "PE write error"; 119817214Smckusick break; 119917214Smckusick case 012: 120017214Smckusick sc->sc_fmesg = "MASSBUS parity error"; 120117214Smckusick break; 120217214Smckusick case 013: 120317214Smckusick sc->sc_fmesg = "invalid data transferred"; 120417214Smckusick break; 120517214Smckusick default: 120617214Smckusick sc->sc_fmesg = "unclassified failure code"; 120717214Smckusick } 120817214Smckusick break; 120917214Smckusick 121017214Smckusick /* TM fault A */ 121117214Smckusick 121217214Smckusick case MTER_TMFLTA: 121317214Smckusick sc->sc_mesg = "TM fault A"; 121417214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 121517214Smckusick case 01: 121617214Smckusick sc->sc_fmesg = "illegal command code"; 121717214Smckusick break; 121817214Smckusick case 02: 121917214Smckusick sc->sc_fmesg = "DT command issued when NDT command active"; 122017214Smckusick break; 122117214Smckusick case 03: 122217214Smckusick sc->sc_fmesg = "WMC error"; 122317214Smckusick break; 122417214Smckusick case 04: 122517214Smckusick sc->sc_fmesg = "RUN not received from MASSBUS controller"; 122617214Smckusick break; 122717214Smckusick case 05: 122817214Smckusick sc->sc_fmesg = "mismatch in command read - function routine"; 122917214Smckusick break; 123017214Smckusick case 06: 123117214Smckusick sc->sc_fmesg = "ECC ROM parity error"; 123217214Smckusick break; 123317214Smckusick case 07: 123417214Smckusick sc->sc_fmesg = "XMC ROM parity error"; 123517214Smckusick break; 123617214Smckusick case 010: 123717214Smckusick sc->sc_fmesg = "mismatch in command read - ID burst command"; 123817214Smckusick break; 123917214Smckusick case 011: 124017214Smckusick sc->sc_fmesg = "mismatch in command read - verify ARA burst command"; 124117214Smckusick break; 124217214Smckusick case 012: 124317214Smckusick sc->sc_fmesg = "mismatch in command read - verify ARA ID command"; 124417214Smckusick break; 124517214Smckusick case 013: 124617214Smckusick sc->sc_fmesg = "mismatch in command read - verify gap command"; 124717214Smckusick break; 124817214Smckusick case 014: 124917214Smckusick sc->sc_fmesg = "mismatch in command read - read id burst command"; 125017214Smckusick break; 125117214Smckusick case 015: 125217214Smckusick sc->sc_fmesg = "mismatch in command read - verify ARA ID command"; 125317214Smckusick break; 125417214Smckusick case 016: 125517214Smckusick sc->sc_fmesg = "mismatch in command read - verify gap command"; 125617214Smckusick break; 125717214Smckusick case 017: 125817214Smckusick sc->sc_fmesg = "mismatch in command read - find gap command"; 125917214Smckusick break; 126017214Smckusick case 020: 126117214Smckusick sc->sc_fmesg = "WMC LEFT failed to set"; 126217214Smckusick break; 126317214Smckusick case 021: 126417214Smckusick sc->sc_fmesg = "XL PE set in INTSTA register"; 126517214Smckusick break; 126617214Smckusick case 022: 126717214Smckusick sc->sc_fmesg = "XMC DONE did not set"; 126817214Smckusick break; 126917214Smckusick case 023: 127017214Smckusick sc->sc_fmesg = "WMC ROM PE or RD PE set in WMCERR register"; 127117214Smckusick break; 127217214Smckusick default: 127317214Smckusick sc->sc_fmesg = "unclassified failure code"; 127417214Smckusick } 127517214Smckusick break; 127617214Smckusick 127717214Smckusick /* TU fault A */ 127817214Smckusick 127917214Smckusick case MTER_TUFLTA: 128017214Smckusick sc->sc_mesg = "TU fault A"; 128117214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 128217214Smckusick case 01: 128317214Smckusick sc->sc_fmesg = "TU status parity error"; 128417214Smckusick break; 128517214Smckusick case 02: 128617214Smckusick sc->sc_fmesg = "TU command parity error"; 128717214Smckusick break; 128817214Smckusick case 03: 128917214Smckusick sc->sc_fmesg = "rewinding tape went offline"; 129017214Smckusick break; 129117214Smckusick case 04: 129217214Smckusick sc->sc_fmesg = "tape went not ready during DSE"; 129317214Smckusick break; 129417214Smckusick case 05: 129517214Smckusick sc->sc_fmesg = "TU CMD status changed during DSE"; 129617214Smckusick break; 129717214Smckusick case 06: 129817214Smckusick sc->sc_fmesg = "TU never came up to speed"; 129917214Smckusick break; 130017214Smckusick case 07: 130117214Smckusick sc->sc_fmesg = "TU velocity changed"; 130217214Smckusick break; 130317214Smckusick case 010: 130417214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion"; 130517214Smckusick break; 130617214Smckusick case 011: 130717214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set drive density"; 130817214Smckusick break; 130917214Smckusick case 012: 131017214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion to write BOT ID"; 131117214Smckusick break; 131217214Smckusick case 013: 131317214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID"; 131417214Smckusick break; 131517214Smckusick case 014: 131617214Smckusick sc->sc_fmesg = "failed to write density ID burst"; 131717214Smckusick break; 131817214Smckusick case 015: 131917214Smckusick sc->sc_fmesg = "failed to write ARA burst"; 132017214Smckusick break; 132117214Smckusick case 016: 132217214Smckusick sc->sc_fmesg = "failed to write ARA ID"; 132317214Smckusick break; 132417214Smckusick case 017: 132517214Smckusick sc->sc_fmesg = "ARA error bit set in MTA status B register"; 132617214Smckusick break; 132717214Smckusick case 021: 132817214Smckusick sc->sc_fmesg = "could not find a gap after ID code was written correctly"; 132917214Smckusick break; 133017214Smckusick case 022: 133117214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion to read ID burst"; 133217214Smckusick break; 133317214Smckusick case 023: 133417214Smckusick sc->sc_fmesg = "timeout looking for BOT after detecting ARA ID burst"; 133517214Smckusick break; 133617214Smckusick case 024: 133717214Smckusick sc->sc_fmesg = "failed to write tape mark"; 133817214Smckusick break; 133917214Smckusick case 025: 134017214Smckusick sc->sc_fmesg = "tape never came up to speed while trying to reposition for retry of writing tape mark"; 134117214Smckusick break; 134217214Smckusick case 026: 134317214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion in erase gap routine"; 134417214Smckusick break; 134517214Smckusick case 027: 134617214Smckusick sc->sc_fmesg = "could not detect a gap in in erase gap routine"; 134717214Smckusick break; 134817214Smckusick case 030: 134917214Smckusick sc->sc_fmesg = "could not detect a gap after writing record"; 135017214Smckusick break; 135117214Smckusick case 031: 135217214Smckusick sc->sc_fmesg = "read path terminated before entire record was written"; 135317214Smckusick break; 135417214Smckusick case 032: 135517214Smckusick sc->sc_fmesg = "could not find a gap after writing record and read path terminated early"; 135617214Smckusick break; 135717214Smckusick case 033: 135817214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to backup for retry of write tape mark"; 135917214Smckusick break; 136017214Smckusick case 034: 136117214Smckusick sc->sc_fmesg = "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark"; 136217214Smckusick break; 136317214Smckusick case 035: 136417214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to backup to retry a load of BOT ID"; 136517214Smckusick break; 136617214Smckusick case 036: 136717214Smckusick sc->sc_fmesg = "timeout looking for BOT after failing to write BOT ID"; 136817214Smckusick break; 136917214Smckusick case 037: 137017214Smckusick sc->sc_fmesg = "TU velocity changed while writing PE gap before starting to write record"; 137117214Smckusick break; 137217214Smckusick case 040: 137317214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst"; 137417214Smckusick break; 137517214Smckusick case 041: 137617214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set GCR tape density after writing Density ID"; 137717214Smckusick break; 137817214Smckusick case 042: 137917214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set PE tape density at start of read from BOT"; 138017214Smckusick break; 138117214Smckusick case 043: 138217214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst"; 138317214Smckusick break; 138417214Smckusick default: 138517214Smckusick sc->sc_fmesg = "unclassified failure code"; 138617214Smckusick } 138717214Smckusick break; 138817214Smckusick 138917214Smckusick /* TM fault B */ 139017214Smckusick 139117214Smckusick case MTER_TMFLTB: 139217214Smckusick sc->sc_mesg = "TM fault B"; 139317214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 139417214Smckusick case 00: 139517214Smckusick sc->sc_fmesg = "RST0 interrupt occurred with TM RDY set"; 139617214Smckusick break; 139717214Smckusick case 01: 139817214Smckusick sc->sc_fmesg = "power failed to interrupt"; 139917214Smckusick break; 140017214Smckusick case 02: 140117214Smckusick sc->sc_fmesg = "unknown interrupt on channel 5.5"; 140217214Smckusick break; 140317214Smckusick case 03: 140417214Smckusick sc->sc_fmesg = "unknown interrupt on channel 6.5"; 140517214Smckusick break; 140617214Smckusick case 04: 140717214Smckusick sc->sc_fmesg = "unknown interrupt on channel 7"; 140817214Smckusick break; 140917214Smckusick case 05: 141017214Smckusick sc->sc_fmesg = "unknown interrupt on channel 7.5"; 141117214Smckusick break; 141217214Smckusick case 06: 141317214Smckusick sc->sc_fmesg = "CAS contention retry count expired"; 141417214Smckusick break; 141517214Smckusick case 07: 141617214Smckusick sc->sc_fmesg = "CAS contention error not retryable"; 141717214Smckusick break; 141817214Smckusick case 010: 141917214Smckusick sc->sc_fmesg = "queue error, could not find queue entry"; 142017214Smckusick break; 142117214Smckusick case 011: 142217214Smckusick sc->sc_fmesg = "queue entry already full"; 142317214Smckusick break; 142417214Smckusick case 012: 142517214Smckusick sc->sc_fmesg = "8085 ROM parity error"; 142617214Smckusick break; 142717214Smckusick case 013: 142817214Smckusick case 014: 142917214Smckusick case 015: 143017214Smckusick case 016: 143117214Smckusick case 017: 143217214Smckusick case 020: 143317214Smckusick case 021: 143417214Smckusick case 022: 143517214Smckusick case 023: 143617214Smckusick case 024: 143717214Smckusick case 025: 143817214Smckusick case 026: 143917214Smckusick case 027: 144017214Smckusick case 030: 144117214Smckusick case 031: 144217214Smckusick case 032: 144317214Smckusick case 033: 144417214Smckusick case 034: 144517214Smckusick case 035: 144617214Smckusick case 036: 144717214Smckusick case 037: 144817214Smckusick case 040: 144917214Smckusick case 041: 145017214Smckusick case 042: 145117214Smckusick case 043: 145217214Smckusick case 044: 145317214Smckusick case 045: 145417214Smckusick case 046: 145517214Smckusick case 047: 145617214Smckusick case 050: 145717214Smckusick case 051: 145817214Smckusick case 052: 145917214Smckusick case 053: 146017214Smckusick case 054: 146117214Smckusick case 055: 146217214Smckusick case 056: 146317214Smckusick case 057: 146417214Smckusick sc->sc_fmesg = "inline test failed"; 146517214Smckusick break; 146617214Smckusick default: 146717214Smckusick sc->sc_fmesg = "unclassified failure code"; 146817214Smckusick } 146917214Smckusick break; 147017214Smckusick 147117214Smckusick /* MASSBUS fault */ 147217214Smckusick 147317214Smckusick case MTER_MBFLT: 147417214Smckusick sc->sc_mesg = "MB fault"; 147517214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 147617214Smckusick case 01: 147717214Smckusick sc->sc_fmesg = "control bus parity error"; 147817214Smckusick break; 147917214Smckusick case 02: 148017214Smckusick sc->sc_fmesg = "illegal register referenced"; 148117214Smckusick break; 148217214Smckusick default: 148317214Smckusick sc->sc_fmesg = "unclassified failure code"; 148417214Smckusick } 148517214Smckusick break; 148617214Smckusick 148717214Smckusick /* keypad entry error */ 148817214Smckusick 148917214Smckusick case MTER_KEYFAIL: 149017214Smckusick sc->sc_mesg = "keypad entry error"; 149117214Smckusick sc->sc_fmesg = ""; 149217214Smckusick break; 149317214Smckusick default: 149417214Smckusick sc->sc_mesg = "unclassified error"; 149517214Smckusick sc->sc_fmesg = ""; 149617214Smckusick break; 149717214Smckusick } 149817214Smckusick } 149917214Smckusick #endif MTLERRM 15004736Swnj #endif 1501