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