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;
|
||||
uint64_t num_blocks;
|
||||
int events;
|
||||
QEMUTimer *nop_timer;
|
||||
} IscsiLun;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
@ -66,6 +67,9 @@ typedef struct IscsiAIOCB {
|
||||
#endif
|
||||
} IscsiAIOCB;
|
||||
|
||||
#define NOP_INTERVAL 5000
|
||||
#define MAX_NOP_FAILURES 3
|
||||
|
||||
static void
|
||||
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 */
|
||||
/* this will allow us to get rid of 'buf' completely */
|
||||
size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||
acb->buf = g_malloc(size);
|
||||
qemu_iovec_to_buf(acb->qiov, 0, acb->buf, size);
|
||||
data.size = MIN(size, acb->qiov->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));
|
||||
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);
|
||||
acb->task->expxferlen = size;
|
||||
|
||||
data.data = acb->buf;
|
||||
data.size = size;
|
||||
|
||||
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||
iscsi_aio_write16_cb,
|
||||
&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
|
||||
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
|
||||
@ -922,6 +952,12 @@ static int iscsi_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
|
||||
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:
|
||||
if (initiator_name != NULL) {
|
||||
g_free(initiator_name);
|
||||
@ -947,6 +983,10 @@ static void iscsi_close(BlockDriverState *bs)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
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);
|
||||
iscsi_destroy_context(iscsi);
|
||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||
@ -957,6 +997,60 @@ static int iscsi_has_zero_init(BlockDriverState *bs)
|
||||
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 = {
|
||||
.format_name = "iscsi",
|
||||
.protocol_name = "iscsi",
|
||||
@ -964,6 +1058,8 @@ static BlockDriver bdrv_iscsi = {
|
||||
.instance_size = sizeof(IscsiLun),
|
||||
.bdrv_file_open = iscsi_open,
|
||||
.bdrv_close = iscsi_close,
|
||||
.bdrv_create = iscsi_create,
|
||||
.create_options = iscsi_create_options,
|
||||
|
||||
.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 (!(s->sstat0 & LSI_SSTAT0_RST)) {
|
||||
BusChild *kid;
|
||||
|
||||
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
|
||||
DeviceState *dev = kid->child;
|
||||
device_reset(dev);
|
||||
}
|
||||
qbus_reset_all(&s->bus.qbus);
|
||||
s->sstat0 |= LSI_SSTAT0_RST;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
} else if (req->bus->unit_attention.key == 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);
|
||||
if (!nb_sectors) {
|
||||
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
|
||||
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);
|
||||
if (!nb_sectors) {
|
||||
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
|
||||
goto illegal_request;
|
||||
|
Loading…
Reference in New Issue
Block a user