mirror of https://github.com/xqemu/xqemu.git
Merge remote-tracking branch 'kwolf/for-anthony' into staging
This commit is contained in:
commit
220724ca4a
10
async.c
10
async.c
|
@ -55,6 +55,9 @@ int qemu_bh_poll(void)
|
||||||
{
|
{
|
||||||
QEMUBH *bh, **bhp, *next;
|
QEMUBH *bh, **bhp, *next;
|
||||||
int ret;
|
int ret;
|
||||||
|
static int nesting = 0;
|
||||||
|
|
||||||
|
nesting++;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
for (bh = first_bh; bh; bh = next) {
|
for (bh = first_bh; bh; bh = next) {
|
||||||
|
@ -68,16 +71,21 @@ int qemu_bh_poll(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nesting--;
|
||||||
|
|
||||||
/* remove deleted bhs */
|
/* remove deleted bhs */
|
||||||
|
if (!nesting) {
|
||||||
bhp = &first_bh;
|
bhp = &first_bh;
|
||||||
while (*bhp) {
|
while (*bhp) {
|
||||||
bh = *bhp;
|
bh = *bhp;
|
||||||
if (bh->deleted) {
|
if (bh->deleted) {
|
||||||
*bhp = bh->next;
|
*bhp = bh->next;
|
||||||
g_free(bh);
|
g_free(bh);
|
||||||
} else
|
} else {
|
||||||
bhp = &bh->next;
|
bhp = &bh->next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
104
block.c
104
block.c
|
@ -44,6 +44,7 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void bdrv_dev_change_media_cb(BlockDriverState *bs);
|
||||||
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
|
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
|
||||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque);
|
BlockDriverCompletionFunc *cb, void *opaque);
|
||||||
|
@ -688,10 +689,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bdrv_key_required(bs)) {
|
if (!bdrv_key_required(bs)) {
|
||||||
/* call the change callback */
|
bdrv_dev_change_media_cb(bs);
|
||||||
bs->media_changed = 1;
|
|
||||||
if (bs->change_cb)
|
|
||||||
bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -727,10 +725,7 @@ void bdrv_close(BlockDriverState *bs)
|
||||||
bdrv_close(bs->file);
|
bdrv_close(bs->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call the change callback */
|
bdrv_dev_change_media_cb(bs);
|
||||||
bs->media_changed = 1;
|
|
||||||
if (bs->change_cb)
|
|
||||||
bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,7 +750,7 @@ void bdrv_make_anon(BlockDriverState *bs)
|
||||||
|
|
||||||
void bdrv_delete(BlockDriverState *bs)
|
void bdrv_delete(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
assert(!bs->peer);
|
assert(!bs->dev);
|
||||||
|
|
||||||
/* remove from list, if necessary */
|
/* remove from list, if necessary */
|
||||||
bdrv_make_anon(bs);
|
bdrv_make_anon(bs);
|
||||||
|
@ -769,26 +764,58 @@ void bdrv_delete(BlockDriverState *bs)
|
||||||
g_free(bs);
|
g_free(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_attach(BlockDriverState *bs, DeviceState *qdev)
|
int bdrv_attach_dev(BlockDriverState *bs, void *dev)
|
||||||
|
/* TODO change to DeviceState *dev when all users are qdevified */
|
||||||
{
|
{
|
||||||
if (bs->peer) {
|
if (bs->dev) {
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
bs->peer = qdev;
|
bs->dev = dev;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_detach(BlockDriverState *bs, DeviceState *qdev)
|
/* TODO qdevified devices don't use this, remove when devices are qdevified */
|
||||||
|
void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
|
||||||
{
|
{
|
||||||
assert(bs->peer == qdev);
|
if (bdrv_attach_dev(bs, dev) < 0) {
|
||||||
bs->peer = NULL;
|
abort();
|
||||||
bs->change_cb = NULL;
|
}
|
||||||
bs->change_opaque = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceState *bdrv_get_attached(BlockDriverState *bs)
|
void bdrv_detach_dev(BlockDriverState *bs, void *dev)
|
||||||
|
/* TODO change to DeviceState *dev when all users are qdevified */
|
||||||
{
|
{
|
||||||
return bs->peer;
|
assert(bs->dev == dev);
|
||||||
|
bs->dev = NULL;
|
||||||
|
bs->dev_ops = NULL;
|
||||||
|
bs->dev_opaque = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO change to return DeviceState * when all users are qdevified */
|
||||||
|
void *bdrv_get_attached_dev(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
return bs->dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
bs->dev_ops = ops;
|
||||||
|
bs->dev_opaque = opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bdrv_dev_change_media_cb(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
if (bs->dev_ops && bs->dev_ops->change_media_cb) {
|
||||||
|
bs->dev_ops->change_media_cb(bs->dev_opaque);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bdrv_dev_resize_cb(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
if (bs->dev_ops && bs->dev_ops->resize_cb) {
|
||||||
|
bs->dev_ops->resize_cb(bs->dev_opaque);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1261,9 +1288,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
|
||||||
ret = drv->bdrv_truncate(bs, offset);
|
ret = drv->bdrv_truncate(bs, offset);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
|
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
|
||||||
if (bs->change_cb) {
|
bdrv_dev_resize_cb(bs);
|
||||||
bs->change_cb(bs->change_opaque, CHANGE_SIZE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1601,15 +1626,6 @@ int bdrv_enable_write_cache(BlockDriverState *bs)
|
||||||
return bs->enable_write_cache;
|
return bs->enable_write_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: no longer used */
|
|
||||||
void bdrv_set_change_cb(BlockDriverState *bs,
|
|
||||||
void (*change_cb)(void *opaque, int reason),
|
|
||||||
void *opaque)
|
|
||||||
{
|
|
||||||
bs->change_cb = change_cb;
|
|
||||||
bs->change_opaque = opaque;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bdrv_is_encrypted(BlockDriverState *bs)
|
int bdrv_is_encrypted(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
if (bs->backing_hd && bs->backing_hd->encrypted)
|
if (bs->backing_hd && bs->backing_hd->encrypted)
|
||||||
|
@ -1647,9 +1663,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
|
||||||
} else if (!bs->valid_key) {
|
} else if (!bs->valid_key) {
|
||||||
bs->valid_key = 1;
|
bs->valid_key = 1;
|
||||||
/* call the change callback now, we skipped it on open */
|
/* call the change callback now, we skipped it on open */
|
||||||
bs->media_changed = 1;
|
bdrv_dev_change_media_cb(bs);
|
||||||
if (bs->change_cb)
|
|
||||||
bs->change_cb(bs->change_opaque, CHANGE_MEDIA);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1739,8 +1753,7 @@ void bdrv_flush_all(void)
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
|
||||||
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
||||||
if (bs->drv && !bdrv_is_read_only(bs) &&
|
if (!bdrv_is_read_only(bs) && bdrv_is_inserted(bs)) {
|
||||||
(!bdrv_is_removable(bs) || bdrv_is_inserted(bs))) {
|
|
||||||
bdrv_flush(bs);
|
bdrv_flush(bs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2084,7 +2097,7 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event)
|
||||||
int bdrv_can_snapshot(BlockDriverState *bs)
|
int bdrv_can_snapshot(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
if (!drv || bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
|
if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3023,22 +3036,17 @@ int bdrv_is_inserted(BlockDriverState *bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return TRUE if the media changed since the last call to this
|
* Return whether the media changed since the last call to this
|
||||||
* function. It is currently only used for floppy disks
|
* function, or -ENOTSUP if we don't know. Most drivers don't know.
|
||||||
*/
|
*/
|
||||||
int bdrv_media_changed(BlockDriverState *bs)
|
int bdrv_media_changed(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!drv || !drv->bdrv_media_changed)
|
if (drv && drv->bdrv_media_changed) {
|
||||||
ret = -ENOTSUP;
|
return drv->bdrv_media_changed(bs);
|
||||||
else
|
}
|
||||||
ret = drv->bdrv_media_changed(bs);
|
return -ENOTSUP;
|
||||||
if (ret == -ENOTSUP)
|
|
||||||
ret = bs->media_changed;
|
|
||||||
bs->media_changed = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
28
block.h
28
block.h
|
@ -28,6 +28,20 @@ typedef struct QEMUSnapshotInfo {
|
||||||
uint64_t vm_clock_nsec; /* VM clock relative to boot */
|
uint64_t vm_clock_nsec; /* VM clock relative to boot */
|
||||||
} QEMUSnapshotInfo;
|
} QEMUSnapshotInfo;
|
||||||
|
|
||||||
|
/* Callbacks for block device models */
|
||||||
|
typedef struct BlockDevOps {
|
||||||
|
/*
|
||||||
|
* Runs when virtual media changed (monitor commands eject, change)
|
||||||
|
* Beware: doesn't run when a host device's physical media
|
||||||
|
* changes. Sure would be useful if it did.
|
||||||
|
*/
|
||||||
|
void (*change_media_cb)(void *opaque);
|
||||||
|
/*
|
||||||
|
* Runs when the size changed (e.g. monitor command block_resize)
|
||||||
|
*/
|
||||||
|
void (*resize_cb)(void *opaque);
|
||||||
|
} BlockDevOps;
|
||||||
|
|
||||||
#define BDRV_O_RDWR 0x0002
|
#define BDRV_O_RDWR 0x0002
|
||||||
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
|
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
|
||||||
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
|
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
|
||||||
|
@ -74,9 +88,12 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
|
||||||
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
||||||
BlockDriver *drv);
|
BlockDriver *drv);
|
||||||
void bdrv_close(BlockDriverState *bs);
|
void bdrv_close(BlockDriverState *bs);
|
||||||
int bdrv_attach(BlockDriverState *bs, DeviceState *qdev);
|
int bdrv_attach_dev(BlockDriverState *bs, void *dev);
|
||||||
void bdrv_detach(BlockDriverState *bs, DeviceState *qdev);
|
void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
|
||||||
DeviceState *bdrv_get_attached(BlockDriverState *bs);
|
void bdrv_detach_dev(BlockDriverState *bs, void *dev);
|
||||||
|
void *bdrv_get_attached_dev(BlockDriverState *bs);
|
||||||
|
void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
|
||||||
|
void *opaque);
|
||||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors);
|
uint8_t *buf, int nb_sectors);
|
||||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
|
@ -192,9 +209,6 @@ int bdrv_media_changed(BlockDriverState *bs);
|
||||||
int bdrv_is_locked(BlockDriverState *bs);
|
int bdrv_is_locked(BlockDriverState *bs);
|
||||||
void bdrv_set_locked(BlockDriverState *bs, int locked);
|
void bdrv_set_locked(BlockDriverState *bs, int locked);
|
||||||
int bdrv_eject(BlockDriverState *bs, int eject_flag);
|
int bdrv_eject(BlockDriverState *bs, int eject_flag);
|
||||||
void bdrv_set_change_cb(BlockDriverState *bs,
|
|
||||||
void (*change_cb)(void *opaque, int reason),
|
|
||||||
void *opaque);
|
|
||||||
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
|
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
|
||||||
BlockDriverState *bdrv_find(const char *name);
|
BlockDriverState *bdrv_find(const char *name);
|
||||||
BlockDriverState *bdrv_next(BlockDriverState *bs);
|
BlockDriverState *bdrv_next(BlockDriverState *bs);
|
||||||
|
@ -244,6 +258,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
|
||||||
const char *base_filename, const char *base_fmt,
|
const char *base_filename, const char *base_fmt,
|
||||||
char *options, uint64_t img_size, int flags);
|
char *options, uint64_t img_size, int flags);
|
||||||
|
|
||||||
|
void *qemu_blockalign(BlockDriverState *bs, size_t size);
|
||||||
|
|
||||||
#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
|
#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
|
||||||
|
|
||||||
void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
|
void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
|
||||||
|
|
|
@ -526,13 +526,14 @@ static int qcow2_co_writev(BlockDriverState *bs,
|
||||||
int n_end;
|
int n_end;
|
||||||
int ret;
|
int ret;
|
||||||
int cur_nr_sectors; /* number of sectors in current iteration */
|
int cur_nr_sectors; /* number of sectors in current iteration */
|
||||||
QCowL2Meta l2meta;
|
|
||||||
uint64_t cluster_offset;
|
uint64_t cluster_offset;
|
||||||
QEMUIOVector hd_qiov;
|
QEMUIOVector hd_qiov;
|
||||||
uint64_t bytes_done = 0;
|
uint64_t bytes_done = 0;
|
||||||
uint8_t *cluster_data = NULL;
|
uint8_t *cluster_data = NULL;
|
||||||
|
QCowL2Meta l2meta = {
|
||||||
|
.nb_clusters = 0,
|
||||||
|
};
|
||||||
|
|
||||||
l2meta.nb_clusters = 0;
|
|
||||||
qemu_co_queue_init(&l2meta.dependent_requests);
|
qemu_co_queue_init(&l2meta.dependent_requests);
|
||||||
|
|
||||||
qemu_iovec_init(&hd_qiov, qiov->niov);
|
qemu_iovec_init(&hd_qiov, qiov->niov);
|
||||||
|
@ -592,13 +593,12 @@ static int qcow2_co_writev(BlockDriverState *bs,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_alloc_cluster_link_l2(bs, &l2meta);
|
ret = qcow2_alloc_cluster_link_l2(bs, &l2meta);
|
||||||
|
|
||||||
run_dependent_requests(s, &l2meta);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run_dependent_requests(s, &l2meta);
|
||||||
|
|
||||||
remaining_sectors -= cur_nr_sectors;
|
remaining_sectors -= cur_nr_sectors;
|
||||||
sector_num += cur_nr_sectors;
|
sector_num += cur_nr_sectors;
|
||||||
bytes_done += cur_nr_sectors * 512;
|
bytes_done += cur_nr_sectors * 512;
|
||||||
|
@ -606,6 +606,8 @@ static int qcow2_co_writev(BlockDriverState *bs,
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
run_dependent_requests(s, &l2meta);
|
||||||
|
|
||||||
qemu_co_mutex_unlock(&s->lock);
|
qemu_co_mutex_unlock(&s->lock);
|
||||||
|
|
||||||
qemu_iovec_destroy(&hd_qiov);
|
qemu_iovec_destroy(&hd_qiov);
|
||||||
|
|
|
@ -236,6 +236,10 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_LINUX_AIO
|
#ifdef CONFIG_LINUX_AIO
|
||||||
|
/*
|
||||||
|
* Currently Linux do AIO only for files opened with O_DIRECT
|
||||||
|
* specified so check NOCACHE flag too
|
||||||
|
*/
|
||||||
if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
|
if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
|
||||||
(BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
|
(BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,11 @@ static int raw_is_inserted(BlockDriverState *bs)
|
||||||
return bdrv_is_inserted(bs->file);
|
return bdrv_is_inserted(bs->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int raw_media_changed(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
return bdrv_media_changed(bs->file);
|
||||||
|
}
|
||||||
|
|
||||||
static void raw_eject(BlockDriverState *bs, int eject_flag)
|
static void raw_eject(BlockDriverState *bs, int eject_flag)
|
||||||
{
|
{
|
||||||
bdrv_eject(bs->file, eject_flag);
|
bdrv_eject(bs->file, eject_flag);
|
||||||
|
@ -137,8 +142,10 @@ static BlockDriver bdrv_raw = {
|
||||||
.bdrv_discard = raw_discard,
|
.bdrv_discard = raw_discard,
|
||||||
|
|
||||||
.bdrv_is_inserted = raw_is_inserted,
|
.bdrv_is_inserted = raw_is_inserted,
|
||||||
|
.bdrv_media_changed = raw_media_changed,
|
||||||
.bdrv_eject = raw_eject,
|
.bdrv_eject = raw_eject,
|
||||||
.bdrv_set_locked = raw_set_locked,
|
.bdrv_set_locked = raw_set_locked,
|
||||||
|
|
||||||
.bdrv_ioctl = raw_ioctl,
|
.bdrv_ioctl = raw_ioctl,
|
||||||
.bdrv_aio_ioctl = raw_aio_ioctl,
|
.bdrv_aio_ioctl = raw_aio_ioctl,
|
||||||
|
|
||||||
|
|
334
block/vmdk.c
334
block/vmdk.c
|
@ -26,9 +26,14 @@
|
||||||
#include "qemu-common.h"
|
#include "qemu-common.h"
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
#include "zlib.h"
|
||||||
|
|
||||||
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
|
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
|
||||||
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
|
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
|
||||||
|
#define VMDK4_COMPRESSION_DEFLATE 1
|
||||||
|
#define VMDK4_FLAG_RGD (1 << 1)
|
||||||
|
#define VMDK4_FLAG_COMPRESS (1 << 16)
|
||||||
|
#define VMDK4_FLAG_MARKER (1 << 17)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
|
@ -51,11 +56,12 @@ typedef struct {
|
||||||
int64_t desc_offset;
|
int64_t desc_offset;
|
||||||
int64_t desc_size;
|
int64_t desc_size;
|
||||||
int32_t num_gtes_per_gte;
|
int32_t num_gtes_per_gte;
|
||||||
int64_t rgd_offset;
|
|
||||||
int64_t gd_offset;
|
int64_t gd_offset;
|
||||||
|
int64_t rgd_offset;
|
||||||
int64_t grain_offset;
|
int64_t grain_offset;
|
||||||
char filler[1];
|
char filler[1];
|
||||||
char check_bytes[4];
|
char check_bytes[4];
|
||||||
|
uint16_t compressAlgorithm;
|
||||||
} QEMU_PACKED VMDK4Header;
|
} QEMU_PACKED VMDK4Header;
|
||||||
|
|
||||||
#define L2_CACHE_SIZE 16
|
#define L2_CACHE_SIZE 16
|
||||||
|
@ -63,6 +69,8 @@ typedef struct {
|
||||||
typedef struct VmdkExtent {
|
typedef struct VmdkExtent {
|
||||||
BlockDriverState *file;
|
BlockDriverState *file;
|
||||||
bool flat;
|
bool flat;
|
||||||
|
bool compressed;
|
||||||
|
bool has_marker;
|
||||||
int64_t sectors;
|
int64_t sectors;
|
||||||
int64_t end_sector;
|
int64_t end_sector;
|
||||||
int64_t flat_start_offset;
|
int64_t flat_start_offset;
|
||||||
|
@ -98,6 +106,12 @@ typedef struct VmdkMetaData {
|
||||||
int valid;
|
int valid;
|
||||||
} VmdkMetaData;
|
} VmdkMetaData;
|
||||||
|
|
||||||
|
typedef struct VmdkGrainMarker {
|
||||||
|
uint64_t lba;
|
||||||
|
uint32_t size;
|
||||||
|
uint8_t data[0];
|
||||||
|
} VmdkGrainMarker;
|
||||||
|
|
||||||
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||||
{
|
{
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
|
@ -174,6 +188,17 @@ static void vmdk_free_extents(BlockDriverState *bs)
|
||||||
g_free(s->extents);
|
g_free(s->extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vmdk_free_last_extent(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
|
||||||
|
if (s->num_extents == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s->num_extents--;
|
||||||
|
s->extents = g_realloc(s->extents, s->num_extents * sizeof(VmdkExtent));
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
|
static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
|
||||||
{
|
{
|
||||||
char desc[DESC_SIZE];
|
char desc[DESC_SIZE];
|
||||||
|
@ -357,18 +382,18 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vmdk_open_vmdk3(BlockDriverState *bs, int flags)
|
static int vmdk_open_vmdk3(BlockDriverState *bs,
|
||||||
|
BlockDriverState *file,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
VMDK3Header header;
|
VMDK3Header header;
|
||||||
BDRVVmdkState *s = bs->opaque;
|
|
||||||
VmdkExtent *extent;
|
VmdkExtent *extent;
|
||||||
|
|
||||||
s->desc_offset = 0x200;
|
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
|
||||||
ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
return ret;
|
||||||
}
|
}
|
||||||
extent = vmdk_add_extent(bs,
|
extent = vmdk_add_extent(bs,
|
||||||
bs->file, false,
|
bs->file, false,
|
||||||
|
@ -378,58 +403,58 @@ static int vmdk_open_vmdk3(BlockDriverState *bs, int flags)
|
||||||
le32_to_cpu(header.granularity));
|
le32_to_cpu(header.granularity));
|
||||||
ret = vmdk_init_tables(bs, extent);
|
ret = vmdk_init_tables(bs, extent);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* vmdk_init_tables cleans up on fail, so only free allocation of
|
/* free extent allocated by vmdk_add_extent */
|
||||||
* vmdk_add_extent here. */
|
vmdk_free_last_extent(bs);
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
fail:
|
|
||||||
vmdk_free_extents(bs);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vmdk_open_vmdk4(BlockDriverState *bs, int flags)
|
static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
|
||||||
|
int64_t desc_offset);
|
||||||
|
|
||||||
|
static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||||
|
BlockDriverState *file,
|
||||||
|
int flags)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
uint32_t l1_size, l1_entry_sectors;
|
uint32_t l1_size, l1_entry_sectors;
|
||||||
VMDK4Header header;
|
VMDK4Header header;
|
||||||
BDRVVmdkState *s = bs->opaque;
|
|
||||||
VmdkExtent *extent;
|
VmdkExtent *extent;
|
||||||
|
int64_t l1_backup_offset = 0;
|
||||||
|
|
||||||
s->desc_offset = 0x200;
|
ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header));
|
||||||
ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
return ret;
|
||||||
|
}
|
||||||
|
if (header.capacity == 0 && header.desc_offset) {
|
||||||
|
return vmdk_open_desc_file(bs, flags, header.desc_offset << 9);
|
||||||
}
|
}
|
||||||
l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
|
l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
|
||||||
* le64_to_cpu(header.granularity);
|
* le64_to_cpu(header.granularity);
|
||||||
|
if (l1_entry_sectors <= 0) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
|
l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
|
||||||
/ l1_entry_sectors;
|
/ l1_entry_sectors;
|
||||||
extent = vmdk_add_extent(bs, bs->file, false,
|
if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) {
|
||||||
|
l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9;
|
||||||
|
}
|
||||||
|
extent = vmdk_add_extent(bs, file, false,
|
||||||
le64_to_cpu(header.capacity),
|
le64_to_cpu(header.capacity),
|
||||||
le64_to_cpu(header.gd_offset) << 9,
|
le64_to_cpu(header.gd_offset) << 9,
|
||||||
le64_to_cpu(header.rgd_offset) << 9,
|
l1_backup_offset,
|
||||||
l1_size,
|
l1_size,
|
||||||
le32_to_cpu(header.num_gtes_per_gte),
|
le32_to_cpu(header.num_gtes_per_gte),
|
||||||
le64_to_cpu(header.granularity));
|
le64_to_cpu(header.granularity));
|
||||||
if (extent->l1_entry_sectors <= 0) {
|
extent->compressed =
|
||||||
ret = -EINVAL;
|
le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE;
|
||||||
goto fail;
|
extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER;
|
||||||
}
|
|
||||||
/* try to open parent images, if exist */
|
|
||||||
ret = vmdk_parent_open(bs);
|
|
||||||
if (ret) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
s->parent_cid = vmdk_read_cid(bs, 1);
|
|
||||||
ret = vmdk_init_tables(bs, extent);
|
ret = vmdk_init_tables(bs, extent);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
goto fail;
|
/* free extent allocated by vmdk_add_extent */
|
||||||
|
vmdk_free_last_extent(bs);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
fail:
|
|
||||||
vmdk_free_extents(bs);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,6 +485,31 @@ static int vmdk_parse_description(const char *desc, const char *opt_name,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Open an extent file and append to bs array */
|
||||||
|
static int vmdk_open_sparse(BlockDriverState *bs,
|
||||||
|
BlockDriverState *file,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
uint32_t magic;
|
||||||
|
|
||||||
|
if (bdrv_pread(file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
magic = be32_to_cpu(magic);
|
||||||
|
switch (magic) {
|
||||||
|
case VMDK3_MAGIC:
|
||||||
|
return vmdk_open_vmdk3(bs, file, flags);
|
||||||
|
break;
|
||||||
|
case VMDK4_MAGIC:
|
||||||
|
return vmdk_open_vmdk4(bs, file, flags);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
||||||
const char *desc_file_path)
|
const char *desc_file_path)
|
||||||
{
|
{
|
||||||
|
@ -470,6 +520,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
||||||
const char *p = desc;
|
const char *p = desc;
|
||||||
int64_t sectors = 0;
|
int64_t sectors = 0;
|
||||||
int64_t flat_offset;
|
int64_t flat_offset;
|
||||||
|
char extent_path[PATH_MAX];
|
||||||
|
BlockDriverState *extent_file;
|
||||||
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
/* parse extent line:
|
/* parse extent line:
|
||||||
|
@ -504,24 +556,29 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
|
||||||
goto next_line;
|
goto next_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save to extents array */
|
|
||||||
if (!strcmp(type, "FLAT")) {
|
|
||||||
/* FLAT extent */
|
|
||||||
char extent_path[PATH_MAX];
|
|
||||||
BlockDriverState *extent_file;
|
|
||||||
VmdkExtent *extent;
|
|
||||||
|
|
||||||
path_combine(extent_path, sizeof(extent_path),
|
path_combine(extent_path, sizeof(extent_path),
|
||||||
desc_file_path, fname);
|
desc_file_path, fname);
|
||||||
ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
|
ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* save to extents array */
|
||||||
|
if (!strcmp(type, "FLAT")) {
|
||||||
|
/* FLAT extent */
|
||||||
|
VmdkExtent *extent;
|
||||||
|
|
||||||
extent = vmdk_add_extent(bs, extent_file, true, sectors,
|
extent = vmdk_add_extent(bs, extent_file, true, sectors,
|
||||||
0, 0, 0, 0, sectors);
|
0, 0, 0, 0, sectors);
|
||||||
extent->flat_start_offset = flat_offset;
|
extent->flat_start_offset = flat_offset << 9;
|
||||||
|
} else if (!strcmp(type, "SPARSE")) {
|
||||||
|
/* SPARSE extent */
|
||||||
|
ret = vmdk_open_sparse(bs, extent_file, bs->open_flags);
|
||||||
|
if (ret) {
|
||||||
|
bdrv_delete(extent_file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* SPARSE extent, not supported for now */
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"VMDK: Not supported extent type \"%s\""".\n", type);
|
"VMDK: Not supported extent type \"%s\""".\n", type);
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
@ -536,14 +593,15 @@ next_line:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
|
static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
|
||||||
|
int64_t desc_offset)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char buf[2048];
|
char buf[2048];
|
||||||
char ct[128];
|
char ct[128];
|
||||||
BDRVVmdkState *s = bs->opaque;
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, 0, buf, sizeof(buf));
|
ret = bdrv_pread(bs->file, desc_offset, buf, sizeof(buf));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -551,7 +609,9 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
|
||||||
if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
|
if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (strcmp(ct, "monolithicFlat")) {
|
if (strcmp(ct, "monolithicFlat") &&
|
||||||
|
strcmp(ct, "twoGbMaxExtentSparse") &&
|
||||||
|
strcmp(ct, "twoGbMaxExtentFlat")) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"VMDK: Not supported image type \"%s\""".\n", ct);
|
"VMDK: Not supported image type \"%s\""".\n", ct);
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
@ -573,19 +633,21 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
|
||||||
|
|
||||||
static int vmdk_open(BlockDriverState *bs, int flags)
|
static int vmdk_open(BlockDriverState *bs, int flags)
|
||||||
{
|
{
|
||||||
uint32_t magic;
|
int ret;
|
||||||
|
BDRVVmdkState *s = bs->opaque;
|
||||||
|
|
||||||
if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
|
if (vmdk_open_sparse(bs, bs->file, flags) == 0) {
|
||||||
return -EIO;
|
s->desc_offset = 0x200;
|
||||||
|
/* try to open parent images, if exist */
|
||||||
|
ret = vmdk_parent_open(bs);
|
||||||
|
if (ret) {
|
||||||
|
vmdk_free_extents(bs);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
s->parent_cid = vmdk_read_cid(bs, 1);
|
||||||
magic = be32_to_cpu(magic);
|
return 0;
|
||||||
if (magic == VMDK3_MAGIC) {
|
|
||||||
return vmdk_open_vmdk3(bs, flags);
|
|
||||||
} else if (magic == VMDK4_MAGIC) {
|
|
||||||
return vmdk_open_vmdk4(bs, flags);
|
|
||||||
} else {
|
} else {
|
||||||
return vmdk_open_desc_file(bs, flags);
|
return vmdk_open_desc_file(bs, flags, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,6 +734,7 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE;
|
||||||
l1_index = (offset >> 9) / extent->l1_entry_sectors;
|
l1_index = (offset >> 9) / extent->l1_entry_sectors;
|
||||||
if (l1_index >= extent->l1_size) {
|
if (l1_index >= extent->l1_size) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -724,10 +787,12 @@ static int get_cluster_offset(BlockDriverState *bs,
|
||||||
|
|
||||||
/* Avoid the L2 tables update for the images that have snapshots. */
|
/* Avoid the L2 tables update for the images that have snapshots. */
|
||||||
*cluster_offset = bdrv_getlength(extent->file);
|
*cluster_offset = bdrv_getlength(extent->file);
|
||||||
|
if (!extent->compressed) {
|
||||||
bdrv_truncate(
|
bdrv_truncate(
|
||||||
extent->file,
|
extent->file,
|
||||||
*cluster_offset + (extent->cluster_sectors << 9)
|
*cluster_offset + (extent->cluster_sectors << 9)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
*cluster_offset >>= 9;
|
*cluster_offset >>= 9;
|
||||||
tmp = cpu_to_le32(*cluster_offset);
|
tmp = cpu_to_le32(*cluster_offset);
|
||||||
|
@ -798,6 +863,113 @@ static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||||
|
int64_t offset_in_cluster, const uint8_t *buf,
|
||||||
|
int nb_sectors, int64_t sector_num)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
VmdkGrainMarker *data = NULL;
|
||||||
|
uLongf buf_len;
|
||||||
|
const uint8_t *write_buf = buf;
|
||||||
|
int write_len = nb_sectors * 512;
|
||||||
|
|
||||||
|
if (extent->compressed) {
|
||||||
|
if (!extent->has_marker) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
buf_len = (extent->cluster_sectors << 9) * 2;
|
||||||
|
data = g_malloc(buf_len + sizeof(VmdkGrainMarker));
|
||||||
|
if (compress(data->data, &buf_len, buf, nb_sectors << 9) != Z_OK ||
|
||||||
|
buf_len == 0) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
data->lba = sector_num;
|
||||||
|
data->size = buf_len;
|
||||||
|
write_buf = (uint8_t *)data;
|
||||||
|
write_len = buf_len + sizeof(VmdkGrainMarker);
|
||||||
|
}
|
||||||
|
ret = bdrv_pwrite(extent->file,
|
||||||
|
cluster_offset + offset_in_cluster,
|
||||||
|
write_buf,
|
||||||
|
write_len);
|
||||||
|
if (ret != write_len) {
|
||||||
|
ret = ret < 0 ? ret : -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
g_free(data);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||||
|
int64_t offset_in_cluster, uint8_t *buf,
|
||||||
|
int nb_sectors)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int cluster_bytes, buf_bytes;
|
||||||
|
uint8_t *cluster_buf, *compressed_data;
|
||||||
|
uint8_t *uncomp_buf;
|
||||||
|
uint32_t data_len;
|
||||||
|
VmdkGrainMarker *marker;
|
||||||
|
uLongf buf_len;
|
||||||
|
|
||||||
|
|
||||||
|
if (!extent->compressed) {
|
||||||
|
ret = bdrv_pread(extent->file,
|
||||||
|
cluster_offset + offset_in_cluster,
|
||||||
|
buf, nb_sectors * 512);
|
||||||
|
if (ret == nb_sectors * 512) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cluster_bytes = extent->cluster_sectors * 512;
|
||||||
|
/* Read two clusters in case GrainMarker + compressed data > one cluster */
|
||||||
|
buf_bytes = cluster_bytes * 2;
|
||||||
|
cluster_buf = g_malloc(buf_bytes);
|
||||||
|
uncomp_buf = g_malloc(cluster_bytes);
|
||||||
|
ret = bdrv_pread(extent->file,
|
||||||
|
cluster_offset,
|
||||||
|
cluster_buf, buf_bytes);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
compressed_data = cluster_buf;
|
||||||
|
buf_len = cluster_bytes;
|
||||||
|
data_len = cluster_bytes;
|
||||||
|
if (extent->has_marker) {
|
||||||
|
marker = (VmdkGrainMarker *)cluster_buf;
|
||||||
|
compressed_data = marker->data;
|
||||||
|
data_len = le32_to_cpu(marker->size);
|
||||||
|
}
|
||||||
|
if (!data_len || data_len > buf_bytes) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len);
|
||||||
|
if (ret != Z_OK) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (offset_in_cluster < 0 ||
|
||||||
|
offset_in_cluster + nb_sectors * 512 > buf_len) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
memcpy(buf, uncomp_buf + offset_in_cluster, nb_sectors * 512);
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_free(uncomp_buf);
|
||||||
|
g_free(cluster_buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
uint8_t *buf, int nb_sectors)
|
uint8_t *buf, int nb_sectors)
|
||||||
{
|
{
|
||||||
|
@ -834,10 +1006,10 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
|
||||||
memset(buf, 0, 512 * n);
|
memset(buf, 0, 512 * n);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = bdrv_pread(extent->file,
|
ret = vmdk_read_extent(extent,
|
||||||
cluster_offset + index_in_cluster * 512,
|
cluster_offset, index_in_cluster * 512,
|
||||||
buf, n * 512);
|
buf, n);
|
||||||
if (ret < 0) {
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -871,12 +1043,29 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
if (!extent) {
|
if (!extent) {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
ret = get_cluster_offset(
|
||||||
|
bs,
|
||||||
|
extent,
|
||||||
|
&m_data,
|
||||||
|
sector_num << 9, !extent->compressed,
|
||||||
|
&cluster_offset);
|
||||||
|
if (extent->compressed) {
|
||||||
|
if (ret == 0) {
|
||||||
|
/* Refuse write to allocated cluster for streamOptimized */
|
||||||
|
fprintf(stderr,
|
||||||
|
"VMDK: can't write to allocated cluster"
|
||||||
|
" for streamOptimized\n");
|
||||||
|
return -EIO;
|
||||||
|
} else {
|
||||||
|
/* allocate */
|
||||||
ret = get_cluster_offset(
|
ret = get_cluster_offset(
|
||||||
bs,
|
bs,
|
||||||
extent,
|
extent,
|
||||||
&m_data,
|
&m_data,
|
||||||
sector_num << 9, 1,
|
sector_num << 9, 1,
|
||||||
&cluster_offset);
|
&cluster_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -886,11 +1075,10 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
n = nb_sectors;
|
n = nb_sectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pwrite(extent->file,
|
ret = vmdk_write_extent(extent,
|
||||||
cluster_offset + index_in_cluster * 512,
|
cluster_offset, index_in_cluster * 512,
|
||||||
buf,
|
buf, n, sector_num);
|
||||||
n * 512);
|
if (ret) {
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if (m_data.valid) {
|
if (m_data.valid) {
|
||||||
|
@ -914,7 +1102,8 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
|
static int vmdk_create_extent(const char *filename, int64_t filesize,
|
||||||
|
bool flat, bool compress)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
int fd = 0;
|
int fd = 0;
|
||||||
|
@ -938,7 +1127,9 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
|
||||||
magic = cpu_to_be32(VMDK4_MAGIC);
|
magic = cpu_to_be32(VMDK4_MAGIC);
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
header.version = 1;
|
header.version = 1;
|
||||||
header.flags = 3; /* ?? */
|
header.flags =
|
||||||
|
3 | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0);
|
||||||
|
header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0;
|
||||||
header.capacity = filesize / 512;
|
header.capacity = filesize / 512;
|
||||||
header.granularity = 128;
|
header.granularity = 128;
|
||||||
header.num_gtes_per_gte = 512;
|
header.num_gtes_per_gte = 512;
|
||||||
|
@ -968,6 +1159,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
|
||||||
header.rgd_offset = cpu_to_le64(header.rgd_offset);
|
header.rgd_offset = cpu_to_le64(header.rgd_offset);
|
||||||
header.gd_offset = cpu_to_le64(header.gd_offset);
|
header.gd_offset = cpu_to_le64(header.gd_offset);
|
||||||
header.grain_offset = cpu_to_le64(header.grain_offset);
|
header.grain_offset = cpu_to_le64(header.grain_offset);
|
||||||
|
header.compressAlgorithm = cpu_to_le16(header.compressAlgorithm);
|
||||||
|
|
||||||
header.check_bytes[0] = 0xa;
|
header.check_bytes[0] = 0xa;
|
||||||
header.check_bytes[1] = 0x20;
|
header.check_bytes[1] = 0x20;
|
||||||
|
@ -1109,7 +1301,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
|
||||||
const char *fmt = NULL;
|
const char *fmt = NULL;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool flat, split;
|
bool flat, split, compress;
|
||||||
char ext_desc_lines[BUF_SIZE] = "";
|
char ext_desc_lines[BUF_SIZE] = "";
|
||||||
char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
|
char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
|
||||||
const int64_t split_size = 0x80000000; /* VMDK has constant split size */
|
const int64_t split_size = 0x80000000; /* VMDK has constant split size */
|
||||||
|
@ -1158,7 +1350,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
|
||||||
} else if (strcmp(fmt, "monolithicFlat") &&
|
} else if (strcmp(fmt, "monolithicFlat") &&
|
||||||
strcmp(fmt, "monolithicSparse") &&
|
strcmp(fmt, "monolithicSparse") &&
|
||||||
strcmp(fmt, "twoGbMaxExtentSparse") &&
|
strcmp(fmt, "twoGbMaxExtentSparse") &&
|
||||||
strcmp(fmt, "twoGbMaxExtentFlat")) {
|
strcmp(fmt, "twoGbMaxExtentFlat") &&
|
||||||
|
strcmp(fmt, "streamOptimized")) {
|
||||||
fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
|
fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1166,6 +1359,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
|
||||||
strcmp(fmt, "twoGbMaxExtentSparse"));
|
strcmp(fmt, "twoGbMaxExtentSparse"));
|
||||||
flat = !(strcmp(fmt, "monolithicFlat") &&
|
flat = !(strcmp(fmt, "monolithicFlat") &&
|
||||||
strcmp(fmt, "twoGbMaxExtentFlat"));
|
strcmp(fmt, "twoGbMaxExtentFlat"));
|
||||||
|
compress = !strcmp(fmt, "streamOptimized");
|
||||||
if (flat) {
|
if (flat) {
|
||||||
desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
|
desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
|
||||||
} else {
|
} else {
|
||||||
|
@ -1220,7 +1414,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
|
||||||
snprintf(ext_filename, sizeof(ext_filename), "%s%s",
|
snprintf(ext_filename, sizeof(ext_filename), "%s%s",
|
||||||
path, desc_filename);
|
path, desc_filename);
|
||||||
|
|
||||||
if (vmdk_create_extent(ext_filename, size, flat)) {
|
if (vmdk_create_extent(ext_filename, size, flat, compress)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
filesize -= size;
|
filesize -= size;
|
||||||
|
@ -1334,7 +1528,7 @@ static QEMUOptionParameter vmdk_create_options[] = {
|
||||||
.type = OPT_STRING,
|
.type = OPT_STRING,
|
||||||
.help =
|
.help =
|
||||||
"VMDK flat extent format, can be one of "
|
"VMDK flat extent format, can be one of "
|
||||||
"{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat} "
|
"{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
|
||||||
},
|
},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
14
block_int.h
14
block_int.h
|
@ -161,21 +161,20 @@ struct BlockDriverState {
|
||||||
int encrypted; /* if true, the media is encrypted */
|
int encrypted; /* if true, the media is encrypted */
|
||||||
int valid_key; /* if true, a valid encryption key has been set */
|
int valid_key; /* if true, a valid encryption key has been set */
|
||||||
int sg; /* if true, the device is a /dev/sg* */
|
int sg; /* if true, the device is a /dev/sg* */
|
||||||
/* event callback when inserting/removing */
|
|
||||||
void (*change_cb)(void *opaque, int reason);
|
|
||||||
void *change_opaque;
|
|
||||||
|
|
||||||
BlockDriver *drv; /* NULL means no media */
|
BlockDriver *drv; /* NULL means no media */
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
|
||||||
DeviceState *peer;
|
void *dev; /* attached device model, if any */
|
||||||
|
/* TODO change to DeviceState when all users are qdevified */
|
||||||
|
const BlockDevOps *dev_ops;
|
||||||
|
void *dev_opaque;
|
||||||
|
|
||||||
char filename[1024];
|
char filename[1024];
|
||||||
char backing_file[1024]; /* if non zero, the image is a diff of
|
char backing_file[1024]; /* if non zero, the image is a diff of
|
||||||
this file image */
|
this file image */
|
||||||
char backing_format[16]; /* if non-zero and backing_file exists */
|
char backing_format[16]; /* if non-zero and backing_file exists */
|
||||||
int is_temporary;
|
int is_temporary;
|
||||||
int media_changed;
|
|
||||||
|
|
||||||
BlockDriverState *backing_hd;
|
BlockDriverState *backing_hd;
|
||||||
BlockDriverState *file;
|
BlockDriverState *file;
|
||||||
|
@ -211,9 +210,6 @@ struct BlockDriverState {
|
||||||
void *private;
|
void *private;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CHANGE_MEDIA 0x01
|
|
||||||
#define CHANGE_SIZE 0x02
|
|
||||||
|
|
||||||
struct BlockDriverAIOCB {
|
struct BlockDriverAIOCB {
|
||||||
AIOPool *pool;
|
AIOPool *pool;
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
|
@ -228,8 +224,6 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque);
|
BlockDriverCompletionFunc *cb, void *opaque);
|
||||||
void qemu_aio_release(void *p);
|
void qemu_aio_release(void *p);
|
||||||
|
|
||||||
void *qemu_blockalign(BlockDriverState *bs, size_t size);
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int is_windows_drive(const char *filename);
|
int is_windows_drive(const char *filename);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "qemu-option.h"
|
#include "qemu-option.h"
|
||||||
#include "qemu-config.h"
|
#include "qemu-config.h"
|
||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
#include "hw/qdev.h"
|
|
||||||
#include "block_int.h"
|
#include "block_int.h"
|
||||||
|
|
||||||
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
|
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
|
||||||
|
@ -738,12 +737,12 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||||
bdrv_flush(bs);
|
bdrv_flush(bs);
|
||||||
bdrv_close(bs);
|
bdrv_close(bs);
|
||||||
|
|
||||||
/* if we have a device associated with this BlockDriverState (bs->peer)
|
/* if we have a device attached to this BlockDriverState
|
||||||
* then we need to make the drive anonymous until the device
|
* then we need to make the drive anonymous until the device
|
||||||
* can be removed. If this is a drive with no device backing
|
* can be removed. If this is a drive with no device backing
|
||||||
* then we can just get rid of the block driver state right here.
|
* then we can just get rid of the block driver state right here.
|
||||||
*/
|
*/
|
||||||
if (bs->peer) {
|
if (bdrv_get_attached_dev(bs)) {
|
||||||
bdrv_make_anon(bs);
|
bdrv_make_anon(bs);
|
||||||
} else {
|
} else {
|
||||||
drive_uninit(drive_get_by_blockdev(bs));
|
drive_uninit(drive_get_by_blockdev(bs));
|
||||||
|
|
44
hw/fdc.c
44
hw/fdc.c
|
@ -535,30 +535,11 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void fdrive_media_changed_pre_save(void *opaque)
|
|
||||||
{
|
|
||||||
FDrive *drive = opaque;
|
|
||||||
|
|
||||||
drive->media_changed = drive->bs->media_changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fdrive_media_changed_post_load(void *opaque, int version_id)
|
|
||||||
{
|
|
||||||
FDrive *drive = opaque;
|
|
||||||
|
|
||||||
if (drive->bs != NULL) {
|
|
||||||
drive->bs->media_changed = drive->media_changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* User ejected the floppy when drive->bs == NULL */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool fdrive_media_changed_needed(void *opaque)
|
static bool fdrive_media_changed_needed(void *opaque)
|
||||||
{
|
{
|
||||||
FDrive *drive = opaque;
|
FDrive *drive = opaque;
|
||||||
|
|
||||||
return (drive->bs != NULL && drive->bs->media_changed != 1);
|
return (drive->bs != NULL && drive->media_changed != 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_fdrive_media_changed = {
|
static const VMStateDescription vmstate_fdrive_media_changed = {
|
||||||
|
@ -566,8 +547,6 @@ static const VMStateDescription vmstate_fdrive_media_changed = {
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.minimum_version_id_old = 1,
|
.minimum_version_id_old = 1,
|
||||||
.pre_save = fdrive_media_changed_pre_save,
|
|
||||||
.post_load = fdrive_media_changed_post_load,
|
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT8(media_changed, FDrive),
|
VMSTATE_UINT8(media_changed, FDrive),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
|
@ -919,7 +898,15 @@ static int fdctrl_media_changed(FDrive *drv)
|
||||||
|
|
||||||
if (!drv->bs)
|
if (!drv->bs)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (drv->media_changed) {
|
||||||
|
drv->media_changed = 0;
|
||||||
|
ret = 1;
|
||||||
|
} else {
|
||||||
ret = bdrv_media_changed(drv->bs);
|
ret = bdrv_media_changed(drv->bs);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = 0; /* we don't know, assume no */
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
fd_revalidate(drv);
|
fd_revalidate(drv);
|
||||||
}
|
}
|
||||||
|
@ -1791,6 +1778,17 @@ static void fdctrl_result_timer(void *opaque)
|
||||||
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fdctrl_change_cb(void *opaque)
|
||||||
|
{
|
||||||
|
FDrive *drive = opaque;
|
||||||
|
|
||||||
|
drive->media_changed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const BlockDevOps fdctrl_block_ops = {
|
||||||
|
.change_media_cb = fdctrl_change_cb,
|
||||||
|
};
|
||||||
|
|
||||||
/* Init functions */
|
/* Init functions */
|
||||||
static int fdctrl_connect_drives(FDCtrl *fdctrl)
|
static int fdctrl_connect_drives(FDCtrl *fdctrl)
|
||||||
{
|
{
|
||||||
|
@ -1814,7 +1812,9 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
|
||||||
fd_init(drive);
|
fd_init(drive);
|
||||||
fd_revalidate(drive);
|
fd_revalidate(drive);
|
||||||
if (drive->bs) {
|
if (drive->bs) {
|
||||||
|
drive->media_changed = 1;
|
||||||
bdrv_set_removable(drive->bs, 1);
|
bdrv_set_removable(drive->bs, 1);
|
||||||
|
bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -783,15 +783,11 @@ static void ide_cfata_metadata_write(IDEState *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called when the inserted state of the media has changed */
|
/* called when the inserted state of the media has changed */
|
||||||
static void cdrom_change_cb(void *opaque, int reason)
|
static void ide_cd_change_cb(void *opaque)
|
||||||
{
|
{
|
||||||
IDEState *s = opaque;
|
IDEState *s = opaque;
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
|
|
||||||
if (!(reason & CHANGE_MEDIA)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bdrv_get_geometry(s->bs, &nb_sectors);
|
bdrv_get_geometry(s->bs, &nb_sectors);
|
||||||
s->nb_sectors = nb_sectors;
|
s->nb_sectors = nb_sectors;
|
||||||
|
|
||||||
|
@ -1133,7 +1129,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
|
||||||
case WIN_STANDBYNOW1:
|
case WIN_STANDBYNOW1:
|
||||||
case WIN_STANDBYNOW2:
|
case WIN_STANDBYNOW2:
|
||||||
case WIN_IDLEIMMEDIATE:
|
case WIN_IDLEIMMEDIATE:
|
||||||
case CFA_IDLEIMMEDIATE:
|
case WIN_IDLEIMMEDIATE2:
|
||||||
case WIN_SETIDLE1:
|
case WIN_SETIDLE1:
|
||||||
case WIN_SETIDLE2:
|
case WIN_SETIDLE2:
|
||||||
case WIN_SLEEPNOW1:
|
case WIN_SLEEPNOW1:
|
||||||
|
@ -1172,7 +1168,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
|
||||||
*/
|
*/
|
||||||
ide_set_irq(s->bus);
|
ide_set_irq(s->bus);
|
||||||
break;
|
break;
|
||||||
case WIN_SRST:
|
case WIN_DEVICE_RESET:
|
||||||
if (s->drive_kind != IDE_CD)
|
if (s->drive_kind != IDE_CD)
|
||||||
goto abort_cmd;
|
goto abort_cmd;
|
||||||
ide_set_signature(s);
|
ide_set_signature(s);
|
||||||
|
@ -1742,6 +1738,10 @@ void ide_bus_reset(IDEBus *bus)
|
||||||
bus->dma->ops->reset(bus->dma);
|
bus->dma->ops->reset(bus->dma);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const BlockDevOps ide_cd_block_ops = {
|
||||||
|
.change_media_cb = ide_cd_change_cb,
|
||||||
|
};
|
||||||
|
|
||||||
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
|
int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
|
||||||
const char *version, const char *serial)
|
const char *version, const char *serial)
|
||||||
{
|
{
|
||||||
|
@ -1776,7 +1776,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
|
||||||
s->smart_errors = 0;
|
s->smart_errors = 0;
|
||||||
s->smart_selftest_count = 0;
|
s->smart_selftest_count = 0;
|
||||||
if (kind == IDE_CD) {
|
if (kind == IDE_CD) {
|
||||||
bdrv_set_change_cb(bs, cdrom_change_cb, s);
|
bdrv_set_dev_ops(bs, &ide_cd_block_ops, s);
|
||||||
bs->buffer_alignment = 2048;
|
bs->buffer_alignment = 2048;
|
||||||
} else {
|
} else {
|
||||||
if (!bdrv_is_inserted(s->bs)) {
|
if (!bdrv_is_inserted(s->bs)) {
|
||||||
|
@ -1890,6 +1890,7 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0,
|
||||||
error_report("Can't set up IDE drive %s", dinfo->id);
|
error_report("Can't set up IDE drive %s", dinfo->id);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
bdrv_attach_dev_nofail(dinfo->bdrv, &bus->ifs[i]);
|
||||||
} else {
|
} else {
|
||||||
ide_reset(&bus->ifs[i]);
|
ide_reset(&bus->ifs[i]);
|
||||||
}
|
}
|
||||||
|
@ -2009,7 +2010,7 @@ static bool ide_error_needed(void *opaque)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
|
/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
|
||||||
const VMStateDescription vmstate_ide_atapi_gesn_state = {
|
static const VMStateDescription vmstate_ide_atapi_gesn_state = {
|
||||||
.name ="ide_drive/atapi/gesn_state",
|
.name ="ide_drive/atapi/gesn_state",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
|
@ -2021,7 +2022,7 @@ const VMStateDescription vmstate_ide_atapi_gesn_state = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_ide_drive_pio_state = {
|
static const VMStateDescription vmstate_ide_drive_pio_state = {
|
||||||
.name = "ide_drive/pio_state",
|
.name = "ide_drive/pio_state",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
|
@ -2083,7 +2084,7 @@ const VMStateDescription vmstate_ide_drive = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const VMStateDescription vmstate_ide_error_status = {
|
static const VMStateDescription vmstate_ide_error_status = {
|
||||||
.name ="ide_bus/error",
|
.name ="ide_bus/error",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
|
|
|
@ -55,111 +55,120 @@ typedef struct IDEDMAOps IDEDMAOps;
|
||||||
#define IDE_CMD_RESET 0x04
|
#define IDE_CMD_RESET 0x04
|
||||||
#define IDE_CMD_DISABLE_IRQ 0x02
|
#define IDE_CMD_DISABLE_IRQ 0x02
|
||||||
|
|
||||||
/* ATA/ATAPI Commands pre T13 Spec */
|
/* ACS-2 T13/2015-D Table B.2 Command codes */
|
||||||
#define WIN_NOP 0x00
|
#define WIN_NOP 0x00
|
||||||
/*
|
/* reserved 0x01..0x02 */
|
||||||
* 0x01->0x02 Reserved
|
|
||||||
*/
|
|
||||||
#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */
|
#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */
|
||||||
/*
|
/* reserved 0x04..0x05 */
|
||||||
* 0x04->0x05 Reserved
|
|
||||||
*/
|
|
||||||
#define WIN_DSM 0x06
|
#define WIN_DSM 0x06
|
||||||
/*
|
/* reserved 0x07 */
|
||||||
* 0x07 Reserved
|
|
||||||
*/
|
|
||||||
#define WIN_SRST 0x08 /* ATAPI soft reset command */
|
|
||||||
#define WIN_DEVICE_RESET 0x08
|
#define WIN_DEVICE_RESET 0x08
|
||||||
/*
|
/* reserved 0x09..0x0a */
|
||||||
* 0x09->0x0F Reserved
|
/* REQUEST SENSE DATA EXT 0x0B */
|
||||||
*/
|
/* reserved 0x0C..0x0F */
|
||||||
#define WIN_RECAL 0x10
|
#define WIN_RECAL 0x10 /* obsolete since ATA4 */
|
||||||
#define WIN_RESTORE WIN_RECAL
|
/* obsolete since ATA3, retired in ATA4 0x11..0x1F */
|
||||||
/*
|
|
||||||
* 0x10->0x1F Reserved
|
|
||||||
*/
|
|
||||||
#define WIN_READ 0x20 /* 28-Bit */
|
#define WIN_READ 0x20 /* 28-Bit */
|
||||||
#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */
|
#define WIN_READ_ONCE 0x21 /* 28-Bit w/o retries, obsolete since ATA5 */
|
||||||
#define WIN_READ_LONG 0x22 /* 28-Bit */
|
/* obsolete since ATA4 0x22..0x23 */
|
||||||
#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */
|
|
||||||
#define WIN_READ_EXT 0x24 /* 48-Bit */
|
#define WIN_READ_EXT 0x24 /* 48-Bit */
|
||||||
#define WIN_READDMA_EXT 0x25 /* 48-Bit */
|
#define WIN_READDMA_EXT 0x25 /* 48-Bit */
|
||||||
#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */
|
#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit, obsolete since ACS2 */
|
||||||
#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */
|
#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */
|
||||||
/*
|
/* reserved 0x28 */
|
||||||
* 0x28
|
|
||||||
*/
|
|
||||||
#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */
|
#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */
|
||||||
/*
|
/* READ STREAM DMA EXT 0x2A */
|
||||||
* 0x2A->0x2F Reserved
|
/* READ STREAM EXT 0x2B */
|
||||||
*/
|
/* reserved 0x2C..0x2E */
|
||||||
|
/* READ LOG EXT 0x2F */
|
||||||
#define WIN_WRITE 0x30 /* 28-Bit */
|
#define WIN_WRITE 0x30 /* 28-Bit */
|
||||||
#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */
|
#define WIN_WRITE_ONCE 0x31 /* 28-Bit w/o retries, obsolete since ATA5 */
|
||||||
#define WIN_WRITE_LONG 0x32 /* 28-Bit */
|
/* obsolete since ATA4 0x32..0x33 */
|
||||||
#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */
|
|
||||||
#define WIN_WRITE_EXT 0x34 /* 48-Bit */
|
#define WIN_WRITE_EXT 0x34 /* 48-Bit */
|
||||||
#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */
|
#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */
|
||||||
#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */
|
#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */
|
||||||
|
#define WIN_SET_MAX_EXT 0x37 /* 48-Bit, obsolete since ACS2 */
|
||||||
#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */
|
#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */
|
||||||
#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */
|
#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */
|
||||||
#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */
|
#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */
|
||||||
/*
|
/* WRITE STREAM DMA EXT 0x3A */
|
||||||
* 0x3A->0x3B Reserved
|
/* WRITE STREAM EXT 0x3B */
|
||||||
*/
|
#define WIN_WRITE_VERIFY 0x3C /* 28-Bit, obsolete since ATA4 */
|
||||||
#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */
|
/* WRITE DMA FUA EXT 0x3D */
|
||||||
/*
|
/* obsolete since ACS2 0x3E */
|
||||||
* 0x3D->0x3F Reserved
|
/* WRITE LOG EXT 0x3F */
|
||||||
*/
|
|
||||||
#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */
|
#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */
|
||||||
#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */
|
#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - w/o retries, obsolete since ATA5 */
|
||||||
#define WIN_VERIFY_EXT 0x42 /* 48-Bit */
|
#define WIN_VERIFY_EXT 0x42 /* 48-Bit */
|
||||||
/*
|
/* reserved 0x43..0x44 */
|
||||||
* 0x43->0x4F Reserved
|
/* WRITE UNCORRECTABLE EXT 0x45 */
|
||||||
*/
|
/* reserved 0x46 */
|
||||||
#define WIN_FORMAT 0x50
|
/* READ LOG DMA EXT 0x47 */
|
||||||
/*
|
/* reserved 0x48..0x4F */
|
||||||
* 0x51->0x5F Reserved
|
/* obsolete since ATA4 0x50 */
|
||||||
*/
|
/* CONFIGURE STREAM 0x51 */
|
||||||
#define WIN_INIT 0x60
|
/* reserved 0x52..0x56 */
|
||||||
/*
|
/* WRITE LOG DMA EXT 0x57 */
|
||||||
* 0x61->0x5F Reserved
|
/* reserved 0x58..0x5A */
|
||||||
*/
|
/* TRUSTED NON DATA 0x5B */
|
||||||
#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */
|
/* TRUSTED RECEIVE 0x5C */
|
||||||
|
/* TRUSTED RECEIVE DMA 0x5D */
|
||||||
|
/* TRUSTED SEND 0x5E */
|
||||||
|
/* TRUSTED SEND DMA 0x5F */
|
||||||
|
/* READ FPDMA QUEUED 0x60 */
|
||||||
|
/* WRITE FPDMA QUEUED 0x61 */
|
||||||
|
/* reserved 0x62->0x6F */
|
||||||
|
#define WIN_SEEK 0x70 /* obsolete since ATA7 */
|
||||||
|
/* reserved 0x71-0x7F */
|
||||||
|
/* vendor specific 0x80-0x86 */
|
||||||
#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */
|
#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */
|
||||||
|
/* vendor specific 0x88-0x8F */
|
||||||
#define WIN_DIAGNOSE 0x90
|
#define WIN_DIAGNOSE 0x90
|
||||||
#define WIN_SPECIFY 0x91 /* set drive geometry translation */
|
#define WIN_SPECIFY 0x91 /* set drive geometry translation, obsolete since ATA6 */
|
||||||
#define WIN_DOWNLOAD_MICROCODE 0x92
|
#define WIN_DOWNLOAD_MICROCODE 0x92
|
||||||
#define WIN_STANDBYNOW2 0x94
|
/* DOWNLOAD MICROCODE DMA 0x93 */
|
||||||
#define CFA_IDLEIMMEDIATE 0x95 /* force drive to become "ready" */
|
#define WIN_STANDBYNOW2 0x94 /* retired in ATA4 */
|
||||||
#define WIN_STANDBY2 0x96
|
#define WIN_IDLEIMMEDIATE2 0x95 /* force drive to become "ready", retired in ATA4 */
|
||||||
#define WIN_SETIDLE2 0x97
|
#define WIN_STANDBY2 0x96 /* retired in ATA4 */
|
||||||
#define WIN_CHECKPOWERMODE2 0x98
|
#define WIN_SETIDLE2 0x97 /* retired in ATA4 */
|
||||||
#define WIN_SLEEPNOW2 0x99
|
#define WIN_CHECKPOWERMODE2 0x98 /* retired in ATA4 */
|
||||||
/*
|
#define WIN_SLEEPNOW2 0x99 /* retired in ATA4 */
|
||||||
* 0x9A VENDOR
|
/* vendor specific 0x9A */
|
||||||
*/
|
/* reserved 0x9B..0x9F */
|
||||||
#define WIN_PACKETCMD 0xA0 /* Send a packet command. */
|
#define WIN_PACKETCMD 0xA0 /* Send a packet command. */
|
||||||
#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */
|
#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */
|
||||||
#define WIN_QUEUED_SERVICE 0xA2
|
#define WIN_QUEUED_SERVICE 0xA2 /* obsolete since ACS2 */
|
||||||
|
/* reserved 0xA3..0xAF */
|
||||||
#define WIN_SMART 0xB0 /* self-monitoring and reporting */
|
#define WIN_SMART 0xB0 /* self-monitoring and reporting */
|
||||||
|
/* Device Configuration Overlay 0xB1 */
|
||||||
|
/* reserved 0xB2..0xB3 */
|
||||||
|
/* Sanitize Device 0xB4 */
|
||||||
|
/* reserved 0xB5 */
|
||||||
|
/* NV Cache 0xB6 */
|
||||||
|
/* reserved for CFA 0xB7..0xBB */
|
||||||
#define CFA_ACCESS_METADATA_STORAGE 0xB8
|
#define CFA_ACCESS_METADATA_STORAGE 0xB8
|
||||||
|
/* reserved 0xBC..0xBF */
|
||||||
#define CFA_ERASE_SECTORS 0xC0 /* microdrives implement as NOP */
|
#define CFA_ERASE_SECTORS 0xC0 /* microdrives implement as NOP */
|
||||||
|
/* vendor specific 0xC1..0xC3 */
|
||||||
#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/
|
#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/
|
||||||
#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
|
#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
|
||||||
#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
|
#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
|
||||||
#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */
|
#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers, obsolete since ACS2 */
|
||||||
#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */
|
#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */
|
||||||
#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */
|
#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - w/o retries, obsolete since ATA5 */
|
||||||
#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */
|
#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */
|
||||||
#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */
|
#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - w/o retries, obsolete since ATA5 */
|
||||||
#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */
|
#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers, obsolete since ACS2 */
|
||||||
#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */
|
#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */
|
||||||
#define WIN_GETMEDIASTATUS 0xDA
|
/* WRITE MULTIPLE FUA EXT 0xCE */
|
||||||
#define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */
|
/* reserved 0xCF..0xDO */
|
||||||
#define WIN_POSTBOOT 0xDC
|
/* CHECK MEDIA CARD TYPE 0xD1 */
|
||||||
#define WIN_PREBOOT 0xDD
|
/* reserved for media card pass through 0xD2..0xD4 */
|
||||||
#define WIN_DOORLOCK 0xDE /* lock door on removable drives */
|
/* reserved 0xD5..0xD9 */
|
||||||
#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */
|
#define WIN_GETMEDIASTATUS 0xDA /* obsolete since ATA8 */
|
||||||
|
/* obsolete since ATA3, retired in ATA4 0xDB..0xDD */
|
||||||
|
#define WIN_DOORLOCK 0xDE /* lock door on removable drives, obsolete since ATA8 */
|
||||||
|
#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives, obsolete since ATA8 */
|
||||||
#define WIN_STANDBYNOW1 0xE0
|
#define WIN_STANDBYNOW1 0xE0
|
||||||
#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */
|
#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */
|
||||||
#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */
|
#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */
|
||||||
|
@ -169,25 +178,25 @@ typedef struct IDEDMAOps IDEDMAOps;
|
||||||
#define WIN_SLEEPNOW1 0xE6
|
#define WIN_SLEEPNOW1 0xE6
|
||||||
#define WIN_FLUSH_CACHE 0xE7
|
#define WIN_FLUSH_CACHE 0xE7
|
||||||
#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */
|
#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */
|
||||||
#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */
|
/* READ BUFFER DMA 0xE9 */
|
||||||
/* SET_FEATURES 0x22 or 0xDD */
|
|
||||||
#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */
|
#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */
|
||||||
|
/* WRITE BUFFER DMA 0xEB */
|
||||||
#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */
|
#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */
|
||||||
#define WIN_MEDIAEJECT 0xED
|
#define WIN_MEDIAEJECT 0xED /* obsolete since ATA8 */
|
||||||
#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */
|
/* obsolete since ATA4 0xEE */
|
||||||
#define WIN_SETFEATURES 0xEF /* set special drive features */
|
#define WIN_SETFEATURES 0xEF /* set special drive features */
|
||||||
#define EXABYTE_ENABLE_NEST 0xF0
|
#define IBM_SENSE_CONDITION 0xF0 /* measure disk temperature, vendor specific */
|
||||||
#define IBM_SENSE_CONDITION 0xF0 /* measure disk temperature */
|
|
||||||
#define WIN_SECURITY_SET_PASS 0xF1
|
#define WIN_SECURITY_SET_PASS 0xF1
|
||||||
#define WIN_SECURITY_UNLOCK 0xF2
|
#define WIN_SECURITY_UNLOCK 0xF2
|
||||||
#define WIN_SECURITY_ERASE_PREPARE 0xF3
|
#define WIN_SECURITY_ERASE_PREPARE 0xF3
|
||||||
#define WIN_SECURITY_ERASE_UNIT 0xF4
|
#define WIN_SECURITY_ERASE_UNIT 0xF4
|
||||||
#define WIN_SECURITY_FREEZE_LOCK 0xF5
|
#define WIN_SECURITY_FREEZE_LOCK 0xF5
|
||||||
#define CFA_WEAR_LEVEL 0xF5 /* microdrives implement as NOP */
|
#define CFA_WEAR_LEVEL 0xF5 /* microdrives implement as NOP; not specified in T13! */
|
||||||
#define WIN_SECURITY_DISABLE 0xF6
|
#define WIN_SECURITY_DISABLE 0xF6
|
||||||
|
/* vendor specific 0xF7 */
|
||||||
#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */
|
#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */
|
||||||
#define WIN_SET_MAX 0xF9
|
#define WIN_SET_MAX 0xF9
|
||||||
#define DISABLE_SEAGATE 0xFB
|
/* vendor specific 0xFA..0xFF */
|
||||||
|
|
||||||
/* set to 1 set disable mult support */
|
/* set to 1 set disable mult support */
|
||||||
#define MAX_MULT_SECTORS 16
|
#define MAX_MULT_SECTORS 16
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include <hw/pci.h>
|
#include <hw/pci.h>
|
||||||
#include <hw/isa.h>
|
#include <hw/isa.h>
|
||||||
#include "block.h"
|
#include "block.h"
|
||||||
#include "block_int.h"
|
|
||||||
#include "sysemu.h"
|
#include "sysemu.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
|
|
||||||
|
@ -176,10 +175,10 @@ static int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||||
|
|
||||||
for (; i < 3; i++) {
|
for (; i < 3; i++) {
|
||||||
di = drive_get_by_index(IF_IDE, i);
|
di = drive_get_by_index(IF_IDE, i);
|
||||||
if (di != NULL && di->bdrv != NULL && !di->bdrv->removable) {
|
if (di != NULL && !di->media_cd) {
|
||||||
DeviceState *ds = bdrv_get_attached(di->bdrv);
|
DeviceState *ds = bdrv_get_attached_dev(di->bdrv);
|
||||||
if (ds) {
|
if (ds) {
|
||||||
bdrv_detach(di->bdrv, ds);
|
bdrv_detach_dev(di->bdrv, ds);
|
||||||
}
|
}
|
||||||
bdrv_close(di->bdrv);
|
bdrv_close(di->bdrv);
|
||||||
pci_ide->bus[di->bus].ifs[di->unit].bs = NULL;
|
pci_ide->bus[di->bus].ifs[di->unit].bs = NULL;
|
||||||
|
|
|
@ -603,6 +603,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base,
|
||||||
g_free(pfl);
|
g_free(pfl);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
bdrv_attach_dev_nofail(pfl->bs, pfl);
|
||||||
}
|
}
|
||||||
#if 0 /* XXX: there should be a bit to set up read-only,
|
#if 0 /* XXX: there should be a bit to set up read-only,
|
||||||
* the same way the hardware does (with WP pin).
|
* the same way the hardware does (with WP pin).
|
||||||
|
|
|
@ -641,6 +641,7 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base,
|
||||||
g_free(pfl);
|
g_free(pfl);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
bdrv_attach_dev_nofail(pfl->bs, pfl);
|
||||||
}
|
}
|
||||||
pflash_setup_mappings(pfl);
|
pflash_setup_mappings(pfl);
|
||||||
pfl->rom_mode = 1;
|
pfl->rom_mode = 1;
|
||||||
|
|
|
@ -312,7 +312,7 @@ static int parse_drive(DeviceState *dev, Property *prop, const char *str)
|
||||||
bs = bdrv_find(str);
|
bs = bdrv_find(str);
|
||||||
if (bs == NULL)
|
if (bs == NULL)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
if (bdrv_attach(bs, dev) < 0)
|
if (bdrv_attach_dev(bs, dev) < 0)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
*ptr = bs;
|
*ptr = bs;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -323,7 +323,7 @@ static void free_drive(DeviceState *dev, Property *prop)
|
||||||
BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
|
BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
|
||||||
|
|
||||||
if (*ptr) {
|
if (*ptr) {
|
||||||
bdrv_detach(*ptr, dev);
|
bdrv_detach_dev(*ptr, dev);
|
||||||
blockdev_auto_del(*ptr);
|
blockdev_auto_del(*ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -678,7 +678,7 @@ int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *va
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = bdrv_attach(value, dev);
|
res = bdrv_attach_dev(value, dev);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
error_report("Can't attach drive %s to %s.%s: %s",
|
error_report("Can't attach drive %s to %s.%s: %s",
|
||||||
bdrv_get_device_name(value),
|
bdrv_get_device_name(value),
|
||||||
|
|
|
@ -498,6 +498,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
|
||||||
memset(req->sense, 0, 18);
|
memset(req->sense, 0, 18);
|
||||||
req->sense[0] = 0xf0;
|
req->sense[0] = 0xf0;
|
||||||
req->sense[2] = sense.key;
|
req->sense[2] = sense.key;
|
||||||
|
req->sense[7] = 10;
|
||||||
req->sense[12] = sense.asc;
|
req->sense[12] = sense.asc;
|
||||||
req->sense[13] = sense.ascq;
|
req->sense[13] = sense.ascq;
|
||||||
req->sense_len = 18;
|
req->sense_len = 18;
|
||||||
|
@ -883,7 +884,7 @@ int scsi_build_sense(uint8_t *in_buf, int in_len,
|
||||||
/* Return fixed format sense buffer */
|
/* Return fixed format sense buffer */
|
||||||
buf[0] = 0xf0;
|
buf[0] = 0xf0;
|
||||||
buf[2] = sense.key;
|
buf[2] = sense.key;
|
||||||
buf[7] = 7;
|
buf[7] = 10;
|
||||||
buf[12] = sense.asc;
|
buf[12] = sense.asc;
|
||||||
buf[13] = sense.ascq;
|
buf[13] = sense.ascq;
|
||||||
return MIN(len, 18);
|
return MIN(len, 18);
|
||||||
|
@ -977,7 +978,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||||
[ LOCATE_16 ] = "LOCATE_16",
|
[ LOCATE_16 ] = "LOCATE_16",
|
||||||
[ WRITE_SAME_16 ] = "WRITE_SAME_16",
|
[ WRITE_SAME_16 ] = "WRITE_SAME_16",
|
||||||
[ ERASE_16 ] = "ERASE_16",
|
[ ERASE_16 ] = "ERASE_16",
|
||||||
[ SERVICE_ACTION_IN ] = "SERVICE_ACTION_IN",
|
[ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
|
||||||
[ WRITE_LONG_16 ] = "WRITE_LONG_16",
|
[ WRITE_LONG_16 ] = "WRITE_LONG_16",
|
||||||
[ REPORT_LUNS ] = "REPORT_LUNS",
|
[ REPORT_LUNS ] = "REPORT_LUNS",
|
||||||
[ BLANK ] = "BLANK",
|
[ BLANK ] = "BLANK",
|
||||||
|
@ -987,6 +988,7 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||||
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
[ LOAD_UNLOAD ] = "LOAD_UNLOAD",
|
||||||
[ READ_12 ] = "READ_12",
|
[ READ_12 ] = "READ_12",
|
||||||
[ WRITE_12 ] = "WRITE_12",
|
[ WRITE_12 ] = "WRITE_12",
|
||||||
|
[ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12",
|
||||||
[ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
|
[ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
|
||||||
[ VERIFY_12 ] = "VERIFY_12",
|
[ VERIFY_12 ] = "VERIFY_12",
|
||||||
[ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12",
|
[ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12",
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
#define LOCATE_16 0x92
|
#define LOCATE_16 0x92
|
||||||
#define WRITE_SAME_16 0x93
|
#define WRITE_SAME_16 0x93
|
||||||
#define ERASE_16 0x93
|
#define ERASE_16 0x93
|
||||||
#define SERVICE_ACTION_IN 0x9e
|
#define SERVICE_ACTION_IN_16 0x9e
|
||||||
#define WRITE_LONG_16 0x9f
|
#define WRITE_LONG_16 0x9f
|
||||||
#define REPORT_LUNS 0xa0
|
#define REPORT_LUNS 0xa0
|
||||||
#define BLANK 0xa1
|
#define BLANK 0xa1
|
||||||
|
@ -112,6 +112,7 @@
|
||||||
#define LOAD_UNLOAD 0xa6
|
#define LOAD_UNLOAD 0xa6
|
||||||
#define READ_12 0xa8
|
#define READ_12 0xa8
|
||||||
#define WRITE_12 0xaa
|
#define WRITE_12 0xaa
|
||||||
|
#define SERVICE_ACTION_IN_12 0xab
|
||||||
#define WRITE_VERIFY_12 0xae
|
#define WRITE_VERIFY_12 0xae
|
||||||
#define VERIFY_12 0xaf
|
#define VERIFY_12 0xaf
|
||||||
#define SEARCH_HIGH_12 0xb0
|
#define SEARCH_HIGH_12 0xb0
|
||||||
|
@ -122,6 +123,11 @@
|
||||||
#define READ_DEFECT_DATA_12 0xb7
|
#define READ_DEFECT_DATA_12 0xb7
|
||||||
#define SET_CD_SPEED 0xbb
|
#define SET_CD_SPEED 0xbb
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SERVICE ACTION IN subcodes
|
||||||
|
*/
|
||||||
|
#define SAI_READ_CAPACITY_16 0x10
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SAM Status codes
|
* SAM Status codes
|
||||||
*/
|
*/
|
||||||
|
|
147
hw/scsi-disk.c
147
hw/scsi-disk.c
|
@ -111,9 +111,10 @@ static void scsi_read_complete(void * opaque, int ret)
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
if (r->req.aiocb != NULL) {
|
||||||
r->req.aiocb = NULL;
|
r->req.aiocb = NULL;
|
||||||
|
|
||||||
bdrv_acct_done(s->bs, &r->acct);
|
bdrv_acct_done(s->bs, &r->acct);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
|
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
|
||||||
|
@ -129,6 +130,24 @@ static void scsi_read_complete(void * opaque, int ret)
|
||||||
scsi_req_data(&r->req, r->iov.iov_len);
|
scsi_req_data(&r->req, r->iov.iov_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void scsi_flush_complete(void * opaque, int ret)
|
||||||
|
{
|
||||||
|
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
|
||||||
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||||
|
|
||||||
|
if (r->req.aiocb != NULL) {
|
||||||
|
r->req.aiocb = NULL;
|
||||||
|
bdrv_acct_done(s->bs, &r->acct);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scsi_req_complete(&r->req, GOOD);
|
||||||
|
}
|
||||||
|
|
||||||
/* Read more data from scsi device into buffer. */
|
/* Read more data from scsi device into buffer. */
|
||||||
static void scsi_read_data(SCSIRequest *req)
|
static void scsi_read_data(SCSIRequest *req)
|
||||||
|
@ -217,9 +236,10 @@ static void scsi_write_complete(void * opaque, int ret)
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
uint32_t n;
|
uint32_t n;
|
||||||
|
|
||||||
|
if (r->req.aiocb != NULL) {
|
||||||
r->req.aiocb = NULL;
|
r->req.aiocb = NULL;
|
||||||
|
|
||||||
bdrv_acct_done(s->bs, &r->acct);
|
bdrv_acct_done(s->bs, &r->acct);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
|
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
|
||||||
|
@ -526,12 +546,12 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
|
static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
|
||||||
int page_control)
|
int page_control)
|
||||||
{
|
{
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
|
||||||
BlockDriverState *bdrv = s->bs;
|
BlockDriverState *bdrv = s->bs;
|
||||||
int cylinders, heads, secs;
|
int cylinders, heads, secs;
|
||||||
|
uint8_t *p = *p_outbuf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If Changeable Values are requested, a mask denoting those mode parameters
|
* If Changeable Values are requested, a mask denoting those mode parameters
|
||||||
|
@ -541,10 +561,13 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
|
||||||
*/
|
*/
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case 4: /* Rigid disk device geometry page. */
|
case 4: /* Rigid disk device geometry page. */
|
||||||
|
if (s->qdev.type == TYPE_ROM) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
p[0] = 4;
|
p[0] = 4;
|
||||||
p[1] = 0x16;
|
p[1] = 0x16;
|
||||||
if (page_control == 1) { /* Changeable Values */
|
if (page_control == 1) { /* Changeable Values */
|
||||||
return p[1] + 2;
|
break;
|
||||||
}
|
}
|
||||||
/* if a geometry hint is available, use it */
|
/* if a geometry hint is available, use it */
|
||||||
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
|
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
|
||||||
|
@ -570,13 +593,16 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
|
||||||
/* Medium rotation rate [rpm], 5400 rpm */
|
/* Medium rotation rate [rpm], 5400 rpm */
|
||||||
p[20] = (5400 >> 8) & 0xff;
|
p[20] = (5400 >> 8) & 0xff;
|
||||||
p[21] = 5400 & 0xff;
|
p[21] = 5400 & 0xff;
|
||||||
return p[1] + 2;
|
break;
|
||||||
|
|
||||||
case 5: /* Flexible disk device geometry page. */
|
case 5: /* Flexible disk device geometry page. */
|
||||||
|
if (s->qdev.type == TYPE_ROM) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
p[0] = 5;
|
p[0] = 5;
|
||||||
p[1] = 0x1e;
|
p[1] = 0x1e;
|
||||||
if (page_control == 1) { /* Changeable Values */
|
if (page_control == 1) { /* Changeable Values */
|
||||||
return p[1] + 2;
|
break;
|
||||||
}
|
}
|
||||||
/* Transfer rate [kbit/s], 5Mbit/s */
|
/* Transfer rate [kbit/s], 5Mbit/s */
|
||||||
p[2] = 5000 >> 8;
|
p[2] = 5000 >> 8;
|
||||||
|
@ -609,26 +635,27 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
|
||||||
/* Medium rotation rate [rpm], 5400 rpm */
|
/* Medium rotation rate [rpm], 5400 rpm */
|
||||||
p[28] = (5400 >> 8) & 0xff;
|
p[28] = (5400 >> 8) & 0xff;
|
||||||
p[29] = 5400 & 0xff;
|
p[29] = 5400 & 0xff;
|
||||||
return p[1] + 2;
|
break;
|
||||||
|
|
||||||
case 8: /* Caching page. */
|
case 8: /* Caching page. */
|
||||||
p[0] = 8;
|
p[0] = 8;
|
||||||
p[1] = 0x12;
|
p[1] = 0x12;
|
||||||
if (page_control == 1) { /* Changeable Values */
|
if (page_control == 1) { /* Changeable Values */
|
||||||
return p[1] + 2;
|
break;
|
||||||
}
|
}
|
||||||
if (bdrv_enable_write_cache(s->bs)) {
|
if (bdrv_enable_write_cache(s->bs)) {
|
||||||
p[2] = 4; /* WCE */
|
p[2] = 4; /* WCE */
|
||||||
}
|
}
|
||||||
return p[1] + 2;
|
break;
|
||||||
|
|
||||||
case 0x2a: /* CD Capabilities and Mechanical Status page. */
|
case 0x2a: /* CD Capabilities and Mechanical Status page. */
|
||||||
if (s->qdev.type != TYPE_ROM)
|
if (s->qdev.type != TYPE_ROM) {
|
||||||
return 0;
|
return -1;
|
||||||
|
}
|
||||||
p[0] = 0x2a;
|
p[0] = 0x2a;
|
||||||
p[1] = 0x14;
|
p[1] = 0x14;
|
||||||
if (page_control == 1) { /* Changeable Values */
|
if (page_control == 1) { /* Changeable Values */
|
||||||
return p[1] + 2;
|
break;
|
||||||
}
|
}
|
||||||
p[2] = 3; // CD-R & CD-RW read
|
p[2] = 3; // CD-R & CD-RW read
|
||||||
p[3] = 0; // Writing not supported
|
p[3] = 0; // Writing not supported
|
||||||
|
@ -653,27 +680,30 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p,
|
||||||
p[19] = (16 * 176) & 0xff;
|
p[19] = (16 * 176) & 0xff;
|
||||||
p[20] = (16 * 176) >> 8; // 16x write speed current
|
p[20] = (16 * 176) >> 8; // 16x write speed current
|
||||||
p[21] = (16 * 176) & 0xff;
|
p[21] = (16 * 176) & 0xff;
|
||||||
return p[1] + 2;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*p_outbuf += p[1] + 2;
|
||||||
|
return p[1] + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
|
static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
|
||||||
{
|
{
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
int page, dbd, buflen, page_control;
|
int page, dbd, buflen, ret, page_control;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
uint8_t dev_specific_param;
|
uint8_t dev_specific_param;
|
||||||
|
|
||||||
dbd = req->cmd.buf[1] & 0x8;
|
dbd = r->req.cmd.buf[1] & 0x8;
|
||||||
page = req->cmd.buf[2] & 0x3f;
|
page = r->req.cmd.buf[2] & 0x3f;
|
||||||
page_control = (req->cmd.buf[2] & 0xc0) >> 6;
|
page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
|
||||||
DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
|
DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
|
||||||
(req->cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, req->cmd.xfer, page_control);
|
(r->req.cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, r->req.cmd.xfer, page_control);
|
||||||
memset(outbuf, 0, req->cmd.xfer);
|
memset(outbuf, 0, r->req.cmd.xfer);
|
||||||
p = outbuf;
|
p = outbuf;
|
||||||
|
|
||||||
if (bdrv_is_read_only(s->bs)) {
|
if (bdrv_is_read_only(s->bs)) {
|
||||||
|
@ -682,7 +712,7 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
|
||||||
dev_specific_param = 0x00;
|
dev_specific_param = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->cmd.buf[0] == MODE_SENSE) {
|
if (r->req.cmd.buf[0] == MODE_SENSE) {
|
||||||
p[1] = 0; /* Default media type. */
|
p[1] = 0; /* Default media type. */
|
||||||
p[2] = dev_specific_param;
|
p[2] = dev_specific_param;
|
||||||
p[3] = 0; /* Block descriptor length. */
|
p[3] = 0; /* Block descriptor length. */
|
||||||
|
@ -696,7 +726,7 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
|
||||||
|
|
||||||
bdrv_get_geometry(s->bs, &nb_sectors);
|
bdrv_get_geometry(s->bs, &nb_sectors);
|
||||||
if (!dbd && nb_sectors) {
|
if (!dbd && nb_sectors) {
|
||||||
if (req->cmd.buf[0] == MODE_SENSE) {
|
if (r->req.cmd.buf[0] == MODE_SENSE) {
|
||||||
outbuf[3] = 8; /* Block descriptor length */
|
outbuf[3] = 8; /* Block descriptor length */
|
||||||
} else { /* MODE_SENSE_10 */
|
} else { /* MODE_SENSE_10 */
|
||||||
outbuf[7] = 8; /* Block descriptor length */
|
outbuf[7] = 8; /* Block descriptor length */
|
||||||
|
@ -715,23 +745,21 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
|
||||||
p += 8;
|
p += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page_control == 3) { /* Saved Values */
|
if (page_control == 3) {
|
||||||
return -1; /* ILLEGAL_REQUEST */
|
/* Saved Values */
|
||||||
|
scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (page) {
|
if (page == 0x3f) {
|
||||||
case 0x04:
|
for (page = 0; page <= 0x3e; page++) {
|
||||||
case 0x05:
|
mode_sense_page(s, page, &p, page_control);
|
||||||
case 0x08:
|
}
|
||||||
case 0x2a:
|
} else {
|
||||||
p += mode_sense_page(req, page, p, page_control);
|
ret = mode_sense_page(s, page, &p, page_control);
|
||||||
break;
|
if (ret == -1) {
|
||||||
case 0x3f:
|
return -1;
|
||||||
p += mode_sense_page(req, 0x08, p, page_control);
|
}
|
||||||
p += mode_sense_page(req, 0x2a, p, page_control);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1; /* ILLEGAL_REQUEST */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buflen = p - outbuf;
|
buflen = p - outbuf;
|
||||||
|
@ -740,14 +768,14 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
|
||||||
* following data that is available to be transferred. The mode data
|
* following data that is available to be transferred. The mode data
|
||||||
* length does not include itself.
|
* length does not include itself.
|
||||||
*/
|
*/
|
||||||
if (req->cmd.buf[0] == MODE_SENSE) {
|
if (r->req.cmd.buf[0] == MODE_SENSE) {
|
||||||
outbuf[0] = buflen - 1;
|
outbuf[0] = buflen - 1;
|
||||||
} else { /* MODE_SENSE_10 */
|
} else { /* MODE_SENSE_10 */
|
||||||
outbuf[0] = ((buflen - 2) >> 8) & 0xff;
|
outbuf[0] = ((buflen - 2) >> 8) & 0xff;
|
||||||
outbuf[1] = (buflen - 2) & 0xff;
|
outbuf[1] = (buflen - 2) & 0xff;
|
||||||
}
|
}
|
||||||
if (buflen > req->cmd.xfer)
|
if (buflen > r->req.cmd.xfer)
|
||||||
buflen = req->cmd.xfer;
|
buflen = r->req.cmd.xfer;
|
||||||
return buflen;
|
return buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -792,7 +820,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
|
||||||
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
|
||||||
uint64_t nb_sectors;
|
uint64_t nb_sectors;
|
||||||
int buflen = 0;
|
int buflen = 0;
|
||||||
int ret;
|
|
||||||
|
|
||||||
switch (req->cmd.buf[0]) {
|
switch (req->cmd.buf[0]) {
|
||||||
case TEST_UNIT_READY:
|
case TEST_UNIT_READY:
|
||||||
|
@ -806,7 +833,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
|
||||||
break;
|
break;
|
||||||
case MODE_SENSE:
|
case MODE_SENSE:
|
||||||
case MODE_SENSE_10:
|
case MODE_SENSE_10:
|
||||||
buflen = scsi_disk_emulate_mode_sense(req, outbuf);
|
buflen = scsi_disk_emulate_mode_sense(r, outbuf);
|
||||||
if (buflen < 0)
|
if (buflen < 0)
|
||||||
goto illegal_request;
|
goto illegal_request;
|
||||||
break;
|
break;
|
||||||
|
@ -864,20 +891,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
|
||||||
outbuf[7] = 0;
|
outbuf[7] = 0;
|
||||||
buflen = 8;
|
buflen = 8;
|
||||||
break;
|
break;
|
||||||
case SYNCHRONIZE_CACHE:
|
|
||||||
{
|
|
||||||
BlockAcctCookie acct;
|
|
||||||
|
|
||||||
bdrv_acct_start(s->bs, &acct, 0, BDRV_ACCT_FLUSH);
|
|
||||||
ret = bdrv_flush(s->bs);
|
|
||||||
bdrv_acct_done(s->bs, &acct);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GET_CONFIGURATION:
|
case GET_CONFIGURATION:
|
||||||
memset(outbuf, 0, 8);
|
memset(outbuf, 0, 8);
|
||||||
/* ??? This should probably return much more information. For now
|
/* ??? This should probably return much more information. For now
|
||||||
|
@ -885,9 +898,9 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf)
|
||||||
outbuf[7] = 8; // CD-ROM
|
outbuf[7] = 8; // CD-ROM
|
||||||
buflen = 8;
|
buflen = 8;
|
||||||
break;
|
break;
|
||||||
case SERVICE_ACTION_IN:
|
case SERVICE_ACTION_IN_16:
|
||||||
/* Service Action In subcommands. */
|
/* Service Action In subcommands. */
|
||||||
if ((req->cmd.buf[1] & 31) == 0x10) {
|
if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
|
||||||
DPRINTF("SAI READ CAPACITY(16)\n");
|
DPRINTF("SAI READ CAPACITY(16)\n");
|
||||||
memset(outbuf, 0, req->cmd.xfer);
|
memset(outbuf, 0, req->cmd.xfer);
|
||||||
bdrv_get_geometry(s->bs, &nb_sectors);
|
bdrv_get_geometry(s->bs, &nb_sectors);
|
||||||
|
@ -941,7 +954,9 @@ not_ready:
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
illegal_request:
|
illegal_request:
|
||||||
|
if (r->req.status == -1) {
|
||||||
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,10 +1000,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
||||||
case START_STOP:
|
case START_STOP:
|
||||||
case ALLOW_MEDIUM_REMOVAL:
|
case ALLOW_MEDIUM_REMOVAL:
|
||||||
case READ_CAPACITY_10:
|
case READ_CAPACITY_10:
|
||||||
case SYNCHRONIZE_CACHE:
|
|
||||||
case READ_TOC:
|
case READ_TOC:
|
||||||
case GET_CONFIGURATION:
|
case GET_CONFIGURATION:
|
||||||
case SERVICE_ACTION_IN:
|
case SERVICE_ACTION_IN_16:
|
||||||
case VERIFY_10:
|
case VERIFY_10:
|
||||||
rc = scsi_disk_emulate_command(r, outbuf);
|
rc = scsi_disk_emulate_command(r, outbuf);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
@ -997,6 +1011,13 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
|
||||||
|
|
||||||
r->iov.iov_len = rc;
|
r->iov.iov_len = rc;
|
||||||
break;
|
break;
|
||||||
|
case SYNCHRONIZE_CACHE:
|
||||||
|
bdrv_acct_start(s->bs, &r->acct, 0, BDRV_ACCT_FLUSH);
|
||||||
|
r->req.aiocb = bdrv_aio_flush(s->bs, scsi_flush_complete, r);
|
||||||
|
if (r->req.aiocb == NULL) {
|
||||||
|
scsi_flush_complete(r, -EIO);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
case READ_6:
|
case READ_6:
|
||||||
case READ_10:
|
case READ_10:
|
||||||
case READ_12:
|
case READ_12:
|
||||||
|
|
14
hw/sd.c
14
hw/sd.c
|
@ -31,7 +31,6 @@
|
||||||
|
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
#include "block.h"
|
#include "block.h"
|
||||||
#include "block_int.h"
|
|
||||||
#include "sd.h"
|
#include "sd.h"
|
||||||
|
|
||||||
//#define DEBUG_SD 1
|
//#define DEBUG_SD 1
|
||||||
|
@ -420,14 +419,10 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv)
|
||||||
sd->pwd_len = 0;
|
sd->pwd_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sd_cardchange(void *opaque, int reason)
|
static void sd_cardchange(void *opaque)
|
||||||
{
|
{
|
||||||
SDState *sd = opaque;
|
SDState *sd = opaque;
|
||||||
|
|
||||||
if (!(reason & CHANGE_MEDIA)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
|
qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
|
||||||
if (bdrv_is_inserted(sd->bdrv)) {
|
if (bdrv_is_inserted(sd->bdrv)) {
|
||||||
sd_reset(sd, sd->bdrv);
|
sd_reset(sd, sd->bdrv);
|
||||||
|
@ -435,6 +430,10 @@ static void sd_cardchange(void *opaque, int reason)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const BlockDevOps sd_block_ops = {
|
||||||
|
.change_media_cb = sd_cardchange,
|
||||||
|
};
|
||||||
|
|
||||||
/* We do not model the chip select pin, so allow the board to select
|
/* We do not model the chip select pin, so allow the board to select
|
||||||
whether card should be in SSI or MMC/SD mode. It is also up to the
|
whether card should be in SSI or MMC/SD mode. It is also up to the
|
||||||
board to ensure that ssi transfers only occur when the chip select
|
board to ensure that ssi transfers only occur when the chip select
|
||||||
|
@ -449,7 +448,8 @@ SDState *sd_init(BlockDriverState *bs, int is_spi)
|
||||||
sd->enable = 1;
|
sd->enable = 1;
|
||||||
sd_reset(sd, bs);
|
sd_reset(sd, bs);
|
||||||
if (sd->bdrv) {
|
if (sd->bdrv) {
|
||||||
bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
|
bdrv_attach_dev_nofail(sd->bdrv, sd);
|
||||||
|
bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
|
||||||
}
|
}
|
||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
|
@ -708,17 +708,13 @@ static void spitz_ssp_attach(PXA2xxState *cpu)
|
||||||
static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
|
static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
|
||||||
{
|
{
|
||||||
PCMCIACardState *md;
|
PCMCIACardState *md;
|
||||||
BlockDriverState *bs;
|
|
||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
|
|
||||||
dinfo = drive_get(IF_IDE, 0, 0);
|
dinfo = drive_get(IF_IDE, 0, 0);
|
||||||
if (!dinfo)
|
if (!dinfo || dinfo->media_cd)
|
||||||
return;
|
return;
|
||||||
bs = dinfo->bdrv;
|
|
||||||
if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
|
|
||||||
md = dscm1xxxx_init(dinfo);
|
md = dscm1xxxx_init(dinfo);
|
||||||
pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
|
pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wm8750 and Max7310 on I2C */
|
/* Wm8750 and Max7310 on I2C */
|
||||||
|
|
|
@ -51,17 +51,13 @@
|
||||||
static void tosa_microdrive_attach(PXA2xxState *cpu)
|
static void tosa_microdrive_attach(PXA2xxState *cpu)
|
||||||
{
|
{
|
||||||
PCMCIACardState *md;
|
PCMCIACardState *md;
|
||||||
BlockDriverState *bs;
|
|
||||||
DriveInfo *dinfo;
|
DriveInfo *dinfo;
|
||||||
|
|
||||||
dinfo = drive_get(IF_IDE, 0, 0);
|
dinfo = drive_get(IF_IDE, 0, 0);
|
||||||
if (!dinfo)
|
if (!dinfo || dinfo->media_cd)
|
||||||
return;
|
return;
|
||||||
bs = dinfo->bdrv;
|
|
||||||
if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
|
|
||||||
md = dscm1xxxx_init(dinfo);
|
md = dscm1xxxx_init(dinfo);
|
||||||
pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
|
pxa2xx_pcmcia_attach(cpu->pcmcia[0], md);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tosa_out_switch(void *opaque, int line, int level)
|
static void tosa_out_switch(void *opaque, int line, int level)
|
||||||
|
|
|
@ -518,7 +518,7 @@ static int usb_msd_initfn(USBDevice *dev)
|
||||||
*
|
*
|
||||||
* The hack is probably a bad idea.
|
* The hack is probably a bad idea.
|
||||||
*/
|
*/
|
||||||
bdrv_detach(bs, &s->dev.qdev);
|
bdrv_detach_dev(bs, &s->dev.qdev);
|
||||||
s->conf.bs = NULL;
|
s->conf.bs = NULL;
|
||||||
|
|
||||||
if (!s->serial) {
|
if (!s->serial) {
|
||||||
|
|
|
@ -543,15 +543,17 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_blk_change_cb(void *opaque, int reason)
|
static void virtio_blk_resize(void *opaque)
|
||||||
{
|
{
|
||||||
VirtIOBlock *s = opaque;
|
VirtIOBlock *s = opaque;
|
||||||
|
|
||||||
if (reason & CHANGE_SIZE) {
|
|
||||||
virtio_notify_config(&s->vdev);
|
virtio_notify_config(&s->vdev);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const BlockDevOps virtio_block_ops = {
|
||||||
|
.resize_cb = virtio_blk_resize,
|
||||||
|
};
|
||||||
|
|
||||||
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||||
char **serial)
|
char **serial)
|
||||||
{
|
{
|
||||||
|
@ -598,7 +600,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||||
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
|
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
|
||||||
virtio_blk_save, virtio_blk_load, s);
|
virtio_blk_save, virtio_blk_load, s);
|
||||||
bdrv_set_removable(s->bs, 0);
|
bdrv_set_removable(s->bs, 0);
|
||||||
bdrv_set_change_cb(s->bs, virtio_blk_change_cb, s);
|
bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
|
||||||
s->bs->buffer_alignment = conf->logical_block_size;
|
s->bs->buffer_alignment = conf->logical_block_size;
|
||||||
|
|
||||||
add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
|
add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
|
||||||
|
|
|
@ -697,6 +697,7 @@ static int blk_init(struct XenDevice *xendev)
|
||||||
xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
|
xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
|
||||||
blkdev->bs = blkdev->dinfo->bdrv;
|
blkdev->bs = blkdev->dinfo->bdrv;
|
||||||
}
|
}
|
||||||
|
bdrv_attach_dev_nofail(blkdev->bs, blkdev);
|
||||||
blkdev->file_blk = BLOCK_SIZE;
|
blkdev->file_blk = BLOCK_SIZE;
|
||||||
blkdev->file_size = bdrv_getlength(blkdev->bs);
|
blkdev->file_size = bdrv_getlength(blkdev->bs);
|
||||||
if (blkdev->file_size < 0) {
|
if (blkdev->file_size < 0) {
|
||||||
|
|
|
@ -181,6 +181,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||||
case QEMU_AIO_READ:
|
case QEMU_AIO_READ:
|
||||||
io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset);
|
io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset);
|
||||||
break;
|
break;
|
||||||
|
/* Currently Linux kernel does not support other operations */
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s: invalid AIO request type 0x%x.\n",
|
fprintf(stderr, "%s: invalid AIO request type 0x%x.\n",
|
||||||
__func__, type);
|
__func__, type);
|
||||||
|
|
4
savevm.c
4
savevm.c
|
@ -1914,7 +1914,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
|
||||||
bs = NULL;
|
bs = NULL;
|
||||||
while ((bs = bdrv_next(bs))) {
|
while ((bs = bdrv_next(bs))) {
|
||||||
|
|
||||||
if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
|
if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2034,7 +2034,7 @@ int load_vmstate(const char *name)
|
||||||
bs = NULL;
|
bs = NULL;
|
||||||
while ((bs = bdrv_next(bs))) {
|
while ((bs = bdrv_next(bs))) {
|
||||||
|
|
||||||
if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) {
|
if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue