1 /* nova_mta.c: NOVA magnetic tape simulator
2 
3    Copyright (c) 1993-2008, Robert M. Supnik
4 
5    Permission is hereby granted, free of charge, to any person obtaining a
6    copy of this software and associated documentation files (the "Software"),
7    to deal in the Software without restriction, including without limitation
8    the rights to use, copy, modify, merge, publish, distribute, sublicense,
9    and/or sell copies of the Software, and to permit persons to whom the
10    Software is furnished to do so, subject to the following conditions:
11 
12    The above copyright notice and this permission notice shall be included in
13    all copies or substantial portions of the Software.
14 
15    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18    ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19    IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22    Except as contained in this notice, the name of Robert M Supnik shall not be
23    used in advertising or otherwise to promote the sale, use or other dealings
24    in this Software without prior written authorization from Robert M Supnik.
25 
26    mta          magnetic tape
27 
28    04-Jul-07    BKR     fixed boot code to properly boot self-boot tapes;
29                         boot routine now uses standard DG APL boot code;
30                         device name changed to DG's MTA from DEC's MT.
31    16-Aug-05    RMS     Fixed C++ declaration and cast problems
32    18-Mar-05    RMS     Added attached test to detach routine
33    22-Nov-03    CEO     DIB returns # records skipped after space fwd
34    22-Nov-03    CEO     Removed cancel of tape events in IORST
35    25-Apr-03    RMS     Revised for extended file support
36    28-Mar-03    RMS     Added multiformat support
37    28-Feb-03    RMS     Revised for magtape library
38    30-Oct-02    RMS     Fixed BOT handling, added error record handling
39    08-Oct-02    RMS     Added DIB
40    30-Sep-02    RMS     Revamped error handling
41    28-Aug-02    RMS     Added end of medium support
42    30-May-02    RMS     Widened POS to 32b
43    22-Apr-02    RMS     Added maximum record length test
44    06-Jan-02    RMS     Revised enable/disable support
45    30-Nov-01    RMS     Added read only unit, extended SET/SHOW support
46    24-Nov-01    RMS     Changed POS, USTAT, FLG to an array
47    26-Apr-01    RMS     Added device enable/disable support
48    18-Apr-01    RMS     Changed to rewind tape before boot
49    10-Dec-00    RMS     Added Eclipse support (Charles Owen)
50    15-Oct-00    RMS     Editorial changes
51    11-Nov-98    CEO     Removed clear of mta_ma on iopC
52    04-Oct-98    RMS     V2.4 magtape format
53    18-Jan-97    RMS     V2.3 magtape format
54    29-Jun-96    RMS     Added unit enable/disable support
55 
56    Magnetic tapes are represented as a series of variable records
57    of the form:
58 
59         32b byte count                  byte count is little endian
60         byte 0
61         byte 1
62         :
63         byte n-2
64         byte n-1
65         32b byte count
66 
67    If the byte count is odd, the record is padded with an extra byte
68    of junk.  File marks are represented by a byte count of 0 and are
69    not duplicated; end of tape by end of file.
70 */
71 
72 #include "nova_defs.h"
73 #include "sim_tape.h"
74 
75 #define MTA_NUMDR       8                               /* #drives */
76 #define USTAT           u3                              /* unit status */
77 #define MTA_MAXFR       (1 << 16)                       /* max record lnt */
78 #define WC_SIZE         (1 << 14)                       /* max word count */
79 #define WC_MASK         (WC_SIZE - 1)
80 
81 /* Command/unit */
82 
83 #define CU_CI           0100000                         /* clear interrupt */
84 #define CU_EP           0002000                         /* poll enable */
85 #define CU_DE           0001000                         /* disable erase */
86 #define CU_DA           0000400                         /* disable autoretry */
87 #define CU_PE           0000400                         /* PE mode */
88 #define CU_V_CMD        3                               /* command */
89 #define CU_M_CMD        027
90 #define  CU_READ         000
91 #define  CU_REWIND       001
92 #define  CU_CMODE        002
93 #define  CU_SPACEF       003
94 #define  CU_SPACER       004
95 #define  CU_WRITE        005
96 #define  CU_WREOF        006
97 #define  CU_ERASE        007
98 #define  CU_READNS       020
99 #define  CU_UNLOAD       021
100 #define  CU_DMODE        022
101 #define CU_V_UNIT       0                               /* unit */
102 #define CU_M_UNIT       07
103 #define GET_CMD(x)      (((x) >> CU_V_CMD) & CU_M_CMD)
104 #define GET_UNIT(x)     (((x) >> CU_V_UNIT) & CU_M_UNIT)
105 
106 /* Status 1 - stored in mta_sta<31:16> or (*) uptr->USTAT<31:16> */
107 
108 #define STA_ERR1        (0100000u << 16)                /* error */
109 #define STA_DLT         (0040000 << 16)                 /* data late */
110 #define STA_REW         (0020000 << 16)                 /* *rewinding */
111 #define STA_ILL         (0010000 << 16)                 /* illegal */
112 #define STA_HDN         (0004000 << 16)                 /* high density */
113 #define STA_DAE         (0002000 << 16)                 /* data error */
114 #define STA_EOT         (0001000 << 16)                 /* *end of tape */
115 #define STA_EOF         (0000400 << 16)                 /* *end of file */
116 #define STA_BOT         (0000200 << 16)                 /* *start of tape */
117 #define STA_9TK         (0000100 << 16)                 /* nine track */
118 #define STA_BAT         (0000040 << 16)                 /* bad tape */
119 #define STA_CHG         (0000010 << 16)                 /* status change */
120 #define STA_WLK         (0000004 << 16)                 /* *write lock */
121 #define STA_ODD         (0000002 << 16)                 /* odd character */
122 #define STA_RDY         (0000001 << 16)                 /* *drive ready */
123 
124 /* Status 2 - stored in mta_sta<15:0> or (*) uptr->USTAT<15:0> */
125 
126 #define STA_ERR2        0100000                         /* error */
127 #define STA_RWY         0040000                         /* runaway tape */
128 #define STA_FGP         0020000                         /* false gap */
129 #define STA_CDL         0004000                         /* corrected dlt */
130 #define STA_V_UNIT      8
131 #define STA_M_UNIT      07                              /* unit */
132 #define STA_WCO         0000200                         /* word count ovflo */
133 #define STA_BDS         0000100                         /* bad signal */
134 #define STA_OVS         0000040                         /* overskew */
135 #define STA_CRC         0000020                         /* check error */
136 #define STA_STE         0000010                         /* single trk error */
137 #define STA_FPR         0000004                         /* false preamble */
138 #define STA_FMT         0000002                         /* format error */
139 #define STA_PEM         0000001                         /* *PE mode */
140 
141 #define STA_EFLGS1      (STA_DLT | STA_ILL | STA_DAE | STA_EOT | \
142 						 STA_EOF | STA_BOT | STA_BAT | STA_ODD)
143 #define STA_EFLGS2      (STA_FGP | STA_CDL | STA_BDS | STA_OVS | \
144 						 STA_CRC | STA_FPR | STA_FPR)   /* set error 2 */
145 #define STA_CLR         ((020 << 16) | 0010000)         /* always clear */
146 #define STA_SET         (STA_HDN | STA_9TK)             /* always set */
147 #define STA_DYN         (STA_REW | STA_EOT | STA_EOF | STA_BOT | \
148 						 STA_WLK | STA_RDY | STA_PEM)   /* kept in USTAT */
149 #define STA_MON         (STA_REW | STA_BOT | STA_WLK | STA_RDY | \
150 						 STA_PEM)                       /* set status chg */
151 
152 extern	uint16	M[];
153 extern	UNIT	cpu_unit;
154 extern	int32	int_req, dev_busy, dev_done, dev_disable;
155 extern	int32	SR, AMASK;
156 
157 extern	t_stat  cpu_boot(int32 unitno, DEVICE * dptr ) ;
158 
159 
160 int32 mta_ma = 0;                                       /* memory address */
161 int32 mta_wc = 0;                                       /* word count */
162 int32 mta_cu = 0;                                       /* command/unit */
163 int32 mta_sta = 0;                                      /* status register */
164 int32 mta_ep = 0;                                       /* enable polling */
165 int32 mta_cwait = 100;                                  /* command latency */
166 int32 mta_rwait = 100;                                  /* record latency */
167 uint8 *mtxb = NULL;                                     /* transfer buffer */
168 
169 DEVICE mta_dev;
170 int32 mta (int32 pulse, int32 code, int32 AC);
171 t_stat mta_svc (UNIT *uptr);
172 t_stat mta_reset (DEVICE *dptr);
173 t_stat mta_boot (int32 unitno, DEVICE *dptr);
174 t_stat mta_attach (UNIT *uptr, char *cptr);
175 t_stat mta_detach (UNIT *uptr);
176 int32 mta_updcsta (UNIT *uptr);
177 void mta_upddsta (UNIT *uptr, int32 newsta);
178 t_stat mta_map_err (UNIT *uptr, t_stat st);
179 t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc);
180 
181 static const int ctype[32] = {                          /* c vs r timing */
182  0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
183  0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1
184  };
185 
186 /* MTA data structures
187 
188    mta_dev      MTA device descriptor
189    mta_unit     MTA unit list
190    mta_reg      MTA register list
191    mta_mod      MTA modifier list
192 */
193 
194 DIB mta_dib = { DEV_MTA, INT_MTA, PI_MTA, &mta };
195 
196 UNIT mta_unit[] = {
197     { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
198     { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
199     { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
200     { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
201     { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
202     { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
203     { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) },
204     { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }
205     };
206 
207 REG mta_reg[] = {
208     { ORDATA (CU, mta_cu, 16) },
209     { ORDATA (MA, mta_ma, 16) },
210     { ORDATA (WC, mta_wc, 16) },
211     { GRDATA (STA1, mta_sta, 8, 16, 16) },
212     { ORDATA (STA2, mta_sta, 16) },
213     { FLDATA (EP, mta_ep, 0) },
214     { FLDATA (BUSY, dev_busy, INT_V_MTA) },
215     { FLDATA (DONE, dev_done, INT_V_MTA) },
216     { FLDATA (DISABLE, dev_disable, INT_V_MTA) },
217     { FLDATA (INT, int_req, INT_V_MTA) },
218     { DRDATA (CTIME, mta_cwait, 24), PV_LEFT },
219     { DRDATA (RTIME, mta_rwait, 24), PV_LEFT },
220     { URDATA (UST, mta_unit[0].USTAT, 8, 32, 0, MTA_NUMDR, 0) },
221     { URDATA (POS, mta_unit[0].pos, 8, T_ADDR_W, 0,
222               MTA_NUMDR, REG_RO | PV_LEFT) },
223     { NULL }
224     };
225 
226 MTAB mta_mod[] = {
227     { MTUF_WLK, 0, "write enabled", "WRITEENABLED", &mta_vlock },
228     { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", &mta_vlock },
229     { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
230       &sim_tape_set_fmt, &sim_tape_show_fmt, NULL },
231     { 0 }
232     };
233 
234 DEVICE mta_dev = {
235     "MTA", mta_unit, mta_reg, mta_mod,
236     MTA_NUMDR, 10, 31, 1, 8, 8,
237     NULL, NULL, &mta_reset,
238     &mta_boot, &mta_attach, &mta_detach,
239     &mta_dib, DEV_DISABLE
240     };
241 
242 /* IOT routine */
243 
mta(int32 pulse,int32 code,int32 AC)244 int32 mta (int32 pulse, int32 code, int32 AC)
245 {
246 UNIT *uptr;
247 int32 u, c, rval;
248 
249 rval = 0;
250 uptr = mta_dev.units + GET_UNIT(mta_cu);                /* get unit */
251 switch (code) {                                         /* decode IR<5:7> */
252 
253     case ioDIA:                                         /* DIA */
254         rval = (mta_updcsta (uptr) >> 16) & DMASK;      /* return status 1 */
255         break;
256 
257     case ioDOA:                                         /* DOA */
258 /*      if (AC & CU_CI) ... clear ep int */
259         mta_cu = AC;                                    /* save cmd/unit */
260         uptr = mta_dev.units + GET_UNIT(mta_cu);        /* get unit */
261         mta_updcsta (uptr);                             /* update status */
262         break;
263 
264     case ioDIB:                                         /* DIB */
265         rval = mta_ma & AMASK;                          /* return ma */
266         break;
267 
268     case ioDOB:                                         /* DOB */
269         mta_ma = AC & AMASK;                            /* save ma */
270         break;
271 
272     case ioDIC:                                         /* DIC */
273         rval = mta_updcsta (uptr) & DMASK;              /* return status 2 */
274         break;
275 
276     case ioDOC:                                         /* DOC */
277         mta_wc = ((AC & 040000) << 1) | (AC & 077777);  /* save wc */
278         break;
279         }                                               /* end switch code */
280 
281 switch (pulse) {                                        /* decode IR<8:9> */
282 
283     case iopS:                                          /* start */
284         c = GET_CMD (mta_cu);                           /* get command */
285         if (dev_busy & INT_MTA)                         /* ignore if busy */
286             break;
287         if ((uptr->USTAT & STA_RDY) == 0) {             /* drive not ready? */
288             mta_sta = mta_sta | STA_ILL;                /* illegal op */
289             dev_busy = dev_busy & ~INT_MTA;             /* clear busy */
290             dev_done = dev_done | INT_MTA;              /* set done */
291             int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
292             }
293         else if ((c == CU_REWIND) || (c == CU_UNLOAD)) { /* rewind, unload? */
294             mta_upddsta (uptr, (uptr->USTAT &           /* update status */
295                 ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)) | STA_REW);
296             sim_activate (uptr, mta_rwait);             /* start IO */
297             if (c == CU_UNLOAD)
298                 detach_unit (uptr);
299             }
300         else {
301             mta_sta = 0;                                /* clear errors */
302             dev_busy = dev_busy | INT_MTA;              /* set busy */
303             dev_done = dev_done & ~INT_MTA;             /* clear done */
304             int_req = int_req & ~INT_MTA;               /* clear int */
305             if (ctype[c])
306                 sim_activate (uptr, mta_cwait);
307             else {
308                 mta_upddsta (uptr, uptr->USTAT &
309                    ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY));
310                 sim_activate (uptr, mta_rwait);
311                 }
312             }
313         mta_updcsta (uptr);                             /* update status */
314         break;
315 
316     case iopC:                                          /* clear */
317         for (u = 0; u < MTA_NUMDR; u++) {               /* loop thru units */
318             uptr = mta_dev.units + u;                   /* cancel IO */
319             if (sim_is_active (uptr) && !(uptr->USTAT & STA_REW)) {
320                 mta_upddsta (uptr, uptr->USTAT | STA_RDY);
321                 sim_cancel (uptr);
322                 }
323             }
324         dev_busy = dev_busy & ~INT_MTA;                 /* clear busy */
325         dev_done = dev_done & ~INT_MTA;                 /* clear done */
326         int_req = int_req & ~INT_MTA;                   /* clear int */
327         mta_sta = mta_cu = 0;                           /* clear registers */
328         mta_updcsta (&mta_unit[0]);                     /* update status */
329         break;
330         }                                               /* end case pulse */
331 
332 return rval;
333 }
334 
335 /* Unit service
336 
337    If rewind done, reposition to start of tape, set status
338    else, do operation, clear busy, set done, interrupt
339 */
340 
mta_svc(UNIT * uptr)341 t_stat mta_svc (UNIT *uptr)
342 {
343 int32 c, p, pa, u;
344 t_mtrlnt i, cbc, tbc, wc;
345 uint16 c1, c2;
346 t_stat st, r = SCPE_OK;
347 
348 u = uptr - mta_dev.units;                               /* get unit number */
349 c = GET_CMD (mta_cu);                                   /* command */
350 wc = WC_SIZE - (mta_wc & WC_MASK);                      /* io wc */
351 
352 if (uptr->USTAT & STA_REW) {                            /* rewind? */
353     sim_tape_rewind (uptr);                             /* update tape */
354     mta_upddsta (uptr, (uptr->USTAT & ~STA_REW) | STA_BOT | STA_RDY);
355     if (u == GET_UNIT (mta_cu))
356         mta_updcsta (uptr);
357     return SCPE_OK;
358     }
359 
360 if ((uptr->flags & UNIT_ATT) == 0) {                    /* not attached? */
361     mta_upddsta (uptr, 0);                              /* unit off line */
362     mta_sta = mta_sta | STA_ILL;                        /* illegal operation */
363     }
364 else switch (c) {                                       /* case on command */
365 
366 	case CU_CMODE:                                      /* controller mode */
367 		mta_ep = mta_cu & CU_EP;
368 		break;
369 
370     case CU_DMODE:                                      /* drive mode */
371         if (!sim_tape_bot (uptr))                       /* must be BOT */
372             mta_sta = mta_sta | STA_ILL;
373         else mta_upddsta (uptr, (mta_cu & CU_PE)?       /* update drv status */
374             uptr->USTAT | STA_PEM: uptr->USTAT & ~ STA_PEM);
375         break;
376 
377     case CU_READ:                                       /* read */
378     case CU_READNS:                                     /* read non-stop */
379         st = sim_tape_rdrecf (uptr, mtxb, &tbc, MTA_MAXFR); /* read rec */
380         if (st == MTSE_RECE)                            /* rec in err? */
381             mta_sta = mta_sta | STA_DAE;
382         else if (st != MTSE_OK) {                       /* other error? */
383             r = mta_map_err (uptr, st);                 /* map error */
384             break;
385             }
386         cbc = wc * 2;                                   /* expected bc */
387         if (tbc & 1)                                    /* odd byte count? */
388             mta_sta = mta_sta | STA_ODD;
389         if (tbc > cbc)                                  /* too big? */
390             mta_sta = mta_sta | STA_WCO;
391         else {
392             cbc = tbc;                                  /* no, use it */
393             wc = (cbc + 1) / 2;                         /* adjust wc */
394             }
395         for (i = p = 0; i < wc; i++) {                  /* copy buf to mem */
396             c1 = mtxb[p++];
397             c2 = mtxb[p++];
398             pa = MapAddr (0, mta_ma);                   /* map address */
399             if (MEM_ADDR_OK (pa))
400                 M[pa] = (c1 << 8) | c2;
401             mta_ma = (mta_ma + 1) & AMASK;
402             }
403         mta_wc = (mta_wc + wc) & DMASK;
404         mta_upddsta (uptr, uptr->USTAT | STA_RDY);
405         break;
406 
407     case CU_WRITE:                                      /* write */
408         tbc = wc * 2;                                   /* io byte count */
409         for (i = p = 0; i < wc; i++) {                  /* copy to buffer */
410             pa = MapAddr (0, mta_ma);                   /* map address */
411             mtxb[p++] = (M[pa] >> 8) & 0377;
412             mtxb[p++] = M[pa] & 0377;
413             mta_ma = (mta_ma + 1) & AMASK;
414             }
415         if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) { /* write rec, err? */
416             r = mta_map_err (uptr, st);                 /* map error */
417             mta_ma = (mta_ma - wc) & AMASK;             /* restore wc */
418             }
419         else mta_wc = 0;                                /* clear wc */
420         mta_upddsta (uptr, uptr->USTAT | STA_RDY);
421         break;
422 
423     case CU_WREOF:                                      /* write eof */
424         if ((st = sim_tape_wrtmk (uptr)))               /* write tmk, err? */
425             r = mta_map_err (uptr, st);                 /* map error */
426         else mta_upddsta (uptr, uptr->USTAT | STA_EOF | STA_RDY);
427         break;
428 
429     case CU_ERASE:                                      /* erase */
430         if (sim_tape_wrp (uptr))                        /* write protected? */
431             r = mta_map_err (uptr, MTSE_WRP);           /* map error */
432         else mta_upddsta (uptr, uptr->USTAT | STA_RDY);
433         break;
434 
435     case CU_SPACEF:                                     /* space forward */
436         do {
437             mta_wc = (mta_wc + 1) & DMASK;              /* incr wc */
438             if ((st = sim_tape_sprecf (uptr, &tbc))) {  /* space rec fwd, err? */
439                 r = mta_map_err (uptr, st);             /* map error */
440                 break;
441                 }
442             } while (mta_wc != 0);
443         mta_upddsta (uptr, uptr->USTAT | STA_RDY);
444         mta_ma = mta_wc;                                /* word count = # records */
445         break;
446 
447     case CU_SPACER:                                     /* space reverse */
448         do {
449             mta_wc = (mta_wc + 1) & DMASK;              /* incr wc */
450             if ((st = sim_tape_sprecr (uptr, &tbc))) {  /* space rec rev, err? */
451                 r = mta_map_err (uptr, st);             /* map error */
452                 break;
453                 }
454             } while (mta_wc != 0);
455         mta_upddsta (uptr, uptr->USTAT | STA_RDY);
456         mta_ma = mta_wc;                                /* word count = # records */
457         break;
458 
459     default:                                            /* reserved */
460         mta_sta = mta_sta | STA_ILL;
461         mta_upddsta (uptr, uptr->USTAT | STA_RDY);
462         break;
463         }                                               /* end case */
464 
465 mta_updcsta (uptr);                                     /* update status */
466 dev_busy = dev_busy & ~INT_MTA;                         /* clear busy */
467 dev_done = dev_done | INT_MTA;                          /* set done */
468 int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable);
469 return r;
470 }
471 
472 /* Update controller status */
473 
mta_updcsta(UNIT * uptr)474 int32 mta_updcsta (UNIT *uptr)                          /* update ctrl */
475 {
476 mta_sta = (mta_sta & ~(STA_DYN | STA_CLR | STA_ERR1 | STA_ERR2)) |
477     (uptr->USTAT & STA_DYN) | STA_SET;
478 if (mta_sta & STA_EFLGS1)
479     mta_sta = mta_sta | STA_ERR1;
480 if (mta_sta & STA_EFLGS2)
481     mta_sta = mta_sta | STA_ERR2;
482 return mta_sta;
483 }
484 
485 /* Update drive status */
486 
mta_upddsta(UNIT * uptr,int32 newsta)487 void mta_upddsta (UNIT *uptr, int32 newsta)             /* drive status */
488 {
489 int32 change;
490 
491 if ((uptr->flags & UNIT_ATT) == 0)                      /* offline? */
492     newsta = 0;
493 change = (uptr->USTAT ^ newsta) & STA_MON;              /* changes? */
494 uptr->USTAT = newsta & STA_DYN;                         /* update status */
495 if (change) {
496 /*  if (mta_ep) {                                       /* if polling */
497 /*      u = uptr - mta_dev.units;                       /* unit num */
498 /*      mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT);
499 /*      set polling interupt...
500 /*      }                                               */
501     mta_sta = mta_sta | STA_CHG;                        /* flag change */
502     }
503 return;
504 }
505 
506 /* Map tape error status */
507 
mta_map_err(UNIT * uptr,t_stat st)508 t_stat mta_map_err (UNIT *uptr, t_stat st)
509 {
510 switch (st) {
511 
512     case MTSE_FMT:                                      /* illegal fmt */
513         mta_upddsta (uptr, uptr->USTAT | STA_WLK | STA_RDY);
514     case MTSE_UNATT:                                    /* unattached */
515         mta_sta = mta_sta | STA_ILL;
516     case MTSE_OK:                                       /* no error */
517         return SCPE_IERR;                               /* never get here! */
518 
519     case MTSE_TMK:                                      /* end of file */
520         mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_EOF);
521         break;
522 
523     case MTSE_IOERR:                                    /* IO error */
524         mta_sta = mta_sta | STA_DAE;                    /* data error */
525         mta_upddsta (uptr, uptr->USTAT | STA_RDY);      /* ready */
526         return SCPE_IOERR;
527 
528     case MTSE_INVRL:                                    /* invalid rec lnt */
529         mta_sta = mta_sta | STA_DAE;                    /* data error */
530         mta_upddsta (uptr, uptr->USTAT | STA_RDY);      /* ready */
531         return SCPE_MTRLNT;
532 
533     case MTSE_RECE:                                     /* record in error */
534         mta_sta = mta_sta | STA_DAE;                    /* data error */
535         mta_upddsta (uptr, uptr->USTAT | STA_RDY);      /* ready */
536         break;
537 
538     case MTSE_EOM:                                      /* end of medium */
539         mta_sta = mta_sta | STA_BAT;                    /* bad tape */
540         mta_upddsta (uptr, uptr->USTAT | STA_RDY);      /* ready */
541         break;
542 
543     case MTSE_BOT:                                      /* reverse into BOT */
544         mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_BOT);
545         break;
546 
547     case MTSE_WRP:                                      /* write protect */
548         mta_upddsta (uptr, uptr->USTAT | STA_WLK | STA_RDY);
549         mta_sta = mta_sta | STA_ILL;                    /* illegal operation */
550         break;
551         }
552 
553 return SCPE_OK;
554 }
555 
556 /* Reset routine */
557 
mta_reset(DEVICE * dptr)558 t_stat mta_reset (DEVICE *dptr)
559 {
560 int32 u;
561 UNIT *uptr;
562 
563 dev_busy = dev_busy & ~INT_MTA;                         /* clear busy */
564 dev_done = dev_done & ~INT_MTA;                         /* clear done, int */
565 int_req = int_req & ~INT_MTA;
566 mta_cu = mta_wc = mta_ma = mta_sta = 0;                 /* clear registers */
567 mta_ep = 0;
568 
569 /* AOS Installer does an IORST after a tape rewind command but before it can
570    be serviced, yet expects the tape to have been rewound */
571 
572 for (u = 0; u < MTA_NUMDR; u++) {                       /* loop thru units */
573     uptr = mta_dev.units + u;
574     if (sim_is_active (uptr) &&                         /* active and */
575        (uptr->flags & STA_REW))                         /* rewinding? */
576         sim_tape_rewind (uptr);                         /* update tape */
577     sim_tape_reset (uptr);                              /* clear pos flag */
578     sim_cancel (uptr);                                  /* cancel activity */
579     if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_RDY |
580 		(uptr->USTAT & STA_PEM) |
581 		(sim_tape_wrp (uptr)? STA_WLK: 0) |
582 		(sim_tape_bot (uptr)? STA_BOT: 0);
583     else uptr->USTAT = 0;
584     }
585 mta_updcsta (&mta_unit[0]);                             /* update status */
586 if (mtxb == NULL)
587     mtxb = (uint8 *) calloc (MTA_MAXFR, sizeof (uint8));
588 if (mtxb == NULL)
589     return SCPE_MEM;
590 return SCPE_OK;
591 }
592 
593 /* Attach routine */
594 
mta_attach(UNIT * uptr,char * cptr)595 t_stat mta_attach (UNIT *uptr, char *cptr)
596 {
597 t_stat r;
598 
599 r = sim_tape_attach (uptr, cptr);
600 if (r != SCPE_OK)
601     return r;
602 if (!sim_is_active (uptr))
603     mta_upddsta (uptr, STA_RDY | STA_BOT | STA_PEM |
604         (sim_tape_wrp (uptr)? STA_WLK: 0));
605 return r;
606 }
607 
608 /* Detach routine */
609 
mta_detach(UNIT * uptr)610 t_stat mta_detach (UNIT* uptr)
611 {
612 if (!(uptr->flags & UNIT_ATT))                          /* attached? */
613     return SCPE_OK;
614 if (!sim_is_active (uptr))
615     mta_upddsta (uptr, 0);
616 return sim_tape_detach (uptr);
617 }
618 
619 /* Write lock/unlock validate routine */
620 
mta_vlock(UNIT * uptr,int32 val,char * cptr,void * desc)621 t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc)
622 {
623 if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr)))
624     mta_upddsta (uptr, uptr->USTAT | STA_WLK);
625 else mta_upddsta (uptr, uptr->USTAT & ~STA_WLK);
626 return SCPE_OK;
627 }
628 
629 /*  Boot routine  */
630 
mta_boot(int32 unitno,DEVICE * dptr)631 t_stat mta_boot (int32 unitno, DEVICE *dptr)
632 	{
633 	sim_tape_rewind( &mta_unit[unitno] ) ;
634 	/*
635 	use common rewind/reset code
636 		device reset
637 		rewind 'tape' file
638 		device
639 		unit
640 		controller
641 	 */
642 	cpu_boot( unitno, dptr ) ;
643 	SR = 0100000 + DEV_MTA ;
644 	return ( SCPE_OK );
645 	}	/*  end of 'mta_boot'  */
646