1*23315Smckusick /* 2*23315Smckusick * Copyright (c) 1982 Regents of the University of California. 3*23315Smckusick * All rights reserved. The Berkeley software License Agreement 4*23315Smckusick * specifies the terms and conditions for redistribution. 5*23315Smckusick * 6*23315Smckusick * @(#)mt.c 6.5 (Berkeley) 06/08/85 7*23315Smckusick */ 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 { 11317214Smckusick #ifdef lint 11417214Smckusick mtread(0); mtwrite(0); mtioctl(0, 0, 0, 0); 11517214Smckusick #endif 1164736Swnj } 1174736Swnj 1187431Skre mtslave(mi, ms, sn) 1194736Swnj struct mba_device *mi; 1204736Swnj struct mba_slave *ms; 1217431Skre int sn; 1224736Swnj { 1234736Swnj register struct mu_softc *sc = &mu_softc[ms->ms_unit]; 1244736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 12517214Smckusick int s = spl7(), rtn = 0, i; 1264736Swnj 12717214Smckusick /* Just in case the controller is ill, reset it. Then issue */ 12817214Smckusick /* a sense operation and wait about a second for it to respond. */ 12917214Smckusick 13017214Smckusick mtcreset(mtaddr); 1314736Swnj mtaddr->mtas = -1; 1327431Skre mtaddr->mtncs[sn] = MT_SENSE|MT_GO; 13317214Smckusick for (i = MTTIMEOUT; i> 0; i--) { 13417214Smckusick DELAY(50); 13517214Smckusick if (MASKREG(mtaddr->mtas) != 0) 13617214Smckusick break; 13717214Smckusick } 13817214Smckusick sc->sc_i_mtas = mtaddr->mtas; 13917214Smckusick sc->sc_i_mtner = mtaddr->mtner; 14017214Smckusick sc->sc_i_mtds = mtaddr->mtds; 14117214Smckusick 14217214Smckusick /* If no response, whimper. If wrong response, call it an */ 14317214Smckusick /* unsolicited interrupt and use mtndtint to log and correct. */ 14417214Smckusick /* Otherwise, note whether this slave exists. */ 14517214Smckusick 14617214Smckusick if (i <= 0) { 14717214Smckusick printf("mt: controller hung\n"); 14817214Smckusick } else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE) { 14917214Smckusick (void) mtndtint(mi); 15017214Smckusick } else if (mtaddr->mtds & MTDS_PRES) { 1514736Swnj sc->sc_mi = mi; 1527431Skre sc->sc_slave = sn; 1534736Swnj mutomt[ms->ms_unit] = mi->mi_unit; 1544736Swnj rtn = 1; 1554736Swnj } 15617214Smckusick 15717214Smckusick /* Cancel the interrupt, then wait a little while for it to go away. */ 15817214Smckusick 1594736Swnj mtaddr->mtas = mtaddr->mtas; 16017214Smckusick DELAY(10); 1614736Swnj splx(s); 1624736Swnj return (rtn); 1634736Swnj } 1644736Swnj 1654736Swnj mtopen(dev, flag) 1664736Swnj dev_t dev; 1674736Swnj int flag; 1684736Swnj { 1694736Swnj register int muunit; 1704736Swnj register struct mba_device *mi; 1714736Swnj register struct mu_softc *sc; 1724736Swnj 1734736Swnj muunit = MUUNIT(dev); 17417214Smckusick if ( (muunit >= NMU) 17517214Smckusick || ((mi = mtinfo[MTUNIT(dev)]) == 0) 17617214Smckusick || (mi->mi_alive == 0) ) 1778581Sroot return (ENXIO); 17817214Smckusick if ((sc = &mu_softc[muunit])->sc_openf) 17917214Smckusick return (EBUSY); 18017214Smckusick sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0; 1814736Swnj mtcommand(dev, MT_SENSE, 1); 1824736Swnj if ((sc->sc_dsreg & MTDS_ONL) == 0) { 1834736Swnj uprintf("mu%d: not online\n", muunit); 1848581Sroot return (EIO); 1854736Swnj } 18617214Smckusick if ((sc->sc_dsreg & MTDS_AVAIL) == 0) { 18717214Smckusick uprintf("mu%d: not online (port selector)\n", muunit); 18817214Smckusick return (EIO); 18917214Smckusick } 19017214Smckusick if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) { 1914736Swnj uprintf("mu%d: no write ring\n", muunit); 1928581Sroot return (EIO); 1934736Swnj } 19417214Smckusick if ( ((sc->sc_dsreg & MTDS_BOT) == 0) 19517214Smckusick && (flag & FWRITE) 19617214Smckusick && ( ( (sc->sc_dens == MT_GCR) 19717214Smckusick && (sc->sc_dsreg & MTDS_PE) ) 19817214Smckusick || ( (sc->sc_dens != MT_GCR) 19917214Smckusick && ((sc->sc_dsreg & MTDS_PE) == 0)))) { 2004736Swnj uprintf("mu%d: can't change density in mid-tape\n", muunit); 2018581Sroot return (EIO); 2024736Swnj } 2034736Swnj sc->sc_openf = 1; 2044736Swnj sc->sc_blkno = (daddr_t)0; 20517214Smckusick 20617214Smckusick /* Since cooked I/O may do a read-ahead before a write, trash */ 20717214Smckusick /* on a tape can make the first write fail. Suppress the first */ 20817214Smckusick /* read-ahead unless definitely doing read-write */ 20917214Smckusick 21017214Smckusick sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) 21117214Smckusick ? (daddr_t)0 21217214Smckusick : (daddr_t)INF; 2134736Swnj sc->sc_flags = 0; 21418324Sralph sc->sc_ttyp = u.u_ttyp; 2158581Sroot return (0); 2164736Swnj } 2174736Swnj 2184736Swnj mtclose(dev, flag) 2194736Swnj register dev_t dev; 22017214Smckusick register int flag; 2214736Swnj { 2224736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 2234736Swnj 22417214Smckusick if ( ((flag & (FREAD | FWRITE)) == FWRITE) 22517214Smckusick || ( (flag & FWRITE) 22617214Smckusick && (sc->sc_flags & H_WRITTEN) )) 2274736Swnj mtcommand(dev, MT_CLS|sc->sc_dens, 1); 22817214Smckusick if ((minor(dev) & H_NOREWIND) == 0) 2294736Swnj mtcommand(dev, MT_REW, 0); 2304736Swnj sc->sc_openf = 0; 2314736Swnj } 2324736Swnj 2334736Swnj mtcommand(dev, com, count) 2344736Swnj dev_t dev; 2354736Swnj int com, count; 2364736Swnj { 2374736Swnj register struct buf *bp; 2385437Sroot register int s; 2394736Swnj 2404736Swnj bp = &cmtbuf[MTUNIT(dev)]; 2415437Sroot s = spl5(); 24217214Smckusick while (bp->b_flags & B_BUSY) { 24317214Smckusick if((bp->b_repcnt == 0) && (bp->b_flags & B_DONE)) 2444736Swnj break; 2454736Swnj bp->b_flags |= B_WANTED; 2464736Swnj sleep((caddr_t)bp, PRIBIO); 2474736Swnj } 2484736Swnj bp->b_flags = B_BUSY|B_READ; 2495437Sroot splx(s); 2504736Swnj bp->b_dev = dev; 2514736Swnj bp->b_command = com; 2524736Swnj bp->b_repcnt = count; 2534736Swnj bp->b_blkno = 0; 25417214Smckusick bp->b_error = 0; 2554736Swnj mtstrategy(bp); 2564736Swnj if (count == 0) 2574736Swnj return; 2584736Swnj iowait(bp); 25917214Smckusick if (bp->b_flags & B_WANTED) 2604736Swnj wakeup((caddr_t)bp); 2614736Swnj bp->b_flags &= B_ERROR; 2624736Swnj } 2634736Swnj 2644736Swnj mtstrategy(bp) 2654736Swnj register struct buf *bp; 2664736Swnj { 2674736Swnj register struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)]; 2684736Swnj register struct buf *dp; 2695437Sroot register int s; 2704736Swnj 27117214Smckusick /* If this is a data transfer operation, set the resid to a */ 27217214Smckusick /* default value (EOF) to simplify getting it right during */ 27317214Smckusick /* error recovery or bail out. */ 27417214Smckusick 27517214Smckusick if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 27617214Smckusick bp->b_resid = bp->b_bcount; 27717214Smckusick 27817214Smckusick /* Link this request onto the end of the queue for this */ 27917214Smckusick /* controller, then start I/O if not already active. */ 28017214Smckusick 2814736Swnj bp->av_forw = NULL; 2824736Swnj dp = &mi->mi_tab; 2835437Sroot s = spl5(); 2844736Swnj if (dp->b_actf == NULL) 2854736Swnj dp->b_actf = bp; 2864736Swnj else 2874736Swnj dp->b_actl->av_forw = bp; 2884736Swnj dp->b_actl = bp; 2894736Swnj if (dp->b_active == 0) 2904736Swnj mbustart(mi); 2915437Sroot splx(s); 2924736Swnj } 2934736Swnj 2944736Swnj mtustart(mi) 2954736Swnj register struct mba_device *mi; 2964736Swnj { 29717214Smckusick register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 2984736Swnj register struct buf *bp = mi->mi_tab.b_actf; 2994736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 3004736Swnj daddr_t blkno; 3014736Swnj 3024736Swnj if (sc->sc_openf < 0) { 3034736Swnj bp->b_flags |= B_ERROR; 3044736Swnj return (MBU_NEXT); 3054736Swnj } 3064736Swnj if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) { 30717214Smckusick 30817214Smckusick /* Signal "no space" if out of tape unless suppressed */ 30917214Smckusick /* by MTIOCIEOT. */ 31017214Smckusick 31117214Smckusick if ( ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT) 31217214Smckusick && ((bp->b_flags & B_READ) == 0) ) { 3134736Swnj bp->b_flags |= B_ERROR; 31417214Smckusick bp->b_error = ENOSPC; 3154736Swnj return (MBU_NEXT); 3164736Swnj } 31717214Smckusick 31817214Smckusick /* special case tests for cooked mode */ 31917214Smckusick 32017214Smckusick if (bp != &rmtbuf[MTUNIT(bp->b_dev)]) { 32117214Smckusick 32217214Smckusick /* seek beyond end of file */ 32317214Smckusick 32417214Smckusick if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 32517214Smckusick bp->b_flags |= B_ERROR; 32617214Smckusick bp->b_error = ENXIO; 32717214Smckusick return (MBU_NEXT); 32817214Smckusick } 32917214Smckusick 33017214Smckusick /* This should be end of file, but the buffer */ 33117214Smckusick /* system wants a one-block look-ahead. Humor it. */ 33217214Smckusick 33317214Smckusick if ( (bdbtofsb(bp->b_blkno) == sc->sc_nxrec) 33417214Smckusick && (bp->b_flags & B_READ) ) { 33517214Smckusick clrbuf(bp); 33617214Smckusick return (MBU_NEXT); 33717214Smckusick } 33817214Smckusick 33917214Smckusick /* If writing, mark the next block invalid. */ 34017214Smckusick 34117214Smckusick if ((bp->b_flags & B_READ) == 0) 34217214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 3434736Swnj } 3444736Swnj } else { 34517214Smckusick 34617214Smckusick /* It's a command, do it now. */ 34717214Smckusick 3484736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3494736Swnj (bp->b_repcnt<<8)|bp->b_command|MT_GO; 3504736Swnj return (MBU_STARTED); 3514736Swnj } 35217214Smckusick 35317214Smckusick /* If raw I/O, or if the tape is positioned correctly for */ 35417214Smckusick /* cooked I/O, set the byte count, unit number and repeat count */ 35517214Smckusick /* then tell the MASSBUS to proceed. Note that a negative */ 35617214Smckusick /* bcount tells mbstart to map the buffer for "read backwards". */ 35717214Smckusick 35817214Smckusick if ( (bp == &rmtbuf[MTUNIT(bp->b_dev)]) 35917214Smckusick || ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) ) { 3604736Swnj if (mi->mi_tab.b_errcnt == 2) { 36117214Smckusick mtaddr->mtbc = -(bp->b_bcount); 3624736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 3634736Swnj } else { 3644736Swnj mtaddr->mtbc = bp->b_bcount; 3654736Swnj mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev); 3664736Swnj } 3674736Swnj return (MBU_DODATA); 3684736Swnj } 36917214Smckusick 37017214Smckusick /* Issue skip operations to position the next block for cooked I/O. */ 37117214Smckusick 3727380Ssam if (blkno < bdbtofsb(bp->b_blkno)) 3734736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3747380Ssam (min((unsigned)(bdbtofsb(bp->b_blkno) - blkno), 0377) << 8) | 3756186Ssam MT_SFORW|MT_GO; 3764736Swnj else 3774736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3787380Ssam (min((unsigned)(blkno - bdbtofsb(bp->b_blkno)), 0377) << 8) | 3796186Ssam MT_SREV|MT_GO; 3804736Swnj return (MBU_STARTED); 3814736Swnj } 3824736Swnj 3834736Swnj mtstart(mi) 3844736Swnj register struct mba_device *mi; 3854736Swnj { 3864736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3874736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 3884736Swnj 3894736Swnj if (bp->b_flags & B_READ) 3904736Swnj if (mi->mi_tab.b_errcnt == 2) 3914736Swnj return(MT_READREV|MT_GO); 3924736Swnj else 3934736Swnj return(MT_READ|MT_GO); 3944736Swnj else 3954736Swnj return(MT_WRITE|sc->sc_dens|MT_GO); 3964736Swnj } 3974736Swnj 3984736Swnj mtdtint(mi, mbsr) 3994736Swnj register struct mba_device *mi; 4004736Swnj int mbsr; 4014736Swnj { 4024736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 4034736Swnj register struct buf *bp = mi->mi_tab.b_actf; 4044736Swnj register struct mu_softc *sc; 40517214Smckusick register int er; 4064736Swnj 40717214Smckusick /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */ 40817214Smckusick 40917214Smckusick if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) { 4104736Swnj printf("mt: wrong unit!\n"); 4114736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 4124736Swnj } 41317214Smckusick 41417214Smckusick er = MASKREG(mtaddr->mter); 4154736Swnj sc = &mu_softc[MUUNIT(bp->b_dev)]; 41617214Smckusick sc->sc_erreg = er; 41717214Smckusick if (bp->b_flags & B_READ) 41817214Smckusick sc->sc_flags &= ~H_WRITTEN; 41917214Smckusick else 4204736Swnj sc->sc_flags |= H_WRITTEN; 42117214Smckusick switch (er & MTER_INTCODE) { 42217214Smckusick 42317214Smckusick case MTER_EOT: 42417214Smckusick sc->sc_flags |= H_EOT; 42517214Smckusick 42617214Smckusick /* fall into MTER_DONE */ 42717214Smckusick 4284736Swnj case MTER_DONE: 42917214Smckusick sc->sc_blkno++; 43017214Smckusick if (mi->mi_tab.b_errcnt == 2) { 43117214Smckusick bp->b_bcount = bp->b_resid; 43217214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 43317214Smckusick if ( (bp->b_resid > 0) 43417214Smckusick && (bp != &rmtbuf[MTUNIT(bp->b_dev)]) ) 43517214Smckusick bp->b_flags |= B_ERROR; 43617214Smckusick } else { 43717214Smckusick bp->b_resid = 0; 43817214Smckusick } 43917214Smckusick break; 44017214Smckusick 44117214Smckusick case MTER_SHRTREC: 44217214Smckusick sc->sc_blkno++; 44317214Smckusick bp->b_bcount = bp->b_resid; 44417214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 44517214Smckusick if (bp != &rmtbuf[MTUNIT(bp->b_dev)]) 44617214Smckusick bp->b_flags |= B_ERROR; 44717214Smckusick break; 44817214Smckusick 44917214Smckusick case MTER_RETRY: 45017214Smckusick 45117214Smckusick /* Simple re-try. Since resid is always a copy of the */ 45217214Smckusick /* original byte count, use it to restore the count. */ 45317214Smckusick 45417214Smckusick mi->mi_tab.b_errcnt = 1; 45517214Smckusick bp->b_bcount = bp->b_resid; 45617214Smckusick return(MBD_RETRY); 45717214Smckusick 45817214Smckusick case MTER_RDOPP: 45917214Smckusick 46017214Smckusick /* The controller just decided to read it backwards. */ 46117214Smckusick /* If the controller returns a byte count of zero, */ 46217214Smckusick /* change it to 1, since zero encodes 65536, which */ 46317214Smckusick /* isn't quite what we had in mind. The byte count */ 46417214Smckusick /* may be larger than the size of the input buffer, so */ 46517214Smckusick /* limit the count to the buffer size. After */ 46617214Smckusick /* making the byte count reasonable, set bcount to the */ 46717214Smckusick /* negative of the controller's version of the byte */ 46817214Smckusick /* count so that the start address for the transfer is */ 46917214Smckusick /* set up correctly. */ 47017214Smckusick 47117214Smckusick if (mt_do_readrev) { 47217214Smckusick mi->mi_tab.b_errcnt = 2; 47317214Smckusick if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0) 47417214Smckusick bp->b_bcount = 1; 47517214Smckusick if (bp->b_bcount > bp->b_resid) 47617214Smckusick bp->b_bcount = bp->b_resid; 47717214Smckusick bp->b_bcount = -(bp->b_bcount); 47817214Smckusick return(MBD_RETRY); 47917214Smckusick } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) { 48017214Smckusick sc->sc_blkno++; 48117214Smckusick bp->b_bcount = bp->b_resid; 48217214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 48317214Smckusick bp->b_flags |= B_ERROR; 48417214Smckusick break; 48517214Smckusick } 48617214Smckusick bp->b_flags |= B_ERROR; 48717214Smckusick 48817214Smckusick /* fall into MTER_LONGREC */ 48917214Smckusick 4904736Swnj case MTER_LONGREC: 49117214Smckusick sc->sc_blkno++; 49217214Smckusick bp->b_bcount = bp->b_resid; 4934736Swnj bp->b_resid = 0; 49417214Smckusick bp->b_error = ENOMEM; 49517214Smckusick bp->b_flags |= B_ERROR; 4964736Swnj break; 4974736Swnj 4984736Swnj case MTER_NOTCAP: 4994736Swnj printf("mu%d: blank tape\n", MUUNIT(bp->b_dev)); 5004736Swnj goto err; 5014736Swnj 5024736Swnj case MTER_TM: 50317214Smckusick 50417214Smckusick /* End of file. Since the default byte count has */ 50517214Smckusick /* already been set, just count the block and proceed. */ 50617214Smckusick 5074736Swnj sc->sc_blkno++; 5084736Swnj err: 5094736Swnj if (bp != &rmtbuf[MTUNIT(bp->b_dev)]) 51017214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno); 5114736Swnj break; 5124736Swnj 5134736Swnj case MTER_OFFLINE: 5144736Swnj if (sc->sc_openf > 0) { 5154736Swnj sc->sc_openf = -1; 51618324Sralph tprintf(sc->sc_ttyp, "mu%d: offline\n", MUUNIT(bp->b_dev)); 5174736Swnj } 5184736Swnj bp->b_flags |= B_ERROR; 5194736Swnj break; 5204736Swnj 52117214Smckusick case MTER_NOTAVL: 52217214Smckusick if (sc->sc_openf > 0) { 52317214Smckusick sc->sc_openf = -1; 52418324Sralph tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", 52518324Sralph MUUNIT(bp->b_dev)); 52617214Smckusick } 52717214Smckusick bp->b_flags |= B_ERROR; 52817214Smckusick break; 52917214Smckusick 5304736Swnj case MTER_FPT: 53118324Sralph tprintf(sc->sc_ttyp, "mu%d: no write ring\n", MUUNIT(bp->b_dev)); 5324736Swnj bp->b_flags |= B_ERROR; 5334736Swnj break; 5344736Swnj 53517214Smckusick case MTER_UNREAD: 53617214Smckusick sc->sc_blkno++; 53717214Smckusick bp->b_bcount = bp->b_resid; 53817214Smckusick bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount); 53917214Smckusick 54017214Smckusick /* Code 010 means a garbage record, nothing serious. */ 54117214Smckusick 54217214Smckusick if (((er & MTER_FAILCODE) >> 10) == 010) { 54318324Sralph tprintf(sc->sc_ttyp, "mu%d: rn=%d bn=%d unreadable record\n", 54417214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno); 54517214Smckusick bp->b_flags |= B_ERROR; 54617214Smckusick break; 54717214Smckusick } 54817214Smckusick 54917214Smckusick /* Anything else might be a hardware problem, */ 55017214Smckusick /* fall into the error report. */ 55117214Smckusick 5524736Swnj default: 55317214Smckusick 55417214Smckusick /* The bits in sc->sc_dsreg are from the last sense */ 55517214Smckusick /* command. To get the most recent copy, you have to */ 55617214Smckusick /* do a sense at interrupt level, which requires nested */ 55717214Smckusick /* error processing. This is a bit messy, so leave */ 55817214Smckusick /* well enough alone. */ 55917214Smckusick 56018324Sralph tprintf(sc->sc_ttyp, "mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=%o (octal) ds=%b\n", 56117214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 56217214Smckusick mbsr, mbsr_bits, er, 56317214Smckusick MASKREG(sc->sc_dsreg), mtds_bits); 56417214Smckusick #ifdef MTLERRM 56517214Smckusick mtintfail(sc); 56617214Smckusick printf(" interrupt code = %o (octal) <%s>\n failure code = %o (octal) <%s>\n", 56717214Smckusick er & MTER_INTCODE, sc->sc_mesg, 56817214Smckusick (er & MTER_FAILCODE) >> 10, sc->sc_fmesg); 56917214Smckusick #endif 5704736Swnj bp->b_flags |= B_ERROR; 57117214Smckusick 57217214Smckusick /* The TM78 manual says to reset the controller after */ 57317214Smckusick /* TM fault B or MASSBUS fault. */ 57417214Smckusick 57517214Smckusick if ( ((er & MTER_INTCODE) == MTER_TMFLTB) 57617214Smckusick || ((er & MTER_INTCODE) == MTER_MBFLT) ) { 57717214Smckusick mtcreset(mtaddr); 57817214Smckusick } 5794736Swnj } 58017214Smckusick 58117214Smckusick /* Just in case some strange error slipped through, (drive off */ 58217214Smckusick /* line during read-reverse error recovery comes to mind) make */ 58317214Smckusick /* sure the byte count is reasonable. */ 58417214Smckusick 58517214Smckusick if (bp->b_bcount < 0) 58617214Smckusick bp->b_bcount = bp->b_resid; 5874736Swnj return (MBD_DONE); 5884736Swnj } 5894736Swnj 5904736Swnj mtndtint(mi) 5914736Swnj register struct mba_device *mi; 5924736Swnj { 5934736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 5944736Swnj register struct buf *bp = mi->mi_tab.b_actf; 5954736Swnj register struct mu_softc *sc; 59617214Smckusick register int er, fc; 59717214Smckusick int unit; 5984736Swnj 5994736Swnj unit = (mtaddr->mtner >> 8) & 3; 6004736Swnj er = MASKREG(mtaddr->mtner); 60117214Smckusick sc = &mu_softc[unit]; 60217214Smckusick sc->sc_erreg = er; 60317214Smckusick 60417214Smckusick /* Check for unsolicited interrupts. */ 60517214Smckusick 6064736Swnj if (bp == 0 || unit != MUUNIT(bp->b_dev)) { /* consistency check */ 60717214Smckusick if ((er & MTER_INTCODE) != MTER_ONLINE) { 60817214Smckusick printf("mt: unit %d unexpected interrupt (non data transfer) er=%o (octal) ds=%b\n", 60917214Smckusick unit, er, MASKREG(sc->sc_dsreg), mtds_bits); 61017214Smckusick #ifdef MTLERRM 61117214Smckusick mtintfail(sc); 61217214Smckusick printf(" interrupt code = %o (octal) <%s>\n failure code = %o (octal) <%s>\n", 61317214Smckusick er & MTER_INTCODE, sc->sc_mesg, 61417214Smckusick (er & MTER_FAILCODE) >> 10, sc->sc_fmesg); 61517214Smckusick #endif 61617214Smckusick if ( ((er & MTER_INTCODE) == MTER_TMFLTB) 61717214Smckusick || ((er & MTER_INTCODE) == MTER_MBFLT) ) { 61817214Smckusick 61917214Smckusick /* Reset the controller, then set error */ 62017214Smckusick /* status if there was anything active */ 62117214Smckusick /* when the fault occurred. This may */ 62217214Smckusick /* shoot an innocent bystander, but */ 62317214Smckusick /* it's better than letting an error */ 62417214Smckusick /* slip through. */ 62517214Smckusick 62617214Smckusick mtcreset(mtaddr); 62717214Smckusick if (bp != 0) { 62817214Smckusick bp->b_flags |= B_ERROR; 62917214Smckusick return (MBN_DONE); 63017214Smckusick } 63117214Smckusick } 63217214Smckusick } 6334736Swnj return (MBN_SKIP); 6344736Swnj } 6354736Swnj if (bp == 0) 6364736Swnj return (MBN_SKIP); 63717214Smckusick 6384736Swnj fc = (mtaddr->mtncs[unit] >> 8) & 0xff; 6394736Swnj sc->sc_resid = fc; 64017214Smckusick 64117214Smckusick /* Clear the "written" flag after any operation that changes */ 64217214Smckusick /* the position of the tape. */ 64317214Smckusick 64417214Smckusick if ( (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 64517214Smckusick || (bp->b_command != MT_SENSE) ) 64617214Smckusick sc->sc_flags &= ~H_WRITTEN; 64717214Smckusick 6484736Swnj switch (er & MTER_INTCODE) { 64917214Smckusick 65017214Smckusick case MTER_EOT: 65117214Smckusick sc->sc_flags |= H_EOT; 65217214Smckusick 65317214Smckusick /* fall into MTER_DONE */ 65417214Smckusick 6554736Swnj case MTER_DONE: 65617214Smckusick 65717214Smckusick /* If this is a command buffer, just update the status. */ 65817214Smckusick 6594736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 6604736Swnj done: 6614736Swnj if (bp->b_command == MT_SENSE) 6624736Swnj sc->sc_dsreg = MASKREG(mtaddr->mtds); 6634736Swnj return (MBN_DONE); 6644736Swnj } 66517214Smckusick 66617214Smckusick /* It's not a command buffer, must be a cooked I/O */ 66717214Smckusick /* skip operation (perhaps a shaky assumption, but it */ 66817214Smckusick /* wasn't my idea). */ 66917214Smckusick 6707380Ssam if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0) 6716186Ssam sc->sc_blkno -= MIN(0377, -fc); 6724736Swnj else 6736186Ssam sc->sc_blkno += MIN(0377, fc); 6744736Swnj return (MBN_RETRY); 6754736Swnj 67617214Smckusick case MTER_ONLINE: /* ddj -- shouldn't happen but did */ 6774736Swnj case MTER_RWDING: 6784736Swnj return (MBN_SKIP); /* ignore "rewind started" interrupt */ 6794736Swnj 6804736Swnj case MTER_NOTCAP: 68118324Sralph tprintf(sc->sc_ttyp, "mu%d: blank tape\n", MUUNIT(bp->b_dev)); 68217214Smckusick bp->b_flags |= B_ERROR; 68317214Smckusick return (MBN_DONE); 6844736Swnj 6854736Swnj case MTER_TM: 6864736Swnj case MTER_LEOT: 68717214Smckusick 68817214Smckusick /* For an ioctl skip operation, count a tape mark as */ 68917214Smckusick /* a record. If there's anything left to do, update */ 69017214Smckusick /* the repeat count and re-start the command. */ 69117214Smckusick 69217214Smckusick if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 69317214Smckusick if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0) 69417214Smckusick return (MBN_DONE); 69517214Smckusick else 69617214Smckusick return (MBN_RETRY); 69717214Smckusick 69817214Smckusick /* Cooked I/O again. Just update the books and wait */ 69917214Smckusick /* for someone else to return end of file or complain */ 70017214Smckusick /* about a bad seek. */ 70117214Smckusick 70217214Smckusick } else if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 70317214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1; 7044736Swnj sc->sc_blkno = sc->sc_nxrec; 7054736Swnj } else { 70617214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc; 70717214Smckusick sc->sc_blkno = sc->sc_nxrec + 1; 7084736Swnj } 7094736Swnj return (MBN_RETRY); 7104736Swnj 7114736Swnj case MTER_FPT: 71218324Sralph tprintf(sc->sc_ttyp, "mu%d: no write ring\n", MUUNIT(bp->b_dev)); 7134736Swnj bp->b_flags |= B_ERROR; 7144736Swnj return (MBN_DONE); 7154736Swnj 7164736Swnj case MTER_OFFLINE: 71717214Smckusick 71817214Smckusick /* If `off line' was intentional, don't complain. */ 71917214Smckusick 72017214Smckusick if ( (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 72117214Smckusick && (bp->b_command == MT_UNLOAD) ) 72217214Smckusick return(MBN_DONE); 7234736Swnj if (sc->sc_openf > 0) { 7244736Swnj sc->sc_openf = -1; 72518324Sralph tprintf(sc->sc_ttyp, "mu%d: offline\n", MUUNIT(bp->b_dev)); 7264736Swnj } 7274736Swnj bp->b_flags |= B_ERROR; 7284736Swnj return (MBN_DONE); 7294736Swnj 73017214Smckusick case MTER_NOTAVL: 73117214Smckusick if (sc->sc_openf > 0) { 73217214Smckusick sc->sc_openf = -1; 73318324Sralph tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", MUUNIT(bp->b_dev)); 73417214Smckusick } 73517214Smckusick bp->b_flags |= B_ERROR; 73617214Smckusick return (MBN_DONE); 73717214Smckusick 7384736Swnj case MTER_BOT: 7394736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 7404736Swnj goto done; 7414736Swnj 74217214Smckusick /* fall through */ 74317214Smckusick 7444736Swnj default: 74518324Sralph tprintf(sc->sc_ttyp, "mu%d: hard error (non data transfer) rn=%d bn=%d er=%o (octal) ds=%b\n", 74617214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 74717214Smckusick er, MASKREG(sc->sc_dsreg), mtds_bits); 74817214Smckusick #ifdef MTLERRM 74917214Smckusick mtintfail(sc); 75017214Smckusick printf(" interrupt code = %o (octal) <%s>\n failure code = %o (octal) <%s>\n", 75117214Smckusick (er & MTER_INTCODE), sc->sc_mesg, 75217214Smckusick (er & MTER_FAILCODE) >> 10, sc->sc_fmesg); 75317214Smckusick #endif 75417214Smckusick if ( ((er & MTER_INTCODE) == MTER_TMFLTB) 75517214Smckusick || ((er & MTER_INTCODE) == MTER_MBFLT) ) { 75617214Smckusick mtcreset(mtaddr); /* reset the controller */ 75717214Smckusick } 7584736Swnj bp->b_flags |= B_ERROR; 7594736Swnj return (MBN_DONE); 7604736Swnj } 7614736Swnj /* NOTREACHED */ 7624736Swnj } 7634736Swnj 76417214Smckusick void mtcreset(mtaddr) 76517214Smckusick register struct mtdevice *mtaddr; 76617214Smckusick { 76717214Smckusick register int i; 76817214Smckusick 76917214Smckusick mtaddr->mtid = MTID_CLR; /* reset the TM78 */ 77017214Smckusick DELAY(200); 77117214Smckusick for (i = MTTIMEOUT; i > 0; i--) { 77217214Smckusick DELAY(50); /* don't nag */ 77317214Smckusick if ((mtaddr->mtid & MTID_RDY) != 0) 77417214Smckusick return; /* exit when ready */ 77517214Smckusick } 77617214Smckusick printf("mt: controller hung\n"); 77717214Smckusick } 77817214Smckusick 7797740Sroot mtread(dev, uio) 7804736Swnj dev_t dev; 7817740Sroot struct uio *uio; 7824736Swnj { 7838158Sroot int errno; 7844736Swnj 7858158Sroot errno = mtphys(dev, uio); 7868158Sroot if (errno) 7878158Sroot return (errno); 7888158Sroot return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_READ, minphys, uio)); 7894736Swnj } 7904736Swnj 79117214Smckusick 7927833Sroot mtwrite(dev, uio) 7937833Sroot dev_t dev; 7947833Sroot struct uio *uio; 7954736Swnj { 7968158Sroot int errno; 7974736Swnj 7988158Sroot errno = mtphys(dev, uio); 7998158Sroot if (errno) 8008158Sroot return (errno); 8018158Sroot return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_WRITE, minphys, uio)); 8024736Swnj } 8034736Swnj 8047740Sroot mtphys(dev, uio) 8054736Swnj dev_t dev; 8067740Sroot struct uio *uio; 8074736Swnj { 8084736Swnj register int mtunit; 80917214Smckusick struct mba_device *mi; 81017214Smckusick register int bsize = uio->uio_iov->iov_len; 8114736Swnj 8124736Swnj mtunit = MTUNIT(dev); 81317214Smckusick if ( (mtunit >= NMT) 81417214Smckusick || ((mi = mtinfo[mtunit]) == 0) 81517214Smckusick || (mi->mi_alive == 0) ) 8167740Sroot return (ENXIO); 81717214Smckusick if ( (bsize > 0xffff) /* controller limit */ 81817214Smckusick || (bsize <= 0) ) /* ambiguous */ 81917214Smckusick return (EINVAL); 8207740Sroot return (0); 8214736Swnj } 8224736Swnj 8234736Swnj /*ARGSUSED*/ 8247637Ssam mtioctl(dev, cmd, data, flag) 8254736Swnj dev_t dev; 8264736Swnj int cmd; 8277637Ssam caddr_t data; 8284736Swnj int flag; 8294736Swnj { 8304736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 8314736Swnj register struct buf *bp = &cmtbuf[MTUNIT(dev)]; 83217214Smckusick register struct mtop *mtop; 83317214Smckusick register struct mtget *mtget; 83417214Smckusick int callcount, fcount; 83517214Smckusick int op; 83617214Smckusick 83717214Smckusick /* We depend on the values and order of the MT codes here. */ 83817214Smckusick 8394736Swnj static mtops[] = 8404736Swnj {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE}; 8414736Swnj 8424736Swnj switch (cmd) { 8437637Ssam 84417214Smckusick /* tape operation */ 84517214Smckusick 84617214Smckusick case MTIOCTOP: 8478606Sroot mtop = (struct mtop *)data; 8488606Sroot switch (mtop->mt_op) { 8497637Ssam 8504736Swnj case MTWEOF: 8517637Ssam callcount = mtop->mt_count; 8524736Swnj fcount = 1; 8534736Swnj break; 8547637Ssam 8554736Swnj case MTFSF: case MTBSF: 8567637Ssam callcount = mtop->mt_count; 8574736Swnj fcount = 1; 8584736Swnj break; 8597637Ssam 8604736Swnj case MTFSR: case MTBSR: 8614736Swnj callcount = 1; 8627637Ssam fcount = mtop->mt_count; 8634736Swnj break; 8647637Ssam 8654736Swnj case MTREW: case MTOFFL: 8664736Swnj callcount = 1; 8674736Swnj fcount = 1; 8684736Swnj break; 8697637Ssam 8704736Swnj default: 8718581Sroot return (ENXIO); 8724736Swnj } 87317214Smckusick if ((callcount <= 0) || (fcount <= 0)) 8748581Sroot return (EINVAL); 8757637Ssam op = mtops[mtop->mt_op]; 8764736Swnj if (op == MT_WTM) 8774736Swnj op |= sc->sc_dens; 8784736Swnj while (--callcount >= 0) { 87917214Smckusick register int n, fc = fcount; 8804736Swnj 8814736Swnj do { 88217214Smckusick n = MIN(fc, 0xff); 8834736Swnj mtcommand(dev, op, n); 88417214Smckusick n -= sc->sc_resid; 88517214Smckusick fc -= n; 88617214Smckusick switch (mtop->mt_op) { 88717214Smckusick 88817214Smckusick case MTWEOF: 88917214Smckusick sc->sc_blkno += (daddr_t)n; 89017214Smckusick sc->sc_nxrec = sc->sc_blkno - 1; 89117214Smckusick break; 89217214Smckusick 89317214Smckusick case MTOFFL: 89417214Smckusick case MTREW: 89517214Smckusick case MTFSF: 89617214Smckusick sc->sc_blkno = (daddr_t)0; 89717214Smckusick sc->sc_nxrec = (daddr_t)INF; 89817214Smckusick break; 89917214Smckusick 90017214Smckusick case MTBSF: 90117214Smckusick if (sc->sc_resid) { 90217214Smckusick sc->sc_blkno = (daddr_t)0; 90317214Smckusick sc->sc_nxrec = (daddr_t)INF; 90417214Smckusick } else { 90517214Smckusick sc->sc_blkno = (daddr_t)(-1); 90617214Smckusick sc->sc_nxrec = (daddr_t)(-1); 90717214Smckusick } 90817214Smckusick break; 90917214Smckusick 91017214Smckusick case MTFSR: 91117214Smckusick sc->sc_blkno += (daddr_t)n; 91217214Smckusick break; 91317214Smckusick 91417214Smckusick case MTBSR: 91517214Smckusick sc->sc_blkno -= (daddr_t)n; 91617214Smckusick break; 91717214Smckusick } 91817214Smckusick if (sc->sc_resid) 91917214Smckusick break; 92017214Smckusick } while (fc); 92117214Smckusick if (fc) { 92217214Smckusick sc->sc_resid = callcount + fc; 92317214Smckusick if ( (mtop->mt_op == MTFSR) 92417214Smckusick || (mtop->mt_op == MTBSR) ) 92517214Smckusick return (EIO); 92617214Smckusick else 92717214Smckusick break; 92817214Smckusick } 92917214Smckusick if (bp->b_flags & B_ERROR) 9304736Swnj break; 9314736Swnj } 9328712Sroot return (geterror(bp)); 9337637Ssam 93417214Smckusick /* tape status */ 93517214Smckusick 9364736Swnj case MTIOCGET: 9377637Ssam mtget = (struct mtget *)data; 9387637Ssam mtget->mt_erreg = sc->sc_erreg; 9397637Ssam mtget->mt_resid = sc->sc_resid; 9404736Swnj mtcommand(dev, MT_SENSE, 1); /* update drive status */ 9417637Ssam mtget->mt_dsreg = sc->sc_dsreg; 9427637Ssam mtget->mt_type = MT_ISMT; 9438581Sroot break; 9447637Ssam 94517214Smckusick /* ignore EOT condition */ 94617214Smckusick 94717214Smckusick case MTIOCIEOT: 94817214Smckusick sc->sc_flags |= H_IEOT; 94917214Smckusick break; 95017214Smckusick 95117214Smckusick /* enable EOT condition */ 95217214Smckusick 95317214Smckusick case MTIOCEEOT: 95417214Smckusick sc->sc_flags &= ~H_IEOT; 95517214Smckusick break; 95617214Smckusick 9574736Swnj default: 9588581Sroot return (ENXIO); 9594736Swnj } 9608581Sroot return (0); 9614736Swnj } 9624736Swnj 9634736Swnj #define DBSIZE 20 9644736Swnj 9654736Swnj mtdump() 9664736Swnj { 9674736Swnj register struct mba_device *mi; 9684736Swnj register struct mba_regs *mp; 9694736Swnj int blk, num; 9704736Swnj int start; 9714736Swnj 9724736Swnj start = 0; 9734736Swnj num = maxfree; 9744736Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 9754736Swnj if (mtinfo[0] == 0) 9764736Swnj return (ENXIO); 9774736Swnj mi = phys(mtinfo[0], struct mba_device *); 9784736Swnj mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 9794736Swnj mp->mba_cr = MBCR_IE; 9806186Ssam #if lint 9818606Sroot blk = 0; num = blk; start = num; blk = start; 9826186Ssam return (0); 9836186Ssam #endif 9846186Ssam #ifdef notyet 9854736Swnj mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive]; 9864736Swnj mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI; 9874736Swnj mtaddr->mtcs1 = MT_DCLR|MT_GO; 9884736Swnj while (num > 0) { 9894736Swnj blk = num > DBSIZE ? DBSIZE : num; 9904736Swnj mtdwrite(start, blk, mtaddr, mp); 9914736Swnj start += blk; 9924736Swnj num -= blk; 9934736Swnj } 9944736Swnj mteof(mtaddr); 9954736Swnj mteof(mtaddr); 9964736Swnj mtwait(mtaddr); 9974736Swnj if (mtaddr->mtds&MTDS_ERR) 9984736Swnj return (EIO); 9994736Swnj mtaddr->mtcs1 = MT_REW|MT_GO; 10004736Swnj return (0); 10014736Swnj } 10024736Swnj 10034736Swnj mtdwrite(dbuf, num, mtaddr, mp) 10044736Swnj register dbuf, num; 10054736Swnj register struct mtdevice *mtaddr; 10064736Swnj struct mba_regs *mp; 10074736Swnj { 10084736Swnj register struct pte *io; 10094736Swnj register int i; 10104736Swnj 10114736Swnj mtwait(mtaddr); 10124736Swnj io = mp->mba_map; 10134736Swnj for (i = 0; i < num; i++) 10144736Swnj *(int *)io++ = dbuf++ | PG_V; 10154736Swnj mtaddr->mtfc = -(num*NBPG); 10164736Swnj mp->mba_sr = -1; 10174736Swnj mp->mba_bcr = -(num*NBPG); 10184736Swnj mp->mba_var = 0; 10194736Swnj mtaddr->mtcs1 = MT_WCOM|MT_GO; 10204736Swnj } 10214736Swnj 10224736Swnj mtwait(mtaddr) 10234736Swnj struct mtdevice *mtaddr; 10244736Swnj { 10254736Swnj register s; 10264736Swnj 10274736Swnj do 10284736Swnj s = mtaddr->mtds; 10294736Swnj while ((s & MTDS_DRY) == 0); 10304736Swnj } 10314736Swnj 10324736Swnj mteof(mtaddr) 10334736Swnj struct mtdevice *mtaddr; 10344736Swnj { 10354736Swnj 10364736Swnj mtwait(mtaddr); 10374736Swnj mtaddr->mtcs1 = MT_WEOF|MT_GO; 10384736Swnj #endif notyet 10394736Swnj } 104017214Smckusick 104117214Smckusick #ifdef MTLERRM 104217214Smckusick mtintfail(sc) 104317214Smckusick register struct mu_softc *sc; 104417214Smckusick { 104517214Smckusick switch (sc->sc_erreg & MTER_INTCODE) { 104617214Smckusick 104717214Smckusick /* unexpected BOT detected */ 104817214Smckusick 104917214Smckusick case MTER_BOT: 105017214Smckusick sc->sc_mesg = "unexpected BOT"; 105117214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 105217214Smckusick case 01: 105317214Smckusick sc->sc_fmesg = "tape was at BOT"; 105417214Smckusick break; 105517214Smckusick case 02: 105617214Smckusick sc->sc_fmesg = "BOT seen after tape started"; 105717214Smckusick break; 105817214Smckusick case 03: 105917214Smckusick sc->sc_fmesg = "ARA ID detected"; 106017214Smckusick break; 106117214Smckusick default: 106217214Smckusick sc->sc_fmesg = "unclassified failure code"; 106317214Smckusick } 106417214Smckusick break; 106517214Smckusick 106617214Smckusick /* unexpected LEOT detected */ 106717214Smckusick 106817214Smckusick case MTER_LEOT: 106917214Smckusick sc->sc_mesg = "unexpected LEOT"; 107017214Smckusick sc->sc_fmesg = ""; 107117214Smckusick break; 107217214Smckusick 107317214Smckusick /* rewinding */ 107417214Smckusick 107517214Smckusick case MTER_RWDING: 107617214Smckusick sc->sc_mesg = "tape rewinding"; 107717214Smckusick sc->sc_fmesg = ""; 107817214Smckusick break; 107917214Smckusick 108017214Smckusick /* not ready */ 108117214Smckusick 108217214Smckusick case MTER_NOTRDY: 108317214Smckusick sc->sc_mesg = "drive not ready"; 108417214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 108517214Smckusick case 01: 108617214Smckusick sc->sc_fmesg = "TU on-line but not ready"; 108717214Smckusick break; 108817214Smckusick case 02: 108917214Smckusick sc->sc_fmesg = "fatal error has occurred"; 109017214Smckusick break; 109117214Smckusick case 03: 109217214Smckusick sc->sc_fmesg = "access allowed but not really"; 109317214Smckusick break; 109417214Smckusick default: 109517214Smckusick sc->sc_fmesg = "unclassified failure code"; 109617214Smckusick } 109717214Smckusick break; 109817214Smckusick 109917214Smckusick /* not available */ 110017214Smckusick 110117214Smckusick case MTER_NOTAVL: 110217214Smckusick sc->sc_mesg = "drive not available"; 110317214Smckusick sc->sc_fmesg = ""; 110417214Smckusick break; 110517214Smckusick 110617214Smckusick /* unit does not exist */ 110717214Smckusick 110817214Smckusick case MTER_NONEX: 110917214Smckusick sc->sc_mesg = "unit does not exist"; 111017214Smckusick sc->sc_fmesg = ""; 111117214Smckusick break; 111217214Smckusick 111317214Smckusick /* not capable */ 111417214Smckusick 111517214Smckusick case MTER_NOTCAP: 111617214Smckusick sc->sc_mesg = "not capable"; 111717214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 111817214Smckusick case 01: 111917214Smckusick sc->sc_fmesg = "no record found within 25 feet"; 112017214Smckusick break; 112117214Smckusick case 02: 112217214Smckusick sc->sc_fmesg = "ID burst neither PE nor GCR"; 112317214Smckusick break; 112417214Smckusick case 03: 112517214Smckusick sc->sc_fmesg = "ARA ID not found"; 112617214Smckusick break; 112717214Smckusick case 04: 112817214Smckusick sc->sc_fmesg = "no gap found after ID burst"; 112917214Smckusick break; 113017214Smckusick default: 113117214Smckusick sc->sc_fmesg = "unclassified failure code"; 113217214Smckusick } 113317214Smckusick break; 113417214Smckusick 113517214Smckusick /* long tape record */ 113617214Smckusick 113717214Smckusick case MTER_LONGREC: 113817214Smckusick sc->sc_mesg = "long record"; 113917214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 114017214Smckusick case 00: 114117214Smckusick sc->sc_fmesg = "extended sense data not found"; 114217214Smckusick break; 114317214Smckusick case 01: 114417214Smckusick sc->sc_fmesg = "extended sense data updated"; 114517214Smckusick break; 114617214Smckusick default: 114717214Smckusick sc->sc_fmesg = "unclassified failure code"; 114817214Smckusick } 114917214Smckusick break; 115017214Smckusick 115117214Smckusick /* unreadable */ 115217214Smckusick 115317214Smckusick case MTER_UNREAD: 115417214Smckusick sc->sc_mesg = "unreadable record"; 115517214Smckusick goto code22; 115617214Smckusick 115717214Smckusick /* error */ 115817214Smckusick 115917214Smckusick case MTER_ERROR: 116017214Smckusick sc->sc_mesg = "error"; 116117214Smckusick goto code22; 116217214Smckusick 116317214Smckusick /* EOT error */ 116417214Smckusick 116517214Smckusick case MTER_EOTERR: 116617214Smckusick sc->sc_mesg = "EOT error"; 116717214Smckusick goto code22; 116817214Smckusick 116917214Smckusick /* tape position lost */ 117017214Smckusick 117117214Smckusick case MTER_BADTAPE: 117217214Smckusick sc->sc_mesg = "bad tape"; 117317214Smckusick code22: 117417214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 117517214Smckusick case 01: 117617214Smckusick sc->sc_fmesg = "GCR write error"; 117717214Smckusick break; 117817214Smckusick case 02: 117917214Smckusick sc->sc_fmesg = "GCR read error"; 118017214Smckusick break; 118117214Smckusick case 03: 118217214Smckusick sc->sc_fmesg = "PE read error"; 118317214Smckusick break; 118417214Smckusick case 04: 118517214Smckusick sc->sc_fmesg = "PE write error"; 118617214Smckusick break; 118717214Smckusick case 05: 118817214Smckusick sc->sc_fmesg = "at least 1 bit set in ECCSTA"; 118917214Smckusick break; 119017214Smckusick case 06: 119117214Smckusick sc->sc_fmesg = "PE write error"; 119217214Smckusick break; 119317214Smckusick case 07: 119417214Smckusick sc->sc_fmesg = "GCR write error"; 119517214Smckusick break; 119617214Smckusick case 010: 119717214Smckusick sc->sc_fmesg = "RSTAT contains bad code"; 119817214Smckusick break; 119917214Smckusick case 011: 120017214Smckusick sc->sc_fmesg = "PE write error"; 120117214Smckusick break; 120217214Smckusick case 012: 120317214Smckusick sc->sc_fmesg = "MASSBUS parity error"; 120417214Smckusick break; 120517214Smckusick case 013: 120617214Smckusick sc->sc_fmesg = "invalid data transferred"; 120717214Smckusick break; 120817214Smckusick default: 120917214Smckusick sc->sc_fmesg = "unclassified failure code"; 121017214Smckusick } 121117214Smckusick break; 121217214Smckusick 121317214Smckusick /* TM fault A */ 121417214Smckusick 121517214Smckusick case MTER_TMFLTA: 121617214Smckusick sc->sc_mesg = "TM fault A"; 121717214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 121817214Smckusick case 01: 121917214Smckusick sc->sc_fmesg = "illegal command code"; 122017214Smckusick break; 122117214Smckusick case 02: 122217214Smckusick sc->sc_fmesg = "DT command issued when NDT command active"; 122317214Smckusick break; 122417214Smckusick case 03: 122517214Smckusick sc->sc_fmesg = "WMC error"; 122617214Smckusick break; 122717214Smckusick case 04: 122817214Smckusick sc->sc_fmesg = "RUN not received from MASSBUS controller"; 122917214Smckusick break; 123017214Smckusick case 05: 123117214Smckusick sc->sc_fmesg = "mismatch in command read - function routine"; 123217214Smckusick break; 123317214Smckusick case 06: 123417214Smckusick sc->sc_fmesg = "ECC ROM parity error"; 123517214Smckusick break; 123617214Smckusick case 07: 123717214Smckusick sc->sc_fmesg = "XMC ROM parity error"; 123817214Smckusick break; 123917214Smckusick case 010: 124017214Smckusick sc->sc_fmesg = "mismatch in command read - ID burst command"; 124117214Smckusick break; 124217214Smckusick case 011: 124317214Smckusick sc->sc_fmesg = "mismatch in command read - verify ARA burst command"; 124417214Smckusick break; 124517214Smckusick case 012: 124617214Smckusick sc->sc_fmesg = "mismatch in command read - verify ARA ID command"; 124717214Smckusick break; 124817214Smckusick case 013: 124917214Smckusick sc->sc_fmesg = "mismatch in command read - verify gap command"; 125017214Smckusick break; 125117214Smckusick case 014: 125217214Smckusick sc->sc_fmesg = "mismatch in command read - read id burst command"; 125317214Smckusick break; 125417214Smckusick case 015: 125517214Smckusick sc->sc_fmesg = "mismatch in command read - verify ARA ID command"; 125617214Smckusick break; 125717214Smckusick case 016: 125817214Smckusick sc->sc_fmesg = "mismatch in command read - verify gap command"; 125917214Smckusick break; 126017214Smckusick case 017: 126117214Smckusick sc->sc_fmesg = "mismatch in command read - find gap command"; 126217214Smckusick break; 126317214Smckusick case 020: 126417214Smckusick sc->sc_fmesg = "WMC LEFT failed to set"; 126517214Smckusick break; 126617214Smckusick case 021: 126717214Smckusick sc->sc_fmesg = "XL PE set in INTSTA register"; 126817214Smckusick break; 126917214Smckusick case 022: 127017214Smckusick sc->sc_fmesg = "XMC DONE did not set"; 127117214Smckusick break; 127217214Smckusick case 023: 127317214Smckusick sc->sc_fmesg = "WMC ROM PE or RD PE set in WMCERR register"; 127417214Smckusick break; 127517214Smckusick default: 127617214Smckusick sc->sc_fmesg = "unclassified failure code"; 127717214Smckusick } 127817214Smckusick break; 127917214Smckusick 128017214Smckusick /* TU fault A */ 128117214Smckusick 128217214Smckusick case MTER_TUFLTA: 128317214Smckusick sc->sc_mesg = "TU fault A"; 128417214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 128517214Smckusick case 01: 128617214Smckusick sc->sc_fmesg = "TU status parity error"; 128717214Smckusick break; 128817214Smckusick case 02: 128917214Smckusick sc->sc_fmesg = "TU command parity error"; 129017214Smckusick break; 129117214Smckusick case 03: 129217214Smckusick sc->sc_fmesg = "rewinding tape went offline"; 129317214Smckusick break; 129417214Smckusick case 04: 129517214Smckusick sc->sc_fmesg = "tape went not ready during DSE"; 129617214Smckusick break; 129717214Smckusick case 05: 129817214Smckusick sc->sc_fmesg = "TU CMD status changed during DSE"; 129917214Smckusick break; 130017214Smckusick case 06: 130117214Smckusick sc->sc_fmesg = "TU never came up to speed"; 130217214Smckusick break; 130317214Smckusick case 07: 130417214Smckusick sc->sc_fmesg = "TU velocity changed"; 130517214Smckusick break; 130617214Smckusick case 010: 130717214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion"; 130817214Smckusick break; 130917214Smckusick case 011: 131017214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set drive density"; 131117214Smckusick break; 131217214Smckusick case 012: 131317214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion to write BOT ID"; 131417214Smckusick break; 131517214Smckusick case 013: 131617214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID"; 131717214Smckusick break; 131817214Smckusick case 014: 131917214Smckusick sc->sc_fmesg = "failed to write density ID burst"; 132017214Smckusick break; 132117214Smckusick case 015: 132217214Smckusick sc->sc_fmesg = "failed to write ARA burst"; 132317214Smckusick break; 132417214Smckusick case 016: 132517214Smckusick sc->sc_fmesg = "failed to write ARA ID"; 132617214Smckusick break; 132717214Smckusick case 017: 132817214Smckusick sc->sc_fmesg = "ARA error bit set in MTA status B register"; 132917214Smckusick break; 133017214Smckusick case 021: 133117214Smckusick sc->sc_fmesg = "could not find a gap after ID code was written correctly"; 133217214Smckusick break; 133317214Smckusick case 022: 133417214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion to read ID burst"; 133517214Smckusick break; 133617214Smckusick case 023: 133717214Smckusick sc->sc_fmesg = "timeout looking for BOT after detecting ARA ID burst"; 133817214Smckusick break; 133917214Smckusick case 024: 134017214Smckusick sc->sc_fmesg = "failed to write tape mark"; 134117214Smckusick break; 134217214Smckusick case 025: 134317214Smckusick sc->sc_fmesg = "tape never came up to speed while trying to reposition for retry of writing tape mark"; 134417214Smckusick break; 134517214Smckusick case 026: 134617214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion in erase gap routine"; 134717214Smckusick break; 134817214Smckusick case 027: 134917214Smckusick sc->sc_fmesg = "could not detect a gap in in erase gap routine"; 135017214Smckusick break; 135117214Smckusick case 030: 135217214Smckusick sc->sc_fmesg = "could not detect a gap after writing record"; 135317214Smckusick break; 135417214Smckusick case 031: 135517214Smckusick sc->sc_fmesg = "read path terminated before entire record was written"; 135617214Smckusick break; 135717214Smckusick case 032: 135817214Smckusick sc->sc_fmesg = "could not find a gap after writing record and read path terminated early"; 135917214Smckusick break; 136017214Smckusick case 033: 136117214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to backup for retry of write tape mark"; 136217214Smckusick break; 136317214Smckusick case 034: 136417214Smckusick sc->sc_fmesg = "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark"; 136517214Smckusick break; 136617214Smckusick case 035: 136717214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to backup to retry a load of BOT ID"; 136817214Smckusick break; 136917214Smckusick case 036: 137017214Smckusick sc->sc_fmesg = "timeout looking for BOT after failing to write BOT ID"; 137117214Smckusick break; 137217214Smckusick case 037: 137317214Smckusick sc->sc_fmesg = "TU velocity changed while writing PE gap before starting to write record"; 137417214Smckusick break; 137517214Smckusick case 040: 137617214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst"; 137717214Smckusick break; 137817214Smckusick case 041: 137917214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set GCR tape density after writing Density ID"; 138017214Smckusick break; 138117214Smckusick case 042: 138217214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set PE tape density at start of read from BOT"; 138317214Smckusick break; 138417214Smckusick case 043: 138517214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst"; 138617214Smckusick break; 138717214Smckusick default: 138817214Smckusick sc->sc_fmesg = "unclassified failure code"; 138917214Smckusick } 139017214Smckusick break; 139117214Smckusick 139217214Smckusick /* TM fault B */ 139317214Smckusick 139417214Smckusick case MTER_TMFLTB: 139517214Smckusick sc->sc_mesg = "TM fault B"; 139617214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 139717214Smckusick case 00: 139817214Smckusick sc->sc_fmesg = "RST0 interrupt occurred with TM RDY set"; 139917214Smckusick break; 140017214Smckusick case 01: 140117214Smckusick sc->sc_fmesg = "power failed to interrupt"; 140217214Smckusick break; 140317214Smckusick case 02: 140417214Smckusick sc->sc_fmesg = "unknown interrupt on channel 5.5"; 140517214Smckusick break; 140617214Smckusick case 03: 140717214Smckusick sc->sc_fmesg = "unknown interrupt on channel 6.5"; 140817214Smckusick break; 140917214Smckusick case 04: 141017214Smckusick sc->sc_fmesg = "unknown interrupt on channel 7"; 141117214Smckusick break; 141217214Smckusick case 05: 141317214Smckusick sc->sc_fmesg = "unknown interrupt on channel 7.5"; 141417214Smckusick break; 141517214Smckusick case 06: 141617214Smckusick sc->sc_fmesg = "CAS contention retry count expired"; 141717214Smckusick break; 141817214Smckusick case 07: 141917214Smckusick sc->sc_fmesg = "CAS contention error not retryable"; 142017214Smckusick break; 142117214Smckusick case 010: 142217214Smckusick sc->sc_fmesg = "queue error, could not find queue entry"; 142317214Smckusick break; 142417214Smckusick case 011: 142517214Smckusick sc->sc_fmesg = "queue entry already full"; 142617214Smckusick break; 142717214Smckusick case 012: 142817214Smckusick sc->sc_fmesg = "8085 ROM parity error"; 142917214Smckusick break; 143017214Smckusick case 013: 143117214Smckusick case 014: 143217214Smckusick case 015: 143317214Smckusick case 016: 143417214Smckusick case 017: 143517214Smckusick case 020: 143617214Smckusick case 021: 143717214Smckusick case 022: 143817214Smckusick case 023: 143917214Smckusick case 024: 144017214Smckusick case 025: 144117214Smckusick case 026: 144217214Smckusick case 027: 144317214Smckusick case 030: 144417214Smckusick case 031: 144517214Smckusick case 032: 144617214Smckusick case 033: 144717214Smckusick case 034: 144817214Smckusick case 035: 144917214Smckusick case 036: 145017214Smckusick case 037: 145117214Smckusick case 040: 145217214Smckusick case 041: 145317214Smckusick case 042: 145417214Smckusick case 043: 145517214Smckusick case 044: 145617214Smckusick case 045: 145717214Smckusick case 046: 145817214Smckusick case 047: 145917214Smckusick case 050: 146017214Smckusick case 051: 146117214Smckusick case 052: 146217214Smckusick case 053: 146317214Smckusick case 054: 146417214Smckusick case 055: 146517214Smckusick case 056: 146617214Smckusick case 057: 146717214Smckusick sc->sc_fmesg = "inline test failed"; 146817214Smckusick break; 146917214Smckusick default: 147017214Smckusick sc->sc_fmesg = "unclassified failure code"; 147117214Smckusick } 147217214Smckusick break; 147317214Smckusick 147417214Smckusick /* MASSBUS fault */ 147517214Smckusick 147617214Smckusick case MTER_MBFLT: 147717214Smckusick sc->sc_mesg = "MB fault"; 147817214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 147917214Smckusick case 01: 148017214Smckusick sc->sc_fmesg = "control bus parity error"; 148117214Smckusick break; 148217214Smckusick case 02: 148317214Smckusick sc->sc_fmesg = "illegal register referenced"; 148417214Smckusick break; 148517214Smckusick default: 148617214Smckusick sc->sc_fmesg = "unclassified failure code"; 148717214Smckusick } 148817214Smckusick break; 148917214Smckusick 149017214Smckusick /* keypad entry error */ 149117214Smckusick 149217214Smckusick case MTER_KEYFAIL: 149317214Smckusick sc->sc_mesg = "keypad entry error"; 149417214Smckusick sc->sc_fmesg = ""; 149517214Smckusick break; 149617214Smckusick default: 149717214Smckusick sc->sc_mesg = "unclassified error"; 149817214Smckusick sc->sc_fmesg = ""; 149917214Smckusick break; 150017214Smckusick } 150117214Smckusick } 150217214Smckusick #endif MTLERRM 15034736Swnj #endif 1504