From b98ece819ba3e0f494e177cb30a5d4c9a4c54b0a Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 29 Nov 2016 18:53:52 -0800 Subject: [PATCH] DISK: Extended and corrected autosize logic for disk attach. Previously only the actual size of the container file was used when attaching a disk. This was correct only when the size of the container file actually aligned with the simulated disk drive. disks created with sim_disk_attach automatically write to the last sector of a simulated disk file when the disk is created. Therefore, auto sizing worked correctly for any disk created with sim_disk_attach. Disk images created with simh prior to 4.X would only write to the portions of the disk drive when the simulated system writes data. These disk images would only be properly sized if the simulated operation of the disk had actually written to the last block of the disk. Auto sizing of these disks would usually size the resulting disk incorrectly and strange behaviors might occur when using such an incorrectly auto sized disk. Fixes #357 --- scp.c | 29 +++--- scp.h | 1 + sim_disk.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 270 insertions(+), 20 deletions(-) diff --git a/scp.c b/scp.c index b012726c..3b831c07 100644 --- a/scp.c +++ b/scp.c @@ -4420,12 +4420,13 @@ if (toks || (flag < 0) || (flag > 1)) return SCPE_OK; } -void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr) +const char *sprint_capac (DEVICE *dptr, UNIT *uptr) { +static char capac_buf[((CHAR_BIT * sizeof (t_value) * 4 + 3)/3) + 8]; t_addr kval = (uptr->flags & UNIT_BINK)? 1024: 1000; t_addr mval; t_addr psize = uptr->capac; -char scale, width; +char *scale, *width; if (sim_switches & SWMASK ('B')) kval = 1024; @@ -4435,23 +4436,27 @@ if (dptr->flags & DEV_SECTORS) { mval = mval / 512; } if ((dptr->dwidth / dptr->aincr) > 8) - width = 'W'; -else width = 'B'; + width = "W"; +else + width = "B"; if (uptr->capac < (kval * 10)) - scale = 0; + scale = ""; else if (uptr->capac < (mval * 10)) { - scale = 'K'; + scale = "K"; psize = psize / kval; } else { - scale = 'M'; + scale = "M"; psize = psize / mval; } -fprint_val (st, (t_value) psize, 10, T_ADDR_W, PV_LEFT); -if (scale) - fputc (scale, st); -fputc (width, st); -return; +sprint_val (capac_buf, (t_value) psize, 10, T_ADDR_W, PV_LEFT); +sprintf (&capac_buf[strlen (capac_buf)], "%s%s", scale, width); +return capac_buf; +} + +void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr) +{ +fprintf (st, "%s", sprint_capac (dptr, uptr)); } /* Show processors */ diff --git a/scp.h b/scp.h index 3d0b1850..2a914446 100644 --- a/scp.h +++ b/scp.h @@ -169,6 +169,7 @@ t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt t_stat sprint_val (char *buf, t_value val, uint32 rdx, uint32 wid, uint32 fmt); t_stat sim_print_val (t_value val, uint32 radix, uint32 width, uint32 format); const char *sim_fmt_secs (double seconds); +const char *sprint_capac (DEVICE *dptr, UNIT *uptr); char *read_line (char *cptr, int32 size, FILE *stream); void fprint_reg_help (FILE *st, DEVICE *dptr); void fprint_set_help (FILE *st, DEVICE *dptr); diff --git a/sim_disk.c b/sim_disk.c index a4c7e09a..6c3e67ee 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -837,6 +837,230 @@ uptr->disk_ctx = NULL; return stat; } +#pragma pack(push,1) +typedef struct _ODS2_HomeBlock + { + uint32 hm2$l_homelbn; + uint32 hm2$l_alhomelbn; + uint32 hm2$l_altidxlbn; + uint8 hm2$b_strucver; + uint8 hm2$b_struclev; + uint16 hm2$w_cluster; + uint16 hm2$w_homevbn; + uint16 hm2$w_alhomevbn; + uint16 hm2$w_altidxvbn; + uint16 hm2$w_ibmapvbn; + uint32 hm2$l_ibmaplbn; + uint32 hm2$l_maxfiles; + uint16 hm2$w_ibmapsize; + uint16 hm2$w_resfiles; + uint16 hm2$w_devtype; + uint16 hm2$w_rvn; + uint16 hm2$w_setcount; + uint16 hm2$w_volchar; + uint32 hm2$l_volowner; + uint32 hm2$l_reserved; + uint16 hm2$w_protect; + uint16 hm2$w_fileprot; + uint16 hm2$w_reserved; + uint16 hm2$w_checksum1; + uint32 hm2$q_credate[2]; + uint8 hm2$b_window; + uint8 hm2$b_lru_lim; + uint16 hm2$w_extend; + uint32 hm2$q_retainmin[2]; + uint32 hm2$q_retainmax[2]; + uint32 hm2$q_revdate[2]; + uint8 hm2$r_min_class[20]; + uint8 hm2$r_max_class[20]; + uint8 hm2$r_reserved[320]; + uint32 hm2$l_serialnum; + uint8 hm2$t_strucname[12]; + uint8 hm2$t_volname[12]; + uint8 hm2$t_ownername[12]; + uint8 hm2$t_format[12]; + uint16 hm2$w_reserved2; + uint16 hm2$w_checksum2; + } ODS2_HomeBlock; + +typedef struct _ODS2_FileHeader + { + uint8 fh2$b_idoffset; + uint8 fh2$b_mpoffset; + uint8 fh2$b_acoffset; + uint8 fh2$b_rsoffset; + uint16 fh2$w_seg_num; + uint16 fh2$w_structlev; + uint16 fh2$w_fid[3]; + uint16 fh2$w_ext_fid[3]; + uint16 fh2$w_recattr[16]; + uint32 fh2$l_filechar; + uint16 fh2$w_remaining[228]; + } ODS2_FileHeader; + +typedef union _ODS2_Retreval + { + struct + { + unsigned fm2$$_fill : 14; /* type specific data */ + unsigned fm2$v_format : 2; /* format type code */ + } fm2$r_word0_bits; + struct + { + unsigned fm2$v_exact : 1; /* exact placement specified */ + unsigned fm2$v_oncyl : 1; /* on cylinder allocation desired */ + unsigned fm2$$_fill : 10; + unsigned fm2$v_lbn : 1; /* use LBN of next map pointer */ + unsigned fm2$v_rvn : 1; /* place on specified RVN */ + unsigned fm2$v_format0 : 2; + } fm2$r_map_bits0; + struct + { + unsigned fm2$b_count1 : 8; /* low byte described below */ + unsigned fm2$v_highlbn1 : 6; /* high order LBN */ + unsigned fm2$v_format1 : 2; + unsigned fm2$w_lowlbn1 : 16; /* low order LBN */ + } fm2$r_map_bits1; + struct + { + struct + { + unsigned fm2$v_count2 : 14; /* count field */ + unsigned fm2$v_format2 : 2; + unsigned fm2$l_lowlbn2 : 16; /* low order LBN */ + } fm2$r_map2_long0; + uint16 fm2$l_highlbn2; /* high order LBN */ + } fm2$r_map_bits2; + struct + { + struct + { + unsigned fm2$v_highcount3 : 14; /* low order count field */ + unsigned fm2$v_format3 : 2; + unsigned fm2$w_lowcount3 : 16; /* high order count field */ + } fm2$r_map3_long0; + uint32 fm2$l_lbn3; + } fm2$r_map_bits3; + } ODS2_Retreval; + +typedef struct _ODS2_StorageControlBlock + { + uint8 scb$b_strucver; /* 1 */ + uint8 scb$b_struclev; /* 2 */ + uint16 scb$w_cluster; + uint32 scb$l_volsize; + uint32 scb$l_blksize; + uint32 scb$l_sectors; + uint32 scb$l_tracks; + uint32 scb$l_cylinder; + uint32 scb$l_status; + uint32 scb$l_status2; + uint16 scb$w_writecnt; + uint8 scb$t_volockname[12]; + uint32 scb$q_mounttime[2]; + uint16 scb$w_backrev; + uint32 scb$q_genernum[2]; + uint8 scb$b_reserved[446]; + uint16 scb$w_checksum; + } ODS2_SCB; +#pragma pack(pop) + +static uint16 +ODS2Checksum (void *Buffer, uint16 WordCount) + { + int i; + uint16 Sum = 0; + uint16 CheckSum = 0; + uint16 *Buf = (uint16 *)Buffer; + + for (i=0; idwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */ +saved_capac = uptr->capac; +uptr->capac = (t_addr)(temp_capac/(capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))); +if (sim_disk_rdsect (uptr, 1, (uint8 *)&Home, NULL, 1)) + goto Return_Cleanup; +CheckSum1 = ODS2Checksum (&Home, (uint16)((((char *)&Home.hm2$w_checksum1)-((char *)&Home.hm2$l_homelbn))/2)); +CheckSum2 = ODS2Checksum (&Home, (uint16)((((char *)&Home.hm2$w_checksum2)-((char *)&Home.hm2$l_homelbn))/2)); +if ((Home.hm2$l_homelbn == 0) || + (Home.hm2$l_alhomelbn == 0) || + (Home.hm2$l_altidxlbn == 0) || + ((Home.hm2$b_struclev != 2) && (Home.hm2$b_struclev != 5)) || + (Home.hm2$b_strucver == 0) || + (Home.hm2$w_cluster == 0) || + (Home.hm2$w_homevbn == 0) || + (Home.hm2$w_alhomevbn == 0) || + (Home.hm2$w_ibmapvbn == 0) || + (Home.hm2$l_ibmaplbn == 0) || + (Home.hm2$w_resfiles >= Home.hm2$l_maxfiles) || + (Home.hm2$w_ibmapsize == 0) || + (Home.hm2$w_resfiles < 5) || + (Home.hm2$w_checksum1 != CheckSum1) || + (Home.hm2$w_checksum2 != CheckSum2)) + goto Return_Cleanup; +if (sim_disk_rdsect (uptr, Home.hm2$l_ibmaplbn+Home.hm2$w_ibmapsize+1, (uint8 *)&Header, NULL, 1)) + goto Return_Cleanup; +CheckSum1 = ODS2Checksum (&Header, 255); +if (CheckSum1 != *(((uint16 *)&Header)+255)) /* Verify Checksum on BITMAP.SYS file header */ + goto Return_Cleanup; +Retr = (ODS2_Retreval *)(((uint16*)(&Header))+Header.fh2$b_mpoffset); +/* The BitMap File has a single extent, which may be preceeded by a placement descriptor */ +if (Retr->fm2$r_word0_bits.fm2$v_format == 0) + Retr = (ODS2_Retreval *)(((uint16 *)Retr)+1); /* skip placement descriptor */ +switch (Retr->fm2$r_word0_bits.fm2$v_format) + { + case 1: + ScbLbn = (Retr->fm2$r_map_bits1.fm2$v_highlbn1<<16)+Retr->fm2$r_map_bits1.fm2$w_lowlbn1; + break; + case 2: + ScbLbn = (Retr->fm2$r_map_bits2.fm2$l_highlbn2<<16)+Retr->fm2$r_map_bits2.fm2$r_map2_long0.fm2$l_lowlbn2; + break; + case 3: + ScbLbn = Retr->fm2$r_map_bits3.fm2$l_lbn3; + break; + } +Retr = (ODS2_Retreval *)(((uint16 *)Retr)+Retr->fm2$r_word0_bits.fm2$v_format+1); +if (sim_disk_rdsect (uptr, ScbLbn, (uint8 *)&Scb, NULL, 1)) + goto Return_Cleanup; +CheckSum1 = ODS2Checksum (&Scb, 255); +if (CheckSum1 != *(((uint16 *)&Scb)+255)) /* Verify Checksum on Storage Control Block */ + goto Return_Cleanup; +if ((Scb.scb$w_cluster != Home.hm2$w_cluster) || + (Scb.scb$b_strucver != Home.hm2$b_strucver) || + (Scb.scb$b_struclev != Home.hm2$b_struclev)) + goto Return_Cleanup; +if (!sim_quiet) { + sim_printf ("%s%d: '%s' Found containing ODS%d File system:\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename, Home.hm2$b_struclev); + sim_printf ("%s%d: Volume Name: %12.12s ", sim_dname (dptr), (int)(uptr-dptr->units), Home.hm2$t_volname); + sim_printf ("Format: %12.12s ", Home.hm2$t_format); + sim_printf ("SectorsInVolume: %d\n", Scb.scb$l_volsize); + } +ret_val = ((t_offset)Scb.scb$l_volsize) * 512; + +Return_Cleanup: +uptr->capac = saved_capac; +return ret_val; +} t_stat sim_disk_attach (UNIT *uptr, const char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay) @@ -850,7 +1074,7 @@ t_offset (*size_function)(FILE *file); t_stat (*storage_function)(FILE *file, uint32 *sector_size, uint32 *removable) = NULL; t_bool created = FALSE, copied = FALSE; t_bool auto_format = FALSE; -t_offset capac; +t_offset capac, filesystem_capac; if (uptr->flags & UNIT_DIS) /* disabled? */ return SCPE_UDIS; @@ -1252,22 +1476,42 @@ if (sim_switches & SWMASK ('K')) { uptr->dynflags |= UNIT_DISK_CHK; } +filesystem_capac = get_filesystem_size (uptr); capac = size_function (uptr->fileref); if (capac && (capac != (t_offset)-1)) { if (dontautosize) { + t_addr saved_capac = uptr->capac; + + if ((filesystem_capac != (t_offset)-1) && + (filesystem_capac > (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1)))) { + if (!sim_quiet) { + uptr->capac = (t_addr)(filesystem_capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))); + sim_printf ("%s%d: The file system on the disk %s is larger than simulated device (%s > ", sim_dname (dptr), (int)(uptr-dptr->units), cptr, sprint_capac (dptr, uptr)); + uptr->capac = saved_capac; + sim_printf ("%s)\n", sprint_capac (dptr, uptr)); + } + sim_disk_detach (uptr); + return SCPE_OPENERR; + } if ((capac < (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) && (DKUF_F_STD != DK_GET_FMT (uptr))) { if (!sim_quiet) { - sim_printf ("%s%d: non expandable disk %s is smaller than simulated device (", sim_dname (dptr), (int)(uptr-dptr->units), cptr); - sim_print_val ((t_addr)(capac/ctx->capac_factor), 10, T_ADDR_W, PV_LEFT); - sim_printf ("%s < ", (ctx->capac_factor == 2) ? "W" : ""); - sim_print_val (uptr->capac*((dptr->flags & DEV_SECTORS) ? 512 : 1), 10, T_ADDR_W, PV_LEFT); - sim_printf ("%s)\n", (ctx->capac_factor == 2) ? "W" : ""); + uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))); + sim_printf ("%s%d: non expandable disk %s is smaller than simulated device (%s < ", sim_dname (dptr), (int)(uptr-dptr->units), cptr, sprint_capac (dptr, uptr)); + uptr->capac = saved_capac; + sim_printf ("%s)\n", sprint_capac (dptr, uptr)); } + sim_disk_detach (uptr); + return SCPE_OPENERR; } } - else - if ((capac > (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) || (DKUF_F_STD != DK_GET_FMT (uptr))) + else { + if ((filesystem_capac != (t_offset)-1) && + (filesystem_capac > capac)) + capac = filesystem_capac; + if ((capac > (((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))) || + (DKUF_F_STD != DK_GET_FMT (uptr))) uptr->capac = (t_addr)(capac/(ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1))); + } } #if defined (SIM_ASYNCH_IO)