diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-01-23 09:08:54 -0600 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-01-23 09:08:54 -0600 |
commit | 177f7fc6884c47666f6c6eeca376a92432ccda38 (patch) | |
tree | 75f5ec98b1aa5c9c15b95033431e9a141cf59fd5 | |
parent | 36ba58044e70a82b93e84b1f31076df847f23109 (diff) | |
parent | 0bf8264e2d2bd19c1eecf9bde0e59284ef47eabb (diff) |
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
-rw-r--r-- | block/iscsi.c | 106 | ||||
-rw-r--r-- | hw/lsi53c895a.c | 7 | ||||
-rw-r--r-- | hw/scsi-bus.c | 2 | ||||
-rw-r--r-- | hw/scsi-disk.c | 4 |
4 files changed, 105 insertions, 14 deletions
diff --git a/block/iscsi.c b/block/iscsi.c index f08cf9663b..fd54a1550e 100644 --- a/block/iscsi.c +++ b/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, diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 89c657fb00..860df328e5 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -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); } diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 267a942f76..a97f1cdc1c 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -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); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 96db9a73c7..28e75bbf5b 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -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; |