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