From patchwork Wed Jun 2 16:48:27 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Markus Armbruster X-Patchwork-Id: 54392 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 36E6AB7D5C for ; Thu, 3 Jun 2010 02:58:47 +1000 (EST) Received: from localhost ([127.0.0.1]:58748 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OJrGP-0007lV-52 for incoming@patchwork.ozlabs.org; Wed, 02 Jun 2010 12:57:57 -0400 Received: from [140.186.70.92] (port=44207 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OJr7M-0002Z3-Vc for qemu-devel@nongnu.org; Wed, 02 Jun 2010 12:48:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OJr7J-00049p-9d for qemu-devel@nongnu.org; Wed, 02 Jun 2010 12:48:36 -0400 Received: from mx1.redhat.com ([209.132.183.28]:6337) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OJr7I-00049X-OD for qemu-devel@nongnu.org; Wed, 02 Jun 2010 12:48:33 -0400 Received: from int-mx05.intmail.prod.int.phx2.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.18]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o52GmVgq028780 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 2 Jun 2010 12:48:31 -0400 Received: from blackfin.pond.sub.org (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx05.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o52GmTEq030190; Wed, 2 Jun 2010 12:48:29 -0400 Received: by blackfin.pond.sub.org (Postfix, from userid 500) id D9CEA70; Wed, 2 Jun 2010 18:48:27 +0200 (CEST) From: Markus Armbruster To: qemu-devel@nongnu.org References: <1275478317-1989-1-git-send-email-armbru@redhat.com> <1275478317-1989-4-git-send-email-armbru@redhat.com> Date: Wed, 02 Jun 2010 18:48:27 +0200 In-Reply-To: <1275478317-1989-4-git-send-email-armbru@redhat.com> (Markus Armbruster's message of "Wed, 2 Jun 2010 13:31:57 +0200") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.67 on 10.5.11.18 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. Cc: kwolf@redhat.com Subject: [Qemu-devel] [PATCH v2 3/3] blockdev: Collect block device code in new blockdev.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Anything that moves hundreds of lines out of vl.c can't be all bad. Signed-off-by: Markus Armbruster --- v2: Licence boilerplate Makefile.objs | 2 +- blockdev.c | 600 ++++++++++++++++++++++++++++++++++++++++++++++++++ blockdev.h | 71 ++++++ hw/acpi_piix4.c | 1 + hw/apb_pci.c | 1 + hw/device-hotplug.c | 2 - hw/fdc.c | 1 - hw/fdc.h | 2 +- hw/ide/core.c | 2 - hw/ide/qdev.c | 1 - hw/lan9118.c | 1 + hw/nand.c | 3 +- hw/omap2.c | 2 + hw/onenand.c | 3 +- hw/parallel.c | 1 + hw/pc.c | 1 + hw/pc_piix.c | 1 + hw/pci-hotplug.c | 2 - hw/pcmcia.h | 2 +- hw/qdev-properties.c | 1 - hw/qdev.h | 2 +- hw/scsi-bus.c | 1 - hw/scsi-disk.c | 2 +- hw/scsi-generic.c | 1 - hw/serial.c | 1 + hw/usb-hid.c | 1 + hw/usb-msd.c | 2 +- hw/virtio-blk.c | 2 - hw/virtio-pci.c | 1 - monitor.c | 104 +--------- qemu-char.c | 1 - savevm.c | 2 +- sysemu.h | 49 ---- vl.c | 483 +---------------------------------------- 34 files changed, 692 insertions(+), 660 deletions(-) create mode 100644 blockdev.c create mode 100644 blockdev.h diff --git a/Makefile.objs b/Makefile.objs index 9796dcb..54dec26 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/blockdev.c b/blockdev.c new file mode 100644 index 0000000..bd9783a --- /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(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; + + 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 0000000..dfc9de1 --- /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 0fce958..a87286b 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 b53e3c3..31c8d70 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 a3fe99e..c1a9a56 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) { diff --git a/hw/fdc.c b/hw/fdc.c index 6306496..b978957 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 c48b5e0..b6b3772 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/core.c b/hw/ide/core.c index 70af1b6..045d18d 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -26,8 +26,6 @@ #include #include #include -#include "block.h" -#include "block_int.h" #include "qemu-timer.h" #include "sysemu.h" #include "dma.h" diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 6231d77..0f9f22e 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -17,7 +17,6 @@ * License along with this library; if not, see . */ #include -#include "sysemu.h" #include "dma.h" #include diff --git a/hw/lan9118.c b/hw/lan9118.c index 16d3330..b996dc4 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 diff --git a/hw/nand.c b/hw/nand.c index 40d5a6a..cd7444f 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 bd1b35e..666c15a 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 . */ + +#include "blockdev.h" #include "hw.h" #include "arm-misc.h" #include "omap.h" diff --git a/hw/onenand.c b/hw/onenand.c index c1e7e4d..4118db9 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 be8e2d5..6b11672 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 9b85c42..6e7c468 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -35,6 +35,7 @@ #include "elf.h" #include "multiboot.h" #include "mc146818rtc.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 70f563a..dc46846 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 a8f3df1..c39e640 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 cf2db9d..3602923 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/qdev-properties.c b/hw/qdev-properties.c index 48a6b45..5a8739d 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" diff --git a/hw/qdev.h b/hw/qdev.h index 0ad6c95..be5ad67 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" diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 383240b..055a94d 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 a3559d1..a9bf7d2 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 diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index c9aa853..e31060e 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 9102edb..c7e4e77 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/usb-hid.c b/hw/usb-hid.c index 8e6c6e0..228d0a0 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 0ba4a64..003bd8a 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 diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index 80d51c4..cdcb492 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -12,9 +12,7 @@ */ #include -#include #include "virtio-blk.h" -#include "block_int.h" #ifdef __linux__ # include #endif diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 7ddf612..e101fa0 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 15b53b9..57f24ff 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; @@ -949,93 +934,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 faaf624..87628ea 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/savevm.c b/savevm.c index dc20390..18852cd 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 dce13c1..5fa45ed 100644 --- a/sysemu.h +++ b/sysemu.h @@ -147,55 +147,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 - -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); - /* 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 db1fefd..0a9862f 100644 --- a/vl.c +++ b/vl.c @@ -140,7 +140,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" @@ -172,7 +172,6 @@ int main(int argc, char **argv) static const char *data_dir; const char *bios_name = NULL; -struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives); enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; DisplayType display_type = DT_DEFAULT; const char* keyboard_layout = NULL; @@ -651,486 +650,6 @@ 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, 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(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; - - 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; -} - static int drive_init_func(QemuOpts *opts, void *opaque) { int *use_scsi = opaque;