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