Merge remote-tracking branch 'kwolf/for-anthony' into staging

Conflicts:
	block/vmdk.c
This commit is contained in:
Anthony Liguori 2011-10-31 11:09:00 -05:00
commit 8494a397b6
33 changed files with 1980 additions and 651 deletions

View File

@ -36,6 +36,7 @@ block-nested-y += qed-check.o
block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
block-nested-$(CONFIG_WIN32) += raw-win32.o
block-nested-$(CONFIG_POSIX) += raw-posix.o
block-nested-$(CONFIG_LIBISCSI) += iscsi.o
block-nested-$(CONFIG_CURL) += curl.o
block-nested-$(CONFIG_RBD) += rbd.o

18
block.c
View File

@ -473,10 +473,13 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
bs->total_sectors = 0;
bs->encrypted = 0;
bs->valid_key = 0;
bs->sg = 0;
bs->open_flags = flags;
bs->growable = 0;
bs->buffer_alignment = 512;
pstrcpy(bs->filename, sizeof(bs->filename), filename);
bs->backing_file[0] = '\0';
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
return -ENOTSUP;
@ -485,8 +488,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
bs->drv = drv;
bs->opaque = g_malloc0(drv->instance_size);
if (flags & BDRV_O_CACHE_WB)
bs->enable_write_cache = 1;
bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB);
/*
* Clear flags that are internal to the block layer before opening the
@ -501,6 +503,8 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
open_flags |= BDRV_O_RDWR;
}
bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
/* Open the image, either directly or using a protocol */
if (drv->bdrv_file_open) {
ret = drv->bdrv_file_open(bs, filename, open_flags);
@ -515,8 +519,6 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
goto free_and_fail;
}
bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR);
ret = refresh_total_sectors(bs, bs->total_sectors);
if (ret < 0) {
goto free_and_fail;
@ -572,6 +574,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv)
{
int ret;
char tmp_filename[PATH_MAX];
if (flags & BDRV_O_SNAPSHOT) {
BlockDriverState *bs1;
@ -579,7 +582,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
int is_protocol = 0;
BlockDriver *bdrv_qcow2;
QEMUOptionParameter *options;
char tmp_filename[PATH_MAX];
char backing_filename[PATH_MAX];
/* if snapshot, we create a temporary backing file and open it
@ -1939,11 +1941,7 @@ const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
void bdrv_get_backing_filename(BlockDriverState *bs,
char *filename, int filename_size)
{
if (!bs->backing_file) {
pstrcpy(filename, filename_size, "");
} else {
pstrcpy(filename, filename_size, bs->backing_file);
}
pstrcpy(filename, filename_size, bs->backing_file);
}
int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,

591
block/iscsi.c Normal file
View File

@ -0,0 +1,591 @@
/*
* QEMU Block driver for iSCSI images
*
* Copyright (c) 2010-2011 Ronnie Sahlberg <ronniesahlberg@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "config-host.h"
#include <poll.h>
#include "qemu-common.h"
#include "qemu-error.h"
#include "block_int.h"
#include "trace.h"
#include <iscsi/iscsi.h>
#include <iscsi/scsi-lowlevel.h>
typedef struct IscsiLun {
struct iscsi_context *iscsi;
int lun;
int block_size;
unsigned long num_blocks;
} IscsiLun;
typedef struct IscsiAIOCB {
BlockDriverAIOCB common;
QEMUIOVector *qiov;
QEMUBH *bh;
IscsiLun *iscsilun;
struct scsi_task *task;
uint8_t *buf;
int status;
int canceled;
size_t read_size;
size_t read_offset;
} IscsiAIOCB;
struct IscsiTask {
IscsiLun *iscsilun;
BlockDriverState *bs;
int status;
int complete;
};
static void
iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
void *private_data)
{
}
static void
iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
{
IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
IscsiLun *iscsilun = acb->iscsilun;
acb->common.cb(acb->common.opaque, -ECANCELED);
acb->canceled = 1;
/* send a task mgmt call to the target to cancel the task on the target */
iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
iscsi_abort_task_cb, NULL);
/* then also cancel the task locally in libiscsi */
iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task);
}
static AIOPool iscsi_aio_pool = {
.aiocb_size = sizeof(IscsiAIOCB),
.cancel = iscsi_aio_cancel,
};
static void iscsi_process_read(void *arg);
static void iscsi_process_write(void *arg);
static int iscsi_process_flush(void *arg)
{
IscsiLun *iscsilun = arg;
return iscsi_queue_length(iscsilun->iscsi) > 0;
}
static void
iscsi_set_events(IscsiLun *iscsilun)
{
struct iscsi_context *iscsi = iscsilun->iscsi;
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
(iscsi_which_events(iscsi) & POLLOUT)
? iscsi_process_write : NULL,
iscsi_process_flush, NULL, iscsilun);
}
static void
iscsi_process_read(void *arg)
{
IscsiLun *iscsilun = arg;
struct iscsi_context *iscsi = iscsilun->iscsi;
iscsi_service(iscsi, POLLIN);
iscsi_set_events(iscsilun);
}
static void
iscsi_process_write(void *arg)
{
IscsiLun *iscsilun = arg;
struct iscsi_context *iscsi = iscsilun->iscsi;
iscsi_service(iscsi, POLLOUT);
iscsi_set_events(iscsilun);
}
static int
iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb)
{
acb->bh = qemu_bh_new(cb, acb);
if (!acb->bh) {
error_report("oom: could not create iscsi bh");
return -EIO;
}
qemu_bh_schedule(acb->bh);
return 0;
}
static void
iscsi_readv_writev_bh_cb(void *p)
{
IscsiAIOCB *acb = p;
qemu_bh_delete(acb->bh);
if (acb->canceled == 0) {
acb->common.cb(acb->common.opaque, acb->status);
}
qemu_aio_release(acb);
}
static void
iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
{
IscsiAIOCB *acb = opaque;
trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled);
g_free(acb->buf);
if (acb->canceled != 0) {
qemu_aio_release(acb);
scsi_free_scsi_task(acb->task);
acb->task = NULL;
return;
}
acb->status = 0;
if (status < 0) {
error_report("Failed to write10 data to iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
}
iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
scsi_free_scsi_task(acb->task);
acb->task = NULL;
}
static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
{
return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
}
static BlockDriverAIOCB *
iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
size_t size;
int fua = 0;
/* set FUA on writes when cache mode is write through */
if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
fua = 1;
}
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->canceled = 0;
/* XXX we should pass the iovec to write10 to avoid the extra copy */
/* this will allow us to get rid of 'buf' completely */
size = nb_sectors * BDRV_SECTOR_SIZE;
acb->buf = g_malloc(size);
qemu_iovec_to_buffer(acb->qiov, acb->buf);
acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size,
sector_qemu2lun(sector_num, iscsilun),
fua, 0, iscsilun->block_size,
iscsi_aio_write10_cb, acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send write10 command. %s",
iscsi_get_error(iscsi));
g_free(acb->buf);
qemu_aio_release(acb);
return NULL;
}
iscsi_set_events(iscsilun);
return &acb->common;
}
static void
iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
{
IscsiAIOCB *acb = opaque;
trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled);
if (acb->canceled != 0) {
qemu_aio_release(acb);
scsi_free_scsi_task(acb->task);
acb->task = NULL;
return;
}
acb->status = 0;
if (status != 0) {
error_report("Failed to read10 data from iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
}
iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
scsi_free_scsi_task(acb->task);
acb->task = NULL;
}
static BlockDriverAIOCB *
iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
size_t qemu_read_size, lun_read_size;
int i;
qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
trace_iscsi_aio_readv(iscsi, sector_num, nb_sectors, opaque, acb);
acb->iscsilun = iscsilun;
acb->qiov = qiov;
acb->canceled = 0;
acb->read_size = qemu_read_size;
acb->buf = NULL;
/* If LUN blocksize is bigger than BDRV_BLOCK_SIZE a read from QEMU
* may be misaligned to the LUN, so we may need to read some extra
* data.
*/
acb->read_offset = 0;
if (iscsilun->block_size > BDRV_SECTOR_SIZE) {
uint64_t bdrv_offset = BDRV_SECTOR_SIZE * sector_num;
acb->read_offset = bdrv_offset % iscsilun->block_size;
}
lun_read_size = (qemu_read_size + iscsilun->block_size
+ acb->read_offset - 1)
/ iscsilun->block_size * iscsilun->block_size;
acb->task = iscsi_read10_task(iscsi, iscsilun->lun,
sector_qemu2lun(sector_num, iscsilun),
lun_read_size, iscsilun->block_size,
iscsi_aio_read10_cb, acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send read10 command. %s",
iscsi_get_error(iscsi));
qemu_aio_release(acb);
return NULL;
}
for (i = 0; i < acb->qiov->niov; i++) {
scsi_task_add_data_in_buffer(acb->task,
acb->qiov->iov[i].iov_len,
acb->qiov->iov[i].iov_base);
}
iscsi_set_events(iscsilun);
return &acb->common;
}
static void
iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
{
IscsiAIOCB *acb = opaque;
if (acb->canceled != 0) {
qemu_aio_release(acb);
scsi_free_scsi_task(acb->task);
acb->task = NULL;
return;
}
acb->status = 0;
if (status < 0) {
error_report("Failed to sync10 data on iSCSI lun. %s",
iscsi_get_error(iscsi));
acb->status = -EIO;
}
iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
scsi_free_scsi_task(acb->task);
acb->task = NULL;
}
static BlockDriverAIOCB *
iscsi_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
IscsiAIOCB *acb;
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
acb->iscsilun = iscsilun;
acb->canceled = 0;
acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
0, 0, 0, 0,
iscsi_synccache10_cb,
acb);
if (acb->task == NULL) {
error_report("iSCSI: Failed to send synchronizecache10 command. %s",
iscsi_get_error(iscsi));
qemu_aio_release(acb);
return NULL;
}
iscsi_set_events(iscsilun);
return &acb->common;
}
static int64_t
iscsi_getlength(BlockDriverState *bs)
{
IscsiLun *iscsilun = bs->opaque;
int64_t len;
len = iscsilun->num_blocks;
len *= iscsilun->block_size;
return len;
}
static void
iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *opaque)
{
struct IscsiTask *itask = opaque;
struct scsi_readcapacity10 *rc10;
struct scsi_task *task = command_data;
if (status != 0) {
error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
iscsi_get_error(iscsi));
itask->status = 1;
itask->complete = 1;
scsi_free_scsi_task(task);
return;
}
rc10 = scsi_datain_unmarshall(task);
if (rc10 == NULL) {
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
itask->status = 1;
itask->complete = 1;
scsi_free_scsi_task(task);
return;
}
itask->iscsilun->block_size = rc10->block_size;
itask->iscsilun->num_blocks = rc10->lba;
itask->bs->total_sectors = (uint64_t)rc10->lba *
rc10->block_size / BDRV_SECTOR_SIZE ;
itask->status = 0;
itask->complete = 1;
scsi_free_scsi_task(task);
}
static void
iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
void *opaque)
{
struct IscsiTask *itask = opaque;
struct scsi_task *task;
if (status != 0) {
itask->status = 1;
itask->complete = 1;
return;
}
task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun, 0, 0,
iscsi_readcapacity10_cb, opaque);
if (task == NULL) {
error_report("iSCSI: failed to send readcapacity command.");
itask->status = 1;
itask->complete = 1;
return;
}
}
/*
* We support iscsi url's on the form
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
*/
static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = NULL;
struct iscsi_url *iscsi_url = NULL;
struct IscsiTask task;
int ret;
if ((BDRV_SECTOR_SIZE % 512) != 0) {
error_report("iSCSI: Invalid BDRV_SECTOR_SIZE. "
"BDRV_SECTOR_SIZE(%lld) is not a multiple "
"of 512", BDRV_SECTOR_SIZE);
return -EINVAL;
}
memset(iscsilun, 0, sizeof(IscsiLun));
/* Should really append the KVM name after the ':' here */
iscsi = iscsi_create_context("iqn.2008-11.org.linux-kvm:");
if (iscsi == NULL) {
error_report("iSCSI: Failed to create iSCSI context.");
ret = -ENOMEM;
goto failed;
}
iscsi_url = iscsi_parse_full_url(iscsi, filename);
if (iscsi_url == NULL) {
error_report("Failed to parse URL : %s %s", filename,
iscsi_get_error(iscsi));
ret = -EINVAL;
goto failed;
}
if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
error_report("iSCSI: Failed to set target name.");
ret = -EINVAL;
goto failed;
}
if (iscsi_url->user != NULL) {
ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
iscsi_url->passwd);
if (ret != 0) {
error_report("Failed to set initiator username and password");
ret = -EINVAL;
goto failed;
}
}
if (iscsi_set_session_type(iscsi, ISCSI_SESSION_NORMAL) != 0) {
error_report("iSCSI: Failed to set session type to normal.");
ret = -EINVAL;
goto failed;
}
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
task.iscsilun = iscsilun;
task.status = 0;
task.complete = 0;
task.bs = bs;
iscsilun->iscsi = iscsi;
iscsilun->lun = iscsi_url->lun;
if (iscsi_full_connect_async(iscsi, iscsi_url->portal, iscsi_url->lun,
iscsi_connect_cb, &task)
!= 0) {
error_report("iSCSI: Failed to start async connect.");
ret = -EINVAL;
goto failed;
}
while (!task.complete) {
iscsi_set_events(iscsilun);
qemu_aio_wait();
}
if (task.status != 0) {
error_report("iSCSI: Failed to connect to LUN : %s",
iscsi_get_error(iscsi));
ret = -EINVAL;
goto failed;
}
if (iscsi_url != NULL) {
iscsi_destroy_url(iscsi_url);
}
return 0;
failed:
if (iscsi_url != NULL) {
iscsi_destroy_url(iscsi_url);
}
if (iscsi != NULL) {
iscsi_destroy_context(iscsi);
}
memset(iscsilun, 0, sizeof(IscsiLun));
return ret;
}
static void iscsi_close(BlockDriverState *bs)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL, NULL);
iscsi_destroy_context(iscsi);
memset(iscsilun, 0, sizeof(IscsiLun));
}
static BlockDriver bdrv_iscsi = {
.format_name = "iscsi",
.protocol_name = "iscsi",
.instance_size = sizeof(IscsiLun),
.bdrv_file_open = iscsi_open,
.bdrv_close = iscsi_close,
.bdrv_getlength = iscsi_getlength,
.bdrv_aio_readv = iscsi_aio_readv,
.bdrv_aio_writev = iscsi_aio_writev,
.bdrv_aio_flush = iscsi_aio_flush,
};
static void iscsi_block_init(void)
{
bdrv_register(&bdrv_iscsi);
}
block_init(iscsi_block_init);

View File

@ -736,8 +736,6 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
return -EINVAL;
out_buf = g_malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
if (!out_buf)
return -1;
/* best compression, small window, no zlib header */
memset(&strm, 0, sizeof(strm));
@ -745,8 +743,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
Z_DEFLATED, -12,
9, Z_DEFAULT_STRATEGY);
if (ret != 0) {
g_free(out_buf);
return -1;
ret = -EINVAL;
goto fail;
}
strm.avail_in = s->cluster_size;
@ -756,9 +754,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
ret = deflate(&strm, Z_FINISH);
if (ret != Z_STREAM_END && ret != Z_OK) {
g_free(out_buf);
deflateEnd(&strm);
return -1;
ret = -EINVAL;
goto fail;
}
out_len = strm.next_out - out_buf;
@ -766,19 +764,29 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
/* could not compress: write normal cluster */
bdrv_write(bs, sector_num, buf, s->cluster_sectors);
ret = bdrv_write(bs, sector_num, buf, s->cluster_sectors);
if (ret < 0) {
goto fail;
}
} else {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
out_len, 0, 0);
if (cluster_offset == 0) {
ret = -EIO;
goto fail;
}
cluster_offset &= s->cluster_offset_mask;
if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) {
g_free(out_buf);
return -1;
ret = bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len);
if (ret < 0) {
goto fail;
}
}
ret = 0;
fail:
g_free(out_buf);
return 0;
return ret;
}
static coroutine_fn int qcow_co_flush(BlockDriverState *bs)

View File

@ -1113,11 +1113,13 @@ static int qcow2_co_flush(BlockDriverState *bs)
qemu_co_mutex_lock(&s->lock);
ret = qcow2_cache_flush(bs, s->l2_table_cache);
if (ret < 0) {
qemu_co_mutex_unlock(&s->lock);
return ret;
}
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
qemu_co_mutex_unlock(&s->lock);
return ret;
}
qemu_co_mutex_unlock(&s->lock);

View File

@ -114,8 +114,13 @@ void uuid_unparse(const uuid_t uu, char *out);
*/
#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
/* Unallocated blocks use this index (no need to convert endianness). */
#define VDI_UNALLOCATED UINT32_MAX
/* A never-allocated block; semantically arbitrary content. */
#define VDI_UNALLOCATED 0xffffffffU
/* A discarded (no longer allocated) block; semantically zero-filled. */
#define VDI_DISCARDED 0xfffffffeU
#define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
#if !defined(CONFIG_UUID)
void uuid_generate(uuid_t out)
@ -307,10 +312,10 @@ static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
/* Check block map and value of blocks_allocated. */
for (block = 0; block < s->header.blocks_in_image; block++) {
uint32_t bmap_entry = le32_to_cpu(s->bmap[block]);
if (bmap_entry != VDI_UNALLOCATED) {
if (VDI_IS_ALLOCATED(bmap_entry)) {
if (bmap_entry < s->header.blocks_in_image) {
blocks_allocated++;
if (bmap[bmap_entry] == VDI_UNALLOCATED) {
if (!VDI_IS_ALLOCATED(bmap[bmap_entry])) {
bmap[bmap_entry] = bmap_entry;
} else {
fprintf(stderr, "ERROR: block index %" PRIu32
@ -472,7 +477,7 @@ static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
n_sectors = nb_sectors;
}
*pnum = n_sectors;
return bmap_entry != VDI_UNALLOCATED;
return VDI_IS_ALLOCATED(bmap_entry);
}
static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
@ -603,7 +608,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
/* prepare next AIO request */
acb->n_sectors = n_sectors;
bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (bmap_entry == VDI_UNALLOCATED) {
if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Block not allocated, return zeros, no need to wait. */
memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
@ -685,7 +690,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
if (acb->header_modified) {
VdiHeader *header = acb->block_buffer;
logout("now writing modified header\n");
assert(acb->bmap_first != VDI_UNALLOCATED);
assert(VDI_IS_ALLOCATED(acb->bmap_first));
*header = s->header;
vdi_header_to_le(header);
acb->header_modified = 0;
@ -699,7 +704,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
goto done;
}
return;
} else if (acb->bmap_first != VDI_UNALLOCATED) {
} else if (VDI_IS_ALLOCATED(acb->bmap_first)) {
/* One or more new blocks were allocated. */
uint64_t offset;
uint32_t bmap_first;
@ -749,7 +754,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
/* prepare next AIO request */
acb->n_sectors = n_sectors;
bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (bmap_entry == VDI_UNALLOCATED) {
if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Allocate new block and write to it. */
uint64_t offset;
uint8_t *block;

View File

@ -212,8 +212,10 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
const char *p_name, *cid_str;
size_t cid_str_size;
BDRVVmdkState *s = bs->opaque;
int ret;
if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
if (ret < 0) {
return 0;
}
@ -225,6 +227,7 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
cid_str_size = sizeof("CID");
}
desc[DESC_SIZE - 1] = '\0';
p_name = strstr(desc, cid_str);
if (p_name != NULL) {
p_name += cid_str_size;
@ -239,13 +242,19 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
char *p_name, *tmp_str;
BDRVVmdkState *s = bs->opaque;
int ret;
memset(desc, 0, sizeof(desc));
if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
return -EIO;
ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE);
if (ret < 0) {
return ret;
}
desc[DESC_SIZE - 1] = '\0';
tmp_str = strstr(desc, "parentCID");
if (tmp_str == NULL) {
return -EINVAL;
}
pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str);
p_name = strstr(desc, "CID");
if (p_name != NULL) {
@ -254,9 +263,11 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
pstrcat(desc, sizeof(desc), tmp_desc);
}
if (bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE) < 0) {
return -EIO;
ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE);
if (ret < 0) {
return ret;
}
return 0;
}
@ -1109,7 +1120,10 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
/* update CID on the first write every time the virtual disk is
* opened */
if (!s->cid_updated) {
vmdk_write_cid(bs, time(NULL));
ret = vmdk_write_cid(bs, time(NULL));
if (ret < 0) {
return ret;
}
s->cid_updated = true;
}
}

31
configure vendored
View File

@ -182,6 +182,7 @@ usb_redir=""
opengl=""
zlib="yes"
guest_agent="yes"
libiscsi=""
# parse CC options first
for opt do
@ -657,6 +658,10 @@ for opt do
;;
--enable-spice) spice="yes"
;;
--disable-libiscsi) libiscsi="no"
;;
--enable-libiscsi) libiscsi="yes"
;;
--enable-profiler) profiler="yes"
;;
--enable-cocoa)
@ -1046,6 +1051,8 @@ echo " Default:trace-<pid>"
echo " --disable-spice disable spice"
echo " --enable-spice enable spice"
echo " --enable-rbd enable building the rados block device (rbd)"
echo " --disable-libiscsi disable iscsi support"
echo " --enable-libiscsi enable iscsi support"
echo " --disable-smartcard disable smartcard support"
echo " --enable-smartcard enable smartcard support"
echo " --disable-smartcard-nss disable smartcard nss support"
@ -2334,6 +2341,25 @@ if compile_prog "" "" ; then
bswap_h=yes
fi
##########################################
# Do we have libiscsi
if test "$libiscsi" != "no" ; then
cat > $TMPC << EOF
#include <iscsi/iscsi.h>
int main(void) { iscsi_create_context(""); return 0; }
EOF
if compile_prog "-Werror" "-liscsi" ; then
libiscsi="yes"
LIBS="$LIBS -liscsi"
else
if test "$libiscsi" = "yes" ; then
feature_not_found "libiscsi"
fi
libiscsi="no"
fi
fi
##########################################
# Do we need librt
cat > $TMPC <<EOF
@ -2744,6 +2770,7 @@ echo "xfsctl support $xfs"
echo "nss used $smartcard_nss"
echo "usb net redir $usb_redir"
echo "OpenGL support $opengl"
echo "libiscsi support $libiscsi"
echo "build guest agent $guest_agent"
if test "$sdl_too_old" = "yes"; then
@ -3042,6 +3069,10 @@ if test "$opengl" = "yes" ; then
echo "CONFIG_OPENGL=y" >> $config_host_mak
fi
if test "$libiscsi" = "yes" ; then
echo "CONFIG_LIBISCSI=y" >> $config_host_mak
fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
echo "CONFIG_BSD=y" >> $config_host_mak

View File

@ -108,8 +108,8 @@ as follows:
refcount_block_entries = (cluster_size / sizeof(uint16_t))
refcount_block_index = (offset / cluster_size) % refcount_table_entries
refcount_table_index = (offset / cluster_size) / refcount_table_entries
refcount_block_index = (offset / cluster_size) % refcount_block_entries
refcount_table_index = (offset / cluster_size) / refcount_block_entries
refcount_block = load_cluster(refcount_table[refcount_table_index]);
return refcount_block[refcount_block_index];
@ -211,7 +211,7 @@ switch the active L1 table, so that a different set of host clusters are
exposed to the guest.
When creating a snapshot, the L1 table should be copied and the refcount of all
L2 tables and clusters reachable form this L1 table must be increased, so that
L2 tables and clusters reachable from this L1 table must be increased, so that
a write causes a COW and isn't visible in other snapshots.
When loading a snapshot, bit 63 of all entries in the new active L1 table and

View File

@ -276,7 +276,7 @@ static void piix4_update_hotplug(PIIX4PMState *s)
s->pci0_hotplug_enable = ~0;
QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
int slot = PCI_SLOT(pdev->devfn);
@ -486,7 +486,7 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
PCIDeviceInfo *info;
int slot = ffs(val) - 1;
QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
dev = DO_UPCAST(PCIDevice, qdev, qdev);
info = container_of(qdev->info, PCIDeviceInfo, qdev);
if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {

View File

@ -217,7 +217,8 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
s->async_len = 0;
}
if (target >= ESP_MAX_DEVS || !s->bus.devs[target]) {
s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
if (!s->current_dev) {
// No such drive
s->rregs[ESP_RSTAT] = 0;
s->rregs[ESP_RINTR] = INTR_DC;
@ -225,7 +226,6 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
esp_raise_irq(s);
return 0;
}
s->current_dev = s->bus.devs[target];
return dmalen;
}
@ -233,10 +233,12 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
{
int32_t datalen;
int lun;
SCSIDevice *current_lun;
trace_esp_do_busid_cmd(busid);
lun = busid & 7;
s->current_req = scsi_req_new(s->current_dev, 0, lun, buf, NULL);
current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
s->current_req = scsi_req_new(current_lun, 0, lun, buf, NULL);
datalen = scsi_req_enqueue(s->current_req);
s->ti_size = datalen;
if (datalen != 0) {
@ -720,7 +722,11 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
*dma_enable = qdev_get_gpio_in(dev, 1);
}
static const struct SCSIBusOps esp_scsi_ops = {
static const struct SCSIBusInfo esp_scsi_info = {
.tcq = false,
.max_target = ESP_MAX_DEVS,
.max_lun = 7,
.transfer_data = esp_transfer_data,
.complete = esp_command_complete,
.cancel = esp_request_cancelled
@ -740,7 +746,7 @@ static int esp_init1(SysBusDevice *dev)
qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, &esp_scsi_ops);
scsi_bus_new(&s->bus, &dev->qdev, &esp_scsi_info);
return scsi_bus_legacy_handle_cmdline(&s->bus);
}

View File

@ -84,7 +84,7 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
DeviceState *qdev;
i2c_slave *slave = NULL;
QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
if (candidate->address == address) {
slave = candidate;

View File

@ -154,10 +154,10 @@ void ide_atapi_io_error(IDEState *s, int ret)
{
/* XXX: handle more errors */
if (ret == -ENOMEDIUM) {
ide_atapi_cmd_error(s, SENSE_NOT_READY,
ide_atapi_cmd_error(s, NOT_READY,
ASC_MEDIUM_NOT_PRESENT);
} else {
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
ASC_LOGICAL_BLOCK_OOR);
}
}
@ -282,7 +282,7 @@ static void ide_atapi_cmd_check_status(IDEState *s)
#ifdef DEBUG_IDE_ATAPI
printf("atapi_cmd_check_status\n");
#endif
s->error = MC_ERR | (SENSE_UNIT_ATTENTION << 4);
s->error = MC_ERR | (UNIT_ATTENTION << 4);
s->status = ERR_STAT;
s->nsector = 0;
ide_set_irq(s->bus);
@ -354,7 +354,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
ide_atapi_cmd_read_dma_cb, s);
if (!s->bus->dma->aiocb) {
/* Note: media not present is the most likely case */
ide_atapi_cmd_error(s, SENSE_NOT_READY,
ide_atapi_cmd_error(s, NOT_READY,
ASC_MEDIUM_NOT_PRESENT);
goto eot;
}
@ -505,19 +505,6 @@ static int ide_dvd_read_structure(IDEState *s, int format,
static unsigned int event_status_media(IDEState *s,
uint8_t *buf)
{
enum media_event_code {
MEC_NO_CHANGE = 0, /* Status unchanged */
MEC_EJECT_REQUESTED, /* received a request from user to eject */
MEC_NEW_MEDIA, /* new media inserted and ready for access */
MEC_MEDIA_REMOVAL, /* only for media changers */
MEC_MEDIA_CHANGED, /* only for media changers */
MEC_BG_FORMAT_COMPLETED, /* MRW or DVD+RW b/g format completed */
MEC_BG_FORMAT_RESTARTED, /* MRW or DVD+RW b/g format restarted */
};
enum media_status {
MS_TRAY_OPEN = 1,
MS_MEDIA_PRESENT = 2,
};
uint8_t event_code, media_status;
media_status = 0;
@ -564,27 +551,6 @@ static void cmd_get_event_status_notification(IDEState *s,
uint8_t notification_class;
uint8_t supported_events;
} QEMU_PACKED *gesn_event_header;
enum notification_class_request_type {
NCR_RESERVED1 = 1 << 0,
NCR_OPERATIONAL_CHANGE = 1 << 1,
NCR_POWER_MANAGEMENT = 1 << 2,
NCR_EXTERNAL_REQUEST = 1 << 3,
NCR_MEDIA = 1 << 4,
NCR_MULTI_HOST = 1 << 5,
NCR_DEVICE_BUSY = 1 << 6,
NCR_RESERVED2 = 1 << 7,
};
enum event_notification_class_field {
ENC_NO_EVENTS = 0,
ENC_OPERATIONAL_CHANGE,
ENC_POWER_MANAGEMENT,
ENC_EXTERNAL_REQUEST,
ENC_MEDIA,
ENC_MULTIPLE_HOSTS,
ENC_DEVICE_BUSY,
ENC_RESERVED,
};
unsigned int max_len, used_len;
gesn_cdb = (void *)packet;
@ -595,7 +561,7 @@ static void cmd_get_event_status_notification(IDEState *s,
/* It is fine by the MMC spec to not support async mode operations */
if (!(gesn_cdb->polled & 0x01)) { /* asynchronous mode */
/* Only polling is supported, asynchronous mode is not. */
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
ASC_INV_FIELD_IN_CMD_PACKET);
return;
}
@ -606,8 +572,11 @@ static void cmd_get_event_status_notification(IDEState *s,
* These are the supported events.
*
* We currently only support requests of the 'media' type.
* Notification class requests and supported event classes are bitmasks,
* but they are build from the same values as the "notification class"
* field.
*/
gesn_event_header->supported_events = NCR_MEDIA;
gesn_event_header->supported_events = 1 << GESN_MEDIA;
/*
* We use |= below to set the class field; other bits in this byte
@ -621,8 +590,8 @@ static void cmd_get_event_status_notification(IDEState *s,
* notification_class_request_type enum above specifies the
* priority: upper elements are higher prio than lower ones.
*/
if (gesn_cdb->class & NCR_MEDIA) {
gesn_event_header->notification_class |= ENC_MEDIA;
if (gesn_cdb->class & (1 << GESN_MEDIA)) {
gesn_event_header->notification_class |= GESN_MEDIA;
used_len = event_status_media(s, buf);
} else {
gesn_event_header->notification_class = 0x80; /* No event available */
@ -643,8 +612,8 @@ static void cmd_request_sense(IDEState *s, uint8_t *buf)
buf[7] = 10;
buf[12] = s->asc;
if (s->sense_key == SENSE_UNIT_ATTENTION) {
s->sense_key = SENSE_NONE;
if (s->sense_key == UNIT_ATTENTION) {
s->sense_key = NO_SENSE;
}
ide_atapi_cmd_reply(s, 18, max_len);
@ -676,7 +645,7 @@ static void cmd_get_configuration(IDEState *s, uint8_t *buf)
/* only feature 0 is supported */
if (buf[2] != 0 || buf[3] != 0) {
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
ASC_INV_FIELD_IN_CMD_PACKET);
return;
}
@ -733,7 +702,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
switch(action) {
case 0: /* current values */
switch(code) {
case GPMODE_R_W_ERROR_PAGE: /* error recovery */
case MODE_PAGE_R_W_ERROR: /* error recovery */
cpu_to_ube16(&buf[0], 16 + 6);
buf[2] = 0x70;
buf[3] = 0;
@ -742,8 +711,8 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
buf[6] = 0;
buf[7] = 0;
buf[8] = 0x01;
buf[9] = 0x06;
buf[8] = MODE_PAGE_R_W_ERROR;
buf[9] = 16 - 10;
buf[10] = 0x00;
buf[11] = 0x05;
buf[12] = 0x00;
@ -752,7 +721,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
buf[15] = 0x00;
ide_atapi_cmd_reply(s, 16, max_len);
break;
case GPMODE_AUDIO_CTL_PAGE:
case MODE_PAGE_AUDIO_CTL:
cpu_to_ube16(&buf[0], 24 + 6);
buf[2] = 0x70;
buf[3] = 0;
@ -761,6 +730,8 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
buf[6] = 0;
buf[7] = 0;
buf[8] = MODE_PAGE_AUDIO_CTL;
buf[9] = 24 - 10;
/* Fill with CDROM audio volume */
buf[17] = 0;
buf[19] = 0;
@ -769,7 +740,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
ide_atapi_cmd_reply(s, 24, max_len);
break;
case GPMODE_CAPABILITIES_PAGE:
case MODE_PAGE_CAPABILITIES:
cpu_to_ube16(&buf[0], 28 + 6);
buf[2] = 0x70;
buf[3] = 0;
@ -778,9 +749,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
buf[6] = 0;
buf[7] = 0;
buf[8] = 0x2a;
buf[9] = 0x12;
buf[10] = 0x00;
buf[8] = MODE_PAGE_CAPABILITIES;
buf[9] = 28 - 10;
buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */
buf[11] = 0x00;
/* Claim PLAY_AUDIO capability (0x01) since some Linux
@ -789,14 +760,14 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
buf[13] = 3 << 5;
buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
if (s->tray_locked) {
buf[6] |= 1 << 1;
buf[14] |= 1 << 1;
}
buf[15] = 0x00;
cpu_to_ube16(&buf[16], 706);
buf[18] = 0;
buf[15] = 0x00; /* No volume & mute control, no changer */
cpu_to_ube16(&buf[16], 704); /* 4x read speed */
buf[18] = 0; /* Two volume levels */
buf[19] = 2;
cpu_to_ube16(&buf[20], 512);
cpu_to_ube16(&buf[22], 706);
cpu_to_ube16(&buf[20], 512); /* 512k buffer */
cpu_to_ube16(&buf[22], 704); /* 4x read speed current */
buf[24] = 0;
buf[25] = 0;
buf[26] = 0;
@ -813,14 +784,14 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf)
goto error_cmd;
default:
case 3: /* saved values */
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
break;
}
return;
error_cmd:
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET);
}
static void cmd_test_unit_ready(IDEState *s, uint8_t *buf)
@ -883,7 +854,7 @@ static void cmd_read_cd(IDEState *s, uint8_t* buf)
ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
break;
default:
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
ASC_INV_FIELD_IN_CMD_PACKET);
break;
}
@ -896,7 +867,7 @@ static void cmd_seek(IDEState *s, uint8_t* buf)
lba = ube32_to_cpu(buf + 2);
if (lba >= total_sectors) {
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_LOGICAL_BLOCK_OOR);
return;
}
@ -912,7 +883,7 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
if (loej) {
if (!start && !s->tray_open && s->tray_locked) {
sense = bdrv_is_inserted(s->bs)
? SENSE_NOT_READY : SENSE_ILLEGAL_REQUEST;
? NOT_READY : ILLEGAL_REQUEST;
ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED);
return;
}
@ -971,7 +942,7 @@ static void cmd_read_toc_pma_atip(IDEState *s, uint8_t* buf)
break;
default:
error_cmd:
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
ASC_INV_FIELD_IN_CMD_PACKET);
}
}
@ -997,11 +968,11 @@ static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
if (format < 0xff) {
if (media_is_cd(s)) {
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
ASC_INCOMPATIBLE_FORMAT);
return;
} else if (!media_present(s)) {
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
ASC_INV_FIELD_IN_CMD_PACKET);
return;
}
@ -1017,7 +988,7 @@ static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
ret = ide_dvd_read_structure(s, format, buf, buf);
if (ret < 0) {
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, -ret);
ide_atapi_cmd_error(s, ILLEGAL_REQUEST, -ret);
} else {
ide_atapi_cmd_reply(s, ret, max_len);
}
@ -1034,7 +1005,7 @@ static void cmd_read_dvd_structure(IDEState *s, uint8_t* buf)
case 0x90: /* TODO: List of recognized format layers */
case 0xc0: /* TODO: Write protection status */
default:
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
ide_atapi_cmd_error(s, ILLEGAL_REQUEST,
ASC_INV_FIELD_IN_CMD_PACKET);
break;
}
@ -1106,7 +1077,7 @@ void ide_atapi_cmd(IDEState *s)
* condition response unless a higher priority status, defined by the drive
* here, is pending.
*/
if (s->sense_key == SENSE_UNIT_ATTENTION &&
if (s->sense_key == UNIT_ATTENTION &&
!(atapi_cmd_table[s->io_buffer[0]].flags & ALLOW_UA)) {
ide_atapi_cmd_check_status(s);
return;
@ -1119,10 +1090,10 @@ void ide_atapi_cmd(IDEState *s)
* states rely on this behavior.
*/
if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) {
ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
s->cdrom_changed = 0;
s->sense_key = SENSE_UNIT_ATTENTION;
s->sense_key = UNIT_ATTENTION;
s->asc = ASC_MEDIUM_MAY_HAVE_CHANGED;
return;
}
@ -1131,7 +1102,7 @@ void ide_atapi_cmd(IDEState *s)
if ((atapi_cmd_table[s->io_buffer[0]].flags & CHECK_READY) &&
(!media_present(s) || !bdrv_is_inserted(s->bs)))
{
ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
ide_atapi_cmd_error(s, NOT_READY, ASC_MEDIUM_NOT_PRESENT);
return;
}
@ -1141,5 +1112,5 @@ void ide_atapi_cmd(IDEState *s)
return;
}
ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE);
ide_atapi_cmd_error(s, ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE);
}

View File

@ -799,7 +799,7 @@ static void ide_cd_change_cb(void *opaque, bool load)
* First indicate to the guest that a CD has been removed. That's
* done on the next command the guest sends us.
*
* Then we set SENSE_UNIT_ATTENTION, by which the guest will
* Then we set UNIT_ATTENTION, by which the guest will
* detect a new CD in the drive. See ide_atapi_cmd() for details.
*/
s->cdrom_changed = 1;
@ -2027,7 +2027,7 @@ static int ide_drive_post_load(void *opaque, int version_id)
IDEState *s = opaque;
if (version_id < 3) {
if (s->sense_key == SENSE_UNIT_ATTENTION &&
if (s->sense_key == UNIT_ATTENTION &&
s->asc == ASC_MEDIUM_MAY_HAVE_CHANGED) {
s->cdrom_changed = 1;
}
@ -2039,7 +2039,7 @@ static int ide_drive_pio_post_load(void *opaque, int version_id)
{
IDEState *s = opaque;
if (s->end_transfer_fn_idx > ARRAY_SIZE(transfer_end_table)) {
if (s->end_transfer_fn_idx >= ARRAY_SIZE(transfer_end_table)) {
return -EINVAL;
}
s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];

View File

@ -11,6 +11,7 @@
#include "iorange.h"
#include "dma.h"
#include "sysemu.h"
#include "hw/scsi-defs.h"
/* debug IDE devices */
//#define DEBUG_IDE
@ -280,71 +281,6 @@ typedef struct IDEDMAOps IDEDMAOps;
#define GPCMD_GET_MEDIA_STATUS 0xda
#define GPCMD_MODE_SENSE_6 0x1a
/* Mode page codes for mode sense/set */
#define GPMODE_R_W_ERROR_PAGE 0x01
#define GPMODE_WRITE_PARMS_PAGE 0x05
#define GPMODE_AUDIO_CTL_PAGE 0x0e
#define GPMODE_POWER_PAGE 0x1a
#define GPMODE_FAULT_FAIL_PAGE 0x1c
#define GPMODE_TO_PROTECT_PAGE 0x1d
#define GPMODE_CAPABILITIES_PAGE 0x2a
#define GPMODE_ALL_PAGES 0x3f
/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
* of MODE_SENSE_POWER_PAGE */
#define GPMODE_CDROM_PAGE 0x0d
/*
* Based on values from <linux/cdrom.h> but extending CD_MINS
* to the maximum common size allowed by the Orange's Book ATIP
*
* 90 and 99 min CDs are also available but using them as the
* upper limit reduces the effectiveness of the heuristic to
* detect DVDs burned to less than 25% of their maximum capacity
*/
/* Some generally useful CD-ROM information */
#define CD_MINS 80 /* max. minutes per CD */
#define CD_SECS 60 /* seconds per minute */
#define CD_FRAMES 75 /* frames per second */
#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */
#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
#define CD_MAX_SECTORS (CD_MAX_BYTES / 512)
/*
* The MMC values are not IDE specific and might need to be moved
* to a common header if they are also needed for the SCSI emulation
*/
/* Profile list from MMC-6 revision 1 table 91 */
#define MMC_PROFILE_NONE 0x0000
#define MMC_PROFILE_CD_ROM 0x0008
#define MMC_PROFILE_CD_R 0x0009
#define MMC_PROFILE_CD_RW 0x000A
#define MMC_PROFILE_DVD_ROM 0x0010
#define MMC_PROFILE_DVD_R_SR 0x0011
#define MMC_PROFILE_DVD_RAM 0x0012
#define MMC_PROFILE_DVD_RW_RO 0x0013
#define MMC_PROFILE_DVD_RW_SR 0x0014
#define MMC_PROFILE_DVD_R_DL_SR 0x0015
#define MMC_PROFILE_DVD_R_DL_JR 0x0016
#define MMC_PROFILE_DVD_RW_DL 0x0017
#define MMC_PROFILE_DVD_DDR 0x0018
#define MMC_PROFILE_DVD_PLUS_RW 0x001A
#define MMC_PROFILE_DVD_PLUS_R 0x001B
#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A
#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B
#define MMC_PROFILE_BD_ROM 0x0040
#define MMC_PROFILE_BD_R_SRM 0x0041
#define MMC_PROFILE_BD_R_RRM 0x0042
#define MMC_PROFILE_BD_RE 0x0043
#define MMC_PROFILE_HDDVD_ROM 0x0050
#define MMC_PROFILE_HDDVD_R 0x0051
#define MMC_PROFILE_HDDVD_RAM 0x0052
#define MMC_PROFILE_HDDVD_RW 0x0053
#define MMC_PROFILE_HDDVD_R_DL 0x0058
#define MMC_PROFILE_HDDVD_RW_DL 0x005A
#define MMC_PROFILE_INVALID 0xFFFF
#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */
#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */
#define ATAPI_INT_REASON_REL 0x04
@ -366,11 +302,6 @@ typedef struct IDEDMAOps IDEDMAOps;
#define CFA_INVALID_ADDRESS 0x21
#define CFA_ADDRESS_OVERFLOW 0x2f
#define SENSE_NONE 0
#define SENSE_NOT_READY 2
#define SENSE_ILLEGAL_REQUEST 5
#define SENSE_UNIT_ATTENTION 6
#define SMART_READ_DATA 0xd0
#define SMART_READ_THRESH 0xd1
#define SMART_ATTR_AUTOSAVE 0xd2

View File

@ -87,7 +87,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
if (!m->aiocb) {
qemu_sglist_destroy(&s->sg);
/* Note: media not present is the most likely case */
ide_atapi_cmd_error(s, SENSE_NOT_READY,
ide_atapi_cmd_error(s, NOT_READY,
ASC_MEDIUM_NOT_PRESENT);
goto done;
}

View File

@ -86,7 +86,7 @@ HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
DeviceState *qdev;
HDACodecDevice *cdev;
QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (cdev->cad == cad) {
return cdev;
@ -490,7 +490,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn
DeviceState *qdev;
HDACodecDevice *cdev;
QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (cdev->info->stream) {
cdev->info->stream(cdev, stream, running, output);
@ -1114,7 +1114,7 @@ static void intel_hda_reset(DeviceState *dev)
d->wall_base_ns = qemu_get_clock_ns(vm_clock);
/* reset codecs */
QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (qdev->info->reset) {
qdev->info->reset(qdev);

View File

@ -531,7 +531,7 @@ static void lsi_bad_selection(LSIState *s, uint32_t id)
/* Initiate a SCSI layer data transfer. */
static void lsi_do_dma(LSIState *s, int out)
{
uint32_t count, id;
uint32_t count;
target_phys_addr_t addr;
SCSIDevice *dev;
@ -542,12 +542,8 @@ static void lsi_do_dma(LSIState *s, int out)
return;
}
id = (s->current->tag >> 8) & 0xf;
dev = s->bus.devs[id];
if (!dev) {
lsi_bad_selection(s, id);
return;
}
dev = s->current->req->dev;
assert(dev);
count = s->dbc;
if (count > s->current->dma_len)
@ -771,7 +767,7 @@ static void lsi_do_command(LSIState *s)
s->command_complete = 0;
id = (s->select_tag >> 8) & 0xf;
dev = s->bus.devs[id];
dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
if (!dev) {
lsi_bad_selection(s, id);
return;
@ -1202,7 +1198,7 @@ again:
}
s->sstat0 |= LSI_SSTAT0_WOA;
s->scntl1 &= ~LSI_SCNTL1_IARB;
if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) {
if (!scsi_device_find(&s->bus, 0, id, 0)) {
lsi_bad_selection(s, id);
break;
}
@ -1684,13 +1680,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
if (val & LSI_SCNTL1_RST) {
if (!(s->sstat0 & LSI_SSTAT0_RST)) {
DeviceState *dev;
int id;
for (id = 0; id < s->bus.ndev; id++) {
if (s->bus.devs[id]) {
dev = &s->bus.devs[id]->qdev;
dev->info->reset(dev);
}
QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) {
dev->info->reset(dev);
}
s->sstat0 |= LSI_SSTAT0_RST;
lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
@ -2091,7 +2083,11 @@ static int lsi_scsi_uninit(PCIDevice *d)
return 0;
}
static const struct SCSIBusOps lsi_scsi_ops = {
static const struct SCSIBusInfo lsi_scsi_info = {
.tcq = true,
.max_target = LSI_MAX_DEVS,
.max_lun = 0, /* LUN support is buggy */
.transfer_data = lsi_transfer_data,
.complete = lsi_command_complete,
.cancel = lsi_request_cancelled
@ -2118,7 +2114,7 @@ static int lsi_scsi_init(PCIDevice *dev)
pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
QTAILQ_INIT(&s->queue);
scsi_bus_new(&s->bus, &dev->qdev, 1, LSI_MAX_DEVS, &lsi_scsi_ops);
scsi_bus_new(&s->bus, &dev->qdev, &lsi_scsi_info);
if (!dev->qdev.hotplugged) {
return scsi_bus_legacy_handle_cmdline(&s->bus);
}

View File

@ -91,7 +91,7 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
qdev_prop_set_defaults(dev, dev->info->props);
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
qdev_prop_set_globals(dev);
QLIST_INSERT_HEAD(&bus->children, dev, sibling);
QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
if (qdev_hotplug) {
assert(bus->allow_hotplug);
dev->hotplugged = 1;
@ -408,7 +408,7 @@ void qdev_free(DeviceState *dev)
if (dev->opts)
qemu_opts_del(dev->opts);
}
QLIST_REMOVE(dev, sibling);
QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
for (prop = dev->info->props; prop && prop->name; prop++) {
if (prop->info->free) {
prop->info->free(dev, prop);
@ -510,7 +510,7 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
}
}
QLIST_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(dev, &bus->children, sibling) {
err = qdev_walk_children(dev, devfn, busfn, opaque);
if (err < 0) {
return err;
@ -560,7 +560,7 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name,
return bus;
}
QLIST_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(dev, &bus->children, sibling) {
QLIST_FOREACH(child, &dev->child_bus, sibling) {
ret = qbus_find_recursive(child, name, info);
if (ret) {
@ -576,7 +576,7 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
DeviceState *dev, *ret;
BusState *child;
QLIST_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (dev->id && strcmp(dev->id, id) == 0)
return dev;
QLIST_FOREACH(child, &dev->child_bus, sibling) {
@ -609,7 +609,7 @@ static void qbus_list_dev(BusState *bus)
const char *sep = " ";
error_printf("devices at \"%s\":", bus->name);
QLIST_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(dev, &bus->children, sibling) {
error_printf("%s\"%s\"", sep, dev->info->name);
if (dev->id)
error_printf("/\"%s\"", dev->id);
@ -640,17 +640,17 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
* (2) driver name
* (3) driver alias, if present
*/
QLIST_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (dev->id && strcmp(dev->id, elem) == 0) {
return dev;
}
}
QLIST_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (strcmp(dev->info->name, elem) == 0) {
return dev;
}
}
QLIST_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
return dev;
}
@ -774,7 +774,7 @@ void qbus_create_inplace(BusState *bus, BusInfo *info,
bus->name = buf;
}
QLIST_INIT(&bus->children);
QTAILQ_INIT(&bus->children);
if (parent) {
QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
parent->num_child_bus++;
@ -809,7 +809,7 @@ void qbus_free(BusState *bus)
{
DeviceState *dev;
while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
qdev_free(dev);
}
if (bus->parent) {
@ -878,7 +878,7 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent)
qdev_printf("bus: %s\n", bus->name);
indent += 2;
qdev_printf("type %s\n", bus->info->name);
QLIST_FOREACH(dev, &bus->children, sibling) {
QTAILQ_FOREACH(dev, &bus->children, sibling) {
qdev_print(mon, dev, indent);
}
}

View File

@ -42,7 +42,7 @@ struct DeviceState {
qemu_irq *gpio_in;
QLIST_HEAD(, BusState) child_bus;
int num_child_bus;
QLIST_ENTRY(DeviceState) sibling;
QTAILQ_ENTRY(DeviceState) sibling;
int instance_id_alias;
int alias_required_for_version;
};
@ -73,7 +73,7 @@ struct BusState {
const char *name;
int allow_hotplug;
int qdev_allocated;
QLIST_HEAD(, DeviceState) children;
QTAILQ_HEAD(ChildrenHead, DeviceState) children;
QLIST_ENTRY(BusState) sibling;
};

View File

@ -274,7 +274,7 @@ VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
DeviceState *dev;
int i;
QLIST_FOREACH(dev, &bus->bus.children, sibling) {
QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
_dev = (VirtIOS390Device *)dev;
for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
if (!virtio_queue_get_addr(_dev->vdev, i))
@ -297,7 +297,7 @@ VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem)
VirtIOS390Device *_dev;
DeviceState *dev;
QLIST_FOREACH(dev, &bus->bus.children, sibling) {
QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
_dev = (VirtIOS390Device *)dev;
if (_dev->dev_offs == mem) {
return _dev;

View File

@ -8,6 +8,7 @@
static char *scsibus_get_fw_dev_path(DeviceState *dev);
static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
static void scsi_req_dequeue(SCSIRequest *req);
static int scsi_build_sense(uint8_t *in_buf, int in_len,
uint8_t *buf, int len, bool fixed);
@ -16,53 +17,123 @@ static struct BusInfo scsi_bus_info = {
.size = sizeof(SCSIBus),
.get_fw_dev_path = scsibus_get_fw_dev_path,
.props = (Property[]) {
DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
DEFINE_PROP_UINT32("lun", SCSIDevice, lun, 0),
DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
DEFINE_PROP_END_OF_LIST(),
},
};
static int next_scsi_bus;
/* Create a scsi bus, and attach devices to it. */
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
const SCSIBusOps *ops)
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
{
qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
bus->busnr = next_scsi_bus++;
bus->tcq = tcq;
bus->ndev = ndev;
bus->ops = ops;
bus->info = info;
bus->qbus.allow_hotplug = 1;
}
static void scsi_dma_restart_bh(void *opaque)
{
SCSIDevice *s = opaque;
SCSIRequest *req, *next;
qemu_bh_delete(s->bh);
s->bh = NULL;
QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
scsi_req_ref(req);
if (req->retry) {
req->retry = false;
switch (req->cmd.mode) {
case SCSI_XFER_FROM_DEV:
case SCSI_XFER_TO_DEV:
scsi_req_continue(req);
break;
case SCSI_XFER_NONE:
scsi_req_dequeue(req);
scsi_req_enqueue(req);
break;
}
}
scsi_req_unref(req);
}
}
void scsi_req_retry(SCSIRequest *req)
{
/* No need to save a reference, because scsi_dma_restart_bh just
* looks at the request list. */
req->retry = true;
}
static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
{
SCSIDevice *s = opaque;
if (!running) {
return;
}
if (!s->bh) {
s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
qemu_bh_schedule(s->bh);
}
}
static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
{
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
SCSIDevice *d;
int rc = -1;
if (dev->id == -1) {
for (dev->id = 0; dev->id < bus->ndev; dev->id++) {
if (bus->devs[dev->id] == NULL)
break;
}
if (dev->channel > bus->info->max_channel) {
error_report("bad scsi channel id: %d", dev->channel);
goto err;
}
if (dev->id >= bus->ndev) {
if (dev->id != -1 && dev->id > bus->info->max_target) {
error_report("bad scsi device id: %d", dev->id);
goto err;
}
if (bus->devs[dev->id]) {
qdev_free(&bus->devs[dev->id]->qdev);
if (dev->id == -1) {
int id = -1;
if (dev->lun == -1) {
dev->lun = 0;
}
do {
d = scsi_device_find(bus, dev->channel, ++id, dev->lun);
} while (d && d->lun == dev->lun && id <= bus->info->max_target);
if (id > bus->info->max_target) {
error_report("no free target");
goto err;
}
dev->id = id;
} else if (dev->lun == -1) {
int lun = -1;
do {
d = scsi_device_find(bus, dev->channel, dev->id, ++lun);
} while (d && d->lun == lun && lun < bus->info->max_lun);
if (lun > bus->info->max_lun) {
error_report("no free lun");
goto err;
}
dev->lun = lun;
} else {
d = scsi_device_find(bus, dev->channel, dev->id, dev->lun);
if (dev->lun == d->lun && dev != d) {
qdev_free(&d->qdev);
}
}
bus->devs[dev->id] = dev;
dev->info = info;
QTAILQ_INIT(&dev->requests);
rc = dev->info->init(dev);
if (rc != 0) {
bus->devs[dev->id] = NULL;
if (rc == 0) {
dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
dev);
}
err:
@ -72,13 +143,13 @@ err:
static int scsi_qdev_exit(DeviceState *qdev)
{
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
assert(bus->devs[dev->id] != NULL);
if (bus->devs[dev->id]->info->destroy) {
bus->devs[dev->id]->info->destroy(bus->devs[dev->id]);
if (dev->vmsentry) {
qemu_del_vm_change_state_handler(dev->vmsentry);
}
if (dev->info->destroy) {
dev->info->destroy(dev);
}
bus->devs[dev->id] = NULL;
return 0;
}
@ -120,7 +191,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
int res = 0, unit;
loc_push_none(&loc);
for (unit = 0; unit < bus->ndev; unit++) {
for (unit = 0; unit < bus->info->max_target; unit++) {
dinfo = drive_get(IF_SCSI, bus->busnr, unit);
if (dinfo == NULL) {
continue;
@ -144,7 +215,7 @@ static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
struct SCSIReqOps reqops_invalid_opcode = {
static const struct SCSIReqOps reqops_invalid_opcode = {
.size = sizeof(SCSIRequest),
.send_command = scsi_invalid_command
};
@ -162,7 +233,7 @@ static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
return 0;
}
struct SCSIReqOps reqops_unit_attention = {
static const struct SCSIReqOps reqops_unit_attention = {
.size = sizeof(SCSIRequest),
.send_command = scsi_unit_attention
};
@ -175,7 +246,7 @@ typedef struct SCSITargetReq SCSITargetReq;
struct SCSITargetReq {
SCSIRequest req;
int len;
uint8_t buf[64];
uint8_t buf[2056];
};
static void store_lun(uint8_t *outbuf, int lun)
@ -190,23 +261,53 @@ static void store_lun(uint8_t *outbuf, int lun)
static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
{
int len;
DeviceState *qdev;
int i, len, n;
int channel, id;
bool found_lun0;
if (r->req.cmd.xfer < 16) {
return false;
}
if (r->req.cmd.buf[2] > 2) {
return false;
}
len = MIN(sizeof r->buf, r->req.cmd.xfer);
memset(r->buf, 0, len);
if (r->req.dev->lun != 0) {
r->buf[3] = 16;
r->len = 24;
store_lun(&r->buf[16], r->req.dev->lun);
} else {
r->buf[3] = 8;
r->len = 16;
channel = r->req.dev->channel;
id = r->req.dev->id;
found_lun0 = false;
n = 0;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == 0) {
found_lun0 = true;
}
n += 8;
}
}
if (!found_lun0) {
n += 8;
}
len = MIN(n + 8, r->req.cmd.xfer & ~7);
if (len > sizeof(r->buf)) {
/* TODO: > 256 LUNs? */
return false;
}
memset(r->buf, 0, len);
stl_be_p(&r->buf, n);
i = found_lun0 ? 8 : 16;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
if (dev->channel == channel && dev->id == id) {
store_lun(&r->buf[i], dev->lun);
i += 8;
}
}
assert(i == n + 8);
r->len = len;
return true;
}
@ -265,7 +366,7 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
r->buf[2] = 5; /* Version */
r->buf[3] = 2 | 0x10; /* HiSup, response data format */
r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */
r->buf[7] = 0x10 | (r->req.bus->tcq ? 0x02 : 0); /* Sync, TCQ. */
r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ. */
memcpy(&r->buf[8], "QEMU ", 8);
memcpy(&r->buf[16], "QEMU TARGET ", 16);
strncpy((char *) &r->buf[32], QEMU_VERSION, 4);
@ -295,6 +396,13 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
r->len = scsi_device_get_sense(r->req.dev, r->buf,
MIN(req->cmd.xfer, sizeof r->buf),
(req->cmd.buf[1] & 1) == 0);
if (r->req.dev->sense_is_ua) {
if (r->req.dev->info->unit_attention_reported) {
r->req.dev->info->unit_attention_reported(req->dev);
}
r->req.dev->sense_len = 0;
r->req.dev->sense_is_ua = false;
}
break;
default:
scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
@ -333,7 +441,7 @@ static uint8_t *scsi_target_get_buf(SCSIRequest *req)
return r->buf;
}
struct SCSIReqOps reqops_target_command = {
static const struct SCSIReqOps reqops_target_command = {
.size = sizeof(SCSITargetReq),
.send_command = scsi_target_send_command,
.read_data = scsi_target_read_data,
@ -341,8 +449,8 @@ struct SCSIReqOps reqops_target_command = {
};
SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag,
uint32_t lun, void *hba_private)
SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
uint32_t tag, uint32_t lun, void *hba_private)
{
SCSIRequest *req;
@ -383,7 +491,13 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
(buf[0] != INQUIRY &&
buf[0] != REPORT_LUNS &&
buf[0] != GET_CONFIGURATION &&
buf[0] != GET_EVENT_STATUS_NOTIFICATION)) {
buf[0] != GET_EVENT_STATUS_NOTIFICATION &&
/*
* If we already have a pending unit attention condition,
* report this one before triggering another one.
*/
!(buf[0] == REQUEST_SENSE && d->sense_is_ua))) {
req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun,
hba_private);
} else if (lun != d->lun ||
@ -392,7 +506,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
hba_private);
} else {
req = d->info->alloc_req(d, tag, lun, hba_private);
req = d->info->alloc_req(d, tag, lun, buf, hba_private);
}
}
@ -479,10 +593,15 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
*
* We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
* 10b for HBAs that do not support it (do not call scsi_req_get_sense).
* In the latter case, scsi_req_complete clears unit attention conditions
* after moving them to the device's sense buffer.
* Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
*/
scsi_clear_unit_attention(req);
if (req->dev->sense_is_ua) {
if (req->dev->info->unit_attention_reported) {
req->dev->info->unit_attention_reported(req->dev);
}
req->dev->sense_len = 0;
req->dev->sense_is_ua = false;
}
return ret;
}
@ -522,6 +641,7 @@ int32_t scsi_req_enqueue(SCSIRequest *req)
static void scsi_req_dequeue(SCSIRequest *req)
{
trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
req->retry = false;
if (req->enqueued) {
QTAILQ_REMOVE(&req->dev->requests, req, next);
req->enqueued = false;
@ -800,7 +920,7 @@ const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
};
/* Illegal request, Incompatible medium installed */
const struct SCSISense sense_code_INCOMPATIBLE_MEDIUM = {
const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
.key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
};
@ -829,6 +949,11 @@ const struct SCSISense sense_code_RESET = {
.key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
};
/* Unit attention, No medium */
const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
.key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
};
/* Unit attention, Medium may have changed */
const struct SCSISense sense_code_MEDIUM_CHANGED = {
.key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
@ -1038,8 +1163,12 @@ void scsi_req_continue(SCSIRequest *req)
Once it completes, calling scsi_req_continue will restart I/O. */
void scsi_req_data(SCSIRequest *req, int len)
{
trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
req->bus->ops->transfer_data(req, len);
if (req->io_canceled) {
trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
} else {
trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
req->bus->info->transfer_data(req, len);
}
}
void scsi_req_print(SCSIRequest *req)
@ -1082,8 +1211,12 @@ void scsi_req_complete(SCSIRequest *req, int status)
if (req->sense_len) {
memcpy(req->dev->sense, req->sense, req->sense_len);
req->dev->sense_len = req->sense_len;
req->dev->sense_is_ua = (req->ops == &reqops_unit_attention);
} else {
req->dev->sense_len = 0;
req->dev->sense_is_ua = false;
}
req->dev->sense_len = req->sense_len;
/*
* Unit attention state is now stored in the device's sense buffer
@ -1094,29 +1227,40 @@ void scsi_req_complete(SCSIRequest *req, int status)
scsi_req_ref(req);
scsi_req_dequeue(req);
req->bus->ops->complete(req, req->status);
req->bus->info->complete(req, req->status);
scsi_req_unref(req);
}
void scsi_req_cancel(SCSIRequest *req)
{
if (req->ops->cancel_io) {
req->ops->cancel_io(req);
if (!req->enqueued) {
return;
}
scsi_req_ref(req);
scsi_req_dequeue(req);
if (req->bus->ops->cancel) {
req->bus->ops->cancel(req);
req->io_canceled = true;
if (req->ops->cancel_io) {
req->ops->cancel_io(req);
}
if (req->bus->info->cancel) {
req->bus->info->cancel(req);
}
scsi_req_unref(req);
}
void scsi_req_abort(SCSIRequest *req, int status)
{
if (!req->enqueued) {
return;
}
scsi_req_ref(req);
scsi_req_dequeue(req);
req->io_canceled = true;
if (req->ops->cancel_io) {
req->ops->cancel_io(req);
}
scsi_req_complete(req, status);
scsi_req_unref(req);
}
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
@ -1133,19 +1277,28 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
static char *scsibus_get_fw_dev_path(DeviceState *dev)
{
SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
SCSIBus *bus = scsi_bus_from_device(d);
char path[100];
int i;
for (i = 0; i < bus->ndev; i++) {
if (bus->devs[i] == d) {
break;
}
}
assert(i != bus->ndev);
snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i);
snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev),
d->channel, d->id, d->lun);
return strdup(path);
}
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
{
DeviceState *qdev;
SCSIDevice *target_dev = NULL;
QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == lun) {
return dev;
}
target_dev = dev;
}
}
return target_dev;
}

View File

@ -113,6 +113,7 @@
#define READ_12 0xa8
#define WRITE_12 0xaa
#define SERVICE_ACTION_IN_12 0xab
#define READ_DVD_STRUCTURE 0xad
#define WRITE_VERIFY_12 0xae
#define VERIFY_12 0xaf
#define SEARCH_HIGH_12 0xb0
@ -122,6 +123,8 @@
#define SEND_VOLUME_TAG 0xb6
#define READ_DEFECT_DATA_12 0xb7
#define SET_CD_SPEED 0xbb
#define MECHANISM_STATUS 0xbd
#define READ_CD 0xbe
/*
* SERVICE ACTION IN subcodes
@ -188,3 +191,90 @@
#define TYPE_INACTIVE 0x20
#define TYPE_NO_LUN 0x7f
/* Mode page codes for mode sense/set */
#define MODE_PAGE_R_W_ERROR 0x01
#define MODE_PAGE_HD_GEOMETRY 0x04
#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY 0x05
#define MODE_PAGE_CACHING 0x08
#define MODE_PAGE_AUDIO_CTL 0x0e
#define MODE_PAGE_POWER 0x1a
#define MODE_PAGE_FAULT_FAIL 0x1c
#define MODE_PAGE_TO_PROTECT 0x1d
#define MODE_PAGE_CAPABILITIES 0x2a
#define MODE_PAGE_ALLS 0x3f
/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
* of MODE_PAGE_SENSE_POWER */
#define MODE_PAGE_CDROM 0x0d
/* Event notification classes for GET EVENT STATUS NOTIFICATION */
#define GESN_NO_EVENTS 0
#define GESN_OPERATIONAL_CHANGE 1
#define GESN_POWER_MANAGEMENT 2
#define GESN_EXTERNAL_REQUEST 3
#define GESN_MEDIA 4
#define GESN_MULTIPLE_HOSTS 5
#define GESN_DEVICE_BUSY 6
/* Event codes for MEDIA event status notification */
#define MEC_NO_CHANGE 0
#define MEC_EJECT_REQUESTED 1
#define MEC_NEW_MEDIA 2
#define MEC_MEDIA_REMOVAL 3 /* only for media changers */
#define MEC_MEDIA_CHANGED 4 /* only for media changers */
#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */
#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */
#define MS_TRAY_OPEN 1
#define MS_MEDIA_PRESENT 2
/*
* Based on values from <linux/cdrom.h> but extending CD_MINS
* to the maximum common size allowed by the Orange's Book ATIP
*
* 90 and 99 min CDs are also available but using them as the
* upper limit reduces the effectiveness of the heuristic to
* detect DVDs burned to less than 25% of their maximum capacity
*/
/* Some generally useful CD-ROM information */
#define CD_MINS 80 /* max. minutes per CD */
#define CD_SECS 60 /* seconds per minute */
#define CD_FRAMES 75 /* frames per second */
#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */
#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
#define CD_MAX_SECTORS (CD_MAX_BYTES / 512)
/*
* The MMC values are not IDE specific and might need to be moved
* to a common header if they are also needed for the SCSI emulation
*/
/* Profile list from MMC-6 revision 1 table 91 */
#define MMC_PROFILE_NONE 0x0000
#define MMC_PROFILE_CD_ROM 0x0008
#define MMC_PROFILE_CD_R 0x0009
#define MMC_PROFILE_CD_RW 0x000A
#define MMC_PROFILE_DVD_ROM 0x0010
#define MMC_PROFILE_DVD_R_SR 0x0011
#define MMC_PROFILE_DVD_RAM 0x0012
#define MMC_PROFILE_DVD_RW_RO 0x0013
#define MMC_PROFILE_DVD_RW_SR 0x0014
#define MMC_PROFILE_DVD_R_DL_SR 0x0015
#define MMC_PROFILE_DVD_R_DL_JR 0x0016
#define MMC_PROFILE_DVD_RW_DL 0x0017
#define MMC_PROFILE_DVD_DDR 0x0018
#define MMC_PROFILE_DVD_PLUS_RW 0x001A
#define MMC_PROFILE_DVD_PLUS_R 0x001B
#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A
#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B
#define MMC_PROFILE_BD_ROM 0x0040
#define MMC_PROFILE_BD_R_SRM 0x0041
#define MMC_PROFILE_BD_R_RRM 0x0042
#define MMC_PROFILE_BD_RE 0x0043
#define MMC_PROFILE_HDDVD_ROM 0x0050
#define MMC_PROFILE_HDDVD_R 0x0051
#define MMC_PROFILE_HDDVD_RAM 0x0052
#define MMC_PROFILE_HDDVD_RW 0x0053
#define MMC_PROFILE_HDDVD_R_DL 0x0058
#define MMC_PROFILE_HDDVD_RW_DL 0x005A
#define MMC_PROFILE_INVALID 0xFFFF

File diff suppressed because it is too large Load Diff

View File

@ -39,15 +39,18 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#define SCSI_SENSE_BUF_SIZE 96
#define SG_ERR_DRIVER_TIMEOUT 0x06
#define SG_ERR_DRIVER_SENSE 0x08
#define SG_ERR_DRIVER_TIMEOUT 0x06
#define SG_ERR_DRIVER_SENSE 0x08
#define SG_ERR_DID_OK 0x00
#define SG_ERR_DID_NO_CONNECT 0x01
#define SG_ERR_DID_BUS_BUSY 0x02
#define SG_ERR_DID_TIME_OUT 0x03
#ifndef MAX_UINT
#define MAX_UINT ((unsigned int)-1)
#endif
typedef struct SCSIGenericState SCSIGenericState;
typedef struct SCSIGenericReq {
SCSIRequest req;
uint8_t *buf;
@ -56,12 +59,6 @@ typedef struct SCSIGenericReq {
sg_io_hdr_t io_header;
} SCSIGenericReq;
struct SCSIGenericState
{
SCSIDevice qdev;
BlockDriverState *bs;
};
static void scsi_free_request(SCSIRequest *req)
{
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
@ -76,8 +73,9 @@ static void scsi_command_complete(void *opaque, int ret)
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
r->req.aiocb = NULL;
if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE)
if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
r->req.sense_len = r->io_header.sb_len_wr;
}
if (ret != 0) {
switch (ret) {
@ -94,9 +92,15 @@ static void scsi_command_complete(void *opaque, int ret)
break;
}
} else {
if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
(r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
status = BUSY;
BADF("Driver Timeout\n");
} else if (r->io_header.host_status) {
status = CHECK_CONDITION;
scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
} else if (r->io_header.status) {
status = r->io_header.status;
} else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
@ -109,6 +113,9 @@ static void scsi_command_complete(void *opaque, int ret)
r, r->req.tag, status);
scsi_req_complete(&r->req, status);
if (!r->req.io_canceled) {
scsi_req_unref(&r->req);
}
}
/* Cancel a pending data transfer. */
@ -119,6 +126,11 @@ static void scsi_cancel_io(SCSIRequest *req)
DPRINTF("Cancel tag=0x%x\n", req->tag);
if (r->req.aiocb) {
bdrv_aio_cancel(r->req.aiocb);
/* This reference was left in by scsi_*_data. We take ownership of
* it independent of whether bdrv_aio_cancel completes the request
* or not. */
scsi_req_unref(&r->req);
}
r->req.aiocb = NULL;
}
@ -151,6 +163,7 @@ static int execute_command(BlockDriverState *bdrv,
static void scsi_read_complete(void * opaque, int ret)
{
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
SCSIDevice *s = r->req.dev;
int len;
r->req.aiocb = NULL;
@ -166,7 +179,21 @@ static void scsi_read_complete(void * opaque, int ret)
if (len == 0) {
scsi_command_complete(r, 0);
} else {
/* Snoop READ CAPACITY output to set the blocksize. */
if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
s->blocksize = ldl_be_p(&r->buf[4]);
s->max_lba = ldl_be_p(&r->buf[0]);
} else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
(r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
s->blocksize = ldl_be_p(&r->buf[8]);
s->max_lba = ldq_be_p(&r->buf[0]);
}
bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
scsi_req_data(&r->req, len);
if (!r->req.io_canceled) {
scsi_req_unref(&r->req);
}
}
}
@ -174,26 +201,28 @@ static void scsi_read_complete(void * opaque, int ret)
static void scsi_read_data(SCSIRequest *req)
{
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
SCSIDevice *s = r->req.dev;
int ret;
DPRINTF("scsi_read_data 0x%x\n", req->tag);
/* The request is used as the AIO opaque value, so add a ref. */
scsi_req_ref(&r->req);
if (r->len == -1) {
scsi_command_complete(r, 0);
return;
}
ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
return;
}
}
static void scsi_write_complete(void * opaque, int ret)
{
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
SCSIDevice *s = r->req.dev;
DPRINTF("scsi_write_complete() ret = %d\n", ret);
r->req.aiocb = NULL;
@ -204,9 +233,9 @@ static void scsi_write_complete(void * opaque, int ret)
}
if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
s->qdev.type == TYPE_TAPE) {
s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
DPRINTF("block size %d\n", s->qdev.blocksize);
s->type == TYPE_TAPE) {
s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
DPRINTF("block size %d\n", s->blocksize);
}
scsi_command_complete(r, ret);
@ -216,8 +245,8 @@ static void scsi_write_complete(void * opaque, int ret)
The transfer may complete asynchronously. */
static void scsi_write_data(SCSIRequest *req)
{
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
SCSIDevice *s = r->req.dev;
int ret;
DPRINTF("scsi_write_data 0x%x\n", req->tag);
@ -227,7 +256,9 @@ static void scsi_write_data(SCSIRequest *req)
return;
}
ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
/* The request is used as the AIO opaque value, so add a ref. */
scsi_req_ref(&r->req);
ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
}
@ -241,19 +272,6 @@ static uint8_t *scsi_get_buf(SCSIRequest *req)
return r->buf;
}
static void scsi_req_fixup(SCSIRequest *req)
{
switch(req->cmd.buf[0]) {
case REWIND:
case START_STOP:
if (req->dev->type == TYPE_TAPE) {
/* force IMMED, otherwise qemu waits end of command */
req->cmd.buf[1] = 0x01;
}
break;
}
}
/* Execute a scsi command. Returns the length of the data expected by the
command. This will be Positive for data transfers from the device
(eg. disk reads), negative for transfers to the device (eg. disk writes),
@ -261,12 +279,10 @@ static void scsi_req_fixup(SCSIRequest *req)
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
{
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
SCSIDevice *s = r->req.dev;
int ret;
scsi_req_fixup(&r->req);
DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
r->req.cmd.xfer, cmd[0]);
@ -285,7 +301,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
g_free(r->buf);
r->buflen = 0;
r->buf = NULL;
ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
/* The request is used as the AIO opaque value, so add a ref. */
scsi_req_ref(&r->req);
ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
return 0;
@ -310,36 +328,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
}
}
static int get_blocksize(BlockDriverState *bdrv)
{
uint8_t cmd[10];
uint8_t buf[8];
uint8_t sensebuf[8];
sg_io_hdr_t io_header;
int ret;
memset(cmd, 0, sizeof(cmd));
memset(buf, 0, sizeof(buf));
cmd[0] = READ_CAPACITY_10;
memset(&io_header, 0, sizeof(io_header));
io_header.interface_id = 'S';
io_header.dxfer_direction = SG_DXFER_FROM_DEV;
io_header.dxfer_len = sizeof(buf);
io_header.dxferp = buf;
io_header.cmdp = cmd;
io_header.cmd_len = sizeof(cmd);
io_header.mx_sb_len = sizeof(sensebuf);
io_header.sbp = sensebuf;
io_header.timeout = 6000; /* XXX */
ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
if (ret < 0)
return -1;
return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
}
static int get_stream_blocksize(BlockDriverState *bdrv)
{
uint8_t cmd[6];
@ -365,89 +353,92 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
io_header.timeout = 6000; /* XXX */
ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
if (ret < 0)
if (ret < 0 || io_header.driver_status || io_header.host_status) {
return -1;
}
return (buf[9] << 16) | (buf[10] << 8) | buf[11];
}
static void scsi_generic_reset(DeviceState *dev)
{
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
scsi_device_purge_requests(s, SENSE_CODE(RESET));
}
static void scsi_destroy(SCSIDevice *d)
static void scsi_destroy(SCSIDevice *s)
{
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
blockdev_mark_auto_del(s->qdev.conf.bs);
scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
blockdev_mark_auto_del(s->conf.bs);
}
static int scsi_generic_initfn(SCSIDevice *dev)
static int scsi_generic_initfn(SCSIDevice *s)
{
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
int sg_version;
struct sg_scsi_id scsiid;
if (!s->qdev.conf.bs) {
if (!s->conf.bs) {
error_report("scsi-generic: drive property not set");
return -1;
}
s->bs = s->qdev.conf.bs;
/* check we are really using a /dev/sg* file */
if (!bdrv_is_sg(s->bs)) {
if (!bdrv_is_sg(s->conf.bs)) {
error_report("scsi-generic: not /dev/sg*");
return -1;
}
if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
error_report("Device doesn't support drive option werror");
return -1;
}
if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
error_report("Device doesn't support drive option rerror");
return -1;
}
/* check we are using a driver managing SG_IO (version 3 and after */
if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
sg_version < 30000) {
error_report("scsi-generic: scsi generic interface too old");
return -1;
}
/* get LUN of the /dev/sg? */
if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
return -1;
}
/* define device state */
s->qdev.type = scsiid.scsi_type;
DPRINTF("device type %d\n", s->qdev.type);
if (s->qdev.type == TYPE_TAPE) {
s->qdev.blocksize = get_stream_blocksize(s->bs);
if (s->qdev.blocksize == -1)
s->qdev.blocksize = 0;
} else {
s->qdev.blocksize = get_blocksize(s->bs);
/* removable media returns 0 if not present */
if (s->qdev.blocksize <= 0) {
if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM)
s->qdev.blocksize = 2048;
else
s->qdev.blocksize = 512;
s->type = scsiid.scsi_type;
DPRINTF("device type %d\n", s->type);
switch (s->type) {
case TYPE_TAPE:
s->blocksize = get_stream_blocksize(s->conf.bs);
if (s->blocksize == -1) {
s->blocksize = 0;
}
break;
/* Make a guess for block devices, we'll fix it when the guest sends.
* READ CAPACITY. If they don't, they likely would assume these sizes
* anyway. (TODO: they could also send MODE SENSE).
*/
case TYPE_ROM:
case TYPE_WORM:
s->blocksize = 2048;
break;
default:
s->blocksize = 512;
break;
}
DPRINTF("block size %d\n", s->qdev.blocksize);
DPRINTF("block size %d\n", s->blocksize);
return 0;
}
static SCSIReqOps scsi_generic_req_ops = {
const SCSIReqOps scsi_generic_req_ops = {
.size = sizeof(SCSIGenericReq),
.free_req = scsi_free_request,
.send_command = scsi_send_command,
@ -458,7 +449,7 @@ static SCSIReqOps scsi_generic_req_ops = {
};
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
void *hba_private)
uint8_t *buf, void *hba_private)
{
SCSIRequest *req;
@ -469,13 +460,13 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
static SCSIDeviceInfo scsi_generic_info = {
.qdev.name = "scsi-generic",
.qdev.desc = "pass through generic scsi device (/dev/sg*)",
.qdev.size = sizeof(SCSIGenericState),
.qdev.size = sizeof(SCSIDevice),
.qdev.reset = scsi_generic_reset,
.init = scsi_generic_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.qdev.props = (Property[]) {
DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
DEFINE_PROP_END_OF_LIST(),
},
};

View File

@ -3,13 +3,14 @@
#include "qdev.h"
#include "block.h"
#include "sysemu.h"
#define MAX_SCSI_DEVS 255
#define SCSI_CMD_BUF_SIZE 16
typedef struct SCSIBus SCSIBus;
typedef struct SCSIBusOps SCSIBusOps;
typedef struct SCSIBusInfo SCSIBusInfo;
typedef struct SCSICommand SCSICommand;
typedef struct SCSIDevice SCSIDevice;
typedef struct SCSIDeviceInfo SCSIDeviceInfo;
@ -41,7 +42,7 @@ struct SCSICommand {
struct SCSIRequest {
SCSIBus *bus;
SCSIDevice *dev;
SCSIReqOps *ops;
const SCSIReqOps *ops;
uint32_t refcount;
uint32_t tag;
uint32_t lun;
@ -51,6 +52,8 @@ struct SCSIRequest {
uint8_t sense[SCSI_SENSE_BUF_SIZE];
uint32_t sense_len;
bool enqueued;
bool io_canceled;
bool retry;
void *hba_private;
QTAILQ_ENTRY(SCSIRequest) next;
};
@ -58,16 +61,21 @@ struct SCSIRequest {
struct SCSIDevice
{
DeviceState qdev;
VMChangeStateEntry *vmsentry;
QEMUBH *bh;
uint32_t id;
BlockConf conf;
SCSIDeviceInfo *info;
SCSISense unit_attention;
bool sense_is_ua;
uint8_t sense[SCSI_SENSE_BUF_SIZE];
uint32_t sense_len;
QTAILQ_HEAD(, SCSIRequest) requests;
uint32_t channel;
uint32_t lun;
int blocksize;
int type;
uint64_t max_lba;
};
/* cdrom.c */
@ -91,11 +99,13 @@ struct SCSIDeviceInfo {
scsi_qdev_initfn init;
void (*destroy)(SCSIDevice *s);
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
void *hba_private);
SCSIReqOps reqops;
uint8_t *buf, void *hba_private);
void (*unit_attention_reported)(SCSIDevice *s);
};
struct SCSIBusOps {
struct SCSIBusInfo {
int tcq;
int max_channel, max_target, max_lun;
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*complete)(SCSIRequest *req, uint32_t arg);
void (*cancel)(SCSIRequest *req);
@ -106,14 +116,10 @@ struct SCSIBus {
int busnr;
SCSISense unit_attention;
int tcq, ndev;
const SCSIBusOps *ops;
SCSIDevice *devs[MAX_SCSI_DEVS];
const SCSIBusInfo *info;
};
void scsi_bus_new(SCSIBus *bus, DeviceState *host, int tcq, int ndev,
const SCSIBusOps *ops);
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
void scsi_qdev_register(SCSIDeviceInfo *info);
static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
@ -159,6 +165,8 @@ extern const struct SCSISense sense_code_IO_ERROR;
extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
/* Command aborted, Logical Unit failure */
extern const struct SCSISense sense_code_LUN_FAILURE;
/* LUN not ready, Medium not present */
extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
/* Unit attention, Power on, reset or bus device reset occurred */
extern const struct SCSISense sense_code_RESET;
/* Unit attention, Medium may have changed*/
@ -172,8 +180,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
int scsi_sense_valid(SCSISense sense);
SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag,
uint32_t lun, void *hba_private);
SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
uint32_t tag, uint32_t lun, void *hba_private);
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
uint8_t *buf, void *hba_private);
int32_t scsi_req_enqueue(SCSIRequest *req);
@ -190,7 +198,12 @@ uint8_t *scsi_req_get_buf(SCSIRequest *req);
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
void scsi_req_abort(SCSIRequest *req, int status);
void scsi_req_cancel(SCSIRequest *req);
void scsi_req_retry(SCSIRequest *req);
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
/* scsi-generic.c. */
extern const SCSIReqOps scsi_generic_req_ops;
#endif

View File

@ -63,7 +63,7 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
DeviceState *qdev;
VIOsPAPRDevice *dev = NULL;
QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
dev = (VIOsPAPRDevice *)qdev;
if (dev->reg == reg) {
break;
@ -588,7 +588,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
return;
}
QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
dev = (VIOsPAPRDevice *)qdev;
spapr_vio_quiesce_one(dev);
}
@ -726,7 +726,7 @@ int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
DeviceState *qdev;
int ret = 0;
QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
ret = vio_make_devnode(dev, fdt);

View File

@ -129,11 +129,38 @@ static void vscsi_put_req(vscsi_req *req)
req->active = 0;
}
static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
{
/* XXX Figure that one out properly ! This is crackpot */
*id = (srp_lun >> 56) & 0x7f;
*lun = (srp_lun >> 48) & 0xff;
int channel = 0, id = 0;
retry:
switch (srp_lun >> 62) {
case 0:
if ((srp_lun >> 56) != 0) {
channel = (srp_lun >> 56) & 0x3f;
id = (srp_lun >> 48) & 0xff;
srp_lun <<= 16;
goto retry;
}
*lun = (srp_lun >> 48) & 0xff;
break;
case 1:
*lun = (srp_lun >> 48) & 0x3fff;
break;
case 2:
channel = (srp_lun >> 53) & 0x7;
id = (srp_lun >> 56) & 0x3f;
*lun = (srp_lun >> 48) & 0x1f;
break;
case 3:
*lun = -1;
return NULL;
default:
abort();
}
return scsi_device_find(bus, channel, id, *lun);
}
static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
@ -582,14 +609,11 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
{
union srp_iu *srp = &req->iu.srp;
SCSIDevice *sdev;
int n, id, lun;
int n, lun;
vscsi_decode_id_lun(be64_to_cpu(srp->cmd.lun), &id, &lun);
/* Qemu vs. linux issue with LUNs to be sorted out ... */
sdev = (id < 8 && lun < 16) ? s->bus.devs[id] : NULL;
sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
if (!sdev) {
dprintf("VSCSI: Command for id %d with no drive\n", id);
dprintf("VSCSI: Command for lun %08" PRIx64 " with no drive\n", be64_to_cpu(srp->cmd.lun));
if (srp->cmd.cdb[0] == INQUIRY) {
vscsi_inquiry_no_target(s, req);
} else {
@ -862,7 +886,12 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
return 0;
}
static const struct SCSIBusOps vscsi_scsi_ops = {
static const struct SCSIBusInfo vscsi_scsi_info = {
.tcq = true,
.max_channel = 7, /* logical unit addressing format */
.max_target = 63,
.max_lun = 31,
.transfer_data = vscsi_transfer_data,
.complete = vscsi_command_complete,
.cancel = vscsi_request_cancelled
@ -883,8 +912,7 @@ static int spapr_vscsi_init(VIOsPAPRDevice *dev)
dev->crq.SendFunc = vscsi_do_crq;
scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT,
&vscsi_scsi_ops);
scsi_bus_new(&s->bus, &dev->qdev, &vscsi_scsi_info);
if (!dev->qdev.hotplugged) {
scsi_bus_legacy_handle_cmdline(&s->bus);
}

View File

@ -25,8 +25,8 @@ static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
SSIBus *bus;
bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
if (QLIST_FIRST(&bus->qbus.children) != dev
|| QLIST_NEXT(dev, sibling) != NULL) {
if (QTAILQ_FIRST(&bus->qbus.children) != dev
|| QTAILQ_NEXT(dev, sibling) != NULL) {
hw_error("Too many devices on SSI bus");
}
@ -61,7 +61,7 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
{
DeviceState *dev;
SSISlave *slave;
dev = QLIST_FIRST(&bus->qbus.children);
dev = QTAILQ_FIRST(&bus->qbus.children);
if (!dev) {
return 0;
}

View File

@ -495,7 +495,11 @@ static void usb_msd_password_cb(void *opaque, int err)
qdev_unplug(&s->dev.qdev);
}
static const struct SCSIBusOps usb_msd_scsi_ops = {
static const struct SCSIBusInfo usb_msd_scsi_info = {
.tcq = false,
.max_target = 0,
.max_lun = 0,
.transfer_data = usb_msd_transfer_data,
.complete = usb_msd_command_complete,
.cancel = usb_msd_request_cancelled
@ -536,7 +540,7 @@ static int usb_msd_initfn(USBDevice *dev)
}
usb_desc_init(dev);
scsi_bus_new(&s->bus, &s->dev.qdev, 0, 1, &usb_msd_scsi_ops);
scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info);
s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable);
if (!s->scsi_dev) {
return -1;

View File

@ -1582,7 +1582,7 @@ static const cmdinfo_t map_cmd = {
static int close_f(int argc, char **argv)
{
bdrv_close(bs);
bdrv_delete(bs);
bs = NULL;
return 0;
}
@ -1611,6 +1611,7 @@ static int openfile(char *name, int flags, int growable)
if (bdrv_open(bs, name, flags, NULL) < 0) {
fprintf(stderr, "%s: can't open device %s\n", progname, name);
bdrv_delete(bs);
bs = NULL;
return 1;
}
@ -1834,7 +1835,7 @@ int main(int argc, char **argv)
qemu_aio_flush();
if (bs) {
bdrv_close(bs);
bdrv_delete(bs);
}
return 0;
}

View File

@ -148,6 +148,9 @@ Define a new drive. Valid options are:
This option defines which disk image (@pxref{disk_images}) to use with
this drive. If the filename contains comma, you must double it
(for instance, "file=my,,file" to use file "my,file").
Special files such as iSCSI devices can be specified using protocol
specific URLs. See the section for "Device URL Syntax" for more information.
@item if=@var{interface}
This option defines on which type on interface the drive is connected.
Available types are: ide, scsi, sd, mtd, floppy, pflash, virtio.
@ -1733,6 +1736,93 @@ ETEXI
DEFHEADING()
STEXI
DEFHEADING(Device URL Syntax:)
In addition to using normal file images for the emulated storage devices,
QEMU can also use networked resources such as iSCSI devices. These are
specified using a special URL syntax.
@table @option
@item iSCSI
iSCSI support allows QEMU to access iSCSI resources directly and use as
images for the guest storage. Both disk and cdrom images are supported.
Syntax for specifying iSCSI LUNs is
``iscsi://<target-ip>[:<port>]/<target-iqn>/<lun>''
Example (without authentication):
@example
qemu -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
--drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
@end example
Example (CHAP username/password via URL):
@example
qemu --drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
@end example
Example (CHAP username/password via environment variables):
@example
LIBISCSI_CHAP_USERNAME="user" \
LIBISCSI_CHAP_PASSWORD="password" \
qemu --drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
@end example
iSCSI support is an optional feature of QEMU and only available when
compiled and linked against libiscsi.
@item NBD
QEMU supports NBD (Network Block Devices) both using TCP protocol as well
as Unix Domain Sockets.
Syntax for specifying a NBD device using TCP
``nbd:<server-ip>:<port>[:exportname=<export>]''
Syntax for specifying a NBD device using Unix Domain Sockets
``nbd:unix:<domain-socket>[:exportname=<export>]''
Example for TCP
@example
qemu --drive file=nbd:192.0.2.1:30000
@end example
Example for Unix Domain Sockets
@example
qemu --drive file=nbd:unix:/tmp/nbd-socket
@end example
@item Sheepdog
Sheepdog is a distributed storage system for QEMU.
QEMU supports using either local sheepdog devices or remote networked
devices.
Syntax for specifying a sheepdog device
@table @list
``sheepdog:<vdiname>''
``sheepdog:<vdiname>:<snapid>''
``sheepdog:<vdiname>:<tag>''
``sheepdog:<host>:<port>:<vdiname>''
``sheepdog:<host>:<port>:<vdiname>:<snapid>''
``sheepdog:<host>:<port>:<vdiname>:<tag>''
@end table
Example
@example
qemu --drive file=sheepdog:192.0.2.1:30000:MyVirtualMachine
@end example
See also @url{http://http://www.osrg.net/sheepdog/}.
@end table
ETEXI
DEFHEADING(Bluetooth(R) options:)
DEF("bt", HAS_ARG, QEMU_OPTION_bt, \

View File

@ -278,6 +278,7 @@ usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
# hw/scsi-bus.c
scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
@ -505,6 +506,12 @@ escc_sunkbd_event_out(int ch) "Translated keycode %2.2x"
escc_kbd_command(int val) "Command %d"
escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x"
# block/iscsi.c
iscsi_aio_write10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
iscsi_aio_writev(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
iscsi_aio_read10_cb(void *iscsi, int status, void *acb, int canceled) "iscsi %p status %d acb %p canceled %d"
iscsi_aio_readv(void *iscsi, int64_t sector_num, int nb_sectors, void *opaque, void *acb) "iscsi %p sector_num %"PRId64" nb_sectors %d opaque %p acb %p"
# hw/esp.c
esp_raise_irq(void) "Raise IRQ"
esp_lower_irq(void) "Lower IRQ"