summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2010-06-14 10:33:36 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2010-06-14 10:33:36 -0500
commita4673e276248ada38f40d39191a197e7e35d3f8b (patch)
tree4ecdac95fb7bb86eefc08ee38ca229c4d89e02e0
parenta2da0395c12bd2b26e2180d735c83988ff66a559 (diff)
parent653dbec7c97cb51d19636423902719e5850da265 (diff)
downloadfocaccia-qemu-a4673e276248ada38f40d39191a197e7e35d3f8b.tar.gz
focaccia-qemu-a4673e276248ada38f40d39191a197e7e35d3f8b.zip
Merge remote branch 'kwolf/for-anthony' into staging
Conflicts:
	hw/pc.c
-rw-r--r--Makefile.objs2
-rw-r--r--block.c91
-rw-r--r--block.h1
-rw-r--r--block/raw-posix.c20
-rw-r--r--blockdev.c600
-rw-r--r--blockdev.h71
-rw-r--r--hw/acpi_piix4.c1
-rw-r--r--hw/apb_pci.c1
-rw-r--r--hw/device-hotplug.c4
-rw-r--r--hw/fdc.c1
-rw-r--r--hw/fdc.h2
-rw-r--r--hw/ide/cmd646.c4
-rw-r--r--hw/ide/core.c108
-rw-r--r--hw/ide/internal.h13
-rw-r--r--hw/ide/isa.c2
-rw-r--r--hw/ide/macio.c2
-rw-r--r--hw/ide/microdrive.c3
-rw-r--r--hw/ide/mmio.c2
-rw-r--r--hw/ide/piix.c4
-rw-r--r--hw/ide/qdev.c21
-rw-r--r--hw/lan9118.c1
-rw-r--r--hw/nand.c3
-rw-r--r--hw/omap2.c2
-rw-r--r--hw/onenand.c3
-rw-r--r--hw/parallel.c1
-rw-r--r--hw/pc.c1
-rw-r--r--hw/pc_piix.c1
-rw-r--r--hw/pci-hotplug.c2
-rw-r--r--hw/pcmcia.h2
-rw-r--r--hw/pl181.c1
-rw-r--r--hw/qdev-properties.c12
-rw-r--r--hw/qdev.c6
-rw-r--r--hw/qdev.h6
-rw-r--r--hw/scsi-bus.c1
-rw-r--r--hw/scsi-disk.c26
-rw-r--r--hw/scsi-generic.c1
-rw-r--r--hw/serial.c1
-rw-r--r--hw/ssi-sd.c1
-rw-r--r--hw/usb-hid.c1
-rw-r--r--hw/usb-msd.c4
-rw-r--r--hw/virtio-blk.c9
-rw-r--r--hw/virtio-pci.c1
-rw-r--r--monitor.c104
-rw-r--r--qemu-char.c1
-rw-r--r--qemu-io.c4
-rw-r--r--savevm.c2
-rw-r--r--sysemu.h52
-rw-r--r--vl.c499
48 files changed, 916 insertions, 785 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 2dad0f941a..2bfb6d1808 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -44,7 +44,7 @@ fsdev-obj-$(CONFIG_LINUX) += $(addprefix fsdev/, $(fsdev-nested-y))
 # system emulation, i.e. a single QEMU executable should support all
 # CPUs and machines.
 
-common-obj-y = $(block-obj-y)
+common-obj-y = $(block-obj-y) blockdev.o
 common-obj-y += $(net-obj-y)
 common-obj-y += $(qobject-obj-y)
 common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
diff --git a/block.c b/block.c
index 39724c17d3..cacf11bd99 100644
--- a/block.c
+++ b/block.c
@@ -331,8 +331,8 @@ static BlockDriver *find_image_format(const char *filename)
     if (ret < 0)
         return NULL;
 
-    /* Return the raw BlockDriver * to scsi-generic devices */
-    if (bs->sg) {
+    /* Return the raw BlockDriver * to scsi-generic devices or empty drives */
+    if (bs->sg || !bdrv_is_inserted(bs)) {
         bdrv_delete(bs);
         return bdrv_find_format("raw");
     }
@@ -522,7 +522,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
             bdrv_delete(bs1);
             return ret;
         }
-        total_size = bdrv_getlength(bs1) >> BDRV_SECTOR_BITS;
+        total_size = bdrv_getlength(bs1) & BDRV_SECTOR_MASK;
 
         if (bs1->drv && bs1->drv->protocol_name)
             is_protocol = 1;
@@ -541,7 +541,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
         bdrv_qcow2 = bdrv_find_format("qcow2");
         options = parse_option_parameters("", bdrv_qcow2->create_options, NULL);
 
-        set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size * 512);
+        set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size);
         set_option_parameter(options, BLOCK_OPT_BACKING_FILE, backing_filename);
         if (drv) {
             set_option_parameter(options, BLOCK_OPT_BACKING_FMT,
@@ -648,6 +648,15 @@ void bdrv_close(BlockDriverState *bs)
     }
 }
 
+void bdrv_close_all(void)
+{
+    BlockDriverState *bs;
+
+    QTAILQ_FOREACH(bs, &bdrv_states, list) {
+        bdrv_close(bs);
+    }
+}
+
 void bdrv_delete(BlockDriverState *bs)
 {
     /* remove from list, if necessary */
@@ -684,7 +693,7 @@ int bdrv_commit(BlockDriverState *bs)
     int64_t i, total_sectors;
     int n, j, ro, open_flags;
     int ret = 0, rw_ret = 0;
-    unsigned char sector[512];
+    unsigned char sector[BDRV_SECTOR_SIZE];
     char filename[1024];
     BlockDriverState *bs_rw, *bs_ro;
 
@@ -824,7 +833,8 @@ static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
 static int bdrv_check_request(BlockDriverState *bs, int64_t sector_num,
                               int nb_sectors)
 {
-    return bdrv_check_byte_request(bs, sector_num * 512, nb_sectors * 512);
+    return bdrv_check_byte_request(bs, sector_num * BDRV_SECTOR_SIZE,
+                                   nb_sectors * BDRV_SECTOR_SIZE);
 }
 
 /* return < 0 if error. See bdrv_write() for the return codes */
@@ -1059,7 +1069,7 @@ struct partition {
 static int guess_disk_lchs(BlockDriverState *bs,
                            int *pcylinders, int *pheads, int *psectors)
 {
-    uint8_t buf[512];
+    uint8_t buf[BDRV_SECTOR_SIZE];
     int ret, i, heads, sectors, cylinders;
     struct partition *p;
     uint32_t nr_sects;
@@ -1535,7 +1545,7 @@ static QObject* bdrv_info_stats_bs(BlockDriverState *bs)
                              "} }",
                              bs->rd_bytes, bs->wr_bytes,
                              bs->rd_ops, bs->wr_ops,
-                             bs->wr_highest_sector * 512);
+                             bs->wr_highest_sector * (long)BDRV_SECTOR_SIZE);
     dict  = qobject_to_qdict(res);
 
     if (*bs->device_name) {
@@ -1621,9 +1631,11 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
     BlockDriver *drv = bs->drv;
     if (!drv)
         return -ENOMEDIUM;
-    if (!drv->bdrv_save_vmstate)
-        return -ENOTSUP;
-    return drv->bdrv_save_vmstate(bs, buf, pos, size);
+    if (drv->bdrv_save_vmstate)
+        return drv->bdrv_save_vmstate(bs, buf, pos, size);
+    if (bs->file)
+        return bdrv_save_vmstate(bs->file, buf, pos, size);
+    return -ENOTSUP;
 }
 
 int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
@@ -1632,9 +1644,11 @@ int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
     BlockDriver *drv = bs->drv;
     if (!drv)
         return -ENOMEDIUM;
-    if (!drv->bdrv_load_vmstate)
-        return -ENOTSUP;
-    return drv->bdrv_load_vmstate(bs, buf, pos, size);
+    if (drv->bdrv_load_vmstate)
+        return drv->bdrv_load_vmstate(bs, buf, pos, size);
+    if (bs->file)
+        return bdrv_load_vmstate(bs->file, buf, pos, size);
+    return -ENOTSUP;
 }
 
 void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
@@ -1658,20 +1672,37 @@ int bdrv_snapshot_create(BlockDriverState *bs,
     BlockDriver *drv = bs->drv;
     if (!drv)
         return -ENOMEDIUM;
-    if (!drv->bdrv_snapshot_create)
-        return -ENOTSUP;
-    return drv->bdrv_snapshot_create(bs, sn_info);
+    if (drv->bdrv_snapshot_create)
+        return drv->bdrv_snapshot_create(bs, sn_info);
+    if (bs->file)
+        return bdrv_snapshot_create(bs->file, sn_info);
+    return -ENOTSUP;
 }
 
 int bdrv_snapshot_goto(BlockDriverState *bs,
                        const char *snapshot_id)
 {
     BlockDriver *drv = bs->drv;
+    int ret, open_ret;
+
     if (!drv)
         return -ENOMEDIUM;
-    if (!drv->bdrv_snapshot_goto)
-        return -ENOTSUP;
-    return drv->bdrv_snapshot_goto(bs, snapshot_id);
+    if (drv->bdrv_snapshot_goto)
+        return drv->bdrv_snapshot_goto(bs, snapshot_id);
+
+    if (bs->file) {
+        drv->bdrv_close(bs);
+        ret = bdrv_snapshot_goto(bs->file, snapshot_id);
+        open_ret = drv->bdrv_open(bs, bs->open_flags);
+        if (open_ret < 0) {
+            bdrv_delete(bs->file);
+            bs->drv = NULL;
+            return open_ret;
+        }
+        return ret;
+    }
+
+    return -ENOTSUP;
 }
 
 int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
@@ -1679,9 +1710,11 @@ int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
     BlockDriver *drv = bs->drv;
     if (!drv)
         return -ENOMEDIUM;
-    if (!drv->bdrv_snapshot_delete)
-        return -ENOTSUP;
-    return drv->bdrv_snapshot_delete(bs, snapshot_id);
+    if (drv->bdrv_snapshot_delete)
+        return drv->bdrv_snapshot_delete(bs, snapshot_id);
+    if (bs->file)
+        return bdrv_snapshot_delete(bs->file, snapshot_id);
+    return -ENOTSUP;
 }
 
 int bdrv_snapshot_list(BlockDriverState *bs,
@@ -1690,9 +1723,11 @@ int bdrv_snapshot_list(BlockDriverState *bs,
     BlockDriver *drv = bs->drv;
     if (!drv)
         return -ENOMEDIUM;
-    if (!drv->bdrv_snapshot_list)
-        return -ENOTSUP;
-    return drv->bdrv_snapshot_list(bs, psn_info);
+    if (drv->bdrv_snapshot_list)
+        return drv->bdrv_snapshot_list(bs, psn_info);
+    if (bs->file)
+        return bdrv_snapshot_list(bs->file, psn_info);
+    return -ENOTSUP;
 }
 
 #define NB_SUFFIXES 4
@@ -2197,7 +2232,7 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
 
     async_ret = NOT_DONE;
     iov.iov_base = (void *)buf;
-    iov.iov_len = nb_sectors * 512;
+    iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
     qemu_iovec_init_external(&qiov, &iov, 1);
     acb = bdrv_aio_readv(bs, sector_num, &qiov, nb_sectors,
         bdrv_rw_em_cb, &async_ret);
@@ -2228,7 +2263,7 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
 
     async_ret = NOT_DONE;
     iov.iov_base = (void *)buf;
-    iov.iov_len = nb_sectors * 512;
+    iov.iov_len = nb_sectors * BDRV_SECTOR_SIZE;
     qemu_iovec_init_external(&qiov, &iov, 1);
     acb = bdrv_aio_writev(bs, sector_num, &qiov, nb_sectors,
         bdrv_rw_em_cb, &async_ret);
diff --git a/block.h b/block.h
index 756670d22f..25744b134f 100644
--- a/block.h
+++ b/block.h
@@ -123,6 +123,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
 /* Ensure contents are flushed to disk.  */
 void bdrv_flush(BlockDriverState *bs);
 void bdrv_flush_all(void);
+void bdrv_close_all(void);
 
 int bdrv_has_zero_init(BlockDriverState *bs);
 int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 7541ed2abe..3f0701b8a4 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -392,8 +392,9 @@ static int raw_read(BlockDriverState *bs, int64_t sector_num,
 {
     int ret;
 
-    ret = raw_pread(bs, sector_num * 512, buf, nb_sectors * 512);
-    if (ret == (nb_sectors * 512))
+    ret = raw_pread(bs, sector_num * BDRV_SECTOR_SIZE, buf,
+                    nb_sectors * BDRV_SECTOR_SIZE);
+    if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
         ret = 0;
     return ret;
 }
@@ -480,8 +481,9 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
     int ret;
-    ret = raw_pwrite(bs, sector_num * 512, buf, nb_sectors * 512);
-    if (ret == (nb_sectors * 512))
+    ret = raw_pwrite(bs, sector_num * BDRV_SECTOR_SIZE, buf,
+                     nb_sectors * BDRV_SECTOR_SIZE);
+    if (ret == (nb_sectors * BDRV_SECTOR_SIZE))
         ret = 0;
     return ret;
 }
@@ -494,7 +496,7 @@ static int qiov_is_aligned(QEMUIOVector *qiov)
     int i;
 
     for (i = 0; i < qiov->niov; i++) {
-        if ((uintptr_t) qiov->iov[i].iov_base % 512) {
+        if ((uintptr_t) qiov->iov[i].iov_base % BDRV_SECTOR_SIZE) {
             return 0;
         }
     }
@@ -703,7 +705,7 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
     /* Read out options */
     while (options && options->name) {
         if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            total_size = options->value.n / 512;
+            total_size = options->value.n / BDRV_SECTOR_SIZE;
         }
         options++;
     }
@@ -713,7 +715,7 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
     if (fd < 0) {
         result = -errno;
     } else {
-        if (ftruncate(fd, total_size * 512) != 0) {
+        if (ftruncate(fd, total_size * BDRV_SECTOR_SIZE) != 0) {
             result = -errno;
         }
         if (close(fd) != 0) {
@@ -976,7 +978,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
     /* Read out options */
     while (options && options->name) {
         if (!strcmp(options->name, "size")) {
-            total_size = options->value.n / 512;
+            total_size = options->value.n / BDRV_SECTOR_SIZE;
         }
         options++;
     }
@@ -989,7 +991,7 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
         ret = -errno;
     else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode))
         ret = -ENODEV;
-    else if (lseek(fd, 0, SEEK_END) < total_size * 512)
+    else if (lseek(fd, 0, SEEK_END) < total_size * BDRV_SECTOR_SIZE)
         ret = -ENOSPC;
 
     close(fd);
diff --git a/blockdev.c b/blockdev.c
new file mode 100644
index 0000000000..642ce756ac
--- /dev/null
+++ b/blockdev.c
@@ -0,0 +1,600 @@
+/*
+ * QEMU host block devices
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later.  See the COPYING file in the top-level directory.
+ */
+
+#include "block.h"
+#include "blockdev.h"
+#include "monitor.h"
+#include "qerror.h"
+#include "qemu-option.h"
+#include "qemu-config.h"
+#include "sysemu.h"
+
+struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives);
+
+QemuOpts *drive_add(const char *file, const char *fmt, ...)
+{
+    va_list ap;
+    char optstr[1024];
+    QemuOpts *opts;
+
+    va_start(ap, fmt);
+    vsnprintf(optstr, sizeof(optstr), fmt, ap);
+    va_end(ap);
+
+    opts = qemu_opts_parse(&qemu_drive_opts, optstr, 0);
+    if (!opts) {
+        return NULL;
+    }
+    if (file)
+        qemu_opt_set(opts, "file", file);
+    return opts;
+}
+
+DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
+{
+    DriveInfo *dinfo;
+
+    /* seek interface, bus and unit */
+
+    QTAILQ_FOREACH(dinfo, &drives, next) {
+        if (dinfo->type == type &&
+	    dinfo->bus == bus &&
+	    dinfo->unit == unit)
+            return dinfo;
+    }
+
+    return NULL;
+}
+
+DriveInfo *drive_get_by_id(const char *id)
+{
+    DriveInfo *dinfo;
+
+    QTAILQ_FOREACH(dinfo, &drives, next) {
+        if (strcmp(id, dinfo->id))
+            continue;
+        return dinfo;
+    }
+    return NULL;
+}
+
+int drive_get_max_bus(BlockInterfaceType type)
+{
+    int max_bus;
+    DriveInfo *dinfo;
+
+    max_bus = -1;
+    QTAILQ_FOREACH(dinfo, &drives, next) {
+        if(dinfo->type == type &&
+           dinfo->bus > max_bus)
+            max_bus = dinfo->bus;
+    }
+    return max_bus;
+}
+
+const char *drive_get_serial(BlockDriverState *bdrv)
+{
+    DriveInfo *dinfo;
+
+    QTAILQ_FOREACH(dinfo, &drives, next) {
+        if (dinfo->bdrv == bdrv)
+            return dinfo->serial;
+    }
+
+    return "\0";
+}
+
+BlockInterfaceErrorAction drive_get_on_error(
+    BlockDriverState *bdrv, int is_read)
+{
+    DriveInfo *dinfo;
+
+    QTAILQ_FOREACH(dinfo, &drives, next) {
+        if (dinfo->bdrv == bdrv)
+            return is_read ? dinfo->on_read_error : dinfo->on_write_error;
+    }
+
+    return is_read ? BLOCK_ERR_REPORT : BLOCK_ERR_STOP_ENOSPC;
+}
+
+static void bdrv_format_print(void *opaque, const char *name)
+{
+    fprintf(stderr, " %s", name);
+}
+
+void drive_uninit(DriveInfo *dinfo)
+{
+    qemu_opts_del(dinfo->opts);
+    bdrv_delete(dinfo->bdrv);
+    QTAILQ_REMOVE(&drives, dinfo, next);
+    qemu_free(dinfo);
+}
+
+static int parse_block_error_action(const char *buf, int is_read)
+{
+    if (!strcmp(buf, "ignore")) {
+        return BLOCK_ERR_IGNORE;
+    } else if (!is_read && !strcmp(buf, "enospc")) {
+        return BLOCK_ERR_STOP_ENOSPC;
+    } else if (!strcmp(buf, "stop")) {
+        return BLOCK_ERR_STOP_ANY;
+    } else if (!strcmp(buf, "report")) {
+        return BLOCK_ERR_REPORT;
+    } else {
+        fprintf(stderr, "qemu: '%s' invalid %s error action\n",
+            buf, is_read ? "read" : "write");
+        return -1;
+    }
+}
+
+DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
+{
+    const char *buf;
+    const char *file = NULL;
+    char devname[128];
+    const char *serial;
+    const char *mediastr = "";
+    BlockInterfaceType type;
+    enum { MEDIA_DISK, MEDIA_CDROM } media;
+    int bus_id, unit_id;
+    int cyls, heads, secs, translation;
+    BlockDriver *drv = NULL;
+    int max_devs;
+    int index;
+    int ro = 0;
+    int bdrv_flags = 0;
+    int on_read_error, on_write_error;
+    const char *devaddr;
+    DriveInfo *dinfo;
+    int snapshot = 0;
+    int ret;
+
+    *fatal_error = 1;
+
+    translation = BIOS_ATA_TRANSLATION_AUTO;
+
+    if (default_to_scsi) {
+        type = IF_SCSI;
+        max_devs = MAX_SCSI_DEVS;
+        pstrcpy(devname, sizeof(devname), "scsi");
+    } else {
+        type = IF_IDE;
+        max_devs = MAX_IDE_DEVS;
+        pstrcpy(devname, sizeof(devname), "ide");
+    }
+    media = MEDIA_DISK;
+
+    /* extract parameters */
+    bus_id  = qemu_opt_get_number(opts, "bus", 0);
+    unit_id = qemu_opt_get_number(opts, "unit", -1);
+    index   = qemu_opt_get_number(opts, "index", -1);
+
+    cyls  = qemu_opt_get_number(opts, "cyls", 0);
+    heads = qemu_opt_get_number(opts, "heads", 0);
+    secs  = qemu_opt_get_number(opts, "secs", 0);
+
+    snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
+    ro = qemu_opt_get_bool(opts, "readonly", 0);
+
+    file = qemu_opt_get(opts, "file");
+    serial = qemu_opt_get(opts, "serial");
+
+    if ((buf = qemu_opt_get(opts, "if")) != NULL) {
+        pstrcpy(devname, sizeof(devname), buf);
+        if (!strcmp(buf, "ide")) {
+	    type = IF_IDE;
+            max_devs = MAX_IDE_DEVS;
+        } else if (!strcmp(buf, "scsi")) {
+	    type = IF_SCSI;
+            max_devs = MAX_SCSI_DEVS;
+        } else if (!strcmp(buf, "floppy")) {
+	    type = IF_FLOPPY;
+            max_devs = 0;
+        } else if (!strcmp(buf, "pflash")) {
+	    type = IF_PFLASH;
+            max_devs = 0;
+	} else if (!strcmp(buf, "mtd")) {
+	    type = IF_MTD;
+            max_devs = 0;
+	} else if (!strcmp(buf, "sd")) {
+	    type = IF_SD;
+            max_devs = 0;
+        } else if (!strcmp(buf, "virtio")) {
+            type = IF_VIRTIO;
+            max_devs = 0;
+	} else if (!strcmp(buf, "xen")) {
+	    type = IF_XEN;
+            max_devs = 0;
+	} else if (!strcmp(buf, "none")) {
+	    type = IF_NONE;
+            max_devs = 0;
+	} else {
+            fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf);
+            return NULL;
+	}
+    }
+
+    if (cyls || heads || secs) {
+        if (cyls < 1 || (type == IF_IDE && cyls > 16383)) {
+            fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf);
+	    return NULL;
+	}
+        if (heads < 1 || (type == IF_IDE && heads > 16)) {
+            fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf);
+	    return NULL;
+	}
+        if (secs < 1 || (type == IF_IDE && secs > 63)) {
+            fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf);
+	    return NULL;
+	}
+    }
+
+    if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
+        if (!cyls) {
+            fprintf(stderr,
+                    "qemu: '%s' trans must be used with cyls,heads and secs\n",
+                    buf);
+            return NULL;
+        }
+        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", buf);
+	    return NULL;
+	}
+    }
+
+    if ((buf = qemu_opt_get(opts, "media")) != NULL) {
+        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", buf);
+	        return NULL;
+            }
+	    media = MEDIA_CDROM;
+	} else {
+	    fprintf(stderr, "qemu: '%s' invalid media\n", buf);
+	    return NULL;
+	}
+    }
+
+    if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
+        if (!strcmp(buf, "off") || !strcmp(buf, "none")) {
+            bdrv_flags |= BDRV_O_NOCACHE;
+        } else if (!strcmp(buf, "writeback")) {
+            bdrv_flags |= BDRV_O_CACHE_WB;
+        } else if (!strcmp(buf, "unsafe")) {
+            bdrv_flags |= BDRV_O_CACHE_WB;
+            bdrv_flags |= BDRV_O_NO_FLUSH;
+        } else if (!strcmp(buf, "writethrough")) {
+            /* this is the default */
+        } else {
+           fprintf(stderr, "qemu: invalid cache option\n");
+           return NULL;
+        }
+    }
+
+#ifdef CONFIG_LINUX_AIO
+    if ((buf = qemu_opt_get(opts, "aio")) != NULL) {
+        if (!strcmp(buf, "native")) {
+            bdrv_flags |= BDRV_O_NATIVE_AIO;
+        } else if (!strcmp(buf, "threads")) {
+            /* this is the default */
+        } else {
+           fprintf(stderr, "qemu: invalid aio option\n");
+           return NULL;
+        }
+    }
+#endif
+
+    if ((buf = qemu_opt_get(opts, "format")) != NULL) {
+       if (strcmp(buf, "?") == 0) {
+            fprintf(stderr, "qemu: Supported formats:");
+            bdrv_iterate_format(bdrv_format_print, NULL);
+            fprintf(stderr, "\n");
+	    return NULL;
+        }
+        drv = bdrv_find_whitelisted_format(buf);
+        if (!drv) {
+            fprintf(stderr, "qemu: '%s' invalid format\n", buf);
+            return NULL;
+        }
+    }
+
+    on_write_error = BLOCK_ERR_STOP_ENOSPC;
+    if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
+        if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
+            fprintf(stderr, "werror is no supported by this format\n");
+            return NULL;
+        }
+
+        on_write_error = parse_block_error_action(buf, 0);
+        if (on_write_error < 0) {
+            return NULL;
+        }
+    }
+
+    on_read_error = BLOCK_ERR_REPORT;
+    if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
+        if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
+            fprintf(stderr, "rerror is no supported by this format\n");
+            return NULL;
+        }
+
+        on_read_error = parse_block_error_action(buf, 1);
+        if (on_read_error < 0) {
+            return NULL;
+        }
+    }
+
+    if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
+        if (type != IF_VIRTIO) {
+            fprintf(stderr, "addr is not supported\n");
+            return NULL;
+        }
+    }
+
+    /* compute bus and unit according index */
+
+    if (index != -1) {
+        if (bus_id != 0 || unit_id != -1) {
+            fprintf(stderr,
+                    "qemu: index cannot be used with bus and unit\n");
+            return NULL;
+        }
+        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(type, bus_id, unit_id) != NULL) {
+           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: unit %d too big (max is %d)\n",
+                unit_id, max_devs - 1);
+        return NULL;
+    }
+
+    /*
+     * ignore multiple definitions
+     */
+
+    if (drive_get(type, bus_id, unit_id) != NULL) {
+        *fatal_error = 0;
+        return NULL;
+    }
+
+    /* init */
+
+    dinfo = qemu_mallocz(sizeof(*dinfo));
+    if ((buf = qemu_opts_id(opts)) != NULL) {
+        dinfo->id = qemu_strdup(buf);
+    } else {
+        /* no id supplied -> create one */
+        dinfo->id = qemu_mallocz(32);
+        if (type == IF_IDE || type == IF_SCSI)
+            mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
+        if (max_devs)
+            snprintf(dinfo->id, 32, "%s%i%s%i",
+                     devname, bus_id, mediastr, unit_id);
+        else
+            snprintf(dinfo->id, 32, "%s%s%i",
+                     devname, mediastr, unit_id);
+    }
+    dinfo->bdrv = bdrv_new(dinfo->id);
+    dinfo->devaddr = devaddr;
+    dinfo->type = type;
+    dinfo->bus = bus_id;
+    dinfo->unit = unit_id;
+    dinfo->on_read_error = on_read_error;
+    dinfo->on_write_error = on_write_error;
+    dinfo->opts = opts;
+    if (serial)
+        strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1);
+    QTAILQ_INSERT_TAIL(&drives, dinfo, next);
+
+    switch(type) {
+    case IF_IDE:
+    case IF_SCSI:
+    case IF_XEN:
+    case IF_NONE:
+        switch(media) {
+	case MEDIA_DISK:
+            if (cyls != 0) {
+                bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs);
+                bdrv_set_translation_hint(dinfo->bdrv, translation);
+            }
+	    break;
+	case MEDIA_CDROM:
+            bdrv_set_type_hint(dinfo->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(dinfo->bdrv, BDRV_TYPE_FLOPPY);
+        break;
+    case IF_PFLASH:
+    case IF_MTD:
+        break;
+    case IF_VIRTIO:
+        /* add virtio block device */
+        opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
+        qemu_opt_set(opts, "driver", "virtio-blk-pci");
+        qemu_opt_set(opts, "drive", dinfo->id);
+        if (devaddr)
+            qemu_opt_set(opts, "addr", devaddr);
+        break;
+    case IF_COUNT:
+        abort();
+    }
+    if (!file) {
+        *fatal_error = 0;
+        return NULL;
+    }
+    if (snapshot) {
+        /* always use cache=unsafe with snapshot */
+        bdrv_flags &= ~BDRV_O_CACHE_MASK;
+        bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
+    }
+
+    if (media == MEDIA_CDROM) {
+        /* CDROM is fine for any interface, don't check.  */
+        ro = 1;
+    } else if (ro == 1) {
+        if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
+            fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n");
+            return NULL;
+        }
+    }
+
+    bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
+
+    ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
+    if (ret < 0) {
+        fprintf(stderr, "qemu: could not open disk image %s: %s\n",
+                        file, strerror(-ret));
+        return NULL;
+    }
+
+    if (bdrv_key_required(dinfo->bdrv))
+        autostart = 0;
+    *fatal_error = 0;
+    return dinfo;
+}
+
+void do_commit(Monitor *mon, const QDict *qdict)
+{
+    int all_devices;
+    DriveInfo *dinfo;
+    const char *device = qdict_get_str(qdict, "device");
+
+    all_devices = !strcmp(device, "all");
+    QTAILQ_FOREACH(dinfo, &drives, next) {
+        if (!all_devices)
+            if (strcmp(bdrv_get_device_name(dinfo->bdrv), device))
+                continue;
+        bdrv_commit(dinfo->bdrv);
+    }
+}
+
+static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
+{
+    if (bdrv_is_inserted(bs)) {
+        if (!force) {
+            if (!bdrv_is_removable(bs)) {
+                qerror_report(QERR_DEVICE_NOT_REMOVABLE,
+                               bdrv_get_device_name(bs));
+                return -1;
+            }
+            if (bdrv_is_locked(bs)) {
+                qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+                return -1;
+            }
+        }
+        bdrv_close(bs);
+    }
+    return 0;
+}
+
+int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    BlockDriverState *bs;
+    int force = qdict_get_int(qdict, "force");
+    const char *filename = qdict_get_str(qdict, "device");
+
+    bs = bdrv_find(filename);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, filename);
+        return -1;
+    }
+    return eject_device(mon, bs, force);
+}
+
+int do_block_set_passwd(Monitor *mon, const QDict *qdict,
+                        QObject **ret_data)
+{
+    BlockDriverState *bs;
+    int err;
+
+    bs = bdrv_find(qdict_get_str(qdict, "device"));
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
+        return -1;
+    }
+
+    err = bdrv_set_key(bs, qdict_get_str(qdict, "password"));
+    if (err == -EINVAL) {
+        qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
+        return -1;
+    } else if (err < 0) {
+        qerror_report(QERR_INVALID_PASSWORD);
+        return -1;
+    }
+
+    return 0;
+}
+
+int do_change_block(Monitor *mon, const char *device,
+                    const char *filename, const char *fmt)
+{
+    BlockDriverState *bs;
+    BlockDriver *drv = NULL;
+    int bdrv_flags;
+
+    bs = bdrv_find(device);
+    if (!bs) {
+        qerror_report(QERR_DEVICE_NOT_FOUND, device);
+        return -1;
+    }
+    if (fmt) {
+        drv = bdrv_find_whitelisted_format(fmt);
+        if (!drv) {
+            qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
+            return -1;
+        }
+    }
+    if (eject_device(mon, bs, 0) < 0) {
+        return -1;
+    }
+    bdrv_flags = bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM ? 0 : BDRV_O_RDWR;
+    if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
+        qerror_report(QERR_OPEN_FILE_FAILED, filename);
+        return -1;
+    }
+    return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+}
diff --git a/blockdev.h b/blockdev.h
new file mode 100644
index 0000000000..dfc9de19ae
--- /dev/null
+++ b/blockdev.h
@@ -0,0 +1,71 @@
+/*
+ * QEMU host block devices
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later.  See the COPYING file in the top-level directory.
+ */
+
+#ifndef BLOCKDEV_H
+#define BLOCKDEV_H
+
+#include "block.h"
+#include "qemu-queue.h"
+
+typedef enum {
+    IF_NONE,
+    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
+    IF_COUNT
+} BlockInterfaceType;
+
+typedef enum {
+    BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC,
+    BLOCK_ERR_STOP_ANY
+} BlockInterfaceErrorAction;
+
+#define BLOCK_SERIAL_STRLEN 20
+
+typedef struct DriveInfo {
+    BlockDriverState *bdrv;
+    char *id;
+    const char *devaddr;
+    BlockInterfaceType type;
+    int bus;
+    int unit;
+    QemuOpts *opts;
+    BlockInterfaceErrorAction on_read_error;
+    BlockInterfaceErrorAction on_write_error;
+    char serial[BLOCK_SERIAL_STRLEN + 1];
+    QTAILQ_ENTRY(DriveInfo) next;
+} DriveInfo;
+
+#define MAX_IDE_DEVS	2
+#define MAX_SCSI_DEVS	7
+
+extern QTAILQ_HEAD(drivelist, DriveInfo) drives;
+
+extern DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
+extern DriveInfo *drive_get_by_id(const char *id);
+extern int drive_get_max_bus(BlockInterfaceType type);
+extern void drive_uninit(DriveInfo *dinfo);
+extern const char *drive_get_serial(BlockDriverState *bdrv);
+
+extern BlockInterfaceErrorAction drive_get_on_error(
+    BlockDriverState *bdrv, int is_read);
+
+extern QemuOpts *drive_add(const char *file, const char *fmt, ...);
+extern DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi,
+                             int *fatal_error);
+
+/* device-hotplug */
+
+DriveInfo *add_init_drive(const char *opts);
+
+void do_commit(Monitor *mon, const QDict *qdict);
+int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data);
+int do_change_block(Monitor *mon, const char *device,
+                    const char *filename, const char *fmt);
+
+#endif
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 0fce958d07..a87286b917 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -21,6 +21,7 @@
 #include "pm_smbus.h"
 #include "pci.h"
 #include "acpi.h"
+#include "sysemu.h"
 
 //#define DEBUG
 
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index b53e3c3bf9..31c8d705a2 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -31,6 +31,7 @@
 #include "pci_host.h"
 #include "rwhandler.h"
 #include "apb_pci.h"
+#include "sysemu.h"
 
 /* debug APB */
 //#define DEBUG_APB
diff --git a/hw/device-hotplug.c b/hw/device-hotplug.c
index 9cc8376691..c1a9a561d7 100644
--- a/hw/device-hotplug.c
+++ b/hw/device-hotplug.c
@@ -25,8 +25,6 @@
 #include "hw.h"
 #include "boards.h"
 #include "net.h"
-#include "block_int.h"
-#include "sysemu.h"
 
 DriveInfo *add_init_drive(const char *optstr)
 {
@@ -38,7 +36,7 @@ DriveInfo *add_init_drive(const char *optstr)
     if (!opts)
         return NULL;
 
-    dinfo = drive_init(opts, current_machine, &fatal_error);
+    dinfo = drive_init(opts, current_machine->use_scsi, &fatal_error);
     if (!dinfo) {
         qemu_opts_del(opts);
         return NULL;
diff --git a/hw/fdc.c b/hw/fdc.c
index 6306496383..b97895786a 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -29,7 +29,6 @@
 
 #include "hw.h"
 #include "fdc.h"
-#include "block.h"
 #include "qemu-timer.h"
 #include "isa.h"
 #include "sysbus.h"
diff --git a/hw/fdc.h b/hw/fdc.h
index c48b5e04df..b6b3772592 100644
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -2,7 +2,7 @@
 #define HW_FDC_H
 
 /* fdc.c */
-#include "sysemu.h"
+#include "blockdev.h"
 #define MAX_FD 2
 
 typedef struct FDCtrl FDCtrl;
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index cdcc9bf1aa..559147ff43 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -260,8 +260,8 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
     irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
     ide_bus_new(&d->bus[0], &d->dev.qdev);
     ide_bus_new(&d->bus[1], &d->dev.qdev);
-    ide_init2(&d->bus[0], NULL, NULL, irq[0]);
-    ide_init2(&d->bus[1], NULL, NULL, irq[1]);
+    ide_init2(&d->bus[0], irq[0]);
+    ide_init2(&d->bus[1], irq[1]);
 
     vmstate_register(0, &vmstate_ide_pci, d);
     qemu_register_reset(cmd646_reset, d);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 066fecb0c0..045d18db2b 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -26,8 +26,6 @@
 #include <hw/pc.h>
 #include <hw/pci.h>
 #include <hw/scsi.h>
-#include "block.h"
-#include "block_int.h"
 #include "qemu-timer.h"
 #include "sysemu.h"
 #include "dma.h"
@@ -98,6 +96,7 @@ static void ide_identify(IDEState *s)
 {
     uint16_t *p;
     unsigned int oldsize;
+    IDEDevice *dev;
 
     if (s->identify_set) {
 	memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
@@ -165,8 +164,9 @@ static void ide_identify(IDEState *s)
     put_le16(p + 101, s->nb_sectors >> 16);
     put_le16(p + 102, s->nb_sectors >> 32);
     put_le16(p + 103, s->nb_sectors >> 48);
-    if (s->conf && s->conf->physical_block_size)
-        put_le16(p + 106, 0x6000 | get_physical_block_exp(s->conf));
+    dev = s->unit ? s->bus->slave : s->bus->master;
+    if (dev && dev->conf.physical_block_size)
+        put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
 
     memcpy(s->identify_data, p, sizeof(s->identify_data));
     s->identify_set = 1;
@@ -2594,39 +2594,35 @@ void ide_bus_reset(IDEBus *bus)
     ide_clear_hob(bus);
 }
 
-void ide_init_drive(IDEState *s, DriveInfo *dinfo, BlockConf *conf,
-        const char *version)
+void ide_init_drive(IDEState *s, DriveInfo *dinfo,
+                    const char *version, const char *serial)
 {
     int cylinders, heads, secs;
     uint64_t nb_sectors;
 
-    if (dinfo && dinfo->bdrv) {
-        s->bs = dinfo->bdrv;
-        bdrv_get_geometry(s->bs, &nb_sectors);
-        bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
-        s->cylinders = cylinders;
-        s->heads = heads;
-        s->sectors = secs;
-        s->nb_sectors = nb_sectors;
-        /* The SMART values should be preserved across power cycles
-           but they aren't.  */
-        s->smart_enabled = 1;
-        s->smart_autosave = 1;
-        s->smart_errors = 0;
-        s->smart_selftest_count = 0;
-        if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
-            s->is_cdrom = 1;
-            bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
-        }
-        strncpy(s->drive_serial_str, drive_get_serial(s->bs),
-                sizeof(s->drive_serial_str));
-        if (conf) {
-            s->conf = conf;
-        }
+    s->bs = dinfo->bdrv;
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
+    s->cylinders = cylinders;
+    s->heads = heads;
+    s->sectors = secs;
+    s->nb_sectors = nb_sectors;
+    /* The SMART values should be preserved across power cycles
+       but they aren't.  */
+    s->smart_enabled = 1;
+    s->smart_autosave = 1;
+    s->smart_errors = 0;
+    s->smart_selftest_count = 0;
+    if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
+        s->is_cdrom = 1;
+        bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
     }
-    if (strlen(s->drive_serial_str) == 0)
+    if (serial && *serial) {
+        strncpy(s->drive_serial_str, serial, sizeof(s->drive_serial_str));
+    } else {
         snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
                  "QM%05d", s->drive_serial);
+    }
     if (version) {
         pstrcpy(s->version, sizeof(s->version), version);
     } else {
@@ -2635,27 +2631,47 @@ void ide_init_drive(IDEState *s, DriveInfo *dinfo, BlockConf *conf,
     ide_reset(s);
 }
 
-void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
-               qemu_irq irq)
+static void ide_init1(IDEBus *bus, int unit)
 {
-    IDEState *s;
     static int drive_serial = 1;
+    IDEState *s = &bus->ifs[unit];
+
+    s->bus = bus;
+    s->unit = unit;
+    s->drive_serial = drive_serial++;
+    s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
+    s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
+    s->smart_selftest_data = qemu_blockalign(s->bs, 512);
+    s->sector_write_timer = qemu_new_timer(vm_clock,
+                                           ide_sector_write_timer_cb, s);
+}
+
+void ide_init2(IDEBus *bus, qemu_irq irq)
+{
     int i;
 
     for(i = 0; i < 2; i++) {
-        s = bus->ifs + i;
-        s->bus = bus;
-        s->unit = i;
-        s->drive_serial = drive_serial++;
-        s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
-        s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
-        s->smart_selftest_data = qemu_blockalign(s->bs, 512);
-        s->sector_write_timer = qemu_new_timer(vm_clock,
-                                               ide_sector_write_timer_cb, s);
-        if (i == 0)
-            ide_init_drive(s, hd0, NULL, NULL);
-        if (i == 1)
-            ide_init_drive(s, hd1, NULL, NULL);
+        ide_init1(bus, i);
+        ide_reset(&bus->ifs[i]);
+    }
+    bus->irq = irq;
+}
+
+/* TODO convert users to qdev and remove */
+void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
+                                    DriveInfo *hd1, qemu_irq irq)
+{
+    int i;
+    DriveInfo *dinfo;
+
+    for(i = 0; i < 2; i++) {
+        dinfo = i == 0 ? hd0 : hd1;
+        ide_init1(bus, i);
+        if (dinfo) {
+            ide_init_drive(&bus->ifs[i], dinfo, NULL, dinfo->serial);
+        } else {
+            ide_reset(&bus->ifs[i]);
+        }
     }
     bus->irq = irq;
 }
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 2efc7846bc..eef1ee141d 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -398,7 +398,6 @@ struct IDEState {
     /* set for lba48 access */
     uint8_t lba48;
     BlockDriverState *bs;
-    BlockConf *conf;
     char version[9];
     /* ATAPI specific */
     uint8_t sense_key;
@@ -458,14 +457,13 @@ struct IDEDevice {
     uint32_t unit;
     BlockConf conf;
     char *version;
+    char *serial;
 };
 
 typedef int (*ide_qdev_initfn)(IDEDevice *dev);
 struct IDEDeviceInfo {
     DeviceInfo qdev;
     ide_qdev_initfn init;
-    uint32_t unit;
-    DriveInfo *drive;
 };
 
 #define BM_STATUS_DMAING 0x01
@@ -557,10 +555,11 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr);
 void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
 uint32_t ide_data_readl(void *opaque, uint32_t addr);
 
-void ide_init_drive(IDEState *s, DriveInfo *dinfo, BlockConf *conf,
-    const char *version);
-void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
-               qemu_irq irq);
+void ide_init_drive(IDEState *s, DriveInfo *dinfo,
+                    const char *version, const char *serial);
+void ide_init2(IDEBus *bus, qemu_irq irq);
+void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
+                                    DriveInfo *hd1, qemu_irq irq);
 void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
 
 /* hw/ide/qdev.c */
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index dff7c796f7..b6c6347289 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -70,7 +70,7 @@ static int isa_ide_initfn(ISADevice *dev)
     ide_bus_new(&s->bus, &s->dev.qdev);
     ide_init_ioport(&s->bus, s->iobase, s->iobase2);
     isa_init_irq(dev, &s->irq, s->isairq);
-    ide_init2(&s->bus, NULL, NULL, s->irq);
+    ide_init2(&s->bus, s->irq);
     vmstate_register(0, &vmstate_ide_isa, s);
     return 0;
 };
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 639f3f6a65..f76c0fa31c 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -314,7 +314,7 @@ int pmac_ide_init (DriveInfo **hd_table, qemu_irq irq,
     int pmac_ide_memory;
 
     d = qemu_mallocz(sizeof(MACIOIDEState));
-    ide_init2(&d->bus, hd_table[0], hd_table[1], irq);
+    ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq);
 
     if (dbdma)
         DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d);
diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c
index bfdb8c8b05..a7beac552a 100644
--- a/hw/ide/microdrive.c
+++ b/hw/ide/microdrive.c
@@ -539,7 +539,8 @@ PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv)
     md->card.cis = dscm1xxxx_cis;
     md->card.cis_len = sizeof(dscm1xxxx_cis);
 
-    ide_init2(&md->bus, bdrv, NULL, qemu_allocate_irqs(md_set_irq, md, 1)[0]);
+    ide_init2_with_non_qdev_drives(&md->bus, bdrv, NULL,
+                                   qemu_allocate_irqs(md_set_irq, md, 1)[0]);
     md->bus.ifs[0].is_cf = 1;
     md->bus.ifs[0].mdata_size = METADATA_SIZE;
     md->bus.ifs[0].mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE);
diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c
index cca883f613..e75cccf56e 100644
--- a/hw/ide/mmio.c
+++ b/hw/ide/mmio.c
@@ -125,7 +125,7 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
     MMIOState *s = qemu_mallocz(sizeof(MMIOState));
     int mem1, mem2;
 
-    ide_init2(&s->bus, hd0, hd1, irq);
+    ide_init2_with_non_qdev_drives(&s->bus, hd0, hd1, irq);
 
     s->shift = shift;
 
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 4fa38519ef..dad6e86ff6 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -135,8 +135,8 @@ static int pci_piix_ide_initfn(PCIIDEState *d)
     ide_init_ioport(&d->bus[0], 0x1f0, 0x3f6);
     ide_init_ioport(&d->bus[1], 0x170, 0x376);
 
-    ide_init2(&d->bus[0], NULL, NULL, isa_reserve_irq(14));
-    ide_init2(&d->bus[1], NULL, NULL, isa_reserve_irq(15));
+    ide_init2(&d->bus[0], isa_reserve_irq(14));
+    ide_init2(&d->bus[1], isa_reserve_irq(15));
     return 0;
 }
 
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index b18693d945..0f9f22e30f 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -17,7 +17,6 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include <hw/hw.h>
-#include "sysemu.h"
 #include "dma.h"
 
 #include <hw/ide/internal.h>
@@ -99,8 +98,23 @@ typedef struct IDEDrive {
 static int ide_drive_initfn(IDEDevice *dev)
 {
     IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
-    ide_init_drive(bus->ifs + dev->unit, dev->conf.dinfo, &dev->conf,
-                   dev->version);
+    IDEState *s = bus->ifs + dev->unit;
+    const char *serial;
+
+    serial = dev->serial;
+    if (!serial) {
+        /* try to fall back to value set with legacy -drive serial=... */
+        serial = dev->conf.dinfo->serial;
+    }
+
+    ide_init_drive(s, dev->conf.dinfo, dev->version, serial);
+
+    if (!dev->version) {
+        dev->version = qemu_strdup(s->version);
+    }
+    if (!dev->serial) {
+        dev->serial = qemu_strdup(s->drive_serial_str);
+    }
     return 0;
 }
 
@@ -112,6 +126,7 @@ static IDEDeviceInfo ide_drive_info = {
         DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1),
         DEFINE_BLOCK_PROPERTIES(IDEDrive, dev.conf),
         DEFINE_PROP_STRING("ver",  IDEDrive, dev.version),
+        DEFINE_PROP_STRING("serial",  IDEDrive, dev.serial),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 16d33304d5..b996dc4f0c 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -10,6 +10,7 @@
 #include "sysbus.h"
 #include "net.h"
 #include "devices.h"
+#include "sysemu.h"
 /* For crc32 */
 #include <zlib.h>
 
diff --git a/hw/nand.c b/hw/nand.c
index 40d5a6a736..cd7444f9a5 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -13,9 +13,8 @@
 
 # include "hw.h"
 # include "flash.h"
-# include "block.h"
+# include "blockdev.h"
 /* FIXME: Pass block device as an argument.  */
-# include "sysemu.h"
 
 # define NAND_CMD_READ0		0x00
 # define NAND_CMD_READ1		0x01
diff --git a/hw/omap2.c b/hw/omap2.c
index bd1b35e661..666c15adb2 100644
--- a/hw/omap2.c
+++ b/hw/omap2.c
@@ -17,6 +17,8 @@
  * You should have received a copy of the GNU General Public License along
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
+
+#include "blockdev.h"
 #include "hw.h"
 #include "arm-misc.h"
 #include "omap.h"
diff --git a/hw/onenand.c b/hw/onenand.c
index c1e7e4d608..4118db922d 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -21,8 +21,7 @@
 #include "qemu-common.h"
 #include "flash.h"
 #include "irq.h"
-#include "sysemu.h"
-#include "block.h"
+#include "blockdev.h"
 
 /* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
 #define PAGE_SHIFT	11
diff --git a/hw/parallel.c b/hw/parallel.c
index be8e2d5479..6b11672e15 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -26,6 +26,7 @@
 #include "qemu-char.h"
 #include "isa.h"
 #include "pc.h"
+#include "sysemu.h"
 
 //#define DEBUG_PARALLEL
 
diff --git a/hw/pc.c b/hw/pc.c
index 14911297ea..0f7d330609 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -36,6 +36,7 @@
 #include "multiboot.h"
 #include "mc146818rtc.h"
 #include "sysbus.h"
+#include "sysemu.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 70f563a67e..dc46846923 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -32,6 +32,7 @@
 #include "boards.h"
 #include "ide.h"
 #include "kvm.h"
+#include "sysemu.h"
 
 #define MAX_IDE_BUS 2
 
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index a8f3df1701..c39e640089 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -26,10 +26,8 @@
 #include "boards.h"
 #include "pci.h"
 #include "net.h"
-#include "sysemu.h"
 #include "pc.h"
 #include "monitor.h"
-#include "block_int.h"
 #include "scsi.h"
 #include "virtio-blk.h"
 #include "qemu-config.h"
diff --git a/hw/pcmcia.h b/hw/pcmcia.h
index cf2db9d325..360292395b 100644
--- a/hw/pcmcia.h
+++ b/hw/pcmcia.h
@@ -1,7 +1,7 @@
 /* PCMCIA/Cardbus */
 
 #include "qemu-common.h"
-#include "sysemu.h"
+#include "blockdev.h"
 
 typedef struct {
     qemu_irq irq;
diff --git a/hw/pl181.c b/hw/pl181.c
index 1924053330..85cadc4fe1 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -9,7 +9,6 @@
 
 #include "sysbus.h"
 #include "sd.h"
-#include "sysemu.h"
 
 //#define DEBUG_PL181 1
 
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 9ffdba792c..5a8739debe 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -1,4 +1,3 @@
-#include "sysemu.h"
 #include "net.h"
 #include "qdev.h"
 #include "qerror.h"
@@ -260,6 +259,11 @@ static int parse_string(DeviceState *dev, Property *prop, const char *str)
     return 0;
 }
 
+static void free_string(DeviceState *dev, Property *prop)
+{
+    qemu_free(*(char **)qdev_get_prop_ptr(dev, prop));
+}
+
 static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len)
 {
     char **ptr = qdev_get_prop_ptr(dev, prop);
@@ -274,6 +278,7 @@ PropertyInfo qdev_prop_string = {
     .size  = sizeof(char*),
     .parse = parse_string,
     .print = print_string,
+    .free  = free_string,
 };
 
 /* --- drive --- */
@@ -617,6 +622,11 @@ void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
     qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64);
 }
 
+void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
+{
+    qdev_prop_set(dev, name, &value, PROP_TYPE_STRING);
+}
+
 void qdev_prop_set_drive(DeviceState *dev, const char *name, DriveInfo *value)
 {
     qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE);
diff --git a/hw/qdev.c b/hw/qdev.c
index 36f29ea79f..61f999c023 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -334,6 +334,7 @@ void qdev_init_nofail(DeviceState *dev)
 void qdev_free(DeviceState *dev)
 {
     BusState *bus;
+    Property *prop;
 
     if (dev->state == DEV_STATE_INITIALIZED) {
         while (dev->num_child_bus) {
@@ -349,6 +350,11 @@ void qdev_free(DeviceState *dev)
     }
     qemu_unregister_reset(qdev_reset, dev);
     QLIST_REMOVE(dev, sibling);
+    for (prop = dev->info->props; prop && prop->name; prop++) {
+        if (prop->info->free) {
+            prop->info->free(dev, prop);
+        }
+    }
     qemu_free(dev);
 }
 
diff --git a/hw/qdev.h b/hw/qdev.h
index a44060e54c..be5ad671cc 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -2,7 +2,7 @@
 #define QDEV_H
 
 #include "hw.h"
-#include "sysemu.h"
+#include "blockdev.h"
 #include "qemu-queue.h"
 #include "qemu-char.h"
 #include "qemu-option.h"
@@ -98,6 +98,7 @@ struct PropertyInfo {
     enum PropertyType type;
     int (*parse)(DeviceState *dev, Property *prop, const char *str);
     int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
+    void (*free)(DeviceState *dev, Property *prop);
 };
 
 typedef struct GlobalProperty {
@@ -124,6 +125,8 @@ void qdev_machine_creation_done(void);
 qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
 void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
 
+BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type);
+
 BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
 
 /*** Device API.  ***/
@@ -268,6 +271,7 @@ void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value);
 void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value);
 void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value);
 void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value);
+void qdev_prop_set_string(DeviceState *dev, const char *name, char *value);
 void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
 void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value);
 void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value);
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 383240bc07..055a94d255 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -2,7 +2,6 @@
 #include "qemu-error.h"
 #include "scsi.h"
 #include "scsi-defs.h"
-#include "block.h"
 #include "qdev.h"
 
 static struct BusInfo scsi_bus_info = {
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 4d209197ce..a9bf7d261a 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -33,9 +33,9 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 
 #include "qemu-common.h"
 #include "qemu-error.h"
-#include "block.h"
 #include "scsi.h"
 #include "scsi-defs.h"
+#include "sysemu.h"
 
 #define SCSI_DMA_BUF_SIZE    131072
 #define SCSI_MAX_INQUIRY_LEN 256
@@ -66,6 +66,7 @@ struct SCSIDiskState
     uint64_t max_lba;
     QEMUBH *bh;
     char *version;
+    char *serial;
 };
 
 static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
@@ -359,9 +360,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
 
         case 0x80: /* Device serial number, optional */
         {
-            const char *serial = req->dev->conf.dinfo->serial ?
-                req->dev->conf.dinfo->serial : "0";
-            int l = strlen(serial);
+            int l = strlen(s->serial);
 
             if (l > req->cmd.xfer)
                 l = req->cmd.xfer;
@@ -371,7 +370,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             DPRINTF("Inquiry EVPD[Serial number] "
                     "buffer size %zd\n", req->cmd.xfer);
             outbuf[buflen++] = l;
-            memcpy(outbuf+buflen, serial, l);
+            memcpy(outbuf+buflen, s->serial, l);
             buflen += l;
             break;
         }
@@ -463,8 +462,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
     }
     memcpy(&outbuf[8], "QEMU    ", 8);
     memset(&outbuf[32], 0, 4);
-    memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION,
-           MIN(4, strlen(s->version ? s->version : QEMU_VERSION)));
+    memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version)));
     /*
      * We claim conformance to SPC-3, which is required for guests
      * to ask for modern features like READ CAPACITY(16) or the
@@ -1058,6 +1056,19 @@ static int scsi_disk_initfn(SCSIDevice *dev)
     }
     s->bs = s->qdev.conf.dinfo->bdrv;
 
+    if (!s->serial) {
+        if (*dev->conf.dinfo->serial) {
+            /* try to fall back to value set with legacy -drive serial=... */
+            s->serial = qemu_strdup(dev->conf.dinfo->serial);
+        } else {
+            s->serial = qemu_strdup("0");
+        }
+    }
+
+    if (!s->version) {
+        s->version = qemu_strdup(QEMU_VERSION);
+    }
+
     if (bdrv_is_sg(s->bs)) {
         error_report("scsi-disk: unwanted /dev/sg*");
         return -1;
@@ -1090,6 +1101,7 @@ static SCSIDeviceInfo scsi_disk_info = {
     .qdev.props   = (Property[]) {
         DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),
         DEFINE_PROP_STRING("ver",  SCSIDiskState, version),
+        DEFINE_PROP_STRING("serial",  SCSIDiskState, serial),
         DEFINE_PROP_END_OF_LIST(),
     },
 };
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index c9aa853cc4..e31060e944 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -13,7 +13,6 @@
 
 #include "qemu-common.h"
 #include "qemu-error.h"
-#include "block.h"
 #include "scsi.h"
 
 #ifdef __linux__
diff --git a/hw/serial.c b/hw/serial.c
index 9102edb77b..c7e4e77cb0 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -27,6 +27,7 @@
 #include "isa.h"
 #include "pc.h"
 #include "qemu-timer.h"
+#include "sysemu.h"
 
 //#define DEBUG_SERIAL
 
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index 5e74e5d7ce..96b33edcbd 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -9,7 +9,6 @@
 
 #include "ssi.h"
 #include "sd.h"
-#include "sysemu.h"
 
 //#define DEBUG_SSI_SD 1
 
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 8e6c6e0322..228d0a052a 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -25,6 +25,7 @@
 #include "hw.h"
 #include "console.h"
 #include "usb.h"
+#include "sysemu.h"
 
 /* HID interface requests */
 #define GET_REPORT   0xa101
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index c1c2537475..003bd8a4cd 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -11,10 +11,10 @@
 #include "qemu-option.h"
 #include "qemu-config.h"
 #include "usb.h"
-#include "block.h"
 #include "scsi.h"
 #include "console.h"
 #include "monitor.h"
+#include "sysemu.h"
 
 //#define DEBUG_MSD
 
@@ -584,7 +584,7 @@ static USBDevice *usb_msd_init(const char *filename)
     qemu_opt_set(opts, "if", "none");
 
     /* create host drive */
-    dinfo = drive_init(opts, NULL, &fatal_error);
+    dinfo = drive_init(opts, 0, &fatal_error);
     if (!dinfo) {
         qemu_opts_del(opts);
         return NULL;
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 5d7f1a2200..cdcb492c14 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -12,9 +12,7 @@
  */
 
 #include <qemu-common.h>
-#include <sysemu.h>
 #include "virtio-blk.h"
-#include "block_int.h"
 #ifdef __linux__
 # include <scsi/sg.h>
 #endif
@@ -277,7 +275,7 @@ static void virtio_blk_handle_write(BlockRequest *blkreq, int *num_writes,
     }
 
     blkreq[*num_writes].sector = req->out->sector;
-    blkreq[*num_writes].nb_sectors = req->qiov.size / 512;
+    blkreq[*num_writes].nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE;
     blkreq[*num_writes].qiov = &req->qiov;
     blkreq[*num_writes].cb = virtio_blk_rw_complete;
     blkreq[*num_writes].opaque = req;
@@ -296,7 +294,8 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
     }
 
     acb = bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
-                         req->qiov.size / 512, virtio_blk_rw_complete, req);
+                         req->qiov.size / BDRV_SECTOR_SIZE,
+                         virtio_blk_rw_complete, req);
     if (!acb) {
         virtio_blk_rw_complete(req, -EIO);
     }
@@ -505,7 +504,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf)
     s->bs = conf->dinfo->bdrv;
     s->conf = conf;
     s->rq = NULL;
-    s->sector_mask = (s->conf->logical_block_size / 512) - 1;
+    s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
     bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
 
     s->vq = virtio_add_queue(&s->vdev, 128, virtio_blk_handle_output);
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 7ddf612282..e101fa0a7d 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -22,7 +22,6 @@
 #include "qemu-error.h"
 #include "msix.h"
 #include "net.h"
-#include "block_int.h"
 #include "loader.h"
 #include "kvm.h"
 
diff --git a/monitor.c b/monitor.c
index 14f77bd472..05a7ed1c42 100644
--- a/monitor.c
+++ b/monitor.c
@@ -38,7 +38,7 @@
 #include "monitor.h"
 #include "readline.h"
 #include "console.h"
-#include "block.h"
+#include "blockdev.h"
 #include "audio/audio.h"
 #include "disas.h"
 #include "balloon.h"
@@ -530,21 +530,6 @@ static void do_help_cmd(Monitor *mon, const QDict *qdict)
     help_cmd(mon, qdict_get_try_str(qdict, "name"));
 }
 
-static void do_commit(Monitor *mon, const QDict *qdict)
-{
-    int all_devices;
-    DriveInfo *dinfo;
-    const char *device = qdict_get_str(qdict, "device");
-
-    all_devices = !strcmp(device, "all");
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        if (!all_devices)
-            if (strcmp(bdrv_get_device_name(dinfo->bdrv), device))
-                continue;
-        bdrv_commit(dinfo->bdrv);
-    }
-}
-
 static void user_monitor_complete(void *opaque, QObject *ret_data)
 {
     MonitorCompletionData *data = (MonitorCompletionData *)opaque; 
@@ -935,93 +920,6 @@ static int do_quit(Monitor *mon, const QDict *qdict, QObject **ret_data)
     return 0;
 }
 
-static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
-{
-    if (bdrv_is_inserted(bs)) {
-        if (!force) {
-            if (!bdrv_is_removable(bs)) {
-                qerror_report(QERR_DEVICE_NOT_REMOVABLE,
-                               bdrv_get_device_name(bs));
-                return -1;
-            }
-            if (bdrv_is_locked(bs)) {
-                qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
-                return -1;
-            }
-        }
-        bdrv_close(bs);
-    }
-    return 0;
-}
-
-static int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
-    BlockDriverState *bs;
-    int force = qdict_get_int(qdict, "force");
-    const char *filename = qdict_get_str(qdict, "device");
-
-    bs = bdrv_find(filename);
-    if (!bs) {
-        qerror_report(QERR_DEVICE_NOT_FOUND, filename);
-        return -1;
-    }
-    return eject_device(mon, bs, force);
-}
-
-static int do_block_set_passwd(Monitor *mon, const QDict *qdict,
-                                QObject **ret_data)
-{
-    BlockDriverState *bs;
-    int err;
-
-    bs = bdrv_find(qdict_get_str(qdict, "device"));
-    if (!bs) {
-        qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
-        return -1;
-    }
-
-    err = bdrv_set_key(bs, qdict_get_str(qdict, "password"));
-    if (err == -EINVAL) {
-        qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
-        return -1;
-    } else if (err < 0) {
-        qerror_report(QERR_INVALID_PASSWORD);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int do_change_block(Monitor *mon, const char *device,
-                           const char *filename, const char *fmt)
-{
-    BlockDriverState *bs;
-    BlockDriver *drv = NULL;
-    int bdrv_flags;
-
-    bs = bdrv_find(device);
-    if (!bs) {
-        qerror_report(QERR_DEVICE_NOT_FOUND, device);
-        return -1;
-    }
-    if (fmt) {
-        drv = bdrv_find_whitelisted_format(fmt);
-        if (!drv) {
-            qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
-            return -1;
-        }
-    }
-    if (eject_device(mon, bs, 0) < 0) {
-        return -1;
-    }
-    bdrv_flags = bdrv_get_type_hint(bs) == BDRV_TYPE_CDROM ? 0 : BDRV_O_RDWR;
-    if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
-        qerror_report(QERR_OPEN_FILE_FAILED, filename);
-        return -1;
-    }
-    return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
-}
-
 static int change_vnc_password(const char *password)
 {
     if (vnc_display_password(NULL, password) < 0) {
diff --git a/qemu-char.c b/qemu-char.c
index faaf6248b5..87628ea33f 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -28,7 +28,6 @@
 #include "sysemu.h"
 #include "qemu-timer.h"
 #include "qemu-char.h"
-#include "block.h"
 #include "hw/usb.h"
 #include "hw/baum.h"
 #include "hw/msmouse.h"
diff --git a/qemu-io.c b/qemu-io.c
index 72a45247da..7c6120b6ac 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1317,7 +1317,7 @@ truncate_f(int argc, char **argv)
 
 	ret = bdrv_truncate(bs, offset);
 	if (ret < 0) {
-		printf("truncate: %s", strerror(ret));
+		printf("truncate: %s\n", strerror(-ret));
 		return 0;
 	}
 
@@ -1342,7 +1342,7 @@ length_f(int argc, char **argv)
 
 	size = bdrv_getlength(bs);
 	if (size < 0) {
-		printf("getlength: %s", strerror(size));
+		printf("getlength: %s\n", strerror(-size));
 		return 0;
 	}
 
diff --git a/savevm.c b/savevm.c
index af92ba2982..1173a22e65 100644
--- a/savevm.c
+++ b/savevm.c
@@ -77,7 +77,7 @@
 #include "sysemu.h"
 #include "qemu-timer.h"
 #include "qemu-char.h"
-#include "block.h"
+#include "blockdev.h"
 #include "audio/audio.h"
 #include "migration.h"
 #include "qemu_socket.h"
diff --git a/sysemu.h b/sysemu.h
index 346cccd76d..fbe103bc34 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -142,58 +142,6 @@ extern int nb_option_roms;
 extern const char *prom_envs[MAX_PROM_ENVS];
 extern unsigned int nb_prom_envs;
 
-typedef enum {
-    IF_NONE,
-    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_XEN,
-    IF_COUNT
-} BlockInterfaceType;
-
-typedef enum {
-    BLOCK_ERR_REPORT, BLOCK_ERR_IGNORE, BLOCK_ERR_STOP_ENOSPC,
-    BLOCK_ERR_STOP_ANY
-} BlockInterfaceErrorAction;
-
-#define BLOCK_SERIAL_STRLEN 20
-
-typedef struct DriveInfo {
-    BlockDriverState *bdrv;
-    char *id;
-    const char *devaddr;
-    BlockInterfaceType type;
-    int bus;
-    int unit;
-    QemuOpts *opts;
-    BlockInterfaceErrorAction on_read_error;
-    BlockInterfaceErrorAction on_write_error;
-    char serial[BLOCK_SERIAL_STRLEN + 1];
-    QTAILQ_ENTRY(DriveInfo) next;
-} DriveInfo;
-
-#define MAX_IDE_DEVS	2
-#define MAX_SCSI_DEVS	7
-#define MAX_DRIVES 32
-
-extern QTAILQ_HEAD(drivelist, DriveInfo) drives;
-extern QTAILQ_HEAD(driveoptlist, DriveOpt) driveopts;
-
-extern DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
-extern DriveInfo *drive_get_by_id(const char *id);
-extern int drive_get_max_bus(BlockInterfaceType type);
-extern void drive_uninit(DriveInfo *dinfo);
-extern const char *drive_get_serial(BlockDriverState *bdrv);
-
-extern BlockInterfaceErrorAction drive_get_on_error(
-    BlockDriverState *bdrv, int is_read);
-
-BlockDriverState *qdev_init_bdrv(DeviceState *dev, BlockInterfaceType type);
-
-extern QemuOpts *drive_add(const char *file, const char *fmt, ...);
-extern DriveInfo *drive_init(QemuOpts *arg, void *machine, int *fatal_error);
-
-/* device-hotplug */
-
-DriveInfo *add_init_drive(const char *opts);
-
 /* pci-hotplug */
 void pci_device_hot_add(Monitor *mon, const QDict *qdict);
 void drive_hot_add(Monitor *mon, const QDict *qdict);
diff --git a/vl.c b/vl.c
index 9cf53347f5..df18198a1e 100644
--- a/vl.c
+++ b/vl.c
@@ -137,7 +137,7 @@ int main(int argc, char **argv)
 #include "qemu-char.h"
 #include "cache-utils.h"
 #include "block.h"
-#include "block_int.h"
+#include "blockdev.h"
 #include "block-migration.h"
 #include "dma.h"
 #include "audio/audio.h"
@@ -170,10 +170,6 @@ int main(int argc, char **argv)
 
 static const char *data_dir;
 const char *bios_name = NULL;
-/* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
-   to store the VM snapshots */
-struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives);
-struct driveoptlist driveopts = QTAILQ_HEAD_INITIALIZER(driveopts);
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 DisplayType display_type = DT_DEFAULT;
 const char* keyboard_layout = NULL;
@@ -633,492 +629,12 @@ static int bt_parse(const char *opt)
 #define MTD_ALIAS "if=mtd"
 #define SD_ALIAS "index=0,if=sd"
 
-QemuOpts *drive_add(const char *file, const char *fmt, ...)
-{
-    va_list ap;
-    char optstr[1024];
-    QemuOpts *opts;
-
-    va_start(ap, fmt);
-    vsnprintf(optstr, sizeof(optstr), fmt, ap);
-    va_end(ap);
-
-    opts = qemu_opts_parse(&qemu_drive_opts, optstr, 0);
-    if (!opts) {
-        return NULL;
-    }
-    if (file)
-        qemu_opt_set(opts, "file", file);
-    return opts;
-}
-
-DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
-{
-    DriveInfo *dinfo;
-
-    /* seek interface, bus and unit */
-
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        if (dinfo->type == type &&
-	    dinfo->bus == bus &&
-	    dinfo->unit == unit)
-            return dinfo;
-    }
-
-    return NULL;
-}
-
-DriveInfo *drive_get_by_id(const char *id)
-{
-    DriveInfo *dinfo;
-
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        if (strcmp(id, dinfo->id))
-            continue;
-        return dinfo;
-    }
-    return NULL;
-}
-
-int drive_get_max_bus(BlockInterfaceType type)
-{
-    int max_bus;
-    DriveInfo *dinfo;
-
-    max_bus = -1;
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        if(dinfo->type == type &&
-           dinfo->bus > max_bus)
-            max_bus = dinfo->bus;
-    }
-    return max_bus;
-}
-
-const char *drive_get_serial(BlockDriverState *bdrv)
-{
-    DriveInfo *dinfo;
-
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        if (dinfo->bdrv == bdrv)
-            return dinfo->serial;
-    }
-
-    return "\0";
-}
-
-BlockInterfaceErrorAction drive_get_on_error(
-    BlockDriverState *bdrv, int is_read)
-{
-    DriveInfo *dinfo;
-
-    QTAILQ_FOREACH(dinfo, &drives, next) {
-        if (dinfo->bdrv == bdrv)
-            return is_read ? dinfo->on_read_error : dinfo->on_write_error;
-    }
-
-    return is_read ? BLOCK_ERR_REPORT : BLOCK_ERR_STOP_ENOSPC;
-}
-
-static void bdrv_format_print(void *opaque, const char *name)
-{
-    fprintf(stderr, " %s", name);
-}
-
-void drive_uninit(DriveInfo *dinfo)
-{
-    qemu_opts_del(dinfo->opts);
-    bdrv_delete(dinfo->bdrv);
-    QTAILQ_REMOVE(&drives, dinfo, next);
-    qemu_free(dinfo);
-}
-
-static int parse_block_error_action(const char *buf, int is_read)
-{
-    if (!strcmp(buf, "ignore")) {
-        return BLOCK_ERR_IGNORE;
-    } else if (!is_read && !strcmp(buf, "enospc")) {
-        return BLOCK_ERR_STOP_ENOSPC;
-    } else if (!strcmp(buf, "stop")) {
-        return BLOCK_ERR_STOP_ANY;
-    } else if (!strcmp(buf, "report")) {
-        return BLOCK_ERR_REPORT;
-    } else {
-        fprintf(stderr, "qemu: '%s' invalid %s error action\n",
-            buf, is_read ? "read" : "write");
-        return -1;
-    }
-}
-
-DriveInfo *drive_init(QemuOpts *opts, void *opaque,
-                      int *fatal_error)
-{
-    const char *buf;
-    const char *file = NULL;
-    char devname[128];
-    const char *serial;
-    const char *mediastr = "";
-    BlockInterfaceType type;
-    enum { MEDIA_DISK, MEDIA_CDROM } media;
-    int bus_id, unit_id;
-    int cyls, heads, secs, translation;
-    BlockDriver *drv = NULL;
-    QEMUMachine *machine = opaque;
-    int max_devs;
-    int index;
-    int ro = 0;
-    int bdrv_flags = 0;
-    int on_read_error, on_write_error;
-    const char *devaddr;
-    DriveInfo *dinfo;
-    int snapshot = 0;
-
-    *fatal_error = 1;
-
-    translation = BIOS_ATA_TRANSLATION_AUTO;
-
-    if (machine && machine->use_scsi) {
-        type = IF_SCSI;
-        max_devs = MAX_SCSI_DEVS;
-        pstrcpy(devname, sizeof(devname), "scsi");
-    } else {
-        type = IF_IDE;
-        max_devs = MAX_IDE_DEVS;
-        pstrcpy(devname, sizeof(devname), "ide");
-    }
-    media = MEDIA_DISK;
-
-    /* extract parameters */
-    bus_id  = qemu_opt_get_number(opts, "bus", 0);
-    unit_id = qemu_opt_get_number(opts, "unit", -1);
-    index   = qemu_opt_get_number(opts, "index", -1);
-
-    cyls  = qemu_opt_get_number(opts, "cyls", 0);
-    heads = qemu_opt_get_number(opts, "heads", 0);
-    secs  = qemu_opt_get_number(opts, "secs", 0);
-
-    snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
-    ro = qemu_opt_get_bool(opts, "readonly", 0);
-
-    file = qemu_opt_get(opts, "file");
-    serial = qemu_opt_get(opts, "serial");
-
-    if ((buf = qemu_opt_get(opts, "if")) != NULL) {
-        pstrcpy(devname, sizeof(devname), buf);
-        if (!strcmp(buf, "ide")) {
-	    type = IF_IDE;
-            max_devs = MAX_IDE_DEVS;
-        } else if (!strcmp(buf, "scsi")) {
-	    type = IF_SCSI;
-            max_devs = MAX_SCSI_DEVS;
-        } else if (!strcmp(buf, "floppy")) {
-	    type = IF_FLOPPY;
-            max_devs = 0;
-        } else if (!strcmp(buf, "pflash")) {
-	    type = IF_PFLASH;
-            max_devs = 0;
-	} else if (!strcmp(buf, "mtd")) {
-	    type = IF_MTD;
-            max_devs = 0;
-	} else if (!strcmp(buf, "sd")) {
-	    type = IF_SD;
-            max_devs = 0;
-        } else if (!strcmp(buf, "virtio")) {
-            type = IF_VIRTIO;
-            max_devs = 0;
-	} else if (!strcmp(buf, "xen")) {
-	    type = IF_XEN;
-            max_devs = 0;
-	} else if (!strcmp(buf, "none")) {
-	    type = IF_NONE;
-            max_devs = 0;
-	} else {
-            fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf);
-            return NULL;
-	}
-    }
-
-    if (cyls || heads || secs) {
-        if (cyls < 1 || (type == IF_IDE && cyls > 16383)) {
-            fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf);
-	    return NULL;
-	}
-        if (heads < 1 || (type == IF_IDE && heads > 16)) {
-            fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf);
-	    return NULL;
-	}
-        if (secs < 1 || (type == IF_IDE && secs > 63)) {
-            fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf);
-	    return NULL;
-	}
-    }
-
-    if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
-        if (!cyls) {
-            fprintf(stderr,
-                    "qemu: '%s' trans must be used with cyls,heads and secs\n",
-                    buf);
-            return NULL;
-        }
-        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", buf);
-	    return NULL;
-	}
-    }
-
-    if ((buf = qemu_opt_get(opts, "media")) != NULL) {
-        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", buf);
-	        return NULL;
-            }
-	    media = MEDIA_CDROM;
-	} else {
-	    fprintf(stderr, "qemu: '%s' invalid media\n", buf);
-	    return NULL;
-	}
-    }
-
-    if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
-        if (!strcmp(buf, "off") || !strcmp(buf, "none")) {
-            bdrv_flags |= BDRV_O_NOCACHE;
-        } else if (!strcmp(buf, "writeback")) {
-            bdrv_flags |= BDRV_O_CACHE_WB;
-        } else if (!strcmp(buf, "unsafe")) {
-            bdrv_flags |= BDRV_O_CACHE_WB;
-            bdrv_flags |= BDRV_O_NO_FLUSH;
-        } else if (!strcmp(buf, "writethrough")) {
-            /* this is the default */
-        } else {
-           fprintf(stderr, "qemu: invalid cache option\n");
-           return NULL;
-        }
-    }
-
-#ifdef CONFIG_LINUX_AIO
-    if ((buf = qemu_opt_get(opts, "aio")) != NULL) {
-        if (!strcmp(buf, "native")) {
-            bdrv_flags |= BDRV_O_NATIVE_AIO;
-        } else if (!strcmp(buf, "threads")) {
-            /* this is the default */
-        } else {
-           fprintf(stderr, "qemu: invalid aio option\n");
-           return NULL;
-        }
-    }
-#endif
-
-    if ((buf = qemu_opt_get(opts, "format")) != NULL) {
-       if (strcmp(buf, "?") == 0) {
-            fprintf(stderr, "qemu: Supported formats:");
-            bdrv_iterate_format(bdrv_format_print, NULL);
-            fprintf(stderr, "\n");
-	    return NULL;
-        }
-        drv = bdrv_find_whitelisted_format(buf);
-        if (!drv) {
-            fprintf(stderr, "qemu: '%s' invalid format\n", buf);
-            return NULL;
-        }
-    }
-
-    on_write_error = BLOCK_ERR_STOP_ENOSPC;
-    if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
-        if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
-            fprintf(stderr, "werror is no supported by this format\n");
-            return NULL;
-        }
-
-        on_write_error = parse_block_error_action(buf, 0);
-        if (on_write_error < 0) {
-            return NULL;
-        }
-    }
-
-    on_read_error = BLOCK_ERR_REPORT;
-    if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
-        if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
-            fprintf(stderr, "rerror is no supported by this format\n");
-            return NULL;
-        }
-
-        on_read_error = parse_block_error_action(buf, 1);
-        if (on_read_error < 0) {
-            return NULL;
-        }
-    }
-
-    if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
-        if (type != IF_VIRTIO) {
-            fprintf(stderr, "addr is not supported\n");
-            return NULL;
-        }
-    }
-
-    /* compute bus and unit according index */
-
-    if (index != -1) {
-        if (bus_id != 0 || unit_id != -1) {
-            fprintf(stderr,
-                    "qemu: index cannot be used with bus and unit\n");
-            return NULL;
-        }
-        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(type, bus_id, unit_id) != NULL) {
-           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: unit %d too big (max is %d)\n",
-                unit_id, max_devs - 1);
-        return NULL;
-    }
-
-    /*
-     * ignore multiple definitions
-     */
-
-    if (drive_get(type, bus_id, unit_id) != NULL) {
-        *fatal_error = 0;
-        return NULL;
-    }
-
-    /* init */
-
-    dinfo = qemu_mallocz(sizeof(*dinfo));
-    if ((buf = qemu_opts_id(opts)) != NULL) {
-        dinfo->id = qemu_strdup(buf);
-    } else {
-        /* no id supplied -> create one */
-        dinfo->id = qemu_mallocz(32);
-        if (type == IF_IDE || type == IF_SCSI)
-            mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
-        if (max_devs)
-            snprintf(dinfo->id, 32, "%s%i%s%i",
-                     devname, bus_id, mediastr, unit_id);
-        else
-            snprintf(dinfo->id, 32, "%s%s%i",
-                     devname, mediastr, unit_id);
-    }
-    dinfo->bdrv = bdrv_new(dinfo->id);
-    dinfo->devaddr = devaddr;
-    dinfo->type = type;
-    dinfo->bus = bus_id;
-    dinfo->unit = unit_id;
-    dinfo->on_read_error = on_read_error;
-    dinfo->on_write_error = on_write_error;
-    dinfo->opts = opts;
-    if (serial)
-        strncpy(dinfo->serial, serial, sizeof(serial));
-    QTAILQ_INSERT_TAIL(&drives, dinfo, next);
-
-    switch(type) {
-    case IF_IDE:
-    case IF_SCSI:
-    case IF_XEN:
-    case IF_NONE:
-        switch(media) {
-	case MEDIA_DISK:
-            if (cyls != 0) {
-                bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs);
-                bdrv_set_translation_hint(dinfo->bdrv, translation);
-            }
-	    break;
-	case MEDIA_CDROM:
-            bdrv_set_type_hint(dinfo->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(dinfo->bdrv, BDRV_TYPE_FLOPPY);
-        break;
-    case IF_PFLASH:
-    case IF_MTD:
-        break;
-    case IF_VIRTIO:
-        /* add virtio block device */
-        opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
-        qemu_opt_set(opts, "driver", "virtio-blk-pci");
-        qemu_opt_set(opts, "drive", dinfo->id);
-        if (devaddr)
-            qemu_opt_set(opts, "addr", devaddr);
-        break;
-    case IF_COUNT:
-        abort();
-    }
-    if (!file) {
-        *fatal_error = 0;
-        return NULL;
-    }
-    if (snapshot) {
-        /* always use cache=unsafe with snapshot */
-        bdrv_flags &= ~BDRV_O_CACHE_MASK;
-        bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
-    }
-
-    if (media == MEDIA_CDROM) {
-        /* CDROM is fine for any interface, don't check.  */
-        ro = 1;
-    } else if (ro == 1) {
-        if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
-            fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n");
-            return NULL;
-        }
-    }
-
-    bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
-
-    if (bdrv_open(dinfo->bdrv, file, bdrv_flags, drv) < 0) {
-        fprintf(stderr, "qemu: could not open disk image %s: %s\n",
-                        file, strerror(errno));
-        return NULL;
-    }
-
-    if (bdrv_key_required(dinfo->bdrv))
-        autostart = 0;
-    *fatal_error = 0;
-    return dinfo;
-}
-
 static int drive_init_func(QemuOpts *opts, void *opaque)
 {
-    QEMUMachine *machine = opaque;
+    int *use_scsi = opaque;
     int fatal_error = 0;
 
-    if (drive_init(opts, machine, &fatal_error) == NULL) {
+    if (drive_init(opts, *use_scsi, &fatal_error) == NULL) {
         if (fatal_error)
             return 1;
     }
@@ -1297,7 +813,7 @@ static void smp_parse(const char *optarg)
 /***********************************************************/
 /* USB devices */
 
-static int usb_device_add(const char *devname, int is_hotplug)
+static int usb_device_add(const char *devname)
 {
     const char *p;
     USBDevice *dev = NULL;
@@ -1349,7 +865,7 @@ static int usb_device_del(const char *devname)
 static int usb_parse(const char *cmdline)
 {
     int r;
-    r = usb_device_add(cmdline, 0);
+    r = usb_device_add(cmdline);
     if (r < 0) {
         fprintf(stderr, "qemu: could not add USB device '%s'\n", cmdline);
     }
@@ -1359,7 +875,7 @@ static int usb_parse(const char *cmdline)
 void do_usb_add(Monitor *mon, const QDict *qdict)
 {
     const char *devname = qdict_get_str(qdict, "devname");
-    if (usb_device_add(devname, 1) < 0) {
+    if (usb_device_add(devname) < 0) {
         error_report("could not add USB device '%s'", devname);
     }
 }
@@ -1841,6 +1357,7 @@ static void main_loop(void)
             vm_stop(r);
         }
     }
+    bdrv_close_all();
     pause_all_vcpus();
 }
 
@@ -3243,7 +2760,7 @@ int main(int argc, char **argv, char **envp)
     /* open the virtual block devices */
     if (snapshot)
         qemu_opts_foreach(&qemu_drive_opts, drive_enable_snapshot, NULL, 0);
-    if (qemu_opts_foreach(&qemu_drive_opts, drive_init_func, machine, 1) != 0)
+    if (qemu_opts_foreach(&qemu_drive_opts, drive_init_func, &machine->use_scsi, 1) != 0)
         exit(1);
 
     register_savevm_live("ram", 0, 3, NULL, ram_save_live, NULL,