From 4525c1337f2a5fc99570ce392e552b8905e36c9a Mon Sep 17 00:00:00 2001 From: Paul Janzen Date: Wed, 4 Jun 2014 22:33:40 -0700 Subject: scsi-disk.c: Fix compilation with -DDEBUG_SCSI In scsi-disk.c, if you #define DEBUG_SCSI=1, you get: hw/scsi/scsi-disk.c: In function 'scsi_disk_emulate_command': hw/scsi/scsi-disk.c:2018: error: 'SCSIRequest' has no member named 'buf' Change the debugging statement to match the actual value tested. Signed-off-by: Paul Janzen Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index fc6e32a..9afbb8a 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -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; } -- cgit v1.1 From 2fe5a9f73b3446690db2cae8a58473b0b4beaa32 Mon Sep 17 00:00:00 2001 From: Ulrich Obergfell Date: Sun, 8 Jun 2014 19:22:33 +0200 Subject: scsi-disk: fix bug in scsi_block_new_request() introduced by commit 137745c This patch fixes a bug in scsi_block_new_request() that was introduced by commit 137745c5c60f083ec982fe9e861e8c16ebca1ba8. If the host cache is used - i.e. if BDRV_O_NOCACHE is _not_ set - the 'break' statement needs to be executed to 'fall back' to SG_IO. Cc: qemu-stable@nongnu.org Signed-off-by: Ulrich Obergfell Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 9afbb8a..fd82a41 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2526,7 +2526,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; } -- cgit v1.1 From b9e77bc718db3593ffbb56f3a51488cdce4d5af3 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 12 Jun 2014 15:41:37 +1000 Subject: scsi: Print command name in debug This makes scsi_command_name() public. This makes use of scsi_command_name() in debug output for scsi-disk and spapr-vscsi host bus adapter. Before this, SCSI used to print hex numbers instead of human-friendly strings. This adds GET_EVENT_STATUS_NOTIFICATION and READ_DISC_INFORMATION to the list of SCSI commands supported by scsi_command_name(). Signed-off-by: Alexey Kardashevskiy Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 4 +++- hw/scsi/scsi-disk.c | 3 ++- hw/scsi/spapr_vscsi.c | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 003d284..ea1ac09 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -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) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index fd82a41..a529ad2 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -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; } diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index f96b7af..048cfc7 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -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 -- cgit v1.1 From 1016b239c5c7b54a02fbd3121f68fb264a42d0a1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 13 Jun 2014 17:26:13 +0200 Subject: megasas: use PCI DMA API MegaSAS emulation is not IOMMU-friendly. Fix this by switching to pci_dma_* functions. Signed-off-by: Paolo Bonzini --- hw/scsi/megasas.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index b05c47a..c68a873 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -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; } -- cgit v1.1 From 36b15c79aa1bef5fe7543f9f2629b6413720bbfb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 10 Jun 2014 16:21:18 +0200 Subject: virtio-scsi: start preparing for any_layout - Introduce virtio_scsi_init_req and virtio_scsi_free_req - rename qemu_sgl_init_external to qemu_sgl_concat - move virtio_scsi_parse_req from virtio_scsi_pop_req to callers and add header length checks to virtio_scsi_parse_req. Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 121 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 49 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index b39880a..f013e35 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -15,6 +15,7 @@ #include "hw/virtio/virtio-scsi.h" #include "qemu/error-report.h" +#include "qemu/iov.h" #include #include #include @@ -56,18 +57,35 @@ static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun)); } +static VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) +{ + VirtIOSCSIReq *req; + req = g_malloc(sizeof(*req)); + + req->vq = vq; + req->dev = s; + req->sreq = NULL; + qemu_sglist_init(&req->qsgl, DEVICE(s), 8, &address_space_memory); + return req; +} + +static void virtio_scsi_free_req(VirtIOSCSIReq *req) +{ + qemu_sglist_destroy(&req->qsgl); + g_free(req); +} + static void virtio_scsi_complete_req(VirtIOSCSIReq *req) { VirtIOSCSI *s = req->dev; VirtQueue *vq = req->vq; VirtIODevice *vdev = VIRTIO_DEVICE(s); virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len); - qemu_sglist_destroy(&req->qsgl); if (req->sreq) { req->sreq->hba_private = NULL; scsi_req_unref(req->sreq); } - g_free(req); + virtio_scsi_free_req(req); virtio_notify(vdev, vq); } @@ -77,50 +95,55 @@ static void virtio_scsi_bad_req(void) exit(1); } -static void qemu_sgl_init_external(VirtIOSCSIReq *req, struct iovec *sg, +static void qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *sg, hwaddr *addr, int num) { QEMUSGList *qsgl = &req->qsgl; - qemu_sglist_init(qsgl, DEVICE(req->dev), num, &address_space_memory); while (num--) { qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len); } } -static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq, - VirtIOSCSIReq *req) +static int virtio_scsi_parse_req(VirtIOSCSIReq *req, + unsigned req_size, unsigned resp_size) { - assert(req->elem.in_num); - req->vq = vq; - req->dev = s; - req->sreq = NULL; + if (req->elem.in_num == 0) { + return -EINVAL; + } + + if (req->elem.out_sg[0].iov_len < req_size) { + return -EINVAL; + } if (req->elem.out_num) { req->req.buf = req->elem.out_sg[0].iov_base; } + + if (req->elem.in_sg[0].iov_len < resp_size) { + return -EINVAL; + } req->resp.buf = req->elem.in_sg[0].iov_base; if (req->elem.out_num > 1) { - qemu_sgl_init_external(req, &req->elem.out_sg[1], - &req->elem.out_addr[1], - req->elem.out_num - 1); + qemu_sgl_concat(req, &req->elem.out_sg[1], + &req->elem.out_addr[1], + req->elem.out_num - 1); } else { - qemu_sgl_init_external(req, &req->elem.in_sg[1], - &req->elem.in_addr[1], - req->elem.in_num - 1); + qemu_sgl_concat(req, &req->elem.in_sg[1], + &req->elem.in_addr[1], + req->elem.in_num - 1); } + + return 0; } static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq) { - VirtIOSCSIReq *req; - req = g_malloc(sizeof(*req)); + VirtIOSCSIReq *req = virtio_scsi_init_req(s, vq); if (!virtqueue_pop(vq, &req->elem)) { - g_free(req); + virtio_scsi_free_req(req); return NULL; } - - virtio_scsi_parse_req(s, vq, req); return req; } @@ -143,9 +166,9 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) VirtIOSCSIReq *req; uint32_t n; - req = g_malloc(sizeof(*req)); qemu_get_be32s(f, &n); assert(n < vs->conf.num_queues); + req = virtio_scsi_init_req(s, vs->cmd_vqs[n]); qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem)); /* TODO: add a way for SCSIBusInfo's load_request to fail, * and fail migration instead of asserting here. @@ -156,7 +179,12 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) #endif assert(req->elem.in_num <= ARRAY_SIZE(req->elem.in_sg)); assert(req->elem.out_num <= ARRAY_SIZE(req->elem.out_sg)); - virtio_scsi_parse_req(s, vs->cmd_vqs[n], req); + + if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, + sizeof(VirtIOSCSICmdResp) + vs->sense_size) < 0) { + error_report("invalid SCSI request migration data"); + exit(1); + } scsi_req_ref(sreq); req->sreq = sreq; @@ -281,29 +309,29 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) VirtIOSCSIReq *req; while ((req = virtio_scsi_pop_req(s, vq))) { - int out_size, in_size; - if (req->elem.out_num < 1 || req->elem.in_num < 1) { + int type; + + if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, + &type, sizeof(type)) < sizeof(type)) { virtio_scsi_bad_req(); - continue; - } - out_size = req->elem.out_sg[0].iov_len; - in_size = req->elem.in_sg[0].iov_len; - if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) { - if (out_size < sizeof(VirtIOSCSICtrlTMFReq) || - in_size < sizeof(VirtIOSCSICtrlTMFResp)) { + } else if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) { + if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), + sizeof(VirtIOSCSICtrlTMFResp)) < 0) { virtio_scsi_bad_req(); + } else { + virtio_scsi_do_tmf(s, req); } - virtio_scsi_do_tmf(s, req); } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY || req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { - if (out_size < sizeof(VirtIOSCSICtrlANReq) || - in_size < sizeof(VirtIOSCSICtrlANResp)) { + if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq), + sizeof(VirtIOSCSICtrlANResp)) < 0) { virtio_scsi_bad_req(); + } else { + req->resp.an->event_actual = 0; + req->resp.an->response = VIRTIO_SCSI_S_OK; } - req->resp.an->event_actual = 0; - req->resp.an->response = VIRTIO_SCSI_S_OK; } virtio_scsi_complete_req(req); } @@ -373,23 +401,18 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) while ((req = virtio_scsi_pop_req(s, vq))) { SCSIDevice *d; - int out_size, in_size; - if (req->elem.out_num < 1 || req->elem.in_num < 1) { - virtio_scsi_bad_req(); - } - - out_size = req->elem.out_sg[0].iov_len; - in_size = req->elem.in_sg[0].iov_len; - if (out_size < sizeof(VirtIOSCSICmdReq) + vs->cdb_size || - in_size < sizeof(VirtIOSCSICmdResp) + vs->sense_size) { - virtio_scsi_bad_req(); - } - + int rc; if (req->elem.out_num > 1 && req->elem.in_num > 1) { virtio_scsi_fail_cmd_req(req); continue; } + rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, + sizeof(VirtIOSCSICmdResp) + vs->sense_size); + if (rc < 0) { + virtio_scsi_bad_req(); + } + d = virtio_scsi_device_find(s, req->req.cmd->lun); if (!d) { req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET; -- cgit v1.1 From b0b4ea17dc7572ca79b2bb54447de5333dada5b2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 10 Jun 2014 16:53:39 +0200 Subject: virtio-scsi: add target swap for VirtIOSCSICtrlTMFReq fields Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index f013e35..ec9a536 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -207,6 +207,7 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */ req->resp.tmf->response = VIRTIO_SCSI_S_OK; + tswap32s(&req->req.tmf->subtype); switch (req->req.tmf->subtype) { case VIRTIO_SCSI_T_TMF_ABORT_TASK: case VIRTIO_SCSI_T_TMF_QUERY_TASK: @@ -314,8 +315,11 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, &type, sizeof(type)) < sizeof(type)) { virtio_scsi_bad_req(); + continue; + } - } else if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) { + tswap32s(&req->req.tmf->type); + if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) { if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), sizeof(VirtIOSCSICtrlTMFResp)) < 0) { virtio_scsi_bad_req(); -- cgit v1.1 From 57fbae6e2cbbea037196a9ad67487c3fe78217f0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 10 Jun 2014 16:39:24 +0200 Subject: virtio-scsi: add extra argument and return type to qemu_sgl_concat Will be used for anylayout support. Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index ec9a536..0718626 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -95,14 +95,27 @@ static void virtio_scsi_bad_req(void) exit(1); } -static void qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *sg, - hwaddr *addr, int num) +static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov, + hwaddr *addr, int num, size_t skip) { QEMUSGList *qsgl = &req->qsgl; - - while (num--) { - qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len); + size_t copied = 0; + + while (num) { + if (skip >= iov->iov_len) { + skip -= iov->iov_len; + } else { + qemu_sglist_add(qsgl, *addr + skip, iov->iov_len - skip); + copied += iov->iov_len - skip; + skip = 0; + } + iov++; + addr++; + num--; } + + assert(skip == 0); + return copied; } static int virtio_scsi_parse_req(VirtIOSCSIReq *req, @@ -127,11 +140,11 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req, if (req->elem.out_num > 1) { qemu_sgl_concat(req, &req->elem.out_sg[1], &req->elem.out_addr[1], - req->elem.out_num - 1); + req->elem.out_num - 1, 0); } else { qemu_sgl_concat(req, &req->elem.in_sg[1], &req->elem.in_addr[1], - req->elem.in_num - 1); + req->elem.in_num - 1, 0); } return 0; -- cgit v1.1 From 489c7901a6e92d65afab333d498b3790b73f7153 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 10 Jun 2014 16:58:19 +0200 Subject: virtio-scsi: prepare sense data handling for any_layout Retrieve sense and copy it to guest memory, to prepare for when we will use qemu_iovec_from_buf. Swap response and request, since we'll use the tail of VirtIOSCSIReq for the CDB. Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 0718626..fbc7db7 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -26,12 +26,7 @@ typedef struct VirtIOSCSIReq { VirtQueueElement elem; QEMUSGList qsgl; SCSIRequest *sreq; - union { - char *buf; - VirtIOSCSICmdReq *cmd; - VirtIOSCSICtrlTMFReq *tmf; - VirtIOSCSICtrlANReq *an; - } req; + size_t resp_size; union { char *buf; VirtIOSCSICmdResp *cmd; @@ -39,6 +34,12 @@ typedef struct VirtIOSCSIReq { VirtIOSCSICtrlANResp *an; VirtIOSCSIEvent *event; } resp; + union { + char *buf; + VirtIOSCSICmdReq *cmd; + VirtIOSCSICtrlTMFReq *tmf; + VirtIOSCSICtrlANReq *an; + } req; } VirtIOSCSIReq; static inline int virtio_scsi_get_lun(uint8_t *lun) @@ -136,6 +137,7 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req, return -EINVAL; } req->resp.buf = req->elem.in_sg[0].iov_base; + req->resp_size = resp_size; if (req->elem.out_num > 1) { qemu_sgl_concat(req, &req->elem.out_sg[1], @@ -358,8 +360,7 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, size_t resid) { VirtIOSCSIReq *req = r->hba_private; - VirtIOSCSI *s = req->dev; - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + uint8_t sense[SCSI_SENSE_BUF_SIZE]; uint32_t sense_len; if (r->io_canceled) { @@ -372,8 +373,9 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, req->resp.cmd->resid = tswap32(resid); } else { req->resp.cmd->resid = 0; - sense_len = scsi_req_get_sense(r, req->resp.cmd->sense, - vs->sense_size); + sense_len = scsi_req_get_sense(r, sense, sizeof(sense)); + sense_len = MIN(sense_len, req->resp_size - sizeof(req->resp.cmd)); + memcpy(req->resp.cmd->sense, sense, sense_len); req->resp.cmd->sense_len = tswap32(sense_len); } virtio_scsi_complete_req(req); -- cgit v1.1 From a3de269ccc6f724e40702d8a9adcc3d41d0db369 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 10 Jun 2014 20:16:20 +0200 Subject: virtio-scsi: introduce virtio_scsi_complete_cmd_req This is also related to sense handling, and will be used by anylayout. Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index fbc7db7..06fda89 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -356,6 +356,11 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) } } +static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req) +{ + virtio_scsi_complete_req(req); +} + static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, size_t resid) { @@ -378,7 +383,7 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, memcpy(req->resp.cmd->sense, sense, sense_len); req->resp.cmd->sense_len = tswap32(sense_len); } - virtio_scsi_complete_req(req); + virtio_scsi_complete_cmd_req(req); } static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r) @@ -400,13 +405,13 @@ static void virtio_scsi_request_cancelled(SCSIRequest *r) } else { req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED; } - virtio_scsi_complete_req(req); + virtio_scsi_complete_cmd_req(req); } static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) { req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE; - virtio_scsi_complete_req(req); + virtio_scsi_complete_cmd_req(req); } static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) @@ -435,7 +440,7 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) d = virtio_scsi_device_find(s, req->req.cmd->lun); if (!d) { req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET; - virtio_scsi_complete_req(req); + virtio_scsi_complete_cmd_req(req); continue; } req->sreq = scsi_req_new(d, req->req.cmd->tag, @@ -449,7 +454,7 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) if (req->sreq->cmd.mode != req_mode || req->sreq->cmd.xfer > req->qsgl.size) { req->resp.cmd->response = VIRTIO_SCSI_S_OVERRUN; - virtio_scsi_complete_req(req); + virtio_scsi_complete_cmd_req(req); continue; } } -- cgit v1.1 From 3eff1f46f08a360a4ae9f834ce9fef4c45bf6f0f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 10 Jun 2014 16:40:31 +0200 Subject: virtio-scsi: add support for the any_layout feature Store the request and response headers by value, and let virtio_scsi_parse_req check that there is only one of datain and dataout. Signed-off-by: Paolo Bonzini --- hw/scsi/virtio-scsi.c | 193 +++++++++++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 89 deletions(-) (limited to 'hw') diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 06fda89..3870c47 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -27,21 +27,27 @@ typedef struct VirtIOSCSIReq { QEMUSGList qsgl; SCSIRequest *sreq; size_t resp_size; + enum SCSIXferMode mode; + QEMUIOVector resp_iov; union { - char *buf; - VirtIOSCSICmdResp *cmd; - VirtIOSCSICtrlTMFResp *tmf; - VirtIOSCSICtrlANResp *an; - VirtIOSCSIEvent *event; + VirtIOSCSICmdResp cmd; + VirtIOSCSICtrlTMFResp tmf; + VirtIOSCSICtrlANResp an; + VirtIOSCSIEvent event; } resp; union { - char *buf; - VirtIOSCSICmdReq *cmd; - VirtIOSCSICtrlTMFReq *tmf; - VirtIOSCSICtrlANReq *an; + struct { + VirtIOSCSICmdReq cmd; + uint8_t cdb[]; + } QEMU_PACKED; + VirtIOSCSICtrlTMFReq tmf; + VirtIOSCSICtrlANReq an; } req; } VirtIOSCSIReq; +QEMU_BUILD_BUG_ON(offsetof(VirtIOSCSIReq, req.cdb) != + offsetof(VirtIOSCSIReq, req.cmd) + sizeof(VirtIOSCSICmdReq)); + static inline int virtio_scsi_get_lun(uint8_t *lun) { return ((lun[2] << 8) | lun[3]) & 0x3FFF; @@ -61,17 +67,21 @@ static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) static VirtIOSCSIReq *virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req; - req = g_malloc(sizeof(*req)); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s); + + req = g_malloc0(sizeof(*req) + vs->cdb_size); req->vq = vq; req->dev = s; req->sreq = NULL; qemu_sglist_init(&req->qsgl, DEVICE(s), 8, &address_space_memory); + qemu_iovec_init(&req->resp_iov, 1); return req; } static void virtio_scsi_free_req(VirtIOSCSIReq *req) { + qemu_iovec_destroy(&req->resp_iov); qemu_sglist_destroy(&req->qsgl); g_free(req); } @@ -81,7 +91,9 @@ static void virtio_scsi_complete_req(VirtIOSCSIReq *req) VirtIOSCSI *s = req->dev; VirtQueue *vq = req->vq; VirtIODevice *vdev = VIRTIO_DEVICE(s); - virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len); + + qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size); + virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size); if (req->sreq) { req->sreq->hba_private = NULL; scsi_req_unref(req->sreq); @@ -122,31 +134,35 @@ static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov, static int virtio_scsi_parse_req(VirtIOSCSIReq *req, unsigned req_size, unsigned resp_size) { - if (req->elem.in_num == 0) { - return -EINVAL; - } + size_t in_size, out_size; - if (req->elem.out_sg[0].iov_len < req_size) { + if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0, + &req->req, req_size) < req_size) { return -EINVAL; } - if (req->elem.out_num) { - req->req.buf = req->elem.out_sg[0].iov_base; - } - if (req->elem.in_sg[0].iov_len < resp_size) { + if (qemu_iovec_concat_iov(&req->resp_iov, + req->elem.in_sg, req->elem.in_num, 0, + resp_size) < resp_size) { return -EINVAL; } - req->resp.buf = req->elem.in_sg[0].iov_base; req->resp_size = resp_size; - if (req->elem.out_num > 1) { - qemu_sgl_concat(req, &req->elem.out_sg[1], - &req->elem.out_addr[1], - req->elem.out_num - 1, 0); - } else { - qemu_sgl_concat(req, &req->elem.in_sg[1], - &req->elem.in_addr[1], - req->elem.in_num - 1, 0); + out_size = qemu_sgl_concat(req, req->elem.out_sg, + &req->elem.out_addr[0], req->elem.out_num, + req_size); + in_size = qemu_sgl_concat(req, req->elem.in_sg, + &req->elem.in_addr[0], req->elem.in_num, + resp_size); + + if (out_size && in_size) { + return -ENOTSUP; + } + + if (out_size) { + req->mode = SCSI_XFER_TO_DEV; + } else if (in_size) { + req->mode = SCSI_XFER_FROM_DEV; } return 0; @@ -204,37 +220,34 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) scsi_req_ref(sreq); req->sreq = sreq; if (req->sreq->cmd.mode != SCSI_XFER_NONE) { - int req_mode = - (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV); - - assert(req->sreq->cmd.mode == req_mode); + assert(req->sreq->cmd.mode == req->mode); } return req; } static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) { - SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf->lun); + SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf.lun); SCSIRequest *r, *next; BusChild *kid; int target; /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */ - req->resp.tmf->response = VIRTIO_SCSI_S_OK; + req->resp.tmf.response = VIRTIO_SCSI_S_OK; - tswap32s(&req->req.tmf->subtype); - switch (req->req.tmf->subtype) { + tswap32s(&req->req.tmf.subtype); + switch (req->req.tmf.subtype) { case VIRTIO_SCSI_T_TMF_ABORT_TASK: case VIRTIO_SCSI_T_TMF_QUERY_TASK: if (!d) { goto fail; } - if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) { + if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { goto incorrect_lun; } QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { VirtIOSCSIReq *cmd_req = r->hba_private; - if (cmd_req && cmd_req->req.cmd->tag == req->req.tmf->tag) { + if (cmd_req && cmd_req->req.cmd.tag == req->req.tmf.tag) { break; } } @@ -244,11 +257,11 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) * check for it in the loop above. */ assert(r->hba_private); - if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) { + if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) { /* "If the specified command is present in the task set, then * return a service response set to FUNCTION SUCCEEDED". */ - req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; + req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; } else { scsi_req_cancel(r); } @@ -259,7 +272,7 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) if (!d) { goto fail; } - if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) { + if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { goto incorrect_lun; } s->resetting++; @@ -273,16 +286,16 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) if (!d) { goto fail; } - if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) { + if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { goto incorrect_lun; } QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { if (r->hba_private) { - if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) { + if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) { /* "If there is any command present in the task set, then * return a service response set to FUNCTION SUCCEEDED". */ - req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; + req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; break; } else { scsi_req_cancel(r); @@ -292,7 +305,7 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) break; case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: - target = req->req.tmf->lun[1]; + target = req->req.tmf.lun[1]; s->resetting++; QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { d = DO_UPCAST(SCSIDevice, qdev, kid->child); @@ -305,18 +318,18 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) case VIRTIO_SCSI_T_TMF_CLEAR_ACA: default: - req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_REJECTED; + req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_REJECTED; break; } return; incorrect_lun: - req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN; + req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN; return; fail: - req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET; + req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET; } static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) @@ -333,8 +346,8 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) continue; } - tswap32s(&req->req.tmf->type); - if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) { + tswap32s(&req->req.tmf.type); + if (req->req.tmf.type == VIRTIO_SCSI_T_TMF) { if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq), sizeof(VirtIOSCSICtrlTMFResp)) < 0) { virtio_scsi_bad_req(); @@ -342,14 +355,14 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) virtio_scsi_do_tmf(s, req); } - } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY || - req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { + } else if (req->req.tmf.type == VIRTIO_SCSI_T_AN_QUERY || + req->req.tmf.type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq), sizeof(VirtIOSCSICtrlANResp)) < 0) { virtio_scsi_bad_req(); } else { - req->resp.an->event_actual = 0; - req->resp.an->response = VIRTIO_SCSI_S_OK; + req->resp.an.event_actual = 0; + req->resp.an.response = VIRTIO_SCSI_S_OK; } } virtio_scsi_complete_req(req); @@ -358,6 +371,10 @@ static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req) { + /* Sense data is not in req->resp and is copied separately + * in virtio_scsi_command_complete. + */ + req->resp_size = sizeof(VirtIOSCSICmdResp); virtio_scsi_complete_req(req); } @@ -372,16 +389,17 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, return; } - req->resp.cmd->response = VIRTIO_SCSI_S_OK; - req->resp.cmd->status = status; - if (req->resp.cmd->status == GOOD) { - req->resp.cmd->resid = tswap32(resid); + req->resp.cmd.response = VIRTIO_SCSI_S_OK; + req->resp.cmd.status = status; + if (req->resp.cmd.status == GOOD) { + req->resp.cmd.resid = tswap32(resid); } else { - req->resp.cmd->resid = 0; + req->resp.cmd.resid = 0; sense_len = scsi_req_get_sense(r, sense, sizeof(sense)); - sense_len = MIN(sense_len, req->resp_size - sizeof(req->resp.cmd)); - memcpy(req->resp.cmd->sense, sense, sense_len); - req->resp.cmd->sense_len = tswap32(sense_len); + sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd)); + qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd), + &req->resp, sense_len); + req->resp.cmd.sense_len = tswap32(sense_len); } virtio_scsi_complete_cmd_req(req); } @@ -401,16 +419,16 @@ static void virtio_scsi_request_cancelled(SCSIRequest *r) return; } if (req->dev->resetting) { - req->resp.cmd->response = VIRTIO_SCSI_S_RESET; + req->resp.cmd.response = VIRTIO_SCSI_S_RESET; } else { - req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED; + req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED; } virtio_scsi_complete_cmd_req(req); } static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) { - req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE; + req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE; virtio_scsi_complete_cmd_req(req); } @@ -426,37 +444,34 @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) while ((req = virtio_scsi_pop_req(s, vq))) { SCSIDevice *d; int rc; - if (req->elem.out_num > 1 && req->elem.in_num > 1) { - virtio_scsi_fail_cmd_req(req); - continue; - } rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size, sizeof(VirtIOSCSICmdResp) + vs->sense_size); if (rc < 0) { - virtio_scsi_bad_req(); + if (rc == -ENOTSUP) { + virtio_scsi_fail_cmd_req(req); + } else { + virtio_scsi_bad_req(); + } + continue; } - d = virtio_scsi_device_find(s, req->req.cmd->lun); + d = virtio_scsi_device_find(s, req->req.cmd.lun); if (!d) { - req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET; + req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; virtio_scsi_complete_cmd_req(req); continue; } - req->sreq = scsi_req_new(d, req->req.cmd->tag, - virtio_scsi_get_lun(req->req.cmd->lun), - req->req.cmd->cdb, req); - - if (req->sreq->cmd.mode != SCSI_XFER_NONE) { - int req_mode = - (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV); - - if (req->sreq->cmd.mode != req_mode || - req->sreq->cmd.xfer > req->qsgl.size) { - req->resp.cmd->response = VIRTIO_SCSI_S_OVERRUN; - virtio_scsi_complete_cmd_req(req); - continue; - } + req->sreq = scsi_req_new(d, req->req.cmd.tag, + virtio_scsi_get_lun(req->req.cmd.lun), + req->req.cdb, req); + + if (req->sreq->cmd.mode != SCSI_XFER_NONE + && (req->sreq->cmd.mode != req->mode || + req->sreq->cmd.xfer > req->qsgl.size)) { + req->resp.cmd.response = VIRTIO_SCSI_S_OVERRUN; + virtio_scsi_complete_cmd_req(req); + continue; } n = scsi_req_enqueue(req->sreq); @@ -560,7 +575,7 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, return; } - if (req->elem.out_num || req->elem.in_num != 1) { + if (req->elem.out_num) { virtio_scsi_bad_req(); } @@ -569,12 +584,12 @@ static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev, s->events_dropped = false; } - in_size = req->elem.in_sg[0].iov_len; + in_size = iov_size(req->elem.in_sg, req->elem.in_num); if (in_size < sizeof(VirtIOSCSIEvent)) { virtio_scsi_bad_req(); } - evt = req->resp.event; + evt = &req->resp.event; memset(evt, 0, sizeof(VirtIOSCSIEvent)); evt->event = event; evt->reason = reason; -- cgit v1.1 From 91d670fbf9945ca4ecbd123affb36889e7fe8a5d Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 19 Jun 2014 16:12:00 +0800 Subject: virtio-scsi: define dummy handle_output for vhost-scsi vqs vhost userspace needn't to handle vq's notification from guest, so define dummy handle_output callback for all vqs of vhost-scsi. In some corner cases(such as when handling vq's reset from VM), virtio-pci still trys to handle pending virtio-scsi events, then object check failure inside virtio_scsi_handle_event() for vhost-scsi can be triggered. The issue can be reproduced by 'rmmod virtio-scsi', 'system sleep' or reboot inside VM. Cc: qemu-stable@nongnu.org Cc: Anthony Liguori Cc: "Michael S. Tsirkin" Cc: Paolo Bonzini Signed-off-by: Ming Lei Signed-off-by: Paolo Bonzini --- hw/scsi/vhost-scsi.c | 8 +++++++- hw/scsi/virtio-scsi.c | 14 +++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'hw') diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 668bafa..cc8df4e 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -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; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 3870c47..8c8c9d1 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -667,7 +667,9 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = { .load_request = virtio_scsi_load_request, }; -void virtio_scsi_common_realize(DeviceState *dev, Error **errp) +void virtio_scsi_common_realize(DeviceState *dev, Error **errp, + HandleOutput ctrl, HandleOutput evt, + HandleOutput cmd) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev); @@ -681,12 +683,12 @@ void virtio_scsi_common_realize(DeviceState *dev, Error **errp) s->cdb_size = VIRTIO_SCSI_CDB_SIZE; s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, - virtio_scsi_handle_ctrl); + ctrl); s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, - virtio_scsi_handle_event); + evt); for (i = 0; i < s->conf.num_queues; i++) { s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, - virtio_scsi_handle_cmd); + cmd); } } @@ -697,7 +699,9 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) static int virtio_scsi_id; Error *err = NULL; - virtio_scsi_common_realize(dev, &err); + virtio_scsi_common_realize(dev, &err, virtio_scsi_handle_ctrl, + virtio_scsi_handle_event, + virtio_scsi_handle_cmd); if (err != NULL) { error_propagate(errp, err); return; -- cgit v1.1