aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/char/mcf_uart.c2
-rw-r--r--hw/scsi/scsi-bus.c3
-rw-r--r--hw/scsi/scsi-disk.c97
-rw-r--r--hw/scsi/scsi-generic.c66
-rw-r--r--hw/scsi/vhost-scsi.c3
-rw-r--r--hw/scsi/virtio-scsi.c5
6 files changed, 117 insertions, 59 deletions
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
index 98fd44e66a..cda22eea5d 100644
--- a/hw/char/mcf_uart.c
+++ b/hw/char/mcf_uart.c
@@ -126,7 +126,7 @@ static void mcf_uart_do_tx(mcf_uart_state *s)
static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
{
/* Misc command. */
- switch ((cmd >> 4) & 3) {
+ switch ((cmd >> 4) & 7) {
case 0: /* No-op. */
break;
case 1: /* Reset mode register pointer. */
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index f0ae4625ff..ffac8f4bb6 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -136,7 +136,8 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
return;
}
if (!s->bh) {
- s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
+ AioContext *ctx = blk_get_aio_context(s->conf.blk);
+ s->bh = aio_bh_new(ctx, scsi_dma_restart_bh, s);
qemu_bh_schedule(s->bh);
}
}
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 64f0694734..bada9a7f62 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -217,6 +217,8 @@ static void scsi_write_do_fua(SCSIDiskReq *r)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ assert(r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -235,15 +237,10 @@ done:
scsi_req_unref(&r->req);
}
-static void scsi_dma_complete_noio(void *opaque, int ret)
+static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret)
{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ assert(r->req.aiocb == NULL);
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -271,9 +268,13 @@ done:
static void scsi_dma_complete(void *opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
assert(r->req.aiocb != NULL);
- scsi_dma_complete_noio(opaque, ret);
+ r->req.aiocb = NULL;
+
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ scsi_dma_complete_noio(r, ret);
}
static void scsi_read_complete(void * opaque, int ret)
@@ -308,16 +309,13 @@ done:
}
/* Actually issue a read to the block device. */
-static void scsi_do_read(void *opaque, int ret)
+static void scsi_do_read(SCSIDiskReq *r, int ret)
{
- SCSIDiskReq *r = opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
+ assert (r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -349,6 +347,18 @@ done:
scsi_req_unref(&r->req);
}
+static void scsi_do_read_cb(void *opaque, int ret)
+{
+ SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ assert (r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ scsi_do_read(opaque, ret);
+}
+
/* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIRequest *req)
{
@@ -384,7 +394,7 @@ static void scsi_read_data(SCSIRequest *req)
if (first && scsi_is_cmd_fua(&r->req.cmd)) {
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0,
BLOCK_ACCT_FLUSH);
- r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read, r);
+ r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r);
} else {
scsi_do_read(r, 0);
}
@@ -399,7 +409,7 @@ static void scsi_read_data(SCSIRequest *req)
*/
static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
{
- bool is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV);
+ bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk,
is_read, error);
@@ -430,16 +440,12 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
return action != BLOCK_ERROR_ACTION_IGNORE;
}
-static void scsi_write_complete(void * opaque, int ret)
+static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n;
- if (r->req.aiocb != NULL) {
- r->req.aiocb = NULL;
- block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
+ assert (r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -467,6 +473,18 @@ done:
scsi_req_unref(&r->req);
}
+static void scsi_write_complete(void * opaque, int ret)
+{
+ SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ assert (r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+
+ block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ scsi_write_complete_noio(r, ret);
+}
+
static void scsi_write_data(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -480,18 +498,18 @@ static void scsi_write_data(SCSIRequest *req)
scsi_req_ref(&r->req);
if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
DPRINTF("Data transfer direction invalid\n");
- scsi_write_complete(r, -EINVAL);
+ scsi_write_complete_noio(r, -EINVAL);
return;
}
if (!r->req.sg && !r->qiov.size) {
/* Called for the first time. Ask the driver to send us more data. */
r->started = true;
- scsi_write_complete(r, 0);
+ scsi_write_complete_noio(r, 0);
return;
}
if (s->tray_open) {
- scsi_write_complete(r, -ENOMEDIUM);
+ scsi_write_complete_noio(r, -ENOMEDIUM);
return;
}
@@ -500,7 +518,7 @@ static void scsi_write_data(SCSIRequest *req)
if (r->req.sg) {
scsi_dma_complete_noio(r, 0);
} else {
- scsi_write_complete(r, 0);
+ scsi_write_complete_noio(r, 0);
}
return;
}
@@ -1557,15 +1575,17 @@ typedef struct UnmapCBData {
int count;
} UnmapCBData;
-static void scsi_unmap_complete(void *opaque, int ret)
+static void scsi_unmap_complete(void *opaque, int ret);
+
+static void scsi_unmap_complete_noio(UnmapCBData *data, int ret)
{
- UnmapCBData *data = opaque;
SCSIDiskReq *r = data->r;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint64_t sector_num;
uint32_t nb_sectors;
- r->req.aiocb = NULL;
+ assert(r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -1601,6 +1621,17 @@ done:
g_free(data);
}
+static void scsi_unmap_complete(void *opaque, int ret)
+{
+ UnmapCBData *data = opaque;
+ SCSIDiskReq *r = data->r;
+
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+
+ scsi_unmap_complete_noio(data, ret);
+}
+
static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
@@ -1638,7 +1669,7 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
/* The matching unref is in scsi_unmap_complete, before data is freed. */
scsi_req_ref(&r->req);
- scsi_unmap_complete(data, 0);
+ scsi_unmap_complete_noio(data, 0);
return;
invalid_param_len:
@@ -1683,6 +1714,10 @@ static void scsi_write_same_complete(void *opaque, int ret)
if (data->iov.iov_len) {
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
data->iov.iov_len, BLOCK_ACCT_WRITE);
+ /* blk_aio_write doesn't like the qiov size being different from
+ * nb_sectors, make sure they match.
+ */
+ qemu_iovec_init_external(&data->qiov, &data->iov, 1);
r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector,
&data->qiov, data->iov.iov_len / 512,
scsi_write_same_complete, data);
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index e53470f85e..1b6350be41 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -88,12 +88,12 @@ static void scsi_free_request(SCSIRequest *req)
}
/* Helper function for command completion. */
-static void scsi_command_complete(void *opaque, int ret)
+static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
{
int status;
- SCSIGenericReq *r = (SCSIGenericReq *)opaque;
- r->req.aiocb = NULL;
+ assert(r->req.aiocb == NULL);
+
if (r->req.io_canceled) {
scsi_req_cancel_complete(&r->req);
goto done;
@@ -142,6 +142,15 @@ done:
scsi_req_unref(&r->req);
}
+static void scsi_command_complete(void *opaque, int ret)
+{
+ SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+
+ assert(r->req.aiocb != NULL);
+ r->req.aiocb = NULL;
+ scsi_command_complete_noio(r, ret);
+}
+
static int execute_command(BlockBackend *blk,
SCSIGenericReq *r, int direction,
BlockCompletionFunc *complete)
@@ -172,33 +181,37 @@ static void scsi_read_complete(void * opaque, int ret)
SCSIDevice *s = r->req.dev;
int len;
+ assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
+
if (ret || r->req.io_canceled) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
return;
}
+
len = r->io_header.dxfer_len - r->io_header.resid;
DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
r->len = -1;
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 &&
- (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
- s->blocksize = ldl_be_p(&r->buf[4]);
- s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
- } 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]);
- }
- blk_set_guest_block_size(s->conf.blk, s->blocksize);
+ scsi_command_complete_noio(r, 0);
+ return;
+ }
- scsi_req_data(&r->req, len);
- scsi_req_unref(&r->req);
+ /* Snoop READ CAPACITY output to set the blocksize. */
+ if (r->req.cmd.buf[0] == READ_CAPACITY_10 &&
+ (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) {
+ s->blocksize = ldl_be_p(&r->buf[4]);
+ s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL;
+ } 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]);
}
+ blk_set_guest_block_size(s->conf.blk, s->blocksize);
+
+ scsi_req_data(&r->req, len);
+ scsi_req_unref(&r->req);
}
/* Read more data from scsi device into buffer. */
@@ -213,14 +226,14 @@ static void scsi_read_data(SCSIRequest *req)
/* 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);
+ scsi_command_complete_noio(r, 0);
return;
}
ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV,
scsi_read_complete);
if (ret < 0) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
}
}
@@ -230,9 +243,12 @@ static void scsi_write_complete(void * opaque, int ret)
SCSIDevice *s = r->req.dev;
DPRINTF("scsi_write_complete() ret = %d\n", ret);
+
+ assert(r->req.aiocb != NULL);
r->req.aiocb = NULL;
+
if (ret || r->req.io_canceled) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
return;
}
@@ -242,7 +258,7 @@ static void scsi_write_complete(void * opaque, int ret)
DPRINTF("block size %d\n", s->blocksize);
}
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
}
/* Write data to a scsi device. Returns nonzero on failure.
@@ -264,7 +280,7 @@ static void scsi_write_data(SCSIRequest *req)
scsi_req_ref(&r->req);
ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete);
if (ret < 0) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
}
}
@@ -306,7 +322,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
ret = execute_command(s->conf.blk, r, SG_DXFER_NONE,
scsi_command_complete);
if (ret < 0) {
- scsi_command_complete(r, ret);
+ scsi_command_complete_noio(r, ret);
return 0;
}
return 0;
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index a69918bef8..7eacca9dc5 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -118,7 +118,7 @@ static int vhost_scsi_start(VHostSCSI *s)
* enabling/disabling irqfd.
*/
for (i = 0; i < s->dev.nvqs; i++) {
- vhost_virtqueue_mask(&s->dev, vdev, i, false);
+ vhost_virtqueue_mask(&s->dev, vdev, s->dev.vq_index + i, false);
}
return ret;
@@ -277,6 +277,7 @@ static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
/* This will stop vhost backend. */
vhost_scsi_set_status(vdev, 0);
+ vhost_dev_cleanup(&s->dev);
g_free(s->dev.vqs);
virtio_scsi_common_unrealize(dev, errp);
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 811c3da8bd..a8bb1c66f9 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -217,6 +217,11 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
assert(req->elem.in_num <= ARRAY_SIZE(req->elem.in_sg));
assert(req->elem.out_num <= ARRAY_SIZE(req->elem.out_sg));
+ virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
+ req->elem.in_num, 1);
+ virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
+ req->elem.out_num, 0);
+
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
sizeof(VirtIOSCSICmdResp) + vs->sense_size) < 0) {
error_report("invalid SCSI request migration data");