This source file includes following definitions.
- sim_disk_set_fmt
- sim_disk_show_fmt
- sim_disk_set_capac
- sim_disk_show_capac
- sim_disk_isavailable
- sim_disk_isavailable_a
- sim_disk_wrp
- sim_disk_size
- _sim_disk_rdsect
- sim_disk_rdsect
- sim_disk_rdsect_a
- _sim_disk_wrsect
- sim_disk_wrsect
- sim_disk_wrsect_a
- sim_disk_unload
- _sim_disk_io_flush
- _err_return
- ODS2Checksum
- get_filesystem_size
- sim_disk_attach
- sim_disk_detach
- sim_disk_attach_help
- sim_disk_reset
- sim_disk_perror
- sim_disk_clearerr
- sim_disk_data_trace
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 #define _FILE_OFFSET_BITS 64
62
63 #include "sim_defs.h"
64 #include "sim_disk.h"
65
66 #include <ctype.h>
67 #include <signal.h>
68 #include <sys/stat.h>
69
70 #include "../decNumber/decContext.h"
71 #include "../decNumber/decNumberLocal.h"
72
73 #ifdef _WIN32
74 # include <windows.h>
75 #endif
76
77 #ifdef TESTING
78 # undef FREE
79 # define FREE(p) free(p)
80 #endif
81
82 #ifndef DECLITEND
83 # error Unknown platform endianness
84 #endif
85
86 struct disk_context {
87 DEVICE *dptr;
88 uint32 dbit;
89 uint32 sector_size;
90 uint32 capac_factor;
91 uint32 xfer_element_size;
92 uint32 storage_sector_size;
93 uint32 removable;
94 uint32 auto_format;
95 };
96
97 #define disk_ctx up8
98
99
100
101 struct sim_disk_fmt {
102 const char *name;
103 int32 uflags;
104 int32 fmtval;
105 t_stat (*impl_fnc)(void);
106 };
107
108 static struct sim_disk_fmt fmts[DKUF_N_FMT] = {
109 { "SIMH", 0, DKUF_F_STD, NULL},
110 { NULL, 0, 0, 0 } };
111
112
113
114 t_stat sim_disk_set_fmt (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
115 {
116 uint32 f;
117
118 if (uptr == NULL)
119 return SCPE_IERR;
120 if (cptr == NULL)
121 return SCPE_ARG;
122 for (f = 0; f < DKUF_N_FMT && fmts[f].name; f++) {
123 if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) {
124 if ((fmts[f].impl_fnc) && (fmts[f].impl_fnc() != SCPE_OK))
125 return SCPE_NOFNC;
126 uptr->flags = (uptr->flags & ~DKUF_FMT) |
127 (fmts[f].fmtval << DKUF_V_FMT) | fmts[f].uflags;
128 return SCPE_OK;
129 }
130 }
131 return SCPE_ARG;
132 }
133
134
135
136 t_stat sim_disk_show_fmt (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
137 {
138 int32 f = DK_GET_FMT (uptr);
139 size_t i;
140
141 for (i = 0; i < DKUF_N_FMT; i++)
142 if (fmts[i].fmtval == f) {
143 fprintf (st, "%s format", fmts[i].name);
144 return SCPE_OK;
145 }
146 fprintf (st, "invalid format");
147 return SCPE_OK;
148 }
149
150
151
152 t_stat sim_disk_set_capac (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
153 {
154 t_offset cap;
155 t_stat r;
156 DEVICE *dptr = find_dev_from_unit (uptr);
157
158 if ((cptr == NULL) || (*cptr == 0))
159 return SCPE_ARG;
160 if (uptr->flags & UNIT_ATT)
161 return SCPE_ALATT;
162 cap = (t_offset) get_uint (cptr, 10, sim_taddr_64? 2000000: 2000, &r);
163 if (r != SCPE_OK)
164 return SCPE_ARG;
165 uptr->capac = (t_addr)((cap * ((t_offset) 1000000))/((dptr->flags & DEV_SECTORS) ? 512 : 1));
166 return SCPE_OK;
167 }
168
169
170
171 t_stat sim_disk_show_capac (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
172 {
173 const char *cap_units = "B";
174 DEVICE *dptr = find_dev_from_unit (uptr);
175 t_offset capac = ((t_offset)uptr->capac)*((dptr->flags & DEV_SECTORS) ? 512 : 1);
176
177 if ((dptr->dwidth / dptr->aincr) == 16)
178 cap_units = "W";
179 if (capac) {
180 if (capac >= (t_offset) 1000000)
181 fprintf (st, "capacity=%luM%s", (unsigned long) (capac / ((t_offset) 1000000)), cap_units);
182 else if (uptr->capac >= (t_addr) 1000)
183 fprintf (st, "capacity=%luK%s", (unsigned long) (capac / ((t_offset) 1000)), cap_units);
184 else fprintf (st, "capacity=%lu%s", (unsigned long) capac, cap_units);
185 }
186 else fprintf (st, "undefined capacity");
187 return SCPE_OK;
188 }
189
190
191
192 t_bool sim_disk_isavailable (UNIT *uptr)
193 {
194 if (!(uptr->flags & UNIT_ATT))
195 return FALSE;
196 switch (DK_GET_FMT (uptr)) {
197 case DKUF_F_STD:
198 return TRUE;
199
200 break;
201 default:
202 return FALSE;
203 }
204 }
205
206 t_bool sim_disk_isavailable_a (UNIT *uptr, DISK_PCALLBACK callback)
207 {
208 t_bool r = FALSE;
209 r = sim_disk_isavailable (uptr);
210 return r;
211 }
212
213
214
215 t_bool sim_disk_wrp (UNIT *uptr)
216 {
217 return (uptr->flags & DKUF_WRP)? TRUE: FALSE;
218 }
219
220
221
222 t_offset sim_disk_size (UNIT *uptr)
223 {
224 switch (DK_GET_FMT (uptr)) {
225 case DKUF_F_STD:
226 return sim_fsize_ex (uptr->fileref);
227
228 break;
229 default:
230 return (t_offset)-1;
231 }
232 }
233
234
235
236 static t_stat _sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
237 {
238 t_offset da;
239 uint32 err, tbc;
240 size_t i;
241 struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
242
243 sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_rdsect(unit=%lu, lba=0x%X, sects=%lu)\n", (unsigned long)(uptr-ctx->dptr->units), lba, (unsigned long)sects);
244
245 da = ((t_offset)lba) * ctx->sector_size;
246 tbc = sects * ctx->sector_size;
247 if (sectsread)
248 *sectsread = 0;
249 err = sim_fseeko (uptr->fileref, da, SEEK_SET);
250 if (!err) {
251 i = sim_fread (buf, ctx->xfer_element_size, tbc/ctx->xfer_element_size, uptr->fileref);
252 if (i < tbc/ctx->xfer_element_size)
253 memset (&buf[i*ctx->xfer_element_size], 0, tbc-(i*ctx->xfer_element_size));
254 err = ferror (uptr->fileref);
255 if ((!err) && (sectsread))
256 *sectsread = (t_seccnt)((i*ctx->xfer_element_size+ctx->sector_size-1)/ctx->sector_size);
257 }
258 return err;
259 }
260
261 t_stat sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects)
262 {
263 t_stat r;
264 struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
265 t_seccnt sread = 0;
266
267 sim_debug (ctx->dbit, ctx->dptr, "sim_disk_rdsect(unit=%lu, lba=0x%X, sects=%lu)\n", (unsigned long)(uptr-ctx->dptr->units), lba, (unsigned long)sects);
268
269 if ((sects == 1) &&
270 (lba >= (uptr->capac*ctx->capac_factor)/(ctx->sector_size/((ctx->dptr->flags & DEV_SECTORS) ? 512 : 1)))) {
271 memset (buf, '\0', ctx->sector_size);
272 if (sectsread)
273 *sectsread = 1;
274 return SCPE_OK;
275 }
276
277 if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) ||
278 ((0 == ((lba*ctx->sector_size) & (ctx->storage_sector_size - 1))) &&
279 (0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1))))) {
280 switch (DK_GET_FMT (uptr)) {
281 case DKUF_F_STD:
282 return _sim_disk_rdsect (uptr, lba, buf, sectsread, sects);
283
284 break;
285 default:
286 return SCPE_NOFNC;
287 }
288
289
290
291
292
293
294 }
295 else {
296 uint8 *tbuf = (uint8*) malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size);
297 t_lba sspsts = ctx->storage_sector_size/ctx->sector_size;
298 t_lba tlba = lba & ~(sspsts - 1);
299 t_seccnt tsects = sects + (lba - tlba);
300
301 tsects = (tsects + (sspsts - 1)) & ~(sspsts - 1);
302 if (sectsread)
303 *sectsread = 0;
304 if (tbuf == NULL)
305 return SCPE_MEM;
306 switch (DK_GET_FMT (uptr)) {
307 case DKUF_F_STD:
308 r = _sim_disk_rdsect (uptr, tlba, tbuf, &sread, tsects);
309 break;
310 default:
311 FREE (tbuf);
312 return SCPE_NOFNC;
313 }
314 if (r == SCPE_OK) {
315 memcpy (buf, tbuf + ((lba - tlba) * ctx->sector_size), sects * ctx->sector_size);
316 if (sectsread) {
317 *sectsread = sread - (lba - tlba);
318 if (*sectsread > sects)
319 *sectsread = sects;
320 }
321 }
322 FREE (tbuf);
323 return r;
324 }
325 }
326
327 t_stat sim_disk_rdsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects, DISK_PCALLBACK callback)
328 {
329 t_stat r = SCPE_OK;
330 r = sim_disk_rdsect (uptr, lba, buf, sectsread, sects);
331 return r;
332 }
333
334
335
336 static t_stat _sim_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
337 {
338 t_offset da;
339 uint32 err, tbc;
340 size_t i;
341 struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
342
343 sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_wrsect(unit=%lu, lba=0x%X, sects=%lu)\n", (unsigned long)(uptr-ctx->dptr->units), lba, (unsigned long)sects);
344
345 da = ((t_offset)lba) * ctx->sector_size;
346 tbc = sects * ctx->sector_size;
347 if (sectswritten)
348 *sectswritten = 0;
349 err = sim_fseeko (uptr->fileref, da, SEEK_SET);
350 if (!err) {
351 i = sim_fwrite (buf, ctx->xfer_element_size, tbc/ctx->xfer_element_size, uptr->fileref);
352 err = ferror (uptr->fileref);
353 if ((!err) && (sectswritten))
354 *sectswritten = (t_seccnt)((i*ctx->xfer_element_size+ctx->sector_size-1)/ctx->sector_size);
355 }
356 return err;
357 }
358
359 t_stat sim_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects)
360 {
361 struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
362 uint32 f = DK_GET_FMT (uptr);
363 t_stat r;
364 uint8 *tbuf = NULL;
365
366 sim_debug (ctx->dbit, ctx->dptr, "sim_disk_wrsect(unit=%lu, lba=0x%X, sects=%lu)\n", (unsigned long)(uptr-ctx->dptr->units), lba, (unsigned long)sects);
367
368 if (uptr->dynflags & UNIT_DISK_CHK) {
369 DEVICE *dptr = find_dev_from_unit (uptr);
370 uint32 capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1;
371 t_lba total_sectors = (t_lba)((uptr->capac*capac_factor)/(ctx->sector_size/((dptr->flags & DEV_SECTORS) ? 512 : 1)));
372 t_lba sect;
373
374 for (sect = 0; sect < sects; sect++) {
375 t_lba offset;
376 t_bool sect_error = FALSE;
377
378 for (offset = 0; offset < ctx->sector_size; offset += sizeof(uint32)) {
379 if (*((uint32 *)&buf[sect*ctx->sector_size + offset]) != (uint32)(lba + sect)) {
380 sect_error = TRUE;
381 break;
382 }
383 }
384 if (sect_error) {
385 uint32 save_dctrl = dptr->dctrl;
386 FILE *save_sim_deb = sim_deb;
387
388 sim_printf ("\n%s%lu: Write Address Verification Error on lbn %lu(0x%X) of %lu(0x%X).\n", sim_dname (dptr), (unsigned long)(uptr-dptr->units), (unsigned long)((unsigned long)lba+(unsigned long)sect), (int)((int)lba+(int)sect), (unsigned long)total_sectors, (int)total_sectors);
389 dptr->dctrl = 0xFFFFFFFF;
390 sim_deb = save_sim_deb ? save_sim_deb : stdout;
391 sim_disk_data_trace (uptr, buf+sect*ctx->sector_size, lba+sect, ctx->sector_size, "Found", TRUE, 1);
392 dptr->dctrl = save_dctrl;
393 sim_deb = save_sim_deb;
394 }
395 }
396 }
397 if (f == DKUF_F_STD)
398 return _sim_disk_wrsect (uptr, lba, buf, sectswritten, sects);
399 if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) ||
400 ((0 == ((lba*ctx->sector_size) & (ctx->storage_sector_size - 1))) &&
401 (0 == ((sects*ctx->sector_size) & (ctx->storage_sector_size - 1))))) {
402
403 sim_end = DECLITEND;
404 if (sim_end || (ctx->xfer_element_size == sizeof (char)))
405 switch (DK_GET_FMT (uptr)) {
406 default:
407 return SCPE_NOFNC;
408 }
409
410 tbuf = (uint8*) malloc (sects * ctx->sector_size);
411 if (NULL == tbuf)
412 return SCPE_MEM;
413 sim_buf_copy_swapped (tbuf, buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size);
414
415 switch (DK_GET_FMT (uptr)) {
416 default:
417 r = SCPE_NOFNC;
418 break;
419 }
420 }
421 else {
422 t_lba sspsts = ctx->storage_sector_size/ctx->sector_size;
423 t_lba tlba = lba & ~(sspsts - 1);
424 t_seccnt tsects = sects + (lba - tlba);
425
426 tbuf = (uint8*) malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size);
427 tsects = (tsects + (sspsts - 1)) & ~(sspsts - 1);
428 if (sectswritten)
429 *sectswritten = 0;
430 if (tbuf == NULL)
431 return SCPE_MEM;
432
433 if ((lba & (sspsts - 1)) ||
434 (sects < sspsts))
435 switch (DK_GET_FMT (uptr)) {
436 default:
437 r = SCPE_NOFNC;
438 break;
439 }
440 if ((tsects > sspsts) &&
441 ((sects + lba - tlba) & (sspsts - 1)))
442 switch (DK_GET_FMT (uptr)) {
443 default:
444 r = SCPE_NOFNC;
445 break;
446 }
447 sim_buf_copy_swapped (tbuf + (lba & (sspsts - 1)) * ctx->sector_size,
448 buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size);
449 switch (DK_GET_FMT (uptr)) {
450 default:
451 r = SCPE_NOFNC;
452 break;
453 }
454 if ((r == SCPE_OK) && sectswritten) {
455 *sectswritten -= (lba - tlba);
456 if (*sectswritten > sects)
457 *sectswritten = sects;
458 }
459 }
460 FREE (tbuf);
461 return r;
462 }
463
464 t_stat sim_disk_wrsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects, DISK_PCALLBACK callback)
465 {
466 t_stat r = SCPE_OK;
467 r = sim_disk_wrsect (uptr, lba, buf, sectswritten, sects);
468 return r;
469 }
470
471 t_stat sim_disk_unload (UNIT *uptr)
472 {
473 switch (DK_GET_FMT (uptr)) {
474 case DKUF_F_STD:
475 return sim_disk_detach (uptr);
476 default:
477 return SCPE_NOFNC;
478 }
479 }
480
481 static void _sim_disk_io_flush (UNIT *uptr)
482 {
483 uint32 f = DK_GET_FMT (uptr);
484
485 switch (f) {
486 case DKUF_F_STD:
487 fflush (uptr->fileref);
488 break;
489 }
490 }
491
492 static t_stat _err_return (UNIT *uptr, t_stat stat)
493 {
494 FREE (uptr->filename);
495 uptr->filename = NULL;
496 FREE (uptr->disk_ctx);
497 uptr->disk_ctx = NULL;
498 return stat;
499 }
500
501 #ifdef __xlc__
502 # pragma pack(1)
503 #else
504 # pragma pack(push,1)
505 #endif
506 typedef struct _ODS2_HomeBlock
507 {
508 uint32 hm2_l_homelbn;
509 uint32 hm2_l_alhomelbn;
510 uint32 hm2_l_altidxlbn;
511 uint8 hm2_b_strucver;
512 uint8 hm2_b_struclev;
513 uint16 hm2_w_cluster;
514 uint16 hm2_w_homevbn;
515 uint16 hm2_w_alhomevbn;
516 uint16 hm2_w_altidxvbn;
517 uint16 hm2_w_ibmapvbn;
518 uint32 hm2_l_ibmaplbn;
519 uint32 hm2_l_maxfiles;
520 uint16 hm2_w_ibmapsize;
521 uint16 hm2_w_resfiles;
522 uint16 hm2_w_devtype;
523 uint16 hm2_w_rvn;
524 uint16 hm2_w_setcount;
525 uint16 hm2_w_volchar;
526 uint32 hm2_l_volowner;
527 uint32 hm2_l_reserved;
528 uint16 hm2_w_protect;
529 uint16 hm2_w_fileprot;
530 uint16 hm2_w_reserved;
531 uint16 hm2_w_checksum1;
532 uint32 hm2_q_credate[2];
533 uint8 hm2_b_window;
534 uint8 hm2_b_lru_lim;
535 uint16 hm2_w_extend;
536 uint32 hm2_q_retainmin[2];
537 uint32 hm2_q_retainmax[2];
538 uint32 hm2_q_revdate[2];
539 uint8 hm2_r_min_class[20];
540 uint8 hm2_r_max_class[20];
541 uint8 hm2_r_reserved[320];
542 uint32 hm2_l_serialnum;
543 uint8 hm2_t_strucname[12];
544 uint8 hm2_t_volname[12];
545 uint8 hm2_t_ownername[12];
546 uint8 hm2_t_format[12];
547 uint16 hm2_w_reserved2;
548 uint16 hm2_w_checksum2;
549 } ODS2_HomeBlock;
550
551 typedef struct _ODS2_FileHeader
552 {
553 uint8 fh2_b_idoffset;
554 uint8 fh2_b_mpoffset;
555 uint8 fh2_b_acoffset;
556 uint8 fh2_b_rsoffset;
557 uint16 fh2_w_seg_num;
558 uint16 fh2_w_structlev;
559 uint16 fh2_w_fid[3];
560 uint16 fh2_w_ext_fid[3];
561 uint16 fh2_w_recattr[16];
562 uint32 fh2_l_filechar;
563 uint16 fh2_w_remaining[228];
564 } ODS2_FileHeader;
565
566 typedef union _ODS2_Retreval
567 {
568 struct
569 {
570 unsigned fm2___fill : 14;
571 unsigned fm2_v_format : 2;
572 } fm2_r_word0_bits;
573 struct
574 {
575 unsigned fm2_v_exact : 1;
576 unsigned fm2_v_oncyl : 1;
577 unsigned fm2___fill : 10;
578 unsigned fm2_v_lbn : 1;
579 unsigned fm2_v_rvn : 1;
580 unsigned fm2_v_format0 : 2;
581 } fm2_r_map_bits0;
582 struct
583 {
584 unsigned fm2_b_count1 : 8;
585 unsigned fm2_v_highlbn1 : 6;
586 unsigned fm2_v_format1 : 2;
587 unsigned fm2_w_lowlbn1 : 16;
588 } fm2_r_map_bits1;
589 struct
590 {
591 struct
592 {
593 unsigned fm2_v_count2 : 14;
594 unsigned fm2_v_format2 : 2;
595 unsigned fm2_l_lowlbn2 : 16;
596 } fm2_r_map2_long0;
597 uint16 fm2_l_highlbn2;
598 } fm2_r_map_bits2;
599 struct
600 {
601 struct
602 {
603 unsigned fm2_v_highcount3 : 14;
604 unsigned fm2_v_format3 : 2;
605 unsigned fm2_w_lowcount3 : 16;
606 } fm2_r_map3_long0;
607 uint32 fm2_l_lbn3;
608 } fm2_r_map_bits3;
609 } ODS2_Retreval;
610
611 typedef struct _ODS2_StorageControlBlock
612 {
613 uint8 scb_b_strucver;
614 uint8 scb_b_struclev;
615 uint16 scb_w_cluster;
616 uint32 scb_l_volsize;
617 uint32 scb_l_blksize;
618 uint32 scb_l_sectors;
619 uint32 scb_l_tracks;
620 uint32 scb_l_cylinder;
621 uint32 scb_l_status;
622 uint32 scb_l_status2;
623 uint16 scb_w_writecnt;
624 uint8 scb_t_volockname[12];
625 uint32 scb_q_mounttime[2];
626 uint16 scb_w_backrev;
627 uint32 scb_q_genernum[2];
628 uint8 scb_b_reserved[446];
629 uint16 scb_w_checksum;
630 } ODS2_SCB;
631 #ifdef __xlc__
632 # pragma pack(reset)
633 #else
634 # pragma pack(pop)
635 #endif
636
637 static uint16
638 ODS2Checksum (void *Buffer, uint16 WordCount)
639 {
640 int i;
641 uint16 CheckSum = 0;
642 uint16 *Buf = (uint16 *)Buffer;
643
644 for (i=0; i<WordCount; i++)
645 CheckSum += Buf[i];
646 return CheckSum;
647 }
648
649 static t_offset get_filesystem_size (UNIT *uptr)
650 {
651 DEVICE *dptr;
652 t_addr saved_capac;
653 t_offset temp_capac = 512 * (t_offset)0xFFFFFFFFu;
654 uint32 capac_factor;
655 ODS2_HomeBlock Home;
656 ODS2_FileHeader Header;
657 ODS2_Retreval *Retr;
658 ODS2_SCB Scb;
659 uint16 CheckSum1, CheckSum2;
660 uint32 ScbLbn = 0;
661 t_offset ret_val = (t_offset)-1;
662
663 if ((dptr = find_dev_from_unit (uptr)) == NULL)
664 return ret_val;
665 capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1;
666 saved_capac = uptr->capac;
667
668 uptr->capac = (t_addr)(temp_capac/(capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
669 if (sim_disk_rdsect (uptr, 1, (uint8 *)&Home, NULL, 1))
670 goto Return_Cleanup;
671
672 CheckSum1 = ODS2Checksum (&Home, (uint16)((((char *)&Home.hm2_w_checksum1)-((char *)&Home.hm2_l_homelbn))/2));
673
674 CheckSum2 = ODS2Checksum (&Home, (uint16)((((char *)&Home.hm2_w_checksum2)-((char *)&Home.hm2_l_homelbn))/2));
675 if ((Home.hm2_l_homelbn == 0) ||
676 (Home.hm2_l_alhomelbn == 0) ||
677 (Home.hm2_l_altidxlbn == 0) ||
678 ((Home.hm2_b_struclev != 2) &&
679 (Home.hm2_b_struclev != 5)) ||
680 (Home.hm2_b_strucver == 0) ||
681 (Home.hm2_w_cluster == 0) ||
682 (Home.hm2_w_homevbn == 0) ||
683 (Home.hm2_w_alhomevbn == 0) ||
684 (Home.hm2_w_ibmapvbn == 0) ||
685 (Home.hm2_l_ibmaplbn == 0) ||
686 (Home.hm2_w_resfiles >= Home.hm2_l_maxfiles) ||
687 (Home.hm2_w_ibmapsize == 0) ||
688 (Home.hm2_w_resfiles < 5) ||
689 (Home.hm2_w_checksum1 != CheckSum1) ||
690 (Home.hm2_w_checksum2 != CheckSum2))
691 goto Return_Cleanup;
692 if (sim_disk_rdsect (uptr, Home.hm2_l_ibmaplbn+Home.hm2_w_ibmapsize+1, (uint8 *)&Header, NULL, 1))
693 goto Return_Cleanup;
694 CheckSum1 = ODS2Checksum (&Header, 255);
695 if (CheckSum1 != *(((uint16 *)&Header)+255))
696 goto Return_Cleanup;
697 Retr = (ODS2_Retreval *)(((uint16*)(&Header))+Header.fh2_b_mpoffset);
698
699 if (Retr->fm2_r_word0_bits.fm2_v_format == 0)
700 Retr = (ODS2_Retreval *)(((uint16 *)Retr)+1);
701 switch (Retr->fm2_r_word0_bits.fm2_v_format)
702 {
703 case 1:
704 ScbLbn = (Retr->fm2_r_map_bits1.fm2_v_highlbn1<<16)+Retr->fm2_r_map_bits1.fm2_w_lowlbn1;
705 break;
706 case 2:
707 ScbLbn = (Retr->fm2_r_map_bits2.fm2_l_highlbn2<<16)+Retr->fm2_r_map_bits2.fm2_r_map2_long0.fm2_l_lowlbn2;
708 break;
709 case 3:
710 ScbLbn = Retr->fm2_r_map_bits3.fm2_l_lbn3;
711 break;
712 }
713 Retr = (ODS2_Retreval *)(((uint16 *)Retr)+Retr->fm2_r_word0_bits.fm2_v_format+1);
714 if (sim_disk_rdsect (uptr, ScbLbn, (uint8 *)&Scb, NULL, 1))
715 goto Return_Cleanup;
716 CheckSum1 = ODS2Checksum (&Scb, 255);
717 if (CheckSum1 != *(((uint16 *)&Scb)+255))
718 goto Return_Cleanup;
719 if ((Scb.scb_w_cluster != Home.hm2_w_cluster) ||
720 (Scb.scb_b_strucver != Home.hm2_b_strucver) ||
721 (Scb.scb_b_struclev != Home.hm2_b_struclev))
722 goto Return_Cleanup;
723 if (!sim_quiet) {
724 sim_printf ("%s%lu: '%s' Contains ODS%lu File system:\n", sim_dname (dptr), (unsigned long)(uptr-dptr->units), uptr->filename, (unsigned long)Home.hm2_b_struclev);
725 sim_printf ("%s%lu: Volume Name: %12.12s ", sim_dname (dptr), (unsigned long)(uptr-dptr->units), Home.hm2_t_volname);
726 sim_printf ("Format: %12.12s ", Home.hm2_t_format);
727 sim_printf ("SectorsInVolume: %lu\n", (unsigned long)Scb.scb_l_volsize);
728 }
729 ret_val = ((t_offset)Scb.scb_l_volsize) * 512;
730
731 Return_Cleanup:
732 uptr->capac = saved_capac;
733 return ret_val;
734 }
735
736 t_stat sim_disk_attach (UNIT *uptr, const char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize,
737 uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay)
738 {
739 struct disk_context *ctx;
740 DEVICE *dptr;
741 FILE *(*open_function)(const char *filename, const char *mode) = sim_fopen;
742 FILE *(*create_function)(const char *filename, t_offset desiredsize) = NULL;
743 t_offset (*size_function)(FILE *file) = NULL;
744 t_stat (*storage_function)(FILE *file, uint32 *sector_size, uint32 *removable) = NULL;
745 t_bool created = FALSE, copied = FALSE;
746 t_bool auto_format = FALSE;
747 t_offset capac, filesystem_capac;
748
749 if (uptr->flags & UNIT_DIS)
750 return SCPE_UDIS;
751 if (!(uptr->flags & UNIT_ATTABLE))
752 return SCPE_NOATT;
753 if ((dptr = find_dev_from_unit (uptr)) == NULL)
754 return SCPE_NOATT;
755 if (sim_switches & SWMASK ('F')) {
756 char gbuf[CBUFSIZE];
757 cptr = get_glyph (cptr, gbuf, 0);
758 if (*cptr == 0)
759 return SCPE_2FARG;
760 if (sim_disk_set_fmt (uptr, 0, gbuf, NULL) != SCPE_OK)
761 return sim_messagef (SCPE_ARG, "Invalid Disk Format: %s\n", gbuf);
762 sim_switches = sim_switches & ~(SWMASK ('F'));
763 auto_format = TRUE;
764 }
765 open_function = sim_fopen;
766 size_function = sim_fsize_ex;
767 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));
768 uptr->disk_ctx = ctx = (struct disk_context *)calloc(1, sizeof(struct disk_context));
769 if (!ctx)
770 {
771 fprintf(stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
772 __func__, __FILE__, __LINE__);
773 #if defined(USE_BACKTRACE)
774 # ifdef SIGUSR2
775 (void)raise(SIGUSR2);
776
777 # endif
778 #endif
779 abort();
780 }
781 if ((uptr->filename == NULL) || (uptr->disk_ctx == NULL))
782 return _err_return (uptr, SCPE_MEM);
783 #ifdef __GNUC__
784 # ifndef __clang_version__
785 # if __GNUC__ > 7
786 # ifndef __INTEL_COMPILER
787 # pragma GCC diagnostic push
788 # pragma GCC diagnostic ignored "-Wstringop-truncation"
789 # endif
790 # endif
791 # endif
792 #endif
793 strncpy (uptr->filename, cptr, CBUFSIZE);
794 #ifdef __GNUC__
795 # ifndef __clang_version__
796 # if __GNUC__ > 7
797 # ifndef __INTEL_COMPILER
798 # pragma GCC diagnostic pop
799 # endif
800 # endif
801 # endif
802 #endif
803 ctx->sector_size = (uint32)sector_size;
804 ctx->capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1;
805 ctx->xfer_element_size = (uint32)xfer_element_size;
806 ctx->dptr = dptr;
807 ctx->dbit = dbit;
808 sim_debug (ctx->dbit, ctx->dptr, "sim_disk_attach(unit=%lu,filename='%s')\n", (unsigned long)(uptr-ctx->dptr->units), uptr->filename);
809 ctx->auto_format = auto_format;
810 ctx->storage_sector_size = (uint32)sector_size;
811 if ((sim_switches & SWMASK ('R')) ||
812 ((uptr->flags & UNIT_RO) != 0)) {
813 if (((uptr->flags & UNIT_ROABLE) == 0) &&
814 ((uptr->flags & UNIT_RO) == 0))
815 return _err_return (uptr, SCPE_NORO);
816 uptr->fileref = open_function (cptr, "rb");
817 if (uptr->fileref == NULL)
818 return _err_return (uptr, SCPE_OPENERR);
819 uptr->flags = uptr->flags | UNIT_RO;
820 if (!sim_quiet) {
821 sim_printf ("%s%lu: unit is read only (%s)\n", sim_dname (dptr), (unsigned long)(uptr-dptr->units), cptr);
822 }
823 }
824 else {
825 uptr->fileref = open_function (cptr, "rb+");
826 if (uptr->fileref == NULL) {
827 if ((errno == EROFS) || (errno == EACCES)) {
828 if ((uptr->flags & UNIT_ROABLE) == 0)
829 return _err_return (uptr, SCPE_NORO);
830 uptr->fileref = open_function (cptr, "rb");
831 if (uptr->fileref == NULL)
832 return _err_return (uptr, SCPE_OPENERR);
833 uptr->flags = uptr->flags | UNIT_RO;
834 if (!sim_quiet)
835 sim_printf ("%s%lu: unit is read only (%s)\n", sim_dname (dptr), (unsigned long)(uptr-dptr->units), cptr);
836 }
837 else {
838 if (sim_switches & SWMASK ('E'))
839 return _err_return (uptr, SCPE_OPENERR);
840 if (create_function)
841 uptr->fileref = create_function (cptr, ((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1));
842 else
843 uptr->fileref = open_function (cptr, "wb+");
844 if (uptr->fileref == NULL)
845 return _err_return (uptr, SCPE_OPENERR);
846 if (!sim_quiet)
847 sim_printf ("%s%lu: creating new file (%s)\n", sim_dname (dptr), (unsigned long)(uptr-dptr->units), cptr);
848 created = TRUE;
849 }
850 }
851 }
852 uptr->flags = uptr->flags | UNIT_ATT;
853 uptr->pos = 0;
854
855
856 if (storage_function)
857 storage_function (uptr->fileref, &ctx->storage_sector_size, &ctx->removable);
858
859 if ((created) && (!copied)) {
860 t_stat r = SCPE_OK;
861 uint8 *secbuf = (uint8 *)calloc (1, ctx->sector_size);
862 if (secbuf == NULL)
863 r = SCPE_MEM;
864 if (r == SCPE_OK)
865 r = sim_disk_wrsect (uptr, (t_lba)(((((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)) - ctx->sector_size)/ctx->sector_size), secbuf, NULL, 1);
866 if (r == SCPE_OK)
867 r = sim_disk_wrsect (uptr, (t_lba)(0), secbuf, NULL, 1);
868 FREE (secbuf);
869 if (r != SCPE_OK) {
870 sim_disk_detach (uptr);
871 remove (cptr);
872 return SCPE_OPENERR;
873 }
874 if (sim_switches & SWMASK ('I')) {
875 uint8 *init_buf = (uint8*) malloc (1024*1024);
876 t_lba lba, sect;
877 uint32 capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1;
878 t_seccnt sectors_per_buffer = (t_seccnt)((1024*1024)/sector_size);
879 t_lba total_sectors = (t_lba)((uptr->capac*capac_factor)/(sector_size/((dptr->flags & DEV_SECTORS) ? 512 : 1)));
880 t_seccnt sects = sectors_per_buffer;
881
882 if (!init_buf) {
883 sim_disk_detach (uptr);
884 remove (cptr);
885 return SCPE_MEM;
886 }
887 for (lba = 0; (lba < total_sectors) && (r == SCPE_OK); lba += sects) {
888 sects = sectors_per_buffer;
889 if (lba + sects > total_sectors)
890 sects = total_sectors - lba;
891 for (sect = 0; sect < sects; sect++) {
892 t_lba offset;
893 for (offset = 0; offset < sector_size; offset += sizeof(uint32))
894 *((uint32 *)&init_buf[sect*sector_size + offset]) = (uint32)(lba + sect);
895 }
896 r = sim_disk_wrsect (uptr, lba, init_buf, NULL, sects);
897 if (r != SCPE_OK) {
898 FREE (init_buf);
899 sim_disk_detach (uptr);
900 remove (cptr);
901 return SCPE_OPENERR;
902 }
903 if (!sim_quiet)
904 sim_printf ("%s%lu: Initialized To Sector Address %luMB. %lu%% complete.\r", sim_dname (dptr), (unsigned long)(uptr-dptr->units), (unsigned long)((((float)lba)*sector_size)/1000000), (unsigned long)((((float)lba)*100)/total_sectors));
905 }
906 if (!sim_quiet)
907 sim_printf ("%s%lu: Initialized To Sector Address %luMB. 100%% complete.\n", sim_dname (dptr), (unsigned long)(uptr-dptr->units), (unsigned long)((((float)lba)*sector_size)/1000000));
908 FREE (init_buf);
909 }
910 }
911
912 if (sim_switches & SWMASK ('K')) {
913 t_stat r = SCPE_OK;
914 t_lba lba, sect;
915 uint32 capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1;
916 t_seccnt sectors_per_buffer = (t_seccnt)((1024*1024)/sector_size);
917 t_lba total_sectors = (t_lba)((uptr->capac*capac_factor)/(sector_size/((dptr->flags & DEV_SECTORS) ? 512 : 1)));
918 t_seccnt sects = sectors_per_buffer;
919 uint8 *verify_buf = (uint8*) malloc (1024*1024);
920
921 if (!verify_buf) {
922 sim_disk_detach (uptr);
923 return SCPE_MEM;
924 }
925 for (lba = 0; (lba < total_sectors) && (r == SCPE_OK); lba += sects) {
926 sects = sectors_per_buffer;
927 if (lba + sects > total_sectors)
928 sects = total_sectors - lba;
929 r = sim_disk_rdsect (uptr, lba, verify_buf, NULL, sects);
930 if (r == SCPE_OK) {
931 for (sect = 0; sect < sects; sect++) {
932 t_lba offset;
933 t_bool sect_error = FALSE;
934
935 for (offset = 0; offset < sector_size; offset += sizeof(uint32)) {
936 if (*((uint32 *)&verify_buf[sect*sector_size + offset]) != (uint32)(lba + sect)) {
937 sect_error = TRUE;
938 break;
939 }
940 }
941 if (sect_error) {
942 uint32 save_dctrl = dptr->dctrl;
943 FILE *save_sim_deb = sim_deb;
944
945 sim_printf ("\n%s%lu: Verification Error on lbn %lu(0x%X) of %lu(0x%X).\n", sim_dname (dptr), (unsigned long)(uptr-dptr->units), (unsigned long)((unsigned long)lba+(unsigned long)sect), (int)((int)lba+(int)sect), (unsigned long)total_sectors, (int)total_sectors);
946 dptr->dctrl = 0xFFFFFFFF;
947 sim_deb = stdout;
948 sim_disk_data_trace (uptr, verify_buf+sect*sector_size, lba+sect, sector_size, "Found", TRUE, 1);
949 dptr->dctrl = save_dctrl;
950 sim_deb = save_sim_deb;
951 }
952 }
953 }
954 if (!sim_quiet)
955 sim_printf ("%s%lu: Verified containing Sector Address %luMB. %lu%% complete.\r", sim_dname (dptr), (unsigned long)(uptr-dptr->units), (unsigned long)((((float)lba)*sector_size)/1000000), (unsigned long)((((float)lba)*100)/total_sectors));
956 }
957 if (!sim_quiet)
958 sim_printf ("%s%lu: Verified containing Sector Address %luMB. 100%% complete.\n", sim_dname (dptr), (unsigned long)(uptr-dptr->units), (unsigned long)((((float)lba)*sector_size)/1000000));
959 FREE (verify_buf);
960 uptr->dynflags |= UNIT_DISK_CHK;
961 }
962
963 filesystem_capac = get_filesystem_size (uptr);
964 capac = size_function (uptr->fileref);
965 if (capac && (capac != (t_offset)-1)) {
966 if (dontautosize) {
967 t_addr saved_capac = uptr->capac;
968
969 if ((filesystem_capac != (t_offset)-1) &&
970 (filesystem_capac > (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)))) {
971 if (!sim_quiet) {
972 uptr->capac = (t_addr)(filesystem_capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
973 sim_printf ("%s%lu: The file system on the disk %s is larger than simulated device (%s > ", sim_dname (dptr), (unsigned long)(uptr-dptr->units), cptr, sprint_capac (dptr, uptr));
974 uptr->capac = saved_capac;
975 sim_printf ("%s)\n", sprint_capac (dptr, uptr));
976 }
977 sim_disk_detach (uptr);
978 return SCPE_OPENERR;
979 }
980 if ((capac < (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) && (DKUF_F_STD != DK_GET_FMT (uptr))) {
981 if (!sim_quiet) {
982 uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
983 sim_printf ("%s%lu: non expandable disk %s is smaller than simulated device (%s < ", sim_dname (dptr), (unsigned long)(uptr-dptr->units), cptr, sprint_capac (dptr, uptr));
984 uptr->capac = saved_capac;
985 sim_printf ("%s)\n", sprint_capac (dptr, uptr));
986 }
987 sim_disk_detach (uptr);
988 return SCPE_OPENERR;
989 }
990 }
991 else {
992 if ((filesystem_capac != (t_offset)-1) &&
993 (filesystem_capac > capac))
994 capac = filesystem_capac;
995 if ((capac > (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) ||
996 (DKUF_F_STD != DK_GET_FMT (uptr)))
997 uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)));
998 }
999 }
1000
1001 uptr->io_flush = _sim_disk_io_flush;
1002
1003 return SCPE_OK;
1004 }
1005
1006 t_stat sim_disk_detach (UNIT *uptr)
1007 {
1008 struct disk_context *ctx;
1009 int (*close_function)(FILE *f);
1010 FILE *fileref;
1011
1012 if ((uptr == NULL) || !(uptr->flags & UNIT_ATT))
1013 return SCPE_NOTATT;
1014
1015 ctx = (struct disk_context *)uptr->disk_ctx;
1016 fileref = uptr->fileref;
1017
1018
1019
1020 switch (DK_GET_FMT (uptr)) {
1021 case DKUF_F_STD:
1022 close_function = fclose;
1023 break;
1024 default:
1025 return SCPE_IERR;
1026 }
1027 if (!(uptr->flags & UNIT_ATTABLE))
1028 return SCPE_NOATT;
1029 if (!(uptr->flags & UNIT_ATT))
1030 return SCPE_OK;
1031 if (NULL == find_dev_from_unit (uptr))
1032 return SCPE_OK;
1033
1034 if (uptr->io_flush)
1035 uptr->io_flush (uptr);
1036
1037 uptr->flags &= ~(UNIT_ATT | UNIT_RO);
1038 uptr->dynflags &= ~(UNIT_NO_FIO | UNIT_DISK_CHK);
1039 FREE (uptr->filename);
1040 uptr->filename = NULL;
1041 uptr->fileref = NULL;
1042 if (uptr->disk_ctx) {
1043 FREE (uptr->disk_ctx);
1044 uptr->disk_ctx = NULL;
1045 }
1046 uptr->io_flush = NULL;
1047 if (ctx && ctx -> auto_format)
1048 sim_disk_set_fmt (uptr, 0, "SIMH", NULL);
1049 if (close_function (fileref) == EOF)
1050 return SCPE_IOERR;
1051 return SCPE_OK;
1052 }
1053
1054 t_stat sim_disk_attach_help(FILE *st, DEVICE *dptr, const UNIT *uptr, int32 flag, const char *cptr)
1055 {
1056 fprintf (st, "%s Disk Attach Help\n\n", dptr->name);
1057 fprintf (st, "Disk files are stored in the following format:\n\n");
1058 fprintf (st, " SIMH An unstructured binary file of the size appropriate\n");
1059 fprintf (st, " for the disk drive being simulated.\n\n");
1060
1061 if (0 == (uptr-dptr->units)) {
1062 if (dptr->numunits > 1) {
1063 uint32 i;
1064
1065 for (i=0; i < dptr->numunits; ++i)
1066 if (dptr->units[i].flags & UNIT_ATTABLE)
1067 fprintf (st, " sim> ATTACH {switches} %s%lu diskfile\n", dptr->name, (unsigned long)i);
1068 }
1069 else
1070 fprintf (st, " sim> ATTACH {switches} %s diskfile\n", dptr->name);
1071 }
1072 else
1073 fprintf (st, " sim> ATTACH {switches} %s diskfile\n\n", dptr->name);
1074 fprintf (st, "\n%s attach command switches\n", dptr->name);
1075 fprintf (st, " -R Attach Read Only.\n");
1076 fprintf (st, " -E Must Exist (if not specified an attempt to create the indicated\n");
1077 fprintf (st, " disk container will be attempted).\n");
1078 fprintf (st, " -F Open the indicated disk container in a specific format\n");
1079 fprintf (st, " -I Initialize newly created disk so that each sector contains its\n");
1080 fprintf (st, " sector address\n");
1081 fprintf (st, " -K Verify that the disk contents contain the sector address in each\n");
1082 fprintf (st, " sector. Whole disk checked at attach time and each sector is\n");
1083 fprintf (st, " checked when written.\n");
1084 fprintf (st, " -V Perform a verification pass to confirm successful data copy\n");
1085 fprintf (st, " operation.\n");
1086 fprintf (st, " -U Fix inconsistencies which are overridden by the -O switch\n");
1087 fprintf (st, " -Y Answer Yes to prompt to overwrite last track (on disk create)\n");
1088 fprintf (st, " -N Answer No to prompt to overwrite last track (on disk create)\n");
1089 return SCPE_OK;
1090 }
1091
1092 t_stat sim_disk_reset (UNIT *uptr)
1093 {
1094 struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
1095
1096 if (!(uptr->flags & UNIT_ATT))
1097 return SCPE_OK;
1098
1099 sim_debug (ctx->dbit, ctx->dptr, "sim_disk_reset(unit=%lu)\n", (unsigned long)(uptr-ctx->dptr->units));
1100
1101 _sim_disk_io_flush(uptr);
1102 return SCPE_OK;
1103 }
1104
1105 t_stat sim_disk_perror (UNIT *uptr, const char *msg)
1106 {
1107 int saved_errno = errno;
1108
1109 if (!(uptr->flags & UNIT_ATTABLE))
1110 return SCPE_NOATT;
1111 switch (DK_GET_FMT (uptr)) {
1112 case DKUF_F_STD:
1113 perror (msg);
1114 sim_printf ("%s %s: %s\n", sim_uname(uptr), msg, strerror(saved_errno));
1115
1116 default:
1117 ;
1118 }
1119 return SCPE_OK;
1120 }
1121
1122 t_stat sim_disk_clearerr (UNIT *uptr)
1123 {
1124 if (!(uptr->flags & UNIT_ATTABLE))
1125 return SCPE_NOATT;
1126 switch (DK_GET_FMT (uptr)) {
1127 case DKUF_F_STD:
1128 clearerr (uptr->fileref);
1129 break;
1130 default:
1131 ;
1132 }
1133 return SCPE_OK;
1134 }
1135
1136 void sim_disk_data_trace(UNIT *uptr, const uint8 *data, size_t lba, size_t len, const char* txt, int detail, uint32 reason)
1137 {
1138 struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
1139
1140 if (sim_deb && (ctx->dptr->dctrl & reason)) {
1141 char pos[32];
1142
1143 sprintf (pos, "lbn: %08X ", (unsigned int)lba);
1144 sim_data_trace(ctx->dptr, uptr, (detail ? data : NULL), pos, len, txt, reason);
1145 }
1146 }