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: X11
   6  * scspell-id: b2c7f6c3-f62a-11ec-9f60-80ee73e9b8e7
   7  *
   8  * ---------------------------------------------------------------------------
   9  *
  10  * Copyright (c) 2011 Mark Pizzolato
  11  * Copyright (c) 2021-2022 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 #ifdef _WIN32
  74 # include <windows.h>
  75 #endif /* ifdef _WIN32 */
  76 
  77 #ifdef TESTING
  78 # undef FREE
  79 # define FREE(p) free(p)
  80 #endif /* ifdef TESTING */
  81 
  82 #ifndef DECLITEND
  83 # error Unknown platform endianness
  84 #endif /* ifndef DECLITEND */
  85 
  86 struct disk_context {
  87     DEVICE              *dptr;              /* Device for unit (access to debug flags) */
  88     uint32              dbit;               /* debugging bit */
  89     uint32              sector_size;        /* Disk Sector Size (of the pseudo disk) */
  90     uint32              capac_factor;       /* Units of Capacity (2 = word, 1 = byte) */
  91     uint32              xfer_element_size;  /* Disk Bus Transfer size (1 - byte, 2 - word, 4 - longword) */
  92     uint32              storage_sector_size;/* Sector size of the containing storage */
  93     uint32              removable;          /* Removable device flag */
  94     uint32              auto_format;        /* Format determined dynamically */
  95     };
  96 
  97 #define disk_ctx up8                        /* Field in Unit structure which points to the disk_context */
  98 
  99 /* Forward declarations */
 100 
 101 struct sim_disk_fmt {
 102     const char          *name;                          /* name */
 103     int32               uflags;                         /* unit flags */
 104     int32               fmtval;                         /* Format type value */
 105     t_stat              (*impl_fnc)(void);              /* Implemented Test Function */
 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 /* Set disk format */
 113 
 114 t_stat sim_disk_set_fmt (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* Show disk format */
 135 
 136 t_stat sim_disk_show_fmt (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* Set disk capacity */
 151 
 152 t_stat sim_disk_set_capac (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* Show disk capacity */
 170 
 171 t_stat sim_disk_show_capac (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 /* Test for available */
 191 
 192 t_bool sim_disk_isavailable (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194 if (!(uptr->flags & UNIT_ATT))                          /* attached? */
 195     return FALSE;
 196 switch (DK_GET_FMT (uptr)) {                            /* case on format */
 197     case DKUF_F_STD:                                    /* SIMH format */
 198         return TRUE;
 199         /*NOTREACHED*/
 200         break;
 201     default:
 202         return FALSE;
 203     }
 204 }
 205 
 206 t_bool sim_disk_isavailable_a (UNIT *uptr, DISK_PCALLBACK callback)
     /* [previous][next][first][last][top][bottom][index][help] */
 207 {
 208 t_bool r = FALSE;
 209     r = sim_disk_isavailable (uptr);
 210 return r;
 211 }
 212 
 213 /* Test for write protect */
 214 
 215 t_bool sim_disk_wrp (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217 return (uptr->flags & DKUF_WRP)? TRUE: FALSE;
 218 }
 219 
 220 /* Get Disk size */
 221 
 222 t_offset sim_disk_size (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224 switch (DK_GET_FMT (uptr)) {                            /* case on format */
 225     case DKUF_F_STD:                                    /* SIMH format */
 226         return sim_fsize_ex (uptr->fileref);
 227         /*NOTREACHED*/
 228         break;
 229     default:
 230         return (t_offset)-1;
 231     }
 232 }
 233 
 234 /* Read Sectors */
 235 
 236 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] */
 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);          /* set pos */
 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)                 /* fill */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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) &&                                     /* Single sector reads */
 270     (lba >= (uptr->capac*ctx->capac_factor)/(ctx->sector_size/((ctx->dptr->flags & DEV_SECTORS) ? 512 : 1)))) {/* beyond the end of the disk */
 271     memset (buf, '\0', ctx->sector_size);               /* are bad block management efforts - zero buffer */
 272     if (sectsread)
 273         *sectsread = 1;
 274     return SCPE_OK;                                     /* return success */
 275     }
 276 
 277 if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) ||   /* Sector Aligned & whole sector transfers */
 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)) {                        /* case on format */
 281         case DKUF_F_STD:                                /* SIMH format */
 282             return _sim_disk_rdsect (uptr, lba, buf, sectsread, sects);
 283             /*NOTREACHED*/
 284             break;
 285         default:
 286             return SCPE_NOFNC;
 287         }
 288 //    if (sectsread)
 289 //        *sectsread = sread;
 290 //    if (r != SCPE_OK)
 291 //        return r;
 292 //    sim_buf_swap_data (buf, ctx->xfer_element_size, (sread * ctx->sector_size) / ctx->xfer_element_size);
 293 //    return r;
 294     }
 295 else { /* Unaligned and/or partial sector transfers */
 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; /* sim sectors in a storage sector */
 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)) {                        /* case on format */
 307         case DKUF_F_STD:                                /* SIMH format */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329 t_stat r = SCPE_OK;
 330     r = sim_disk_rdsect (uptr, lba, buf, sectsread, sects);
 331 return r;
 332 }
 333 
 334 /* Write Sectors */
 335 
 336 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] */
 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);          /* set pos */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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; /* capacity units (word: 2, byte: 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))) ||   /* Sector Aligned & whole sector transfers */
 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)) {                            /* case on format */
 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)) {                            /* case on format */
 416         default:
 417             r = SCPE_NOFNC;
 418             break;
 419         }
 420     }
 421 else { /* Unaligned and/or partial sector transfers */
 422     t_lba sspsts = ctx->storage_sector_size/ctx->sector_size; /* sim sectors in a storage sector */
 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     /* Partial Sector writes require a read-modify-write sequence for the partial sectors */
 433     if ((lba & (sspsts - 1)) ||
 434         (sects < sspsts))
 435         switch (DK_GET_FMT (uptr)) {                            /* case on format */
 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)) {                            /* case on format */
 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)) {                            /* case on format */
 450         default:
 451             r = SCPE_NOFNC;
 452             break;
 453         }
 454     if ((r == SCPE_OK) && sectswritten) { //-V560
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 472 {
 473 switch (DK_GET_FMT (uptr)) {                            /* case on format */
 474     case DKUF_F_STD:                                    /* Simh */
 475         return sim_disk_detach (uptr);
 476     default:
 477         return SCPE_NOFNC;
 478     }
 479 }
 480 
 481 static void _sim_disk_io_flush (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 482 {
 483 uint32 f = DK_GET_FMT (uptr);
 484 
 485 switch (f) {                                            /* case on format */
 486     case DKUF_F_STD:                                    /* Simh */
 487         fflush (uptr->fileref);
 488         break;
 489         }
 490 }
 491 
 492 static t_stat _err_return (UNIT *uptr, t_stat stat)
     /* [previous][next][first][last][top][bottom][index][help] */
 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;       /* type specific data               */
 571             unsigned fm2_v_format : 2;        /* format type code                 */
 572             } fm2_r_word0_bits;
 573         struct
 574             {
 575             unsigned fm2_v_exact    : 1;      /* exact placement specified        */
 576             unsigned fm2_v_oncyl    : 1;      /* on cylinder allocation desired   */
 577             unsigned fm2___fill     : 10;
 578             unsigned fm2_v_lbn      : 1;      /* use LBN of next map pointer      */
 579             unsigned fm2_v_rvn      : 1;      /* place on specified RVN           */
 580             unsigned fm2_v_format0  : 2;
 581             } fm2_r_map_bits0;
 582         struct
 583             {
 584             unsigned fm2_b_count1   : 8;      /* low byte described below         */
 585             unsigned fm2_v_highlbn1 : 6;      /* high order LBN                   */
 586             unsigned fm2_v_format1  : 2;
 587             unsigned fm2_w_lowlbn1  : 16;     /* low order LBN                    */
 588             } fm2_r_map_bits1;
 589         struct
 590             {
 591             struct
 592                 {
 593                 unsigned fm2_v_count2   : 14; /* count field                      */
 594                 unsigned fm2_v_format2  : 2;
 595                 unsigned fm2_l_lowlbn2  : 16; /* low order LBN                    */
 596                 } fm2_r_map2_long0;
 597             uint16 fm2_l_highlbn2;            /* high order LBN                   */
 598             } fm2_r_map_bits2;
 599         struct
 600             {
 601             struct
 602                 {
 603                 unsigned fm2_v_highcount3 : 14; /* low order count field          */
 604                 unsigned fm2_v_format3  : 2;
 605                 unsigned fm2_w_lowcount3 : 16;  /* high order count field         */
 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;   /* 1 */
 614     uint8  scb_b_struclev;   /* 2 */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 650 {
 651 DEVICE *dptr;
 652 t_addr saved_capac;
 653 t_offset temp_capac = 512 * (t_offset)0xFFFFFFFFu;  /* Make sure we can access the largest sector */
 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; /* save capacity units (word: 2, byte: 1) */
 666 saved_capac = uptr->capac;
 667 /* cppcheck-suppress signConversion */
 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 /* cppcheck-suppress comparePointers */
 672 CheckSum1 = ODS2Checksum (&Home, (uint16)((((char *)&Home.hm2_w_checksum1)-((char *)&Home.hm2_l_homelbn))/2));
 673 /* cppcheck-suppress comparePointers */
 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)) //-V1032 /* Verify Checksum on BITMAP.SYS file header */
 696     goto Return_Cleanup;
 697 Retr = (ODS2_Retreval *)(((uint16*)(&Header))+Header.fh2_b_mpoffset);
 698 /* The BitMap File has a single extent, which may be preceeded by a placement descriptor */
 699 if (Retr->fm2_r_word0_bits.fm2_v_format == 0)
 700     Retr = (ODS2_Retreval *)(((uint16 *)Retr)+1); //-V1032 /* skip placement descriptor */
 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)) //-V1032 /* Verify Checksum on Storage Control Block */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)                             /* disabled? */
 750     return SCPE_UDIS;
 751 if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
 752     return SCPE_NOATT;
 753 if ((dptr = find_dev_from_unit (uptr)) == NULL)
 754     return SCPE_NOATT;
 755 if (sim_switches & SWMASK ('F')) {                      /* format spec? */
 756     char gbuf[CBUFSIZE];
 757     cptr = get_glyph (cptr, gbuf, 0);                   /* get spec */
 758     if (*cptr == 0)                                     /* must be more */
 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'));      /* Record Format specifier already processed */
 763     auto_format = TRUE;
 764     }
 765 open_function = sim_fopen;
 766 size_function = sim_fsize_ex;
 767 uptr->filename = (char *) calloc (CBUFSIZE, sizeof (char));/* alloc name buf */
 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   /*NOTREACHED*/ /* unreachable */
 777 # endif /* ifdef SIGUSR2 */
 778 #endif /* if defined(USE_BACKTRACE) */
 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 /* ifndef __INTEL_COMPILER */
 790 #  endif /* if __GNUC__ > 7 */
 791 # endif /* ifndef __clang_version__ */
 792 #endif /* ifdef __GNUC__ */
 793 strncpy (uptr->filename, cptr, CBUFSIZE);               /* save name */
 794 #ifdef __GNUC__
 795 # ifndef __clang_version__
 796 #  if __GNUC__ > 7
 797 #   ifndef __INTEL_COMPILER
 798 #    pragma GCC diagnostic pop
 799 #   endif /* ifndef __INTEL_COMPILER */
 800 #  endif /* if __GNUC__ > 7 */
 801 # endif /* ifndef __clang_version__ */
 802 #endif /* ifdef __GNUC__ */
 803 ctx->sector_size = (uint32)sector_size;                 /* save sector_size */
 804 ctx->capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* save capacity units (word: 2, byte: 1) */
 805 ctx->xfer_element_size = (uint32)xfer_element_size;     /* save xfer_element_size */
 806 ctx->dptr = dptr;                                       /* save DEVICE pointer */
 807 ctx->dbit = dbit;                                       /* save debug bit */
 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;                         /* save that we auto selected format */
 810 ctx->storage_sector_size = (uint32)sector_size;         /* Default */
 811 if ((sim_switches & SWMASK ('R')) ||                    /* read only? */
 812     ((uptr->flags & UNIT_RO) != 0)) {
 813     if (((uptr->flags & UNIT_ROABLE) == 0) &&           /* allowed? */
 814         ((uptr->flags & UNIT_RO) == 0))
 815         return _err_return (uptr, SCPE_NORO);           /* no, error */
 816     uptr->fileref = open_function (cptr, "rb");         /* open rd only */
 817     if (uptr->fileref == NULL)                          /* open fail? */
 818         return _err_return (uptr, SCPE_OPENERR);        /* yes, error */
 819     uptr->flags = uptr->flags | UNIT_RO;                /* set rd only */
 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 {                                                  /* normal */
 825     uptr->fileref = open_function (cptr, "rb+");        /* open r/w */
 826     if (uptr->fileref == NULL) {                        /* open fail? */
 827         if ((errno == EROFS) || (errno == EACCES)) {    /* read only? */
 828             if ((uptr->flags & UNIT_ROABLE) == 0)       /* allowed? */
 829                 return _err_return (uptr, SCPE_NORO);   /* no error */
 830             uptr->fileref = open_function (cptr, "rb"); /* open rd only */
 831             if (uptr->fileref == NULL)                  /* open fail? */
 832                 return _err_return (uptr, SCPE_OPENERR);/* yes, error */
 833             uptr->flags = uptr->flags | UNIT_RO;        /* set rd only */
 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 {                                          /* doesn't exist */
 838             if (sim_switches & SWMASK ('E'))            /* must exist? */
 839                 return _err_return (uptr, SCPE_OPENERR); /* yes, error */
 840             if (create_function) //-V547
 841                 uptr->fileref = create_function (cptr, ((t_offset)uptr->capac)*ctx->capac_factor*((dptr->flags & DEV_SECTORS) ? 512 : 1));/* create new file */
 842             else
 843                 uptr->fileref = open_function (cptr, "wb+");/* open new file */
 844             if (uptr->fileref == NULL)                  /* open fail? */
 845                 return _err_return (uptr, SCPE_OPENERR);/* yes, error */
 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         }                                               /* end if null */
 851     }                                                   /* end else */
 852 uptr->flags = uptr->flags | UNIT_ATT;
 853 uptr->pos = 0;
 854 
 855 /* Get Device attributes if they are available */
 856 if (storage_function) //-V547
 857     storage_function (uptr->fileref, &ctx->storage_sector_size, &ctx->removable);
 858 
 859 if ((created) && (!copied)) { //-V560
 860     t_stat r = SCPE_OK;
 861     uint8 *secbuf = (uint8 *)calloc (1, ctx->sector_size);       /* alloc temp sector buf */
 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); /* Write Last Sector */
 866     if (r == SCPE_OK)
 867         r = sim_disk_wrsect (uptr, (t_lba)(0), secbuf, NULL, 1); /* Write First Sector */
 868     FREE (secbuf);
 869     if (r != SCPE_OK) {
 870         sim_disk_detach (uptr);                         /* report error now */
 871         remove (cptr);                                  /* remove the create file */
 872         return SCPE_OPENERR;
 873         }
 874     if (sim_switches & SWMASK ('I')) {                  /* Initialize To Sector Address */
 875         uint8 *init_buf = (uint8*) malloc (1024*1024);
 876         t_lba lba, sect;
 877         uint32 capac_factor = ((dptr->dwidth / dptr->aincr) == 16) ? 2 : 1; /* capacity units (word: 2, byte: 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);                         /* report error now */
 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);                         /* report error now */
 900                 remove (cptr);                                  /* remove the create file */
 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; /* capacity units (word: 2, byte: 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);                         /* report error now */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
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 //sim_debug (ctx->dbit, ctx->dptr, "sim_disk_detach(unit=%lu,filename='%s')\n", (unsigned long)(uptr-ctx->dptr->units), uptr->filename);
1019 
1020 switch (DK_GET_FMT (uptr)) {                            /* case on format */
1021     case DKUF_F_STD:                                    /* Simh */
1022         close_function = fclose;
1023         break;
1024     default:
1025         return SCPE_IERR;
1026         }
1027 if (!(uptr->flags & UNIT_ATTABLE))                      /* attachable? */
1028     return SCPE_NOATT;
1029 if (!(uptr->flags & UNIT_ATT))                          /* attached? */
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);                              /* flush buffered data */
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);           /* restore file format */
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)
     /* [previous][next][first][last][top][bottom][index][help] */
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)
     /* [previous][next][first][last][top][bottom][index][help] */
1093 {
1094 struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
1095 
1096 if (!(uptr->flags & UNIT_ATT))                          /* attached? */
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)
     /* [previous][next][first][last][top][bottom][index][help] */
1106 {
1107 int saved_errno = errno;
1108 
1109 if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
1110     return SCPE_NOATT;
1111 switch (DK_GET_FMT (uptr)) {                            /* case on format */
1112     case DKUF_F_STD:                                    /* SIMH format */
1113         perror (msg);
1114         sim_printf ("%s %s: %s\n", sim_uname(uptr), msg, strerror(saved_errno));
1115     /*FALLTHRU*/
1116     default:
1117         ;
1118     }
1119 return SCPE_OK;
1120 }
1121 
1122 t_stat sim_disk_clearerr (UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
1123 {
1124 if (!(uptr->flags & UNIT_ATTABLE))                      /* not attachable? */
1125     return SCPE_NOATT;
1126 switch (DK_GET_FMT (uptr)) {                            /* case on format */
1127     case DKUF_F_STD:                                    /* SIMH format */
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)
     /* [previous][next][first][last][top][bottom][index][help] */
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 }

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