mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/bonzini/scsi-next' into staging
* remotes/bonzini/scsi-next:
virtio-scsi: define dummy handle_output for vhost-scsi vqs
block/iscsi: drop obsolete pointers from iscsi_co_writev
block/iscsi: fix init value for iTask->retries
block/iscsi: bump libiscsi requirement to 1.9.0
virtio-scsi: add support for the any_layout feature
virtio-scsi: introduce virtio_scsi_complete_cmd_req
virtio-scsi: prepare sense data handling for any_layout
virtio-scsi: add extra argument and return type to qemu_sgl_concat
virtio-scsi: add target swap for VirtIOSCSICtrlTMFReq fields
virtio-scsi: start preparing for any_layout
util: add return value to qemu_iovec_concat_iov
megasas: use PCI DMA API
scsi: Print command name in debug
scsi-disk: fix bug in scsi_block_new_request() introduced by commit 137745c
scsi-disk.c: Fix compilation with -DDEBUG_SCSI
block/iscsi: use 16 byte CDBs only when necessary
block/iscsi: fix potential segfault on early callback
block/iscsi: handle BUSY condition
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+86
-103
@@ -26,6 +26,7 @@
|
||||
#include "config-host.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include <math.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/config-file.h"
|
||||
@@ -64,6 +65,7 @@ typedef struct IscsiLun {
|
||||
unsigned char *zeroblock;
|
||||
unsigned long *allocationmap;
|
||||
int cluster_sectors;
|
||||
bool use_16_for_rw;
|
||||
} IscsiLun;
|
||||
|
||||
typedef struct IscsiTask {
|
||||
@@ -75,6 +77,7 @@ typedef struct IscsiTask {
|
||||
Coroutine *co;
|
||||
QEMUBH *bh;
|
||||
IscsiLun *iscsilun;
|
||||
QEMUTimer retry_timer;
|
||||
} IscsiTask;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
@@ -86,7 +89,6 @@ typedef struct IscsiAIOCB {
|
||||
uint8_t *buf;
|
||||
int status;
|
||||
int canceled;
|
||||
int retries;
|
||||
int64_t sector_num;
|
||||
int nb_sectors;
|
||||
#ifdef __linux__
|
||||
@@ -96,7 +98,8 @@ typedef struct IscsiAIOCB {
|
||||
|
||||
#define NOP_INTERVAL 5000
|
||||
#define MAX_NOP_FAILURES 3
|
||||
#define ISCSI_CMD_RETRIES 5
|
||||
#define ISCSI_CMD_RETRIES ARRAY_SIZE(iscsi_retry_times)
|
||||
static const unsigned iscsi_retry_times[] = {8, 32, 128, 512, 2048};
|
||||
|
||||
/* this threshhold is a trade-off knob to choose between
|
||||
* the potential additional overhead of an extra GET_LBA_STATUS request
|
||||
@@ -142,10 +145,25 @@ iscsi_schedule_bh(IscsiAIOCB *acb)
|
||||
static void iscsi_co_generic_bh_cb(void *opaque)
|
||||
{
|
||||
struct IscsiTask *iTask = opaque;
|
||||
iTask->complete = 1;
|
||||
qemu_bh_delete(iTask->bh);
|
||||
qemu_coroutine_enter(iTask->co, NULL);
|
||||
}
|
||||
|
||||
static void iscsi_retry_timer_expired(void *opaque)
|
||||
{
|
||||
struct IscsiTask *iTask = opaque;
|
||||
iTask->complete = 1;
|
||||
if (iTask->co) {
|
||||
qemu_coroutine_enter(iTask->co, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned exp_random(double mean)
|
||||
{
|
||||
return -mean * log((double)rand() / RAND_MAX);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
@@ -153,19 +171,34 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
struct IscsiTask *iTask = opaque;
|
||||
struct scsi_task *task = command_data;
|
||||
|
||||
iTask->complete = 1;
|
||||
iTask->status = status;
|
||||
iTask->do_retry = 0;
|
||||
iTask->task = task;
|
||||
|
||||
if (iTask->retries-- > 0 && status == SCSI_STATUS_CHECK_CONDITION
|
||||
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION) {
|
||||
error_report("iSCSI CheckCondition: %s", iscsi_get_error(iscsi));
|
||||
iTask->do_retry = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (status != SCSI_STATUS_GOOD) {
|
||||
if (iTask->retries++ < ISCSI_CMD_RETRIES) {
|
||||
if (status == SCSI_STATUS_CHECK_CONDITION
|
||||
&& task->sense.key == SCSI_SENSE_UNIT_ATTENTION) {
|
||||
error_report("iSCSI CheckCondition: %s",
|
||||
iscsi_get_error(iscsi));
|
||||
iTask->do_retry = 1;
|
||||
goto out;
|
||||
}
|
||||
if (status == SCSI_STATUS_BUSY) {
|
||||
unsigned retry_time =
|
||||
exp_random(iscsi_retry_times[iTask->retries - 1]);
|
||||
error_report("iSCSI Busy (retry #%u in %u ms): %s",
|
||||
iTask->retries, retry_time,
|
||||
iscsi_get_error(iscsi));
|
||||
aio_timer_init(iTask->iscsilun->aio_context,
|
||||
&iTask->retry_timer, QEMU_CLOCK_REALTIME,
|
||||
SCALE_MS, iscsi_retry_timer_expired, iTask);
|
||||
timer_mod(&iTask->retry_timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + retry_time);
|
||||
iTask->do_retry = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
error_report("iSCSI Failure: %s", iscsi_get_error(iscsi));
|
||||
}
|
||||
|
||||
@@ -174,15 +207,16 @@ out:
|
||||
iTask->bh = aio_bh_new(iTask->iscsilun->aio_context,
|
||||
iscsi_co_generic_bh_cb, iTask);
|
||||
qemu_bh_schedule(iTask->bh);
|
||||
} else {
|
||||
iTask->complete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void iscsi_co_init_iscsitask(IscsiLun *iscsilun, struct IscsiTask *iTask)
|
||||
{
|
||||
*iTask = (struct IscsiTask) {
|
||||
.co = qemu_coroutine_self(),
|
||||
.retries = ISCSI_CMD_RETRIES,
|
||||
.iscsilun = iscsilun,
|
||||
.co = qemu_coroutine_self(),
|
||||
.iscsilun = iscsilun,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -325,8 +359,6 @@ static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
uint32_t num_sectors;
|
||||
uint8_t *data = NULL;
|
||||
uint8_t *buf = NULL;
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
return -EINVAL;
|
||||
@@ -334,31 +366,24 @@ static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
/* if the iovec only contains one buffer we can pass it directly */
|
||||
if (iov->niov == 1) {
|
||||
data = iov->iov[0].iov_base;
|
||||
} else {
|
||||
size_t size = MIN(nb_sectors * BDRV_SECTOR_SIZE, iov->size);
|
||||
buf = g_malloc(size);
|
||||
qemu_iovec_to_buf(iov, 0, buf, size);
|
||||
data = buf;
|
||||
}
|
||||
#endif
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
data, num_sectors * iscsilun->block_size,
|
||||
iscsilun->block_size, 0, 0, 0, 0, 0,
|
||||
iscsi_co_generic_cb, &iTask);
|
||||
if (iscsilun->use_16_for_rw) {
|
||||
iTask.task = iscsi_write16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
NULL, num_sectors * iscsilun->block_size,
|
||||
iscsilun->block_size, 0, 0, 0, 0, 0,
|
||||
iscsi_co_generic_cb, &iTask);
|
||||
} else {
|
||||
iTask.task = iscsi_write10_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
NULL, num_sectors * iscsilun->block_size,
|
||||
iscsilun->block_size, 0, 0, 0, 0, 0,
|
||||
iscsi_co_generic_cb, &iTask);
|
||||
}
|
||||
if (iTask.task == NULL) {
|
||||
g_free(buf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
scsi_task_set_iov_out(iTask.task, (struct scsi_iovec *) iov->iov,
|
||||
iov->niov);
|
||||
#endif
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
@@ -374,8 +399,6 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
|
||||
g_free(buf);
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
return -EIO;
|
||||
}
|
||||
@@ -386,7 +409,6 @@ retry:
|
||||
}
|
||||
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
@@ -496,9 +518,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* LIBISCSI_FEATURE_IOVECTOR */
|
||||
|
||||
|
||||
static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
@@ -507,15 +526,11 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
uint32_t num_sectors;
|
||||
#if !defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
int i;
|
||||
#endif
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
if (iscsilun->lbprz && nb_sectors >= ISCSI_CHECKALLOC_THRES &&
|
||||
!iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
|
||||
int64_t ret;
|
||||
@@ -529,42 +544,28 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
switch (iscsilun->type) {
|
||||
case TYPE_DISK:
|
||||
if (iscsilun->use_16_for_rw) {
|
||||
iTask.task = iscsi_read16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
num_sectors * iscsilun->block_size,
|
||||
iscsilun->block_size, 0, 0, 0, 0, 0,
|
||||
iscsi_co_generic_cb, &iTask);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
iTask.task = iscsi_read10_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
num_sectors * iscsilun->block_size,
|
||||
iscsilun->block_size,
|
||||
#if !defined(CONFIG_LIBISCSI_1_4) /* API change from 1.4.0 to 1.5.0 */
|
||||
0, 0, 0, 0, 0,
|
||||
#endif
|
||||
iscsi_co_generic_cb, &iTask);
|
||||
break;
|
||||
}
|
||||
if (iTask.task == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
scsi_task_set_iov_in(iTask.task, (struct scsi_iovec *) iov->iov, iov->niov);
|
||||
#else
|
||||
for (i = 0; i < iov->niov; i++) {
|
||||
scsi_task_add_data_in_buffer(iTask.task,
|
||||
iov->iov[i].iov_len,
|
||||
iov->iov[i].iov_base);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
@@ -719,18 +720,9 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
||||
data.data = acb->ioh->dxferp;
|
||||
data.size = acb->ioh->dxfer_len;
|
||||
} else {
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
scsi_task_set_iov_out(acb->task,
|
||||
(struct scsi_iovec *) acb->ioh->dxferp,
|
||||
acb->ioh->iovec_count);
|
||||
#else
|
||||
struct iovec *iov = (struct iovec *)acb->ioh->dxferp;
|
||||
|
||||
acb->buf = g_malloc(acb->ioh->dxfer_len);
|
||||
data.data = acb->buf;
|
||||
data.size = iov_to_buf(iov, acb->ioh->iovec_count, 0,
|
||||
acb->buf, acb->ioh->dxfer_len);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,20 +742,9 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
||||
acb->ioh->dxfer_len,
|
||||
acb->ioh->dxferp);
|
||||
} else {
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
scsi_task_set_iov_in(acb->task,
|
||||
(struct scsi_iovec *) acb->ioh->dxferp,
|
||||
acb->ioh->iovec_count);
|
||||
#else
|
||||
int i;
|
||||
for (i = 0; i < acb->ioh->iovec_count; i++) {
|
||||
struct iovec *iov = (struct iovec *)acb->ioh->dxferp;
|
||||
|
||||
scsi_task_add_data_in_buffer(acb->task,
|
||||
iov[i].iov_len,
|
||||
iov[i].iov_base);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,7 +753,6 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
|
||||
static void ioctl_cb(void *opaque, int status)
|
||||
{
|
||||
int *p_status = opaque;
|
||||
@@ -877,8 +857,6 @@ retry:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED)
|
||||
|
||||
static int
|
||||
coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags)
|
||||
@@ -887,19 +865,27 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
struct IscsiTask iTask;
|
||||
uint64_t lba;
|
||||
uint32_t nb_blocks;
|
||||
bool use_16_for_ws = iscsilun->use_16_for_rw;
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||
/* WRITE SAME with UNMAP is not supported by the target,
|
||||
* fall back and try WRITE SAME without UNMAP */
|
||||
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||
if (flags & BDRV_REQ_MAY_UNMAP) {
|
||||
if (!use_16_for_ws && !iscsilun->lbp.lbpws10) {
|
||||
/* WRITESAME10 with UNMAP is unsupported try WRITESAME16 */
|
||||
use_16_for_ws = true;
|
||||
}
|
||||
if (use_16_for_ws && !iscsilun->lbp.lbpws) {
|
||||
/* WRITESAME16 with UNMAP is not supported by the target,
|
||||
* fall back and try WRITESAME10/16 without UNMAP */
|
||||
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||
use_16_for_ws = iscsilun->use_16_for_rw;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
||||
/* WRITE SAME without UNMAP is not supported by the target */
|
||||
/* WRITESAME without UNMAP is not supported by the target */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -912,10 +898,18 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
retry:
|
||||
if (iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
iscsilun->zeroblock, iscsilun->block_size,
|
||||
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
|
||||
0, 0, iscsi_co_generic_cb, &iTask) == NULL) {
|
||||
if (use_16_for_ws) {
|
||||
iTask.task = iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
iscsilun->zeroblock, iscsilun->block_size,
|
||||
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
|
||||
0, 0, iscsi_co_generic_cb, &iTask);
|
||||
} else {
|
||||
iTask.task = iscsi_writesame10_task(iscsilun->iscsi, iscsilun->lun, lba,
|
||||
iscsilun->zeroblock, iscsilun->block_size,
|
||||
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
|
||||
0, 0, iscsi_co_generic_cb, &iTask);
|
||||
}
|
||||
if (iTask.task == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -957,8 +951,6 @@ retry:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED */
|
||||
|
||||
static void parse_chap(struct iscsi_context *iscsi, const char *target,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -1068,7 +1060,6 @@ static char *parse_initiator_name(const char *target)
|
||||
return iscsi_name;
|
||||
}
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||
static void iscsi_nop_timed_event(void *opaque)
|
||||
{
|
||||
IscsiLun *iscsilun = opaque;
|
||||
@@ -1086,7 +1077,6 @@ static void iscsi_nop_timed_event(void *opaque)
|
||||
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
|
||||
iscsi_set_events(iscsilun);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
|
||||
{
|
||||
@@ -1113,6 +1103,7 @@ static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
|
||||
iscsilun->num_blocks = rc16->returned_lba + 1;
|
||||
iscsilun->lbpme = rc16->lbpme;
|
||||
iscsilun->lbprz = rc16->lbprz;
|
||||
iscsilun->use_16_for_rw = (rc16->returned_lba > 0xffffffff);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1224,14 +1215,12 @@ static void iscsi_attach_aio_context(BlockDriverState *bs,
|
||||
iscsilun->aio_context = new_context;
|
||||
iscsi_set_events(iscsilun);
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||
/* Set up a timer for sending out iSCSI NOPs */
|
||||
iscsilun->nop_timer = aio_timer_new(iscsilun->aio_context,
|
||||
QEMU_CLOCK_REALTIME, SCALE_MS,
|
||||
iscsi_nop_timed_event, iscsilun);
|
||||
timer_mod(iscsilun->nop_timer,
|
||||
qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1423,13 +1412,11 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||
iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran *
|
||||
iscsilun->block_size) >> BDRV_SECTOR_BITS;
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) {
|
||||
iscsilun->allocationmap =
|
||||
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
||||
iscsilun->cluster_sectors));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -1614,13 +1601,9 @@ static BlockDriver bdrv_iscsi = {
|
||||
.bdrv_truncate = iscsi_truncate,
|
||||
.bdrv_refresh_limits = iscsi_refresh_limits,
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
.bdrv_co_get_block_status = iscsi_co_get_block_status,
|
||||
#endif
|
||||
.bdrv_co_discard = iscsi_co_discard,
|
||||
#if defined(SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED)
|
||||
.bdrv_co_write_zeroes = iscsi_co_write_zeroes,
|
||||
#endif
|
||||
.bdrv_co_readv = iscsi_co_readv,
|
||||
.bdrv_co_writev = iscsi_co_writev,
|
||||
.bdrv_co_flush_to_disk = iscsi_co_flush,
|
||||
|
||||
@@ -3405,46 +3405,20 @@ if compile_prog "" "" ; then
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# Do we have libiscsi
|
||||
# We check for iscsi_write16_sync() to make sure we have a
|
||||
# at least version 1.4.0 of libiscsi.
|
||||
# Do we have libiscsi >= 1.9.0
|
||||
if test "$libiscsi" != "no" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <stdio.h>
|
||||
#include <iscsi/iscsi.h>
|
||||
int main(void) { iscsi_write16_sync(NULL,0,0,NULL,0,0,0,0,0,0,0); return 0; }
|
||||
EOF
|
||||
if $pkg_config --atleast-version=1.7.0 libiscsi; then
|
||||
if $pkg_config --atleast-version=1.9.0 libiscsi; then
|
||||
libiscsi="yes"
|
||||
libiscsi_cflags=$($pkg_config --cflags libiscsi)
|
||||
libiscsi_libs=$($pkg_config --libs libiscsi)
|
||||
elif compile_prog "" "-liscsi" ; then
|
||||
libiscsi="yes"
|
||||
libiscsi_libs="-liscsi"
|
||||
else
|
||||
if test "$libiscsi" = "yes" ; then
|
||||
feature_not_found "libiscsi" "Install libiscsi devel"
|
||||
feature_not_found "libiscsi" "Install libiscsi >= 1.9.0"
|
||||
fi
|
||||
libiscsi="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
# We also need to know the API version because there was an
|
||||
# API change from 1.4.0 to 1.5.0.
|
||||
if test "$libiscsi" = "yes"; then
|
||||
cat >$TMPC <<EOF
|
||||
#include <iscsi/iscsi.h>
|
||||
int main(void)
|
||||
{
|
||||
iscsi_read10_task(0, 0, 0, 0, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "-liscsi"; then
|
||||
libiscsi_version="1.4.0"
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# Do we need libm
|
||||
cat > $TMPC << EOF
|
||||
@@ -4218,11 +4192,7 @@ echo "nss used $smartcard_nss"
|
||||
echo "libusb $libusb"
|
||||
echo "usb net redir $usb_redir"
|
||||
echo "GLX support $glx"
|
||||
if test "$libiscsi_version" = "1.4.0"; then
|
||||
echo "libiscsi support $libiscsi (1.4.0)"
|
||||
else
|
||||
echo "libiscsi support $libiscsi"
|
||||
fi
|
||||
echo "libnfs support $libnfs"
|
||||
echo "build guest agent $guest_agent"
|
||||
echo "QGA VSS support $guest_agent_with_vss"
|
||||
@@ -4579,9 +4549,6 @@ fi
|
||||
|
||||
if test "$libiscsi" = "yes" ; then
|
||||
echo "CONFIG_LIBISCSI=m" >> $config_host_mak
|
||||
if test "$libiscsi_version" = "1.4.0"; then
|
||||
echo "CONFIG_LIBISCSI_1_4=y" >> $config_host_mak
|
||||
fi
|
||||
echo "LIBISCSI_CFLAGS=$libiscsi_cflags" >> $config_host_mak
|
||||
echo "LIBISCSI_LIBS=$libiscsi_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
+10
-6
@@ -294,6 +294,7 @@ static void megasas_unmap_sgl(MegasasCmd *cmd)
|
||||
static int megasas_build_sense(MegasasCmd *cmd, uint8_t *sense_ptr,
|
||||
uint8_t sense_len)
|
||||
{
|
||||
PCIDevice *pcid = PCI_DEVICE(cmd->state);
|
||||
uint32_t pa_hi = 0, pa_lo;
|
||||
hwaddr pa;
|
||||
|
||||
@@ -306,7 +307,7 @@ static int megasas_build_sense(MegasasCmd *cmd, uint8_t *sense_ptr,
|
||||
pa_hi = le32_to_cpu(cmd->frame->pass.sense_addr_hi);
|
||||
}
|
||||
pa = ((uint64_t) pa_hi << 32) | pa_lo;
|
||||
cpu_physical_memory_write(pa, sense_ptr, sense_len);
|
||||
pci_dma_write(pcid, pa, sense_ptr, sense_len);
|
||||
cmd->frame->header.sense_len = sense_len;
|
||||
}
|
||||
return sense_len;
|
||||
@@ -472,6 +473,7 @@ static MegasasCmd *megasas_next_frame(MegasasState *s,
|
||||
static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
|
||||
hwaddr frame, uint64_t context, int count)
|
||||
{
|
||||
PCIDevice *pcid = PCI_DEVICE(s);
|
||||
MegasasCmd *cmd = NULL;
|
||||
int frame_size = MFI_FRAME_SIZE * 16;
|
||||
hwaddr frame_size_p = frame_size;
|
||||
@@ -484,11 +486,11 @@ static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
|
||||
if (!cmd->pa) {
|
||||
cmd->pa = frame;
|
||||
/* Map all possible frames */
|
||||
cmd->frame = cpu_physical_memory_map(frame, &frame_size_p, 0);
|
||||
cmd->frame = pci_dma_map(pcid, frame, &frame_size_p, 0);
|
||||
if (frame_size_p != frame_size) {
|
||||
trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame);
|
||||
if (cmd->frame) {
|
||||
cpu_physical_memory_unmap(cmd->frame, frame_size_p, 0, 0);
|
||||
pci_dma_unmap(pcid, cmd->frame, frame_size_p, 0, 0);
|
||||
cmd->frame = NULL;
|
||||
cmd->pa = 0;
|
||||
}
|
||||
@@ -561,13 +563,14 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context)
|
||||
|
||||
static void megasas_reset_frames(MegasasState *s)
|
||||
{
|
||||
PCIDevice *pcid = PCI_DEVICE(s);
|
||||
int i;
|
||||
MegasasCmd *cmd;
|
||||
|
||||
for (i = 0; i < s->fw_cmds; i++) {
|
||||
cmd = &s->frames[i];
|
||||
if (cmd->pa) {
|
||||
cpu_physical_memory_unmap(cmd->frame, cmd->pa_size, 0, 0);
|
||||
pci_dma_unmap(pcid, cmd->frame, cmd->pa_size, 0, 0);
|
||||
cmd->frame = NULL;
|
||||
cmd->pa = 0;
|
||||
}
|
||||
@@ -584,6 +587,7 @@ static void megasas_abort_command(MegasasCmd *cmd)
|
||||
|
||||
static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd)
|
||||
{
|
||||
PCIDevice *pcid = PCI_DEVICE(s);
|
||||
uint32_t pa_hi, pa_lo;
|
||||
hwaddr iq_pa, initq_size;
|
||||
struct mfi_init_qinfo *initq;
|
||||
@@ -595,7 +599,7 @@ static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd)
|
||||
iq_pa = (((uint64_t) pa_hi << 32) | pa_lo);
|
||||
trace_megasas_init_firmware((uint64_t)iq_pa);
|
||||
initq_size = sizeof(*initq);
|
||||
initq = cpu_physical_memory_map(iq_pa, &initq_size, 0);
|
||||
initq = pci_dma_map(pcid, iq_pa, &initq_size, 0);
|
||||
if (!initq || initq_size != sizeof(*initq)) {
|
||||
trace_megasas_initq_map_failed(cmd->index);
|
||||
s->event_count++;
|
||||
@@ -631,7 +635,7 @@ static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd)
|
||||
s->fw_state = MFI_FWSTATE_OPERATIONAL;
|
||||
out:
|
||||
if (initq) {
|
||||
cpu_physical_memory_unmap(initq, initq_size, 0, 0);
|
||||
pci_dma_unmap(pcid, initq, initq_size, 0, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
+3
-1
@@ -1429,7 +1429,7 @@ int scsi_build_sense(uint8_t *in_buf, int in_len,
|
||||
}
|
||||
}
|
||||
|
||||
static const char *scsi_command_name(uint8_t cmd)
|
||||
const char *scsi_command_name(uint8_t cmd)
|
||||
{
|
||||
static const char *names[] = {
|
||||
[ TEST_UNIT_READY ] = "TEST_UNIT_READY",
|
||||
@@ -1545,6 +1545,8 @@ static const char *scsi_command_name(uint8_t cmd)
|
||||
[ SET_READ_AHEAD ] = "SET_READ_AHEAD",
|
||||
[ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE",
|
||||
[ MECHANISM_STATUS ] = "MECHANISM_STATUS",
|
||||
[ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
|
||||
[ READ_DISC_INFORMATION ] = "READ_DISC_INFORMATION",
|
||||
};
|
||||
|
||||
if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
|
||||
|
||||
+4
-3
@@ -2015,7 +2015,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
||||
case VERIFY_10:
|
||||
case VERIFY_12:
|
||||
case VERIFY_16:
|
||||
DPRINTF("Verify (bytchk %lu)\n", (r->req.buf[1] >> 1) & 3);
|
||||
DPRINTF("Verify (bytchk %d)\n", (req->cmd.buf[1] >> 1) & 3);
|
||||
if (req->cmd.buf[1] & 6) {
|
||||
goto illegal_request;
|
||||
}
|
||||
@@ -2027,7 +2027,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
||||
(long)r->req.cmd.xfer);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||
DPRINTF("Unknown SCSI command (%2.2x=%s)\n", buf[0],
|
||||
scsi_command_name(buf[0]));
|
||||
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
|
||||
return 0;
|
||||
}
|
||||
@@ -2526,7 +2527,7 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
|
||||
* ones (such as WRITE SAME or EXTENDED COPY, etc.). So, without
|
||||
* O_DIRECT everything must go through SG_IO.
|
||||
*/
|
||||
if (bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE) {
|
||||
if (!(bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -799,8 +799,9 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
|
||||
req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req);
|
||||
n = scsi_req_enqueue(req->sreq);
|
||||
|
||||
DPRINTF("VSCSI: Queued command tag 0x%x CMD 0x%x LUN %d ret: %d\n",
|
||||
req->qtag, srp->cmd.cdb[0], lun, n);
|
||||
DPRINTF("VSCSI: Queued command tag 0x%x CMD 0x%x=%s LUN %d ret: %d\n",
|
||||
req->qtag, srp->cmd.cdb[0], scsi_command_name(srp->cmd.cdb[0]),
|
||||
lun, n);
|
||||
|
||||
if (n) {
|
||||
/* Transfer direction must be set before preprocessing the
|
||||
|
||||
@@ -196,6 +196,10 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
|
||||
}
|
||||
}
|
||||
|
||||
static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
{
|
||||
}
|
||||
|
||||
static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
|
||||
@@ -217,7 +221,9 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
virtio_scsi_common_realize(dev, &err);
|
||||
virtio_scsi_common_realize(dev, &err, vhost_dummy_handle_output,
|
||||
vhost_dummy_handle_output,
|
||||
vhost_dummy_handle_output);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
|
||||
+202
-136
File diff suppressed because it is too large
Load Diff
@@ -143,6 +143,8 @@
|
||||
#define READ_CD 0xbe
|
||||
#define SEND_DVD_STRUCTURE 0xbf
|
||||
|
||||
const char *scsi_command_name(uint8_t cmd);
|
||||
|
||||
/*
|
||||
* SERVICE ACTION IN subcodes
|
||||
*/
|
||||
|
||||
@@ -268,6 +268,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
|
||||
|
||||
#define PC_COMPAT_2_0 \
|
||||
{\
|
||||
.driver = "virtio-scsi-pci",\
|
||||
.property = "any_layout",\
|
||||
.value = "off",\
|
||||
},{\
|
||||
.driver = "apic",\
|
||||
.property = "version",\
|
||||
.value = stringify(0x11),\
|
||||
|
||||
@@ -84,14 +84,13 @@
|
||||
#define VIRTIO_SCSI_EVT_RESET_RESCAN 1
|
||||
#define VIRTIO_SCSI_EVT_RESET_REMOVED 2
|
||||
|
||||
/* SCSI command request, followed by data-out */
|
||||
/* SCSI command request, followed by CDB and data-out */
|
||||
typedef struct {
|
||||
uint8_t lun[8]; /* Logical Unit Number */
|
||||
uint64_t tag; /* Command identifier */
|
||||
uint8_t task_attr; /* Task attribute */
|
||||
uint8_t prio;
|
||||
uint8_t crn;
|
||||
uint8_t cdb[];
|
||||
} QEMU_PACKED VirtIOSCSICmdReq;
|
||||
|
||||
/* Response, followed by sense data and data-in */
|
||||
@@ -101,7 +100,6 @@ typedef struct {
|
||||
uint16_t status_qualifier; /* Status qualifier */
|
||||
uint8_t status; /* Command completion status */
|
||||
uint8_t response; /* Response values */
|
||||
uint8_t sense[];
|
||||
} QEMU_PACKED VirtIOSCSICmdResp;
|
||||
|
||||
/* Task Management Request */
|
||||
@@ -186,7 +184,12 @@ typedef struct {
|
||||
DEFINE_PROP_BIT("param_change", _state, _feature_field, \
|
||||
VIRTIO_SCSI_F_CHANGE, true)
|
||||
|
||||
void virtio_scsi_common_realize(DeviceState *dev, Error **errp);
|
||||
typedef void (*HandleOutput)(VirtIODevice *, VirtQueue *);
|
||||
|
||||
void virtio_scsi_common_realize(DeviceState *dev, Error **errp,
|
||||
HandleOutput ctrl, HandleOutput evt,
|
||||
HandleOutput cmd);
|
||||
|
||||
void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp);
|
||||
|
||||
#endif /* _QEMU_VIRTIO_SCSI_H */
|
||||
|
||||
@@ -315,9 +315,9 @@ void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov);
|
||||
void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
|
||||
void qemu_iovec_concat(QEMUIOVector *dst,
|
||||
QEMUIOVector *src, size_t soffset, size_t sbytes);
|
||||
void qemu_iovec_concat_iov(QEMUIOVector *dst,
|
||||
struct iovec *src_iov, unsigned int src_cnt,
|
||||
size_t soffset, size_t sbytes);
|
||||
size_t qemu_iovec_concat_iov(QEMUIOVector *dst,
|
||||
struct iovec *src_iov, unsigned int src_cnt,
|
||||
size_t soffset, size_t sbytes);
|
||||
bool qemu_iovec_is_zero(QEMUIOVector *qiov);
|
||||
void qemu_iovec_destroy(QEMUIOVector *qiov);
|
||||
void qemu_iovec_reset(QEMUIOVector *qiov);
|
||||
|
||||
+6
-4
@@ -295,15 +295,15 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
|
||||
* of src".
|
||||
* Only vector pointers are processed, not the actual data buffers.
|
||||
*/
|
||||
void qemu_iovec_concat_iov(QEMUIOVector *dst,
|
||||
struct iovec *src_iov, unsigned int src_cnt,
|
||||
size_t soffset, size_t sbytes)
|
||||
size_t qemu_iovec_concat_iov(QEMUIOVector *dst,
|
||||
struct iovec *src_iov, unsigned int src_cnt,
|
||||
size_t soffset, size_t sbytes)
|
||||
{
|
||||
int i;
|
||||
size_t done;
|
||||
|
||||
if (!sbytes) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
assert(dst->nalloc != -1);
|
||||
for (i = 0, done = 0; done < sbytes && i < src_cnt; i++) {
|
||||
@@ -317,6 +317,8 @@ void qemu_iovec_concat_iov(QEMUIOVector *dst,
|
||||
}
|
||||
}
|
||||
assert(soffset == 0); /* offset beyond end of src */
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user