|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: *
6: * @(#)mt.c 7.8 (Berkeley) 4/12/90
7: */
8:
9: #include "mu.h"
10: #if NMT > 0
11: /*
12: * TM78/TU78 tape driver
13: *
14: * Original author - ?
15: * Most error recovery bug fixes - ggs (ulysses!ggs)
16: * `read reverse' error recovery - ggs (ulysses!ggs)
17: *
18: * OPTIONS:
19: * MTLERRM - Long error message text - twd, Brown University
20: *
21: * TODO:
22: * Add odd byte count kludge from VMS driver (?)
23: * Write dump routine
24: */
25:
26: #include "param.h"
27: #include "systm.h"
28: #include "buf.h"
29: #include "conf.h"
30: #include "file.h"
31: #include "user.h"
32: #include "proc.h"
33: #include "map.h"
34: #include "ioctl.h"
35: #include "mtio.h"
36: #include "cmap.h"
37: #include "tty.h"
38: #include "syslog.h"
39:
40: #include "../vax/pte.h"
41: #include "../vax/cpu.h"
42: #include "mbareg.h"
43: #include "mbavar.h"
44: #include "mtreg.h"
45:
46: #define MTTIMEOUT 10000 /* loop limit for controller test */
47: #define INF 1000000L /* a block number that won't exist */
48: #define MASKREG(r) ((r) & 0xffff) /* the control registers have 16 bits */
49:
50: /* Bits for sc_flags */
51:
52: #define H_WRITTEN 01 /* last operation was a write */
53: #define H_EOT 02 /* end of tape encountered */
54: #define H_IEOT 04 /* ignore EOT condition */
55:
56: int mt_do_readrev = 1;
57:
58: /* Per unit status information */
59:
60: struct mu_softc {
61: char sc_openf; /* unit is open if != 0 */
62: char sc_flags; /* state flags */
63: daddr_t sc_blkno; /* current physical block number */
64: daddr_t sc_nxrec; /* firewall input block number */
65: u_short sc_erreg; /* copy of mter or mtner */
66: u_short sc_dsreg; /* copy of mtds */
67: short sc_resid; /* residual function count for ioctl */
68: short sc_dens; /* density code - MT_GCR or zero */
69: int sc_i_mtas; /* mtas at slave attach time */
70: int sc_i_mtner; /* mtner at slave attach time */
71: int sc_i_mtds; /* mtds at slave attach time */
72: caddr_t sc_ctty; /* record user's tty for errors */
73: int sc_blks; /* number of I/O operations since open */
74: int sc_softerrs; /* number of soft I/O errors since open */
75: } mu_softc[NMU];
76:
77: struct buf cmtbuf[NMT]; /* tape command buffer structures */
78:
79: struct mba_device *mtinfo[NMT]; /* unit to ctlr structures */
80: struct mba_slave *muinfo[NMU]; /* unit to slave structures */
81:
82: char mtds_bits[] = MTDS_BITS; /* mtds bit names for error messages */
83: short mttypes[] = { MBDT_TU78, 0 };
84:
85: int mtattach(), mtslave(), mtustart(), mtstart(), mtndtint(), mtdtint();
86: struct mba_driver mtdriver =
87: { mtattach, mtslave, mtustart, mtstart, mtdtint, mtndtint,
88: mttypes, "mt", "mu", mtinfo };
89:
90: /* Bits in minor device */
91: #define MUUNIT(dev) (minor(dev)&03)
92: #define H_NOREWIND 04
93: #define H_6250BPI 010
94:
95: #define MTUNIT(dev) (muinfo[MUUNIT(dev)]->ms_ctlr)
96:
97: void mtcreset();
98:
99: /*ARGSUSED*/
100: mtattach(mi)
101: struct mba_device *mi;
102: {
103:
104: /* void */
105: }
106:
107: mtslave(mi, ms, sn)
108: struct mba_device *mi;
109: struct mba_slave *ms;
110: int sn;
111: {
112: register struct mu_softc *sc = &mu_softc[ms->ms_unit];
113: register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
114: int s = spl5(), rtn = 0, i;
115:
116: /*
117: * Just in case the controller is ill, reset it. Then issue
118: * a sense operation and wait about a second for it to respond.
119: */
120: mtcreset(mtaddr);
121: mtaddr->mtas = -1;
122: mtaddr->mtncs[sn] = MT_SENSE|MT_GO;
123: for (i = MTTIMEOUT; i > 0; i--) {
124: DELAY(50);
125: if (MASKREG(mtaddr->mtas) != 0)
126: break;
127: }
128: sc->sc_i_mtas = mtaddr->mtas;
129: sc->sc_i_mtner = mtaddr->mtner;
130: sc->sc_i_mtds = mtaddr->mtds;
131:
132: /*
133: * If no response, whimper. If wrong response, call it an
134: * unsolicited interrupt and use mtndtint to log and correct.
135: * Otherwise, note whether this slave exists.
136: */
137: if (i <= 0)
138: printf("mt: controller hung\n");
139: else if ((mtaddr->mtner & MTER_INTCODE) != MTER_DONE)
140: (void) mtndtint(mi);
141: else if (mtaddr->mtds & MTDS_PRES) {
142: muinfo[ms->ms_unit] = ms;
143: rtn = 1;
144: }
145:
146: /* cancel the interrupt, then wait a little while for it to go away */
147: mtaddr->mtas = mtaddr->mtas;
148: DELAY(10);
149: splx(s);
150: return (rtn);
151: }
152:
153: mtopen(dev, flag)
154: dev_t dev;
155: int flag;
156: {
157: register int muunit;
158: register struct mu_softc *sc;
159: register struct mba_slave *ms;
160:
161: muunit = MUUNIT(dev);
162: if (muunit >= NMU || (ms = muinfo[muunit]) == NULL ||
163: ms->ms_alive == 0 || mtinfo[ms->ms_ctlr]->mi_alive == 0)
164: return (ENXIO);
165: if ((sc = &mu_softc[muunit])->sc_openf)
166: return (EBUSY);
167: sc->sc_openf = 1;
168: sc->sc_dens = (minor(dev) & H_6250BPI) ? MT_GCR : 0;
169: mtcommand(dev, MT_SENSE, 1);
170: if ((sc->sc_dsreg & MTDS_ONL) == 0) {
171: uprintf("mu%d: not online\n", muunit);
172: sc->sc_openf = 0;
173: return (EIO);
174: }
175: if ((sc->sc_dsreg & MTDS_AVAIL) == 0) {
176: uprintf("mu%d: not online (port selector)\n", muunit);
177: sc->sc_openf = 0;
178: return (EIO);
179: }
180: if ((flag & FWRITE) && (sc->sc_dsreg & MTDS_FPT)) {
181: uprintf("mu%d: no write ring\n", muunit);
182: sc->sc_openf = 0;
183: return (EIO);
184: }
185: if ((sc->sc_dsreg & MTDS_BOT) == 0 && (flag & FWRITE) &&
186: (sc->sc_dens == MT_GCR) != ((sc->sc_dsreg & MTDS_PE) == 0)) {
187: uprintf("mu%d: can't change density in mid-tape\n", muunit);
188: sc->sc_openf = 0;
189: return (EIO);
190: }
191: sc->sc_blkno = (daddr_t)0;
192:
193: /*
194: * Since cooked I/O may do a read-ahead before a write, trash
195: * on a tape can make the first write fail. Suppress the first
196: * read-ahead unless definitely doing read-write.
197: */
198: sc->sc_nxrec = ((flag & (FTRUNC | FWRITE)) == (FTRUNC | FWRITE)) ?
199: (daddr_t)0 : (daddr_t)INF;
200: sc->sc_flags = 0;
201: sc->sc_blks = 0;
202: sc->sc_softerrs = 0;
203: sc->sc_ctty = (caddr_t)(u.u_procp->p_flag&SCTTY ?
204: u.u_procp->p_session->s_ttyp : 0);
205: return (0);
206: }
207:
208: mtclose(dev, flag)
209: register dev_t dev;
210: register int flag;
211: {
212: register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
213:
214: if ((flag & (FREAD | FWRITE)) == FWRITE ||
215: ((flag & FWRITE) && (sc->sc_flags & H_WRITTEN)))
216: mtcommand(dev, MT_CLS|sc->sc_dens, 1);
217: if ((minor(dev) & H_NOREWIND) == 0)
218: mtcommand(dev, MT_REW, 0);
219: if (sc->sc_blks > 100 && sc->sc_softerrs > sc->sc_blks / 100)
220: log(LOG_INFO, "mu%d: %d soft errors in %d blocks\n",
221: MUUNIT(dev), sc->sc_softerrs, sc->sc_blks);
222: sc->sc_openf = 0;
223: return (0);
224: }
225:
226: mtcommand(dev, com, count)
227: dev_t dev;
228: int com, count;
229: {
230: register struct buf *bp;
231: int s;
232:
233: bp = &cmtbuf[MTUNIT(dev)];
234: s = spl5();
235: while (bp->b_flags & B_BUSY) {
236: if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE))
237: break;
238: bp->b_flags |= B_WANTED;
239: sleep((caddr_t)bp, PRIBIO);
240: }
241: bp->b_flags = B_BUSY|B_READ;
242: splx(s);
243: bp->b_dev = dev;
244: bp->b_command = com;
245: bp->b_repcnt = count;
246: bp->b_blkno = 0;
247: bp->b_error = 0;
248: mtstrategy(bp);
249: if (count == 0)
250: return;
251: biowait(bp);
252: if (bp->b_flags & B_WANTED)
253: wakeup((caddr_t)bp);
254: bp->b_flags &= B_ERROR;
255: }
256:
257: mtstrategy(bp)
258: register struct buf *bp;
259: {
260: register struct buf *dp;
261: struct mba_device *mi = mtinfo[MTUNIT(bp->b_dev)];
262: int s;
263:
264: /*
265: * If this is a data transfer operation, set the resid to a
266: * default value (EOF) to simplify getting it right during
267: * error recovery or bail out.
268: */
269: if (bp != &cmtbuf[MTUNIT(bp->b_dev)])
270: bp->b_resid = bp->b_bcount;
271:
272: /*
273: * Link this request onto the end of the queue for this
274: * controller, then start I/O if not already active.
275: */
276: bp->av_forw = NULL;
277: dp = &mi->mi_tab;
278: s = spl5();
279: if (dp->b_actf == NULL)
280: dp->b_actf = bp;
281: else
282: dp->b_actl->av_forw = bp;
283: dp->b_actl = bp;
284: if (dp->b_active == 0)
285: mbustart(mi);
286: splx(s);
287: }
288:
289: mtustart(mi)
290: register struct mba_device *mi;
291: {
292: register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
293: register struct buf *bp = mi->mi_tab.b_actf;
294: register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
295: daddr_t blkno;
296: int count;
297:
298: if (sc->sc_openf < 0) {
299: bp->b_flags |= B_ERROR;
300: return (MBU_NEXT);
301: }
302: if (bp != &cmtbuf[MTUNIT(bp->b_dev)]) {
303: /*
304: * Data transfer. If write at end of tape,
305: * signal "no space" unless suppressed
306: * by MTIOCIEOT.
307: */
308: if ((sc->sc_flags & (H_EOT | H_IEOT)) == H_EOT &&
309: (bp->b_flags & B_READ) == 0) {
310: bp->b_flags |= B_ERROR;
311: bp->b_error = ENOSPC;
312: return (MBU_NEXT);
313: }
314:
315: if (bp->b_flags & B_RAW) {
316: /* raw transfer; never seek */
317: sc->sc_blkno = bdbtofsb(bp->b_blkno);
318: sc->sc_nxrec = sc->sc_blkno + 1;
319: } else {
320: /* seek beyond end of file */
321: if (bdbtofsb(bp->b_blkno) > sc->sc_nxrec) {
322: bp->b_flags |= B_ERROR;
323: bp->b_error = ENXIO;
324: return (MBU_NEXT);
325: }
326:
327: /*
328: * This should be end of file, but the buffer
329: * system wants a one-block look-ahead. Humor it.
330: */
331: if (bdbtofsb(bp->b_blkno) == sc->sc_nxrec &&
332: bp->b_flags & B_READ) {
333: bp->b_resid = bp->b_bcount;
334: clrbuf(bp);
335: return (MBU_NEXT);
336: }
337:
338: /* If writing, mark the next block invalid. */
339: if ((bp->b_flags & B_READ) == 0)
340: sc->sc_nxrec = bdbtofsb(bp->b_blkno) + 1;
341: }
342: } else {
343: /* It's a command, do it now. */
344: mtaddr->mtncs[MUUNIT(bp->b_dev)] =
345: (bp->b_repcnt<<8)|bp->b_command|MT_GO;
346: return (MBU_STARTED);
347: }
348:
349: /*
350: * If raw I/O, or if the tape is positioned correctly for
351: * cooked I/O, set the byte count, unit number and repeat count
352: * then tell the MASSBUS to proceed. Note that a negative
353: * bcount tells mbstart to map the buffer for "read backwards".
354: */
355: if ((blkno = sc->sc_blkno) == bdbtofsb(bp->b_blkno)) {
356: if (mi->mi_tab.b_errcnt == 2) {
357: mtaddr->mtbc = -bp->b_bcount;
358: mtaddr->mtca = MUUNIT(bp->b_dev);
359: } else {
360: mtaddr->mtbc = bp->b_bcount;
361: mtaddr->mtca = (1<<2)|MUUNIT(bp->b_dev);
362: }
363: return (MBU_DODATA);
364: }
365:
366: /* Issue skip operations to position the next block for cooked I/O. */
367:
368: if (blkno < bdbtofsb(bp->b_blkno))
369: count = bdbtofsb(bp->b_blkno) - blkno;
370: else
371: count = blkno - bdbtofsb(bp->b_blkno);
372: if ((unsigned)count > 0377)
373: count = 0377;
374: mtaddr->mtncs[MUUNIT(bp->b_dev)] = count | MT_SFORW|MT_GO;
375: return (MBU_STARTED);
376: }
377:
378: mtstart(mi)
379: register struct mba_device *mi;
380: {
381: register struct buf *bp = mi->mi_tab.b_actf;
382: register struct mu_softc *sc = &mu_softc[MUUNIT(bp->b_dev)];
383:
384: if (bp->b_flags & B_READ)
385: if (mi->mi_tab.b_errcnt == 2)
386: return (MT_READREV|MT_GO);
387: else
388: return (MT_READ|MT_GO);
389: else
390: return (MT_WRITE|sc->sc_dens|MT_GO);
391: }
392:
393: mtdtint(mi, mbsr)
394: register struct mba_device *mi;
395: int mbsr;
396: {
397: register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
398: register struct buf *bp = mi->mi_tab.b_actf;
399: register struct mu_softc *sc;
400: register int er;
401:
402: /* I'M still NOT SURE IF THIS SHOULD ALWAYS BE THE CASE SO FOR NOW... */
403: if ((mtaddr->mtca & 3) != MUUNIT(bp->b_dev)) {
404: printf("mt: wrong unit!\n");
405: mtaddr->mtca = MUUNIT(bp->b_dev);
406: }
407:
408: er = MASKREG(mtaddr->mter);
409: sc = &mu_softc[MUUNIT(bp->b_dev)];
410: sc->sc_erreg = er;
411: if (bp->b_flags & B_READ)
412: sc->sc_flags &= ~H_WRITTEN;
413: else
414: sc->sc_flags |= H_WRITTEN;
415: switch (er & MTER_INTCODE) {
416:
417: case MTER_EOT:
418: sc->sc_flags |= H_EOT;
419: /* fall into MTER_DONE */
420:
421: case MTER_DONE:
422: sc->sc_blkno++;
423: if (mi->mi_tab.b_errcnt == 2) {
424: bp->b_bcount = bp->b_resid;
425: bp->b_resid -= MASKREG(mtaddr->mtbc);
426: if (bp->b_resid > 0 && (bp->b_flags & B_RAW) == 0)
427: bp->b_flags |= B_ERROR;
428: } else
429: bp->b_resid = 0;
430: break;
431:
432: case MTER_SHRTREC:
433: sc->sc_blkno++;
434: bp->b_bcount = bp->b_resid;
435: bp->b_resid -= MASKREG(mtaddr->mtbc);
436: if ((bp->b_flags & B_RAW) == 0)
437: bp->b_flags |= B_ERROR;
438: break;
439:
440: case MTER_RETRY:
441: /*
442: * Simple re-try. Since resid is always a copy of the
443: * original byte count, use it to restore the count.
444: */
445: mi->mi_tab.b_errcnt = 1;
446: bp->b_bcount = bp->b_resid;
447: return (MBD_RETRY);
448:
449: case MTER_RDOPP:
450: /*
451: * The controller just decided to read it backwards.
452: * If the controller returns a byte count of zero,
453: * change it to 1, since zero encodes 65536, which
454: * isn't quite what we had in mind. The byte count
455: * may be larger than the size of the input buffer, so
456: * limit the count to the buffer size. After
457: * making the byte count reasonable, set bcount to the
458: * negative of the controller's version of the byte
459: * count so that the start address for the transfer is
460: * set up correctly.
461: */
462: if (mt_do_readrev) {
463: mi->mi_tab.b_errcnt = 2;
464: if ((bp->b_bcount = MASKREG(mtaddr->mtbc)) == 0)
465: bp->b_bcount = 1;
466: if (bp->b_bcount > bp->b_resid)
467: bp->b_bcount = bp->b_resid;
468: bp->b_bcount = -(bp->b_bcount);
469: return(MBD_RETRY);
470: } else if (MASKREG(mtaddr->mtbc) <= bp->b_resid) {
471: sc->sc_blkno++;
472: bp->b_bcount = bp->b_resid;
473: bp->b_resid -= MASKREG(mtaddr->mtbc);
474: bp->b_flags |= B_ERROR;
475: break;
476: }
477: bp->b_flags |= B_ERROR;
478: /* fall into MTER_LONGREC */
479:
480: case MTER_LONGREC:
481: sc->sc_blkno++;
482: bp->b_bcount = bp->b_resid;
483: bp->b_resid = 0;
484: bp->b_error = ENOMEM;
485: bp->b_flags |= B_ERROR;
486: break;
487:
488: case MTER_NOTCAP:
489: printf("mu%d: blank tape\n", MUUNIT(bp->b_dev));
490: goto err;
491:
492: case MTER_TM:
493: /*
494: * End of file. Since the default byte count has
495: * already been set, just count the block and proceed.
496: */
497: sc->sc_blkno++;
498: err:
499: sc->sc_nxrec = bdbtofsb(bp->b_blkno);
500: break;
501:
502: case MTER_OFFLINE:
503: if (sc->sc_openf > 0) {
504: sc->sc_openf = -1;
505: tprintf(sc->sc_ctty, "mu%d: offline\n",
506: MUUNIT(bp->b_dev));
507: }
508: bp->b_flags |= B_ERROR;
509: break;
510:
511: case MTER_NOTAVL:
512: if (sc->sc_openf > 0) {
513: sc->sc_openf = -1;
514: tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n",
515: MUUNIT(bp->b_dev));
516: }
517: bp->b_flags |= B_ERROR;
518: break;
519:
520: case MTER_FPT:
521: tprintf(sc->sc_ctty, "mu%d: no write ring\n",
522: MUUNIT(bp->b_dev));
523: bp->b_flags |= B_ERROR;
524: break;
525:
526: case MTER_UNREAD:
527: sc->sc_blkno++;
528: bp->b_bcount = bp->b_resid;
529: bp->b_resid -= MIN(MASKREG(mtaddr->mtbc), bp->b_bcount);
530:
531: /* code 010 means a garbage record, nothing serious. */
532: if ((er & MTER_FAILCODE) == (010 << MTER_FSHIFT)) {
533: tprintf(sc->sc_ctty,
534: "mu%d: rn=%d bn=%d unreadable record\n",
535: MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno);
536: bp->b_flags |= B_ERROR;
537: break;
538: }
539:
540: /*
541: * Anything else might be a hardware problem,
542: * fall into the error report.
543: */
544:
545: default:
546: /*
547: * The bits in sc->sc_dsreg are from the last sense
548: * command. To get the most recent copy, you have to
549: * do a sense at interrupt level, which requires nested
550: * error processing. This is a bit messy, so leave
551: * well enough alone.
552: */
553: tprintf(sc->sc_ctty, "\
554: mu%d: hard error (data transfer) rn=%d bn=%d mbsr=%b er=0%o ds=%b\n",
555: MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
556: mbsr, mbsr_bits, er,
557: MASKREG(sc->sc_dsreg), mtds_bits);
558: #ifdef MTLERRM
559: mtintfail(er);
560: #endif
561: bp->b_flags |= B_ERROR;
562:
563: /*
564: * The TM78 manual says to reset the controller after
565: * TM fault B or MASSBUS fault.
566: */
567: if ((er & MTER_INTCODE) == MTER_TMFLTB ||
568: (er & MTER_INTCODE) == MTER_MBFLT)
569: mtcreset(mtaddr);
570: }
571:
572: /*
573: * Just in case some strange error slipped through (drive off
574: * line during read-reverse error recovery comes to mind), make
575: * sure the byte count is reasonable.
576: */
577: if (bp->b_bcount < 0)
578: bp->b_bcount = bp->b_resid;
579:
580: if ((bp->b_flags & B_ERROR) == 0) {
581: /* this counts reverse reads as soft errors */
582: sc->sc_blks++;
583: if (mi->mi_tab.b_errcnt) /* alternatively, if == 1 */
584: sc->sc_softerrs++;
585: }
586: return (MBD_DONE);
587: }
588:
589: mtndtint(mi)
590: register struct mba_device *mi;
591: {
592: register struct mtdevice *mtaddr = (struct mtdevice *)mi->mi_drv;
593: register struct buf *bp = mi->mi_tab.b_actf;
594: register struct mu_softc *sc;
595: register int er, fc;
596: int unit;
597:
598: unit = (mtaddr->mtner >> 8) & 3;
599: er = MASKREG(mtaddr->mtner);
600: sc = &mu_softc[unit];
601: sc->sc_erreg = er;
602:
603: /* Check for unsolicited interrupts. */
604: if (bp == NULL || unit != MUUNIT(bp->b_dev)) {
605: if ((er & MTER_INTCODE) == MTER_ONLINE)
606: return (MBN_SKIP);
607:
608: printf("mu%d: stray intr (non data transfer) er=0%o ds=%b\n",
609: unit, er, MASKREG(sc->sc_dsreg), mtds_bits);
610: #ifdef MTLERRM
611: mtintfail(er);
612: #endif
613: if ((er & MTER_INTCODE) == MTER_TMFLTB ||
614: (er & MTER_INTCODE) == MTER_MBFLT) {
615: /*
616: * Reset the controller, then set error status
617: * if there was anything active when the fault
618: * occurred. This may shoot an innocent
619: * bystander, but it's better than letting
620: * an error slip through.
621: */
622: mtcreset(mtaddr);
623: if (bp != NULL) {
624: bp->b_flags |= B_ERROR;
625: return (MBN_DONE);
626: }
627: }
628: return (MBN_SKIP);
629: }
630:
631: fc = (mtaddr->mtncs[unit] >> 8) & 0xff;
632: sc->sc_resid = fc;
633:
634: /*
635: * Clear the "written" flag after any operation that changes
636: * the position of the tape.
637: */
638: if (bp != &cmtbuf[MTUNIT(bp->b_dev)] || bp->b_command != MT_SENSE)
639: sc->sc_flags &= ~H_WRITTEN;
640:
641: switch (er & MTER_INTCODE) {
642:
643: case MTER_EOT:
644: sc->sc_flags |= H_EOT;
645: /* fall into MTER_DONE */
646:
647: case MTER_DONE:
648: /* If this is a command buffer, just update the status. */
649: if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
650: done:
651: if (bp->b_command == MT_SENSE)
652: sc->sc_dsreg = MASKREG(mtaddr->mtds);
653: return (MBN_DONE);
654: }
655:
656: /*
657: * It's not a command buffer, must be a cooked I/O
658: * skip operation (perhaps a shaky assumption, but it
659: * wasn't my idea).
660: */
661: if ((fc = bdbtofsb(bp->b_blkno) - sc->sc_blkno) < 0)
662: sc->sc_blkno -= MIN(0377, -fc);
663: else
664: sc->sc_blkno += MIN(0377, fc);
665: return (MBN_RETRY);
666:
667: case MTER_ONLINE: /* ddj -- shouldn't happen but did */
668: case MTER_RWDING:
669: return (MBN_SKIP); /* ignore "rewind started" interrupt */
670:
671: case MTER_NOTCAP:
672: tprintf(sc->sc_ctty, "mu%d: blank tape\n", MUUNIT(bp->b_dev));
673: bp->b_flags |= B_ERROR;
674: return (MBN_DONE);
675:
676: case MTER_TM:
677: case MTER_LEOT:
678: /*
679: * For an ioctl skip operation, count a tape mark as
680: * a record. If there's anything left to do, update
681: * the repeat count and re-start the command.
682: */
683: if (bp == &cmtbuf[MTUNIT(bp->b_dev)]) {
684: if ((sc->sc_resid = bp->b_repcnt = fc - 1) == 0)
685: return (MBN_DONE);
686: else
687: return (MBN_RETRY);
688: } else {
689: /*
690: * Cooked I/O again. Just update the books and
691: * wait for someone else to return end of file or
692: * complain about a bad seek.
693: */
694: if (sc->sc_blkno > bdbtofsb(bp->b_blkno)) {
695: sc->sc_nxrec = bdbtofsb(bp->b_blkno) + fc - 1;
696: sc->sc_blkno = sc->sc_nxrec;
697: } else {
698: sc->sc_nxrec = bdbtofsb(bp->b_blkno) - fc;
699: sc->sc_blkno = sc->sc_nxrec + 1;
700: }
701: }
702: return (MBN_RETRY);
703:
704: case MTER_FPT:
705: tprintf(sc->sc_ctty, "mu%d: no write ring\n",
706: MUUNIT(bp->b_dev));
707: bp->b_flags |= B_ERROR;
708: return (MBN_DONE);
709:
710: case MTER_OFFLINE:
711: /* If `off line' was intentional, don't complain. */
712: if (bp == &cmtbuf[MTUNIT(bp->b_dev)] &&
713: bp->b_command == MT_UNLOAD)
714: return(MBN_DONE);
715: if (sc->sc_openf > 0) {
716: sc->sc_openf = -1;
717: tprintf(sc->sc_ctty, "mu%d: offline\n",
718: MUUNIT(bp->b_dev));
719: }
720: bp->b_flags |= B_ERROR;
721: return (MBN_DONE);
722:
723: case MTER_NOTAVL:
724: if (sc->sc_openf > 0) {
725: sc->sc_openf = -1;
726: tprintf(sc->sc_ctty, "mu%d: offline (port selector)\n",
727: MUUNIT(bp->b_dev));
728: }
729: bp->b_flags |= B_ERROR;
730: return (MBN_DONE);
731:
732: case MTER_BOT:
733: if (bp == &cmtbuf[MTUNIT(bp->b_dev)])
734: goto done;
735: /* fall through */
736:
737: default:
738: tprintf(sc->sc_ctty, "\
739: mu%d: hard error (non data transfer) rn=%d bn=%d er=0%o ds=%b\n",
740: MUUNIT(bp->b_dev), sc->sc_blkno, bp->b_blkno,
741: er, MASKREG(sc->sc_dsreg), mtds_bits);
742: #ifdef MTLERRM
743: mtintfail(er);
744: #endif
745: if ((er & MTER_INTCODE) == MTER_TMFLTB ||
746: (er & MTER_INTCODE) == MTER_MBFLT)
747: mtcreset(mtaddr); /* reset the controller */
748: bp->b_flags |= B_ERROR;
749: return (MBN_DONE);
750: }
751: /* NOTREACHED */
752: }
753:
754: void
755: mtcreset(mtaddr)
756: register struct mtdevice *mtaddr;
757: {
758: register int i;
759:
760: mtaddr->mtid = MTID_CLR; /* reset the TM78 */
761: DELAY(200);
762: for (i = MTTIMEOUT; i > 0; i--) {
763: DELAY(50); /* don't nag */
764: if ((mtaddr->mtid & MTID_RDY) != 0)
765: return; /* exit when ready */
766: }
767: printf("mt: controller hung\n");
768: }
769:
770: /*ARGSUSED*/
771: mtioctl(dev, cmd, data, flag)
772: dev_t dev;
773: int cmd;
774: caddr_t data;
775: int flag;
776: {
777: register struct mu_softc *sc = &mu_softc[MUUNIT(dev)];
778: register struct buf *bp = &cmtbuf[MTUNIT(dev)];
779: register struct mtop *mtop;
780: register struct mtget *mtget;
781: int callcount, fcount, error = 0;
782: int op;
783:
784: /* We depend on the values and order of the MT codes here. */
785:
786: static mtops[] =
787: {MT_WTM,MT_SFORWF,MT_SREVF,MT_SFORW,MT_SREV,MT_REW,MT_UNLOAD,MT_SENSE};
788:
789: switch (cmd) {
790:
791: /* tape operation */
792:
793: case MTIOCTOP:
794: mtop = (struct mtop *)data;
795: switch (mtop->mt_op) {
796:
797: case MTWEOF:
798: callcount = mtop->mt_count;
799: fcount = 1;
800: break;
801:
802: case MTFSF: case MTBSF:
803: callcount = mtop->mt_count;
804: fcount = 1;
805: break;
806:
807: case MTFSR: case MTBSR:
808: callcount = 1;
809: fcount = mtop->mt_count;
810: break;
811:
812: case MTREW: case MTOFFL:
813: callcount = 1;
814: fcount = 1;
815: break;
816:
817: default:
818: return (ENXIO);
819: }
820: if (callcount <= 0 || fcount <= 0)
821: return (EINVAL);
822: op = mtops[mtop->mt_op];
823: if (op == MT_WTM)
824: op |= sc->sc_dens;
825: while (--callcount >= 0) {
826: register int n, fc = fcount;
827:
828: do {
829: n = MIN(fc, 0xff);
830: mtcommand(dev, op, n);
831: n -= sc->sc_resid;
832: fc -= n;
833: switch (mtop->mt_op) {
834:
835: case MTWEOF:
836: sc->sc_blkno += (daddr_t)n;
837: sc->sc_nxrec = sc->sc_blkno - 1;
838: break;
839:
840: case MTOFFL:
841: case MTREW:
842: case MTFSF:
843: sc->sc_blkno = (daddr_t)0;
844: sc->sc_nxrec = (daddr_t)INF;
845: break;
846:
847: case MTBSF:
848: if (sc->sc_resid) {
849: sc->sc_blkno = (daddr_t)0;
850: sc->sc_nxrec = (daddr_t)INF;
851: } else {
852: sc->sc_blkno = (daddr_t)(-1);
853: sc->sc_nxrec = (daddr_t)(-1);
854: }
855: break;
856:
857: case MTFSR:
858: sc->sc_blkno += (daddr_t)n;
859: break;
860:
861: case MTBSR:
862: sc->sc_blkno -= (daddr_t)n;
863: break;
864: }
865: if (sc->sc_resid)
866: break;
867: } while (fc);
868: if (fc) {
869: sc->sc_resid = callcount + fc;
870: if (mtop->mt_op == MTFSR ||
871: mtop->mt_op == MTBSR)
872: return (EIO);
873: break;
874: }
875: if (bp->b_flags & B_ERROR)
876: break;
877: }
878: if (bp->b_flags&B_ERROR)
879: if ((error = bp->b_error)==0)
880: return (EIO);
881: return (error);
882:
883: /* tape status */
884: case MTIOCGET:
885: mtget = (struct mtget *)data;
886: mtget->mt_erreg = sc->sc_erreg;
887: mtget->mt_resid = sc->sc_resid;
888: mtcommand(dev, MT_SENSE, 1); /* update drive status */
889: mtget->mt_dsreg = sc->sc_dsreg;
890: mtget->mt_type = MT_ISMT;
891: break;
892:
893: /* ignore EOT condition */
894: case MTIOCIEOT:
895: sc->sc_flags |= H_IEOT;
896: break;
897:
898: /* enable EOT condition */
899: case MTIOCEEOT:
900: sc->sc_flags &= ~H_IEOT;
901: break;
902:
903: default:
904: return (ENXIO);
905: }
906: return (0);
907: }
908:
909: #define DBSIZE 20
910:
911: mtdump()
912: {
913: register struct mba_device *mi;
914: register struct mba_regs *mp;
915: int blk, num;
916: int start;
917:
918: start = 0;
919: num = maxfree;
920: #define phys(a,b) ((b)((int)(a)&0x7fffffff))
921: if (mtinfo[0] == 0)
922: return (ENXIO);
923: mi = phys(mtinfo[0], struct mba_device *);
924: mp = phys(mi->mi_hd, struct mba_hd *)->mh_physmba;
925: mp->mba_cr = MBCR_IE;
926: #if lint
927: blk = 0; num = blk; start = num; blk = start;
928: return (0);
929: #endif
930: #ifdef notyet
931: mtaddr = (struct mtdevice *)&mp->mba_drv[mi->mi_drive];
932: mtaddr->mttc = MTTC_PDP11|MTTC_1600BPI;
933: mtaddr->mtcs1 = MT_DCLR|MT_GO;
934: while (num > 0) {
935: blk = num > DBSIZE ? DBSIZE : num;
936: mtdwrite(start, blk, mtaddr, mp);
937: start += blk;
938: num -= blk;
939: }
940: mteof(mtaddr);
941: mteof(mtaddr);
942: mtwait(mtaddr);
943: if (mtaddr->mtds&MTDS_ERR)
944: return (EIO);
945: mtaddr->mtcs1 = MT_REW|MT_GO;
946: return (0);
947: }
948:
949: mtdwrite(dbuf, num, mtaddr, mp)
950: register dbuf, num;
951: register struct mtdevice *mtaddr;
952: struct mba_regs *mp;
953: {
954: register struct pte *io;
955: register int i;
956:
957: mtwait(mtaddr);
958: io = mp->mba_map;
959: for (i = 0; i < num; i++)
960: *(int *)io++ = dbuf++ | PG_V;
961: mtaddr->mtfc = -(num*NBPG);
962: mp->mba_sr = -1;
963: mp->mba_bcr = -(num*NBPG);
964: mp->mba_var = 0;
965: mtaddr->mtcs1 = MT_WCOM|MT_GO;
966: }
967:
968: mtwait(mtaddr)
969: struct mtdevice *mtaddr;
970: {
971: register s;
972:
973: do
974: s = mtaddr->mtds;
975: while ((s & MTDS_DRY) == 0);
976: }
977:
978: mteof(mtaddr)
979: struct mtdevice *mtaddr;
980: {
981:
982: mtwait(mtaddr);
983: mtaddr->mtcs1 = MT_WEOF|MT_GO;
984: #endif notyet
985: }
986:
987: #ifdef MTLERRM
988: /*
989: * Failure messages for each failure code, per interrupt code.
990: * Each table ends with a code of -1 as a default.
991: */
992: struct fmesg {
993: int f_code;
994: char *f_mesg;
995: };
996:
997: static char unclass[] = "unclassified failure code";
998:
999: /* MTER_BOT */
1000: static struct fmesg botmsg[] = {
1001: 01, "tape was at BOT",
1002: 02, "BOT seen after tape started",
1003: 03, "ARA ID detected",
1004: -1, unclass
1005: };
1006:
1007: /* MTER_NOTRDY */
1008: static struct fmesg notrdymsg[] = {
1009: 01, "TU on-line but not ready",
1010: 02, "fatal error has occurred",
1011: 03, "access allowed but not ready",
1012: -1, unclass
1013: };
1014:
1015: /* MTER_NOTCAP */
1016: static struct fmesg notcapmsg[] = {
1017: 01, "no record found within 25 feet",
1018: 02, "ID burst neither PE nor GCR",
1019: 03, "ARA ID not found",
1020: 04, "no gap found after ID burst",
1021: -1, unclass
1022: };
1023:
1024: /* MTER_LONGREC */
1025: static struct fmesg longrecmsg[] = {
1026: 00, "extended sense data not found",
1027: 01, "extended sense data updated",
1028: -1, unclass
1029: };
1030:
1031: /* MTER_UNREAD, MTER_ERROR, MTER_EOTERR, MTER_BADTAPE */
1032: static struct fmesg code22msg[] = {
1033: 01, "GCR write error",
1034: 02, "GCR read error",
1035: 03, "PE read error",
1036: 04, "PE write error",
1037: 05, "at least 1 bit set in ECCSTA",
1038: 06, "PE write error",
1039: 07, "GCR write error",
1040: 010, "RSTAT contains bad code",
1041: 011, "PE write error",
1042: 012, "MASSBUS parity error",
1043: 013, "invalid data transferred",
1044: -1, unclass
1045: };
1046:
1047: /* MTER_TMFLTA */
1048: static struct fmesg tmfltamsg[] = {
1049: 01, "illegal command code",
1050: 02, "DT command issued when NDT command active",
1051: 03, "WMC error",
1052: 04, "RUN not received from MASSBUS controller",
1053: 05, "mismatch in command read - function routine",
1054: 06, "ECC ROM parity error",
1055: 07, "XMC ROM parity error",
1056: 010, "mismatch in command read - ID burst command",
1057: 011, "mismatch in command read - verify ARA burst command",
1058: 012, "mismatch in command read - verify ARA ID command",
1059: 013, "mismatch in command read - verify gap command",
1060: 014, "mismatch in command read - read id burst command",
1061: 015, "mismatch in command read - verify ARA ID command",
1062: 016, "mismatch in command read - verify gap command",
1063: 017, "mismatch in command read - find gap command",
1064: 020, "WMC LEFT failed to set",
1065: 021, "XL PE set in INTSTA register",
1066: 022, "XMC DONE did not set",
1067: 023, "WMC ROM PE or RD PE set in WMCERR register",
1068: -1, unclass
1069: };
1070:
1071: /* MTER_TUFLTA */
1072: static struct fmesg tufltamsg[] = {
1073: 01, "TU status parity error",
1074: 02, "TU command parity error",
1075: 03, "rewinding tape went offline",
1076: 04, "tape went not ready during DSE",
1077: 05, "TU CMD status changed during DSE",
1078: 06, "TU never came up to speed",
1079: 07, "TU velocity changed",
1080: 010, "TU CMD did not load correctly to start tape motion",
1081: 011, "TU CMD did not load correctly to set drive density",
1082: 012, "TU CMD did not load correctly to start tape motion to write BOT ID",
1083: 013, "TU CMD did not load correctly to backup tape to BOT after failing to write BOT ID",
1084: 014, "failed to write density ID burst",
1085: 015, "failed to write ARA burst",
1086: 016, "failed to write ARA ID",
1087: 017, "ARA error bit set in MTA status B register",
1088: 021, "could not find a gap after ID code was written correctly",
1089: 022, "TU CMD did not load correctly to start tape motion to read ID burst",
1090: 023, "timeout looking for BOT after detecting ARA ID burst",
1091: 024, "failed to write tape mark",
1092: 025, "tape never came up to speed while trying to reposition for retry of writing tape mark",
1093: 026, "TU CMD did not load correctly to start tape motion in erase gap routine",
1094: 027, "could not detect a gap in in erase gap routine",
1095: 030, "could not detect a gap after writing record",
1096: 031, "read path terminated before entire record was written",
1097: 032, "could not find a gap after writing record and read path terminated early",
1098: 033, "TU CMD did not load correctly to backup for retry of write tape mark",
1099: 034, "TU velocity changed after up to speed while trying to reposition for retry of writing tape mark",
1100: 035, "TU CMD did not load correctly to backup to retry a load of BOT ID",
1101: 036, "timeout looking for BOT after failing to write BOT ID",
1102: 037, "TU velocity changed while writing PE gap before starting to write record",
1103: 040, "TU CMD did not load correctly to set PE tape density at start of write BOT ID burst",
1104: 041, "TU CMD did not load correctly to set GCR tape density after writing Density ID",
1105: 042, "TU CMD did not load correctly to set PE tape density at start of read from BOT",
1106: 043, "TU CMD did not load correctly to set GCR tape density after reading a GCR Density ID burst",
1107: };
1108:
1109: /* MTER_TMFLTB */
1110: static char inlinetest[] = "inline test failed";
1111: static struct fmesg tmfltbmsg[] = {
1112: 00, "RST0 interrupt occurred with TM RDY set",
1113: 01, "power failed to interrupt",
1114: 02, "unknown interrupt on channel 5.5",
1115: 03, "unknown interrupt on channel 6.5",
1116: 04, "unknown interrupt on channel 7",
1117: 05, "unknown interrupt on channel 7.5",
1118: 06, "CAS contention retry count expired",
1119: 07, "CAS contention error not retryable",
1120: 010, "queue error, could not find queue entry",
1121: 011, "queue entry already full",
1122: 012, "8085 ROM parity error",
1123: 013, inlinetest,
1124: 013, inlinetest,
1125: 014, inlinetest,
1126: 015, inlinetest,
1127: 016, inlinetest,
1128: 017, inlinetest,
1129: 020, inlinetest,
1130: 021, inlinetest,
1131: 022, inlinetest,
1132: 023, inlinetest,
1133: 024, inlinetest,
1134: 025, inlinetest,
1135: 026, inlinetest,
1136: 027, inlinetest,
1137: 030, inlinetest,
1138: 031, inlinetest,
1139: 032, inlinetest,
1140: 033, inlinetest,
1141: 034, inlinetest,
1142: 035, inlinetest,
1143: 036, inlinetest,
1144: 037, inlinetest,
1145: 040, inlinetest,
1146: 041, inlinetest,
1147: 042, inlinetest,
1148: 043, inlinetest,
1149: 044, inlinetest,
1150: 045, inlinetest,
1151: 046, inlinetest,
1152: 047, inlinetest,
1153: 050, inlinetest,
1154: 051, inlinetest,
1155: 052, inlinetest,
1156: 053, inlinetest,
1157: 054, inlinetest,
1158: 055, inlinetest,
1159: 056, inlinetest,
1160: 057, inlinetest,
1161: -1, unclass
1162: };
1163:
1164: /* MTER_MBFLT */
1165: static struct fmesg mbfltmsg[] = {
1166: 01, "control bus parity error",
1167: 02, "illegal register referenced",
1168: -1, unclass
1169: };
1170:
1171: /*
1172: * MTER_LEOT, MTER_RWDING, NTER_NOTAVL, MTER_NONEX, MTER_KEYFAIL,
1173: * and default: no failure message.
1174: */
1175: static struct fmesg nullmsg[] = {
1176: -1, ""
1177: };
1178:
1179: /*
1180: * Interrupt code table.
1181: */
1182: static struct errmsg {
1183: int e_code;
1184: char *e_mesg;
1185: struct fmesg *e_fmesg;
1186: } errmsg[] = {
1187: MTER_BOT, "unexpected BOT", botmsg,
1188: MTER_LEOT, "unexpected LEOT", nullmsg,
1189: MTER_RWDING, "tape rewinding", nullmsg,
1190: MTER_NOTRDY, "drive not ready", notrdymsg,
1191: MTER_NOTAVL, "drive not available", nullmsg,
1192: MTER_NONEX, "unit does not exist", nullmsg,
1193: MTER_NOTCAP, "not capable", notcapmsg,
1194: MTER_LONGREC, "long record", longrecmsg,
1195: MTER_UNREAD, "unreadable record", code22msg,
1196: MTER_ERROR, "error", code22msg,
1197: MTER_EOTERR, "EOT error", code22msg,
1198: MTER_BADTAPE, "tape position lost", code22msg,
1199: MTER_TMFLTA, "TM fault A", tmfltamsg,
1200: MTER_TUFLTA, "TU fault A", tufltamsg,
1201: MTER_TMFLTB, "TM fault B", tmfltbmsg,
1202: MTER_MBFLT, "MB fault", mbfltmsg,
1203: MTER_KEYFAIL, "keypad entry error", nullmsg,
1204: -1, "unclassified error", nullmsg
1205: };
1206:
1207: /*
1208: * Decode an interrupt-time failure.
1209: */
1210: mtintfail(erreg)
1211: int erreg;
1212: {
1213: register struct errmsg *e;
1214: register struct fmesg *f;
1215: register int ecode, fcode;
1216:
1217: ecode = erreg & MTER_INTCODE;
1218: fcode = (erreg & MTER_FAILCODE) >> MTER_FSHIFT;
1219: for (e = errmsg; e->e_code >= 0; e++)
1220: if (e->e_code == ecode)
1221: break;
1222: for (f = e->e_fmesg; f->f_code >= 0; f++)
1223: if (f->f_code == fcode)
1224: break;
1225: printf(" interrupt code = 0%o <%s>\n", ecode, e->e_mesg);
1226: printf(" failure code = 0%o <%s>\n", fcode, f->f_mesg);
1227: }
1228: #endif /* MTLERRM */
1229: #endif /* NMT > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.