Merge remote-tracking branch 'bonzini/scsi-next' into staging
# By Peter Lieven (3) and others # Via Paolo Bonzini * bonzini/scsi-next: scsi: Drop useless null test in scsi_unit_attention() lsi: use qbus_reset_all to reset SCSI bus scsi: fix segfault with 0-byte disk iscsi: add support for iSCSI NOPs [v2] iscsi: partly avoid iovec linearization in iscsi_aio_writev iscsi: add iscsi_create support
This commit is contained in:
commit
177f7fc688
106
block/iscsi.c
106
block/iscsi.c
|
@ -48,6 +48,7 @@ typedef struct IscsiLun {
|
||||||
int block_size;
|
int block_size;
|
||||||
uint64_t num_blocks;
|
uint64_t num_blocks;
|
||||||
int events;
|
int events;
|
||||||
|
QEMUTimer *nop_timer;
|
||||||
} IscsiLun;
|
} IscsiLun;
|
||||||
|
|
||||||
typedef struct IscsiAIOCB {
|
typedef struct IscsiAIOCB {
|
||||||
|
@ -66,6 +67,9 @@ typedef struct IscsiAIOCB {
|
||||||
#endif
|
#endif
|
||||||
} IscsiAIOCB;
|
} IscsiAIOCB;
|
||||||
|
|
||||||
|
#define NOP_INTERVAL 5000
|
||||||
|
#define MAX_NOP_FAILURES 3
|
||||||
|
|
||||||
static void
|
static void
|
||||||
iscsi_bh_cb(void *p)
|
iscsi_bh_cb(void *p)
|
||||||
{
|
{
|
||||||
|
@ -241,8 +245,17 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||||
/* XXX we should pass the iovec to write16 to avoid the extra copy */
|
/* XXX we should pass the iovec to write16 to avoid the extra copy */
|
||||||
/* this will allow us to get rid of 'buf' completely */
|
/* this will allow us to get rid of 'buf' completely */
|
||||||
size = nb_sectors * BDRV_SECTOR_SIZE;
|
size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||||
acb->buf = g_malloc(size);
|
data.size = MIN(size, acb->qiov->size);
|
||||||
qemu_iovec_to_buf(acb->qiov, 0, acb->buf, size);
|
|
||||||
|
/* if the iovec only contains one buffer we can pass it directly */
|
||||||
|
if (acb->qiov->niov == 1) {
|
||||||
|
acb->buf = NULL;
|
||||||
|
data.data = acb->qiov->iov[0].iov_base;
|
||||||
|
} else {
|
||||||
|
acb->buf = g_malloc(data.size);
|
||||||
|
qemu_iovec_to_buf(acb->qiov, 0, acb->buf, data.size);
|
||||||
|
data.data = acb->buf;
|
||||||
|
}
|
||||||
|
|
||||||
acb->task = malloc(sizeof(struct scsi_task));
|
acb->task = malloc(sizeof(struct scsi_task));
|
||||||
if (acb->task == NULL) {
|
if (acb->task == NULL) {
|
||||||
|
@ -263,9 +276,6 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||||
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
|
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
|
||||||
acb->task->expxferlen = size;
|
acb->task->expxferlen = size;
|
||||||
|
|
||||||
data.data = acb->buf;
|
|
||||||
data.size = size;
|
|
||||||
|
|
||||||
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||||
iscsi_aio_write16_cb,
|
iscsi_aio_write16_cb,
|
||||||
&data,
|
&data,
|
||||||
|
@ -762,6 +772,26 @@ static char *parse_initiator_name(const char *target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||||
|
static void iscsi_nop_timed_event(void *opaque)
|
||||||
|
{
|
||||||
|
IscsiLun *iscsilun = opaque;
|
||||||
|
|
||||||
|
if (iscsi_get_nops_in_flight(iscsilun->iscsi) > MAX_NOP_FAILURES) {
|
||||||
|
error_report("iSCSI: NOP timeout. Reconnecting...");
|
||||||
|
iscsi_reconnect(iscsilun->iscsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) {
|
||||||
|
error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL);
|
||||||
|
iscsi_set_events(iscsilun);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We support iscsi url's on the form
|
* We support iscsi url's on the form
|
||||||
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
|
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
|
||||||
|
@ -922,6 +952,12 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
#if defined(LIBISCSI_FEATURE_NOP_COUNTER)
|
||||||
|
/* Set up a timer for sending out iSCSI NOPs */
|
||||||
|
iscsilun->nop_timer = qemu_new_timer_ms(rt_clock, iscsi_nop_timed_event, iscsilun);
|
||||||
|
qemu_mod_timer(iscsilun->nop_timer, qemu_get_clock_ms(rt_clock) + NOP_INTERVAL);
|
||||||
|
#endif
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (initiator_name != NULL) {
|
if (initiator_name != NULL) {
|
||||||
g_free(initiator_name);
|
g_free(initiator_name);
|
||||||
|
@ -947,6 +983,10 @@ static void iscsi_close(BlockDriverState *bs)
|
||||||
IscsiLun *iscsilun = bs->opaque;
|
IscsiLun *iscsilun = bs->opaque;
|
||||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||||
|
|
||||||
|
if (iscsilun->nop_timer) {
|
||||||
|
qemu_del_timer(iscsilun->nop_timer);
|
||||||
|
qemu_free_timer(iscsilun->nop_timer);
|
||||||
|
}
|
||||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
|
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
|
||||||
iscsi_destroy_context(iscsi);
|
iscsi_destroy_context(iscsi);
|
||||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||||
|
@ -957,6 +997,60 @@ static int iscsi_has_zero_init(BlockDriverState *bs)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int iscsi_create(const char *filename, QEMUOptionParameter *options)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int64_t total_size = 0;
|
||||||
|
BlockDriverState bs;
|
||||||
|
IscsiLun *iscsilun = NULL;
|
||||||
|
|
||||||
|
memset(&bs, 0, sizeof(BlockDriverState));
|
||||||
|
|
||||||
|
/* Read out options */
|
||||||
|
while (options && options->name) {
|
||||||
|
if (!strcmp(options->name, "size")) {
|
||||||
|
total_size = options->value.n / BDRV_SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
options++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bs.opaque = g_malloc0(sizeof(struct IscsiLun));
|
||||||
|
iscsilun = bs.opaque;
|
||||||
|
|
||||||
|
ret = iscsi_open(&bs, filename, 0);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (iscsilun->nop_timer) {
|
||||||
|
qemu_del_timer(iscsilun->nop_timer);
|
||||||
|
qemu_free_timer(iscsilun->nop_timer);
|
||||||
|
}
|
||||||
|
if (iscsilun->type != TYPE_DISK) {
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (bs.total_sectors < total_size) {
|
||||||
|
ret = -ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
if (iscsilun->iscsi != NULL) {
|
||||||
|
iscsi_destroy_context(iscsilun->iscsi);
|
||||||
|
}
|
||||||
|
g_free(bs.opaque);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QEMUOptionParameter iscsi_create_options[] = {
|
||||||
|
{
|
||||||
|
.name = BLOCK_OPT_SIZE,
|
||||||
|
.type = OPT_SIZE,
|
||||||
|
.help = "Virtual disk size"
|
||||||
|
},
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static BlockDriver bdrv_iscsi = {
|
static BlockDriver bdrv_iscsi = {
|
||||||
.format_name = "iscsi",
|
.format_name = "iscsi",
|
||||||
.protocol_name = "iscsi",
|
.protocol_name = "iscsi",
|
||||||
|
@ -964,6 +1058,8 @@ static BlockDriver bdrv_iscsi = {
|
||||||
.instance_size = sizeof(IscsiLun),
|
.instance_size = sizeof(IscsiLun),
|
||||||
.bdrv_file_open = iscsi_open,
|
.bdrv_file_open = iscsi_open,
|
||||||
.bdrv_close = iscsi_close,
|
.bdrv_close = iscsi_close,
|
||||||
|
.bdrv_create = iscsi_create,
|
||||||
|
.create_options = iscsi_create_options,
|
||||||
|
|
||||||
.bdrv_getlength = iscsi_getlength,
|
.bdrv_getlength = iscsi_getlength,
|
||||||
|
|
||||||
|
|
|
@ -1670,12 +1670,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
|
||||||
}
|
}
|
||||||
if (val & LSI_SCNTL1_RST) {
|
if (val & LSI_SCNTL1_RST) {
|
||||||
if (!(s->sstat0 & LSI_SSTAT0_RST)) {
|
if (!(s->sstat0 & LSI_SSTAT0_RST)) {
|
||||||
BusChild *kid;
|
qbus_reset_all(&s->bus.qbus);
|
||||||
|
|
||||||
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
|
|
||||||
DeviceState *dev = kid->child;
|
|
||||||
device_reset(dev);
|
|
||||||
}
|
|
||||||
s->sstat0 |= LSI_SSTAT0_RST;
|
s->sstat0 |= LSI_SSTAT0_RST;
|
||||||
lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
|
lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -282,7 +282,7 @@ static const struct SCSIReqOps reqops_invalid_opcode = {
|
||||||
|
|
||||||
static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
|
static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
|
||||||
{
|
{
|
||||||
if (req->dev && req->dev->unit_attention.key == UNIT_ATTENTION) {
|
if (req->dev->unit_attention.key == UNIT_ATTENTION) {
|
||||||
scsi_req_build_sense(req, req->dev->unit_attention);
|
scsi_req_build_sense(req, req->dev->unit_attention);
|
||||||
} else if (req->bus->unit_attention.key == UNIT_ATTENTION) {
|
} else if (req->bus->unit_attention.key == UNIT_ATTENTION) {
|
||||||
scsi_req_build_sense(req, req->bus->unit_attention);
|
scsi_req_build_sense(req, req->bus->unit_attention);
|
||||||
|
|
|
@ -1680,7 +1680,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
||||||
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
|
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
|
||||||
if (!nb_sectors) {
|
if (!nb_sectors) {
|
||||||
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
|
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
|
if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
|
||||||
goto illegal_request;
|
goto illegal_request;
|
||||||
|
@ -1749,7 +1749,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
|
||||||
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
|
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
|
||||||
if (!nb_sectors) {
|
if (!nb_sectors) {
|
||||||
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
|
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
|
if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
|
||||||
goto illegal_request;
|
goto illegal_request;
|
||||||
|
|
Loading…
Reference in New Issue