--- trunk/src/diskimage.c 2007/10/08 16:18:00 4 +++ trunk/src/diskimage.c 2007/10/08 16:18:38 12 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: diskimage.c,v 1.84 2005/04/17 00:15:24 debug Exp $ + * $Id: diskimage.c,v 1.95 2005/08/10 22:25:50 debug Exp $ * * Disk image support. * @@ -36,10 +36,8 @@ * that return feof (which results in a filemark). This is probably * trivial to fix, but I don't feel like it right now. * - * TODO: Non-SCSI disk images? - * - * TODO: diskimage_remove() ? - * Actually test diskimage_access() to see that it works. + * TODO: diskimage_remove()? This would be useful for floppies in PC-style + * machines, where disks may need to be swapped during boot etc. */ #include @@ -58,6 +56,7 @@ extern int quiet_mode; extern int single_step; +static char *diskimage_types[] = DISKIMAGE_TYPES; static struct scsi_transfer *first_free_scsi_transfer_alloc = NULL; @@ -209,14 +208,15 @@ /* * diskimage_exist(): * - * Returns 1 if the specified SCSI id exists, 0 otherwise. + * Returns 1 if the specified disk id (for a specific type) exists, 0 + * otherwise. */ -int diskimage_exist(struct machine *machine, int scsi_id) +int diskimage_exist(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { - if ( /* d->type == DISKIMAGE_SCSI && */ d->id == scsi_id) + if (d->type == type && d->id == id) return 1; d = d->next; } @@ -256,21 +256,24 @@ d->total_size = size; d->ncyls = d->total_size / 1048576; + + /* TODO: There is a mismatch between d->ncyls and d->cylinders, + SCSI-based stuff usually doesn't care. TODO: Fix this. */ } /* * diskimage_getsize(): * - * Returns -1 if the specified SCSI id does not exists, otherwise + * Returns -1 if the specified disk id/type does not exists, otherwise * the size of the disk image is returned. */ -int64_t diskimage_getsize(struct machine *machine, int scsi_id) +int64_t diskimage_getsize(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { - if ( /* d->type == DISKIMAGE_SCSI && */ d->id == scsi_id) + if (d->type == type && d->id == id) return d->total_size; d = d->next; } @@ -279,6 +282,31 @@ /* + * diskimage_getchs(): + * + * Returns the current CHS values of a disk image. + */ +void diskimage_getchs(struct machine *machine, int id, int type, + int *c, int *h, int *s) +{ + struct diskimage *d = machine->first_diskimage; + + while (d != NULL) { + if (d->type == type && d->id == id) { + *c = d->cylinders; + *h = d->heads; + *s = d->sectors_per_track; + return; + } + d = d->next; + } + fatal("diskimage_getchs(): disk id %i (type %i) not found?\n", + id, diskimage_types[type]); + exit(1); +} + + +/* * diskimage__return_default_status_and_message(): * * Set the status and msg_in parts of a scsi_transfer struct @@ -381,7 +409,7 @@ static int diskimage__internal_access(struct diskimage *d, int writeflag, off_t offset, unsigned char *buf, size_t len) { - size_t lendone; + ssize_t lendone; int res; if (buf == NULL) { @@ -447,7 +475,7 @@ * 1 if otherwise ok, * 0 on error. */ -int diskimage_scsicommand(struct cpu *cpu, int scsi_id, +int diskimage_scsicommand(struct cpu *cpu, int id, int type, struct scsi_transfer *xferp) { int retlen, i; @@ -464,13 +492,13 @@ d = machine->first_diskimage; while (d != NULL) { - if ( /* d->type == DISKIMAGE_SCSI && */ d->id == scsi_id) + if (d->type == type && d->id == id) break; d = d->next; } if (d == NULL) { - fprintf(stderr, "[ diskimage_scsicommand(): SCSI disk" - " with id %i not connected? ]\n", scsi_id); + fprintf(stderr, "[ diskimage_scsicommand(): %s " + " id %i not connected? ]\n", diskimage_types[type], id); } if (xferp->cmd == NULL) { @@ -485,11 +513,11 @@ } debug("[ diskimage_scsicommand(id=%i) cmd=0x%02x: ", - scsi_id, xferp->cmd[0]); + id, xferp->cmd[0]); #if 0 fatal("[ diskimage_scsicommand(id=%i) cmd=0x%02x len=%i:", - scsi_id, xferp->cmd[0], xferp->cmd_len); + id, xferp->cmd[0], xferp->cmd_len); for (i=0; icmd_len; i++) fatal(" %02x", xferp->cmd[i]); fatal("\n"); @@ -504,7 +532,7 @@ f = fopen("scsi_log.txt", "w"); if (f != NULL) { int i; - fprintf(f, "id=%i cmd =", scsi_id); + fprintf(f, "id=%i cmd =", id); for (i=0; icmd_len; i++) fprintf(f, " %02x", xferp->cmd[i]); fprintf(f, "\n"); @@ -694,7 +722,7 @@ pagecode = xferp->cmd[2] & 0x3f; - debug("[ MODE SENSE id %i, pagecode=%i ]\n", scsi_id, pagecode); + debug("[ MODE SENSE id %i, pagecode=%i ]\n", id, pagecode); /* 4 bytes of header for 6-byte command, 8 bytes of header for 10-byte command. */ @@ -735,7 +763,7 @@ /* 10,11 = sectors per track */ xferp->data_in[12 + 10] = 0; - xferp->data_in[12 + 11] = 1; /* TODO */ + xferp->data_in[12 + 11] = d->sectors_per_track; /* 12,13 = physical sector size */ xferp->data_in[12 + 12] = @@ -748,7 +776,7 @@ xferp->data_in[12 + 2] = (d->ncyls >> 16) & 255; xferp->data_in[12 + 3] = (d->ncyls >> 8) & 255; xferp->data_in[12 + 4] = d->ncyls & 255; - xferp->data_in[12 + 5] = 15; /* nr of heads */ + xferp->data_in[12 + 5] = d->heads; xferp->data_in[12 + 20] = (d->rpms >> 8) & 255; xferp->data_in[12 + 21] = d->rpms & 255; @@ -761,8 +789,8 @@ xferp->data_in[12 + 2] = ((5000) >> 8) & 255; xferp->data_in[12 + 3] = (5000) & 255; - xferp->data_in[12 + 4] = 2; /* nr of heads */ - xferp->data_in[12 + 5] = 18; /* sectors per track */ + xferp->data_in[12 + 4] = d->heads; + xferp->data_in[12 + 5] = d->sectors_per_track; /* 6,7 = data bytes per sector */ xferp->data_in[12 + 6] = (d->logical_block_size >> 8) @@ -819,7 +847,7 @@ ofs = d->tape_offset; fatal("[ READ tape, id=%i file=%i, cmd[1]=%02x size=%i" - ", ofs=%lli ]\n", scsi_id, d->tape_filenr, + ", ofs=%lli ]\n", id, d->tape_filenr, xferp->cmd[1], (int)size, (long long)ofs); } else { if (xferp->cmd[0] == SCSICMD_READ) { @@ -882,7 +910,7 @@ * be set to NO SENSE".. */ if (d->is_a_tape && d->f != NULL && feof(d->f)) { - debug(" feof id=%i\n", scsi_id); + debug(" feof id=%i\n", id); xferp->status[0] = 0x02; /* CHECK CONDITION */ d->filemark = 1; @@ -891,7 +919,7 @@ xferp->data_in, size); if (d->is_a_tape && d->f != NULL) - d->tape_offset = ftell(d->f); + d->tape_offset = ftello(d->f); /* TODO: other errors? */ break; @@ -978,7 +1006,7 @@ if (xferp->cmd_len != 6) debug(" (weird len=%i)", xferp->cmd_len); - for (i=0; icmd_len ; i++) + for (i=0; icmd_len; i++) debug(" %02x", xferp->cmd[i]); /* TODO: actualy care about cmd[] */ @@ -1275,11 +1303,12 @@ &xferp->data_in, retlen, 1); diskimage__return_default_status_and_message(xferp); + break; default: fatal("[ UNIMPLEMENTED SCSI command 0x%02x, disk id=%i ]\n", - xferp->cmd[0], scsi_id); + xferp->cmd[0], id); exit(1); } debug(" ]\n"); @@ -1295,25 +1324,21 @@ * * Returns 1 if the access completed successfully, 0 otherwise. */ -int diskimage_access(struct machine *machine, int scsi_id, int writeflag, +int diskimage_access(struct machine *machine, int id, int type, int writeflag, off_t offset, unsigned char *buf, size_t len) { struct diskimage *d = machine->first_diskimage; - /* - * TODO: How about mixing SCSI, IDE, and FLOPPY in one - * emulated machine? - */ - while (d != NULL) { - if ( /* d->type == DISKIMAGE_SCSI && */ d->id == scsi_id) + if (d->type == type && d->id == id) break; d = d->next; } if (d == NULL) { fatal("[ diskimage_access(): ERROR: trying to access a " - "non-existant SCSI disk image (%i)\n", scsi_id); + "non-existant %s disk image (id %i)\n", + diskimage_types[type], id); return 0; } @@ -1328,10 +1353,12 @@ * The filename may be prefixed with one or more modifiers, followed * by a colon. * - * b specifies that this is the boot device - * c CD-ROM (instead of normal SCSI DISK) + * b specifies that this is a bootable device + * c CD-ROM (instead of a normal DISK) * d DISK (this is the default) * f FLOPPY (instead of SCSI) + * gH;S; set geometry (H=heads, S=sectors per track, cylinders are + * automatically calculated). (This is ignored for floppies.) * i IDE (instead of SCSI) * r read-only (don't allow changes to the file) * s SCSI (this is the default) @@ -1344,17 +1371,11 @@ int diskimage_add(struct machine *machine, char *fname) { struct diskimage *d, *d2; - int id = 0; + int id = 0, override_heads=0, override_spt=0; + int64_t bytespercyl; char *cp; - int prefix_b = 0; - int prefix_c = 0; - int prefix_d = 0; - int prefix_f = 0; - int prefix_i = 0; - int prefix_r = 0; - int prefix_s = 0; - int prefix_t = 0; - int prefix_id = -1; + int prefix_b=0, prefix_c=0, prefix_d=0, prefix_f=0, prefix_g=0; + int prefix_i=0, prefix_r=0, prefix_s=0, prefix_t=0, prefix_id = -1; if (fname == NULL) { fprintf(stderr, "diskimage_add(): NULL ptr\n"); @@ -1389,6 +1410,27 @@ case 'f': prefix_f = 1; break; + case 'g': + prefix_g = 1; + override_heads = atoi(fname); + while (*fname != '\0' && *fname != ';') + fname ++; + if (*fname == ';') + fname ++; + override_spt = atoi(fname); + while (*fname != '\0' && *fname != ';' && + *fname != ':') + fname ++; + if (*fname == ';') + fname ++; + if (override_heads < 1 || + override_spt < 1) { + fatal("Bad geometry: heads=%i " + "spt=%i\n", override_heads, + override_spt); + exit(1); + } + break; case 'i': prefix_i = 1; break; @@ -1411,39 +1453,6 @@ } } - /* Calculate which ID to use: */ - if (prefix_id == -1) { - int free = 0, collision = 1; - - while (collision) { - collision = 0; - d = machine->first_diskimage; - while (d != NULL) { - if (d->id == free) { - collision = 1; - break; - } - d = d->next; - } - if (!collision) - id = free; - else - free ++; - } - } else { - id = prefix_id; - - d = machine->first_diskimage; - while (d != NULL) { - if (d->id == id) { - fprintf(stderr, "disk image SCSI id %i " - "already in use\n", id); - exit(1); - } - d = d->next; - } - } - /* Allocate a new diskimage struct: */ d = malloc(sizeof(struct diskimage)); if (d == NULL) { @@ -1462,11 +1471,11 @@ } d->type = DISKIMAGE_SCSI; - d->id = id; /* Special cases: some machines usually have FLOPPY/IDE, not SCSI: */ if (machine->arch == ARCH_X86 || machine->machine_type == MACHINE_COBALT || + machine->machine_type == MACHINE_EVBMIPS || machine->machine_type == MACHINE_HPCMIPS || machine->machine_type == MACHINE_PS2) d->type = DISKIMAGE_IDE; @@ -1532,9 +1541,36 @@ diskimage_recalc_size(d); - if (d->total_size == 1474560 && !prefix_i && !prefix_s) + if ((d->total_size == 720*1024 || d->total_size == 1474560 + || d->total_size == 2949120 || d->total_size == 1228800) + && !prefix_i && !prefix_s) d->type = DISKIMAGE_FLOPPY; + switch (d->type) { + case DISKIMAGE_FLOPPY: + if (d->total_size < 737280) { + fatal("\nTODO: small (non-80-cylinder) floppies?\n\n"); + exit(1); + } + d->cylinders = 80; + d->heads = 2; + d->sectors_per_track = d->total_size / (d->cylinders * + d->heads * 512); + break; + default:/* Non-floppies: */ + d->heads = 16; + d->sectors_per_track = 63; + if (prefix_g) { + d->chs_override = 1; + d->heads = override_heads; + d->sectors_per_track = override_spt; + } + bytespercyl = d->heads * d->sectors_per_track * 512; + d->cylinders = d->total_size / bytespercyl; + if (d->cylinders * bytespercyl < d->total_size) + d->cylinders ++; + } + d->rpms = 3600; if (prefix_b) @@ -1551,6 +1587,50 @@ exit(1); } + /* Calculate which ID to use: */ + if (prefix_id == -1) { + int free = 0, collision = 1; + + while (collision) { + collision = 0; + d2 = machine->first_diskimage; + while (d2 != NULL) { + /* (don't compare against ourselves :) */ + if (d2 == d) { + d2 = d2->next; + continue; + } + if (d2->id == free && d2->type == d->type) { + collision = 1; + break; + } + d2 = d2->next; + } + if (!collision) + id = free; + else + free ++; + } + } else { + id = prefix_id; + d2 = machine->first_diskimage; + while (d2 != NULL) { + /* (don't compare against ourselves :) */ + if (d2 == d) { + d2 = d2->next; + continue; + } + if (d2->id == id && d2->type == d->type) { + fprintf(stderr, "disk image id %i " + "already in use\n", id); + exit(1); + } + d2 = d2->next; + } + } + + d->id = id; + return id; } @@ -1558,23 +1638,32 @@ /* * diskimage_bootdev(): * - * Returns the disk id (0..7) of the device which we're booting from. + * Returns the disk id of the device which we're booting from. If typep is + * non-NULL, the type is returned as well. * * If no disk was used as boot device, then -1 is returned. (In practice, * this is used to fake network (tftp) boot.) */ -int diskimage_bootdev(struct machine *machine) +int diskimage_bootdev(struct machine *machine, int *typep) { - struct diskimage *d = machine->first_diskimage; + struct diskimage *d; + + d = machine->first_diskimage; while (d != NULL) { - if (d->is_boot_device) + if (d->is_boot_device) { + if (typep != NULL) + *typep = d->type; return d->id; + } d = d->next; } d = machine->first_diskimage; - if (d != NULL) + if (d != NULL) { + if (typep != NULL) + *typep = d->type; return d->id; + } return -1; } @@ -1583,14 +1672,14 @@ /* * diskimage_is_a_cdrom(): * - * Returns 1 if a disk image is a SCSI CDROM, 0 otherwise. + * Returns 1 if a disk image is a CDROM, 0 otherwise. */ -int diskimage_is_a_cdrom(struct machine *machine, int scsi_id) +int diskimage_is_a_cdrom(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { - if (d->type == DISKIMAGE_SCSI && d->id == scsi_id) + if (d->type == type && d->id == id) return d->is_a_cdrom; d = d->next; } @@ -1601,16 +1690,17 @@ /* * diskimage_is_a_tape(): * - * Returns 1 if a disk image is a SCSI tape, 0 otherwise. + * Returns 1 if a disk image is a tape, 0 otherwise. + * * (Used in src/machine.c, to select 'rz' vs 'tz' for DECstation * boot strings.) */ -int diskimage_is_a_tape(struct machine *machine, int scsi_id) +int diskimage_is_a_tape(struct machine *machine, int id, int type) { struct diskimage *d = machine->first_diskimage; while (d != NULL) { - if (d->type == DISKIMAGE_SCSI && d->id == scsi_id) + if (d->type == type && d->id == id) return d->is_a_tape; d = d->next; } @@ -1656,9 +1746,16 @@ else debug("%lli MB", (long long) (d->total_size / 1048576)); - debug(" (%lli sectors)%s\n", - (long long) (d->total_size / 512), - d->is_boot_device? " (BOOT)" : ""); + if (d->type == DISKIMAGE_FLOPPY || d->chs_override) + debug(" (CHS=%i,%i,%i)", d->cylinders, d->heads, + d->sectors_per_track); + else + debug(" (%lli sectors)", (long long) + (d->total_size / 512)); + + if (d->is_boot_device) + debug(" (BOOT)"); + debug("\n"); debug_indentation(-iadd);