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 "../simh/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\r\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\r\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\r\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\r\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\r\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.\r\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]\r\n");
559 sim_print(" i.e. SET TAPE ADD_PATH=BK=./tapes/backups\r\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:\r\n");
639 sim_printf("%-32s %s\r\n", "Prefix", "Directory");
640 sim_printf("%-32s %s\r\n", "------", "---------");
641 PATH_ENTRY *current_entry = search_list_head;
642 while (current_entry != NULL)
643 {
644 sim_printf("%-32s %s\r\n", current_entry->label_prefix, current_entry->dir);
645 current_entry = current_entry->next_entry;
646 }
647
648 sim_printf("%-32s %s\r\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\r\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\r\n", (long) tape_unit_idx);
739 sim_printf ("error: Invalid unit number %ld\r\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\r\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\r\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\r\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\r\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\r\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\r\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\r\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.\r\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\r\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.\r\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\r\n",
1046 __func__, rc, simh_tape_msg (rc));
1047 sim_debug (DBG_ERR, & tape_dev,
1048 "%s: Returning arbitrary error code\r\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\r\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)\r\n",
1069 __func__);
1070 tally = 4096;
1071 }
1072
1073 sim_debug (DBG_DEBUG, & tape_dev,
1074 "%s: Tally %d (%o)\r\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\r\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\r\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\r\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\r\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\r\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)\r\n",
1258 __func__);
1259 tally = 4096;
1260 }
1261
1262 sim_debug (DBG_DEBUG, & tape_dev,
1263 "%s: Tally %d (%o)\r\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\r\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\r\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\r\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.\r\n",
1358 __func__, tape_statep -> tbc);
1359 }
1360 return 0;
1361 }
1362 sim_warn ("%s: Cannot write tape: %d - %s\r\n",
1363 __func__, ret, simh_tape_msg(ret));
1364 sim_warn ("%s: Returning arbitrary error code\r\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\r\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\r\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\r\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\r\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\r\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.\r\n", __func__, p->IDCW_DEV_CMD, p->IDCW_DEV_CMD);
1533 p -> recordResidue = 0;
1534 switch (p->IDCW_DEV_CMD) {
1535 case 000: {
1536 if_sim_debug (DBG_TRACE, & tape_dev) {
1537 sim_printf ("// Tape Request Status\r\n");
1538 }
1539
1540 if (p->IDCW_CHAN_CMD == 040) {
1541 sim_debug (DBG_DEBUG, & tape_dev, "%s: controller suspend\r\n", __func__);
1542 send_special_interrupt (iomUnitIdx, chan, p->IDCW_DEV_CODE, 01, 0 );
1543 p->stati = 04000;
1544 } else {
1545 p->stati = 04000;
1546 }
1547 sim_debug (DBG_DEBUG, & tape_dev, "%s: Request status: %04o control %0o chan_cmd %02o\r\n", __func__,
1548 p->stati, p->IDCW_CHAN_CTRL, p->IDCW_CHAN_CMD);
1549 }
1550 break;
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
1605 case 002:
1606 if_sim_debug (DBG_TRACE, & tape_dev) {
1607 sim_printf ("// Tape Read Controller Main Memory\r\n");
1608 }
1609 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read controller main memory\r\n", __func__);
1610
1611 tape_statep->io_mode = tape_rd_ctlr;
1612 p->stati = 04000;
1613 break;
1614
1615 case 003:
1616 if_sim_debug (DBG_TRACE, & tape_dev) {
1617 sim_printf ("// Tape Read 9 Record\r\n");
1618 }
1619 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read 9 record\r\n", __func__);
1620 tape_statep->io_mode = tape_rd_9;
1621 tape_statep->is9 = true;
1622 if (! (unitp->flags & UNIT_ATT)) {
1623 p->stati = 04104;
1624 return IOM_CMD_ERROR;
1625 }
1626 p->stati = 04000;
1627 break;
1628
1629
1630
1631 case 005:
1632 if_sim_debug (DBG_TRACE, & tape_dev) {
1633 sim_printf ("// Tape Read Binary Record\r\n");
1634 }
1635 sim_debug (DBG_DEBUG, & tape_dev, "%s: Read binary record\r\n", __func__);
1636 tape_statep->io_mode = tape_rd_bin;
1637 tape_statep->is9 = false;
1638 if (! (unitp->flags & UNIT_ATT)) {
1639 p->stati = 04104;
1640 return IOM_CMD_ERROR;
1641 }
1642 p->stati = 04000;
1643 break;
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665 case 006:
1666 if_sim_debug (DBG_TRACE, & tape_dev) {
1667 sim_printf ("// Tape Initiate Read Data Transfer\r\n");
1668 }
1669 sim_debug (DBG_DEBUG, & tape_dev, "%s: initiate read data transfer\r\n", __func__);
1670 tape_statep->io_mode = tape_initiate_rd_mem;
1671 p->stati = 04000;
1672 break;
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682 case 013:
1683 if_sim_debug (DBG_TRACE, & tape_dev) {
1684 sim_printf ("// Tape Write 9 Record\r\n");
1685 }
1686 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write 9 record\r\n", __func__);
1687 tape_statep->io_mode = tape_wr_9;
1688 if (! (unitp->flags & UNIT_ATT)) {
1689 p->stati = 04104;
1690 return IOM_CMD_ERROR;
1691 }
1692 p->stati = 04000;
1693 break;
1694
1695
1696
1697 case 015:
1698 if_sim_debug (DBG_TRACE, & tape_dev) {
1699 sim_printf ("// Tape Write Binary Record\r\n");
1700 }
1701 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write binary record\r\n", __func__);
1702 tape_statep->io_mode = tape_wr_bin;
1703 if (! (unitp->flags & UNIT_ATT)) {
1704 p->stati = 04104;
1705 return IOM_CMD_ERROR;
1706 }
1707 p->stati = 04000;
1708 break;
1709
1710 case 016:
1711 if_sim_debug (DBG_TRACE, & tape_dev) {
1712 sim_printf ("// Tape Write Control Registers\r\n");
1713 }
1714 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write Control Registers\r\n", __func__);
1715 tape_statep->io_mode = tape_wr_ctrl_regs;
1716 p->stati = 04000;
1717 break;
1718
1719
1720
1721 case 020: {
1722 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Release Controller\r\n"); }
1723 if (p->IDCW_CHAN_CMD == 040) {
1724 sim_debug (DBG_DEBUG, & tape_dev, "%s: Release controller\r\n", __func__);
1725 p->stati = 04000;
1726 sim_debug (DBG_DEBUG, & tape_dev, "%s: Release status: %04o control %0o chan_cmd %02o\r\n",
1727 __func__, p->stati, p->IDCW_CHAN_CTRL, p->IDCW_CHAN_CMD);
1728 send_special_interrupt (iomUnitIdx, chan, p->IDCW_DEV_CODE, 02, 0 );
1729 } else {
1730 p->stati = 04501;
1731 p->chanStatus = chanStatIncorrectDCW;
1732 sim_warn ("%s: Unknown command %02o\r\n", __func__, p->IDCW_DEV_CMD);
1733 }
1734 }
1735 break;
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757 case 032:
1758
1759 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Write Main Memory\r\n"); }
1760 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write controller main memory\r\n", __func__);
1761 tape_statep->io_mode = tape_MTP_wr;
1762 p->stati = 04000;
1763 break;
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775 case 040:
1776 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Reset Status\r\n"); }
1777 sim_debug (DBG_DEBUG, & tape_dev, "%s Reset status\r\n", __func__);
1778 p->stati = 04000;
1779 p->isRead = false;
1780
1781 if (dev_code == 077) {
1782 p->stati = 04502;
1783 return IOM_CMD_DISCONNECT;
1784 }
1785 if (sim_tape_wrp (unitp))
1786 p->stati |= 1;
1787 if (sim_tape_bot (unitp))
1788 p->stati |= 2;
1789
1790
1791 break;
1792
1793 case 041:
1794 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 6259 CPI\r\n"); }
1795 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 6250 cpi\r\n", __func__);
1796 p->stati = 04000;
1797 if (sim_tape_wrp (unitp))
1798 p->stati |= 1;
1799 if (sim_tape_bot (unitp))
1800 p->stati |= 2;
1801
1802
1803 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 800 bpi\r\n", __func__);
1804 break;
1805
1806 case 042:
1807 case 060:
1808 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 800 BPI\r\n"); }
1809 p->stati = 04000;
1810 if (sim_tape_wrp (unitp))
1811 p->stati |= 1;
1812 if (sim_tape_bot (unitp))
1813 p->stati |= 2;
1814
1815
1816 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 800 bpi\r\n", __func__);
1817 break;
1818
1819 case 043:
1820 case 061:
1821 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 556 BPI\r\n"); }
1822 p->stati = 04000;
1823 if (sim_tape_wrp (unitp))
1824 p->stati |= 1;
1825 if (sim_tape_bot (unitp))
1826 p->stati |= 2;
1827
1828
1829 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 556 bpi\r\n", __func__);
1830 break;
1831
1832 case 044: {
1833 if_sim_debug (DBG_TRACE, & tape_dev) {
1834 sim_printf ("// Tape Forward Skip One Record\r\n");
1835 sim_printf ("// pos before %d\r\n", unitp->pos);
1836 }
1837 #if defined(TESTING)
1838 hdbgNote ("tape", "Tape Forward Skip One Record pos before %d", unitp->pos);
1839 #endif
1840 if (! (unitp->flags & UNIT_ATT)) {
1841 p->stati = 04104;
1842 return IOM_CMD_ERROR;
1843 }
1844 uint tally = p->IDCW_COUNT;
1845 if (tally == 0) {
1846 sim_debug (DBG_DEBUG, & tape_dev, "%s: Tally of zero interpreted as 64\r\n", __func__);
1847 tally = 64;
1848 }
1849 sim_debug (DBG_DEBUG, & tape_dev, "%s: Forward skip record %d\r\n", __func__, tally);
1850
1851
1852
1853
1854
1855
1856 uint32 skipped = 0;
1857 t_stat ret = MTSE_OK;
1858 while (skipped < tally) {
1859 ret = sim_tape_sprecf (unitp, & tape_statep->tbc);
1860 if (ret != MTSE_OK && ret != MTSE_TMK)
1861 break;
1862 skipped = skipped + 1;
1863 }
1864
1865 if (ret != MTSE_OK && ret != MTSE_TMK && ret != MTSE_EOM) {
1866 break;
1867 }
1868 if (skipped != tally) {
1869 sim_warn ("skipped %d != tally %d\r\n", skipped, tally);
1870 }
1871
1872 tape_statep->rec_num += (int) skipped;
1873 if (unitp->flags & UNIT_WATCH)
1874 sim_printf ("Tape %ld forward skips to record %d\r\n", (long) MT_UNIT_NUM (unitp), tape_statep->rec_num);
1875
1876 p->tallyResidue = (word12) (tally - skipped);
1877
1878 p->stati = 04000;
1879 if (sim_tape_wrp (unitp))
1880 p->stati |= 1;
1881 if (sim_tape_bot (unitp))
1882 p->stati |= 2;
1883
1884
1885 if_sim_debug (DBG_TRACE, & tape_dev) {
1886 sim_printf ("// pos after %d\r\n", unitp->pos);
1887 }
1888 #if defined(TESTING)
1889 hdbgNote ("tape", "Tape Forward Skip One Record pos after %d", unitp->pos);
1890 #endif
1891 }
1892 break;
1893
1894 case 045: {
1895 if_sim_debug (DBG_TRACE, & tape_dev) {
1896 sim_printf ("// Tape Forward Skip One File\r\n");
1897 sim_printf ("// pos before %d\r\n", unitp->pos);
1898 }
1899 #if defined(TESTING)
1900 hdbgNote ("tape", "Tape Forward Skip One File pos before %d", unitp->pos);
1901 #endif
1902 sim_debug (DBG_DEBUG, & tape_dev, "%s:: Forward Skip File\r\n", __func__);
1903 if (! (unitp->flags & UNIT_ATT)) {
1904 p->stati = 04104;
1905 return IOM_CMD_ERROR;
1906 }
1907 uint tally = 1;
1908
1909 uint32 skipped, recsskipped;
1910 t_stat ret = sim_tape_spfilebyrecf (unitp, tally, & skipped, & recsskipped, false);
1911 if_sim_debug (DBG_TRACE, & tape_dev)
1912 {
1913 sim_printf ("// sim_tape_spfilebyrecf ret %d skipped %d recsskipped %d\r\n",
1914 ret, skipped, recsskipped);
1915 }
1916 if (ret != MTSE_OK && ret != MTSE_TMK && ret != MTSE_LEOT) {
1917 sim_warn ("sim_tape_spfilebyrecf returned %d\r\n", ret);
1918 break;
1919 }
1920 if (skipped != tally) {
1921 sim_warn ("skipped %d != tally %d\r\n", skipped, tally);
1922 }
1923
1924 tape_statep->rec_num += (int) recsskipped;
1925 if (unitp->flags & UNIT_WATCH)
1926 sim_printf ("Tape %ld forward skips to record %d\r\n", (long) MT_UNIT_NUM (unitp), tape_statep->rec_num);
1927
1928 p->tallyResidue = (word12) (tally - skipped);
1929 sim_debug (DBG_NOTIFY, & tape_dev, "%s: Forward space %d files\r\n", __func__, tally);
1930
1931 p->stati = 04000;
1932 if (sim_tape_wrp (unitp))
1933 p->stati |= 1;
1934 if (sim_tape_bot (unitp))
1935 p->stati |= 2;
1936
1937
1938 }
1939 if_sim_debug (DBG_TRACE, & tape_dev) {
1940 sim_printf ("// pos after %d\r\n", unitp->pos);
1941 }
1942 #if defined(TESTING)
1943 hdbgNote ("tape", "Tape Forward Skip One File pos after %d", unitp->pos);
1944 #endif
1945 break;
1946
1947 case 046: {
1948 if_sim_debug (DBG_TRACE, & tape_dev) {
1949 sim_printf ("// Tape Backspace One Record\r\n");
1950 sim_printf ("// pos before %d\r\n", unitp->pos);
1951 }
1952 #if defined(TESTING)
1953 hdbgNote ("tape", "Tape Backspace One Record pos before %d", unitp->pos);
1954 #endif
1955 sim_debug (DBG_DEBUG, & tape_dev, "%s: Backspace Record\r\n", __func__);
1956 if (! (unitp->flags & UNIT_ATT)) {
1957 p->stati = 04104;
1958 return IOM_CMD_ERROR;
1959 }
1960
1961 uint tally = p->IDCW_COUNT;
1962 if (tally == 0) {
1963 sim_debug (DBG_DEBUG, & tape_dev, "%s: Tally of zero interpreted as 64\r\n", __func__);
1964 tally = 64;
1965 }
1966
1967 sim_debug (DBG_DEBUG, & tape_dev, "%s: Backspace record tally %d\r\n", __func__, tally);
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978 uint32 skipped = 0;
1979 while (skipped < tally) {
1980 t_stat ret = sim_tape_sprecr (unitp, & tape_statep->tbc);
1981 if (ret != MTSE_OK && ret != MTSE_TMK)
1982 break;
1983 skipped ++;
1984 }
1985
1986 if (skipped != tally) {
1987 sim_warn ("skipped %d != tally %d\r\n", skipped, tally);
1988 }
1989 tape_statep->rec_num -= (int) skipped;
1990 if (unitp->flags & UNIT_WATCH)
1991 sim_printf ("Tape %ld skip back to record %d\r\n", (long) MT_UNIT_NUM (unitp), tape_statep->rec_num);
1992
1993 p->tallyResidue = (word12) (tally - skipped);
1994
1995 sim_debug (DBG_NOTIFY, & tape_dev, "%s: Backspace %d records\r\n", __func__, skipped);
1996
1997 p->stati = 04000;
1998 if (sim_tape_wrp (unitp))
1999 p->stati |= 1;
2000 if (sim_tape_bot (unitp))
2001 p->stati |= 2;
2002
2003
2004 }
2005 if_sim_debug (DBG_TRACE, & tape_dev) {
2006 sim_printf ("// pos after %d\r\n", unitp->pos);
2007 }
2008 #if defined(TESTING)
2009 hdbgNote ("tape", "Tape Backspace One Record pos after %d", unitp->pos);
2010 #endif
2011 break;
2012
2013 case 047: {
2014 if_sim_debug (DBG_TRACE, & tape_dev) {
2015 sim_printf ("// Tape Backspace One File\r\n");
2016 sim_printf ("// pos before %d\r\n", unitp->pos);
2017 }
2018 sim_debug (DBG_DEBUG, & tape_dev, "%s: Backspace File\r\n", __func__);
2019 #if defined(TESTING)
2020 hdbgNote ("tape", "Tape Backspace One File pos before %d", unitp->pos);
2021 #endif
2022 if (! (unitp->flags & UNIT_ATT)) {
2023 p->stati = 04104;
2024 return IOM_CMD_ERROR;
2025 }
2026 uint tally = 1;
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047 uint32 skipped, recsskipped;
2048 t_stat ret = sim_tape_spfilebyrecr (unitp, tally, & skipped, & recsskipped);
2049 if (ret != MTSE_OK && ret != MTSE_TMK && ret != MTSE_BOT) {
2050 sim_warn ("sim_tape_spfilebyrecr returned %d\r\n", ret);
2051 break;
2052 }
2053 if (skipped != tally) {
2054 sim_warn ("skipped %d != tally %d\r\n", skipped, tally);
2055 }
2056
2057 tape_statep->rec_num -= (int) recsskipped;
2058 if (unitp->flags & UNIT_WATCH)
2059 sim_printf ("Tape %ld backward skips to record %d\r\n", (long) MT_UNIT_NUM (unitp), tape_statep->rec_num);
2060
2061 p->tallyResidue = (word12) (tally - skipped);
2062 sim_debug (DBG_NOTIFY, & tape_dev, "%s: Backspace %d records\r\n", __func__, tally);
2063
2064
2065 p->stati = 04000;
2066 if (sim_tape_wrp (unitp))
2067 p->stati |= 1;
2068 if (sim_tape_bot (unitp))
2069 p->stati |= 2;
2070
2071
2072 }
2073 if_sim_debug (DBG_TRACE, & tape_dev) {
2074 sim_printf ("// pos after %d\r\n", unitp->pos);
2075 }
2076 #if defined(TESTING)
2077 hdbgNote ("tape", "Tape Backspace One File pos after %d", unitp->pos);
2078 #endif
2079 break;
2080
2081 case 050: {
2082 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Request Device Status\r\n"); }
2083 p->stati = 04000;
2084 if (sim_tape_wrp (unitp))
2085 p->stati |= 1;
2086 if (sim_tape_bot (unitp))
2087 p->stati |= 2;
2088
2089
2090 sim_debug (DBG_DEBUG, & tape_dev, "%s: Request device status: %o\r\n", __func__, p->stati);
2091 }
2092 break;
2093
2094
2095
2096
2097
2098
2099
2100
2101 case 051: {
2102 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Reset Device Status\r\n"); }
2103 if (p->isPCW) {
2104 p->stati = 04501;
2105 p->chanStatus = chanStatIncorrectDCW;
2106 return IOM_CMD_ERROR;
2107 }
2108 p->stati = 04000;
2109 if (sim_tape_wrp (unitp))
2110 p->stati |= 1;
2111 if (sim_tape_bot (unitp))
2112 p->stati |= 2;
2113
2114
2115 sim_debug (DBG_DEBUG, & tape_dev, "%s: Reset device status: %o\r\n", __func__, p->stati);
2116 }
2117 break;
2118
2119
2120
2121
2122
2123
2124
2125 case 055:
2126 if_sim_debug (DBG_TRACE, & tape_dev) {
2127 sim_printf ("// Tape Write EOF\r\n");
2128 sim_printf ("// pos before %d\r\n", unitp->pos);
2129 }
2130 sim_debug (DBG_DEBUG, & tape_dev, "%s: Write tape mark\r\n", __func__);
2131 #if defined(TESTING)
2132 hdbgNote ("tape", "Tape Write EOF pos before %d", unitp->pos);
2133 #endif
2134
2135 if (! (unitp->flags & UNIT_ATT)) {
2136 p->stati = 04104;
2137 return IOM_CMD_ERROR;
2138 }
2139 int ret;
2140 ret = sim_tape_wrtmk (unitp);
2141 sim_debug (DBG_DEBUG, & tape_dev, "%s: returned %d\r\n", __func__, ret);
2142 if (unitp->io_flush)
2143 unitp->io_flush (unitp);
2144 if (ret != 0) {
2145 if (ret == MTSE_EOM) {
2146 sim_debug (DBG_NOTIFY, & tape_dev, "%s: EOM: %s\r\n", __func__, simh_tape_msg (ret));
2147 p->stati = 04340;
2148 sim_warn ("%s: Wrote tape mark with EOM.\r\n", __func__);
2149 break;
2150 }
2151 sim_warn ("%s: Cannot write tape mark: %d - %s\r\n", __func__, ret, simh_tape_msg(ret));
2152 sim_warn ("%s: Returning arbitrary error code\r\n", __func__);
2153 p->stati = 05001;
2154 p->chanStatus = chanStatParityErrPeriph;
2155 break;
2156 }
2157
2158 sim_tape_wreom (unitp);
2159 if (unitp->io_flush)
2160 unitp->io_flush (unitp);
2161
2162 tape_statep->rec_num ++;
2163 if (unitp->flags & UNIT_WATCH)
2164 sim_printf ("Tape %ld writes tape mark %ld\r\n", (long) MT_UNIT_NUM (unitp), (long) tape_statep->rec_num);
2165
2166 p->stati = 04000;
2167 if (sim_tape_eot (unitp))
2168 p->stati = 04340;
2169
2170 sim_debug (DBG_INFO, & tape_dev, "%s: Wrote tape mark; status %04o\r\n", __func__, p->stati);
2171 if_sim_debug (DBG_TRACE, & tape_dev) {
2172 sim_printf ("// pos after %d\r\n", unitp->pos);
2173 }
2174 #if defined(TESTING)
2175 hdbgNote ("tape", "Tape Write EOF pos after %d", unitp->pos);
2176 #endif
2177 break;
2178
2179
2180
2181 case 057:
2182 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Survey Devices\r\n"); }
2183 sim_debug (DBG_DEBUG, & tape_dev, "%s: survey_devices\r\n", __func__);
2184 tape_statep->io_mode = tape_survey;
2185 p->stati = 04000;
2186 break;
2187
2188
2189
2190
2191
2192
2193
2194 case 063:
2195 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set File Permit\r\n"); }
2196 sim_debug (DBG_WARN, & tape_dev, "%s: Set file permit\r\n", __func__);
2197 p->stati = 04000;
2198 if (sim_tape_wrp (unitp))
2199 p->stati |= 1;
2200 if (sim_tape_bot (unitp))
2201 p->stati |= 2;
2202 break;
2203
2204 case 064:
2205 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 200 BPI\r\n"); }
2206 p->stati = 04000;
2207 if (sim_tape_wrp (unitp))
2208 p->stati |= 1;
2209 if (sim_tape_bot (unitp))
2210 p->stati |= 2;
2211
2212
2213 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 200 bpi\r\n", __func__);
2214 break;
2215
2216 case 065:
2217 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Set 1600 CPI\r\n"); }
2218 p->stati = 04000;
2219 if (sim_tape_wrp (unitp))
2220 p->stati |= 1;
2221 if (sim_tape_bot (unitp))
2222 p->stati |= 2;
2223
2224
2225 sim_debug (DBG_DEBUG, & tape_dev, "%s: Set 1600 CPI\r\n", __func__);
2226 break;
2227
2228
2229
2230
2231
2232 case 070:
2233 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Rewind\r\n"); }
2234 sim_debug (DBG_DEBUG, & tape_dev, "%s: Rewind\r\n", __func__);
2235 if (! (unitp->flags & UNIT_ATT)) {
2236 p->stati = 04104;
2237 return IOM_CMD_ERROR;
2238 }
2239 sim_tape_rewind (unitp);
2240
2241 tape_statep->rec_num = 0;
2242 if (unitp->flags & UNIT_WATCH)
2243 sim_printf ("Tape %ld rewinds\r\n", (long) MT_UNIT_NUM (unitp));
2244
2245 p->stati = 04000;
2246 if (sim_tape_wrp (unitp))
2247 p->stati |= 1;
2248 if (sim_tape_bot (unitp))
2249 p->stati |= 2;
2250
2251
2252 send_special_interrupt (iomUnitIdx, chan, dev_code, 0, 0100 );
2253 break;
2254
2255
2256
2257 case 072:
2258 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Rewind/Unload\r\n"); }
2259 if ((unitp->flags & UNIT_ATT)) {
2260 if (unitp->flags & UNIT_WATCH)
2261 sim_printf ("Tape %ld unloads\r\n", (long) MT_UNIT_NUM (unitp));
2262 sim_debug (DBG_DEBUG, & tape_dev, "%s: Rewind/unload\r\n", __func__);
2263 sim_tape_detach (unitp);
2264 }
2265 p->stati = 04000;
2266
2267
2268
2269
2270
2271
2272 break;
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284 default:
2285 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape Unknown %02o\r\n", p->IDCW_DEV_CMD); }
2286 p->stati = 04501;
2287 p->chanStatus = chanStatIncorrectDCW;
2288 sim_warn ("%s: tape unrecognized device command %02o\r\n", __func__, p->IDCW_DEV_CMD);
2289 return IOM_CMD_ERROR;
2290
2291 }
2292
2293 sim_debug (DBG_DEBUG, & tape_dev, "%s: stati %04o\r\n", __func__, p->stati);
2294 return rc;
2295 }
2296
2297
2298 switch (tape_statep->io_mode) {
2299 case tape_no_mode:
2300
2301
2302
2303
2304
2305
2306
2307
2308 break;
2309
2310 case tape_rd_9:
2311 case tape_rd_bin: {
2312 if_sim_debug (DBG_TRACE, & tape_dev) {
2313 sim_printf ("// Tape IOT Read\r\n");
2314 sim_printf ("// pos before %d\r\n", unitp->pos);
2315 }
2316 #if defined(TESTING)
2317 hdbgNote ("tape", "Tape IOT Read pos before %d", unitp->pos);
2318 #endif
2319 int rc = mtReadRecord (devUnitIdx, iomUnitIdx, chan);
2320 if (rc)
2321 return IOM_CMD_ERROR;
2322 }
2323 if_sim_debug (DBG_TRACE, & tape_dev) {
2324 sim_printf ("// pos after %d\r\n", unitp->pos);
2325 }
2326 #if defined(TESTING)
2327 hdbgNote ("tape", "Tape IOT Read pos after %d", unitp->pos);
2328 #endif
2329 break;
2330
2331 case tape_wr_9:
2332 case tape_wr_bin: {
2333 if_sim_debug (DBG_TRACE, & tape_dev) {
2334 sim_printf ("// Tape IOT Write\r\n");
2335 sim_printf ("// pos before %d\r\n", unitp->pos);
2336 }
2337 #if defined(TESTING)
2338 hdbgNote ("tape", "Tape IOT write pos before %d", unitp->pos);
2339 #endif
2340 int rc = mtWriteRecord (devUnitIdx, iomUnitIdx, chan);
2341 if_sim_debug (DBG_TRACE, & tape_dev) {
2342 sim_printf ("// pos after %d\r\n", unitp->pos);
2343 }
2344 #if defined(TESTING)
2345 hdbgNote ("tape", "Tape IOT write pos after %d", unitp->pos);
2346 #endif
2347 if (rc)
2348 return IOM_CMD_ERROR;
2349 }
2350 break;
2351
2352 case tape_rd_ctlr:
2353 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Read Memory\r\n"); }
2354 mtReadCtrlMainMem (devUnitIdx, iomUnitIdx, chan);
2355 break;
2356
2357 case tape_initiate_rd_mem:
2358 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Write Memory\r\n"); }
2359 mtInitRdMem (devUnitIdx, iomUnitIdx, chan);
2360 break;
2361
2362 case tape_initiate_wr_mem:
2363 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Initiate Write\r\n"); }
2364 mtInitWrMem (devUnitIdx, iomUnitIdx, chan);
2365 break;
2366
2367 case tape_MTP_wr:
2368 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT MTP Write\r\n"); }
2369 mtMTPWr (devUnitIdx, iomUnitIdx, chan);
2370 break;
2371
2372 case tape_wr_ctrl_regs:
2373 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Wr Ctrl Regs\r\n"); }
2374 mtWRCtrlRegs (devUnitIdx, iomUnitIdx, chan);
2375 break;
2376
2377 case tape_survey:
2378 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT Survey\r\n"); }
2379 surveyDevices (iomUnitIdx, chan);
2380 break;
2381
2382 default:
2383 if_sim_debug (DBG_TRACE, & tape_dev) { sim_printf ("// Tape IOT unknown %d\r\n", tape_statep->io_mode); }
2384 sim_warn ("%s: Unrecognized io_mode %d\r\n", __func__, tape_statep->io_mode);
2385 return IOM_CMD_ERROR;
2386 }
2387
2388 return rc;
2389 }
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399 static const char *simh_tape_msg(int code)
2400 {
2401
2402
2403
2404
2405 if (code == MTSE_OK)
2406 return "OK";
2407 else if (code == MTSE_UNATT)
2408 return "Unit not attached to a file";
2409 else if (code == MTSE_FMT)
2410 return "Unit specifies an unsupported tape file format";
2411 else if (code == MTSE_IOERR)
2412 return "Host OS I/O error";
2413 else if (code == MTSE_INVRL)
2414 return "Invalid record length (exceeds maximum allowed)";
2415 else if (code == MTSE_RECE)
2416 return "Record header contains error flag";
2417 else if (code == MTSE_TMK)
2418 return "Tape mark encountered";
2419 else if (code == MTSE_BOT)
2420 return "BOT encountered during reverse operation";
2421 else if (code == MTSE_EOM)
2422 return "End of Medium encountered";
2423 else if (code == MTSE_WRP)
2424 return "Write protected unit during write operation";
2425 else
2426 return "Unknown tape error";
2427 }
2428
2429 t_stat attachTape (char * label, bool withring, char * drive)
2430 {
2431
2432 int i;
2433 for (i = 0; i < N_MT_UNITS_MAX; i ++)
2434 {
2435 if (strcmp (drive, tape_states [i] . device_name) == 0)
2436 break;
2437 }
2438 if (i >= N_MT_UNITS_MAX)
2439 {
2440 sim_printf ("can't find device named %s\r\n", drive);
2441 return SCPE_ARG;
2442 }
2443 sim_printf ("attachTape selected unit %d\r\n", i);
2444 loadTape ((uint) i, label, ! withring);
2445 return SCPE_OK;
2446 }
2447
2448
2449
2450 t_stat mount_tape (UNUSED int32 arg, const char * buf)
2451 {
2452 size_t bufl = strlen (buf) + 1;
2453 char fname [bufl];
2454 char ring [bufl];
2455 char drive [bufl];
2456 int nParams = sscanf (buf, "%s %s %s", fname, ring, drive);
2457 if (nParams != 3)
2458 goto usage;
2459 size_t ringl = strlen (ring);
2460 bool withring;
2461 if (strncasecmp ("noring", ring, ringl) == 0)
2462 withring = false;
2463 else if (strncasecmp ("ring", ring, ringl) == 0)
2464 withring = true;
2465 else
2466 goto usage;
2467 return attachTape (fname, withring, drive);
2468
2469 usage:
2470 sim_printf ("mount <image.tap> ring|noring <drive>\r\n");
2471 return SCPE_ARG;
2472 }
2473
2474 #if !defined(QUIET_UNUSED)
2475 t_stat detachTape (char * drive)
2476 {
2477
2478 int i;
2479 for (i = 0; i < N_MT_UNITS_MAX; i ++)
2480 {
2481 if (strcmp (drive, tape_states [i] . device_name) == 0)
2482 break;
2483 }
2484 if (i >= N_MT_UNITS_MAX)
2485 {
2486 sim_printf ("can't find device named %s\r\n", drive);
2487 return SCPE_ARG;
2488 }
2489 unloadTape ((uint) i);
2490 return SCPE_OK;
2491 }
2492 #endif