1*18324Sralph /* mt.c 6.4 85/03/13 */ 24736Swnj 34736Swnj #include "mu.h" 44736Swnj #if NMT > 0 54736Swnj /* 64736Swnj * TM78/TU78 tape driver 74736Swnj * 817214Smckusick * Original author - ? 917214Smckusick * Most error recovery bug fixes - ggs (ulysses!ggs) 104736Swnj * 1117214Smckusick * OPTIONS: 1217214Smckusick * MTLERRM - Long error message text - twd, Brown University 1317214Smckusick * MTRDREV - `read reverse' error recovery - ggs (ulysses!ggs) 1417214Smckusick * 154736Swnj * TODO: 1617214Smckusick * Add odd byte count kludge from VMS driver (?) 1717214Smckusick * Write dump routine 184736Swnj */ 1917214Smckusick 209789Ssam #include "../machine/pte.h" 219789Ssam 2217119Sbloom #include "param.h" 2317119Sbloom #include "systm.h" 2417119Sbloom #include "buf.h" 2517119Sbloom #include "conf.h" 2617119Sbloom #include "dir.h" 2717119Sbloom #include "file.h" 2817119Sbloom #include "user.h" 2917119Sbloom #include "map.h" 3017119Sbloom #include "ioctl.h" 3117119Sbloom #include "mtio.h" 3217119Sbloom #include "cmap.h" 3317119Sbloom #include "uio.h" 34*18324Sralph #include "tty.h" 354736Swnj 368471Sroot #include "../vax/cpu.h" 3717119Sbloom #include "mbareg.h" 3817119Sbloom #include "mbavar.h" 3917119Sbloom #include "mtreg.h" 404736Swnj 4117214Smckusick #define MTTIMEOUT 10000 /* loop limit for controller test */ 4217214Smckusick #define INF 1000000L /* a block number that won't exist */ 4317214Smckusick #define MASKREG(r) ((r) & 0xffff) /* the control registers have 16 bits */ 444736Swnj 4517214Smckusick /* Bits for sc_flags */ 464736Swnj 4717214Smckusick #define H_WRITTEN 01 /* last operation was a write */ 4817214Smckusick #define H_EOT 02 /* end of tape encountered */ 4917214Smckusick #define H_IEOT 04 /* ignore EOT condition */ 504736Swnj 5117214Smckusick /* Bits in minor device */ 5217214Smckusick 534736Swnj #define MUUNIT(dev) (minor(dev)&03) 544736Swnj #define H_NOREWIND 04 5517214Smckusick #define H_6250BPI 010 564736Swnj 574736Swnj #define MTUNIT(dev) (mutomt[MUUNIT(dev)]) 584736Swnj 5917214Smckusick #ifdef MTRDREV 6017214Smckusick int mt_do_readrev = 1; 6117214Smckusick #else 6217214Smckusick int mt_do_readrev = 0; 6317214Smckusick #endif 644736Swnj 6517214Smckusick /* Per unit status information */ 6617214Smckusick 674736Swnj struct mu_softc { 6817214Smckusick char sc_openf; /* unit is open if != 0 */ 6917214Smckusick char sc_flags; /* state flags */ 7017214Smckusick daddr_t sc_blkno; /* current physical block number */ 7117214Smckusick daddr_t sc_nxrec; /* firewall input block number */ 7217214Smckusick u_short sc_erreg; /* copy of mter or mtner */ 7317214Smckusick u_short sc_dsreg; /* copy of mtds */ 7417214Smckusick short sc_resid; /* residual function count for ioctl */ 7517214Smckusick short sc_dens; /* density code - MT_GCR or zero */ 7617214Smckusick struct mba_device *sc_mi; /* massbus structure for unit */ 7717214Smckusick int sc_slave; /* slave number for unit */ 7817214Smckusick int sc_i_mtas; /* mtas at slave attach time */ 7917214Smckusick int sc_i_mtner; /* mtner at slave attach time */ 8017214Smckusick int sc_i_mtds; /* mtds at slave attach time */ 8117214Smckusick #ifdef MTLERRM 8217214Smckusick char *sc_mesg; /* text for interrupt type code */ 8317214Smckusick char *sc_fmesg; /* text for tape error code */ 8417214Smckusick #endif 85*18324Sralph struct tty *sc_ttyp; /* record user's tty for errors */ 864736Swnj } mu_softc[NMU]; 874736Swnj 8817214Smckusick struct buf rmtbuf[NMT]; /* data transfer buffer structures */ 8917214Smckusick struct buf cmtbuf[NMT]; /* tape command buffer structures */ 904736Swnj 9117214Smckusick struct mba_device *mtinfo[NMT]; /* unit massbus structure pointers */ 9217214Smckusick short mutomt[NMU]; /* tape unit to controller number map */ 9317214Smckusick char mtds_bits[] = MTDS_BITS; /* mtds bit names for error messages */ 9417214Smckusick short mttypes[] = { MBDT_TU78, 0 }; 954736Swnj 9617214Smckusick int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint(); 9717214Smckusick struct mba_driver mtdriver = 9817214Smckusick { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint, 9917214Smckusick mttypes, "mt", "mu", mtinfo }; 10017214Smckusick 10117214Smckusick void mtcreset(); 10217214Smckusick 1034736Swnj /*ARGSUSED*/ 1044736Swnj mtattach(mi) 1054736Swnj struct mba_device *mi; 1064736Swnj { 10717214Smckusick #ifdef lint 10817214Smckusick mtread(0); mtwrite(0); mtioctl(0, 0, 0, 0); 10917214Smckusick #endif 1104736Swnj } 1114736Swnj 1127431Skre mtslave(mi, ms, sn) 1134736Swnj struct mba_device *mi; 1144736Swnj struct mba_slave *ms; 1157431Skre int sn; 1164736Swnj { 1174736Swnj register struct mu_softc *sc = &mu_softc[ms->ms_unit]; 1184736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 11917214Smckusick int s = spl7(), rtn = 0, i; 1204736Swnj 12117214Smckusick /* Just in case the controller is ill, reset it. Then issue */ 12217214Smckusick /* a sense operation and wait about a second for it to respond. */ 12317214Smckusick 12417214Smckusick mtcreset(mtaddr); 1254736Swnj mtaddr->mtas = -1; 1267431Skre mtaddr->mtncs[sn] = MT_SENSE|MT_GO; 12717214Smckusick for (i = MTTIMEOUT; i> 0; i--) { 12817214Smckusick DELAY(50); 12917214Smckusick if (MASKREG(mtaddr->mtas) != 0) 13017214Smckusick break; 13117214Smckusick } 13217214Smckusick sc->sc_i_mtas = mtaddr->mtas; 13317214Smckusick sc->sc_i_mtner = mtaddr->mtner; 13417214Smckusick sc->sc_i_mtds = mtaddr->mtds; 13517214Smckusick 13617214Smckusick /* If no response, whimper. If wrong response, call it an */ 13717214Smckusick /* unsolicited interrupt and use mtndtint to log and correct. */ 13817214Smckusick /* Otherwise, note whether this slave exists. */ 13917214Smckusick 14017214Smckusick if (i <= 0) { 14117214Smckusick printf("mt: controller hung\n"); 14217214Smckusick } else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE) { 14317214Smckusick (void) mtndtint(mi); 14417214Smckusick } else if (mtaddr->mtds & MTDS_PRES) { 1454736Swnj sc->sc_mi = mi; 1467431Skre sc->sc_slave = sn; 1474736Swnj mutomt[ms->ms_unit] = mi->mi_unit; 1484736Swnj rtn = 1; 1494736Swnj } 15017214Smckusick 15117214Smckusick /* Cancel the interrupt, then wait a little while for it to go away. */ 15217214Smckusick 1534736Swnj mtaddr->mtas = mtaddr->mtas; 15417214Smckusick DELAY(10); 1554736Swnj splx(s); 1564736Swnj return (rtn); 1574736Swnj } 1584736Swnj 1594736Swnj mtopen(dev, flag) 1604736Swnj dev_t dev; 1614736Swnj int flag; 1624736Swnj { 1634736Swnj register int muunit; 1644736Swnj register struct mba_device *mi; 1654736Swnj register struct mu_softc *sc; 1664736Swnj 1674736Swnj muunit = MUUNIT(dev); 16817214Smckusick if ( (muunit >= NMU) 16917214Smckusick || ((mi = mtinfo[MTUNIT(dev)]) == 0) 17017214Smckusick || (mi->mi_alive == 0) ) 1718581Sroot return (ENXIO); 17217214Smckusick if ((sc = &mu_softc[muunit])->sc_openf) 17317214Smckusick return (EBUSY); 17417214Smckusick sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0; 1754736Swnj mtcommand(dev, MT_SENSE, 1); 1764736Swnj if ((sc->sc_dsreg & MTDS_ONL) == 0) { 1774736Swnj uprintf("mu%d: not online\n", muunit); 1788581Sroot return (EIO); 1794736Swnj } 18017214Smckusick if ((sc->sc_dsreg & MTDS_AVAIL) == 0) { 18117214Smckusick uprintf("mu%d: not online (port selector)\n", muunit); 18217214Smckusick return (EIO); 18317214Smckusick } 18417214Smckusick if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) { 1854736Swnj uprintf("mu%d: no write ring\n", muunit); 1868581Sroot return (EIO); 1874736Swnj } 18817214Smckusick if ( ((sc->sc_dsreg & MTDS_BOT) == 0) 18917214Smckusick && (flag & FWRITE) 19017214Smckusick && ( ( (sc->sc_dens == MT_GCR) 19117214Smckusick && (sc->sc_dsreg & MTDS_PE) ) 19217214Smckusick || ( (sc->sc_dens != MT_GCR) 19317214Smckusick && ((sc->sc_dsreg & MTDS_PE) == 0)))) { 1944736Swnj uprintf("mu%d: can't change density in mid-tape\n", muunit); 1958581Sroot return (EIO); 1964736Swnj } 1974736Swnj sc->sc_openf = 1; 1984736Swnj sc->sc_blkno = (daddr_t)0; 19917214Smckusick 20017214Smckusick /* Since cooked I/O may do a read-ahead before a write, trash */ 20117214Smckusick /* on a tape can make the first write fail. Suppress the first */ 20217214Smckusick /* read-ahead unless definitely doing read-write */ 20317214Smckusick 20417214Smckusick sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) 20517214Smckusick ? (daddr_t)0 20617214Smckusick : (daddr_t)INF; 2074736Swnj sc->sc_flags = 0; 208*18324Sralph sc->sc_ttyp = u.u_ttyp; 2098581Sroot return (0); 2104736Swnj } 2114736Swnj 2124736Swnj mtclose(dev, flag) 2134736Swnj register dev_t dev; 21417214Smckusick register int flag; 2154736Swnj { 2164736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 2174736Swnj 21817214Smckusick if ( ((flag & (FREAD | FWRITE)) == FWRITE) 21917214Smckusick || ( (flag & FWRITE) 22017214Smckusick && (sc->sc_flags & H_WRITTEN) )) 2214736Swnj mtcommand(dev, MT_CLS|sc->sc_dens, 1); 22217214Smckusick if ((minor(dev) & H_NOREWIND) == 0) 2234736Swnj mtcommand(dev, MT_REW, 0); 2244736Swnj sc->sc_openf = 0; 2254736Swnj } 2264736Swnj 2274736Swnj mtcommand(dev, com, count) 2284736Swnj dev_t dev; 2294736Swnj int com, count; 2304736Swnj { 2314736Swnj register struct buf *bp; 2325437Sroot register int s; 2334736Swnj 2344736Swnj bp = &cmtbuf[MTUNIT(dev)]; 2355437Sroot s = spl5(); 23617214Smckusick while (bp->b_flags & B_BUSY) { 23717214Smckusick if((bp->b_repcnt == 0) && (bp->b_flags & B_DONE)) 2384736Swnj break; 2394736Swnj bp->b_flags |= B_WANTED; 2404736Swnj sleep((caddr_t)bp, PRIBIO); 2414736Swnj } 2424736Swnj bp->b_flags = B_BUSY|B_READ; 2435437Sroot splx(s); 2444736Swnj bp->b_dev = dev; 2454736Swnj bp->b_command = com; 2464736Swnj bp->b_repcnt = count; 2474736Swnj bp->b_blkno = 0; 24817214Smckusick bp->b_error = 0; 2494736Swnj mtstrategy(bp); 2504736Swnj if (count == 0) 2514736Swnj return; 2524736Swnj iowait(bp); 25317214Smckusick if (bp->b_flags & B_WANTED) 2544736Swnj wakeup((caddr_t)bp); 2554736Swnj bp->b_flags &= B_ERROR; 2564736Swnj } 2574736Swnj 2584736Swnj mtstrategy(bp) 2594736Swnj register struct buf *bp; 2604736Swnj { 2614736Swnj register struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)]; 2624736Swnj register struct buf *dp; 2635437Sroot register int s; 2644736Swnj 26517214Smckusick /* If this is a data transfer operation, set the resid to a */ 26617214Smckusick /* default value (EOF) to simplify getting it right during */ 26717214Smckusick /* error recovery or bail out. */ 26817214Smckusick 26917214Smckusick if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 27017214Smckusick bp->b_resid = bp->b_bcount; 27117214Smckusick 27217214Smckusick /* Link this request onto the end of the queue for this */ 27317214Smckusick /* controller, then start I/O if not already active. */ 27417214Smckusick 2754736Swnj bp->av_forw = NULL; 2764736Swnj dp = &mi->mi_tab; 2775437Sroot s = spl5(); 2784736Swnj if (dp->b_actf == NULL) 2794736Swnj dp->b_actf = bp; 2804736Swnj else 2814736Swnj dp->b_actl->av_forw = bp; 2824736Swnj dp->b_actl = bp; 2834736Swnj if (dp->b_active == 0) 2844736Swnj mbustart(mi); 2855437Sroot splx(s); 2864736Swnj } 2874736Swnj 2884736Swnj mtustart(mi) 2894736Swnj register struct mba_device *mi; 2904736Swnj { 29117214Smckusick register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 2924736Swnj register struct buf *bp = mi->mi_tab.b_actf; 2934736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 2944736Swnj daddr_t blkno; 2954736Swnj 2964736Swnj if (sc->sc_openf < 0) { 2974736Swnj bp->b_flags |= B_ERROR; 2984736Swnj return (MBU_NEXT); 2994736Swnj } 3004736Swnj if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) { 30117214Smckusick 30217214Smckusick /* Signal "no space" if out of tape unless suppressed */ 30317214Smckusick /* by MTIOCIEOT. */ 30417214Smckusick 30517214Smckusick if ( ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT) 30617214Smckusick && ((bp->b_flags & B_READ) == 0) ) { 3074736Swnj bp->b_flags |= B_ERROR; 30817214Smckusick bp->b_error = ENOSPC; 3094736Swnj return (MBU_NEXT); 3104736Swnj } 31117214Smckusick 31217214Smckusick /* special case tests for cooked mode */ 31317214Smckusick 31417214Smckusick if (bp != &rmtbuf[MTUNIT(bp->b_dev)]) { 31517214Smckusick 31617214Smckusick /* seek beyond end of file */ 31717214Smckusick 31817214Smckusick if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) { 31917214Smckusick bp->b_flags |= B_ERROR; 32017214Smckusick bp->b_error = ENXIO; 32117214Smckusick return (MBU_NEXT); 32217214Smckusick } 32317214Smckusick 32417214Smckusick /* This should be end of file, but the buffer */ 32517214Smckusick /* system wants a one-block look-ahead. Humor it. */ 32617214Smckusick 32717214Smckusick if ( (bdbtofsb(bp->b_blkno) == sc->sc_nxrec) 32817214Smckusick && (bp->b_flags & B_READ) ) { 32917214Smckusick clrbuf(bp); 33017214Smckusick return (MBU_NEXT); 33117214Smckusick } 33217214Smckusick 33317214Smckusick /* If writing, mark the next block invalid. */ 33417214Smckusick 33517214Smckusick if ((bp->b_flags & B_READ) == 0) 33617214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1; 3374736Swnj } 3384736Swnj } else { 33917214Smckusick 34017214Smckusick /* It's a command, do it now. */ 34117214Smckusick 3424736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3434736Swnj (bp->b_repcnt<<8)|bp->b_command|MT_GO; 3444736Swnj return (MBU_STARTED); 3454736Swnj } 34617214Smckusick 34717214Smckusick /* If raw I/O, or if the tape is positioned correctly for */ 34817214Smckusick /* cooked I/O, set the byte count, unit number and repeat count */ 34917214Smckusick /* then tell the MASSBUS to proceed. Note that a negative */ 35017214Smckusick /* bcount tells mbstart to map the buffer for "read backwards". */ 35117214Smckusick 35217214Smckusick if ( (bp == &rmtbuf[MTUNIT(bp->b_dev)]) 35317214Smckusick || ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) ) { 3544736Swnj if (mi->mi_tab.b_errcnt == 2) { 35517214Smckusick mtaddr->mtbc = -(bp->b_bcount); 3564736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 3574736Swnj } else { 3584736Swnj mtaddr->mtbc = bp->b_bcount; 3594736Swnj mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev); 3604736Swnj } 3614736Swnj return (MBU_DODATA); 3624736Swnj } 36317214Smckusick 36417214Smckusick /* Issue skip operations to position the next block for cooked I/O. */ 36517214Smckusick 3667380Ssam if (blkno < bdbtofsb(bp->b_blkno)) 3674736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3687380Ssam (min((unsigned)(bdbtofsb(bp->b_blkno) - blkno), 0377) << 8) | 3696186Ssam MT_SFORW|MT_GO; 3704736Swnj else 3714736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] = 3727380Ssam (min((unsigned)(blkno - bdbtofsb(bp->b_blkno)), 0377) << 8) | 3736186Ssam MT_SREV|MT_GO; 3744736Swnj return (MBU_STARTED); 3754736Swnj } 3764736Swnj 3774736Swnj mtstart(mi) 3784736Swnj register struct mba_device *mi; 3794736Swnj { 3804736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3814736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)]; 3824736Swnj 3834736Swnj if (bp->b_flags & B_READ) 3844736Swnj if (mi->mi_tab.b_errcnt == 2) 3854736Swnj return(MT_READREV|MT_GO); 3864736Swnj else 3874736Swnj return(MT_READ|MT_GO); 3884736Swnj else 3894736Swnj return(MT_WRITE|sc->sc_dens|MT_GO); 3904736Swnj } 3914736Swnj 3924736Swnj mtdtint(mi, mbsr) 3934736Swnj register struct mba_device *mi; 3944736Swnj int mbsr; 3954736Swnj { 3964736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 3974736Swnj register struct buf *bp = mi->mi_tab.b_actf; 3984736Swnj register struct mu_softc *sc; 39917214Smckusick register int er; 4004736Swnj 40117214Smckusick /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */ 40217214Smckusick 40317214Smckusick if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) { 4044736Swnj printf("mt: wrong unit!\n"); 4054736Swnj mtaddr->mtca = MUUNIT(bp->b_dev); 4064736Swnj } 40717214Smckusick 40817214Smckusick er = MASKREG(mtaddr->mter); 4094736Swnj sc = &mu_softc[MUUNIT(bp->b_dev)]; 41017214Smckusick sc->sc_erreg = er; 41117214Smckusick if (bp->b_flags & B_READ) 41217214Smckusick sc->sc_flags &= ~H_WRITTEN; 41317214Smckusick else 4144736Swnj sc->sc_flags |= H_WRITTEN; 41517214Smckusick switch (er & MTER_INTCODE) { 41617214Smckusick 41717214Smckusick case MTER_EOT: 41817214Smckusick sc->sc_flags |= H_EOT; 41917214Smckusick 42017214Smckusick /* fall into MTER_DONE */ 42117214Smckusick 4224736Swnj case MTER_DONE: 42317214Smckusick sc->sc_blkno++; 42417214Smckusick if (mi->mi_tab.b_errcnt == 2) { 42517214Smckusick bp->b_bcount = bp->b_resid; 42617214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 42717214Smckusick if ( (bp->b_resid > 0) 42817214Smckusick && (bp != &rmtbuf[MTUNIT(bp->b_dev)]) ) 42917214Smckusick bp->b_flags |= B_ERROR; 43017214Smckusick } else { 43117214Smckusick bp->b_resid = 0; 43217214Smckusick } 43317214Smckusick break; 43417214Smckusick 43517214Smckusick case MTER_SHRTREC: 43617214Smckusick sc->sc_blkno++; 43717214Smckusick bp->b_bcount = bp->b_resid; 43817214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 43917214Smckusick if (bp != &rmtbuf[MTUNIT(bp->b_dev)]) 44017214Smckusick bp->b_flags |= B_ERROR; 44117214Smckusick break; 44217214Smckusick 44317214Smckusick case MTER_RETRY: 44417214Smckusick 44517214Smckusick /* Simple re-try. Since resid is always a copy of the */ 44617214Smckusick /* original byte count, use it to restore the count. */ 44717214Smckusick 44817214Smckusick mi->mi_tab.b_errcnt = 1; 44917214Smckusick bp->b_bcount = bp->b_resid; 45017214Smckusick return(MBD_RETRY); 45117214Smckusick 45217214Smckusick case MTER_RDOPP: 45317214Smckusick 45417214Smckusick /* The controller just decided to read it backwards. */ 45517214Smckusick /* If the controller returns a byte count of zero, */ 45617214Smckusick /* change it to 1, since zero encodes 65536, which */ 45717214Smckusick /* isn't quite what we had in mind. The byte count */ 45817214Smckusick /* may be larger than the size of the input buffer, so */ 45917214Smckusick /* limit the count to the buffer size. After */ 46017214Smckusick /* making the byte count reasonable, set bcount to the */ 46117214Smckusick /* negative of the controller's version of the byte */ 46217214Smckusick /* count so that the start address for the transfer is */ 46317214Smckusick /* set up correctly. */ 46417214Smckusick 46517214Smckusick if (mt_do_readrev) { 46617214Smckusick mi->mi_tab.b_errcnt = 2; 46717214Smckusick if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0) 46817214Smckusick bp->b_bcount = 1; 46917214Smckusick if (bp->b_bcount > bp->b_resid) 47017214Smckusick bp->b_bcount = bp->b_resid; 47117214Smckusick bp->b_bcount = -(bp->b_bcount); 47217214Smckusick return(MBD_RETRY); 47317214Smckusick } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) { 47417214Smckusick sc->sc_blkno++; 47517214Smckusick bp->b_bcount = bp->b_resid; 47617214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc); 47717214Smckusick bp->b_flags |= B_ERROR; 47817214Smckusick break; 47917214Smckusick } 48017214Smckusick bp->b_flags |= B_ERROR; 48117214Smckusick 48217214Smckusick /* fall into MTER_LONGREC */ 48317214Smckusick 4844736Swnj case MTER_LONGREC: 48517214Smckusick sc->sc_blkno++; 48617214Smckusick bp->b_bcount = bp->b_resid; 4874736Swnj bp->b_resid = 0; 48817214Smckusick bp->b_error = ENOMEM; 48917214Smckusick bp->b_flags |= B_ERROR; 4904736Swnj break; 4914736Swnj 4924736Swnj case MTER_NOTCAP: 4934736Swnj printf("mu%d: blank tape\n", MUUNIT(bp->b_dev)); 4944736Swnj goto err; 4954736Swnj 4964736Swnj case MTER_TM: 49717214Smckusick 49817214Smckusick /* End of file. Since the default byte count has */ 49917214Smckusick /* already been set, just count the block and proceed. */ 50017214Smckusick 5014736Swnj sc->sc_blkno++; 5024736Swnj err: 5034736Swnj if (bp != &rmtbuf[MTUNIT(bp->b_dev)]) 50417214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno); 5054736Swnj break; 5064736Swnj 5074736Swnj case MTER_OFFLINE: 5084736Swnj if (sc->sc_openf > 0) { 5094736Swnj sc->sc_openf = -1; 510*18324Sralph tprintf(sc->sc_ttyp, "mu%d: offline\n", MUUNIT(bp->b_dev)); 5114736Swnj } 5124736Swnj bp->b_flags |= B_ERROR; 5134736Swnj break; 5144736Swnj 51517214Smckusick case MTER_NOTAVL: 51617214Smckusick if (sc->sc_openf > 0) { 51717214Smckusick sc->sc_openf = -1; 518*18324Sralph tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", 519*18324Sralph MUUNIT(bp->b_dev)); 52017214Smckusick } 52117214Smckusick bp->b_flags |= B_ERROR; 52217214Smckusick break; 52317214Smckusick 5244736Swnj case MTER_FPT: 525*18324Sralph tprintf(sc->sc_ttyp, "mu%d: no write ring\n", MUUNIT(bp->b_dev)); 5264736Swnj bp->b_flags |= B_ERROR; 5274736Swnj break; 5284736Swnj 52917214Smckusick case MTER_UNREAD: 53017214Smckusick sc->sc_blkno++; 53117214Smckusick bp->b_bcount = bp->b_resid; 53217214Smckusick bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount); 53317214Smckusick 53417214Smckusick /* Code 010 means a garbage record, nothing serious. */ 53517214Smckusick 53617214Smckusick if (((er & MTER_FAILCODE) >> 10) == 010) { 537*18324Sralph tprintf(sc->sc_ttyp, "mu%d: rn=%d bn=%d unreadable record\n", 53817214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno); 53917214Smckusick bp->b_flags |= B_ERROR; 54017214Smckusick break; 54117214Smckusick } 54217214Smckusick 54317214Smckusick /* Anything else might be a hardware problem, */ 54417214Smckusick /* fall into the error report. */ 54517214Smckusick 5464736Swnj default: 54717214Smckusick 54817214Smckusick /* The bits in sc->sc_dsreg are from the last sense */ 54917214Smckusick /* command. To get the most recent copy, you have to */ 55017214Smckusick /* do a sense at interrupt level, which requires nested */ 55117214Smckusick /* error processing. This is a bit messy, so leave */ 55217214Smckusick /* well enough alone. */ 55317214Smckusick 554*18324Sralph tprintf(sc->sc_ttyp, "mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=%o (octal) ds=%b\n", 55517214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 55617214Smckusick mbsr, mbsr_bits, er, 55717214Smckusick MASKREG(sc->sc_dsreg), mtds_bits); 55817214Smckusick #ifdef MTLERRM 55917214Smckusick mtintfail(sc); 56017214Smckusick printf(" interrupt code = %o (octal) <%s>\n failure code = %o (octal) <%s>\n", 56117214Smckusick er & MTER_INTCODE, sc->sc_mesg, 56217214Smckusick (er & MTER_FAILCODE) >> 10, sc->sc_fmesg); 56317214Smckusick #endif 5644736Swnj bp->b_flags |= B_ERROR; 56517214Smckusick 56617214Smckusick /* The TM78 manual says to reset the controller after */ 56717214Smckusick /* TM fault B or MASSBUS fault. */ 56817214Smckusick 56917214Smckusick if ( ((er & MTER_INTCODE) == MTER_TMFLTB) 57017214Smckusick || ((er & MTER_INTCODE) == MTER_MBFLT) ) { 57117214Smckusick mtcreset(mtaddr); 57217214Smckusick } 5734736Swnj } 57417214Smckusick 57517214Smckusick /* Just in case some strange error slipped through, (drive off */ 57617214Smckusick /* line during read-reverse error recovery comes to mind) make */ 57717214Smckusick /* sure the byte count is reasonable. */ 57817214Smckusick 57917214Smckusick if (bp->b_bcount < 0) 58017214Smckusick bp->b_bcount = bp->b_resid; 5814736Swnj return (MBD_DONE); 5824736Swnj } 5834736Swnj 5844736Swnj mtndtint(mi) 5854736Swnj register struct mba_device *mi; 5864736Swnj { 5874736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv; 5884736Swnj register struct buf *bp = mi->mi_tab.b_actf; 5894736Swnj register struct mu_softc *sc; 59017214Smckusick register int er, fc; 59117214Smckusick int unit; 5924736Swnj 5934736Swnj unit = (mtaddr->mtner >> 8) & 3; 5944736Swnj er = MASKREG(mtaddr->mtner); 59517214Smckusick sc = &mu_softc[unit]; 59617214Smckusick sc->sc_erreg = er; 59717214Smckusick 59817214Smckusick /* Check for unsolicited interrupts. */ 59917214Smckusick 6004736Swnj if (bp == 0 || unit != MUUNIT(bp->b_dev)) { /* consistency check */ 60117214Smckusick if ((er & MTER_INTCODE) != MTER_ONLINE) { 60217214Smckusick printf("mt: unit %d unexpected interrupt (non data transfer) er=%o (octal) ds=%b\n", 60317214Smckusick unit, er, MASKREG(sc->sc_dsreg), mtds_bits); 60417214Smckusick #ifdef MTLERRM 60517214Smckusick mtintfail(sc); 60617214Smckusick printf(" interrupt code = %o (octal) <%s>\n failure code = %o (octal) <%s>\n", 60717214Smckusick er & MTER_INTCODE, sc->sc_mesg, 60817214Smckusick (er & MTER_FAILCODE) >> 10, sc->sc_fmesg); 60917214Smckusick #endif 61017214Smckusick if ( ((er & MTER_INTCODE) == MTER_TMFLTB) 61117214Smckusick || ((er & MTER_INTCODE) == MTER_MBFLT) ) { 61217214Smckusick 61317214Smckusick /* Reset the controller, then set error */ 61417214Smckusick /* status if there was anything active */ 61517214Smckusick /* when the fault occurred. This may */ 61617214Smckusick /* shoot an innocent bystander, but */ 61717214Smckusick /* it's better than letting an error */ 61817214Smckusick /* slip through. */ 61917214Smckusick 62017214Smckusick mtcreset(mtaddr); 62117214Smckusick if (bp != 0) { 62217214Smckusick bp->b_flags |= B_ERROR; 62317214Smckusick return (MBN_DONE); 62417214Smckusick } 62517214Smckusick } 62617214Smckusick } 6274736Swnj return (MBN_SKIP); 6284736Swnj } 6294736Swnj if (bp == 0) 6304736Swnj return (MBN_SKIP); 63117214Smckusick 6324736Swnj fc = (mtaddr->mtncs[unit] >> 8) & 0xff; 6334736Swnj sc->sc_resid = fc; 63417214Smckusick 63517214Smckusick /* Clear the "written" flag after any operation that changes */ 63617214Smckusick /* the position of the tape. */ 63717214Smckusick 63817214Smckusick if ( (bp != &cmtbuf[MTUNIT(bp->b_dev)]) 63917214Smckusick || (bp->b_command != MT_SENSE) ) 64017214Smckusick sc->sc_flags &= ~H_WRITTEN; 64117214Smckusick 6424736Swnj switch (er & MTER_INTCODE) { 64317214Smckusick 64417214Smckusick case MTER_EOT: 64517214Smckusick sc->sc_flags |= H_EOT; 64617214Smckusick 64717214Smckusick /* fall into MTER_DONE */ 64817214Smckusick 6494736Swnj case MTER_DONE: 65017214Smckusick 65117214Smckusick /* If this is a command buffer, just update the status. */ 65217214Smckusick 6534736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 6544736Swnj done: 6554736Swnj if (bp->b_command == MT_SENSE) 6564736Swnj sc->sc_dsreg = MASKREG(mtaddr->mtds); 6574736Swnj return (MBN_DONE); 6584736Swnj } 65917214Smckusick 66017214Smckusick /* It's not a command buffer, must be a cooked I/O */ 66117214Smckusick /* skip operation (perhaps a shaky assumption, but it */ 66217214Smckusick /* wasn't my idea). */ 66317214Smckusick 6647380Ssam if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0) 6656186Ssam sc->sc_blkno -= MIN(0377, -fc); 6664736Swnj else 6676186Ssam sc->sc_blkno += MIN(0377, fc); 6684736Swnj return (MBN_RETRY); 6694736Swnj 67017214Smckusick case MTER_ONLINE: /* ddj -- shouldn't happen but did */ 6714736Swnj case MTER_RWDING: 6724736Swnj return (MBN_SKIP); /* ignore "rewind started" interrupt */ 6734736Swnj 6744736Swnj case MTER_NOTCAP: 675*18324Sralph tprintf(sc->sc_ttyp, "mu%d: blank tape\n", MUUNIT(bp->b_dev)); 67617214Smckusick bp->b_flags |= B_ERROR; 67717214Smckusick return (MBN_DONE); 6784736Swnj 6794736Swnj case MTER_TM: 6804736Swnj case MTER_LEOT: 68117214Smckusick 68217214Smckusick /* For an ioctl skip operation, count a tape mark as */ 68317214Smckusick /* a record. If there's anything left to do, update */ 68417214Smckusick /* the repeat count and re-start the command. */ 68517214Smckusick 68617214Smckusick if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) { 68717214Smckusick if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0) 68817214Smckusick return (MBN_DONE); 68917214Smckusick else 69017214Smckusick return (MBN_RETRY); 69117214Smckusick 69217214Smckusick /* Cooked I/O again. Just update the books and wait */ 69317214Smckusick /* for someone else to return end of file or complain */ 69417214Smckusick /* about a bad seek. */ 69517214Smckusick 69617214Smckusick } else if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) { 69717214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1; 6984736Swnj sc->sc_blkno = sc->sc_nxrec; 6994736Swnj } else { 70017214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc; 70117214Smckusick sc->sc_blkno = sc->sc_nxrec + 1; 7024736Swnj } 7034736Swnj return (MBN_RETRY); 7044736Swnj 7054736Swnj case MTER_FPT: 706*18324Sralph tprintf(sc->sc_ttyp, "mu%d: no write ring\n", MUUNIT(bp->b_dev)); 7074736Swnj bp->b_flags |= B_ERROR; 7084736Swnj return (MBN_DONE); 7094736Swnj 7104736Swnj case MTER_OFFLINE: 71117214Smckusick 71217214Smckusick /* If `off line' was intentional, don't complain. */ 71317214Smckusick 71417214Smckusick if ( (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 71517214Smckusick && (bp->b_command == MT_UNLOAD) ) 71617214Smckusick return(MBN_DONE); 7174736Swnj if (sc->sc_openf > 0) { 7184736Swnj sc->sc_openf = -1; 719*18324Sralph tprintf(sc->sc_ttyp, "mu%d: offline\n", MUUNIT(bp->b_dev)); 7204736Swnj } 7214736Swnj bp->b_flags |= B_ERROR; 7224736Swnj return (MBN_DONE); 7234736Swnj 72417214Smckusick case MTER_NOTAVL: 72517214Smckusick if (sc->sc_openf > 0) { 72617214Smckusick sc->sc_openf = -1; 727*18324Sralph tprintf(sc->sc_ttyp, "mu%d: offline (port selector)\n", MUUNIT(bp->b_dev)); 72817214Smckusick } 72917214Smckusick bp->b_flags |= B_ERROR; 73017214Smckusick return (MBN_DONE); 73117214Smckusick 7324736Swnj case MTER_BOT: 7334736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) 7344736Swnj goto done; 7354736Swnj 73617214Smckusick /* fall through */ 73717214Smckusick 7384736Swnj default: 739*18324Sralph tprintf(sc->sc_ttyp, "mu%d: hard error (non data transfer) rn=%d bn=%d er=%o (octal) ds=%b\n", 74017214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno, 74117214Smckusick er, MASKREG(sc->sc_dsreg), mtds_bits); 74217214Smckusick #ifdef MTLERRM 74317214Smckusick mtintfail(sc); 74417214Smckusick printf(" interrupt code = %o (octal) <%s>\n failure code = %o (octal) <%s>\n", 74517214Smckusick (er & MTER_INTCODE), sc->sc_mesg, 74617214Smckusick (er & MTER_FAILCODE) >> 10, sc->sc_fmesg); 74717214Smckusick #endif 74817214Smckusick if ( ((er & MTER_INTCODE) == MTER_TMFLTB) 74917214Smckusick || ((er & MTER_INTCODE) == MTER_MBFLT) ) { 75017214Smckusick mtcreset(mtaddr); /* reset the controller */ 75117214Smckusick } 7524736Swnj bp->b_flags |= B_ERROR; 7534736Swnj return (MBN_DONE); 7544736Swnj } 7554736Swnj /* NOTREACHED */ 7564736Swnj } 7574736Swnj 75817214Smckusick void mtcreset(mtaddr) 75917214Smckusick register struct mtdevice *mtaddr; 76017214Smckusick { 76117214Smckusick register int i; 76217214Smckusick 76317214Smckusick mtaddr->mtid = MTID_CLR; /* reset the TM78 */ 76417214Smckusick DELAY(200); 76517214Smckusick for (i = MTTIMEOUT; i > 0; i--) { 76617214Smckusick DELAY(50); /* don't nag */ 76717214Smckusick if ((mtaddr->mtid & MTID_RDY) != 0) 76817214Smckusick return; /* exit when ready */ 76917214Smckusick } 77017214Smckusick printf("mt: controller hung\n"); 77117214Smckusick } 77217214Smckusick 7737740Sroot mtread(dev, uio) 7744736Swnj dev_t dev; 7757740Sroot struct uio *uio; 7764736Swnj { 7778158Sroot int errno; 7784736Swnj 7798158Sroot errno = mtphys(dev, uio); 7808158Sroot if (errno) 7818158Sroot return (errno); 7828158Sroot return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_READ, minphys, uio)); 7834736Swnj } 7844736Swnj 78517214Smckusick 7867833Sroot mtwrite(dev, uio) 7877833Sroot dev_t dev; 7887833Sroot struct uio *uio; 7894736Swnj { 7908158Sroot int errno; 7914736Swnj 7928158Sroot errno = mtphys(dev, uio); 7938158Sroot if (errno) 7948158Sroot return (errno); 7958158Sroot return (physio(mtstrategy, &rmtbuf[MTUNIT(dev)], dev, B_WRITE, minphys, uio)); 7964736Swnj } 7974736Swnj 7987740Sroot mtphys(dev, uio) 7994736Swnj dev_t dev; 8007740Sroot struct uio *uio; 8014736Swnj { 8024736Swnj register int mtunit; 80317214Smckusick struct mba_device *mi; 80417214Smckusick register int bsize = uio->uio_iov->iov_len; 8054736Swnj 8064736Swnj mtunit = MTUNIT(dev); 80717214Smckusick if ( (mtunit >= NMT) 80817214Smckusick || ((mi = mtinfo[mtunit]) == 0) 80917214Smckusick || (mi->mi_alive == 0) ) 8107740Sroot return (ENXIO); 81117214Smckusick if ( (bsize > 0xffff) /* controller limit */ 81217214Smckusick || (bsize <= 0) ) /* ambiguous */ 81317214Smckusick return (EINVAL); 8147740Sroot return (0); 8154736Swnj } 8164736Swnj 8174736Swnj /*ARGSUSED*/ 8187637Ssam mtioctl(dev, cmd, data, flag) 8194736Swnj dev_t dev; 8204736Swnj int cmd; 8217637Ssam caddr_t data; 8224736Swnj int flag; 8234736Swnj { 8244736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)]; 8254736Swnj register struct buf *bp = &cmtbuf[MTUNIT(dev)]; 82617214Smckusick register struct mtop *mtop; 82717214Smckusick register struct mtget *mtget; 82817214Smckusick int callcount, fcount; 82917214Smckusick int op; 83017214Smckusick 83117214Smckusick /* We depend on the values and order of the MT codes here. */ 83217214Smckusick 8334736Swnj static mtops[] = 8344736Swnj {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE}; 8354736Swnj 8364736Swnj switch (cmd) { 8377637Ssam 83817214Smckusick /* tape operation */ 83917214Smckusick 84017214Smckusick case MTIOCTOP: 8418606Sroot mtop = (struct mtop *)data; 8428606Sroot switch (mtop->mt_op) { 8437637Ssam 8444736Swnj case MTWEOF: 8457637Ssam callcount = mtop->mt_count; 8464736Swnj fcount = 1; 8474736Swnj break; 8487637Ssam 8494736Swnj case MTFSF: case MTBSF: 8507637Ssam callcount = mtop->mt_count; 8514736Swnj fcount = 1; 8524736Swnj break; 8537637Ssam 8544736Swnj case MTFSR: case MTBSR: 8554736Swnj callcount = 1; 8567637Ssam fcount = mtop->mt_count; 8574736Swnj break; 8587637Ssam 8594736Swnj case MTREW: case MTOFFL: 8604736Swnj callcount = 1; 8614736Swnj fcount = 1; 8624736Swnj break; 8637637Ssam 8644736Swnj default: 8658581Sroot return (ENXIO); 8664736Swnj } 86717214Smckusick if ((callcount <= 0) || (fcount <= 0)) 8688581Sroot return (EINVAL); 8697637Ssam op = mtops[mtop->mt_op]; 8704736Swnj if (op == MT_WTM) 8714736Swnj op |= sc->sc_dens; 8724736Swnj while (--callcount >= 0) { 87317214Smckusick register int n, fc = fcount; 8744736Swnj 8754736Swnj do { 87617214Smckusick n = MIN(fc, 0xff); 8774736Swnj mtcommand(dev, op, n); 87817214Smckusick n -= sc->sc_resid; 87917214Smckusick fc -= n; 88017214Smckusick switch (mtop->mt_op) { 88117214Smckusick 88217214Smckusick case MTWEOF: 88317214Smckusick sc->sc_blkno += (daddr_t)n; 88417214Smckusick sc->sc_nxrec = sc->sc_blkno - 1; 88517214Smckusick break; 88617214Smckusick 88717214Smckusick case MTOFFL: 88817214Smckusick case MTREW: 88917214Smckusick case MTFSF: 89017214Smckusick sc->sc_blkno = (daddr_t)0; 89117214Smckusick sc->sc_nxrec = (daddr_t)INF; 89217214Smckusick break; 89317214Smckusick 89417214Smckusick case MTBSF: 89517214Smckusick if (sc->sc_resid) { 89617214Smckusick sc->sc_blkno = (daddr_t)0; 89717214Smckusick sc->sc_nxrec = (daddr_t)INF; 89817214Smckusick } else { 89917214Smckusick sc->sc_blkno = (daddr_t)(-1); 90017214Smckusick sc->sc_nxrec = (daddr_t)(-1); 90117214Smckusick } 90217214Smckusick break; 90317214Smckusick 90417214Smckusick case MTFSR: 90517214Smckusick sc->sc_blkno += (daddr_t)n; 90617214Smckusick break; 90717214Smckusick 90817214Smckusick case MTBSR: 90917214Smckusick sc->sc_blkno -= (daddr_t)n; 91017214Smckusick break; 91117214Smckusick } 91217214Smckusick if (sc->sc_resid) 91317214Smckusick break; 91417214Smckusick } while (fc); 91517214Smckusick if (fc) { 91617214Smckusick sc->sc_resid = callcount + fc; 91717214Smckusick if ( (mtop->mt_op == MTFSR) 91817214Smckusick || (mtop->mt_op == MTBSR) ) 91917214Smckusick return (EIO); 92017214Smckusick else 92117214Smckusick break; 92217214Smckusick } 92317214Smckusick if (bp->b_flags & B_ERROR) 9244736Swnj break; 9254736Swnj } 9268712Sroot return (geterror(bp)); 9277637Ssam 92817214Smckusick /* tape status */ 92917214Smckusick 9304736Swnj case MTIOCGET: 9317637Ssam mtget = (struct mtget *)data; 9327637Ssam mtget->mt_erreg = sc->sc_erreg; 9337637Ssam mtget->mt_resid = sc->sc_resid; 9344736Swnj mtcommand(dev, MT_SENSE, 1); /* update drive status */ 9357637Ssam mtget->mt_dsreg = sc->sc_dsreg; 9367637Ssam mtget->mt_type = MT_ISMT; 9378581Sroot break; 9387637Ssam 93917214Smckusick /* ignore EOT condition */ 94017214Smckusick 94117214Smckusick case MTIOCIEOT: 94217214Smckusick sc->sc_flags |= H_IEOT; 94317214Smckusick break; 94417214Smckusick 94517214Smckusick /* enable EOT condition */ 94617214Smckusick 94717214Smckusick case MTIOCEEOT: 94817214Smckusick sc->sc_flags &= ~H_IEOT; 94917214Smckusick break; 95017214Smckusick 9514736Swnj default: 9528581Sroot return (ENXIO); 9534736Swnj } 9548581Sroot return (0); 9554736Swnj } 9564736Swnj 9574736Swnj #define DBSIZE 20 9584736Swnj 9594736Swnj mtdump() 9604736Swnj { 9614736Swnj register struct mba_device *mi; 9624736Swnj register struct mba_regs *mp; 9634736Swnj int blk, num; 9644736Swnj int start; 9654736Swnj 9664736Swnj start = 0; 9674736Swnj num = maxfree; 9684736Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff)) 9694736Swnj if (mtinfo[0] == 0) 9704736Swnj return (ENXIO); 9714736Swnj mi = phys(mtinfo[0], struct mba_device *); 9724736Swnj mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba; 9734736Swnj mp->mba_cr = MBCR_IE; 9746186Ssam #if lint 9758606Sroot blk = 0; num = blk; start = num; blk = start; 9766186Ssam return (0); 9776186Ssam #endif 9786186Ssam #ifdef notyet 9794736Swnj mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive]; 9804736Swnj mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI; 9814736Swnj mtaddr->mtcs1 = MT_DCLR|MT_GO; 9824736Swnj while (num > 0) { 9834736Swnj blk = num > DBSIZE ? DBSIZE : num; 9844736Swnj mtdwrite(start, blk, mtaddr, mp); 9854736Swnj start += blk; 9864736Swnj num -= blk; 9874736Swnj } 9884736Swnj mteof(mtaddr); 9894736Swnj mteof(mtaddr); 9904736Swnj mtwait(mtaddr); 9914736Swnj if (mtaddr->mtds&MTDS_ERR) 9924736Swnj return (EIO); 9934736Swnj mtaddr->mtcs1 = MT_REW|MT_GO; 9944736Swnj return (0); 9954736Swnj } 9964736Swnj 9974736Swnj mtdwrite(dbuf, num, mtaddr, mp) 9984736Swnj register dbuf, num; 9994736Swnj register struct mtdevice *mtaddr; 10004736Swnj struct mba_regs *mp; 10014736Swnj { 10024736Swnj register struct pte *io; 10034736Swnj register int i; 10044736Swnj 10054736Swnj mtwait(mtaddr); 10064736Swnj io = mp->mba_map; 10074736Swnj for (i = 0; i < num; i++) 10084736Swnj *(int *)io++ = dbuf++ | PG_V; 10094736Swnj mtaddr->mtfc = -(num*NBPG); 10104736Swnj mp->mba_sr = -1; 10114736Swnj mp->mba_bcr = -(num*NBPG); 10124736Swnj mp->mba_var = 0; 10134736Swnj mtaddr->mtcs1 = MT_WCOM|MT_GO; 10144736Swnj } 10154736Swnj 10164736Swnj mtwait(mtaddr) 10174736Swnj struct mtdevice *mtaddr; 10184736Swnj { 10194736Swnj register s; 10204736Swnj 10214736Swnj do 10224736Swnj s = mtaddr->mtds; 10234736Swnj while ((s & MTDS_DRY) == 0); 10244736Swnj } 10254736Swnj 10264736Swnj mteof(mtaddr) 10274736Swnj struct mtdevice *mtaddr; 10284736Swnj { 10294736Swnj 10304736Swnj mtwait(mtaddr); 10314736Swnj mtaddr->mtcs1 = MT_WEOF|MT_GO; 10324736Swnj #endif notyet 10334736Swnj } 103417214Smckusick 103517214Smckusick #ifdef MTLERRM 103617214Smckusick mtintfail(sc) 103717214Smckusick register struct mu_softc *sc; 103817214Smckusick { 103917214Smckusick switch (sc->sc_erreg & MTER_INTCODE) { 104017214Smckusick 104117214Smckusick /* unexpected BOT detected */ 104217214Smckusick 104317214Smckusick case MTER_BOT: 104417214Smckusick sc->sc_mesg = "unexpected BOT"; 104517214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 104617214Smckusick case 01: 104717214Smckusick sc->sc_fmesg = "tape was at BOT"; 104817214Smckusick break; 104917214Smckusick case 02: 105017214Smckusick sc->sc_fmesg = "BOT seen after tape started"; 105117214Smckusick break; 105217214Smckusick case 03: 105317214Smckusick sc->sc_fmesg = "ARA ID detected"; 105417214Smckusick break; 105517214Smckusick default: 105617214Smckusick sc->sc_fmesg = "unclassified failure code"; 105717214Smckusick } 105817214Smckusick break; 105917214Smckusick 106017214Smckusick /* unexpected LEOT detected */ 106117214Smckusick 106217214Smckusick case MTER_LEOT: 106317214Smckusick sc->sc_mesg = "unexpected LEOT"; 106417214Smckusick sc->sc_fmesg = ""; 106517214Smckusick break; 106617214Smckusick 106717214Smckusick /* rewinding */ 106817214Smckusick 106917214Smckusick case MTER_RWDING: 107017214Smckusick sc->sc_mesg = "tape rewinding"; 107117214Smckusick sc->sc_fmesg = ""; 107217214Smckusick break; 107317214Smckusick 107417214Smckusick /* not ready */ 107517214Smckusick 107617214Smckusick case MTER_NOTRDY: 107717214Smckusick sc->sc_mesg = "drive not ready"; 107817214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 107917214Smckusick case 01: 108017214Smckusick sc->sc_fmesg = "TU on-line but not ready"; 108117214Smckusick break; 108217214Smckusick case 02: 108317214Smckusick sc->sc_fmesg = "fatal error has occurred"; 108417214Smckusick break; 108517214Smckusick case 03: 108617214Smckusick sc->sc_fmesg = "access allowed but not really"; 108717214Smckusick break; 108817214Smckusick default: 108917214Smckusick sc->sc_fmesg = "unclassified failure code"; 109017214Smckusick } 109117214Smckusick break; 109217214Smckusick 109317214Smckusick /* not available */ 109417214Smckusick 109517214Smckusick case MTER_NOTAVL: 109617214Smckusick sc->sc_mesg = "drive not available"; 109717214Smckusick sc->sc_fmesg = ""; 109817214Smckusick break; 109917214Smckusick 110017214Smckusick /* unit does not exist */ 110117214Smckusick 110217214Smckusick case MTER_NONEX: 110317214Smckusick sc->sc_mesg = "unit does not exist"; 110417214Smckusick sc->sc_fmesg = ""; 110517214Smckusick break; 110617214Smckusick 110717214Smckusick /* not capable */ 110817214Smckusick 110917214Smckusick case MTER_NOTCAP: 111017214Smckusick sc->sc_mesg = "not capable"; 111117214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 111217214Smckusick case 01: 111317214Smckusick sc->sc_fmesg = "no record found within 25 feet"; 111417214Smckusick break; 111517214Smckusick case 02: 111617214Smckusick sc->sc_fmesg = "ID burst neither PE nor GCR"; 111717214Smckusick break; 111817214Smckusick case 03: 111917214Smckusick sc->sc_fmesg = "ARA ID not found"; 112017214Smckusick break; 112117214Smckusick case 04: 112217214Smckusick sc->sc_fmesg = "no gap found after ID burst"; 112317214Smckusick break; 112417214Smckusick default: 112517214Smckusick sc->sc_fmesg = "unclassified failure code"; 112617214Smckusick } 112717214Smckusick break; 112817214Smckusick 112917214Smckusick /* long tape record */ 113017214Smckusick 113117214Smckusick case MTER_LONGREC: 113217214Smckusick sc->sc_mesg = "long record"; 113317214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 113417214Smckusick case 00: 113517214Smckusick sc->sc_fmesg = "extended sense data not found"; 113617214Smckusick break; 113717214Smckusick case 01: 113817214Smckusick sc->sc_fmesg = "extended sense data updated"; 113917214Smckusick break; 114017214Smckusick default: 114117214Smckusick sc->sc_fmesg = "unclassified failure code"; 114217214Smckusick } 114317214Smckusick break; 114417214Smckusick 114517214Smckusick /* unreadable */ 114617214Smckusick 114717214Smckusick case MTER_UNREAD: 114817214Smckusick sc->sc_mesg = "unreadable record"; 114917214Smckusick goto code22; 115017214Smckusick 115117214Smckusick /* error */ 115217214Smckusick 115317214Smckusick case MTER_ERROR: 115417214Smckusick sc->sc_mesg = "error"; 115517214Smckusick goto code22; 115617214Smckusick 115717214Smckusick /* EOT error */ 115817214Smckusick 115917214Smckusick case MTER_EOTERR: 116017214Smckusick sc->sc_mesg = "EOT error"; 116117214Smckusick goto code22; 116217214Smckusick 116317214Smckusick /* tape position lost */ 116417214Smckusick 116517214Smckusick case MTER_BADTAPE: 116617214Smckusick sc->sc_mesg = "bad tape"; 116717214Smckusick code22: 116817214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 116917214Smckusick case 01: 117017214Smckusick sc->sc_fmesg = "GCR write error"; 117117214Smckusick break; 117217214Smckusick case 02: 117317214Smckusick sc->sc_fmesg = "GCR read error"; 117417214Smckusick break; 117517214Smckusick case 03: 117617214Smckusick sc->sc_fmesg = "PE read error"; 117717214Smckusick break; 117817214Smckusick case 04: 117917214Smckusick sc->sc_fmesg = "PE write error"; 118017214Smckusick break; 118117214Smckusick case 05: 118217214Smckusick sc->sc_fmesg = "at least 1 bit set in ECCSTA"; 118317214Smckusick break; 118417214Smckusick case 06: 118517214Smckusick sc->sc_fmesg = "PE write error"; 118617214Smckusick break; 118717214Smckusick case 07: 118817214Smckusick sc->sc_fmesg = "GCR write error"; 118917214Smckusick break; 119017214Smckusick case 010: 119117214Smckusick sc->sc_fmesg = "RSTAT contains bad code"; 119217214Smckusick break; 119317214Smckusick case 011: 119417214Smckusick sc->sc_fmesg = "PE write error"; 119517214Smckusick break; 119617214Smckusick case 012: 119717214Smckusick sc->sc_fmesg = "MASSBUS parity error"; 119817214Smckusick break; 119917214Smckusick case 013: 120017214Smckusick sc->sc_fmesg = "invalid data transferred"; 120117214Smckusick break; 120217214Smckusick default: 120317214Smckusick sc->sc_fmesg = "unclassified failure code"; 120417214Smckusick } 120517214Smckusick break; 120617214Smckusick 120717214Smckusick /* TM fault A */ 120817214Smckusick 120917214Smckusick case MTER_TMFLTA: 121017214Smckusick sc->sc_mesg = "TM fault A"; 121117214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 121217214Smckusick case 01: 121317214Smckusick sc->sc_fmesg = "illegal command code"; 121417214Smckusick break; 121517214Smckusick case 02: 121617214Smckusick sc->sc_fmesg = "DT command issued when NDT command active"; 121717214Smckusick break; 121817214Smckusick case 03: 121917214Smckusick sc->sc_fmesg = "WMC error"; 122017214Smckusick break; 122117214Smckusick case 04: 122217214Smckusick sc->sc_fmesg = "RUN not received from MASSBUS controller"; 122317214Smckusick break; 122417214Smckusick case 05: 122517214Smckusick sc->sc_fmesg = "mismatch in command read - function routine"; 122617214Smckusick break; 122717214Smckusick case 06: 122817214Smckusick sc->sc_fmesg = "ECC ROM parity error"; 122917214Smckusick break; 123017214Smckusick case 07: 123117214Smckusick sc->sc_fmesg = "XMC ROM parity error"; 123217214Smckusick break; 123317214Smckusick case 010: 123417214Smckusick sc->sc_fmesg = "mismatch in command read - ID burst command"; 123517214Smckusick break; 123617214Smckusick case 011: 123717214Smckusick sc->sc_fmesg = "mismatch in command read - verify ARA burst command"; 123817214Smckusick break; 123917214Smckusick case 012: 124017214Smckusick sc->sc_fmesg = "mismatch in command read - verify ARA ID command"; 124117214Smckusick break; 124217214Smckusick case 013: 124317214Smckusick sc->sc_fmesg = "mismatch in command read - verify gap command"; 124417214Smckusick break; 124517214Smckusick case 014: 124617214Smckusick sc->sc_fmesg = "mismatch in command read - read id burst command"; 124717214Smckusick break; 124817214Smckusick case 015: 124917214Smckusick sc->sc_fmesg = "mismatch in command read - verify ARA ID command"; 125017214Smckusick break; 125117214Smckusick case 016: 125217214Smckusick sc->sc_fmesg = "mismatch in command read - verify gap command"; 125317214Smckusick break; 125417214Smckusick case 017: 125517214Smckusick sc->sc_fmesg = "mismatch in command read - find gap command"; 125617214Smckusick break; 125717214Smckusick case 020: 125817214Smckusick sc->sc_fmesg = "WMC LEFT failed to set"; 125917214Smckusick break; 126017214Smckusick case 021: 126117214Smckusick sc->sc_fmesg = "XL PE set in INTSTA register"; 126217214Smckusick break; 126317214Smckusick case 022: 126417214Smckusick sc->sc_fmesg = "XMC DONE did not set"; 126517214Smckusick break; 126617214Smckusick case 023: 126717214Smckusick sc->sc_fmesg = "WMC ROM PE or RD PE set in WMCERR register"; 126817214Smckusick break; 126917214Smckusick default: 127017214Smckusick sc->sc_fmesg = "unclassified failure code"; 127117214Smckusick } 127217214Smckusick break; 127317214Smckusick 127417214Smckusick /* TU fault A */ 127517214Smckusick 127617214Smckusick case MTER_TUFLTA: 127717214Smckusick sc->sc_mesg = "TU fault A"; 127817214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 127917214Smckusick case 01: 128017214Smckusick sc->sc_fmesg = "TU status parity error"; 128117214Smckusick break; 128217214Smckusick case 02: 128317214Smckusick sc->sc_fmesg = "TU command parity error"; 128417214Smckusick break; 128517214Smckusick case 03: 128617214Smckusick sc->sc_fmesg = "rewinding tape went offline"; 128717214Smckusick break; 128817214Smckusick case 04: 128917214Smckusick sc->sc_fmesg = "tape went not ready during DSE"; 129017214Smckusick break; 129117214Smckusick case 05: 129217214Smckusick sc->sc_fmesg = "TU CMD status changed during DSE"; 129317214Smckusick break; 129417214Smckusick case 06: 129517214Smckusick sc->sc_fmesg = "TU never came up to speed"; 129617214Smckusick break; 129717214Smckusick case 07: 129817214Smckusick sc->sc_fmesg = "TU velocity changed"; 129917214Smckusick break; 130017214Smckusick case 010: 130117214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion"; 130217214Smckusick break; 130317214Smckusick case 011: 130417214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set drive density"; 130517214Smckusick break; 130617214Smckusick case 012: 130717214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion to write BOT ID"; 130817214Smckusick break; 130917214Smckusick case 013: 131017214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID"; 131117214Smckusick break; 131217214Smckusick case 014: 131317214Smckusick sc->sc_fmesg = "failed to write density ID burst"; 131417214Smckusick break; 131517214Smckusick case 015: 131617214Smckusick sc->sc_fmesg = "failed to write ARA burst"; 131717214Smckusick break; 131817214Smckusick case 016: 131917214Smckusick sc->sc_fmesg = "failed to write ARA ID"; 132017214Smckusick break; 132117214Smckusick case 017: 132217214Smckusick sc->sc_fmesg = "ARA error bit set in MTA status B register"; 132317214Smckusick break; 132417214Smckusick case 021: 132517214Smckusick sc->sc_fmesg = "could not find a gap after ID code was written correctly"; 132617214Smckusick break; 132717214Smckusick case 022: 132817214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion to read ID burst"; 132917214Smckusick break; 133017214Smckusick case 023: 133117214Smckusick sc->sc_fmesg = "timeout looking for BOT after detecting ARA ID burst"; 133217214Smckusick break; 133317214Smckusick case 024: 133417214Smckusick sc->sc_fmesg = "failed to write tape mark"; 133517214Smckusick break; 133617214Smckusick case 025: 133717214Smckusick sc->sc_fmesg = "tape never came up to speed while trying to reposition for retry of writing tape mark"; 133817214Smckusick break; 133917214Smckusick case 026: 134017214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to start tape motion in erase gap routine"; 134117214Smckusick break; 134217214Smckusick case 027: 134317214Smckusick sc->sc_fmesg = "could not detect a gap in in erase gap routine"; 134417214Smckusick break; 134517214Smckusick case 030: 134617214Smckusick sc->sc_fmesg = "could not detect a gap after writing record"; 134717214Smckusick break; 134817214Smckusick case 031: 134917214Smckusick sc->sc_fmesg = "read path terminated before entire record was written"; 135017214Smckusick break; 135117214Smckusick case 032: 135217214Smckusick sc->sc_fmesg = "could not find a gap after writing record and read path terminated early"; 135317214Smckusick break; 135417214Smckusick case 033: 135517214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to backup for retry of write tape mark"; 135617214Smckusick break; 135717214Smckusick case 034: 135817214Smckusick sc->sc_fmesg = "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark"; 135917214Smckusick break; 136017214Smckusick case 035: 136117214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to backup to retry a load of BOT ID"; 136217214Smckusick break; 136317214Smckusick case 036: 136417214Smckusick sc->sc_fmesg = "timeout looking for BOT after failing to write BOT ID"; 136517214Smckusick break; 136617214Smckusick case 037: 136717214Smckusick sc->sc_fmesg = "TU velocity changed while writing PE gap before starting to write record"; 136817214Smckusick break; 136917214Smckusick case 040: 137017214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst"; 137117214Smckusick break; 137217214Smckusick case 041: 137317214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set GCR tape density after writing Density ID"; 137417214Smckusick break; 137517214Smckusick case 042: 137617214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set PE tape density at start of read from BOT"; 137717214Smckusick break; 137817214Smckusick case 043: 137917214Smckusick sc->sc_fmesg = "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst"; 138017214Smckusick break; 138117214Smckusick default: 138217214Smckusick sc->sc_fmesg = "unclassified failure code"; 138317214Smckusick } 138417214Smckusick break; 138517214Smckusick 138617214Smckusick /* TM fault B */ 138717214Smckusick 138817214Smckusick case MTER_TMFLTB: 138917214Smckusick sc->sc_mesg = "TM fault B"; 139017214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 139117214Smckusick case 00: 139217214Smckusick sc->sc_fmesg = "RST0 interrupt occurred with TM RDY set"; 139317214Smckusick break; 139417214Smckusick case 01: 139517214Smckusick sc->sc_fmesg = "power failed to interrupt"; 139617214Smckusick break; 139717214Smckusick case 02: 139817214Smckusick sc->sc_fmesg = "unknown interrupt on channel 5.5"; 139917214Smckusick break; 140017214Smckusick case 03: 140117214Smckusick sc->sc_fmesg = "unknown interrupt on channel 6.5"; 140217214Smckusick break; 140317214Smckusick case 04: 140417214Smckusick sc->sc_fmesg = "unknown interrupt on channel 7"; 140517214Smckusick break; 140617214Smckusick case 05: 140717214Smckusick sc->sc_fmesg = "unknown interrupt on channel 7.5"; 140817214Smckusick break; 140917214Smckusick case 06: 141017214Smckusick sc->sc_fmesg = "CAS contention retry count expired"; 141117214Smckusick break; 141217214Smckusick case 07: 141317214Smckusick sc->sc_fmesg = "CAS contention error not retryable"; 141417214Smckusick break; 141517214Smckusick case 010: 141617214Smckusick sc->sc_fmesg = "queue error, could not find queue entry"; 141717214Smckusick break; 141817214Smckusick case 011: 141917214Smckusick sc->sc_fmesg = "queue entry already full"; 142017214Smckusick break; 142117214Smckusick case 012: 142217214Smckusick sc->sc_fmesg = "8085 ROM parity error"; 142317214Smckusick break; 142417214Smckusick case 013: 142517214Smckusick case 014: 142617214Smckusick case 015: 142717214Smckusick case 016: 142817214Smckusick case 017: 142917214Smckusick case 020: 143017214Smckusick case 021: 143117214Smckusick case 022: 143217214Smckusick case 023: 143317214Smckusick case 024: 143417214Smckusick case 025: 143517214Smckusick case 026: 143617214Smckusick case 027: 143717214Smckusick case 030: 143817214Smckusick case 031: 143917214Smckusick case 032: 144017214Smckusick case 033: 144117214Smckusick case 034: 144217214Smckusick case 035: 144317214Smckusick case 036: 144417214Smckusick case 037: 144517214Smckusick case 040: 144617214Smckusick case 041: 144717214Smckusick case 042: 144817214Smckusick case 043: 144917214Smckusick case 044: 145017214Smckusick case 045: 145117214Smckusick case 046: 145217214Smckusick case 047: 145317214Smckusick case 050: 145417214Smckusick case 051: 145517214Smckusick case 052: 145617214Smckusick case 053: 145717214Smckusick case 054: 145817214Smckusick case 055: 145917214Smckusick case 056: 146017214Smckusick case 057: 146117214Smckusick sc->sc_fmesg = "inline test failed"; 146217214Smckusick break; 146317214Smckusick default: 146417214Smckusick sc->sc_fmesg = "unclassified failure code"; 146517214Smckusick } 146617214Smckusick break; 146717214Smckusick 146817214Smckusick /* MASSBUS fault */ 146917214Smckusick 147017214Smckusick case MTER_MBFLT: 147117214Smckusick sc->sc_mesg = "MB fault"; 147217214Smckusick switch ((sc->sc_erreg & MTER_FAILCODE) >> 10) { 147317214Smckusick case 01: 147417214Smckusick sc->sc_fmesg = "control bus parity error"; 147517214Smckusick break; 147617214Smckusick case 02: 147717214Smckusick sc->sc_fmesg = "illegal register referenced"; 147817214Smckusick break; 147917214Smckusick default: 148017214Smckusick sc->sc_fmesg = "unclassified failure code"; 148117214Smckusick } 148217214Smckusick break; 148317214Smckusick 148417214Smckusick /* keypad entry error */ 148517214Smckusick 148617214Smckusick case MTER_KEYFAIL: 148717214Smckusick sc->sc_mesg = "keypad entry error"; 148817214Smckusick sc->sc_fmesg = ""; 148917214Smckusick break; 149017214Smckusick default: 149117214Smckusick sc->sc_mesg = "unclassified error"; 149217214Smckusick sc->sc_fmesg = ""; 149317214Smckusick break; 149417214Smckusick } 149517214Smckusick } 149617214Smckusick #endif MTLERRM 14974736Swnj #endif 1498