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

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