This source file includes following definitions.
- mtp_show_nunits
- mtp_set_nunits
- mtp_show_boot_drive
- mtp_set_boot_drive
- mtp_show_device_name
- mtp_set_device_name
- mtp_reset
- mt_rewind
- mt_show_nunits
- mt_set_nunits
- mt_show_device_name
- mt_set_device_name
- mt_show_tape_path
- mt_set_tape_path
- mt_add_tape_search_path
- mt_show_tape_search_paths
- mt_set_capac
- signal_tape
- tape_set_ready
- mt_reset
- deterimeFullTapeFileName
- loadTape
- unloadTape
- mt_init
- mt_exit
- mtReadRecord
- mtReadCtrlMainMem
- mtInitRdMem
- mtWRCtrlRegs
- mtInitWrMem
- mtMTPWr
- mtWriteRecord
- surveyDevices
- mt_iom_cmd
- simh_tape_msg
- attachTape
- mount_tape
- detachTape
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 #include <stdio.h>
34 #include <signal.h>
35 #include <ctype.h>
36 #include <dirent.h>
37
38 #include "dps8.h"
39 #include "dps8_sys.h"
40 #include "dps8_iom.h"
41 #include "dps8_cable.h"
42 #include "dps8_cpu.h"
43 #include "dps8_faults.h"
44 #include "dps8_scu.h"
45 #include "dps8_utils.h"
46 #include "dps8_mt.h"
47
48 #define DBG_CTR 1
49
50 #if defined(FREE)
51 # undef FREE
52 #endif
53 #define FREE(p) do \
54 { \
55 free((p)); \
56 (p) = NULL; \
57 } while(0)
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 #include "sim_tape.h"
127
128 static DEBTAB mt_dt [] =
129 {
130 { "NOTIFY", DBG_NOTIFY, NULL },
131 { "INFO", DBG_INFO, NULL },
132 { "ERR", DBG_ERR, NULL },
133 { "WARN", DBG_WARN, NULL },
134 { "DEBUG", DBG_DEBUG, NULL },
135 { "TRACE", DBG_TRACE, NULL },
136 { "ALL", DBG_ALL, NULL },
137 { NULL, 0, NULL }
138 };
139
140
141
142
143
144
145
146 #define MTP_UNIT_IDX(uptr) ((uptr) - mtp_unit)
147 #define N_MTP_UNITS 1
148
149 static struct mtp_state_s
150 {
151 uint boot_drive;
152 char device_name [MAX_DEV_NAME_LEN];
153 } mtp_state [N_MTP_UNITS_MAX];
154
155 static t_stat mtp_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
156 UNUSED int val, UNUSED const void * desc)
157 {
158 sim_printf ("Number of MTP controllers in the system is %d\n",
159 mtp_dev.numunits);
160 return SCPE_OK;
161 }
162
163 static t_stat mtp_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
164 const char * cptr, UNUSED void * desc)
165 {
166 if (! cptr)
167 return SCPE_ARG;
168 int n = atoi (cptr);
169 if (n < 0 || n > N_MTP_UNITS_MAX)
170 return SCPE_ARG;
171 mtp_dev.numunits = (uint32) n;
172 return SCPE_OK;
173 }
174
175 static t_stat mtp_show_boot_drive (UNUSED FILE * st, UNIT * uptr,
176 UNUSED int val, UNUSED const void * desc)
177 {
178 long mtp_unit_idx = MTP_UNIT_IDX (uptr);
179 if (mtp_unit_idx < 0 || mtp_unit_idx >= N_MTP_UNITS_MAX)
180 {
181 sim_printf ("Controller unit number out of range\n");
182 return SCPE_ARG;
183 }
184 sim_printf ("boot : %u",
185 mtp_state[mtp_unit_idx].boot_drive);
186 return SCPE_OK;
187 }
188
189 static t_stat mtp_set_boot_drive (UNIT * uptr, UNUSED int32 value,
190 const char * cptr, UNUSED void * desc)
191 {
192 long mtp_unit_idx = MTP_UNIT_IDX (uptr);
193 if (mtp_unit_idx < 0 || mtp_unit_idx >= N_MTP_UNITS_MAX)
194 {
195 sim_printf ("Controller unit number out of range\n");
196 return SCPE_ARG;
197 }
198 if (! cptr)
199 return SCPE_ARG;
200 int n = (int) atoi (cptr);
201 if (n < 0 || n >= N_DEV_CODES)
202 return SCPE_ARG;
203 mtp_state[mtp_unit_idx].boot_drive = (uint) n;
204 return SCPE_OK;
205 }
206
207 UNIT mtp_unit [N_MTP_UNITS_MAX] = {
208 #if defined(NO_C_ELLIPSIS)
209 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
210 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
211 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
212 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
213 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
214 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
215 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
216 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
217 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
218 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
219 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
220 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
221 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
222 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
223 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
224 { UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
225 #else
226 [0 ... N_MTP_UNITS_MAX-1] = {
227 UDATA (NULL, 0, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
228 }
229 #endif
230 };
231
232 static t_stat mtp_show_device_name (UNUSED FILE * st, UNIT * uptr,
233 UNUSED int val, UNUSED const void * desc)
234 {
235 int n = (int) MTP_UNIT_IDX (uptr);
236 if (n < 0 || n >= N_MTP_UNITS_MAX)
237 return SCPE_ARG;
238 sim_printf("name : %s", mtp_state [n].device_name);
239 return SCPE_OK;
240 }
241
242 static t_stat mtp_set_device_name (UNIT * uptr, UNUSED int32 value,
243 const char * cptr, UNUSED void * desc)
244 {
245 int n = (int) MTP_UNIT_IDX (uptr);
246 if (n < 0 || n >= N_MTP_UNITS_MAX)
247 return SCPE_ARG;
248 if (cptr)
249 {
250 strncpy (mtp_state[n].device_name, cptr, MAX_DEV_NAME_LEN-1);
251 mtp_state[n].device_name[MAX_DEV_NAME_LEN-1] = 0;
252 }
253 else
254 mtp_state[n].device_name[0] = 0;
255 return SCPE_OK;
256 }
257
258 static MTAB mtp_mod [] =
259 {
260 {
261 MTAB_XTD | MTAB_VDV | \
262 MTAB_NMO | MTAB_VALR,
263 0,
264 "NUNITS",
265 "NUNITS",
266 mtp_set_nunits,
267 mtp_show_nunits,
268 "Number of TAPE units in the system",
269 NULL
270 },
271 {
272 MTAB_XTD | MTAB_VUN | MTAB_VALR,
273 0,
274 "BOOT_DRIVE",
275 "BOOT_DRIVE",
276 mtp_set_boot_drive,
277 mtp_show_boot_drive,
278 "Select the boot drive",
279 NULL
280 },
281 {
282 MTAB_XTD | MTAB_VUN | \
283 MTAB_VALR | MTAB_NC,
284 0,
285 "NAME",
286 "NAME",
287 mtp_set_device_name,
288 mtp_show_device_name,
289 "Set the device name",
290 NULL
291 },
292 { 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }
293 };
294
295 static t_stat mtp_reset (UNUSED DEVICE * dptr)
296 {
297 return SCPE_OK;
298 }
299
300 DEVICE mtp_dev =
301 {
302 "MTP",
303 mtp_unit,
304 NULL,
305 mtp_mod,
306 N_MTP_UNITS,
307 10,
308 31,
309 1,
310 8,
311 9,
312 NULL,
313 NULL,
314 mtp_reset,
315 NULL,
316 NULL,
317 NULL,
318 NULL,
319 DEV_DEBUG,
320 0,
321 mt_dt,
322 NULL,
323 NULL,
324 NULL,
325 NULL,
326 NULL,
327 NULL,
328 NULL
329 };
330
331
332
333
334
335
336
337 #define MT_UNIT_NUM(uptr) ((uptr) - mt_unit)
338
339 struct tape_state tape_states [N_MT_UNITS_MAX];
340 static const char * simh_tape_msg (int code);
341
342 static char tape_path_prefix [PATH_MAX+2];
343
344
345 #define LABEL_MAX 32
346
347 #define N_MT_UNITS 1
348
349 UNIT mt_unit [N_MT_UNITS_MAX] = {
350
351
352
353
354
355
356 #if defined(NO_C_ELLIPSIS)
357 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
358 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
359 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
360 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
361 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
362 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
363 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
364 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
365 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
366 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
367 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
368 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
369 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
370 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
371 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
372 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
373 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
374 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
375 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
376 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
377 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
378 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
379 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
380 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
381 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
382 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
383 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
384 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
385 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
386 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
387 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
388 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
389 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
390 { UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
391 #else
392 [0 ... N_MT_UNITS_MAX-1] = {
393 UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
394 }
395 #endif
396 };
397
398 #define UNIT_WATCH (1 << MTUF_V_UF)
399
400 static t_stat mt_rewind (UNIT * uptr, UNUSED int32 value,
401 UNUSED const char * cptr, UNUSED void * desc)
402 {
403 return sim_tape_rewind (uptr);
404 }
405
406 static t_stat mt_show_nunits (UNUSED FILE * st, UNUSED UNIT * uptr,
407 UNUSED int val, UNUSED const void * desc)
408 {
409 sim_printf("Number of TAPE units in system is %d\n", tape_dev . numunits);
410 return SCPE_OK;
411 }
412
413 static t_stat mt_set_nunits (UNUSED UNIT * uptr, UNUSED int32 value,
414 const char * cptr, UNUSED void * desc)
415 {
416 if (! cptr)
417 return SCPE_ARG;
418 int n = atoi (cptr);
419 if (n < 1 || n > N_MT_UNITS_MAX)
420 return SCPE_ARG;
421 tape_dev . numunits = (uint32) n;
422 return SCPE_OK;
423 }
424
425 static t_stat mt_show_device_name (UNUSED FILE * st, UNIT * uptr,
426 UNUSED int val, UNUSED const void * desc)
427 {
428 int n = (int) MT_UNIT_NUM (uptr);
429 if (n < 0 || n >= N_MT_UNITS_MAX)
430 return SCPE_ARG;
431 if (tape_states[n].device_name[1] == 0)
432 sim_printf("name : default");
433 else
434 sim_printf("name : %s", tape_states[n].device_name);
435 return SCPE_OK;
436 }
437
438 static t_stat mt_set_device_name (UNUSED UNIT * uptr, UNUSED int32 value,
439 UNUSED const char * cptr, UNUSED void * desc)
440 {
441 int n = (int) MT_UNIT_NUM (uptr);
442 if (n < 0 || n >= N_MT_UNITS_MAX)
443 return SCPE_ARG;
444 if (cptr)
445 {
446 strncpy (tape_states [n] . device_name, cptr, MAX_DEV_NAME_LEN - 1);
447 tape_states [n] . device_name [MAX_DEV_NAME_LEN - 1] = 0;
448 }
449 else
450 tape_states [n] . device_name [0] = 0;
451 return SCPE_OK;
452 }
453
454 static t_stat mt_show_tape_path (UNUSED FILE * st, UNUSED UNIT * uptr,
455 UNUSED int val, UNUSED const void * desc)
456 {
457 sim_printf("TAPE DEFAULT_PATH: %s\n", tape_path_prefix);
458 return SCPE_OK;
459 }
460
461 typedef struct path_node PATH_ENTRY;
462
463 struct path_node
464 {
465 size_t prefix_len;
466 char label_prefix[LABEL_MAX + 1];
467 char dir[PATH_MAX + 1];
468 PATH_ENTRY *next_entry;
469 };
470
471 static PATH_ENTRY *search_list_head = NULL;
472 static PATH_ENTRY *search_list_tail = NULL;
473
474 static t_stat mt_set_tape_path (UNUSED UNIT * uptr, UNUSED int32 value,
475 const char * cptr, UNUSED void * desc)
476 {
477 if (! cptr)
478 return SCPE_ARG;
479
480 size_t len = strlen(cptr);
481
482
483
484 if (len >= (sizeof(tape_path_prefix) - (LABEL_MAX + 2)))
485 return SCPE_ARG;
486
487
488 PATH_ENTRY *current_entry = search_list_head;
489 while (current_entry != NULL)
490 {
491 PATH_ENTRY *old_entry = current_entry;
492 current_entry = current_entry->next_entry;
493 FREE(old_entry);
494 }
495
496 search_list_head = NULL;
497 search_list_tail = NULL;
498
499
500 DIR * dp;
501 dp = opendir (cptr);
502 if (! dp)
503 {
504 sim_warn ("\rInvalid '%s' ", cptr);
505 perror ("opendir");
506 sim_warn ("\r\n");
507 return SCPE_ARG;
508 }
509
510 closedir(dp);
511
512
513 strncpy (tape_path_prefix, cptr, (sizeof(tape_path_prefix)-1));
514 if (len > 0)
515 {
516 if (tape_path_prefix[len - 1] != '/')
517 {
518 tape_path_prefix[len++] = '/';
519 tape_path_prefix[len] = 0;
520 }
521 }
522
523 return SCPE_OK;
524 }
525
526 static t_stat mt_add_tape_search_path(UNUSED UNIT * uptr, UNUSED int32 value,
527 const char * cptr, UNUSED void * desc)
528 {
529 if (! cptr)
530 return SCPE_ARG;
531
532 if (!tape_path_prefix[0])
533 {
534 sim_print("ERROR: DEFAULT_PATH must be set before ADD_PATH is used.\n");
535 return SCPE_ARG;
536 }
537
538 size_t len = strlen(cptr);
539
540 char buffer[len + 2];
541 char prefix[len + 2];
542 char dir[len + 2];
543
544 strcpy(buffer, cptr);
545
546
547 char *token = strtok(buffer, "=");
548 if (token == NULL)
549 {
550 return SCPE_ARG;
551 }
552
553 strcpy(prefix, token);
554
555 token = strtok(NULL, "=");
556 if (token == NULL)
557 {
558 sim_print("ERROR: ADD_PATH parameter must be specified as [prefix]=[dir]\n");
559 sim_print(" i.e. SET TAPE ADD_PATH=BK=./tapes/backups\n");
560 return SCPE_ARG;
561 }
562
563 strcpy(dir, token);
564
565 if (strtok(NULL, "=") != NULL)
566 {
567 return SCPE_ARG;
568 }
569
570 size_t prefix_len = strlen(prefix);
571 if ((prefix_len > LABEL_MAX) || (prefix_len < 1))
572 {
573 return SCPE_ARG;
574 }
575
576 size_t dir_len = strlen(dir);
577
578
579 if (dir_len > (PATH_MAX - 1))
580 {
581 return SCPE_ARG;
582 }
583
584
585 DIR * dp;
586 dp = opendir (dir);
587 if (! dp)
588 {
589 sim_warn ("\rInvalid '%s' ", dir);
590 perror ("opendir");
591 sim_warn ("\r\n");
592 return SCPE_ARG;
593 }
594
595 closedir(dp);
596
597 PATH_ENTRY *new_entry = malloc(sizeof(PATH_ENTRY));
598 if (!new_entry)
599 {
600 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
601 __func__, __FILE__, __LINE__);
602 #if defined(USE_BACKTRACE)
603 # if defined(SIGUSR2)
604 (void)raise(SIGUSR2);
605
606 # endif
607 #endif
608 abort();
609 }
610 new_entry->prefix_len = prefix_len;
611 strcpy(new_entry->label_prefix, prefix);
612 strcpy(new_entry->dir, dir);
613
614 if (new_entry->dir[dir_len - 1] != '/')
615 {
616 new_entry->dir[dir_len++] = '/';
617 new_entry->dir[dir_len] = 0;
618 }
619
620 new_entry->next_entry = NULL;
621 if (search_list_tail == NULL)
622 {
623 search_list_head = new_entry;
624 search_list_tail = new_entry;
625 }
626 else
627 {
628 search_list_tail->next_entry = new_entry;
629 search_list_tail = new_entry;
630 }
631
632 return SCPE_OK;
633 }
634
635 static t_stat mt_show_tape_search_paths(UNUSED FILE * st, UNUSED UNIT * uptr,
636 UNUSED int val, UNUSED const void * desc)
637 {
638 sim_print("Tape directory search paths:\n");
639 sim_printf("%-32s %s\n", "Prefix", "Directory");
640 sim_printf("%-32s %s\n", "------", "---------");
641 PATH_ENTRY *current_entry = search_list_head;
642 while (current_entry != NULL)
643 {
644 sim_printf("%-32s %s\n", current_entry->label_prefix, current_entry->dir);
645 current_entry = current_entry->next_entry;
646 }
647
648 sim_printf("%-32s %s\n", "[default]", tape_path_prefix);
649
650 return SCPE_OK;
651 }
652
653 static t_stat mt_set_capac (UNUSED UNIT * uptr, UNUSED int32 value,
654 const char * cptr, UNUSED void * desc)
655 {
656 if (! cptr)
657 return SCPE_ARG;
658 t_stat rc;
659 int i;
660
661
662 for (i = 1; i < N_MT_UNITS_MAX; i ++)
663 {
664 rc = sim_tape_set_capac (mt_unit + i, value, cptr, desc);
665 if (rc != SCPE_OK)
666 return rc;
667 }
668 return SCPE_OK;
669 }
670
671 t_stat signal_tape (uint tap_unit_idx, word8 status0, word8 status1) {
672
673
674
675
676
677
678
679
680
681
682
683
684
685 if (! sim_is_running)
686 return SCPE_OK;
687
688 uint ctlr_unit_idx = cables->tape_to_mtp[tap_unit_idx].ctlr_unit_idx;
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713 for (uint ctlr_port_num = 0; ctlr_port_num < MAX_CTLR_PORTS; ctlr_port_num ++) {
714 if (cables->mtp_to_iom[ctlr_unit_idx][ctlr_port_num].in_use) {
715 uint iom_unit_idx = cables->mtp_to_iom[ctlr_unit_idx][ctlr_port_num].iom_unit_idx;
716 uint chan_num = cables->mtp_to_iom[ctlr_unit_idx][ctlr_port_num].chan_num;
717 uint dev_code = cables->tape_to_mtp[tap_unit_idx].dev_code;
718 send_special_interrupt (iom_unit_idx, chan_num, dev_code, 0, 020 );
719 return SCPE_OK;
720 }
721 }
722 sim_warn ("loadTape can't find controller; dropping interrupt\n");
723 return SCPE_ARG;
724
725 }
726
727 static t_stat tape_set_ready (UNIT * uptr, UNUSED int32 value,
728 UNUSED const char * cptr,
729 UNUSED void * desc)
730 {
731 #if defined(TESTING)
732 cpu_state_t * cpup = _cpup;
733 #endif
734 uint32_t tape_unit_idx = MT_UNIT_NUM (uptr);
735 if (tape_unit_idx >= N_MT_UNITS_MAX)
736 {
737 sim_debug (DBG_ERR, & tape_dev,
738 "Tape set ready: Invalid unit number %ld\n", (long) tape_unit_idx);
739 sim_printf ("error: Invalid unit number %ld\n", (long) tape_unit_idx);
740 return SCPE_ARG;
741 }
742 return signal_tape ((unsigned int) tape_unit_idx, 0, 020 );
743 }
744
745 static MTAB mt_mod [] =
746 {
747 #if !defined(SPEED)
748 { UNIT_WATCH, UNIT_WATCH, "WATCH", "WATCH", NULL, NULL, NULL, NULL },
749 { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", NULL, NULL, NULL, NULL },
750 #endif
751 {
752 MTAB_XTD | MTAB_VUN | \
753 MTAB_NC,
754 0,
755 NULL,
756 "REWIND",
757 mt_rewind,
758 NULL,
759 NULL,
760 NULL
761 },
762 {
763 MTAB_XTD | MTAB_VDV | \
764 MTAB_NMO | MTAB_VALR,
765 0,
766 "NUNITS",
767 "NUNITS",
768 mt_set_nunits,
769 mt_show_nunits,
770 "Number of TAPE units in the system",
771 NULL
772 },
773 {
774 MTAB_XTD | MTAB_VUN | \
775 MTAB_VALR | MTAB_NC,
776 0,
777 "NAME",
778 "NAME",
779 mt_set_device_name,
780 mt_show_device_name,
781 "Set the device name",
782 NULL
783 },
784 {
785 MTAB_XTD | MTAB_VDV | MTAB_NMO | \
786 MTAB_VALR | MTAB_NC,
787 0,
788 "DEFAULT_PATH",
789 "DEFAULT_PATH",
790 mt_set_tape_path,
791 mt_show_tape_path,
792 "Set the default path to the directory containing tape images (also clear search paths)",
793 NULL
794 },
795 {
796 MTAB_XTD | MTAB_VDV | MTAB_NMO | \
797 MTAB_VALR | MTAB_NC,
798 0,
799 "ADD_PATH",
800 "ADD_PATH",
801 mt_add_tape_search_path,
802 mt_show_tape_search_paths,
803 "Add a search path for tape directories",
804 NULL
805 },
806 {
807 MTAB_XTD | MTAB_VUN,
808 0,
809 "CAPACITY",
810 "CAPACITY",
811 sim_tape_set_capac,
812 sim_tape_show_capac,
813 "Set the device capacity",
814 NULL
815 },
816 {
817 MTAB_XTD | MTAB_VDV | \
818 MTAB_NMO | MTAB_VALR,
819 0,
820 "CAPACITY_ALL",
821 "CAPACITY_ALL",
822 mt_set_capac,
823 NULL,
824 "Set the tape capacity of all drives",
825 NULL
826 },
827 {
828 MTAB_XTD | MTAB_VUN | \
829 MTAB_NMO | MTAB_VALR,
830 0,
831 "READY",
832 "READY",
833 tape_set_ready,
834 NULL,
835 NULL,
836 NULL
837 },
838 { 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }
839 };
840
841 static t_stat mt_reset (DEVICE * dptr)
842 {
843 for (int i = 0; i < (int) dptr -> numunits; i ++)
844 {
845 sim_tape_reset (& mt_unit [i]);
846
847 }
848 return SCPE_OK;
849 }
850
851 DEVICE tape_dev =
852 {
853 "TAPE",
854 mt_unit,
855 NULL,
856 mt_mod,
857 N_MT_UNITS,
858 10,
859 31,
860 1,
861 8,
862 9,
863 NULL,
864 NULL,
865 mt_reset,
866 NULL,
867 &sim_tape_attach,
868 &sim_tape_detach,
869 NULL,
870 DEV_DEBUG,
871 0,
872 mt_dt,
873 NULL,
874 NULL,
875 NULL,
876 NULL,
877 NULL,
878 NULL,
879 NULL
880 };
881
882 static void deterimeFullTapeFileName(char * tapeFileName, char * buffer, int bufferLength)
883 {
884
885 if (!tape_path_prefix[0])
886 {
887 strncpy(buffer, tapeFileName, (unsigned long)bufferLength);
888 buffer[bufferLength - 1] = 0;
889 return;
890 }
891
892
893 PATH_ENTRY *current_entry = search_list_head;
894 while (current_entry != NULL)
895 {
896 if (strncmp(current_entry->label_prefix, tapeFileName, current_entry->prefix_len) == 0)
897 {
898 break;
899 }
900
901 current_entry = current_entry->next_entry;
902 }
903
904 char *selected_path = tape_path_prefix;
905 if (current_entry != NULL)
906 {
907 selected_path = current_entry->dir;
908 }
909
910
911 if ((size_t) bufferLength < (strlen(selected_path) + strlen(tapeFileName) + 1))
912 {
913
914
915 strncpy(buffer, tapeFileName, (unsigned long)bufferLength);
916 buffer[bufferLength - 1] = 0;
917 return;
918 }
919
920
921 int buffWrote;
922 buffWrote = snprintf(buffer,
923 ((int)((strlen(selected_path)+strlen(tapeFileName))+1)),
924 "%s%s", selected_path, tapeFileName);
925 if (buffWrote < 0)
926 sim_warn("%s snprintf problem, returned %d\n", __func__, buffWrote);
927 }
928
929 t_stat loadTape (uint driveNumber, char * tapeFilename, bool ro)
930 {
931 char full_tape_file_name[PATH_MAX + 1];
932
933 if (ro)
934 mt_unit [driveNumber] . flags |= MTUF_WRP;
935 else
936 mt_unit [driveNumber] . flags &= ~ MTUF_WRP;
937
938 deterimeFullTapeFileName(tapeFilename, full_tape_file_name, (sizeof(full_tape_file_name)-1));
939
940 sim_printf("loadTape Attaching drive %u to file %s\n", driveNumber, full_tape_file_name);
941 t_stat stat = sim_tape_attach (& mt_unit [driveNumber], full_tape_file_name);
942 if (stat != SCPE_OK)
943 {
944 sim_printf ("%s sim_tape_attach returned %d\n", __func__, stat);
945 return stat;
946 }
947 return signal_tape (driveNumber, 0, 020 );
948 }
949
950 t_stat unloadTape (uint driveNumber)
951 {
952 if (mt_unit [driveNumber] . flags & UNIT_ATT)
953 {
954 t_stat stat = sim_tape_detach (& mt_unit [driveNumber]);
955 if (stat != SCPE_OK)
956 {
957 sim_warn ("%s sim_tape_detach returned %d\n", __func__, stat);
958 return stat;
959 }
960 }
961 return signal_tape (driveNumber, 0, 040 );
962 }
963
964 void mt_init(void)
965 {
966 (void)memset(tape_states, 0, sizeof(tape_states));
967 for (int i = 0; i < N_MT_UNITS_MAX; i ++)
968 {
969 mt_unit [i] . capac = 40000000;
970 }
971 }
972
973 void mt_exit (void) {
974
975 PATH_ENTRY * current_entry = search_list_head;
976 while (current_entry != NULL) {
977 PATH_ENTRY * old_entry = current_entry;
978 current_entry = current_entry->next_entry;
979 FREE (old_entry);
980 }
981 }
982
983 static iom_cmd_rc_t mtReadRecord (uint devUnitIdx, uint iomUnitIdx, uint chan)
984 {
985
986
987 #if defined(TESTING)
988 cpu_state_t * cpup = _cpup;
989 #endif
990 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
991 UNIT * unitp = & mt_unit[devUnitIdx];
992 struct tape_state * tape_statep = & tape_states[devUnitIdx];
993
994
995 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read %s record\n", __func__,
996 tape_statep->is9 ? "9" : "binary");
997
998 tape_statep->tbc = 0;
999 if (! (unitp -> flags & UNIT_ATT))
1000 {
1001 p->stati = 04104;
1002 return IOM_CMD_ERROR;
1003 }
1004 t_stat rc = sim_tape_rdrecf (unitp, & tape_statep -> buf [0], & tape_statep -> tbc,
1005 BUFSZ);
1006 sim_debug (DBG_DEBUG, & tape_dev, "%s: sim_tape_rdrecf returned %d, with tbc %d\n",
1007 __func__, rc, tape_statep -> tbc);
1008 if (rc == MTSE_TMK)
1009 {
1010 tape_statep -> rec_num ++;
1011 sim_debug (DBG_NOTIFY, & tape_dev,
1012 "%s: EOF: %s\n", __func__, simh_tape_msg (rc));
1013 p -> stati = 04423;
1014 if (tape_statep -> tbc != 0)
1015 {
1016 sim_warn ("%s: Read %d bytes with EOF.\n",
1017 __func__, tape_statep -> tbc);
1018 }
1019 tape_statep -> tbc = 0;
1020
1021 return IOM_CMD_ERROR;
1022 }
1023 if (rc == MTSE_EOM)
1024 {
1025 sim_debug (DBG_NOTIFY, & tape_dev,
1026 "%s: EOM: %s\n", __func__, simh_tape_msg (rc));
1027
1028 if (sim_tape_bot (unitp))
1029 p -> stati = 04302;
1030 else
1031 p -> stati = 04340;
1032 if (tape_statep -> tbc != 0)
1033 {
1034 sim_warn ("%s: Read %d bytes with EOM.\n",
1035 __func__, tape_statep -> tbc);
1036
1037 }
1038 tape_statep -> tbc = 0;
1039
1040 return IOM_CMD_PROCEED;
1041 }
1042 if (rc != 0)
1043 {
1044 sim_debug (DBG_ERR, & tape_dev,
1045 "%s: Cannot read tape: %d - %s\n",
1046 __func__, rc, simh_tape_msg (rc));
1047 sim_debug (DBG_ERR, & tape_dev,
1048 "%s: Returning arbitrary error code\n",
1049 __func__);
1050 p -> stati = 05001;
1051 p -> chanStatus = chanStatParityErrPeriph;
1052 return IOM_CMD_ERROR;
1053 }
1054 p -> stati = 04000;
1055 if (sim_tape_wrp (unitp))
1056 p -> stati |= 1;
1057 tape_statep -> rec_num ++;
1058
1059 tape_statep -> words_processed = 0;
1060 if (unitp->flags & UNIT_WATCH)
1061 sim_printf ("Tape %ld reads record %d\n",
1062 (long) MT_UNIT_NUM (unitp), tape_statep -> rec_num);
1063
1064 uint tally = p -> DDCW_TALLY;
1065 if (tally == 0)
1066 {
1067 sim_debug (DBG_DEBUG, & tape_dev,
1068 "%s: Tally of zero interpreted as 010000(4096)\n",
1069 __func__);
1070 tally = 4096;
1071 }
1072
1073 sim_debug (DBG_DEBUG, & tape_dev,
1074 "%s: Tally %d (%o)\n", __func__, tally, tally);
1075
1076 word36 buffer [tally];
1077 uint i;
1078 int rc2;
1079 for (i = 0; i < tally; i ++)
1080 {
1081 if (tape_statep -> is9)
1082 rc2 = extractASCII36FromBuffer (tape_statep -> buf,
1083 tape_statep -> tbc, & tape_statep -> words_processed, buffer + i);
1084 else
1085 rc2 = extractWord36FromBuffer (tape_statep -> buf,
1086 tape_statep -> tbc, & tape_statep -> words_processed, buffer + i);
1087 if (rc2)
1088 {
1089 break;
1090 }
1091 }
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107 iom_indirect_data_service (iomUnitIdx, chan, buffer,
1108 & tape_statep -> words_processed, true);
1109 if (p -> tallyResidue)
1110 {
1111 sim_debug (DBG_WARN, & tape_dev,
1112 "%s: Read buffer exhausted on channel %d\n",
1113 __func__, chan);
1114
1115 }
1116
1117 if (tape_statep -> is9)
1118 p -> charPos = tape_statep -> tbc % 4;
1119 else
1120 p -> charPos = (tape_statep -> tbc * 8) / 9 % 4;
1121 return IOM_CMD_PROCEED;
1122 }
1123
1124 static void mtReadCtrlMainMem (uint devUnitIdx, uint iomUnitIdx, uint chan)
1125 {
1126 struct tape_state * tape_statep = & tape_states[devUnitIdx];
1127 word36 control[1];
1128 uint count;
1129 iom_indirect_data_service (iomUnitIdx, chan, control, &count, false);
1130 if (count != 1)
1131 sim_warn ("%s: count %d not 1\n", __func__, count);
1132 tape_statep -> cntlrAddress = getbits36_16 (control[0], 0);
1133 tape_statep -> cntlrTally = getbits36_16 (control[0], 16);
1134 }
1135
1136 static void mtInitRdMem (uint devUnitIdx, uint iomUnitIdx, uint chan)
1137 {
1138 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1139
1140 uint tally = p -> DDCW_TALLY;
1141 if (tally != 04000)
1142 {
1143 sim_warn ("%s: tape controller read memory expected tally of 04000\n", __func__);
1144 p -> stati = 04501;
1145 p -> chanStatus = chanStatIncorrectDCW;
1146 return;
1147 }
1148 uint16 mem [04000 * 2];
1149 (void)memset (mem, 0, sizeof (mem));
1150
1151 const uint charTableOS = 0xE0;
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176 mem [charTableOS + 0] = 4096;
1177 mem [charTableOS + 1] = 0;
1178
1179
1180 mem [charTableOS + 2] = 04000 + 0123;
1181 mem [charTableOS + 3] = 0;
1182 mem [charTableOS + 4] = 0;
1183 mem [charTableOS + 5] = 04000 + 0234;
1184 mem [charTableOS + 6] = 04000 + 0345;
1185 mem [charTableOS + 7] = 04000 + 0456;
1186 mem [charTableOS + 8] = 012345;
1187
1188
1189 mem [charTableOS + 9] = 0x0013;
1190
1191 mem [charTableOS + 10] = 0x1025;
1192
1193 word36 buf [tally];
1194
1195 (void)memset (buf, 0, sizeof (word36) * tally);
1196 for (uint i = 0; i < tally; i ++)
1197 {
1198 putbits36_18 (buf + i, 0, mem [i * 2]);
1199 putbits36_18 (buf + i, 18, mem [i * 2 + 1]);
1200 }
1201 iom_indirect_data_service (iomUnitIdx, chan, buf, & tally, true);
1202 p -> stati = 04000;
1203 }
1204
1205 static void mtWRCtrlRegs (uint devUnitIdx, uint iomUnitIdx, uint chan)
1206 {
1207 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1208
1209 p->initiate = false;
1210 return;
1211 }
1212
1213 static void mtInitWrMem (uint devUnitIdx, uint iomUnitIdx, uint chan)
1214 {
1215 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1216
1217 p->initiate = false;
1218 return;
1219 }
1220
1221 static void mtMTPWr (uint devUnitIdx, uint iomUnitIdx, uint chan)
1222 {
1223 iom_chan_data_t * p = & iom_chan_data[iomUnitIdx][chan];
1224 struct tape_state * tape_statep = & tape_states [devUnitIdx];
1225
1226 word36 control[1];
1227 uint count;
1228 iom_indirect_data_service (iomUnitIdx, chan, control, &count, false);
1229 if (count != 1)
1230 sim_warn ("%s: count %d not 1\n", __func__, count);
1231 tape_statep -> cntlrAddress = getbits36_16 (control[0], 0);
1232 tape_statep -> cntlrTally = getbits36_16 (control[0], 16);
1233 p -> stati = 04000;
1234 }
1235
1236 static int mtWriteRecord (uint devUnitIdx, uint iomUnitIdx, uint chan)
1237 {
1238
1239
1240 #if defined(TESTING)
1241 cpu_state_t * cpup = _cpup;
1242 #endif
1243 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
1244 UNIT * unitp = & mt_unit [devUnitIdx];
1245 struct tape_state * tape_statep = & tape_states [devUnitIdx];
1246
1247 tape_statep -> is9 = p -> IDCW_DEV_CMD == 013;
1248 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write %s record\n", __func__,
1249 tape_statep -> is9 ? "9" : "binary");
1250
1251 p -> isRead = false;
1252
1253 uint tally = p -> DDCW_TALLY;
1254 if (tally == 0)
1255 {
1256 sim_debug (DBG_DEBUG, & tape_dev,
1257 "%s: Tally of zero interpreted as 010000(4096)\n",
1258 __func__);
1259 tally = 4096;
1260 }
1261
1262 sim_debug (DBG_DEBUG, & tape_dev,
1263 "%s: Tally %d (%o)\n", __func__, tally, tally);
1264
1265
1266
1267 tape_statep -> words_processed = 0;
1268 word36 buffer [tally];
1269
1270 iom_indirect_data_service (iomUnitIdx, chan, buffer,
1271 & tape_statep -> words_processed, false);
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289 if (tape_statep -> is9)
1290 tape_statep -> tbc = tape_statep -> words_processed * 4;
1291 else
1292 tape_statep -> tbc = (tape_statep -> words_processed * 9 + 1) / 2;
1293
1294
1295
1296 tape_statep -> words_processed = 0;
1297 uint i;
1298 for (i = 0; i < tally; i ++)
1299 {
1300 int rc2;
1301 if (tape_statep -> is9)
1302 {
1303 rc2 = insertASCII36toBuffer (tape_statep -> buf,
1304 tape_statep -> tbc,
1305 & tape_statep -> words_processed,
1306 buffer [i]);
1307 }
1308 else
1309 {
1310 rc2 = insertWord36toBuffer (tape_statep -> buf,
1311 tape_statep -> tbc,
1312 & tape_statep -> words_processed,
1313 buffer [i]);
1314 }
1315 if (rc2)
1316 {
1317 p -> stati = 04000;
1318 if (sim_tape_wrp (unitp))
1319 p -> stati |= 1;
1320 sim_debug (DBG_WARN, & tape_dev,
1321 "%s: Write buffer exhausted on channel %d\n",
1322 __func__, chan);
1323 break;
1324 }
1325 }
1326 p -> tallyResidue = (word12) (tally - i);
1327
1328
1329 if (tape_statep -> is9)
1330 p -> charPos = tape_statep -> tbc % 4;
1331 else
1332 p -> charPos = (tape_statep -> tbc * 8) / 9 % 4;
1333
1334
1335
1336 if (! (unitp -> flags & UNIT_ATT))
1337 return MTSE_UNATT;
1338
1339 int ret = sim_tape_wrrecf (unitp, tape_statep -> buf, tape_statep -> tbc);
1340 sim_debug (DBG_DEBUG, & tape_dev, "%s: sim_tape_wrrecf returned %d, with tbc %d\n",
1341 __func__, ret, tape_statep -> tbc);
1342
1343 if (unitp->io_flush)
1344 unitp->io_flush (unitp);
1345
1346
1347 if (ret != 0)
1348 {
1349
1350 if (ret == MTSE_EOM)
1351 {
1352 sim_debug (DBG_NOTIFY, & tape_dev,
1353 "%s: EOM: %s\n", __func__, simh_tape_msg (ret));
1354 p -> stati = 04340;
1355 if (tape_statep -> tbc != 0)
1356 {
1357 sim_warn ("%s: Wrote %d bytes with EOM.\n",
1358 __func__, tape_statep -> tbc);
1359 }
1360 return 0;
1361 }
1362 sim_warn ("%s: Cannot write tape: %d - %s\n",
1363 __func__, ret, simh_tape_msg(ret));
1364 sim_warn ("%s: Returning arbitrary error code\n",
1365 __func__);
1366 p -> stati = 05001;
1367 p -> chanStatus = chanStatParityErrPeriph;
1368 return IOM_CMD_ERROR;
1369 }
1370 tape_statep -> rec_num ++;
1371 if (unitp->flags & UNIT_WATCH)
1372 sim_printf ("Tape %ld writes record %d\n",
1373 (long) MT_UNIT_NUM (unitp), tape_statep -> rec_num);
1374
1375 sim_tape_wreom (unitp);
1376 if (unitp->io_flush)
1377 unitp->io_flush (unitp);
1378
1379 p -> stati = 04000;
1380 if (sim_tape_wrp (unitp))
1381 p -> stati |= 1;
1382 if (sim_tape_eot (unitp))
1383 p -> stati |= 04340;
1384
1385 sim_debug (DBG_INFO, & tape_dev,
1386 "%s: Wrote %d bytes to simulated tape; status %04o\n",
1387 __func__, (int) tape_statep -> tbc, p -> stati);
1388
1389 return 0;
1390 }
1391
1392
1393
1394 static int surveyDevices (uint iomUnitIdx, uint chan)
1395 {
1396 #if defined(TESTING)
1397 cpu_state_t * cpup = _cpup;
1398 #endif
1399 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414 sim_debug (DBG_DEBUG, & tape_dev,
1415 "%s: Survey devices\n", __func__);
1416 p -> stati = 04000;
1417
1418 uint bufsz = 8;
1419 word36 buffer [bufsz];
1420 uint cnt = 0;
1421 for (uint i = 0; i < bufsz; i ++)
1422 buffer [i] = 0;
1423
1424 uint ctlr_idx = get_ctlr_idx (iomUnitIdx, chan);
1425
1426 for (uint dev_code = 0; dev_code < N_DEV_CODES; dev_code ++)
1427 {
1428 if (cnt / 2 >= bufsz)
1429 break;
1430
1431 struct ctlr_to_dev_s * p = & cables->mtp_to_tape[ctlr_idx][dev_code];
1432 if (! p -> in_use)
1433 continue;
1434 uint unit_idx = p->unit_idx;
1435
1436 word18 handler = 0;
1437 handler |= 0100000;
1438 if (mt_unit [unit_idx].filename)
1439 {
1440 handler |= 0040000;
1441 }
1442 handler |= ((word18) dev_code & 037) << 9;
1443 handler |= 0000040;
1444 handler |= 0000020;
1445 handler |= 0000007;
1446 sim_debug (DBG_DEBUG, & tape_dev,
1447 "%s: unit %d handler %06o\n", __func__, unit_idx, handler);
1448 if (cnt % 2 == 0)
1449 {
1450 buffer [cnt / 2] = ((word36) handler) << 18;
1451 }
1452 else
1453 {
1454 buffer [cnt / 2] |= handler;
1455 }
1456 cnt ++;
1457 }
1458 iom_indirect_data_service (iomUnitIdx, chan, buffer, & bufsz, true);
1459 p -> stati = 04000;
1460 return 0;
1461 }
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478 iom_cmd_rc_t mt_iom_cmd (uint iomUnitIdx, uint chan) {
1479 iom_chan_data_t * p = & iom_chan_data [iomUnitIdx] [chan];
1480 #if defined(TESTING)
1481 cpu_state_t * cpup = _cpup;
1482 if_sim_debug (DBG_TRACE, & tape_dev) dumpDCW (p->DCW, 0);
1483 #endif
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496 uint ctlr_unit_idx = get_ctlr_idx (iomUnitIdx, chan);
1497 uint dev_code = p->IDCW_DEV_CODE;
1498 #if defined(TESTING)
1499 if_sim_debug (DBG_TRACE, & tape_dev) dumpDCW (p->DCW, 0);
1500 #endif
1501 if (p->IDCW_DEV_CODE == 0)
1502 dev_code = mtp_state[ctlr_unit_idx].boot_drive;
1503
1504 sim_debug (DBG_DEBUG, & tape_dev, "%s: Tape %c%02o_%02o\n", __func__, iomChar (iomUnitIdx), chan, dev_code);
1505
1506 uint devUnitIdx = cables->mtp_to_tape[ctlr_unit_idx][dev_code].unit_idx;
1507 UNIT * unitp = & mt_unit [devUnitIdx];
1508 struct tape_state * tape_statep = & tape_states [devUnitIdx];
1509
1510 iom_cmd_rc_t rc = IOM_CMD_PROCEED;
1511
1512
1513 if (IS_IDCW (p)) {
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531 tape_statep->io_mode = tape_no_mode;
1532 sim_debug (DBG_DEBUG, & tape_dev, "%s: IDCW_DEV_CMD %oo %d.\n", __func__, p->IDCW_DEV_CMD, p->IDCW_DEV_CMD);
1533 switch (p->IDCW_DEV_CMD) {
1534 case 000: {
1535 if_sim_debug (DBG_TRACE, & tape_dev) {
1536 sim_printf ("// Tape Request Status\r\n");
1537 }
1538
1539 if (p->IDCW_CHAN_CMD == 040) {
1540 sim_debug (DBG_DEBUG, & tape_dev, "%s: controller suspend\n", __func__);
1541 send_special_interrupt (iomUnitIdx, chan, p->IDCW_DEV_CODE, 01, 0 );
1542 p->stati = 04000;
1543 } else {
1544 p->stati = 04000;
1545 }
1546 sim_debug (DBG_DEBUG, & tape_dev, "%s: Request status: %04o control %0o chan_cmd %02o\n", __func__,
1547 p->stati, p->IDCW_CHAN_CTRL, p->IDCW_CHAN_CMD);
1548 }
1549 break;
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604 case 002:
1605 if_sim_debug (DBG_TRACE, & tape_dev) {
1606 sim_printf ("// Tape Read Controller Main Memory\r\n");
1607 }
1608 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read controller main memory\n", __func__);
1609
1610 tape_statep->io_mode = tape_rd_ctlr;
1611 p->stati = 04000;
1612 break;
1613
1614 case 003:
1615 if_sim_debug (DBG_TRACE, & tape_dev) {
1616 sim_printf ("// Tape Read 9 Record\r\n");
1617 }
1618 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read 9 record\n", __func__);
1619 tape_statep->io_mode = tape_rd_9;
1620 tape_statep->is9 = true;
1621 if (! (unitp->flags & UNIT_ATT)) {
1622 p->stati = 04104;
1623 return IOM_CMD_ERROR;
1624 }
1625 p->stati = 04000;
1626 break;
1627
1628
1629
1630 case 005:
1631 if_sim_debug (DBG_TRACE, & tape_dev) {
1632 sim_printf ("// Tape Read Binary Record\r\n");
1633 }
1634 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read binary record\n", __func__);
1635 tape_statep->io_mode = tape_rd_bin;
1636 tape_statep->is9 = false;
1637 if (! (unitp->flags & UNIT_ATT)) {
1638 p->stati = 04104;
1639 return IOM_CMD_ERROR;
1640 }
1641 p->stati = 04000;
1642 break;
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664 case 006:
1665 if_sim_debug (DBG_TRACE, & tape_dev) {
1666 sim_printf ("// Tape Initiate Read Data Transfer\r\n");
1667 }
1668 sim_debug (DBG_DEBUG, & tape_dev, "%s: initiate read data transfer\n", __func__);
1669 tape_statep->io_mode = tape_initiate_rd_mem;
1670 p->stati = 04000;
1671 break;
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681 case 013:
1682 if_sim_debug (DBG_TRACE, & tape_dev) {
1683 sim_printf ("// Tape Write 9 Record\r\n");
1684 }
1685 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write 9 record\n", __func__);
1686 tape_statep->io_mode = tape_wr_9;
1687 if (! (unitp->flags & UNIT_ATT)) {
1688 p->stati = 04104;
1689 return IOM_CMD_ERROR;
1690 }
1691 p->stati = 04000;
1692 break;
1693
1694
1695
1696 case 015:
1697 if_sim_debug (DBG_TRACE, & tape_dev) {
1698 sim_printf ("// Tape Write Binary Record\r\n");
1699 }
1700 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write binary record\n", __func__);
1701 tape_statep->io_mode = tape_wr_bin;
1702 if (! (unitp->flags & UNIT_ATT)) {
1703 p->stati = 04104;
1704 return IOM_CMD_ERROR;
1705 }
1706 p->stati = 04000;
1707 break;
1708
1709 case 016:
1710 if_sim_debug (DBG_TRACE, & tape_dev) {
1711 sim_printf ("// Tape Write Control Registers\r\n");
1712 }
1713 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write Control Registers\n", __func__);
1714 tape_statep->io_mode = tape_wr_ctrl_regs;
1715 p->stati = 04000;
1716 break;
1717
1718
1719
1720 case 020: {
1721 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Release Controller\r\n"); }
1722 if (p->IDCW_CHAN_CMD == 040) {
1723 sim_debug (DBG_DEBUG, & tape_dev, "%s: Release controller\n", __func__);
1724 p->stati = 04000;
1725 sim_debug (DBG_DEBUG, & tape_dev, "%s: Release status: %04o control %0o chan_cmd %02o\n",
1726 __func__, p->stati, p->IDCW_CHAN_CTRL, p->IDCW_CHAN_CMD);
1727 send_special_interrupt (iomUnitIdx, chan, p->IDCW_DEV_CODE, 02, 0 );
1728 } else {
1729 p->stati = 04501;
1730 p->chanStatus = chanStatIncorrectDCW;
1731 sim_warn ("%s: Unknown command %02o\n", __func__, p->IDCW_DEV_CMD);
1732 }
1733 }
1734 break;
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756 case 032:
1757
1758 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Write Main Memory\r\n"); }
1759 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write controller main memory\n", __func__);
1760 tape_statep->io_mode = tape_MTP_wr;
1761 p->stati = 04000;
1762 break;
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774 case 040:
1775 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Reset Status\r\n"); }
1776 sim_debug (DBG_DEBUG, & tape_dev, "%s Reset status\n", __func__);
1777 p->stati = 04000;
1778 p->isRead = false;
1779
1780 if (dev_code == 077) {
1781 p->stati = 04502;
1782 return IOM_CMD_DISCONNECT;
1783 }
1784 if (sim_tape_wrp (unitp))
1785 p->stati |= 1;
1786 if (sim_tape_bot (unitp))
1787 p->stati |= 2;
1788
1789
1790 break;
1791
1792 case 041:
1793 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 6259 CPI\r\n"); }
1794 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 6250 cpi\n", __func__);
1795 p->stati = 04000;
1796 if (sim_tape_wrp (unitp))
1797 p->stati |= 1;
1798 if (sim_tape_bot (unitp))
1799 p->stati |= 2;
1800
1801
1802 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 800 bpi\n", __func__);
1803 break;
1804
1805 case 042:
1806 case 060:
1807 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 800 BPI\r\n"); }
1808 p->stati = 04000;
1809 if (sim_tape_wrp (unitp))
1810 p->stati |= 1;
1811 if (sim_tape_bot (unitp))
1812 p->stati |= 2;
1813
1814
1815 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 800 bpi\n", __func__);
1816 break;
1817
1818 case 043:
1819 case 061:
1820 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 556 BPI\r\n"); }
1821 p->stati = 04000;
1822 if (sim_tape_wrp (unitp))
1823 p->stati |= 1;
1824 if (sim_tape_bot (unitp))
1825 p->stati |= 2;
1826
1827
1828 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 556 bpi\n", __func__);
1829 break;
1830
1831 case 044: {
1832 if_sim_debug (DBG_TRACE, & tape_dev) {
1833 sim_printf ("// Tape Forward Skip One Record\r\n");
1834 sim_printf ("// pos before %d\r\n", unitp->pos);
1835 }
1836 #if defined(TESTING)
1837 hdbgNote ("tape", "Tape Forward Skip One Record pos before %d", unitp->pos);
1838 #endif
1839 if (! (unitp->flags & UNIT_ATT)) {
1840 p->stati = 04104;
1841 return IOM_CMD_ERROR;
1842 }
1843 uint tally = p->IDCW_COUNT;
1844 if (tally == 0) {
1845 sim_debug (DBG_DEBUG, & tape_dev, "%s: Tally of zero interpreted as 64\n", __func__);
1846 tally = 64;
1847 }
1848 sim_debug (DBG_DEBUG, & tape_dev, "%s: Forward skip record %d\n", __func__, tally);
1849
1850
1851
1852
1853
1854
1855 uint32 skipped = 0;
1856 t_stat ret = MTSE_OK;
1857 while (skipped < tally) {
1858 ret = sim_tape_sprecf (unitp, & tape_statep->tbc);
1859 if (ret != MTSE_OK && ret != MTSE_TMK)
1860 break;
1861 skipped = skipped + 1;
1862 }
1863
1864 if (ret != MTSE_OK && ret != MTSE_TMK && ret != MTSE_EOM) {
1865 break;
1866 }
1867 if (skipped != tally) {
1868 sim_warn ("skipped %d != tally %d\n", skipped, tally);
1869 }
1870
1871 tape_statep->rec_num += (int) skipped;
1872 if (unitp->flags & UNIT_WATCH)
1873 sim_printf ("Tape %ld forward skips to record %d\n", (long) MT_UNIT_NUM (unitp), tape_statep->rec_num);
1874
1875 p->tallyResidue = (word12) (tally - skipped);
1876
1877 p->stati = 04000;
1878 if (sim_tape_wrp (unitp))
1879 p->stati |= 1;
1880 if (sim_tape_bot (unitp))
1881 p->stati |= 2;
1882
1883
1884 if_sim_debug (DBG_TRACE, & tape_dev) {
1885 sim_printf ("// pos after %d\r\n", unitp->pos);
1886 }
1887 #if defined(TESTING)
1888 hdbgNote ("tape", "Tape Forward Skip One Record pos after %d", unitp->pos);
1889 #endif
1890 }
1891 break;
1892
1893 case 045: {
1894 if_sim_debug (DBG_TRACE, & tape_dev) {
1895 sim_printf ("// Tape Forward Skip One File\r\n");
1896 sim_printf ("// pos before %d\r\n", unitp->pos);
1897 }
1898 #if defined(TESTING)
1899 hdbgNote ("tape", "Tape Forward Skip One File pos before %d", unitp->pos);
1900 #endif
1901 sim_debug (DBG_DEBUG, & tape_dev, "%s:: Forward Skip File\n", __func__);
1902 if (! (unitp->flags & UNIT_ATT)) {
1903 p->stati = 04104;
1904 return IOM_CMD_ERROR;
1905 }
1906 uint tally = 1;
1907
1908 uint32 skipped, recsskipped;
1909 t_stat ret = sim_tape_spfilebyrecf (unitp, tally, & skipped, & recsskipped, false);
1910 if_sim_debug (DBG_TRACE, & tape_dev)
1911 {
1912 sim_printf ("// sim_tape_spfilebyrecf ret %d skipped %d recsskipped %d\r\n",
1913 ret, skipped, recsskipped);
1914 }
1915 if (ret != MTSE_OK && ret != MTSE_TMK && ret != MTSE_LEOT) {
1916 sim_warn ("sim_tape_spfilebyrecf returned %d\n", ret);
1917 break;
1918 }
1919 if (skipped != tally) {
1920 sim_warn ("skipped %d != tally %d\n", skipped, tally);
1921 }
1922
1923 tape_statep->rec_num += (int) recsskipped;
1924 if (unitp->flags & UNIT_WATCH)
1925 sim_printf ("Tape %ld forward skips to record %d\n", (long) MT_UNIT_NUM (unitp), tape_statep->rec_num);
1926
1927 p->tallyResidue = (word12) (tally - skipped);
1928 sim_debug (DBG_NOTIFY, & tape_dev, "%s: Forward space %d files\n", __func__, tally);
1929
1930 p->stati = 04000;
1931 if (sim_tape_wrp (unitp))
1932 p->stati |= 1;
1933 if (sim_tape_bot (unitp))
1934 p->stati |= 2;
1935
1936
1937 }
1938 if_sim_debug (DBG_TRACE, & tape_dev) {
1939 sim_printf ("// pos after %d\r\n", unitp->pos);
1940 }
1941 #if defined(TESTING)
1942 hdbgNote ("tape", "Tape Forward Skip One File pos after %d", unitp->pos);
1943 #endif
1944 break;
1945
1946 case 046: {
1947 if_sim_debug (DBG_TRACE, & tape_dev) {
1948 sim_printf ("// Tape Backspace One Record\r\n");
1949 sim_printf ("// pos before %d\r\n", unitp->pos);
1950 }
1951 #if defined(TESTING)
1952 hdbgNote ("tape", "Tape Backspace One Record pos before %d", unitp->pos);
1953 #endif
1954 sim_debug (DBG_DEBUG, & tape_dev, "%s: Backspace Record\n", __func__);
1955 if (! (unitp->flags & UNIT_ATT)) {
1956 p->stati = 04104;
1957 return IOM_CMD_ERROR;
1958 }
1959
1960 uint tally = p->IDCW_COUNT;
1961 if (tally == 0) {
1962 sim_debug (DBG_DEBUG, & tape_dev, "%s: Tally of zero interpreted as 64\n", __func__);
1963 tally = 64;
1964 }
1965
1966 sim_debug (DBG_DEBUG, & tape_dev, "%s: Backspace record tally %d\n", __func__, tally);
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977 uint32 skipped = 0;
1978 while (skipped < tally) {
1979 t_stat ret = sim_tape_sprecr (unitp, & tape_statep->tbc);
1980 if (ret != MTSE_OK && ret != MTSE_TMK)
1981 break;
1982 skipped ++;
1983 }
1984
1985 if (skipped != tally) {
1986 sim_warn ("skipped %d != tally %d\n", skipped, tally);
1987 }
1988 tape_statep->rec_num -= (int) skipped;
1989 if (unitp->flags & UNIT_WATCH)
1990 sim_printf ("Tape %ld skip back to record %d\n", (long) MT_UNIT_NUM (unitp), tape_statep->rec_num);
1991
1992 p->tallyResidue = (word12) (tally - skipped);
1993
1994 sim_debug (DBG_NOTIFY, & tape_dev, "%s: Backspace %d records\n", __func__, skipped);
1995
1996 p->stati = 04000;
1997 if (sim_tape_wrp (unitp))
1998 p->stati |= 1;
1999 if (sim_tape_bot (unitp))
2000 p->stati |= 2;
2001
2002
2003 }
2004 if_sim_debug (DBG_TRACE, & tape_dev) {
2005 sim_printf ("// pos after %d\r\n", unitp->pos);
2006 }
2007 #if defined(TESTING)
2008 hdbgNote ("tape", "Tape Backspace One Record pos after %d", unitp->pos);
2009 #endif
2010 break;
2011
2012 case 047: {
2013 if_sim_debug (DBG_TRACE, & tape_dev) {
2014 sim_printf ("// Tape Backspace One File\r\n");
2015 sim_printf ("// pos before %d\r\n", unitp->pos);
2016 }
2017 sim_debug (DBG_DEBUG, & tape_dev, "%s: Backspace File\n", __func__);
2018 #if defined(TESTING)
2019 hdbgNote ("tape", "Tape Backspace One File pos before %d", unitp->pos);
2020 #endif
2021 if (! (unitp->flags & UNIT_ATT)) {
2022 p->stati = 04104;
2023 return IOM_CMD_ERROR;
2024 }
2025 uint tally = 1;
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046 uint32 skipped, recsskipped;
2047 t_stat ret = sim_tape_spfilebyrecr (unitp, tally, & skipped, & recsskipped);
2048 if (ret != MTSE_OK && ret != MTSE_TMK && ret != MTSE_BOT) {
2049 sim_warn ("sim_tape_spfilebyrecr returned %d\n", ret);
2050 break;
2051 }
2052 if (skipped != tally) {
2053 sim_warn ("skipped %d != tally %d\n", skipped, tally);
2054 }
2055
2056 tape_statep->rec_num -= (int) recsskipped;
2057 if (unitp->flags & UNIT_WATCH)
2058 sim_printf ("Tape %ld backward skips to record %d\n", (long) MT_UNIT_NUM (unitp), tape_statep->rec_num);
2059
2060 p->tallyResidue = (word12) (tally - skipped);
2061 sim_debug (DBG_NOTIFY, & tape_dev, "%s: Backspace %d records\n", __func__, tally);
2062
2063
2064 p->stati = 04000;
2065 if (sim_tape_wrp (unitp))
2066 p->stati |= 1;
2067 if (sim_tape_bot (unitp))
2068 p->stati |= 2;
2069
2070
2071 }
2072 if_sim_debug (DBG_TRACE, & tape_dev) {
2073 sim_printf ("// pos after %d\r\n", unitp->pos);
2074 }
2075 #if defined(TESTING)
2076 hdbgNote ("tape", "Tape Backspace One File pos after %d", unitp->pos);
2077 #endif
2078 break;
2079
2080 case 050: {
2081 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Request Device Status\r\n"); }
2082 p->stati = 04000;
2083 if (sim_tape_wrp (unitp))
2084 p->stati |= 1;
2085 if (sim_tape_bot (unitp))
2086 p->stati |= 2;
2087
2088
2089 sim_debug (DBG_DEBUG, & tape_dev, "%s: Request device status: %o\n", __func__, p->stati);
2090 }
2091 break;
2092
2093
2094
2095
2096
2097
2098
2099
2100 case 051: {
2101 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Reset Device Status\r\n"); }
2102 if (p->isPCW) {
2103 p->stati = 04501;
2104 p->chanStatus = chanStatIncorrectDCW;
2105 return IOM_CMD_ERROR;
2106 }
2107 p->stati = 04000;
2108 if (sim_tape_wrp (unitp))
2109 p->stati |= 1;
2110 if (sim_tape_bot (unitp))
2111 p->stati |= 2;
2112
2113
2114 sim_debug (DBG_DEBUG, & tape_dev, "%s: Reset device status: %o\n", __func__, p->stati);
2115 }
2116 break;
2117
2118
2119
2120
2121
2122
2123
2124 case 055:
2125 if_sim_debug (DBG_TRACE, & tape_dev) {
2126 sim_printf ("// Tape Write EOF\r\n");
2127 sim_printf ("// pos before %d\r\n", unitp->pos);
2128 }
2129 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write tape mark\n", __func__);
2130 #if defined(TESTING)
2131 hdbgNote ("tape", "Tape Write EOF pos before %d", unitp->pos);
2132 #endif
2133
2134 if (! (unitp->flags & UNIT_ATT)) {
2135 p->stati = 04104;
2136 return IOM_CMD_ERROR;
2137 }
2138 int ret;
2139 ret = sim_tape_wrtmk (unitp);
2140 sim_debug (DBG_DEBUG, & tape_dev, "%s: returned %d\n", __func__, ret);
2141 if (unitp->io_flush)
2142 unitp->io_flush (unitp);
2143 if (ret != 0) {
2144 if (ret == MTSE_EOM) {
2145 sim_debug (DBG_NOTIFY, & tape_dev, "%s: EOM: %s\n", __func__, simh_tape_msg (ret));
2146 p->stati = 04340;
2147 sim_warn ("%s: Wrote tape mark with EOM.\n", __func__);
2148 break;
2149 }
2150 sim_warn ("%s: Cannot write tape mark: %d - %s\n", __func__, ret, simh_tape_msg(ret));
2151 sim_warn ("%s: Returning arbitrary error code\n", __func__);
2152 p->stati = 05001;
2153 p->chanStatus = chanStatParityErrPeriph;
2154 break;
2155 }
2156
2157 sim_tape_wreom (unitp);
2158 if (unitp->io_flush)
2159 unitp->io_flush (unitp);
2160
2161 tape_statep->rec_num ++;
2162 if (unitp->flags & UNIT_WATCH)
2163 sim_printf ("Tape %ld writes tape mark %ld\n", (long) MT_UNIT_NUM (unitp), (long) tape_statep->rec_num);
2164
2165 p->stati = 04000;
2166 if (sim_tape_eot (unitp))
2167 p->stati = 04340;
2168
2169 sim_debug (DBG_INFO, & tape_dev, "%s: Wrote tape mark; status %04o\n", __func__, p->stati);
2170 if_sim_debug (DBG_TRACE, & tape_dev) {
2171 sim_printf ("// pos after %d\r\n", unitp->pos);
2172 }
2173 #if defined(TESTING)
2174 hdbgNote ("tape", "Tape Write EOF pos after %d", unitp->pos);
2175 #endif
2176 break;
2177
2178
2179
2180 case 057:
2181 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Survey Devices\r\n"); }
2182 sim_debug (DBG_DEBUG, & tape_dev, "%s: survey_devices\n", __func__);
2183 tape_statep->io_mode = tape_survey;
2184 p->stati = 04000;
2185 break;
2186
2187
2188
2189
2190
2191
2192
2193 case 063:
2194 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set File Permit\r\n"); }
2195 sim_debug (DBG_WARN, & tape_dev, "%s: Set file permit\n", __func__);
2196 p->stati = 04000;
2197 if (sim_tape_wrp (unitp))
2198 p->stati |= 1;
2199 if (sim_tape_bot (unitp))
2200 p->stati |= 2;
2201 break;
2202
2203 case 064:
2204 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 200 BPI\r\n"); }
2205 p->stati = 04000;
2206 if (sim_tape_wrp (unitp))
2207 p->stati |= 1;
2208 if (sim_tape_bot (unitp))
2209 p->stati |= 2;
2210
2211
2212 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 200 bpi\n", __func__);
2213 break;
2214
2215 case 065:
2216 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 1600 CPI\r\n"); }
2217 p->stati = 04000;
2218 if (sim_tape_wrp (unitp))
2219 p->stati |= 1;
2220 if (sim_tape_bot (unitp))
2221 p->stati |= 2;
2222
2223
2224 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 1600 CPI\n", __func__);
2225 break;
2226
2227
2228
2229
2230
2231 case 070:
2232 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Rewind\r\n"); }
2233 sim_debug (DBG_DEBUG, & tape_dev, "%s: Rewind\n", __func__);
2234 if (! (unitp->flags & UNIT_ATT)) {
2235 p->stati = 04104;
2236 return IOM_CMD_ERROR;
2237 }
2238 sim_tape_rewind (unitp);
2239
2240 tape_statep->rec_num = 0;
2241 if (unitp->flags & UNIT_WATCH)
2242 sim_printf ("Tape %ld rewinds\n", (long) MT_UNIT_NUM (unitp));
2243
2244 p->stati = 04000;
2245 if (sim_tape_wrp (unitp))
2246 p->stati |= 1;
2247 if (sim_tape_bot (unitp))
2248 p->stati |= 2;
2249
2250
2251 send_special_interrupt (iomUnitIdx, chan, dev_code, 0, 0100 );
2252 break;
2253
2254
2255
2256 case 072:
2257 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Rewind/Unload\r\n"); }
2258 if ((unitp->flags & UNIT_ATT)) {
2259 if (unitp->flags & UNIT_WATCH)
2260 sim_printf ("Tape %ld unloads\n", (long) MT_UNIT_NUM (unitp));
2261 sim_debug (DBG_DEBUG, & tape_dev, "%s: Rewind/unload\n", __func__);
2262 sim_tape_detach (unitp);
2263 }
2264 p->stati = 04000;
2265
2266
2267
2268
2269
2270
2271 break;
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283 default:
2284 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Unknown %02o\r\n", p->IDCW_DEV_CMD); }
2285 p->stati = 04501;
2286 p->chanStatus = chanStatIncorrectDCW;
2287 sim_warn ("%s: tape unrecognized device command %02o\n", __func__, p->IDCW_DEV_CMD);
2288 return IOM_CMD_ERROR;
2289
2290 }
2291
2292 sim_debug (DBG_DEBUG, & tape_dev, "%s: stati %04o\n", __func__, p->stati);
2293 return rc;
2294 }
2295
2296
2297 switch (tape_statep->io_mode) {
2298 case tape_no_mode:
2299
2300
2301
2302
2303
2304
2305
2306
2307 break;
2308
2309 case tape_rd_9:
2310 case tape_rd_bin: {
2311 if_sim_debug (DBG_TRACE, & tape_dev) {
2312 sim_printf ("// Tape IOT Read\r\n");
2313 sim_printf ("// pos before %d\r\n", unitp->pos);
2314 }
2315 #if defined(TESTING)
2316 hdbgNote ("tape", "Tape IOT Read pos before %d", unitp->pos);
2317 #endif
2318 int rc = mtReadRecord (devUnitIdx, iomUnitIdx, chan);
2319 if (rc)
2320 return IOM_CMD_ERROR;
2321 }
2322 if_sim_debug (DBG_TRACE, & tape_dev) {
2323 sim_printf ("// pos after %d\r\n", unitp->pos);
2324 }
2325 #if defined(TESTING)
2326 hdbgNote ("tape", "Tape IOT Read pos after %d", unitp->pos);
2327 #endif
2328 break;
2329
2330 case tape_wr_9:
2331 case tape_wr_bin: {
2332 if_sim_debug (DBG_TRACE, & tape_dev) {
2333 sim_printf ("// Tape IOT Write\r\n");
2334 sim_printf ("// pos before %d\r\n", unitp->pos);
2335 }
2336 #if defined(TESTING)
2337 hdbgNote ("tape", "Tape IOT write pos before %d", unitp->pos);
2338 #endif
2339 int rc = mtWriteRecord (devUnitIdx, iomUnitIdx, chan);
2340 if_sim_debug (DBG_TRACE, & tape_dev) {
2341 sim_printf ("// pos after %d\r\n", unitp->pos);
2342 }
2343 #if defined(TESTING)
2344 hdbgNote ("tape", "Tape IOT write pos after %d", unitp->pos);
2345 #endif
2346 if (rc)
2347 return IOM_CMD_ERROR;
2348 }
2349 break;
2350
2351 case tape_rd_ctlr:
2352 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Read Memory\r\n"); }
2353 mtReadCtrlMainMem (devUnitIdx, iomUnitIdx, chan);
2354 break;
2355
2356 case tape_initiate_rd_mem:
2357 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Write Memory\r\n"); }
2358 mtInitRdMem (devUnitIdx, iomUnitIdx, chan);
2359 break;
2360
2361 case tape_initiate_wr_mem:
2362 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Initiate Write\r\n"); }
2363 mtInitWrMem (devUnitIdx, iomUnitIdx, chan);
2364 break;
2365
2366 case tape_MTP_wr:
2367 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT MTP Write\r\n"); }
2368 mtMTPWr (devUnitIdx, iomUnitIdx, chan);
2369 break;
2370
2371 case tape_wr_ctrl_regs:
2372 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Wr Ctrl Regs\r\n"); }
2373 mtWRCtrlRegs (devUnitIdx, iomUnitIdx, chan);
2374 break;
2375
2376 case tape_survey:
2377 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Survey\r\n"); }
2378 surveyDevices (iomUnitIdx, chan);
2379 break;
2380
2381 default:
2382 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT unknown %d\r\n", tape_statep->io_mode); }
2383 sim_warn ("%s: Unrecognized io_mode %d\n", __func__, tape_statep->io_mode);
2384 return IOM_CMD_ERROR;
2385 }
2386
2387 return rc;
2388 }
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398 static const char *simh_tape_msg(int code)
2399 {
2400
2401
2402
2403
2404 if (code == MTSE_OK)
2405 return "OK";
2406 else if (code == MTSE_UNATT)
2407 return "Unit not attached to a file";
2408 else if (code == MTSE_FMT)
2409 return "Unit specifies an unsupported tape file format";
2410 else if (code == MTSE_IOERR)
2411 return "Host OS I/O error";
2412 else if (code == MTSE_INVRL)
2413 return "Invalid record length (exceeds maximum allowed)";
2414 else if (code == MTSE_RECE)
2415 return "Record header contains error flag";
2416 else if (code == MTSE_TMK)
2417 return "Tape mark encountered";
2418 else if (code == MTSE_BOT)
2419 return "BOT encountered during reverse operation";
2420 else if (code == MTSE_EOM)
2421 return "End of Medium encountered";
2422 else if (code == MTSE_WRP)
2423 return "Write protected unit during write operation";
2424 else
2425 return "Unknown tape error";
2426 }
2427
2428 t_stat attachTape (char * label, bool withring, char * drive)
2429 {
2430
2431 int i;
2432 for (i = 0; i < N_MT_UNITS_MAX; i ++)
2433 {
2434 if (strcmp (drive, tape_states [i] . device_name) == 0)
2435 break;
2436 }
2437 if (i >= N_MT_UNITS_MAX)
2438 {
2439 sim_printf ("can't find device named %s\n", drive);
2440 return SCPE_ARG;
2441 }
2442 sim_printf ("attachTape selected unit %d\n", i);
2443 loadTape ((uint) i, label, ! withring);
2444 return SCPE_OK;
2445 }
2446
2447
2448
2449 t_stat mount_tape (UNUSED int32 arg, const char * buf)
2450 {
2451 size_t bufl = strlen (buf) + 1;
2452 char fname [bufl];
2453 char ring [bufl];
2454 char drive [bufl];
2455 int nParams = sscanf (buf, "%s %s %s", fname, ring, drive);
2456 if (nParams != 3)
2457 goto usage;
2458 size_t ringl = strlen (ring);
2459 bool withring;
2460 if (strncasecmp ("noring", ring, ringl) == 0)
2461 withring = false;
2462 else if (strncasecmp ("ring", ring, ringl) == 0)
2463 withring = true;
2464 else
2465 goto usage;
2466 return attachTape (fname, withring, drive);
2467
2468 usage:
2469 sim_printf ("mount <image.tap> ring|noring <drive>\n");
2470 return SCPE_ARG;
2471 }
2472
2473 #if !defined(QUIET_UNUSED)
2474 t_stat detachTape (char * drive)
2475 {
2476
2477 int i;
2478 for (i = 0; i < N_MT_UNITS_MAX; i ++)
2479 {
2480 if (strcmp (drive, tape_states [i] . device_name) == 0)
2481 break;
2482 }
2483 if (i >= N_MT_UNITS_MAX)
2484 {
2485 sim_printf ("can't find device named %s\n", drive);
2486 return SCPE_ARG;
2487 }
2488 unloadTape ((uint) i);
2489 return SCPE_OK;
2490 }
2491 #endif