All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Vivier <Laurent.Vivier@bull.net>
Cc: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH][UPDATE3] Add -drive parameter
Date: Mon, 19 Nov 2007 09:24:26 +0100	[thread overview]
Message-ID: <11954606662783@bull.net> (raw)
In-Reply-To: 


This is an update with Qemu CVS tree and comments from Blue Swirl.

This patch introduces a new parameter allowing to define drives.

The new parameter is "-drive":

    -drive [file=file][,if=type][,bus=n][,unit=m][,media=d][index=i][,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]

where:

    file is the disk image
    type is the interface type (ide, scsi, sd, mtd, floppy, pflash)
    n is the bus number of the given type
    m is the unit number on the given bus
    d is the type of the media (disk, cdrom)
    c,h,s,t are the parameters usually given by -hdachs
    snapshot allows to enable or not the snapshot for this disk
    i is an index number within the given type (replace bus,unit)

"-cdrom file" is an alias for "-drive file=file,index=2,media=cdrom"
"-hda file" is an alias for "-drive file=file,index=0,media=disk"
"-hdb file" is an alias for "-drive file=file,index=1,media=disk"
"-hdc file" is an alias for "-drive file=file,index=2,media=disk"
"-hdd file" is an alias for "-drive file=file,index=3,media=disk"
"-hda file -hdachs a,b,c" is an alias for 
                 "-drive file=file,index=0,cyls=a,heads=b,secs=c"

You can also define a cdrom on the slace of ide0 with:
"-drive file=file,if=ide,index=1,media=cdrom"

You can define an empty cdrom:
"-drive if=ide,index=1,media=cdrom"

"-drive file=file,if=scsi,bus=0,unit=6" allows to connect the disk image file 
to the scsi bus 0 with the unit id 6.

if there is no SCSI disk, the SCSI interface is not created.

It also defines the default interface type to "scsi" for targets
"realview", "SS-5", "SS-10", "versatilepb", "versatileab"
to keep old behavior, where "-hda" is a SCSI disk.

"-fda file" is an alias for "-drive file=file,index=0,if=floppy"
"-fdb file" is an alias for "-drive file=file,index=1,if=floppy"
"-pflash file" is an alias for "-drive file=file,if=pflash"
"-mtdblock file" is an alias for "-drive file=file,if=mtd"
"-sd file" becomes the alias of "-drive file=file,if=sd"

"-drive file=a -drive file=b" will be interpreted like "-hda a -hdb b"
---
 hw/esp.c           |   10 -
 hw/integratorcp.c  |    8
 hw/lsi53c895a.c    |    3
 hw/mips_malta.c    |   15 +
 hw/mips_pica61.c   |   21 +-
 hw/mips_r4k.c      |   17 +
 hw/nand.c          |    2
 hw/omap_mmc.c      |    2
 hw/pc.c            |   65 ++++--
 hw/ppc405_boards.c |   29 +-
 hw/ppc_chrp.c      |   17 +
 hw/ppc_oldworld.c  |   31 ++-
 hw/ppc_prep.c      |   27 ++
 hw/pxa2xx_mmci.c   |    3
 hw/realview.c      |   17 +
 hw/spitz.c         |    9
 hw/esp.c           |   10 
 hw/gumstix.c       |    6 
 hw/integratorcp.c  |    8 
 hw/lsi53c895a.c    |    3 
 hw/mips_malta.c    |   20 +
 hw/mips_pica61.c   |   29 ++
 hw/mips_r4k.c      |   22 +
 hw/nand.c          |    8 
 hw/omap.c          |    9 
 hw/pc.c            |   70 +++--
 hw/pci.h           |    1 
 hw/ppc405_boards.c |   29 +-
 hw/ppc_chrp.c      |   21 +
 hw/ppc_oldworld.c  |   35 ++
 hw/ppc_prep.c      |   32 ++
 hw/pxa2xx.c        |   20 +
 hw/realview.c      |   21 +
 hw/spitz.c         |    9 
 hw/sun4m.c         |   29 +-
 hw/sun4m.h         |    3 
 hw/sun4u.c         |   29 ++
 hw/versatilepb.c   |   22 +
 monitor.c          |   11 
 sysemu.h           |   27 +-
 vl.c               |  655 +++++++++++++++++++++++++++++++++++++----------------
 25 files changed, 830 insertions(+), 299 deletions(-)

Index: qemu/vl.c
===================================================================
--- qemu.orig/vl.c	2007-11-19 09:00:41.000000000 +0100
+++ qemu/vl.c	2007-11-19 09:01:01.000000000 +0100
@@ -164,12 +164,10 @@ char phys_ram_file[1024];
 void *ioport_opaque[MAX_IOPORTS];
 IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
 IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
-/* Note: bs_table[MAX_DISKS] is a dummy block driver if none available
+/* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
    to store the VM snapshots */
-BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD];
-BlockDriverState *pflash_table[MAX_PFLASH];
-BlockDriverState *sd_bdrv;
-BlockDriverState *mtd_bdrv;
+DriveInfo drives_table[MAX_DRIVES+1];
+int nb_drives;
 /* point to the block driver where the snapshots are managed */
 BlockDriverState *bs_snapshots;
 int vga_ram_size;
@@ -233,6 +231,8 @@ int alt_grab = 0;
 unsigned int nb_prom_envs = 0;
 const char *prom_envs[MAX_PROM_ENVS];
 #endif
+int nb_drives_opt;
+char drives_opt[MAX_DRIVES][1024];
 
 #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
 
@@ -1749,12 +1749,9 @@ static int mux_proc_byte(CharDriverState
         case 's':
             {
                 int i;
-                for (i = 0; i < MAX_DISKS; i++) {
-                    if (bs_table[i])
-                        bdrv_commit(bs_table[i]);
+                for (i = 0; i < nb_drives; i++) {
+                        bdrv_commit(drives_table[i].bdrv);
                 }
-                if (mtd_bdrv)
-                    bdrv_commit(mtd_bdrv);
             }
             break;
         case 'b':
@@ -4518,38 +4515,51 @@ static int net_socket_mcast_init(VLANSta
 
 }
 
+static const char *get_word(char *buf, int buf_size, const char *p)
+{
+    char *q;
+    int substring;
+
+    substring = 0;
+    q = buf;
+    while (*p != '\0') {
+        if (*p == '\\') {
+            p++;
+            if (*p == '\0')
+                break;
+        } else if (*p == '\"') {
+            substring = !substring;
+            p++;
+            continue;
+        } else if (!substring && (*p == ',' || *p == '='))
+            break;
+        if (q && (q - buf) < buf_size - 1)
+            *q++ = *p;
+        p++;
+    }
+    if (q)
+        *q = '\0';
+
+    return p;
+}
+
 static int get_param_value(char *buf, int buf_size,
                            const char *tag, const char *str)
 {
     const char *p;
-    char *q;
     char option[128];
 
     p = str;
     for(;;) {
-        q = option;
-        while (*p != '\0' && *p != '=') {
-            if ((q - option) < sizeof(option) - 1)
-                *q++ = *p;
-            p++;
-        }
-        *q = '\0';
+        p = get_word(option, sizeof(option), p);
         if (*p != '=')
             break;
         p++;
         if (!strcmp(tag, option)) {
-            q = buf;
-            while (*p != '\0' && *p != ',') {
-                if ((q - buf) < buf_size - 1)
-                    *q++ = *p;
-                p++;
-            }
-            *q = '\0';
-            return q - buf;
+            (void)get_word(buf, buf_size, p);
+            return strlen(buf);
         } else {
-            while (*p != '\0' && *p != ',') {
-                p++;
-            }
+            p = get_word(NULL, 0, p);
         }
         if (*p != ',')
             break;
@@ -4558,6 +4568,32 @@ static int get_param_value(char *buf, in
     return 0;
 }
 
+static int check_params(char *buf, int buf_size,
+                        char **params, const char *str)
+{
+    const char *p;
+    int i;
+
+    p = str;
+    for(;;) {
+        p = get_word(buf, buf_size, p);
+        if (*p != '=')
+            return -1;
+        p++;
+        for(i = 0; params[i] != NULL; i++)
+            if (!strcmp(params[i], buf))
+                break;
+        if (params[i] == NULL)
+            return -1;
+        p = get_word(NULL, 0, p);
+        if (*p != ',')
+            break;
+        p++;
+    }
+    return 0;
+}
+
+
 static int net_client_init(const char *str)
 {
     const char *p;
@@ -4708,6 +4744,323 @@ void do_info_network(void)
     }
 }
 
+#define HD_ALIAS "file=\"%s\",index=%d,media=disk"
+#ifdef TARGET_PPC
+#define CDROM_ALIAS "index=1,media=cdrom"
+#else
+#define CDROM_ALIAS "index=2,media=cdrom"
+#endif
+#define FD_ALIAS "index=%d,if=floppy"
+#define PFLASH_ALIAS "file=\"%s\",if=pflash"
+#define MTD_ALIAS "file=\"%s\",if=mtd"
+#define SD_ALIAS "file=\"%s\",if=sd"
+
+static int drive_add(const char *fmt, ...)
+{
+    va_list ap;
+
+    if (nb_drives_opt >= MAX_DRIVES) {
+        fprintf(stderr, "qemu: too many drives\n");
+        exit(1);
+    }
+
+    va_start(ap, fmt);
+    vsnprintf(drives_opt[nb_drives_opt], sizeof(drives_opt[0]), fmt, ap);
+    va_end(ap);
+
+    return nb_drives_opt++;
+}
+
+int drive_get_index(BlockInterfaceType interface, int bus, int unit)
+{
+    int index;
+
+    /* seek interface, bus and unit */
+
+    for (index = 0; index < nb_drives; index++)
+        if (drives_table[index].interface == interface &&
+	    drives_table[index].bus == bus &&
+	    drives_table[index].unit == unit)
+        return index;
+
+    return -1;
+}
+
+int drive_get_max_bus(BlockInterfaceType interface)
+{
+    int max_bus;
+    int index;
+
+    max_bus = -1;
+    for (index = 0; index < nb_drives; index++) {
+        if(drives_table[index].interface == interface &&
+           drives_table[index].bus > max_bus)
+            max_bus = drives_table[index].bus;
+    }
+    return max_bus;
+}
+
+static int drive_init(const char *str, int snapshot, QEMUMachine *machine)
+{
+    char buf[128];
+    char file[1024];
+    BlockInterfaceType interface;
+    enum { MEDIA_DISK, MEDIA_CDROM } media;
+    int bus_id, unit_id;
+    int cyls, heads, secs, translation;
+    BlockDriverState *bdrv;
+    int max_devs;
+    int index;
+    char *params[] = { "bus", "unit", "if", "index", "cyls", "heads",
+                       "secs", "trans", "media", "snapshot", "file", NULL };
+
+    if (check_params(buf, sizeof(buf), params, str) < 0) {
+         fprintf(stderr, "qemu: unknowm parameter '%s' in '%s'\n",
+                         buf, str);
+         return -1;
+    }
+
+    file[0] = 0;
+    cyls = heads = secs = 0;
+    bus_id = 0;
+    unit_id = -1;
+    translation = BIOS_ATA_TRANSLATION_AUTO;
+    index = -1;
+
+    if (!strcmp(machine->name, "realview") ||
+        !strcmp(machine->name, "SS-5") ||
+        !strcmp(machine->name, "SS-10") ||
+        !strcmp(machine->name, "SS-600MP") ||
+        !strcmp(machine->name, "versatilepb") ||
+        !strcmp(machine->name, "versatileab")) {
+        interface = IF_SCSI;
+        max_devs = MAX_SCSI_DEVS;
+    } else {
+        interface = IF_IDE;
+        max_devs = MAX_IDE_DEVS;
+    }
+    media = MEDIA_DISK;
+
+    /* extract parameters */
+
+    if (get_param_value(buf, sizeof(buf), "bus", str)) {
+        bus_id = strtol(buf, NULL, 0);
+	if (bus_id < 0) {
+	    fprintf(stderr, "qemu: '%s' invalid bus id\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "unit", str)) {
+        unit_id = strtol(buf, NULL, 0);
+	if (unit_id < 0) {
+	    fprintf(stderr, "qemu: '%s' invalid unit id\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "if", str)) {
+        if (!strcmp(buf, "ide")) {
+	    interface = IF_IDE;
+            max_devs = MAX_IDE_DEVS;
+        } else if (!strcmp(buf, "scsi")) {
+	    interface = IF_SCSI;
+            max_devs = MAX_SCSI_DEVS;
+        } else if (!strcmp(buf, "floppy")) {
+	    interface = IF_FLOPPY;
+            max_devs = 0;
+        } else if (!strcmp(buf, "pflash")) {
+	    interface = IF_PFLASH;
+            max_devs = 0;
+	} else if (!strcmp(buf, "mtd")) {
+	    interface = IF_MTD;
+            max_devs = 0;
+	} else if (!strcmp(buf, "sd")) {
+	    interface = IF_SD;
+            max_devs = 0;
+	} else {
+            fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
+            return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "index", str)) {
+        index = strtol(buf, NULL, 0);
+	if (index < 0) {
+	    fprintf(stderr, "qemu: '%s' invalid index\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "cyls", str)) {
+        cyls = strtol(buf, NULL, 0);
+    }
+
+    if (get_param_value(buf, sizeof(buf), "heads", str)) {
+        heads = strtol(buf, NULL, 0);
+    }
+
+    if (get_param_value(buf, sizeof(buf), "secs", str)) {
+        secs = strtol(buf, NULL, 0);
+    }
+
+    if (cyls || heads || secs) {
+        if (cyls < 1 || cyls > 16383) {
+            fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str);
+	    return -1;
+	}
+        if (heads < 1 || heads > 16) {
+            fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str);
+	    return -1;
+	}
+        if (secs < 1 || secs > 63) {
+            fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "trans", str)) {
+        if (!cyls) {
+            fprintf(stderr,
+                    "qemu: '%s' trans must be used with cyls,heads and secs\n",
+                    str);
+            return -1;
+        }
+        if (!strcmp(buf, "none"))
+            translation = BIOS_ATA_TRANSLATION_NONE;
+        else if (!strcmp(buf, "lba"))
+            translation = BIOS_ATA_TRANSLATION_LBA;
+        else if (!strcmp(buf, "auto"))
+            translation = BIOS_ATA_TRANSLATION_AUTO;
+	else {
+            fprintf(stderr, "qemu: '%s' invalid translation type\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "media", str)) {
+        if (!strcmp(buf, "disk")) {
+	    media = MEDIA_DISK;
+	} else if (!strcmp(buf, "cdrom")) {
+            if (cyls || secs || heads) {
+                fprintf(stderr,
+                        "qemu: '%s' invalid physical CHS format\n", str);
+	        return -1;
+            }
+	    media = MEDIA_CDROM;
+	} else {
+	    fprintf(stderr, "qemu: '%s' invalid media\n", str);
+	    return -1;
+	}
+    }
+
+    if (get_param_value(buf, sizeof(buf), "snapshot", str)) {
+        if (!strcmp(buf, "on"))
+	    snapshot = 1;
+        else if (!strcmp(buf, "off"))
+	    snapshot = 0;
+	else {
+	    fprintf(stderr, "qemu: '%s' invalid snapshot option\n", str);
+	    return -1;
+	}
+    }
+
+    get_param_value(file, sizeof(file), "file", str);
+
+    /* compute bus and unit according index */
+
+    if (index != -1) {
+        if (bus_id != 0 || unit_id != -1) {
+            fprintf(stderr,
+                    "qemu: '%s' index cannot be used with bus and unit\n", str);
+            return -1;
+        }
+        if (max_devs == 0)
+        {
+            unit_id = index;
+            bus_id = 0;
+        } else {
+            unit_id = index % max_devs;
+            bus_id = index / max_devs;
+        }
+    }
+
+    /* if user doesn't specify a unit_id,
+     * try to find the first free
+     */
+
+    if (unit_id == -1) {
+       unit_id = 0;
+       while (drive_get_index(interface, bus_id, unit_id) != -1) {
+           unit_id++;
+           if (max_devs && unit_id >= max_devs) {
+               unit_id -= max_devs;
+               bus_id++;
+           }
+       }
+    }
+
+    /* check unit id */
+
+    if (max_devs && unit_id >= max_devs) {
+        fprintf(stderr, "qemu: '%s' unit %d too big (max is %d)\n",
+                        str, unit_id, max_devs - 1);
+        return -1;
+    }
+
+    /*
+     * ignore multiple definitions
+     */
+
+    if (drive_get_index(interface, bus_id, unit_id) != -1)
+        return 0;
+
+    /* init */
+
+    snprintf(buf, sizeof(buf), "drive%d", nb_drives);
+    bdrv = bdrv_new(buf);
+    drives_table[nb_drives].bdrv = bdrv;
+    drives_table[nb_drives].interface = interface;
+    drives_table[nb_drives].bus = bus_id;
+    drives_table[nb_drives].unit = unit_id;
+    nb_drives++;
+
+    switch(interface) {
+    case IF_IDE:
+    case IF_SCSI:
+        switch(media) {
+	case MEDIA_DISK:
+            if (cyls != 0) {
+                bdrv_set_geometry_hint(bdrv, cyls, heads, secs);
+                bdrv_set_translation_hint(bdrv, translation);
+            }
+	    break;
+	case MEDIA_CDROM:
+            bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
+	    break;
+	}
+        break;
+    case IF_SD:
+        /* FIXME: This isn't really a floppy, but it's a reasonable
+           approximation.  */
+    case IF_FLOPPY:
+        bdrv_set_type_hint(bdrv, BDRV_TYPE_FLOPPY);
+        break;
+    case IF_PFLASH:
+    case IF_MTD:
+        break;
+    }
+    if (!file[0])
+        return 0;
+    if (bdrv_open(bdrv, file, snapshot ? BDRV_O_SNAPSHOT : 0) < 0 ||
+        qemu_key_check(bdrv, file)) {
+        fprintf(stderr, "qemu: could not open disk image %s\n",
+                        file);
+        return -1;
+    }
+    return 0;
+}
+
 /***********************************************************/
 /* USB devices */
 
@@ -5490,8 +5843,8 @@ static BlockDriverState *get_bs_snapshot
 
     if (bs_snapshots)
         return bs_snapshots;
-    for(i = 0; i <= MAX_DISKS; i++) {
-        bs = bs_table[i];
+    for(i = 0; i <= nb_drives; i++) {
+        bs = drives_table[i].bdrv;
         if (bdrv_can_snapshot(bs))
             goto ok;
     }
@@ -5599,8 +5952,8 @@ void do_savevm(const char *name)
 
     /* create the snapshots */
 
-    for(i = 0; i < MAX_DISKS; i++) {
-        bs1 = bs_table[i];
+    for(i = 0; i < nb_drives; i++) {
+        bs1 = drives_table[i].bdrv;
         if (bdrv_has_snapshot(bs1)) {
             if (must_delete) {
                 ret = bdrv_snapshot_delete(bs1, old_sn->id_str);
@@ -5642,8 +5995,8 @@ void do_loadvm(const char *name)
     saved_vm_running = vm_running;
     vm_stop(0);
 
-    for(i = 0; i <= MAX_DISKS; i++) {
-        bs1 = bs_table[i];
+    for(i = 0; i <= nb_drives; i++) {
+        bs1 = drives_table[i].bdrv;
         if (bdrv_has_snapshot(bs1)) {
             ret = bdrv_snapshot_goto(bs1, name);
             if (ret < 0) {
@@ -5703,8 +6056,8 @@ void do_delvm(const char *name)
         return;
     }
 
-    for(i = 0; i <= MAX_DISKS; i++) {
-        bs1 = bs_table[i];
+    for(i = 0; i <= nb_drives; i++) {
+        bs1 = drives_table[i].bdrv;
         if (bdrv_has_snapshot(bs1)) {
             ret = bdrv_snapshot_delete(bs1, name);
             if (ret < 0) {
@@ -5732,8 +6085,8 @@ void do_info_snapshots(void)
         return;
     }
     term_printf("Snapshot devices:");
-    for(i = 0; i <= MAX_DISKS; i++) {
-        bs1 = bs_table[i];
+    for(i = 0; i <= nb_drives; i++) {
+        bs1 = drives_table[i].bdrv;
         if (bdrv_has_snapshot(bs1)) {
             if (bs == bs1)
                 term_printf(" %s", bdrv_get_device_name(bs1));
@@ -6483,15 +6836,14 @@ static void ram_save(QEMUFile *f, void *
             /* find if the memory block is available on a virtual
                block device */
             sector_num = -1;
-            for(j = 0; j < MAX_DISKS; j++) {
-                if (bs_table[j]) {
-                    sector_num = bdrv_hash_find(bs_table[j],
-                                                phys_ram_base + i, BDRV_HASH_BLOCK_SIZE);
-                    if (sector_num >= 0)
-                        break;
-                }
+            for(j = 0; j < nb_drives; j++) {
+                sector_num = bdrv_hash_find(drives_table[j].bdrv,
+                                            phys_ram_base + i,
+					    BDRV_HASH_BLOCK_SIZE);
+                if (sector_num >= 0)
+                    break;
             }
-            if (j == MAX_DISKS)
+            if (j == nb_drives)
                 goto normal_compress;
             buf[0] = 1;
             buf[1] = j;
@@ -6542,11 +6894,12 @@ static int ram_load(QEMUFile *f, void *o
             ram_decompress_buf(s, buf + 1, 9);
             bs_index = buf[1];
             sector_num = be64_to_cpupu((const uint64_t *)(buf + 2));
-            if (bs_index >= MAX_DISKS || bs_table[bs_index] == NULL) {
+            if (bs_index >= nb_drives) {
                 fprintf(stderr, "Invalid block device index %d\n", bs_index);
                 goto error;
             }
-            if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i,
+            if (bdrv_read(drives_table[bs_index].bdrv, sector_num,
+	                  phys_ram_base + i,
                           BDRV_HASH_BLOCK_SIZE / 512) < 0) {
                 fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n",
                         bs_index, sector_num);
@@ -7043,6 +7396,9 @@ static void help(int exitcode)
            "-hda/-hdb file  use 'file' as IDE hard disk 0/1 image\n"
            "-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"
+	   "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][index=i]\n"
+           "       [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off]\n"
+	   "                use 'file' as a drive image\n"
            "-mtdblock file  use 'file' as on-board Flash memory image\n"
            "-sd file        use 'file' as SecureDigital card image\n"
            "-pflash file    use 'file' as a parallel flash image\n"
@@ -7188,6 +7544,7 @@ enum {
     QEMU_OPTION_hdb,
     QEMU_OPTION_hdc,
     QEMU_OPTION_hdd,
+    QEMU_OPTION_drive,
     QEMU_OPTION_cdrom,
     QEMU_OPTION_mtdblock,
     QEMU_OPTION_sd,
@@ -7277,6 +7634,7 @@ const QEMUOption qemu_options[] = {
     { "hdb", HAS_ARG, QEMU_OPTION_hdb },
     { "hdc", HAS_ARG, QEMU_OPTION_hdc },
     { "hdd", HAS_ARG, QEMU_OPTION_hdd },
+    { "drive", HAS_ARG, QEMU_OPTION_drive },
     { "cdrom", HAS_ARG, QEMU_OPTION_cdrom },
     { "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock },
     { "sd", HAS_ARG, QEMU_OPTION_sd },
@@ -7389,16 +7747,9 @@ int qemu_key_check(BlockDriverState *bs,
 
 static BlockDriverState *get_bdrv(int index)
 {
-    BlockDriverState *bs;
-
-    if (index < 4) {
-        bs = bs_table[index];
-    } else if (index < 6) {
-        bs = fd_table[index - 4];
-    } else {
-        bs = NULL;
-    }
-    return bs;
+    if (index > nb_drives)
+        return NULL;
+    return drives_table[index].bdrv;
 }
 
 static void read_passwords(void)
@@ -7599,19 +7950,16 @@ int main(int argc, char **argv)
     const char *gdbstub_port;
 #endif
     uint32_t boot_devices_bitmap = 0;
-    int i, cdrom_index, pflash_index;
+    int i;
     int snapshot, linux_boot, net_boot;
     const char *initrd_filename;
-    const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
-    const char *pflash_filename[MAX_PFLASH];
-    const char *sd_filename;
-    const char *mtd_filename;
     const char *kernel_filename, *kernel_cmdline;
     const char *boot_devices = "";
     DisplayState *ds = &display_state;
     int cyls, heads, secs, translation;
     char net_clients[MAX_NET_CLIENTS][256];
     int nb_net_clients;
+    int hda_index;
     int optind;
     const char *r, *optarg;
     CharDriverState *monitor_hd;
@@ -7664,15 +8012,6 @@ int main(int argc, char **argv)
     machine = first_machine;
     cpu_model = NULL;
     initrd_filename = NULL;
-    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_PFLASH; i++)
-        pflash_filename[i] = NULL;
-    pflash_index = 0;
-    sd_filename = NULL;
-    mtd_filename = NULL;
     ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
     vga_ram_size = VGA_RAM_SIZE;
 #ifdef CONFIG_GDBSTUB
@@ -7683,11 +8022,6 @@ int main(int argc, char **argv)
     nographic = 0;
     kernel_filename = NULL;
     kernel_cmdline = "";
-#ifdef TARGET_PPC
-    cdrom_index = 1;
-#else
-    cdrom_index = 2;
-#endif
     cyls = heads = secs = 0;
     translation = BIOS_ATA_TRANSLATION_AUTO;
     pstrcpy(monitor_device, sizeof(monitor_device), "vc");
@@ -7705,6 +8039,9 @@ int main(int argc, char **argv)
     usb_devices_index = 0;
 
     nb_net_clients = 0;
+    nb_drives = 0;
+    nb_drives_opt = 0;
+    hda_index = -1;
 
     nb_nics = 0;
     /* default mac address of the first network interface */
@@ -7715,7 +8052,7 @@ int main(int argc, char **argv)
             break;
         r = argv[optind];
         if (r[0] != '-') {
-            hd_filename[0] = argv[optind++];
+	    hda_index = drive_add(HD_ALIAS, argv[optind++], 0);
         } else {
             const QEMUOption *popt;
 
@@ -7775,29 +8112,33 @@ int main(int argc, char **argv)
                 initrd_filename = optarg;
                 break;
             case QEMU_OPTION_hda:
+                if (cyls == 0)
+                    hda_index = drive_add(HD_ALIAS, optarg, 0);
+                else
+                    hda_index = drive_add(HD_ALIAS
+			     ",cyls=%d,heads=%d,secs=%d%s",
+                             optarg, 0, cyls, heads, secs,
+                             translation == BIOS_ATA_TRANSLATION_LBA ?
+                                 ",trans=lba" :
+                             translation == BIOS_ATA_TRANSLATION_NONE ?
+                                 ",trans=none" : "");
+                 break;
             case QEMU_OPTION_hdb:
             case QEMU_OPTION_hdc:
             case QEMU_OPTION_hdd:
-                {
-                    int hd_index;
-                    hd_index = popt->index - QEMU_OPTION_hda;
-                    hd_filename[hd_index] = optarg;
-                    if (hd_index == cdrom_index)
-                        cdrom_index = -1;
-                }
+		drive_add(HD_ALIAS, optarg, popt->index - QEMU_OPTION_hda);
                 break;
+            case QEMU_OPTION_drive:
+                drive_add("%s", optarg);
+	        break;
             case QEMU_OPTION_mtdblock:
-                mtd_filename = optarg;
+	        drive_add(MTD_ALIAS, optarg);
                 break;
             case QEMU_OPTION_sd:
-                sd_filename = optarg;
+                drive_add(SD_ALIAS, optarg);
                 break;
             case QEMU_OPTION_pflash:
-                if (pflash_index >= MAX_PFLASH) {
-                    fprintf(stderr, "qemu: too many parallel flash images\n");
-                    exit(1);
-                }
-                pflash_filename[pflash_index++] = optarg;
+	        drive_add(PFLASH_ALIAS, optarg);
                 break;
             case QEMU_OPTION_snapshot:
                 snapshot = 1;
@@ -7836,6 +8177,17 @@ int main(int argc, char **argv)
                         fprintf(stderr, "qemu: invalid physical CHS format\n");
                         exit(1);
                     }
+		    if (hda_index != -1)
+		        snprintf(drives_opt[hda_index] +
+			         strlen(drives_opt[hda_index]),
+			         sizeof(drives_opt[0]) -
+				 strlen(drives_opt[hda_index]),
+		                 ",cyls=%d,heads=%d,secs=%d%s",
+			         cyls, heads, secs,
+			         translation == BIOS_ATA_TRANSLATION_LBA ?
+			     	    ",trans=lba" :
+			         translation == BIOS_ATA_TRANSLATION_NONE ?
+			             ",trans=none" : "");
                 }
                 break;
             case QEMU_OPTION_nographic:
@@ -7854,9 +8206,7 @@ int main(int argc, char **argv)
                 kernel_cmdline = optarg;
                 break;
             case QEMU_OPTION_cdrom:
-                if (cdrom_index >= 0) {
-                    hd_filename[cdrom_index] = optarg;
-                }
+		drive_add("file=\"%s\"," CDROM_ALIAS, optarg);
                 break;
             case QEMU_OPTION_boot:
                 boot_devices = optarg;
@@ -7890,10 +8240,9 @@ int main(int argc, char **argv)
                 }
                 break;
             case QEMU_OPTION_fda:
-                fd_filename[0] = optarg;
-                break;
             case QEMU_OPTION_fdb:
-                fd_filename[1] = optarg;
+		drive_add("file=\"%s\"," FD_ALIAS, optarg,
+		          popt->index - QEMU_OPTION_fda);
                 break;
 #ifdef TARGET_I386
             case QEMU_OPTION_no_fd_bootchk:
@@ -8274,20 +8623,12 @@ int main(int argc, char **argv)
 
     /* XXX: this should not be: some embedded targets just have flash */
     if (!linux_boot && net_boot == 0 &&
-        hd_filename[0] == NULL &&
-        (cdrom_index >= 0 && hd_filename[cdrom_index] == NULL) &&
-        fd_filename[0] == NULL &&
-        pflash_filename[0] == NULL)
+        nb_drives_opt == 0)
         help(1);
 
     /* boot to floppy or the default cd if no hard disk defined yet */
     if (!boot_devices[0]) {
-        if (hd_filename[0] != NULL)
-            boot_devices = "c";
-        else if (fd_filename[0] != NULL)
-            boot_devices = "a";
-        else
-            boot_devices = "d";
+        boot_devices = "cad";
     }
     setvbuf(stdout, NULL, _IOLBF, 0);
 
@@ -8364,97 +8705,23 @@ 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 */
-    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);
-            }
-        }
-    }
+    /* we always create the cdrom drive, even if no disk is there */
 
-    /* we always create at least one floppy disk */
-    fd_table[0] = bdrv_new("fda");
-    bdrv_set_type_hint(fd_table[0], BDRV_TYPE_FLOPPY);
-
-    for(i = 0; i < MAX_FD; i++) {
-        if (fd_filename[i]) {
-            if (!fd_table[i]) {
-                char buf[64];
-                snprintf(buf, sizeof(buf), "fd%c", i + 'a');
-                fd_table[i] = bdrv_new(buf);
-                bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY);
-            }
-            if (fd_filename[i][0] != '\0') {
-                if (bdrv_open(fd_table[i], fd_filename[i],
-                              snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
-                    fprintf(stderr, "qemu: could not open floppy disk image '%s'\n",
-                            fd_filename[i]);
-                    exit(1);
-                }
-            }
-        }
-    }
+    if (nb_drives_opt < MAX_DRIVES)
+        drive_add(CDROM_ALIAS);
 
-    /* Open the virtual parallel flash block devices */
-    for(i = 0; i < MAX_PFLASH; i++) {
-        if (pflash_filename[i]) {
-            if (!pflash_table[i]) {
-                char buf[64];
-                snprintf(buf, sizeof(buf), "fl%c", i + 'a');
-                pflash_table[i] = bdrv_new(buf);
-            }
-            if (bdrv_open(pflash_table[i], pflash_filename[i],
-                          snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
-                fprintf(stderr, "qemu: could not open flash image '%s'\n",
-                        pflash_filename[i]);
-                exit(1);
-            }
-        }
-    }
+    /* we always create at least on floppy */
 
-    sd_bdrv = bdrv_new ("sd");
-    /* FIXME: This isn't really a floppy, but it's a reasonable
-       approximation.  */
-    bdrv_set_type_hint(sd_bdrv, BDRV_TYPE_FLOPPY);
-    if (sd_filename) {
-        if (bdrv_open(sd_bdrv, sd_filename,
-                      snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
-            fprintf(stderr, "qemu: could not open SD card image %s\n",
-                    sd_filename);
-        } else
-            qemu_key_check(sd_bdrv, sd_filename);
-    }
+    if (nb_drives_opt < MAX_DRIVES)
+        drive_add(FD_ALIAS, 0);
 
-    if (mtd_filename) {
-        mtd_bdrv = bdrv_new ("mtd");
-        if (bdrv_open(mtd_bdrv, mtd_filename,
-                      snapshot ? BDRV_O_SNAPSHOT : 0) < 0 ||
-            qemu_key_check(mtd_bdrv, mtd_filename)) {
-            fprintf(stderr, "qemu: could not open Flash image %s\n",
-                    mtd_filename);
-            bdrv_delete(mtd_bdrv);
-            mtd_bdrv = 0;
-        }
-    }
+    /* open the virtual block devices */
+
+    for(i = 0; i < nb_drives_opt; i++)
+        if (drive_init(drives_opt[i], snapshot, machine) == -1)
+	    exit(1);
 
     register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
     register_savevm("ram", 0, 2, ram_save, ram_load, NULL);
Index: qemu/monitor.c
===================================================================
--- qemu.orig/monitor.c	2007-11-19 09:00:26.000000000 +0100
+++ qemu/monitor.c	2007-11-19 09:01:01.000000000 +0100
@@ -215,16 +215,11 @@ static void do_commit(const char *device
     int i, all_devices;
 
     all_devices = !strcmp(device, "all");
-    for (i = 0; i < MAX_DISKS; i++) {
-        if (bs_table[i]) {
+    for (i = 0; i < nb_drives; i++) {
             if (all_devices ||
-                !strcmp(bdrv_get_device_name(bs_table[i]), device))
-                bdrv_commit(bs_table[i]);
-        }
+                !strcmp(bdrv_get_device_name(drives_table[i].bdrv), device))
+                bdrv_commit(drives_table[i].bdrv);
     }
-    if (mtd_bdrv)
-        if (all_devices || !strcmp(bdrv_get_device_name(mtd_bdrv), device))
-            bdrv_commit(mtd_bdrv);
 }
 
 static void do_info(const char *item)
Index: qemu/hw/mips_pica61.c
===================================================================
--- qemu.orig/hw/mips_pica61.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/mips_pica61.c	2007-11-19 09:01:01.000000000 +0100
@@ -44,6 +44,9 @@
 
 #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
 
+#define MAX_IDE_BUS 2
+#define MAX_FD 2
+
 static const int ide_iobase[2] = { 0x1f0, 0x170 };
 static const int ide_iobase2[2] = { 0x3f6, 0x376 };
 static const int ide_irq[2] = { 14, 15 };
@@ -72,6 +75,8 @@ void mips_pica61_init (int ram_size, int
     int i;
     int available_ram;
     qemu_irq *i8259;
+    int index;
+    BlockDriverState *fd[MAX_FD];
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -141,9 +146,20 @@ void mips_pica61_init (int ram_size, int
     i8042_mm_init(i8259[6], i8259[7], 0x80005060, 0);
 
     /* IDE controller */
-    for(i = 0; i < 2; i++)
+
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+
+    for(i = 0; i < MAX_IDE_BUS; i++) {
+        int hd0, hd1;
+        hd0 = drive_get_index(IF_IDE, i, 0);
+        hd1 = drive_get_index(IF_IDE, i, 1);
         isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
-                     bs_table[2 * i], bs_table[2 * i + 1]);
+                     hd0 == -1 ? NULL : drives_table[hd0].bdrv,
+                     hd1 == -1 ? NULL : drives_table[hd1].bdrv);
+    }
 
     /* Network controller */
     /* FIXME: missing NS SONIC DP83932 */
@@ -152,7 +168,14 @@ void mips_pica61_init (int ram_size, int
     /* FIXME: missing NCR 53C94 */
 
     /* ISA devices (floppy, serial, parallel) */
-    fdctrl_init(i8259[1], 1, 1, 0x80003000, fd_table);
+
+    for (i = 0; i < MAX_FD; i++) {
+        index = drive_get_index(IF_FLOPPY, 0, i);
+        if (index == -1)
+            continue;
+        fd[i] = drives_table[index].bdrv;
+    }
+    fdctrl_init(i8259[1], 1, 1, 0x80003000, fd);
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
             serial_mm_init(serial_base[i], 0, i8259[serial_irq[i]], serial_hds[i], 1);
Index: qemu/hw/mips_r4k.c
===================================================================
--- qemu.orig/hw/mips_r4k.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/mips_r4k.c	2007-11-19 09:01:01.000000000 +0100
@@ -25,6 +25,8 @@
 
 #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
 
+#define MAX_IDE_BUS 2
+
 static const int ide_iobase[2] = { 0x1f0, 0x170 };
 static const int ide_iobase2[2] = { 0x3f6, 0x376 };
 static const int ide_irq[2] = { 14, 15 };
@@ -155,6 +157,8 @@ void mips_r4k_init (int ram_size, int vg
     RTCState *rtc_state;
     int i;
     qemu_irq *i8259;
+    int index;
+    BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -245,9 +249,23 @@ void mips_r4k_init (int ram_size, int vg
         }
     }
 
-    for(i = 0; i < 2; i++)
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+        if (index != -1)
+            hd[i] = drives_table[index].bdrv;
+        else
+            hd[i] = NULL;
+    }
+
+    for(i = 0; i < MAX_IDE_BUS; i++)
         isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
-                     bs_table[2 * i], bs_table[2 * i + 1]);
+                     hd[MAX_IDE_DEVS * i],
+		     hd[MAX_IDE_DEVS * i + 1]);
 
     i8042_init(i8259[1], i8259[12], 0x60);
     ds1225y_init(0x9000, "nvram");
Index: qemu/hw/pc.c
===================================================================
--- qemu.orig/hw/pc.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/pc.c	2007-11-19 09:01:01.000000000 +0100
@@ -42,6 +42,8 @@
 /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
 #define ACPI_DATA_SIZE       0x10000
 
+#define MAX_IDE_BUS 2
+
 static fdctrl_t *floppy_controller;
 static RTCState *rtc_state;
 static PITState *pit;
@@ -381,8 +383,10 @@ static void generate_bootsect(uint32_t g
 {
     uint8_t bootsect[512], *p;
     int i;
+    int hda;
 
-    if (bs_table[0] == NULL) {
+    hda = drive_get_index(IF_IDE, 0, 0);
+    if (hda == -1) {
 	fprintf(stderr, "A disk image must be given for 'hda' when booting "
 		"a Linux kernel\n");
 	exit(1);
@@ -391,7 +395,7 @@ static void generate_bootsect(uint32_t g
     memset(bootsect, 0, sizeof(bootsect));
 
     /* Copy the MSDOS partition table if possible */
-    bdrv_read(bs_table[0], 0, bootsect, 1);
+    bdrv_read(drives_table[hda].bdrv, 0, bootsect, 1);
 
     /* Make sure we have a partition signature */
     bootsect[510] = 0x55;
@@ -428,7 +432,7 @@ static void generate_bootsect(uint32_t g
     *p++ = segs[1];		/* CS */
     *p++ = segs[1] >> 8;
 
-    bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));
+    bdrv_set_boot_sector(drives_table[hda].bdrv, bootsect, sizeof(bootsect));
 }
 
 static int load_kernel(const char *filename, uint8_t *addr,
@@ -709,6 +713,9 @@ static void pc_init1(int ram_size, int v
     NICInfo *nd;
     qemu_irq *cpu_irq;
     qemu_irq *i8259;
+    int index;
+    BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    BlockDriverState *fd[MAX_FD];
 
     linux_boot = (kernel_filename != NULL);
 
@@ -926,12 +933,25 @@ static void pc_init1(int ram_size, int v
         }
     }
 
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+	if (index != -1)
+	    hd[i] = drives_table[index].bdrv;
+	else
+	    hd[i] = NULL;
+    }
+
     if (pci_enabled) {
-        pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1, i8259);
+        pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259);
     } else {
-        for(i = 0; i < 2; i++) {
+        for(i = 0; i < MAX_IDE_BUS; i++) {
             isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
-                         bs_table[2 * i], bs_table[2 * i + 1]);
+	                 hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
         }
     }
 
@@ -941,9 +961,16 @@ static void pc_init1(int ram_size, int v
     audio_init(pci_enabled ? pci_bus : NULL, i8259);
 #endif
 
-    floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table);
+    for(i = 0; i < MAX_FD; i++) {
+        index = drive_get_index(IF_FLOPPY, 0, i);
+	if (index != -1)
+	    fd[i] = drives_table[index].bdrv;
+	else
+	    fd[i] = NULL;
+    }
+    floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
 
-    cmos_init(ram_size, boot_device, bs_table);
+    cmos_init(ram_size, boot_device, hd);
 
     if (pci_enabled && usb_enabled) {
         usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
@@ -963,23 +990,24 @@ static void pc_init1(int ram_size, int v
     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) {
+	int max_bus;
+        int bus, unit;
         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);
+        max_bus = drive_get_max_bus(IF_SCSI);
+
+	for (bus = 0; bus <= max_bus; bus++) {
+            scsi = lsi_scsi_init(pci_bus, -1);
+            for (unit = 0; unit < LSI_MAX_DEVS; unit++) {
+	        index = drive_get_index(IF_SCSI, bus, unit);
+		if (index == -1)
+		    continue;
+		lsi_scsi_attach(scsi, drives_table[index].bdrv, unit);
+	    }
+        }
     }
-#endif
 }
 
 static void pc_init_pci(int ram_size, int vga_ram_size,
Index: qemu/hw/ppc_prep.c
===================================================================
--- qemu.orig/hw/ppc_prep.c	2007-11-19 09:00:42.000000000 +0100
+++ qemu/hw/ppc_prep.c	2007-11-19 09:01:01.000000000 +0100
@@ -38,6 +38,8 @@
 /* SMP is not enabled, for now */
 #define MAX_CPUS 1
 
+#define MAX_IDE_BUS 2
+
 #define BIOS_FILENAME "ppc_rom.bin"
 #define KERNEL_LOAD_ADDR 0x01000000
 #define INITRD_LOAD_ADDR 0x01800000
@@ -548,6 +550,9 @@ static void ppc_prep_init (int ram_size,
     PCIBus *pci_bus;
     qemu_irq *i8259;
     int ppc_boot_device;
+    int index;
+    BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    BlockDriverState *fd[MAX_FD];
 
     sysctrl = qemu_mallocz(sizeof(sysctrl_t));
     if (sysctrl == NULL)
@@ -672,16 +677,37 @@ static void ppc_prep_init (int ram_size,
         }
     }
 
-    for(i = 0; i < 2; i++) {
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+        if (index != -1)
+            hd[i] = drives_table[index].bdrv;
+        else
+            hd[i] = NULL;
+    }
+
+    for(i = 0; i < MAX_IDE_BUS; i++) {
         isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
-                     bs_table[2 * i], bs_table[2 * i + 1]);
+                     hd[2 * i],
+		     hd[2 * i + 1]);
     }
     i8042_init(i8259[1], i8259[12], 0x60);
     DMA_init(1);
     //    AUD_init();
     //    SB16_init();
 
-    fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table);
+    for(i = 0; i < MAX_FD; i++) {
+        index = drive_get_index(IF_FLOPPY, 0, i);
+        if (index != -1)
+            fd[i] = drives_table[index].bdrv;
+        else
+            fd[i] = NULL;
+    }
+    fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
 
     /* Register speaker port */
     register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
Index: qemu/hw/esp.c
===================================================================
--- qemu.orig/hw/esp.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/esp.c	2007-11-19 09:01:01.000000000 +0100
@@ -50,14 +50,11 @@ do { printf("ESP: " fmt , ##args); } whi
 #define ESP_REGS 16
 #define ESP_SIZE (ESP_REGS * 4)
 #define TI_BUFSZ 32
-/* The HBA is ID 7, so for simplicitly limit to 7 devices.  */
-#define ESP_MAX_DEVS      7
 
 typedef struct ESPState ESPState;
 
 struct ESPState {
     qemu_irq irq;
-    BlockDriverState **bd;
     uint8_t rregs[ESP_REGS];
     uint8_t wregs[ESP_REGS];
     int32_t ti_size;
@@ -65,7 +62,7 @@ struct ESPState {
     uint8_t ti_buf[TI_BUFSZ];
     int sense;
     int dma;
-    SCSIDevice *scsi_dev[MAX_DISKS];
+    SCSIDevice *scsi_dev[ESP_MAX_DEVS];
     SCSIDevice *current_dev;
     uint8_t cmdbuf[TI_BUFSZ];
     int cmdlen;
@@ -127,7 +124,7 @@ static int get_cmd(ESPState *s, uint8_t 
         s->async_len = 0;
     }
 
-    if (target >= MAX_DISKS || !s->scsi_dev[target]) {
+    if (target >= ESP_MAX_DEVS || !s->scsi_dev[target]) {
         // No such drive
         s->rregs[4] = STAT_IN;
         s->rregs[5] = INTR_DC;
@@ -579,7 +576,7 @@ void esp_scsi_attach(void *opaque, Block
     s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
 }
 
-void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr,
+void *esp_init(target_phys_addr_t espaddr,
                void *dma_opaque, qemu_irq irq, qemu_irq *reset)
 {
     ESPState *s;
@@ -589,7 +586,6 @@ void *esp_init(BlockDriverState **bd, ta
     if (!s)
         return NULL;
 
-    s->bd = bd;
     s->irq = irq;
     s->dma_opaque = dma_opaque;
 
Index: qemu/hw/realview.c
===================================================================
--- qemu.orig/hw/realview.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/realview.c	2007-11-19 09:01:01.000000000 +0100
@@ -32,6 +32,7 @@ static void realview_init(int ram_size, 
     int done_smc = 0;
     qemu_irq cpu_irq[4];
     int ncpu;
+    int index;
 
     if (!cpu_model)
         cpu_model = "arm926";
@@ -89,7 +90,12 @@ static void realview_init(int ram_size, 
 
     pl110_init(ds, 0x10020000, pic[23], 1);
 
-    pl181_init(0x10005000, sd_bdrv, pic[17], pic[18]);
+    index = drive_get_index(IF_SD, 0, 0);
+    if (index == -1) {
+        fprintf(stderr, "qemu: missing SecureDigital card\n");
+        exit(1);
+    }
+    pl181_init(0x10005000, drives_table[index].bdrv, pic[17], pic[18]);
 
     pl031_init(0x10017000, pic[10]);
 
@@ -97,11 +103,16 @@ static void realview_init(int ram_size, 
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, 3, -1);
     }
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
     scsi_hba = lsi_scsi_init(pci_bus, -1);
-    for (n = 0; n < MAX_DISKS; n++) {
-        if (bs_table[n]) {
-            lsi_scsi_attach(scsi_hba, bs_table[n], n);
-        }
+    for (n = 0; n < LSI_MAX_DEVS; n++) {
+        index = drive_get_index(IF_SCSI, 0, n);
+        if (index == -1)
+            continue;
+        lsi_scsi_attach(scsi_hba, drives_table[index].bdrv, n);
     }
     for(n = 0; n < nb_nics; n++) {
         nd = &nd_table[n];
Index: qemu/hw/sun4m.c
===================================================================
--- qemu.orig/hw/sun4m.c	2007-11-19 09:00:26.000000000 +0100
+++ qemu/hw/sun4m.c	2007-11-19 09:01:01.000000000 +0100
@@ -283,6 +283,8 @@ static void *sun4m_hw_init(const struct 
     qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq,
         *espdma_irq, *ledma_irq;
     qemu_irq *esp_reset, *le_reset;
+    BlockDriverState *fd[MAX_FD];
+    int index;
 
     /* init CPUs */
 
@@ -355,16 +357,29 @@ static void *sun4m_hw_init(const struct 
     slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq],
                        serial_hds[1], serial_hds[0]);
 
-    if (hwdef->fd_base != (target_phys_addr_t)-1)
-        sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd_table);
+    if (hwdef->fd_base != (target_phys_addr_t)-1) {
+        /* there is zero or one floppy drive */
+        fd[1] = fd[0] = NULL;
+        index = drive_get_index(IF_FLOPPY, 0, 0);
+        if (index != -1)
+            fd[0] = drives_table[index].bdrv;
 
-    main_esp = esp_init(bs_table, hwdef->esp_base, espdma, *espdma_irq,
+        sun4m_fdctrl_init(slavio_irq[hwdef->fd_irq], hwdef->fd_base, fd);
+    }
+
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
+
+    main_esp = esp_init(hwdef->esp_base, espdma, *espdma_irq,
                         esp_reset);
 
-    for (i = 0; i < MAX_DISKS; i++) {
-        if (bs_table[i]) {
-            esp_scsi_attach(main_esp, bs_table[i], i);
-        }
+    for (i = 0; i < ESP_MAX_DEVS; i++) {
+        index = drive_get_index(IF_SCSI, 0, i);
+        if (index == -1)
+            continue;
+        esp_scsi_attach(main_esp, drives_table[index].bdrv, i);
     }
 
     slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->power_base,
Index: qemu/hw/versatilepb.c
===================================================================
--- qemu.orig/hw/versatilepb.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/versatilepb.c	2007-11-19 09:01:01.000000000 +0100
@@ -171,6 +171,7 @@ static void versatile_init(int ram_size,
     NICInfo *nd;
     int n;
     int done_smc = 0;
+    int index;
 
     if (!cpu_model)
         cpu_model = "arm926";
@@ -206,11 +207,16 @@ static void versatile_init(int ram_size,
     if (usb_enabled) {
         usb_ohci_init_pci(pci_bus, 3, -1);
     }
+    if (drive_get_max_bus(IF_SCSI) > 0) {
+        fprintf(stderr, "qemu: too many SCSI bus\n");
+        exit(1);
+    }
     scsi_hba = lsi_scsi_init(pci_bus, -1);
-    for (n = 0; n < MAX_DISKS; n++) {
-        if (bs_table[n]) {
-            lsi_scsi_attach(scsi_hba, bs_table[n], n);
-        }
+    for (n = 0; n < LSI_MAX_DEVS; n++) {
+        index = drive_get_index(IF_SCSI, 0, n);
+        if (index == -1)
+            continue;
+        lsi_scsi_attach(scsi_hba, drives_table[index].bdrv, n);
     }
 
     pl011_init(0x101f1000, pic[12], serial_hds[0], PL011_ARM);
@@ -226,7 +232,13 @@ static void versatile_init(int ram_size,
        that includes hardware cursor support from the PL111.  */
     pl110_init(ds, 0x10120000, pic[16], 1);
 
-    pl181_init(0x10005000, sd_bdrv, sic[22], sic[1]);
+    index = drive_get_index(IF_SD, 0, 0);
+    if (index == -1) {
+        fprintf(stderr, "qemu: missing SecureDigital card\n");
+        exit(1);
+    }
+
+    pl181_init(0x10005000, drives_table[index].bdrv, sic[22], sic[1]);
 #if 0
     /* Disabled because there's no way of specifying a block device.  */
     pl181_init(0x1000b000, NULL, sic, 23, 2);
Index: qemu/hw/integratorcp.c
===================================================================
--- qemu.orig/hw/integratorcp.c	2007-11-19 09:00:26.000000000 +0100
+++ qemu/hw/integratorcp.c	2007-11-19 09:01:01.000000000 +0100
@@ -478,6 +478,7 @@ static void integratorcp_init(int ram_si
     uint32_t bios_offset;
     qemu_irq *pic;
     qemu_irq *cpu_pic;
+    int sd;
 
     if (!cpu_model)
         cpu_model = "arm926";
@@ -506,7 +507,12 @@ static void integratorcp_init(int ram_si
     icp_control_init(0xcb000000);
     pl050_init(0x18000000, pic[3], 0);
     pl050_init(0x19000000, pic[4], 1);
-    pl181_init(0x1c000000, sd_bdrv, pic[23], pic[24]);
+    sd = drive_get_index(IF_SD, 0, 0);
+    if (sd == -1) {
+        fprintf(stderr, "qemu: missing SecureDigital card\n");
+        exit(1);
+    }
+    pl181_init(0x1c000000, drives_table[sd].bdrv, pic[23], pic[24]);
     if (nd_table[0].vlan) {
         if (nd_table[0].model == NULL
             || strcmp(nd_table[0].model, "smc91c111") == 0) {
Index: qemu/hw/lsi53c895a.c
===================================================================
--- qemu.orig/hw/lsi53c895a.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/lsi53c895a.c	2007-11-19 09:01:01.000000000 +0100
@@ -151,9 +151,6 @@ do { fprintf(stderr, "lsi_scsi: error: "
 #define PHASE_MI          7
 #define PHASE_MASK        7
 
-/* The HBA is ID 7, so for simplicitly limit to 7 devices.  */
-#define LSI_MAX_DEVS      7
-
 /* Maximum length of MSG IN data.  */
 #define LSI_MAX_MSGIN_LEN 8
 
Index: qemu/hw/nand.c
===================================================================
--- qemu.orig/hw/nand.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/nand.c	2007-11-19 09:01:01.000000000 +0100
@@ -444,14 +444,20 @@ struct nand_flash_s *nand_init(int manf_
 {
     int pagesize;
     struct nand_flash_s *s;
+    int index;
 
     if (nand_flash_ids[chip_id].size == 0) {
         cpu_abort(cpu_single_env, "%s: Unsupported NAND chip ID.\n",
                         __FUNCTION__);
     }
+    index = drive_get_index(IF_MTD, 0, 0);
+    if (index == -1) {
+        cpu_abort(cpu_single_env, "%s: missing MTD device\n",
+                        __FUNCTION__);
+    }
 
     s = (struct nand_flash_s *) qemu_mallocz(sizeof(struct nand_flash_s));
-    s->bdrv = mtd_bdrv;
+    s->bdrv = drives_table[index].bdrv;
     s->manf_id = manf_id;
     s->chip_id = chip_id;
     s->size = nand_flash_ids[s->chip_id].size << 20;
Index: qemu/hw/ppc405_boards.c
===================================================================
--- qemu.orig/hw/ppc405_boards.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/ppc405_boards.c	2007-11-19 09:01:01.000000000 +0100
@@ -197,6 +197,7 @@ static void ref405ep_init (int ram_size,
     int linux_boot;
     int fl_idx, fl_sectors, len;
     int ppc_boot_device = boot_device[0];
+    int index;
 
     /* XXX: fix this */
     ram_bases[0] = 0x00000000;
@@ -223,17 +224,18 @@ static void ref405ep_init (int ram_size,
     bios_offset = sram_offset + sram_size;
     fl_idx = 0;
 #ifdef USE_FLASH_BIOS
-    if (pflash_table[fl_idx] != NULL) {
-        bios_size = bdrv_getlength(pflash_table[fl_idx]);
+    index = drive_get_index(IF_PFLASH, 0, fl_idx);
+    if (index != -1) {
+        bios_size = bdrv_getlength(drives_table[index].bdrv);
         fl_sectors = (bios_size + 65535) >> 16;
 #ifdef DEBUG_BOARD_INIT
         printf("Register parallel flash %d size " ADDRX " at offset %08lx "
                " addr " ADDRX " '%s' %d\n",
                fl_idx, bios_size, bios_offset, -bios_size,
-               bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors);
+               bdrv_get_device_name(drives_table[index].bdrv), fl_sectors);
 #endif
         pflash_register((uint32_t)(-bios_size), bios_offset,
-                        pflash_table[fl_idx], 65536, fl_sectors, 2,
+                        drives_table[index].bdrv, 65536, fl_sectors, 2,
                         0x0001, 0x22DA, 0x0000, 0x0000);
         fl_idx++;
     } else
@@ -519,6 +521,7 @@ static void taihu_405ep_init(int ram_siz
     int linux_boot;
     int fl_idx, fl_sectors;
     int ppc_boot_device = boot_device[0];
+    int index;
 
     /* RAM is soldered to the board so the size cannot be changed */
     ram_bases[0] = 0x00000000;
@@ -536,8 +539,9 @@ static void taihu_405ep_init(int ram_siz
 #endif
     fl_idx = 0;
 #if defined(USE_FLASH_BIOS)
-    if (pflash_table[fl_idx] != NULL) {
-        bios_size = bdrv_getlength(pflash_table[fl_idx]);
+    index = drive_get_index(IF_PFLASH, 0, fl_idx);
+    if (index != -1) {
+        bios_size = bdrv_getlength(drives_table[index].bdrv);
         /* XXX: should check that size is 2MB */
         //        bios_size = 2 * 1024 * 1024;
         fl_sectors = (bios_size + 65535) >> 16;
@@ -545,10 +549,10 @@ static void taihu_405ep_init(int ram_siz
         printf("Register parallel flash %d size " ADDRX " at offset %08lx "
                " addr " ADDRX " '%s' %d\n",
                fl_idx, bios_size, bios_offset, -bios_size,
-               bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors);
+               bdrv_get_device_name(drives_table[index].bdrv), fl_sectors);
 #endif
         pflash_register((uint32_t)(-bios_size), bios_offset,
-                        pflash_table[fl_idx], 65536, fl_sectors, 4,
+                        drives_table[index].bdrv, 65536, fl_sectors, 4,
                         0x0001, 0x22DA, 0x0000, 0x0000);
         fl_idx++;
     } else
@@ -571,8 +575,9 @@ static void taihu_405ep_init(int ram_siz
     }
     bios_offset += bios_size;
     /* Register Linux flash */
-    if (pflash_table[fl_idx] != NULL) {
-        bios_size = bdrv_getlength(pflash_table[fl_idx]);
+    index = drive_get_index(IF_PFLASH, 0, fl_idx);
+    if (index != -1) {
+        bios_size = bdrv_getlength(drives_table[index].bdrv);
         /* XXX: should check that size is 32MB */
         bios_size = 32 * 1024 * 1024;
         fl_sectors = (bios_size + 65535) >> 16;
@@ -580,9 +585,9 @@ static void taihu_405ep_init(int ram_siz
         printf("Register parallel flash %d size " ADDRX " at offset %08lx "
                " addr " ADDRX " '%s'\n",
                fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
-               bdrv_get_device_name(pflash_table[fl_idx]));
+               bdrv_get_device_name(drives_table[index].bdrv));
 #endif
-        pflash_register(0xfc000000, bios_offset, pflash_table[fl_idx],
+        pflash_register(0xfc000000, bios_offset, drives_table[index].bdrv,
                         65536, fl_sectors, 4,
                         0x0001, 0x22DA, 0x0000, 0x0000);
         fl_idx++;
Index: qemu/hw/ppc_chrp.c
===================================================================
--- qemu.orig/hw/ppc_chrp.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/ppc_chrp.c	2007-11-19 09:01:01.000000000 +0100
@@ -32,6 +32,8 @@
 #include "sysemu.h"
 #include "boards.h"
 
+#define MAX_IDE_BUS 2
+
 /* UniN device */
 static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
@@ -81,6 +83,8 @@ static void ppc_core99_init (int ram_siz
     int pic_mem_index, dbdma_mem_index, cuda_mem_index;
     int ide_mem_index[2];
     int ppc_boot_device;
+    int index;
+    BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
 
     linux_boot = (kernel_filename != NULL);
 
@@ -266,11 +270,22 @@ static void ppc_core99_init (int ram_siz
             nd_table[i].model = "ne2k_pci";
         pci_nic_init(pci_bus, &nd_table[i], -1);
     }
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+        if (index != -1)
+            hd[i] = drives_table[index].bdrv;
+        else
+            hd[i] = NULL;
+    }
 #if 1
-    ide_mem_index[0] = pmac_ide_init(&bs_table[0], pic[0x13]);
-    ide_mem_index[1] = pmac_ide_init(&bs_table[2], pic[0x14]);
+    ide_mem_index[0] = pmac_ide_init(&hd[0], pic[0x13]);
+    ide_mem_index[1] = pmac_ide_init(&hd[2], pic[0x14]);
 #else
-    pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
+    pci_cmd646_ide_init(pci_bus, &hd[0], 0);
 #endif
     /* cuda also initialize ADB */
     cuda_init(&cuda_mem_index, pic[0x19]);
Index: qemu/hw/spitz.c
===================================================================
--- qemu.orig/hw/spitz.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/spitz.c	2007-11-19 09:01:01.000000000 +0100
@@ -940,9 +940,14 @@ static void spitz_ssp_attach(struct pxa2
 static void spitz_microdrive_attach(struct pxa2xx_state_s *cpu)
 {
     struct pcmcia_card_s *md;
-    BlockDriverState *bs = bs_table[0];
+    int index;
+    BlockDriverState *bs;
 
-    if (bs && bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
+    index = drive_get_index(IF_IDE, 0, 0);
+    if (index == -1)
+        return;
+    bs = drives_table[index].bdrv;
+    if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
         md = dscm1xxxx_init(bs);
         pxa2xx_pcmcia_attach(cpu->pcmcia[1], md);
     }
Index: qemu/hw/mips_malta.c
===================================================================
--- qemu.orig/hw/mips_malta.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/mips_malta.c	2007-11-19 09:01:01.000000000 +0100
@@ -52,6 +52,8 @@
 #define ENVP_NB_ENTRIES	 	16
 #define ENVP_ENTRY_SIZE	 	256
 
+#define MAX_IDE_BUS 2
+
 extern FILE *logfile;
 
 typedef struct {
@@ -775,6 +777,8 @@ void mips_malta_init (int ram_size, int 
     uint8_t *eeprom_buf;
     i2c_bus *smbus;
     int i;
+    int index;
+    BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -861,8 +865,22 @@ void mips_malta_init (int ram_size, int 
     pci_bus = pci_gt64120_init(i8259);
 
     /* Southbridge */
+
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+        if (index != -1)
+            hd[i] = drives_table[index].bdrv;
+        else
+            hd[i] = NULL;
+    }
+
     piix4_devfn = piix4_init(pci_bus, 80);
-    pci_piix4_ide_init(pci_bus, bs_table, piix4_devfn + 1, i8259);
+    pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1, i8259);
     usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
     smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100);
     eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
Index: qemu/hw/sun4u.c
===================================================================
--- qemu.orig/hw/sun4u.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/sun4u.c	2007-11-19 09:01:01.000000000 +0100
@@ -43,6 +43,7 @@
 #define VGA_BASE             (APB_MEM_BASE + 0x400000ULL)
 #define PROM_FILENAME        "openbios-sparc64"
 #define NVRAM_SIZE           0x2000
+#define MAX_IDE_BUS          2
 
 /* TSC handling */
 
@@ -240,6 +241,9 @@ static void sun4u_init(int ram_size, int
     PCIBus *pci_bus;
     QEMUBH *bh;
     qemu_irq *irq;
+    int index;
+    BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    BlockDriverState *fd[MAX_FD];
 
     linux_boot = (kernel_filename != NULL);
 
@@ -342,11 +346,30 @@ static void sun4u_init(int ram_size, int
     }
 
     irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32);
-    // XXX pci_cmd646_ide_init(pci_bus, bs_table, 1);
-    pci_piix3_ide_init(pci_bus, bs_table, -1, irq);
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+        index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+       if (index != -1)
+           hd[i] = drives_table[index].bdrv;
+       else
+           hd[i] = NULL;
+    }
+
+    // XXX pci_cmd646_ide_init(pci_bus, hd, 1);
+    pci_piix3_ide_init(pci_bus, hd, -1, irq);
     /* FIXME: wire up interrupts.  */
     i8042_init(NULL/*1*/, NULL/*12*/, 0x60);
-    floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table);
+    for(i = 0; i < MAX_FD; i++) {
+        index = drive_get_index(IF_FLOPPY, 0, i);
+       if (index != -1)
+           fd[i] = drives_table[index].bdrv;
+       else
+           fd[i] = NULL;
+    }
+    floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd);
     nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59);
     sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_devices,
                          KERNEL_LOAD_ADDR, kernel_size,
Index: qemu/hw/ppc_oldworld.c
===================================================================
--- qemu.orig/hw/ppc_oldworld.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/ppc_oldworld.c	2007-11-19 09:01:01.000000000 +0100
@@ -33,6 +33,8 @@
 #include "pci.h"
 #include "boards.h"
 
+#define MAX_IDE_BUS 2
+
 /* temporary frame buffer OSI calls for the video.x driver. The right
    solution is to modify the driver to use VGA PCI I/Os */
 /* XXX: to be removed. This is no way related to emulation */
@@ -122,6 +124,8 @@ static void ppc_heathrow_init (int ram_s
     int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
     int ide_mem_index[2];
     int ppc_boot_device;
+    BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+    int index;
 
     linux_boot = (kernel_filename != NULL);
 
@@ -291,10 +295,37 @@ static void ppc_heathrow_init (int ram_s
     }
 
     /* First IDE channel is a CMD646 on the PCI bus */
-    pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
+
+    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+        fprintf(stderr, "qemu: too many IDE bus\n");
+        exit(1);
+    }
+    index = drive_get_index(IF_IDE, 0, 0);
+    if (index == -1)
+        hd[0] = NULL;
+    else
+        hd[0] =  drives_table[index].bdrv;
+    index = drive_get_index(IF_IDE, 0, 1);
+    if (index == -1)
+        hd[1] = NULL;
+    else
+        hd[1] =  drives_table[index].bdrv;
+    hd[3] = hd[2] = NULL;
+    pci_cmd646_ide_init(pci_bus, hd, 0);
+
     /* Second IDE channel is a MAC IDE on the MacIO bus */
+    index = drive_get_index(IF_IDE, 1, 0);
+    if (index == -1)
+        hd[0] = NULL;
+    else
+        hd[0] =  drives_table[index].bdrv;
+    index = drive_get_index(IF_IDE, 1, 1);
+    if (index == -1)
+        hd[1] = NULL;
+    else
+        hd[1] =  drives_table[index].bdrv;
     ide_mem_index[0] = -1;
-    ide_mem_index[1] = pmac_ide_init(&bs_table[2], pic[0x0D]);
+    ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D]);
 
     /* cuda also initialize ADB */
     cuda_init(&cuda_mem_index, pic[0x12]);
Index: qemu/hw/gumstix.c
===================================================================
--- qemu.orig/hw/gumstix.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/gumstix.c	2007-11-19 09:01:01.000000000 +0100
@@ -25,6 +25,7 @@ static void gumstix_common_init(int ram_
                 const char *cpu_model, enum gumstix_model_e model)
 {
     struct pxa2xx_state_s *cpu;
+    int index;
 
     uint32_t gumstix_rom = 0x02000000;
     uint32_t gumstix_ram = 0x08000000;
@@ -37,14 +38,15 @@ static void gumstix_common_init(int ram_
 
     cpu = pxa255_init(gumstix_ram, ds);
 
-    if (pflash_table[0] == NULL) {
+    index = drive_get_index(IF_PFLASH, 0, 0);
+    if (index == -1) {
         fprintf(stderr, "A flash image must be given with the "
                 "'pflash' parameter\n");
         exit(1);
     }
 
     if (!pflash_register(0x00000000, gumstix_ram + PXA2XX_INTERNAL_SIZE,
-            pflash_table[0], 128 * 1024, 128, 2, 0, 0, 0, 0)) {
+            drives_table[index].bdrv, 128 * 1024, 128, 2, 0, 0, 0, 0)) {
         fprintf(stderr, "qemu: Error register flash memory.\n");
         exit(1);
     }
Index: qemu/hw/pxa2xx.c
===================================================================
--- qemu.orig/hw/pxa2xx.c	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/pxa2xx.c	2007-11-19 09:01:01.000000000 +0100
@@ -2036,6 +2036,7 @@ struct pxa2xx_state_s *pxa270_init(unsig
     struct pxa2xx_state_s *s;
     struct pxa2xx_ssp_s *ssp;
     int iomemtype, i;
+    int index;
     s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s));
 
     if (revision && strncmp(revision, "pxa27", 5)) {
@@ -2070,8 +2071,13 @@ struct pxa2xx_state_s *pxa270_init(unsig
 
     s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
 
-    s->mmc = pxa2xx_mmci_init(0x41100000, sd_bdrv, s->pic[PXA2XX_PIC_MMC],
-                              s->dma);
+    index = drive_get_index(IF_SD, 0, 0);
+    if (index == -1) {
+        fprintf(stderr, "qemu: missing SecureDigital device\n");
+        exit(1);
+    }
+    s->mmc = pxa2xx_mmci_init(0x41100000, drives_table[index].bdrv,
+                              s->pic[PXA2XX_PIC_MMC], s->dma);
 
     for (i = 0; pxa270_serial[i].io_base; i ++)
         if (serial_hds[i])
@@ -2160,6 +2166,7 @@ struct pxa2xx_state_s *pxa255_init(unsig
     struct pxa2xx_state_s *s;
     struct pxa2xx_ssp_s *ssp;
     int iomemtype, i;
+    int index;
 
     s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s));
 
@@ -2187,8 +2194,13 @@ struct pxa2xx_state_s *pxa255_init(unsig
 
     s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85);
 
-    s->mmc = pxa2xx_mmci_init(0x41100000, sd_bdrv, s->pic[PXA2XX_PIC_MMC],
-                              s->dma);
+    index = drive_get_index(IF_SD, 0, 0);
+    if (index == -1) {
+        fprintf(stderr, "qemu: missing SecureDigital device\n");
+        exit(1);
+    }
+    s->mmc = pxa2xx_mmci_init(0x41100000, drives_table[index].bdrv,
+                              s->pic[PXA2XX_PIC_MMC], s->dma);
 
     for (i = 0; pxa255_serial[i].io_base; i ++)
         if (serial_hds[i])
Index: qemu/hw/omap.c
===================================================================
--- qemu.orig/hw/omap.c	2007-11-19 09:00:41.000000000 +0100
+++ qemu/hw/omap.c	2007-11-19 09:01:01.000000000 +0100
@@ -4721,6 +4721,7 @@ struct omap_mpu_state_s *omap310_mpu_ini
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
             qemu_mallocz(sizeof(struct omap_mpu_state_s));
     ram_addr_t imif_base, emiff_base;
+    int index;
     
     if (!core)
         core = "ti925t";
@@ -4817,7 +4818,13 @@ struct omap_mpu_state_s *omap310_mpu_ini
     omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
     omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
 
-    s->mmc = omap_mmc_init(0xfffb7800, sd_bdrv, s->irq[1][OMAP_INT_OQN],
+    index = drive_get_index(IF_SD, 0, 0);
+    if (index == -1) {
+        fprintf(stderr, "qemu: missing SecureDigital device\n");
+        exit(1);
+    }
+    s->mmc = omap_mmc_init(0xfffb7800, drives_table[index].bdrv,
+                    s->irq[1][OMAP_INT_OQN],
                     &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck"));
 
     s->mpuio = omap_mpuio_init(0xfffb5000,
Index: qemu/sysemu.h
===================================================================
--- qemu.orig/sysemu.h	2007-11-19 09:00:26.000000000 +0100
+++ qemu/sysemu.h	2007-11-19 09:01:01.000000000 +0100
@@ -116,15 +116,26 @@ extern unsigned int nb_prom_envs;
 #define BIOS_SIZE (4 * 1024 * 1024)
 #endif
 
-#define MAX_DISKS 4
+typedef enum {
+    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD
+} BlockInterfaceType;
+
+typedef struct DriveInfo {
+    BlockDriverState *bdrv;
+    BlockInterfaceType interface;
+    int bus;
+    int unit;
+} DriveInfo;
+
+#define MAX_IDE_DEVS	2
+#define MAX_SCSI_DEVS	7
+#define MAX_DRIVES 32
 
-extern BlockDriverState *bs_table[MAX_DISKS + 1];
-extern BlockDriverState *sd_bdrv;
-extern BlockDriverState *mtd_bdrv;
-
-/* NOR flash devices */
-#define MAX_PFLASH 4
-extern BlockDriverState *pflash_table[MAX_PFLASH];
+int nb_drives;
+DriveInfo drives_table[MAX_DRIVES+1];
+
+extern int drive_get_index(BlockInterfaceType interface, int bus, int unit);
+extern int drive_get_max_bus(BlockInterfaceType interface);
 
 /* serial ports */
 
Index: qemu/hw/pci.h
===================================================================
--- qemu.orig/hw/pci.h	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/pci.h	2007-11-19 09:01:01.000000000 +0100
@@ -97,6 +97,7 @@ PCIBus *pci_bridge_init(PCIBus *bus, int
                         pci_map_irq_fn map_irq, const char *name);
 
 /* lsi53c895a.c */
+#define LSI_MAX_DEVS 7
 void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id);
 void *lsi_scsi_init(PCIBus *bus, int devfn);
 
Index: qemu/hw/sun4m.h
===================================================================
--- qemu.orig/hw/sun4m.h	2007-11-19 09:00:27.000000000 +0100
+++ qemu/hw/sun4m.h	2007-11-19 09:01:01.000000000 +0100
@@ -49,8 +49,9 @@ void *slavio_misc_init(target_phys_addr_
 void slavio_set_power_fail(void *opaque, int power_failing);
 
 /* esp.c */
+#define ESP_MAX_DEVS 7
 void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id);
-void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr,
+void *esp_init(target_phys_addr_t espaddr,
                void *dma_opaque, qemu_irq irq, qemu_irq *reset);
 
 /* cs4231.c */

             reply	other threads:[~2007-11-19  8:28 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-11-19  8:24 Laurent Vivier [this message]
2007-11-25 20:54 ` [Qemu-devel] [PATCH][UPDATE3] Add -drive parameter Blue Swirl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=11954606662783@bull.net \
    --to=laurent.vivier@bull.net \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.