upstream: integrate block changes

This large patch upgrades the block support code to the upstream
version available in ba5e7f82169f32ab8163c707d97c799ca09f8924
dated 2010-08-08

Change-Id: I8b24df0c287e72f6620650a4d6a62e1bb315453e
diff --git a/hw/android_arm.c b/hw/android_arm.c
index d805b0e..6062981 100644
--- a/hw/android_arm.c
+++ b/hw/android_arm.c
@@ -20,6 +20,7 @@
 #include "audio/audio.h"
 #include "arm-misc.h"
 #include "console.h"
+#include "blockdev.h"
 #ifdef CONFIG_MEMCHECK
 #include "memcheck/memcheck_api.h"
 #endif  // CONFIG_MEMCHECK
@@ -120,9 +121,10 @@
     goldfish_audio_init(0xff004000, 0, audio_input_source);
 #endif
     {
-        int  idx = drive_get_index( IF_IDE, 0, 0 );
-        if (idx >= 0)
-            goldfish_mmc_init(0xff005000, 0, drives_table[idx].bdrv);
+        DriveInfo* info = drive_get( IF_IDE, 0, 0 );
+        if (info != NULL) {
+            goldfish_mmc_init(0xff005000, 0, info->bdrv);
+        }
     }
 
     goldfish_memlog_init(0xff006000);
diff --git a/hw/qdev.c b/hw/qdev.c
index 1c8b981..ef6384e 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -30,6 +30,7 @@
 #include "qdev.h"
 #include "sysemu.h"
 #include "monitor.h"
+#include "blockdev.h"
 
 struct DeviceProperty {
     const char *name;
@@ -102,6 +103,119 @@
     return dev;
 }
 
+int qdev_device_help(QemuOpts *opts)
+{
+#ifdef CONFIG_ANDROID  /* Not ready yet, will remove when we properly integrate upstream qdev */
+    return 0;
+#else
+    const char *driver;
+    DeviceInfo *info;
+    Property *prop;
+
+    driver = qemu_opt_get(opts, "driver");
+    if (driver && !strcmp(driver, "?")) {
+        for (info = device_info_list; info != NULL; info = info->next) {
+            if (info->no_user) {
+                continue;       /* not available, don't show */
+            }
+            qdev_print_devinfo(info);
+        }
+        return 1;
+    }
+
+    if (!qemu_opt_get(opts, "?")) {
+        return 0;
+    }
+
+    info = qdev_find_info(NULL, driver);
+    if (!info) {
+        return 0;
+    }
+
+    for (prop = info->props; prop && prop->name; prop++) {
+        /*
+         * TODO Properties without a parser are just for dirty hacks.
+         * qdev_prop_ptr is the only such PropertyInfo.  It's marked
+         * for removal.  This conditional should be removed along with
+         * it.
+         */
+        if (!prop->info->parse) {
+            continue;           /* no way to set it, don't show */
+        }
+        error_printf("%s.%s=%s\n", info->name, prop->name, prop->info->name);
+    }
+    return 1;
+#endif
+}
+
+DeviceState *qdev_device_add(QemuOpts *opts)
+{
+#ifdef CONFIG_ANDROID  /* Not ready yet */
+    return NULL;
+#else
+    const char *driver, *path, *id;
+    DeviceInfo *info;
+    DeviceState *qdev;
+    BusState *bus;
+
+    driver = qemu_opt_get(opts, "driver");
+    if (!driver) {
+        qerror_report(QERR_MISSING_PARAMETER, "driver");
+        return NULL;
+    }
+
+    /* find driver */
+    info = qdev_find_info(NULL, driver);
+    if (!info || info->no_user) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
+        error_printf_unless_qmp("Try with argument '?' for a list.\n");
+        return NULL;
+    }
+
+    /* find bus */
+    path = qemu_opt_get(opts, "bus");
+    if (path != NULL) {
+        bus = qbus_find(path);
+        if (!bus) {
+            return NULL;
+        }
+        if (bus->info != info->bus_info) {
+            qerror_report(QERR_BAD_BUS_FOR_DEVICE,
+                           driver, bus->info->name);
+            return NULL;
+        }
+    } else {
+        bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
+        if (!bus) {
+            qerror_report(QERR_NO_BUS_FOR_DEVICE,
+                           info->name, info->bus_info->name);
+            return NULL;
+        }
+    }
+    if (qdev_hotplug && !bus->allow_hotplug) {
+        qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
+        return NULL;
+    }
+
+    /* create device, set properties */
+    qdev = qdev_create_from_info(bus, info);
+    id = qemu_opts_id(opts);
+    if (id) {
+        qdev->id = id;
+    }
+    if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
+        qdev_free(qdev);
+        return NULL;
+    }
+    if (qdev_init(qdev) < 0) {
+        qerror_report(QERR_DEVICE_INIT_FAILED, driver);
+        return NULL;
+    }
+    qdev->opts = opts;
+    return qdev;
+#endif
+}
+
 /* Initialize a device.  Device properties should be set before calling
    this function.  IRQs and MMIO regions should be connected/mapped after
    calling this function.  */
@@ -280,13 +394,13 @@
 BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type)
 {
     int unit = next_block_unit[type]++;
-    int index;
+    DriveInfo* info;
 
-    index = drive_get_index(type, 0, unit);
-    if (index == -1) {
+    info = drive_get(type, 0, unit);
+    if (info == NULL) {
         return NULL;
     }
-    return drives_table[index].bdrv;
+    return info->bdrv;
 }
 
 BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
@@ -309,14 +423,14 @@
 {
    int bus = next_scsi_bus++;
    int unit;
-   int index;
+   DriveInfo* info;
 
    for (unit = 0; unit < MAX_SCSI_DEVS; unit++) {
-       index = drive_get_index(IF_SCSI, bus, unit);
-       if (index == -1) {
+       info = drive_get(IF_SCSI, bus, unit);
+       if (info == NULL) {
            continue;
        }
-       attach(host, drives_table[index].bdrv, unit);
+       attach(host, info->bdrv, unit);
    }
 }
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index a0485db..3d3946a 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -15,6 +15,7 @@
 
 #include <qemu-common.h>
 #include <sysemu.h>
+#include "blockdev.h"
 //#define DEBUG_SCSI
 
 #ifdef DEBUG_SCSI
@@ -219,7 +220,7 @@
 
 static int scsi_handle_write_error(SCSIRequest *r, int error)
 {
-    BlockInterfaceErrorAction action = drive_get_onerror(r->dev->bdrv);
+    BlockErrorAction action = bdrv_get_on_error(r->dev->bdrv, 0);
 
     if (action == BLOCK_ERR_IGNORE)
         return 0;
@@ -318,7 +319,7 @@
     while (r) {
         if (r->status & SCSI_REQ_STATUS_RETRY) {
             r->status &= ~SCSI_REQ_STATUS_RETRY;
-            scsi_write_request(r); 
+            scsi_write_request(r);
         }
         r = r->next;
     }
@@ -948,9 +949,11 @@
     if (nb_sectors)
         nb_sectors--;
     s->max_lba = nb_sectors;
+#if 0
     strncpy(s->drive_serial_str, drive_get_serial(s->bdrv),
             sizeof(s->drive_serial_str));
     if (strlen(s->drive_serial_str) == 0)
+#endif
         pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0");
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
     d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 3a3eb4a..16e482e 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -551,7 +551,7 @@
     s = qemu_mallocz(sizeof(MSDState));
 
     bdrv = bdrv_new("usb");
-    if (bdrv_open2(bdrv, filename, 0, drv) < 0)
+    if (bdrv_open(bdrv, filename, 0, drv) < 0)
         goto fail;
     s->bs = bdrv;