149439Sbostic /*-
249439Sbostic * Copyright (c) 1982, 1986 The Regents of the University of California.
349439Sbostic * All rights reserved.
423315Smckusick *
549439Sbostic * %sccs.include.proprietary.c%
649439Sbostic *
7*64634Sbostic * @(#)mt.c 7.11 (Berkeley) 09/23/93
823315Smckusick */
94736Swnj
104736Swnj #include "mu.h"
114736Swnj #if NMT > 0
124736Swnj /*
134736Swnj * TM78/TU78 tape driver
144736Swnj *
1517214Smckusick * Original author - ?
1617214Smckusick * Most error recovery bug fixes - ggs (ulysses!ggs)
1734221Sbostic * `read reverse' error recovery - ggs (ulysses!ggs)
184736Swnj *
1917214Smckusick * OPTIONS:
2017214Smckusick * MTLERRM - Long error message text - twd, Brown University
2117214Smckusick *
224736Swnj * TODO:
2317214Smckusick * Add odd byte count kludge from VMS driver (?)
2417214Smckusick * Write dump routine
254736Swnj */
2617214Smckusick
2745802Sbostic #include "sys/param.h"
2845802Sbostic #include "sys/systm.h"
2945802Sbostic #include "sys/buf.h"
3045802Sbostic #include "sys/conf.h"
3145802Sbostic #include "sys/file.h"
3245802Sbostic #include "sys/user.h"
3345802Sbostic #include "sys/proc.h"
3445802Sbostic #include "sys/map.h"
3545802Sbostic #include "sys/ioctl.h"
3645802Sbostic #include "sys/mtio.h"
3745802Sbostic #include "sys/cmap.h"
3845802Sbostic #include "sys/tty.h"
3945802Sbostic #include "sys/syslog.h"
404736Swnj
4145802Sbostic #include "../include/pte.h"
4245802Sbostic #include "../include/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
5734221Sbostic int mt_do_readrev = 1;
5817214Smckusick
5917214Smckusick /* Per unit status information */
6017214Smckusick
614736Swnj struct mu_softc {
6234221Sbostic char sc_openf; /* unit is open if != 0 */
6334221Sbostic char sc_flags; /* state flags */
6434221Sbostic daddr_t sc_blkno; /* current physical block number */
6534221Sbostic daddr_t sc_nxrec; /* firewall input block number */
6634221Sbostic u_short sc_erreg; /* copy of mter or mtner */
6734221Sbostic u_short sc_dsreg; /* copy of mtds */
6834221Sbostic short sc_resid; /* residual function count for ioctl */
6934221Sbostic short sc_dens; /* density code - MT_GCR or zero */
7034221Sbostic int sc_i_mtas; /* mtas at slave attach time */
7134221Sbostic int sc_i_mtner; /* mtner at slave attach time */
7234221Sbostic int sc_i_mtds; /* mtds at slave attach time */
7340899Ssklower caddr_t sc_ctty; /* record user's tty for errors */
7434221Sbostic int sc_blks; /* number of I/O operations since open */
7534221Sbostic int sc_softerrs; /* number of soft I/O errors since open */
764736Swnj } mu_softc[NMU];
774736Swnj
7817214Smckusick struct buf cmtbuf[NMT]; /* tape command buffer structures */
794736Swnj
8034221Sbostic struct mba_device *mtinfo[NMT]; /* unit to ctlr structures */
8134221Sbostic struct mba_slave *muinfo[NMU]; /* unit to slave structures */
8234221Sbostic
8317214Smckusick char mtds_bits[] = MTDS_BITS; /* mtds bit names for error messages */
8417214Smckusick short mttypes[] = { MBDT_TU78, 0 };
854736Swnj
8617214Smckusick int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
8717214Smckusick struct mba_driver mtdriver =
8817214Smckusick { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
8917214Smckusick mttypes, "mt", "mu", mtinfo };
9017214Smckusick
9134221Sbostic /* Bits in minor device */
9234221Sbostic #define MUUNIT(dev) (minor(dev)&03)
9334221Sbostic #define H_NOREWIND 04
9434221Sbostic #define H_6250BPI 010
9517214Smckusick
9634221Sbostic #define MTUNIT(dev) (muinfo[MUUNIT(dev)]->ms_ctlr)
9734221Sbostic
9834221Sbostic void mtcreset();
9934221Sbostic
1004736Swnj /*ARGSUSED*/
1014736Swnj mtattach(mi)
1024736Swnj struct mba_device *mi;
1034736Swnj {
10434221Sbostic
10534221Sbostic /* void */
1064736Swnj }
1074736Swnj
1087431Skre mtslave(mi, ms, sn)
1094736Swnj struct mba_device *mi;
1104736Swnj struct mba_slave *ms;
1117431Skre int sn;
1124736Swnj {
1134736Swnj register struct mu_softc *sc = &mu_softc[ms->ms_unit];
1144736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
11526377Skarels int s = spl5(), rtn = 0, i;
1164736Swnj
11734221Sbostic /*
11834221Sbostic * Just in case the controller is ill, reset it. Then issue
11934221Sbostic * a sense operation and wait about a second for it to respond.
12034221Sbostic */
12117214Smckusick mtcreset(mtaddr);
1224736Swnj mtaddr->mtas = -1;
1237431Skre mtaddr->mtncs[sn] = MT_SENSE|MT_GO;
12434221Sbostic for (i = MTTIMEOUT; i > 0; i--) {
12517214Smckusick DELAY(50);
12617214Smckusick if (MASKREG(mtaddr->mtas) != 0)
12717214Smckusick break;
12817214Smckusick }
12917214Smckusick sc->sc_i_mtas = mtaddr->mtas;
13017214Smckusick sc->sc_i_mtner = mtaddr->mtner;
13117214Smckusick sc->sc_i_mtds = mtaddr->mtds;
13217214Smckusick
13334221Sbostic /*
13434221Sbostic * If no response, whimper. If wrong response, call it an
13534221Sbostic * unsolicited interrupt and use mtndtint to log and correct.
13634221Sbostic * Otherwise, note whether this slave exists.
13734221Sbostic */
13834221Sbostic if (i <= 0)
13917214Smckusick printf("mt: controller hung\n");
14034221Sbostic else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE)
14117214Smckusick (void) mtndtint(mi);
14234654Skarels else if (mtaddr->mtds & MTDS_PRES) {
14334654Skarels muinfo[ms->ms_unit] = ms;
1444736Swnj rtn = 1;
14534654Skarels }
14617214Smckusick
14734221Sbostic /* cancel the interrupt, then wait a little while for it to go away */
1484736Swnj mtaddr->mtas = mtaddr->mtas;
14917214Smckusick DELAY(10);
1504736Swnj splx(s);
1514736Swnj return (rtn);
1524736Swnj }
1534736Swnj
mtopen(dev,flag)1544736Swnj mtopen(dev, flag)
1554736Swnj dev_t dev;
1564736Swnj int flag;
1574736Swnj {
1584736Swnj register int muunit;
1594736Swnj register struct mu_softc *sc;
16034221Sbostic register struct mba_slave *ms;
1614736Swnj
1624736Swnj muunit = MUUNIT(dev);
16334221Sbostic if (muunit >= NMU || (ms = muinfo[muunit]) == NULL ||
16434221Sbostic ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0)
1658581Sroot return (ENXIO);
16617214Smckusick if ((sc = &mu_softc[muunit])->sc_openf)
16717214Smckusick return (EBUSY);
16834221Sbostic sc->sc_openf = 1;
16917214Smckusick sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0;
1704736Swnj mtcommand(dev, MT_SENSE, 1);
1714736Swnj if ((sc->sc_dsreg & MTDS_ONL) == 0) {
1724736Swnj uprintf("mu%d: not online\n", muunit);
17334221Sbostic sc->sc_openf = 0;
1748581Sroot return (EIO);
1754736Swnj }
17617214Smckusick if ((sc->sc_dsreg & MTDS_AVAIL) == 0) {
17717214Smckusick uprintf("mu%d: not online (port selector)\n", muunit);
17834221Sbostic sc->sc_openf = 0;
17917214Smckusick return (EIO);
18017214Smckusick }
18117214Smckusick if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) {
1824736Swnj uprintf("mu%d: no write ring\n", muunit);
18334221Sbostic sc->sc_openf = 0;
1848581Sroot return (EIO);
1854736Swnj }
18634221Sbostic if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) &&
18734221Sbostic (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) {
1884736Swnj uprintf("mu%d: can't change density in mid-tape\n", muunit);
18934221Sbostic sc->sc_openf = 0;
1908581Sroot return (EIO);
1914736Swnj }
1924736Swnj sc->sc_blkno = (daddr_t)0;
19317214Smckusick
19434221Sbostic /*
19534221Sbostic * Since cooked I/O may do a read-ahead before a write, trash
19634221Sbostic * on a tape can make the first write fail. Suppress the first
19734221Sbostic * read-ahead unless definitely doing read-write.
19834221Sbostic */
19934221Sbostic sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ?
20034221Sbostic (daddr_t)0 : (daddr_t)INF;
2014736Swnj sc->sc_flags = 0;
20234221Sbostic sc->sc_blks = 0;
20334221Sbostic sc->sc_softerrs = 0;
204*64634Sbostic sc->sc_ctty = (caddr_t)(u.u_procp->p_flag & P_CONTROLT ?
205*64634Sbostic u.u_procp->p_session->s_ttyp : 0);
2068581Sroot return (0);
2074736Swnj }
2084736Swnj
mtclose(dev,flag)2094736Swnj mtclose(dev, flag)
2104736Swnj register dev_t dev;
21117214Smckusick register int flag;
2124736Swnj {
2134736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
2144736Swnj
21534221Sbostic if ((flag & (FREAD | FWRITE)) == FWRITE ||
21634221Sbostic ((flag & FWRITE) && (sc->sc_flags & H_WRITTEN)))
2174736Swnj mtcommand(dev, MT_CLS|sc->sc_dens, 1);
21817214Smckusick if ((minor(dev) & H_NOREWIND) == 0)
2194736Swnj mtcommand(dev, MT_REW, 0);
22034221Sbostic if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
22134221Sbostic log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n",
22234221Sbostic MUUNIT(dev), sc->sc_softerrs, sc->sc_blks);
2234736Swnj sc->sc_openf = 0;
22440733Skarels return (0);
2254736Swnj }
2264736Swnj
mtcommand(dev,com,count)2274736Swnj mtcommand(dev, com, count)
2284736Swnj dev_t dev;
2294736Swnj int com, count;
2304736Swnj {
2314736Swnj register struct buf *bp;
23234221Sbostic int s;
2334736Swnj
2344736Swnj bp = &cmtbuf[MTUNIT(dev)];
2355437Sroot s = spl5();
23617214Smckusick while (bp->b_flags & B_BUSY) {
23734221Sbostic 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;
25234221Sbostic biowait(bp);
25317214Smckusick if (bp->b_flags & B_WANTED)
2544736Swnj wakeup((caddr_t)bp);
2554736Swnj bp->b_flags &= B_ERROR;
2564736Swnj }
2574736Swnj
mtstrategy(bp)2584736Swnj mtstrategy(bp)
2594736Swnj register struct buf *bp;
2604736Swnj {
2614736Swnj register struct buf *dp;
26234221Sbostic struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
26334221Sbostic int s;
2644736Swnj
26534221Sbostic /*
26634221Sbostic * If this is a data transfer operation, set the resid to a
26734221Sbostic * default value (EOF) to simplify getting it right during
26834221Sbostic * error recovery or bail out.
26934221Sbostic */
27017214Smckusick if (bp != &cmtbuf[MTUNIT(bp->b_dev)])
27117214Smckusick bp->b_resid = bp->b_bcount;
27217214Smckusick
27334221Sbostic /*
27434221Sbostic * Link this request onto the end of the queue for this
27534221Sbostic * controller, then start I/O if not already active.
27634221Sbostic */
2774736Swnj bp->av_forw = NULL;
2784736Swnj dp = &mi->mi_tab;
2795437Sroot s = spl5();
2804736Swnj if (dp->b_actf == NULL)
2814736Swnj dp->b_actf = bp;
2824736Swnj else
2834736Swnj dp->b_actl->av_forw = bp;
2844736Swnj dp->b_actl = bp;
2854736Swnj if (dp->b_active == 0)
2864736Swnj mbustart(mi);
2875437Sroot splx(s);
2884736Swnj }
2894736Swnj
mtustart(mi)2904736Swnj mtustart(mi)
2914736Swnj register struct mba_device *mi;
2924736Swnj {
29317214Smckusick register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
2944736Swnj register struct buf *bp = mi->mi_tab.b_actf;
2954736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
2964736Swnj daddr_t blkno;
29726377Skarels int count;
2984736Swnj
2994736Swnj if (sc->sc_openf < 0) {
3004736Swnj bp->b_flags |= B_ERROR;
3014736Swnj return (MBU_NEXT);
3024736Swnj }
3034736Swnj if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
30434221Sbostic /*
30534221Sbostic * Data transfer. If write at end of tape,
30634221Sbostic * signal "no space" unless suppressed
30734221Sbostic * by MTIOCIEOT.
30834221Sbostic */
30934221Sbostic if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT &&
31034221Sbostic (bp->b_flags & B_READ) == 0) {
3114736Swnj bp->b_flags |= B_ERROR;
31217214Smckusick bp->b_error = ENOSPC;
3134736Swnj return (MBU_NEXT);
3144736Swnj }
31517214Smckusick
31634221Sbostic if (bp->b_flags & B_RAW) {
31734221Sbostic /* raw transfer; never seek */
31834221Sbostic sc->sc_blkno = bdbtofsb(bp->b_blkno);
31934221Sbostic sc->sc_nxrec = sc->sc_blkno + 1;
32034221Sbostic } else {
32117214Smckusick /* seek beyond end of file */
32217214Smckusick if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
32317214Smckusick bp->b_flags |= B_ERROR;
32417214Smckusick bp->b_error = ENXIO;
32517214Smckusick return (MBU_NEXT);
32617214Smckusick }
32717214Smckusick
32834221Sbostic /*
32934221Sbostic * This should be end of file, but the buffer
33034221Sbostic * system wants a one-block look-ahead. Humor it.
33134221Sbostic */
33234221Sbostic if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
33334221Sbostic bp->b_flags & B_READ) {
33434221Sbostic bp->b_resid = bp->b_bcount;
33517214Smckusick clrbuf(bp);
33617214Smckusick return (MBU_NEXT);
33717214Smckusick }
33817214Smckusick
33917214Smckusick /* If writing, mark the next block invalid. */
34017214Smckusick if ((bp->b_flags & B_READ) == 0)
34117214Smckusick sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
3424736Swnj }
3434736Swnj } else {
34417214Smckusick /* It's a command, do it now. */
3454736Swnj mtaddr->mtncs[MUUNIT(bp->b_dev)] =
3464736Swnj (bp->b_repcnt<<8)|bp->b_command|MT_GO;
3474736Swnj return (MBU_STARTED);
3484736Swnj }
34917214Smckusick
35034221Sbostic /*
35134221Sbostic * If raw I/O, or if the tape is positioned correctly for
35234221Sbostic * cooked I/O, set the byte count, unit number and repeat count
35334221Sbostic * then tell the MASSBUS to proceed. Note that a negative
35434221Sbostic * bcount tells mbstart to map the buffer for "read backwards".
35534221Sbostic */
35634221Sbostic if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
3574736Swnj if (mi->mi_tab.b_errcnt == 2) {
35834221Sbostic mtaddr->mtbc = -bp->b_bcount;
3594736Swnj mtaddr->mtca = MUUNIT(bp->b_dev);
3604736Swnj } else {
3614736Swnj mtaddr->mtbc = bp->b_bcount;
3624736Swnj mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
3634736Swnj }
3644736Swnj return (MBU_DODATA);
3654736Swnj }
36617214Smckusick
36717214Smckusick /* Issue skip operations to position the next block for cooked I/O. */
36817214Smckusick
3697380Ssam if (blkno < bdbtofsb(bp->b_blkno))
37034221Sbostic count = bdbtofsb(bp->b_blkno) - blkno;
3714736Swnj else
37234221Sbostic count = blkno - bdbtofsb(bp->b_blkno);
37334221Sbostic if ((unsigned)count > 0377)
37426377Skarels count = 0377;
37526377Skarels mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO;
3764736Swnj return (MBU_STARTED);
3774736Swnj }
3784736Swnj
mtstart(mi)3794736Swnj mtstart(mi)
3804736Swnj register struct mba_device *mi;
3814736Swnj {
3824736Swnj register struct buf *bp = mi->mi_tab.b_actf;
3834736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
3844736Swnj
3854736Swnj if (bp->b_flags & B_READ)
3864736Swnj if (mi->mi_tab.b_errcnt == 2)
38734221Sbostic return (MT_READREV|MT_GO);
3884736Swnj else
38934221Sbostic return (MT_READ|MT_GO);
3904736Swnj else
39134221Sbostic return (MT_WRITE|sc->sc_dens|MT_GO);
3924736Swnj }
3934736Swnj
mtdtint(mi,mbsr)3944736Swnj mtdtint(mi, mbsr)
3954736Swnj register struct mba_device *mi;
3964736Swnj int mbsr;
3974736Swnj {
3984736Swnj register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
3994736Swnj register struct buf *bp = mi->mi_tab.b_actf;
4004736Swnj register struct mu_softc *sc;
40117214Smckusick register int er;
4024736Swnj
40317214Smckusick /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
40417214Smckusick if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) {
4054736Swnj printf("mt: wrong unit!\n");
4064736Swnj mtaddr->mtca = MUUNIT(bp->b_dev);
4074736Swnj }
40817214Smckusick
40917214Smckusick er = MASKREG(mtaddr->mter);
4104736Swnj sc = &mu_softc[MUUNIT(bp->b_dev)];
41117214Smckusick sc->sc_erreg = er;
41217214Smckusick if (bp->b_flags & B_READ)
41317214Smckusick sc->sc_flags &= ~H_WRITTEN;
41417214Smckusick else
4154736Swnj sc->sc_flags |= H_WRITTEN;
41617214Smckusick switch (er & MTER_INTCODE) {
41717214Smckusick
41817214Smckusick case MTER_EOT:
41917214Smckusick sc->sc_flags |= H_EOT;
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);
42734221Sbostic if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0)
42817214Smckusick bp->b_flags |= B_ERROR;
42934221Sbostic } else
43017214Smckusick bp->b_resid = 0;
43117214Smckusick break;
43217214Smckusick
43317214Smckusick case MTER_SHRTREC:
43417214Smckusick sc->sc_blkno++;
43517214Smckusick bp->b_bcount = bp->b_resid;
43617214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc);
43734221Sbostic if ((bp->b_flags & B_RAW) == 0)
43817214Smckusick bp->b_flags |= B_ERROR;
43917214Smckusick break;
44017214Smckusick
44117214Smckusick case MTER_RETRY:
44234221Sbostic /*
44334221Sbostic * Simple re-try. Since resid is always a copy of the
44434221Sbostic * original byte count, use it to restore the count.
44534221Sbostic */
44617214Smckusick mi->mi_tab.b_errcnt = 1;
44717214Smckusick bp->b_bcount = bp->b_resid;
44834221Sbostic return (MBD_RETRY);
44917214Smckusick
45017214Smckusick case MTER_RDOPP:
45134221Sbostic /*
45234221Sbostic * The controller just decided to read it backwards.
45334221Sbostic * If the controller returns a byte count of zero,
45434221Sbostic * change it to 1, since zero encodes 65536, which
45534221Sbostic * isn't quite what we had in mind. The byte count
45634221Sbostic * may be larger than the size of the input buffer, so
45734221Sbostic * limit the count to the buffer size. After
45834221Sbostic * making the byte count reasonable, set bcount to the
45934221Sbostic * negative of the controller's version of the byte
46034221Sbostic * count so that the start address for the transfer is
46134221Sbostic * set up correctly.
46234221Sbostic */
46317214Smckusick if (mt_do_readrev) {
46417214Smckusick mi->mi_tab.b_errcnt = 2;
46517214Smckusick if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0)
46617214Smckusick bp->b_bcount = 1;
46717214Smckusick if (bp->b_bcount > bp->b_resid)
46817214Smckusick bp->b_bcount = bp->b_resid;
46917214Smckusick bp->b_bcount = -(bp->b_bcount);
47017214Smckusick return(MBD_RETRY);
47117214Smckusick } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) {
47217214Smckusick sc->sc_blkno++;
47317214Smckusick bp->b_bcount = bp->b_resid;
47417214Smckusick bp->b_resid -= MASKREG(mtaddr->mtbc);
47517214Smckusick bp->b_flags |= B_ERROR;
47617214Smckusick break;
47717214Smckusick }
47817214Smckusick bp->b_flags |= B_ERROR;
47917214Smckusick /* fall into MTER_LONGREC */
48017214Smckusick
4814736Swnj case MTER_LONGREC:
48217214Smckusick sc->sc_blkno++;
48317214Smckusick bp->b_bcount = bp->b_resid;
4844736Swnj bp->b_resid = 0;
48517214Smckusick bp->b_error = ENOMEM;
48617214Smckusick bp->b_flags |= B_ERROR;
4874736Swnj break;
4884736Swnj
4894736Swnj case MTER_NOTCAP:
4904736Swnj printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
4914736Swnj goto err;
4924736Swnj
4934736Swnj case MTER_TM:
49434221Sbostic /*
49534221Sbostic * End of file. Since the default byte count has
49634221Sbostic * already been set, just count the block and proceed.
49734221Sbostic */
4984736Swnj sc->sc_blkno++;
4994736Swnj err:
50034221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno);
5014736Swnj break;
5024736Swnj
5034736Swnj case MTER_OFFLINE:
5044736Swnj if (sc->sc_openf > 0) {
5054736Swnj sc->sc_openf = -1;
50640899Ssklower tprintf(sc->sc_ctty, "mu%d: offline\n",
50734221Sbostic MUUNIT(bp->b_dev));
5084736Swnj }
5094736Swnj bp->b_flags |= B_ERROR;
5104736Swnj break;
5114736Swnj
51217214Smckusick case MTER_NOTAVL:
51317214Smckusick if (sc->sc_openf > 0) {
51417214Smckusick sc->sc_openf = -1;
51540899Ssklower tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n",
51618324Sralph MUUNIT(bp->b_dev));
51717214Smckusick }
51817214Smckusick bp->b_flags |= B_ERROR;
51917214Smckusick break;
52017214Smckusick
5214736Swnj case MTER_FPT:
52240899Ssklower tprintf(sc->sc_ctty, "mu%d: no write ring\n",
52334221Sbostic MUUNIT(bp->b_dev));
5244736Swnj bp->b_flags |= B_ERROR;
5254736Swnj break;
5264736Swnj
52717214Smckusick case MTER_UNREAD:
52817214Smckusick sc->sc_blkno++;
52917214Smckusick bp->b_bcount = bp->b_resid;
53017214Smckusick bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount);
53117214Smckusick
53234221Sbostic /* code 010 means a garbage record, nothing serious. */
53334221Sbostic if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) {
53440899Ssklower tprintf(sc->sc_ctty,
53534221Sbostic "mu%d: rn=%d bn=%d unreadable record\n",
53617214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno);
53717214Smckusick bp->b_flags |= B_ERROR;
53817214Smckusick break;
53917214Smckusick }
54017214Smckusick
54134221Sbostic /*
54234221Sbostic * Anything else might be a hardware problem,
54334221Sbostic * fall into the error report.
54434221Sbostic */
54517214Smckusick
5464736Swnj default:
54734221Sbostic /*
54834221Sbostic * The bits in sc->sc_dsreg are from the last sense
54934221Sbostic * command. To get the most recent copy, you have to
55034221Sbostic * do a sense at interrupt level, which requires nested
55134221Sbostic * error processing. This is a bit messy, so leave
55234221Sbostic * well enough alone.
55334221Sbostic */
55440899Ssklower tprintf(sc->sc_ctty, "\
55534221Sbostic mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n",
55617214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
55717214Smckusick mbsr, mbsr_bits, er,
55817214Smckusick MASKREG(sc->sc_dsreg), mtds_bits);
55917214Smckusick #ifdef MTLERRM
56034221Sbostic mtintfail(er);
56117214Smckusick #endif
5624736Swnj bp->b_flags |= B_ERROR;
56317214Smckusick
56434221Sbostic /*
56534221Sbostic * The TM78 manual says to reset the controller after
56634221Sbostic * TM fault B or MASSBUS fault.
56734221Sbostic */
56834221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB ||
56934221Sbostic (er & MTER_INTCODE) == MTER_MBFLT)
57017214Smckusick mtcreset(mtaddr);
5714736Swnj }
57217214Smckusick
57334221Sbostic /*
57434221Sbostic * Just in case some strange error slipped through (drive off
57534221Sbostic * line during read-reverse error recovery comes to mind), make
57634221Sbostic * sure the byte count is reasonable.
57734221Sbostic */
57817214Smckusick if (bp->b_bcount < 0)
57917214Smckusick bp->b_bcount = bp->b_resid;
58034221Sbostic
58134221Sbostic if ((bp->b_flags & B_ERROR) == 0) {
58234221Sbostic /* this counts reverse reads as soft errors */
58334221Sbostic sc->sc_blks++;
58434221Sbostic if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */
58534221Sbostic sc->sc_softerrs++;
58634221Sbostic }
5874736Swnj return (MBD_DONE);
5884736Swnj }
5894736Swnj
mtndtint(mi)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. */
60534221Sbostic if (bp == NULL || unit != MUUNIT(bp->b_dev)) {
60634221Sbostic if ((er & MTER_INTCODE) == MTER_ONLINE)
60734221Sbostic return (MBN_SKIP);
60817214Smckusick
60934221Sbostic printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n",
61034221Sbostic unit, er, MASKREG(sc->sc_dsreg), mtds_bits);
61117214Smckusick #ifdef MTLERRM
61234221Sbostic mtintfail(er);
61317214Smckusick #endif
61434221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB ||
61534221Sbostic (er & MTER_INTCODE) == MTER_MBFLT) {
61634221Sbostic /*
61734221Sbostic * Reset the controller, then set error status
61834221Sbostic * if there was anything active when the fault
61934221Sbostic * occurred. This may shoot an innocent
62034221Sbostic * bystander, but it's better than letting
62134221Sbostic * an error slip through.
62234221Sbostic */
62334221Sbostic mtcreset(mtaddr);
62434221Sbostic if (bp != NULL) {
62534221Sbostic bp->b_flags |= B_ERROR;
62634221Sbostic return (MBN_DONE);
62717214Smckusick }
62817214Smckusick }
6294736Swnj return (MBN_SKIP);
6304736Swnj }
63117214Smckusick
6324736Swnj fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
6334736Swnj sc->sc_resid = fc;
63417214Smckusick
63534221Sbostic /*
63634221Sbostic * Clear the "written" flag after any operation that changes
63734221Sbostic * the position of the tape.
63834221Sbostic */
63934221Sbostic if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || 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 /* fall into MTER_DONE */
64717214Smckusick
6484736Swnj case MTER_DONE:
64917214Smckusick /* If this is a command buffer, just update the status. */
6504736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
6514736Swnj done:
6524736Swnj if (bp->b_command == MT_SENSE)
6534736Swnj sc->sc_dsreg = MASKREG(mtaddr->mtds);
6544736Swnj return (MBN_DONE);
6554736Swnj }
65617214Smckusick
65734221Sbostic /*
65834221Sbostic * It's not a command buffer, must be a cooked I/O
65934221Sbostic * skip operation (perhaps a shaky assumption, but it
66034221Sbostic * wasn't my idea).
66134221Sbostic */
6627380Ssam if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
6636186Ssam sc->sc_blkno -= MIN(0377, -fc);
6644736Swnj else
6656186Ssam sc->sc_blkno += MIN(0377, fc);
6664736Swnj return (MBN_RETRY);
6674736Swnj
66817214Smckusick case MTER_ONLINE: /* ddj -- shouldn't happen but did */
6694736Swnj case MTER_RWDING:
6704736Swnj return (MBN_SKIP); /* ignore "rewind started" interrupt */
6714736Swnj
6724736Swnj case MTER_NOTCAP:
67340899Ssklower tprintf(sc->sc_ctty, "mu%d: blank tape\n", MUUNIT(bp->b_dev));
67417214Smckusick bp->b_flags |= B_ERROR;
67517214Smckusick return (MBN_DONE);
6764736Swnj
6774736Swnj case MTER_TM:
6784736Swnj case MTER_LEOT:
67934221Sbostic /*
68034221Sbostic * For an ioctl skip operation, count a tape mark as
68134221Sbostic * a record. If there's anything left to do, update
68234221Sbostic * the repeat count and re-start the command.
68334221Sbostic */
68417214Smckusick if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
68517214Smckusick if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0)
68617214Smckusick return (MBN_DONE);
68717214Smckusick else
68817214Smckusick return (MBN_RETRY);
6894736Swnj } else {
69034221Sbostic /*
69134221Sbostic * Cooked I/O again. Just update the books and
69234221Sbostic * wait for someone else to return end of file or
69334221Sbostic * complain about a bad seek.
69434221Sbostic */
69534221Sbostic if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
69634221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1;
69734221Sbostic sc->sc_blkno = sc->sc_nxrec;
69834221Sbostic } else {
69934221Sbostic sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc;
70034221Sbostic sc->sc_blkno = sc->sc_nxrec + 1;
70134221Sbostic }
7024736Swnj }
7034736Swnj return (MBN_RETRY);
7044736Swnj
7054736Swnj case MTER_FPT:
70640899Ssklower tprintf(sc->sc_ctty, "mu%d: no write ring\n",
70734221Sbostic MUUNIT(bp->b_dev));
7084736Swnj bp->b_flags |= B_ERROR;
7094736Swnj return (MBN_DONE);
7104736Swnj
7114736Swnj case MTER_OFFLINE:
71217214Smckusick /* If `off line' was intentional, don't complain. */
71334221Sbostic if (bp == &cmtbuf[MTUNIT(bp->b_dev)] &&
71434221Sbostic bp->b_command == MT_UNLOAD)
71517214Smckusick return(MBN_DONE);
7164736Swnj if (sc->sc_openf > 0) {
7174736Swnj sc->sc_openf = -1;
71840899Ssklower tprintf(sc->sc_ctty, "mu%d: offline\n",
71934221Sbostic 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;
72740899Ssklower tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n",
72834221Sbostic MUUNIT(bp->b_dev));
72917214Smckusick }
73017214Smckusick bp->b_flags |= B_ERROR;
73117214Smckusick return (MBN_DONE);
73217214Smckusick
7334736Swnj case MTER_BOT:
7344736Swnj if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
7354736Swnj goto done;
73617214Smckusick /* fall through */
73717214Smckusick
7384736Swnj default:
73940899Ssklower tprintf(sc->sc_ctty, "\
74034221Sbostic mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n",
74117214Smckusick MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
74217214Smckusick er, MASKREG(sc->sc_dsreg), mtds_bits);
74317214Smckusick #ifdef MTLERRM
74434221Sbostic mtintfail(er);
74517214Smckusick #endif
74634221Sbostic if ((er & MTER_INTCODE) == MTER_TMFLTB ||
74734221Sbostic (er & MTER_INTCODE) == MTER_MBFLT)
74817214Smckusick mtcreset(mtaddr); /* reset the controller */
7494736Swnj bp->b_flags |= B_ERROR;
7504736Swnj return (MBN_DONE);
7514736Swnj }
7524736Swnj /* NOTREACHED */
7534736Swnj }
7544736Swnj
75534221Sbostic void
mtcreset(mtaddr)75634221Sbostic mtcreset(mtaddr)
75717214Smckusick register struct mtdevice *mtaddr;
75817214Smckusick {
75917214Smckusick register int i;
76017214Smckusick
76117214Smckusick mtaddr->mtid = MTID_CLR; /* reset the TM78 */
76217214Smckusick DELAY(200);
76317214Smckusick for (i = MTTIMEOUT; i > 0; i--) {
76417214Smckusick DELAY(50); /* don't nag */
76517214Smckusick if ((mtaddr->mtid & MTID_RDY) != 0)
76617214Smckusick return; /* exit when ready */
76717214Smckusick }
76817214Smckusick printf("mt: controller hung\n");
76917214Smckusick }
77017214Smckusick
7714736Swnj /*ARGSUSED*/
mtioctl(dev,cmd,data,flag)7727637Ssam mtioctl(dev, cmd, data, flag)
7734736Swnj dev_t dev;
7744736Swnj int cmd;
7757637Ssam caddr_t data;
7764736Swnj int flag;
7774736Swnj {
7784736Swnj register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
7794736Swnj register struct buf *bp = &cmtbuf[MTUNIT(dev)];
78017214Smckusick register struct mtop *mtop;
78117214Smckusick register struct mtget *mtget;
78240909Ssklower int callcount, fcount, error = 0;
78317214Smckusick int op;
78417214Smckusick
78517214Smckusick /* We depend on the values and order of the MT codes here. */
78617214Smckusick
7874736Swnj static mtops[] =
7884736Swnj {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
7894736Swnj
7904736Swnj switch (cmd) {
7917637Ssam
79217214Smckusick /* tape operation */
79317214Smckusick
79417214Smckusick case MTIOCTOP:
7958606Sroot mtop = (struct mtop *)data;
7968606Sroot switch (mtop->mt_op) {
7977637Ssam
7984736Swnj case MTWEOF:
7997637Ssam callcount = mtop->mt_count;
8004736Swnj fcount = 1;
8014736Swnj break;
8027637Ssam
8034736Swnj case MTFSF: case MTBSF:
8047637Ssam callcount = mtop->mt_count;
8054736Swnj fcount = 1;
8064736Swnj break;
8077637Ssam
8084736Swnj case MTFSR: case MTBSR:
8094736Swnj callcount = 1;
8107637Ssam fcount = mtop->mt_count;
8114736Swnj break;
8127637Ssam
8134736Swnj case MTREW: case MTOFFL:
8144736Swnj callcount = 1;
8154736Swnj fcount = 1;
8164736Swnj break;
8177637Ssam
8184736Swnj default:
8198581Sroot return (ENXIO);
8204736Swnj }
82134221Sbostic if (callcount <= 0 || fcount <= 0)
8228581Sroot return (EINVAL);
8237637Ssam op = mtops[mtop->mt_op];
8244736Swnj if (op == MT_WTM)
8254736Swnj op |= sc->sc_dens;
8264736Swnj while (--callcount >= 0) {
82717214Smckusick register int n, fc = fcount;
8284736Swnj
8294736Swnj do {
83017214Smckusick n = MIN(fc, 0xff);
8314736Swnj mtcommand(dev, op, n);
83217214Smckusick n -= sc->sc_resid;
83317214Smckusick fc -= n;
83417214Smckusick switch (mtop->mt_op) {
83517214Smckusick
83617214Smckusick case MTWEOF:
83717214Smckusick sc->sc_blkno += (daddr_t)n;
83817214Smckusick sc->sc_nxrec = sc->sc_blkno - 1;
83917214Smckusick break;
84017214Smckusick
84117214Smckusick case MTOFFL:
84217214Smckusick case MTREW:
84317214Smckusick case MTFSF:
84417214Smckusick sc->sc_blkno = (daddr_t)0;
84517214Smckusick sc->sc_nxrec = (daddr_t)INF;
84617214Smckusick break;
84717214Smckusick
84817214Smckusick case MTBSF:
84917214Smckusick if (sc->sc_resid) {
85017214Smckusick sc->sc_blkno = (daddr_t)0;
85117214Smckusick sc->sc_nxrec = (daddr_t)INF;
85217214Smckusick } else {
85317214Smckusick sc->sc_blkno = (daddr_t)(-1);
85417214Smckusick sc->sc_nxrec = (daddr_t)(-1);
85517214Smckusick }
85617214Smckusick break;
85717214Smckusick
85817214Smckusick case MTFSR:
85917214Smckusick sc->sc_blkno += (daddr_t)n;
86017214Smckusick break;
86117214Smckusick
86217214Smckusick case MTBSR:
86317214Smckusick sc->sc_blkno -= (daddr_t)n;
86417214Smckusick break;
86517214Smckusick }
86617214Smckusick if (sc->sc_resid)
86717214Smckusick break;
86817214Smckusick } while (fc);
86917214Smckusick if (fc) {
87017214Smckusick sc->sc_resid = callcount + fc;
87134221Sbostic if (mtop->mt_op == MTFSR ||
87234221Sbostic mtop->mt_op == MTBSR)
87317214Smckusick return (EIO);
87434221Sbostic break;
87517214Smckusick }
87617214Smckusick if (bp->b_flags & B_ERROR)
8774736Swnj break;
8784736Swnj }
87940909Ssklower if (bp->b_flags&B_ERROR)
88040909Ssklower if ((error = bp->b_error)==0)
88140909Ssklower return (EIO);
88240909Ssklower return (error);
8837637Ssam
88417214Smckusick /* tape status */
8854736Swnj case MTIOCGET:
8867637Ssam mtget = (struct mtget *)data;
8877637Ssam mtget->mt_erreg = sc->sc_erreg;
8887637Ssam mtget->mt_resid = sc->sc_resid;
8894736Swnj mtcommand(dev, MT_SENSE, 1); /* update drive status */
8907637Ssam mtget->mt_dsreg = sc->sc_dsreg;
8917637Ssam mtget->mt_type = MT_ISMT;
8928581Sroot break;
8937637Ssam
89417214Smckusick /* ignore EOT condition */
89517214Smckusick case MTIOCIEOT:
89617214Smckusick sc->sc_flags |= H_IEOT;
89717214Smckusick break;
89817214Smckusick
89917214Smckusick /* enable EOT condition */
90017214Smckusick case MTIOCEEOT:
90117214Smckusick sc->sc_flags &= ~H_IEOT;
90217214Smckusick break;
90317214Smckusick
9044736Swnj default:
9058581Sroot return (ENXIO);
9064736Swnj }
9078581Sroot return (0);
9084736Swnj }
9094736Swnj
9104736Swnj #define DBSIZE 20
9114736Swnj
mtdump()9124736Swnj mtdump()
9134736Swnj {
9144736Swnj register struct mba_device *mi;
9154736Swnj register struct mba_regs *mp;
9164736Swnj int blk, num;
9174736Swnj int start;
9184736Swnj
9194736Swnj start = 0;
9204736Swnj num = maxfree;
9214736Swnj #define phys(a,b) ((b)((int)(a)&0x7fffffff))
9224736Swnj if (mtinfo[0] == 0)
9234736Swnj return (ENXIO);
9244736Swnj mi = phys(mtinfo[0], struct mba_device *);
9254736Swnj mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
9264736Swnj mp->mba_cr = MBCR_IE;
9276186Ssam #if lint
9288606Sroot blk = 0; num = blk; start = num; blk = start;
9296186Ssam return (0);
9306186Ssam #endif
9316186Ssam #ifdef notyet
9324736Swnj mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
9334736Swnj mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
9344736Swnj mtaddr->mtcs1 = MT_DCLR|MT_GO;
9354736Swnj while (num > 0) {
9364736Swnj blk = num > DBSIZE ? DBSIZE : num;
9374736Swnj mtdwrite(start, blk, mtaddr, mp);
9384736Swnj start += blk;
9394736Swnj num -= blk;
9404736Swnj }
9414736Swnj mteof(mtaddr);
9424736Swnj mteof(mtaddr);
9434736Swnj mtwait(mtaddr);
9444736Swnj if (mtaddr->mtds&MTDS_ERR)
9454736Swnj return (EIO);
9464736Swnj mtaddr->mtcs1 = MT_REW|MT_GO;
9474736Swnj return (0);
9484736Swnj }
9494736Swnj
mtdwrite(dbuf,num,mtaddr,mp)9504736Swnj mtdwrite(dbuf, num, mtaddr, mp)
9514736Swnj register dbuf, num;
9524736Swnj register struct mtdevice *mtaddr;
9534736Swnj struct mba_regs *mp;
9544736Swnj {
9554736Swnj register struct pte *io;
9564736Swnj register int i;
9574736Swnj
9584736Swnj mtwait(mtaddr);
9594736Swnj io = mp->mba_map;
9604736Swnj for (i = 0; i < num; i++)
9614736Swnj *(int *)io++ = dbuf++ | PG_V;
9624736Swnj mtaddr->mtfc = -(num*NBPG);
9634736Swnj mp->mba_sr = -1;
9644736Swnj mp->mba_bcr = -(num*NBPG);
9654736Swnj mp->mba_var = 0;
9664736Swnj mtaddr->mtcs1 = MT_WCOM|MT_GO;
9674736Swnj }
9684736Swnj
9694736Swnj mtwait(mtaddr)
9704736Swnj struct mtdevice *mtaddr;
9714736Swnj {
9724736Swnj register s;
9734736Swnj
9744736Swnj do
9754736Swnj s = mtaddr->mtds;
9764736Swnj while ((s & MTDS_DRY) == 0);
9774736Swnj }
9784736Swnj
9794736Swnj mteof(mtaddr)
9804736Swnj struct mtdevice *mtaddr;
9814736Swnj {
9824736Swnj
9834736Swnj mtwait(mtaddr);
9844736Swnj mtaddr->mtcs1 = MT_WEOF|MT_GO;
9854736Swnj #endif notyet
9864736Swnj }
98717214Smckusick
98817214Smckusick #ifdef MTLERRM
98934221Sbostic /*
99034221Sbostic * Failure messages for each failure code, per interrupt code.
99134221Sbostic * Each table ends with a code of -1 as a default.
99234221Sbostic */
99334221Sbostic struct fmesg {
99434221Sbostic int f_code;
99534221Sbostic char *f_mesg;
99634221Sbostic };
99717214Smckusick
99834221Sbostic static char unclass[] = "unclassified failure code";
99917214Smckusick
100034221Sbostic /* MTER_BOT */
100134221Sbostic static struct fmesg botmsg[] = {
100234221Sbostic 01, "tape was at BOT",
100334221Sbostic 02, "BOT seen after tape started",
100434221Sbostic 03, "ARA ID detected",
100534221Sbostic -1, unclass
100634221Sbostic };
100717214Smckusick
100834221Sbostic /* MTER_NOTRDY */
100934221Sbostic static struct fmesg notrdymsg[] = {
101034221Sbostic 01, "TU on-line but not ready",
101134221Sbostic 02, "fatal error has occurred",
101236548Sbostic 03, "access allowed but not ready",
101334221Sbostic -1, unclass
101434221Sbostic };
101517214Smckusick
101634221Sbostic /* MTER_NOTCAP */
101734221Sbostic static struct fmesg notcapmsg[] = {
101834221Sbostic 01, "no record found within 25 feet",
101934221Sbostic 02, "ID burst neither PE nor GCR",
102034221Sbostic 03, "ARA ID not found",
102134221Sbostic 04, "no gap found after ID burst",
102234221Sbostic -1, unclass
102334221Sbostic };
102417214Smckusick
102534221Sbostic /* MTER_LONGREC */
102634221Sbostic static struct fmesg longrecmsg[] = {
102734221Sbostic 00, "extended sense data not found",
102834221Sbostic 01, "extended sense data updated",
102934221Sbostic -1, unclass
103034221Sbostic };
103117214Smckusick
103234221Sbostic /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */
103334221Sbostic static struct fmesg code22msg[] = {
103434221Sbostic 01, "GCR write error",
103534221Sbostic 02, "GCR read error",
103634221Sbostic 03, "PE read error",
103734221Sbostic 04, "PE write error",
103834221Sbostic 05, "at least 1 bit set in ECCSTA",
103934221Sbostic 06, "PE write error",
104034221Sbostic 07, "GCR write error",
104134221Sbostic 010, "RSTAT contains bad code",
104234221Sbostic 011, "PE write error",
104334221Sbostic 012, "MASSBUS parity error",
104434221Sbostic 013, "invalid data transferred",
104534221Sbostic -1, unclass
104634221Sbostic };
104717214Smckusick
104834221Sbostic /* MTER_TMFLTA */
104934221Sbostic static struct fmesg tmfltamsg[] = {
105034221Sbostic 01, "illegal command code",
105134221Sbostic 02, "DT command issued when NDT command active",
105234221Sbostic 03, "WMC error",
105334221Sbostic 04, "RUN not received from MASSBUS controller",
105434221Sbostic 05, "mismatch in command read - function routine",
105534221Sbostic 06, "ECC ROM parity error",
105634221Sbostic 07, "XMC ROM parity error",
105734221Sbostic 010, "mismatch in command read - ID burst command",
105834221Sbostic 011, "mismatch in command read - verify ARA burst command",
105934221Sbostic 012, "mismatch in command read - verify ARA ID command",
106034221Sbostic 013, "mismatch in command read - verify gap command",
106134221Sbostic 014, "mismatch in command read - read id burst command",
106234221Sbostic 015, "mismatch in command read - verify ARA ID command",
106334221Sbostic 016, "mismatch in command read - verify gap command",
106434221Sbostic 017, "mismatch in command read - find gap command",
106534221Sbostic 020, "WMC LEFT failed to set",
106634221Sbostic 021, "XL PE set in INTSTA register",
106734221Sbostic 022, "XMC DONE did not set",
106834221Sbostic 023, "WMC ROM PE or RD PE set in WMCERR register",
106934221Sbostic -1, unclass
107034221Sbostic };
107117214Smckusick
107234221Sbostic /* MTER_TUFLTA */
107334221Sbostic static struct fmesg tufltamsg[] = {
107434221Sbostic 01, "TU status parity error",
107534221Sbostic 02, "TU command parity error",
107634221Sbostic 03, "rewinding tape went offline",
107734221Sbostic 04, "tape went not ready during DSE",
107834221Sbostic 05, "TU CMD status changed during DSE",
107934221Sbostic 06, "TU never came up to speed",
108034221Sbostic 07, "TU velocity changed",
108134221Sbostic 010, "TU CMD did not load correctly to start tape motion",
108234221Sbostic 011, "TU CMD did not load correctly to set drive density",
108334221Sbostic 012, "TU CMD did not load correctly to start tape motion to write BOT ID",
108434221Sbostic 013, "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID",
108534221Sbostic 014, "failed to write density ID burst",
108634221Sbostic 015, "failed to write ARA burst",
108734221Sbostic 016, "failed to write ARA ID",
108834221Sbostic 017, "ARA error bit set in MTA status B register",
108934221Sbostic 021, "could not find a gap after ID code was written correctly",
109034221Sbostic 022, "TU CMD did not load correctly to start tape motion to read ID burst",
109134221Sbostic 023, "timeout looking for BOT after detecting ARA ID burst",
109234221Sbostic 024, "failed to write tape mark",
109334221Sbostic 025, "tape never came up to speed while trying to reposition for retry of writing tape mark",
109434221Sbostic 026, "TU CMD did not load correctly to start tape motion in erase gap routine",
109534221Sbostic 027, "could not detect a gap in in erase gap routine",
109634221Sbostic 030, "could not detect a gap after writing record",
109734221Sbostic 031, "read path terminated before entire record was written",
109834221Sbostic 032, "could not find a gap after writing record and read path terminated early",
109934221Sbostic 033, "TU CMD did not load correctly to backup for retry of write tape mark",
110034221Sbostic 034, "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark",
110134221Sbostic 035, "TU CMD did not load correctly to backup to retry a load of BOT ID",
110234221Sbostic 036, "timeout looking for BOT after failing to write BOT ID",
110334221Sbostic 037, "TU velocity changed while writing PE gap before starting to write record",
110434221Sbostic 040, "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst",
110534221Sbostic 041, "TU CMD did not load correctly to set GCR tape density after writing Density ID",
110634221Sbostic 042, "TU CMD did not load correctly to set PE tape density at start of read from BOT",
110734221Sbostic 043, "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst",
110834221Sbostic };
110917214Smckusick
111034221Sbostic /* MTER_TMFLTB */
111134221Sbostic static char inlinetest[] = "inline test failed";
111234221Sbostic static struct fmesg tmfltbmsg[] = {
111334221Sbostic 00, "RST0 interrupt occurred with TM RDY set",
111434221Sbostic 01, "power failed to interrupt",
111534221Sbostic 02, "unknown interrupt on channel 5.5",
111634221Sbostic 03, "unknown interrupt on channel 6.5",
111734221Sbostic 04, "unknown interrupt on channel 7",
111834221Sbostic 05, "unknown interrupt on channel 7.5",
111934221Sbostic 06, "CAS contention retry count expired",
112034221Sbostic 07, "CAS contention error not retryable",
112134221Sbostic 010, "queue error, could not find queue entry",
112234221Sbostic 011, "queue entry already full",
112334221Sbostic 012, "8085 ROM parity error",
112434221Sbostic 013, inlinetest,
112534221Sbostic 013, inlinetest,
112634221Sbostic 014, inlinetest,
112734221Sbostic 015, inlinetest,
112834221Sbostic 016, inlinetest,
112934221Sbostic 017, inlinetest,
113034221Sbostic 020, inlinetest,
113134221Sbostic 021, inlinetest,
113234221Sbostic 022, inlinetest,
113334221Sbostic 023, inlinetest,
113434221Sbostic 024, inlinetest,
113534221Sbostic 025, inlinetest,
113634221Sbostic 026, inlinetest,
113734221Sbostic 027, inlinetest,
113834221Sbostic 030, inlinetest,
113934221Sbostic 031, inlinetest,
114034221Sbostic 032, inlinetest,
114134221Sbostic 033, inlinetest,
114234221Sbostic 034, inlinetest,
114334221Sbostic 035, inlinetest,
114434221Sbostic 036, inlinetest,
114534221Sbostic 037, inlinetest,
114634221Sbostic 040, inlinetest,
114734221Sbostic 041, inlinetest,
114834221Sbostic 042, inlinetest,
114934221Sbostic 043, inlinetest,
115034221Sbostic 044, inlinetest,
115136548Sbostic 045, inlinetest,
115234221Sbostic 046, inlinetest,
115334221Sbostic 047, inlinetest,
115434221Sbostic 050, inlinetest,
115534221Sbostic 051, inlinetest,
115634221Sbostic 052, inlinetest,
115734221Sbostic 053, inlinetest,
115834221Sbostic 054, inlinetest,
115934221Sbostic 055, inlinetest,
116034221Sbostic 056, inlinetest,
116134221Sbostic 057, inlinetest,
116234221Sbostic -1, unclass
116334221Sbostic };
116417214Smckusick
116534221Sbostic /* MTER_MBFLT */
116634221Sbostic static struct fmesg mbfltmsg[] = {
116734221Sbostic 01, "control bus parity error",
116834221Sbostic 02, "illegal register referenced",
116934221Sbostic -1, unclass
117034221Sbostic };
117117214Smckusick
117234221Sbostic /*
117334221Sbostic * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL,
117434221Sbostic * and default: no failure message.
117534221Sbostic */
117634221Sbostic static struct fmesg nullmsg[] = {
117734221Sbostic -1, ""
117834221Sbostic };
117917214Smckusick
118034221Sbostic /*
118134221Sbostic * Interrupt code table.
118234221Sbostic */
118334221Sbostic static struct errmsg {
118434221Sbostic int e_code;
118534221Sbostic char *e_mesg;
118634221Sbostic struct fmesg *e_fmesg;
118734221Sbostic } errmsg[] = {
118834221Sbostic MTER_BOT, "unexpected BOT", botmsg,
118934221Sbostic MTER_LEOT, "unexpected LEOT", nullmsg,
119034221Sbostic MTER_RWDING, "tape rewinding", nullmsg,
119134221Sbostic MTER_NOTRDY, "drive not ready", notrdymsg,
119234221Sbostic MTER_NOTAVL, "drive not available", nullmsg,
119334221Sbostic MTER_NONEX, "unit does not exist", nullmsg,
119434221Sbostic MTER_NOTCAP, "not capable", notcapmsg,
119534221Sbostic MTER_LONGREC, "long record", longrecmsg,
119634221Sbostic MTER_UNREAD, "unreadable record", code22msg,
119734221Sbostic MTER_ERROR, "error", code22msg,
119834221Sbostic MTER_EOTERR, "EOT error", code22msg,
119934221Sbostic MTER_BADTAPE, "tape position lost", code22msg,
120034221Sbostic MTER_TMFLTA, "TM fault A", tmfltamsg,
120134221Sbostic MTER_TUFLTA, "TU fault A", tufltamsg,
120234221Sbostic MTER_TMFLTB, "TM fault B", tmfltbmsg,
120334221Sbostic MTER_MBFLT, "MB fault", mbfltmsg,
120434221Sbostic MTER_KEYFAIL, "keypad entry error", nullmsg,
120534221Sbostic -1, "unclassified error", nullmsg
120634221Sbostic };
120717214Smckusick
120834221Sbostic /*
120934221Sbostic * Decode an interrupt-time failure.
121034221Sbostic */
mtintfail(erreg)121134221Sbostic mtintfail(erreg)
121234221Sbostic int erreg;
121334221Sbostic {
121434221Sbostic register struct errmsg *e;
121534221Sbostic register struct fmesg *f;
121634221Sbostic register int ecode, fcode;
121717214Smckusick
121834221Sbostic ecode = erreg & MTER_INTCODE;
121934221Sbostic fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT;
122034221Sbostic for (e = errmsg; e->e_code >= 0; e++)
122134221Sbostic if (e->e_code == ecode)
122217214Smckusick break;
122334221Sbostic for (f = e->e_fmesg; f->f_code >= 0; f++)
122434221Sbostic if (f->f_code == fcode)
122517214Smckusick break;
122634221Sbostic printf(" interrupt code = 0%o <%s>\n", ecode, e->e_mesg);
122734221Sbostic printf(" failure code = 0%o <%s>\n", fcode, f->f_mesg);
122817214Smckusick }
122934221Sbostic #endif /* MTLERRM */
123034221Sbostic #endif /* NMT > 0 */
1231