1cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner/*
2cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner * QEMU host block devices
3cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner *
4cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner * Copyright (c) 2003-2008 Fabrice Bellard
5cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner *
6cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner * This work is licensed under the terms of the GNU GPL, version 2 or
7cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner * later.  See the COPYING file in the top-level directory.
8cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner */
9cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
10e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "block/block.h"
1134c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/blockdev.h"
126af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turner#include "monitor/monitor.h"
131c31e3e43ce4cca85a707dfff631e5e102fdecedDavid 'Digit' Turner#include "qapi/qmp/qerror.h"
1493e0d9cfb6d950b638ba93cf5318e5689e4ba64eDavid 'Digit' Turner#include "qemu/option.h"
151c31e3e43ce4cca85a707dfff631e5e102fdecedDavid 'Digit' Turner#include "qemu/config-file.h"
1634c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/sysemu.h"
17cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
18cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerstatic QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
19cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
20cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner/*
21cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner * We automatically delete the drive when a device using it gets
22cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner * unplugged.  Questionable feature, but we can't just drop it.
23cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner * Device models call blockdev_mark_auto_del() to schedule the
24cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner * automatic deletion, and generic qdev code calls blockdev_auto_del()
25cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner * when deletion is actually safe.
26cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner */
27cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnervoid blockdev_mark_auto_del(BlockDriverState *bs)
28cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
29cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    DriveInfo *dinfo = drive_get_by_blockdev(bs);
30cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
31cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    dinfo->auto_del = 1;
32cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
33cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
34cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnervoid blockdev_auto_del(BlockDriverState *bs)
35cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
36cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    DriveInfo *dinfo = drive_get_by_blockdev(bs);
37cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
38cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (dinfo->auto_del) {
39cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        drive_uninit(dinfo);
40cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
41cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
42cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
43cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' TurnerQemuOpts *drive_add(const char *file, const char *fmt, ...)
44cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
45cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    va_list ap;
46cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    char optstr[1024];
47cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    QemuOpts *opts;
48cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
49cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    va_start(ap, fmt);
50cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    vsnprintf(optstr, sizeof(optstr), fmt, ap);
51cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    va_end(ap);
52cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
53cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    opts = qemu_opts_parse(qemu_find_opts("drive"), optstr, 0);
54cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (!opts) {
55cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return NULL;
56cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
57cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (file)
58cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        qemu_opt_set(opts, "file", file);
59cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    return opts;
60cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
61cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
62cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' TurnerDriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
63cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
64cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    DriveInfo *dinfo;
65cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
66cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    /* seek interface, bus and unit */
67cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
68cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    QTAILQ_FOREACH(dinfo, &drives, next) {
69cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (dinfo->type == type &&
70cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    dinfo->bus == bus &&
71cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    dinfo->unit == unit)
72cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return dinfo;
73cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
74cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
75cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    return NULL;
76cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
77cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
78cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerint drive_get_max_bus(BlockInterfaceType type)
79cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
80cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int max_bus;
81cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    DriveInfo *dinfo;
82cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
83cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    max_bus = -1;
84cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    QTAILQ_FOREACH(dinfo, &drives, next) {
85cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if(dinfo->type == type &&
86cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner           dinfo->bus > max_bus)
87cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_bus = dinfo->bus;
88cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
89cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    return max_bus;
90cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
91cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
92cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' TurnerDriveInfo *drive_get_by_blockdev(BlockDriverState *bs)
93cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
94cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    DriveInfo *dinfo;
95cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
96cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    QTAILQ_FOREACH(dinfo, &drives, next) {
97cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (dinfo->bdrv == bs) {
98cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return dinfo;
99cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
100cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
101cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    return NULL;
102cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
103cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
104cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerstatic void bdrv_format_print(void *opaque, const char *name)
105cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
106cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    fprintf(stderr, " %s", name);
107cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
108cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
109cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnervoid drive_uninit(DriveInfo *dinfo)
110cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
111cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    qemu_opts_del(dinfo->opts);
112cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bdrv_delete(dinfo->bdrv);
113cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    QTAILQ_REMOVE(&drives, dinfo, next);
114aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(dinfo);
115cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
116cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
117cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerstatic int parse_block_error_action(const char *buf, int is_read)
118cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
119cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (!strcmp(buf, "ignore")) {
120cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return BLOCK_ERR_IGNORE;
121cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else if (!is_read && !strcmp(buf, "enospc")) {
122cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return BLOCK_ERR_STOP_ENOSPC;
123cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else if (!strcmp(buf, "stop")) {
124cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return BLOCK_ERR_STOP_ANY;
125cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else if (!strcmp(buf, "report")) {
126cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return BLOCK_ERR_REPORT;
127cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else {
128cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        fprintf(stderr, "qemu: '%s' invalid %s error action\n",
129cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            buf, is_read ? "read" : "write");
130cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return -1;
131cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
132cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
133cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
134cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' TurnerDriveInfo *drive_init(QemuOpts *opts, int default_to_scsi, int *fatal_error)
135cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
136cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    const char *buf;
137cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    const char *file = NULL;
138cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    char devname[128];
139cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    const char *serial;
140cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    const char *mediastr = "";
141cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    BlockInterfaceType type;
142cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    enum { MEDIA_DISK, MEDIA_CDROM } media;
143cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int bus_id, unit_id;
144cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int cyls, heads, secs, translation;
145cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    BlockDriver *drv = NULL;
146cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int max_devs;
147cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int index;
148cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int ro = 0;
149cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int bdrv_flags = 0;
150cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int on_read_error, on_write_error;
151cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    const char *devaddr;
152cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    DriveInfo *dinfo;
153cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int snapshot = 0;
154cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int ret;
155cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
156cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    *fatal_error = 1;
157cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
158cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    translation = BIOS_ATA_TRANSLATION_AUTO;
159cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
160cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (default_to_scsi) {
161cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        type = IF_SCSI;
162cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        max_devs = MAX_SCSI_DEVS;
163cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        pstrcpy(devname, sizeof(devname), "scsi");
164cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else {
165cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        type = IF_IDE;
166cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        max_devs = MAX_IDE_DEVS;
167cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        pstrcpy(devname, sizeof(devname), "ide");
168cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
169cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    media = MEDIA_DISK;
170cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
171cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    /* extract parameters */
172cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bus_id  = qemu_opt_get_number(opts, "bus", 0);
173cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    unit_id = qemu_opt_get_number(opts, "unit", -1);
174cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    index   = qemu_opt_get_number(opts, "index", -1);
175cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
176cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    cyls  = qemu_opt_get_number(opts, "cyls", 0);
177cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    heads = qemu_opt_get_number(opts, "heads", 0);
178cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    secs  = qemu_opt_get_number(opts, "secs", 0);
179cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
180cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
181cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    ro = qemu_opt_get_bool(opts, "readonly", 0);
182cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
183cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    file = qemu_opt_get(opts, "file");
184cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    serial = qemu_opt_get(opts, "serial");
185cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
186cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((buf = qemu_opt_get(opts, "if")) != NULL) {
187cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        pstrcpy(devname, sizeof(devname), buf);
188cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!strcmp(buf, "ide")) {
189cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    type = IF_IDE;
190cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_devs = MAX_IDE_DEVS;
191cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else if (!strcmp(buf, "scsi")) {
192cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    type = IF_SCSI;
193cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_devs = MAX_SCSI_DEVS;
194cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else if (!strcmp(buf, "floppy")) {
195cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    type = IF_FLOPPY;
196cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_devs = 0;
197cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else if (!strcmp(buf, "pflash")) {
198cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    type = IF_PFLASH;
199cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_devs = 0;
200cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	} else if (!strcmp(buf, "mtd")) {
201cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    type = IF_MTD;
202cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_devs = 0;
203cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	} else if (!strcmp(buf, "sd")) {
204cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    type = IF_SD;
205cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_devs = 0;
206cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else if (!strcmp(buf, "virtio")) {
207cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            type = IF_VIRTIO;
208cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_devs = 0;
209cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	} else if (!strcmp(buf, "xen")) {
210cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    type = IF_XEN;
211cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_devs = 0;
212cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	} else if (!strcmp(buf, "none")) {
213cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    type = IF_NONE;
214cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            max_devs = 0;
215cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	} else {
216cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf);
217cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
218cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	}
219cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
220cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
221cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (cyls || heads || secs) {
222cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (cyls < 1 || (type == IF_IDE && cyls > 16383)) {
223cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf);
224cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    return NULL;
225cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	}
226cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (heads < 1 || (type == IF_IDE && heads > 16)) {
227cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf);
228cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    return NULL;
229cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	}
230cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (secs < 1 || (type == IF_IDE && secs > 63)) {
231cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf);
232cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    return NULL;
233cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	}
234cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
235cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
236cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
237cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!cyls) {
238cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr,
239cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                    "qemu: '%s' trans must be used with cyls,heads and secs\n",
240cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                    buf);
241cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
242cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
243cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!strcmp(buf, "none"))
244cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            translation = BIOS_ATA_TRANSLATION_NONE;
245cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        else if (!strcmp(buf, "lba"))
246cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            translation = BIOS_ATA_TRANSLATION_LBA;
247cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        else if (!strcmp(buf, "auto"))
248cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            translation = BIOS_ATA_TRANSLATION_AUTO;
249cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	else {
250cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "qemu: '%s' invalid translation type\n", buf);
251cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    return NULL;
252cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	}
253cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
254cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
255cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((buf = qemu_opt_get(opts, "media")) != NULL) {
256cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!strcmp(buf, "disk")) {
257cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    media = MEDIA_DISK;
258cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	} else if (!strcmp(buf, "cdrom")) {
259cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            if (cyls || secs || heads) {
260cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                fprintf(stderr,
261cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                        "qemu: '%s' invalid physical CHS format\n", buf);
262cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	        return NULL;
263cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            }
264cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    media = MEDIA_CDROM;
265cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	} else {
266cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    fprintf(stderr, "qemu: '%s' invalid media\n", buf);
267cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    return NULL;
268cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	}
269cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
270cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
271cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
272cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!strcmp(buf, "off") || !strcmp(buf, "none")) {
273cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            bdrv_flags |= BDRV_O_NOCACHE;
274cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else if (!strcmp(buf, "writeback")) {
275cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            bdrv_flags |= BDRV_O_CACHE_WB;
276cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else if (!strcmp(buf, "unsafe")) {
277cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            bdrv_flags |= BDRV_O_CACHE_WB;
278cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            bdrv_flags |= BDRV_O_NO_FLUSH;
279cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else if (!strcmp(buf, "writethrough")) {
280cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            /* this is the default */
281cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else {
282cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner           fprintf(stderr, "qemu: invalid cache option\n");
283cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner           return NULL;
284cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
285cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
286cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
287cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#ifdef CONFIG_LINUX_AIO
288cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((buf = qemu_opt_get(opts, "aio")) != NULL) {
289cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!strcmp(buf, "native")) {
290cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            bdrv_flags |= BDRV_O_NATIVE_AIO;
291cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else if (!strcmp(buf, "threads")) {
292cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            /* this is the default */
293cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else {
294cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner           fprintf(stderr, "qemu: invalid aio option\n");
295cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner           return NULL;
296cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
297cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
298cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner#endif
299cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
300cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((buf = qemu_opt_get(opts, "format")) != NULL) {
301cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner       if (strcmp(buf, "?") == 0) {
302cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "qemu: Supported formats:");
303cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            bdrv_iterate_format(bdrv_format_print, NULL);
304cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "\n");
305cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    return NULL;
306cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
307cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        drv = bdrv_find_whitelisted_format(buf);
308cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!drv) {
309cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "qemu: '%s' invalid format\n", buf);
310cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
311cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
312cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
313cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
314cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    on_write_error = BLOCK_ERR_STOP_ENOSPC;
315cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
316cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
317cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "werror is no supported by this format\n");
318cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
319cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
320cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
321cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        on_write_error = parse_block_error_action(buf, 0);
322cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (on_write_error < 0) {
323cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
324cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
325cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
326cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
327cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    on_read_error = BLOCK_ERR_REPORT;
328cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
329cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (type != IF_IDE && type != IF_VIRTIO && type != IF_NONE) {
330cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "rerror is no supported by this format\n");
331cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
332cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
333cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
334cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        on_read_error = parse_block_error_action(buf, 1);
335cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (on_read_error < 0) {
336cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
337cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
338cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
339cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
340cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
341cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (type != IF_VIRTIO) {
342cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "addr is not supported\n");
343cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
344cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
345cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
346cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
347cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    /* compute bus and unit according index */
348cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
349cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (index != -1) {
350cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (bus_id != 0 || unit_id != -1) {
351cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr,
352cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                    "qemu: index cannot be used with bus and unit\n");
353cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
354cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
355cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (max_devs == 0)
356cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        {
357cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            unit_id = index;
358cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            bus_id = 0;
359cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        } else {
360cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            unit_id = index % max_devs;
361cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            bus_id = index / max_devs;
362cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
363cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
364cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
365cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    /* if user doesn't specify a unit_id,
366cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     * try to find the first free
367cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     */
368cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
369cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (unit_id == -1) {
370cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner       unit_id = 0;
371cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner       while (drive_get(type, bus_id, unit_id) != NULL) {
372cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner           unit_id++;
373cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner           if (max_devs && unit_id >= max_devs) {
374cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner               unit_id -= max_devs;
375cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner               bus_id++;
376cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner           }
377cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner       }
378cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
379cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
380cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    /* check unit id */
381cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
382cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (max_devs && unit_id >= max_devs) {
383cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        fprintf(stderr, "qemu: unit %d too big (max is %d)\n",
384cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                unit_id, max_devs - 1);
385cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return NULL;
386cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
387cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
388cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    /*
389cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     * ignore multiple definitions
390cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner     */
391cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
392cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (drive_get(type, bus_id, unit_id) != NULL) {
393cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        *fatal_error = 0;
394cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return NULL;
395cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
396cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
397cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    /* init */
398cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
399aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    dinfo = g_malloc0(sizeof(*dinfo));
400cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if ((buf = qemu_opts_id(opts)) != NULL) {
401aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        dinfo->id = g_strdup(buf);
402cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else {
403cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /* no id supplied -> create one */
404aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        dinfo->id = g_malloc0(32);
405cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (type == IF_IDE || type == IF_SCSI)
406cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
407cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (max_devs)
408cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            snprintf(dinfo->id, 32, "%s%i%s%i",
409cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                     devname, bus_id, mediastr, unit_id);
410cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        else
411cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            snprintf(dinfo->id, 32, "%s%s%i",
412cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                     devname, mediastr, unit_id);
413cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
414cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    dinfo->bdrv = bdrv_new(dinfo->id);
415cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    dinfo->devaddr = devaddr;
416cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    dinfo->type = type;
417cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    dinfo->bus = bus_id;
418cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    dinfo->unit = unit_id;
419cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    dinfo->opts = opts;
420cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (serial)
421cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1);
422cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    QTAILQ_INSERT_TAIL(&drives, dinfo, next);
423cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
424cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
425cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
426cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    switch(type) {
427cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_IDE:
428cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_SCSI:
429cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_XEN:
430cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_NONE:
431cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        switch(media) {
432cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	case MEDIA_DISK:
433cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            if (cyls != 0) {
434cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs);
435cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                bdrv_set_translation_hint(dinfo->bdrv, translation);
436cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            }
437cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    break;
438cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	case MEDIA_CDROM:
439cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_CDROM);
440cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	    break;
441cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner	}
442cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        break;
443cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_SD:
444cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /* FIXME: This isn't really a floppy, but it's a reasonable
445cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner           approximation.  */
446cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_FLOPPY:
447cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_FLOPPY);
448cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        break;
449cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_PFLASH:
450cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_MTD:
451cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        break;
452cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_VIRTIO:
453cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /* add virtio block device */
454cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
455cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        qemu_opt_set(opts, "driver", "virtio-blk-pci");
456cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        qemu_opt_set(opts, "drive", dinfo->id);
457cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (devaddr)
458cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            qemu_opt_set(opts, "addr", devaddr);
459cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        break;
460cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    case IF_COUNT:
461cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        abort();
462cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
463cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (!file || !*file) {
464cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        *fatal_error = 0;
465cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return NULL;
466cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
467cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (snapshot) {
468cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /* always use cache=unsafe with snapshot */
469cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        bdrv_flags &= ~BDRV_O_CACHE_MASK;
470cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH);
471cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
472cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
473cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (media == MEDIA_CDROM) {
474cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        /* CDROM is fine for any interface, don't check.  */
475cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        ro = 1;
476cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else if (ro == 1) {
477cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
478cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n");
479cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return NULL;
480cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
481cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
482cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
483cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
484cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
485cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    ret = bdrv_open(dinfo->bdrv, file, bdrv_flags, drv);
486cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (ret < 0) {
487cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        fprintf(stderr, "qemu: could not open disk image %s: %s\n",
488cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                        file, strerror(-ret));
489cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return NULL;
490cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
491cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
492cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (bdrv_key_required(dinfo->bdrv))
493cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        autostart = 0;
494cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    *fatal_error = 0;
495cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    return dinfo;
496cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
497cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
498cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnervoid do_commit(Monitor *mon, const QDict *qdict)
499cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
500cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    const char *device = qdict_get_str(qdict, "device");
501cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    BlockDriverState *bs;
502cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
503cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (!strcmp(device, "all")) {
504cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        bdrv_commit_all();
505cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else {
506cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        bs = bdrv_find(device);
507cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!bs) {
508cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            qerror_report(QERR_DEVICE_NOT_FOUND, device);
509cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return;
510cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
511cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        bdrv_commit(bs);
512cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
513cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
514cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
515cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerstatic int eject_device(Monitor *mon, BlockDriverState *bs, int force)
516cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
517cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (!force) {
518cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!bdrv_is_removable(bs)) {
519cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            qerror_report(QERR_DEVICE_NOT_REMOVABLE,
520cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                           bdrv_get_device_name(bs));
521cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return -1;
522cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
523cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (bdrv_is_locked(bs)) {
524cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
525cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return -1;
526cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
527cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
528cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bdrv_close(bs);
529cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    return 0;
530cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
531cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
532cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerint do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
533cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
534cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    BlockDriverState *bs;
535cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int force = qdict_get_try_bool(qdict, "force", 0);
536cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    const char *filename = qdict_get_str(qdict, "device");
537cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
538cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs = bdrv_find(filename);
539cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (!bs) {
540cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        qerror_report(QERR_DEVICE_NOT_FOUND, filename);
541cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return -1;
542cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
543cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    return eject_device(mon, bs, force);
544cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
545cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
546cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerint do_block_set_passwd(Monitor *mon, const QDict *qdict,
547cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                        QObject **ret_data)
548cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
549cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    BlockDriverState *bs;
550cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int err;
551cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
552cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs = bdrv_find(qdict_get_str(qdict, "device"));
553cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (!bs) {
554cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
555cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return -1;
556cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
557cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
558cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    err = bdrv_set_key(bs, qdict_get_str(qdict, "password"));
559cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (err == -EINVAL) {
560cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
561cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return -1;
562cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    } else if (err < 0) {
563cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        qerror_report(QERR_INVALID_PASSWORD);
564cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return -1;
565cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
566cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
567cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    return 0;
568cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
569cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
570aa1180ca05774398245953deb306c0e25829afeeDavid 'Digit' Turner#ifndef CONFIG_ANDROID
571aa1180ca05774398245953deb306c0e25829afeeDavid 'Digit' Turner// Monitor support disabled on Android.
572cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turnerint do_change_block(Monitor *mon, const char *device,
573cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner                    const char *filename, const char *fmt)
574cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner{
575cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    BlockDriverState *bs;
576cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    BlockDriver *drv = NULL;
577cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    int bdrv_flags;
578cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner
579cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bs = bdrv_find(device);
580cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (!bs) {
581cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        qerror_report(QERR_DEVICE_NOT_FOUND, device);
582cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return -1;
583cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
584cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (fmt) {
585cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        drv = bdrv_find_whitelisted_format(fmt);
586cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        if (!drv) {
587cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
588cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner            return -1;
589cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        }
590cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
591cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (eject_device(mon, bs, 0) < 0) {
592cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return -1;
593cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
594cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
595cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
596cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
597910aea96b67d7f0357f586c47f20848ec435aa1bDavid 'Digit' Turner        qerror_report(QERR_IO_ERROR);
598cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner        return -1;
599cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    }
600cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner    return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
601cb42a1b1461e02efb034582ac5d8f71534723b92David 'Digit' Turner}
602aa1180ca05774398245953deb306c0e25829afeeDavid 'Digit' Turner#endif
603