diff options
author | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-12-22 16:34:12 +0000 |
---|---|---|
committer | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-12-22 16:34:12 +0000 |
commit | 42550fde7e16ac040fbd391bb2c65c3f5fa08d60 (patch) | |
tree | 7e592c6013287a3e70ec65296b35613b212583b0 | |
parent | 62ee021121dea0b08b7e2f7c741cb417fc392bb2 (diff) |
SCSI emulation improvements, by Chuck Brazie.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2265 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | hw/pc.c | 26 | ||||
-rw-r--r-- | qemu-doc.texi | 8 | ||||
-rw-r--r-- | vl.c | 347 | ||||
-rw-r--r-- | vl.h | 21 |
4 files changed, 343 insertions, 59 deletions
@@ -688,23 +688,21 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device, if (i440fx_state) { i440fx_init_memory_mappings(i440fx_state); } -#if 0 - /* ??? Need to figure out some way for the user to - specify SCSI devices. */ if (pci_enabled) { void *scsi; - BlockDriverState *bdrv; - - scsi = lsi_scsi_init(pci_bus, -1); - bdrv = bdrv_new("scsidisk"); - bdrv_open(bdrv, "scsi_disk.img", 0); - lsi_scsi_attach(scsi, bdrv, -1); - bdrv = bdrv_new("scsicd"); - bdrv_open(bdrv, "scsi_cd.iso", 0); - bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); - lsi_scsi_attach(scsi, bdrv, -1); + + if (scsi_hba_lsi > 0) { + if (!(scsi = lsi_scsi_init(pci_bus, -1))) { + exit(1); + } + for(i = 0; i < MAX_SCSI_DISKS; i++) { + if (scsi_disks_info[i].adapter == SCSI_LSI_53C895A && + scsi_disks_info[i].device_type != SCSI_NONE) { + lsi_scsi_attach(scsi, bs_scsi_table[i], scsi_disks_info[i].id); + } + } + } } -#endif } static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, diff --git a/qemu-doc.texi b/qemu-doc.texi index 6796aeb6d3..9b9df33053 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -223,10 +223,16 @@ using @file{/dev/cdrom} as filename (@pxref{host_drives}). Boot on floppy (a), hard disk (c) or CD-ROM (d). Hard disk boot is the default. +@item -disk ide,img=file[,hdx=a..dd][,type=disk|cdrom] +Use @var{file} as the IDE disk/CD-ROM image. The defaults are: hdx=a,type=disk + +@item -disk scsi,img=file[,sdx=a..g][,type=disk|cdrom][,id=n] +Use @var{file} as the SCSI disk/CD-ROM image. The defaults are: sdx=a,type=disk,id='auto assign' + @item -snapshot Write to temporary files instead of disk image files. In this case, the raw disk image you use is not written back. You can however force -the write back by pressing @key{C-a s} (@pxref{disk_images}). +the write back by pressing @key{C-a s} (@pxref{disk_images}). @item -no-fd-bootchk Disable boot signature checking for floppy disks in Bochs BIOS. It may @@ -109,6 +109,8 @@ /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 +#define DISK_OPTIONS_SIZE 256 + const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; void *ioport_opaque[MAX_IOPORTS]; @@ -119,6 +121,9 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; +BlockDriverState *bs_scsi_table[MAX_SCSI_DISKS]; +SCSIDiskInfo scsi_disks_info[MAX_SCSI_DISKS]; +int scsi_hba_lsi; /* Count of scsi disks/cdrom using this lsi adapter */ int vga_ram_size; int bios_size; static DisplayState display_state; @@ -3814,7 +3819,172 @@ void do_info_network(void) term_printf(" %s\n", vc->info_str); } } - + +/* Parse IDE and SCSI disk options */ +static int disk_options_init(int num_ide_disks, + char ide_disk_options[][DISK_OPTIONS_SIZE], + int snapshot, + int num_scsi_disks, + char scsi_disk_options[][DISK_OPTIONS_SIZE], + int cdrom_index, + int cyls, + int heads, + int secs, + int translation) +{ + char buf[256]; + char dev_name[64]; + int id, i, j; + int cdrom_device; + int ide_cdrom_created = 0; + int scsi_index; + scsi_host_adapters temp_adapter; + + /* Process any IDE disks/cdroms */ + for (i=0; i< num_ide_disks; i++) { + for (j=0; j<MAX_DISKS; j++) { + if (ide_disk_options[j][0] == '\0') + continue; + + if (get_param_value(buf, sizeof(buf),"type",ide_disk_options[j])) { + if (!strcmp(buf, "disk")) { + cdrom_device = 0; + } else if (!strcmp(buf, "cdrom")) { + cdrom_device = 1; + ide_cdrom_created = 1; + } else { + fprintf(stderr, "qemu: invalid IDE disk type= value: %s\n", buf); + return -1; + } + } else { + cdrom_device = 0; + } + + if (cdrom_device) { + snprintf(dev_name, sizeof(dev_name), "cdrom%c", i); + } else { + snprintf(dev_name, sizeof(dev_name), "hd%c", i + 'a'); + } + + if (!(get_param_value(buf, sizeof(buf),"img",ide_disk_options[j]))) { + fprintf(stderr, "qemu: missing IDE disk img= value.\n"); + return -1; + } + + if (!(bs_table[i] = bdrv_new(dev_name))) { + fprintf(stderr, "qemu: unable to create new block device for:%s\n",dev_name); + return -1; + } + + if (cdrom_device) { + bdrv_set_type_hint(bs_table[i], BDRV_TYPE_CDROM); + } + + if (bdrv_open(bs_table[i], buf, snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { + fprintf(stderr, "qemu: could not open hard disk image: '%s'\n", + buf); + return -1; + } + if (i == 0 && cyls != 0) { + bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs); + bdrv_set_translation_hint(bs_table[i], translation); + } + ide_disk_options[j][0] = '\0'; + + if (i == cdrom_index) { + cdrom_index = -1; + } + break; /* finished with this IDE device*/ + } + } + + if (cdrom_index >= 0 && (!ide_cdrom_created)) { + bs_table[cdrom_index] = bdrv_new("cdrom"); + bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); + } + + for(i = 0; i < num_scsi_disks; i++) { + + temp_adapter = SCSI_LSI_53C895A; + scsi_hba_lsi++; + + /*Check for sdx= parameter */ + if (get_param_value(buf, sizeof(buf), "sdx", scsi_disk_options[i])) { + if (buf[0] >= 'a' && buf[0] <= 'g') { + scsi_index = buf[0] - 'a'; + } else{ + fprintf(stderr, "qemu: sdx= option for SCSI must be one letter from a-g. %s \n",buf); + exit(1); + } + } else { + scsi_index = 0; + } + + /* Check for SCSI id specified. */ + if (get_param_value(buf, sizeof(buf),"id",scsi_disk_options[i])) { + id = strtol(buf, NULL, 0); + if (id < 0 || id > 6) { + fprintf(stderr, "qemu: SCSI id must be from 0-6: %d\n", id); + return -1; + } + /* Check if id already used */ + for(j = 0; j < MAX_SCSI_DISKS; j++) { + if (scsi_disks_info[j].device_type != SCSI_NONE && + j != i && + scsi_disks_info[j].adapter == temp_adapter && + scsi_disks_info[j].id == id ) { + fprintf(stderr, "qemu: SCSI id already used: %u\n", id); + return -1; + } + } + } else { + id = -1; + } + scsi_disks_info[i].adapter = temp_adapter; + scsi_disks_info[i].id = id; + + if (get_param_value(buf, sizeof(buf),"type",scsi_disk_options[i])) { + if (!strcmp(buf, "disk")) { + cdrom_device = 0; + } else if (!strcmp(buf, "cdrom")) { + cdrom_device = 1; + } else { + fprintf(stderr, "qemu: invalid SCSI disk type= value: %s\n", buf); + return -1; + } + } else { + cdrom_device = 0; + } + + if (cdrom_device) { + snprintf(dev_name, sizeof(buf), "cdrom%c", scsi_index); + scsi_disks_info[scsi_index].device_type = SCSI_CDROM; + } else { + snprintf(dev_name, sizeof(buf), "sd%c", scsi_index + 'a'); + scsi_disks_info[scsi_index].device_type = SCSI_DISK; + } + + if (!(bs_scsi_table[scsi_index] = bdrv_new(dev_name))) { + fprintf(stderr, "qemu: unable to create new block device for:%s\n",dev_name); + return -1; + } + + /* Get image filename from options and then try to open it */ + if (get_param_value(buf, sizeof(buf),"img",scsi_disk_options[i])) { + if (bdrv_open(bs_scsi_table[scsi_index], buf, 0) < 0) { + fprintf(stderr, "qemu: could not open SCSI disk image img='%s'\n",buf); + return -1; + } + } else { + fprintf(stderr, "qemu: SCSI disk image not specified for sd%c \n", i + 'a'); + return -1; + } + } + + return 0; +} + + /***********************************************************/ /* USB devices */ @@ -5923,6 +6093,10 @@ void help(void) "-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n" "-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n" "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" + "-disk ide,img=file[,hdx=a..dd][,type=disk|cdrom] \n" + " defaults are: hdx=a,type=disk \n" + "-disk scsi,img=file[,sdx=a..g][,type=disk|cdrom][,id=n] \n" + " defaults are: sdx=a,type=disk,id='auto assign' \n" "-snapshot write to temporary files instead of disk image files\n" #ifdef CONFIG_SDL "-no-quit disable SDL window close capability\n" @@ -6103,6 +6277,7 @@ enum { QEMU_OPTION_no_acpi, QEMU_OPTION_no_reboot, QEMU_OPTION_daemonize, + QEMU_OPTION_disk, }; typedef struct QEMUOption { @@ -6177,6 +6352,7 @@ const QEMUOption qemu_options[] = { { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, { "vnc", HAS_ARG, QEMU_OPTION_vnc }, + { "disk", HAS_ARG, QEMU_OPTION_disk }, /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, @@ -6395,7 +6571,11 @@ int main(int argc, char **argv) int i, cdrom_index; int snapshot, linux_boot; const char *initrd_filename; - const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; + const char *fd_filename[MAX_FD]; + char scsi_options[MAX_SCSI_DISKS] [DISK_OPTIONS_SIZE]; + char ide_options[MAX_DISKS] [DISK_OPTIONS_SIZE]; + int num_ide_disks; + int num_scsi_disks; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; @@ -6450,10 +6630,19 @@ int main(int argc, char **argv) register_machines(); machine = first_machine; initrd_filename = NULL; + for(i = 0; i < MAX_SCSI_DISKS; i++) { + scsi_disks_info[i].device_type = SCSI_NONE; + bs_scsi_table[i] = NULL; + } + + num_ide_disks = 0; + num_scsi_disks = 0; + for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; - for(i = 0; i < MAX_DISKS; i++) - hd_filename[i] = NULL; + for(i = 0; i < MAX_DISKS; i++) { + ide_options[i][0] = '\0'; + } ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; bios_size = BIOS_SIZE; @@ -6497,7 +6686,16 @@ int main(int argc, char **argv) break; r = argv[optind]; if (r[0] != '-') { - hd_filename[0] = argv[optind++]; + + /* Build new disk IDE syntax string */ + pstrcpy(ide_options[0], + 14, + "hdx=a,img="); + /*Add on image filename */ + pstrcpy(&(ide_options[0][13]), + sizeof(ide_options[0])-13, + argv[optind++]); + num_ide_disks++; } else { const QEMUOption *popt; @@ -6547,10 +6745,75 @@ int main(int argc, char **argv) case QEMU_OPTION_hdd: { int hd_index; + const char newIDE_DiskSyntax [][10] = { + "hdx=a,img=", "hdx=b,img=", "hdx=c,img=", "hdx=d,img=" }; + hd_index = popt->index - QEMU_OPTION_hda; - hd_filename[hd_index] = optarg; - if (hd_index == cdrom_index) - cdrom_index = -1; + if (num_ide_disks >= MAX_DISKS){ + fprintf(stderr, "qemu: too many IDE disks defined.\n"); + exit(1); + } + /* Build new disk IDE syntax string */ + pstrcpy(ide_options[hd_index], + 11, + newIDE_DiskSyntax[hd_index]); + /* Add on image filename */ + pstrcpy(&(ide_options[hd_index][10]), + sizeof(ide_options[0])-10, + optarg); + num_ide_disks++; + } + break; + case QEMU_OPTION_disk: /*Combined IDE and SCSI, for disk and CDROM */ + { + const char *p_input_char; + char *p_output_string; + char device[64]; + int disk_index; + + p_input_char = optarg; + p_output_string = device; + while (*p_input_char != '\0' && *p_input_char != ',') { + if ((p_output_string - device) < sizeof(device) - 1) + *p_output_string++ = *p_input_char; + p_input_char++; + } + *p_output_string = '\0'; + if (*p_input_char == ',') + p_input_char++; + + if (!strcmp(device, "scsi")) { + if (num_scsi_disks >= MAX_SCSI_DISKS) { + fprintf(stderr, "qemu: too many SCSI disks defined.\n"); + exit(1); + } + pstrcpy(scsi_options[num_scsi_disks], + sizeof(scsi_options[0]), + p_input_char); + num_scsi_disks++; + } else if (!strcmp(device,"ide")) { + if (num_ide_disks >= MAX_DISKS) { + fprintf(stderr, "qemu: too many IDE disks/cdroms defined.\n"); + exit(1); + } + disk_index = 0; /* default is hda */ + if (get_param_value(device, sizeof(device),"hdx",p_input_char)) { + if (device[0] >= 'a' && device[0] <= 'd') { + disk_index = device[0] - 'a'; + } else { + fprintf(stderr, "qemu: invalid IDE disk hdx= value: %s\n", device); + return -1; + } + } + else disk_index=0; + pstrcpy(ide_options[disk_index], + sizeof(ide_options[0]), + p_input_char); + num_ide_disks++; + } else { + fprintf(stderr, "qemu: -disk option must specify IDE or SCSI: %s \n",device); + exit(1); + } } break; case QEMU_OPTION_snapshot: @@ -6604,8 +6867,22 @@ int main(int argc, char **argv) kernel_cmdline = optarg; break; case QEMU_OPTION_cdrom: - if (cdrom_index >= 0) { - hd_filename[cdrom_index] = optarg; + { + char buf[24]; + if (num_ide_disks >= MAX_DISKS) { + fprintf(stderr, "qemu: too many IDE disks/cdroms defined.\n"); + exit(1); + } + snprintf(buf, sizeof(buf), "type=cdrom,hdx=%c,img=", cdrom_index + 'a'); + /* Build new disk IDE syntax string */ + pstrcpy(ide_options[cdrom_index], + 25, + buf); + /* Add on image filename */ + pstrcpy(&(ide_options[cdrom_index][24]), + sizeof(ide_options[0])-24, + optarg); + num_ide_disks++; } break; case QEMU_OPTION_boot: @@ -6893,20 +7170,11 @@ int main(int argc, char **argv) kqemu_allowed = 0; #endif linux_boot = (kernel_filename != NULL); - - if (!linux_boot && - hd_filename[0] == '\0' && - (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && + + if (!linux_boot && + num_ide_disks == 0 && fd_filename[0] == '\0') help(); - - /* boot to cd by default if no hard disk */ - if (hd_filename[0] == '\0' && boot_device == 'c') { - if (fd_filename[0] != '\0') - boot_device = 'a'; - else - boot_device = 'd'; - } setvbuf(stdout, NULL, _IOLBF, 0); @@ -6942,31 +7210,22 @@ int main(int argc, char **argv) exit(1); } - /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); - if (cdrom_index >= 0) { - bs_table[cdrom_index] = bdrv_new("cdrom"); - bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); + + /* open the virtual block devices, disks or CDRoms */ + if (disk_options_init(num_ide_disks,ide_options,snapshot, + num_scsi_disks,scsi_options, + cdrom_index, + cyls, heads, secs, translation)){ + exit(1); } - /* open the virtual block devices */ - for(i = 0; i < MAX_DISKS; i++) { - if (hd_filename[i]) { - if (!bs_table[i]) { - char buf[64]; - snprintf(buf, sizeof(buf), "hd%c", i + 'a'); - bs_table[i] = bdrv_new(buf); - } - if (bdrv_open(bs_table[i], hd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { - fprintf(stderr, "qemu: could not open hard disk image '%s'\n", - hd_filename[i]); - exit(1); - } - if (i == 0 && cyls != 0) { - bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs); - bdrv_set_translation_hint(bs_table[i], translation); - } - } + /* boot to floppy or default cd if no hard disk */ + if (num_ide_disks == 0 && boot_device == 'c') { + if (fd_filename[0] != '\0') + boot_device = 'a'; + else + boot_device = 'd'; } /* we always create at least one floppy disk */ @@ -1222,9 +1222,30 @@ int scsi_write_data(SCSIDevice *s, uint32_t tag); void scsi_cancel_io(SCSIDevice *s, uint32_t tag); uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag); +enum scsi_host_adapters { + SCSI_LSI_53C895A +}; +enum scsi_devices { + SCSI_CDROM, + SCSI_DISK, + SCSI_NONE +}; +typedef enum scsi_host_adapters scsi_host_adapters; +typedef enum scsi_devices scsi_devices; +typedef struct SCSIDiskInfo { + scsi_host_adapters adapter; + int id; + scsi_devices device_type; +} SCSIDiskInfo; + +#define MAX_SCSI_DISKS 7 +extern BlockDriverState *bs_scsi_table[MAX_SCSI_DISKS]; +extern SCSIDiskInfo scsi_disks_info[MAX_SCSI_DISKS]; + /* lsi53c895a.c */ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id); void *lsi_scsi_init(PCIBus *bus, int devfn); +extern int scsi_hba_lsi; // Count of scsi disks/cdrom using this lsi adapter /* integratorcp.c */ extern QEMUMachine integratorcp926_machine; |