root/src/simh/sim_disk.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sim_disk_set_fmt
  2. sim_disk_show_fmt
  3. sim_disk_set_capac
  4. sim_disk_show_capac
  5. sim_disk_isavailable
  6. sim_disk_isavailable_a
  7. sim_disk_wrp
  8. sim_disk_size
  9. _sim_disk_rdsect
  10. sim_disk_rdsect
  11. sim_disk_rdsect_a
  12. _sim_disk_wrsect
  13. sim_disk_wrsect
  14. sim_disk_wrsect_a
  15. sim_disk_unload
  16. _sim_disk_io_flush
  17. _err_return
  18. ODS2Checksum
  19. get_filesystem_size
  20. sim_disk_attach
  21. sim_disk_detach
  22. sim_disk_attach_help
  23. sim_disk_reset
  24. sim_disk_perror
  25. sim_disk_clearerr
  26. sim_disk_data_trace

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

/* [previous][next][first][last][top][bottom][index][help] */