2011-02-11 11:40:59 +03:00
|
|
|
/*
|
|
|
|
* Virtio SCSI HBA
|
|
|
|
*
|
|
|
|
* Copyright IBM, Corp. 2010
|
|
|
|
* Copyright Red Hat, Inc. 2011
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
|
|
|
* Paolo Bonzini <pbonzini@redhat.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
|
|
|
* See the COPYING file in the top-level directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-01-26 21:17:07 +03:00
|
|
|
#include "qemu/osdep.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 11:01:28 +03:00
|
|
|
#include "qapi/error.h"
|
2015-02-17 00:36:20 +03:00
|
|
|
#include "standard-headers/linux/virtio_ids.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/virtio/virtio-scsi.h"
|
2013-02-04 14:37:52 +04:00
|
|
|
#include "qemu/error-report.h"
|
2014-06-10 18:21:18 +04:00
|
|
|
#include "qemu/iov.h"
|
2014-10-07 15:59:18 +04:00
|
|
|
#include "sysemu/block-backend.h"
|
2016-06-22 20:11:19 +03:00
|
|
|
#include "hw/scsi/scsi.h"
|
2017-08-22 10:23:55 +03:00
|
|
|
#include "scsi/constants.h"
|
2016-06-22 20:11:19 +03:00
|
|
|
#include "hw/virtio/virtio-bus.h"
|
2014-06-24 21:48:53 +04:00
|
|
|
#include "hw/virtio/virtio-access.h"
|
2011-02-11 11:40:59 +03:00
|
|
|
|
2011-11-14 19:58:41 +04:00
|
|
|
static inline int virtio_scsi_get_lun(uint8_t *lun)
|
|
|
|
{
|
|
|
|
return ((lun[2] << 8) | lun[3]) & 0x3FFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun)
|
|
|
|
{
|
|
|
|
if (lun[0] != 1) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun));
|
|
|
|
}
|
|
|
|
|
2016-02-04 17:26:51 +03:00
|
|
|
void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req)
|
2014-06-10 18:21:18 +04:00
|
|
|
{
|
2017-07-04 15:21:06 +03:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
2016-02-14 20:17:10 +03:00
|
|
|
const size_t zero_skip =
|
|
|
|
offsetof(VirtIOSCSIReq, resp_iov) + sizeof(req->resp_iov);
|
2014-06-10 18:21:18 +04:00
|
|
|
|
|
|
|
req->vq = vq;
|
|
|
|
req->dev = s;
|
2017-07-04 15:21:06 +03:00
|
|
|
qemu_sglist_init(&req->qsgl, DEVICE(s), 8, vdev->dma_as);
|
2014-06-10 18:40:31 +04:00
|
|
|
qemu_iovec_init(&req->resp_iov, 1);
|
2014-09-16 11:20:18 +04:00
|
|
|
memset((uint8_t *)req + zero_skip, 0, sizeof(*req) - zero_skip);
|
2014-06-10 18:21:18 +04:00
|
|
|
}
|
|
|
|
|
2014-08-06 09:35:04 +04:00
|
|
|
void virtio_scsi_free_req(VirtIOSCSIReq *req)
|
2014-06-10 18:21:18 +04:00
|
|
|
{
|
2014-06-10 18:40:31 +04:00
|
|
|
qemu_iovec_destroy(&req->resp_iov);
|
2014-06-10 18:21:18 +04:00
|
|
|
qemu_sglist_destroy(&req->qsgl);
|
2015-10-01 13:59:01 +03:00
|
|
|
g_free(req);
|
2014-06-10 18:21:18 +04:00
|
|
|
}
|
|
|
|
|
2011-02-13 13:55:52 +03:00
|
|
|
static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
|
|
|
|
{
|
|
|
|
VirtIOSCSI *s = req->dev;
|
|
|
|
VirtQueue *vq = req->vq;
|
2013-03-21 18:15:18 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
2014-06-10 18:40:31 +04:00
|
|
|
|
|
|
|
qemu_iovec_from_buf(&req->resp_iov, 0, &req->resp, req->resp_size);
|
2016-02-14 20:17:10 +03:00
|
|
|
virtqueue_push(vq, &req->elem, req->qsgl.size + req->resp_iov.size);
|
2016-04-06 13:16:24 +03:00
|
|
|
if (s->dataplane_started && !s->dataplane_fenced) {
|
virtio: set ISR on dataplane notifications
Dataplane has been omitting forever the step of setting ISR when
an interrupt is raised. This caused little breakage, because the
specification actually says that ISR may not be updated in MSI mode.
Some versions of the Windows drivers however didn't clear MSI mode
correctly, and proceeded using polling mode (using ISR, not the used
ring index!) for crashdump and hibernation. If it were just crashdump
and hibernation it would not be a big deal, but recent releases of
Windows do not really shut down, but rather log out and hibernate to
make the next startup faster. Hence, this manifested as a more serious
hang during shutdown with e.g. Windows 8.1 and virtio-win 1.8.0 RPMs.
Newer versions fixed this, while older versions do not use MSI at all.
The failure has always been there for virtio dataplane, but it became
visible after commits 9ffe337 ("virtio-blk: always use dataplane path
if ioeventfd is active", 2016-10-30) and ad07cd6 ("virtio-scsi: always
use dataplane path if ioeventfd is active", 2016-10-30) made virtio-blk
and virtio-scsi always use the dataplane code under KVM. The good news
therefore is that it was not a bug in the patches---they were doing
exactly what they were meant for, i.e. shake out remaining dataplane bugs.
The fix is not hard, so it's worth arranging for the broken drivers.
The virtio_should_notify+event_notifier_set pair that is common to
virtio-blk and virtio-scsi dataplane is replaced with a new public
function virtio_notify_irqfd that also sets ISR. The irqfd emulation
code now need not set ISR anymore, so virtio_irq is removed.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Tested-by: Farhan Ali <alifm@linux.vnet.ibm.com>
Tested-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-11-18 18:07:02 +03:00
|
|
|
virtio_notify_irqfd(vdev, vq);
|
2014-09-23 11:49:25 +04:00
|
|
|
} else {
|
|
|
|
virtio_notify(vdev, vq);
|
|
|
|
}
|
|
|
|
|
2011-02-13 13:55:52 +03:00
|
|
|
if (req->sreq) {
|
|
|
|
req->sreq->hba_private = NULL;
|
|
|
|
scsi_req_unref(req->sreq);
|
|
|
|
}
|
2014-06-10 18:21:18 +04:00
|
|
|
virtio_scsi_free_req(req);
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
|
|
|
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
static void virtio_scsi_bad_req(VirtIOSCSIReq *req)
|
2011-02-13 13:55:52 +03:00
|
|
|
{
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
virtio_error(VIRTIO_DEVICE(req->dev), "wrong size for virtio-scsi headers");
|
|
|
|
virtqueue_detach_element(req->vq, &req->elem, 0);
|
|
|
|
virtio_scsi_free_req(req);
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
|
|
|
|
2014-06-10 18:39:24 +04:00
|
|
|
static size_t qemu_sgl_concat(VirtIOSCSIReq *req, struct iovec *iov,
|
|
|
|
hwaddr *addr, int num, size_t skip)
|
2011-02-13 13:55:52 +03:00
|
|
|
{
|
2013-06-03 16:17:19 +04:00
|
|
|
QEMUSGList *qsgl = &req->qsgl;
|
2014-06-10 18:39:24 +04:00
|
|
|
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--;
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
2014-06-10 18:39:24 +04:00
|
|
|
|
|
|
|
assert(skip == 0);
|
|
|
|
return copied;
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
|
|
|
|
2014-06-10 18:21:18 +04:00
|
|
|
static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
|
|
|
|
unsigned req_size, unsigned resp_size)
|
2011-02-13 13:55:52 +03:00
|
|
|
{
|
2014-11-07 16:00:02 +03:00
|
|
|
VirtIODevice *vdev = (VirtIODevice *) req->dev;
|
2014-06-10 18:40:31 +04:00
|
|
|
size_t in_size, out_size;
|
2014-06-10 18:21:18 +04:00
|
|
|
|
2014-06-10 18:40:31 +04:00
|
|
|
if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
|
|
|
|
&req->req, req_size) < req_size) {
|
2014-06-10 18:21:18 +04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2014-06-10 18:40:31 +04:00
|
|
|
if (qemu_iovec_concat_iov(&req->resp_iov,
|
|
|
|
req->elem.in_sg, req->elem.in_num, 0,
|
|
|
|
resp_size) < resp_size) {
|
2014-06-10 18:21:18 +04:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
2014-11-07 16:00:02 +03:00
|
|
|
|
2014-06-10 18:58:19 +04:00
|
|
|
req->resp_size = resp_size;
|
2011-02-13 13:55:52 +03:00
|
|
|
|
2014-11-07 16:00:02 +03:00
|
|
|
/* Old BIOSes left some padding by mistake after the req_size/resp_size.
|
|
|
|
* As a workaround, always consider the first buffer as the virtio-scsi
|
|
|
|
* request/response, making the payload start at the second element
|
|
|
|
* of the iovec.
|
|
|
|
*
|
|
|
|
* The actual length of the response header, stored in req->resp_size,
|
|
|
|
* does not change.
|
|
|
|
*
|
|
|
|
* TODO: always disable this workaround for virtio 1.0 devices.
|
|
|
|
*/
|
2015-08-17 12:48:29 +03:00
|
|
|
if (!virtio_vdev_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) {
|
2015-03-13 10:55:54 +03:00
|
|
|
if (req->elem.out_num) {
|
|
|
|
req_size = req->elem.out_sg[0].iov_len;
|
|
|
|
}
|
|
|
|
if (req->elem.in_num) {
|
|
|
|
resp_size = req->elem.in_sg[0].iov_len;
|
|
|
|
}
|
2014-11-07 16:00:02 +03:00
|
|
|
}
|
|
|
|
|
2014-06-10 18:40:31 +04:00
|
|
|
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;
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
2014-06-10 18:21:18 +04:00
|
|
|
|
|
|
|
return 0;
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
|
|
|
|
{
|
2016-02-04 17:26:51 +03:00
|
|
|
VirtIOSCSICommon *vs = (VirtIOSCSICommon *)s;
|
|
|
|
VirtIOSCSIReq *req;
|
|
|
|
|
|
|
|
req = virtqueue_pop(vq, sizeof(VirtIOSCSIReq) + vs->cdb_size);
|
|
|
|
if (!req) {
|
2011-02-13 13:55:52 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
2016-02-04 17:26:51 +03:00
|
|
|
virtio_scsi_init_req(s, vq, req);
|
2011-02-13 13:55:52 +03:00
|
|
|
return req;
|
|
|
|
}
|
|
|
|
|
2011-12-02 18:23:15 +04:00
|
|
|
static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
|
|
|
|
{
|
|
|
|
VirtIOSCSIReq *req = sreq->hba_private;
|
2013-03-29 05:08:15 +04:00
|
|
|
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(req->dev);
|
2016-05-20 21:04:21 +03:00
|
|
|
uint32_t n = virtio_get_queue_index(req->vq) - 2;
|
2011-12-02 18:23:15 +04:00
|
|
|
|
2013-03-29 05:08:15 +04:00
|
|
|
assert(n < vs->conf.num_queues);
|
2012-04-06 12:20:43 +04:00
|
|
|
qemu_put_be32s(f, &n);
|
2016-01-31 13:28:59 +03:00
|
|
|
qemu_put_virtqueue_element(f, &req->elem);
|
2011-12-02 18:23:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
|
|
|
|
{
|
|
|
|
SCSIBus *bus = sreq->bus;
|
|
|
|
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
|
2013-03-29 05:08:15 +04:00
|
|
|
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
2016-12-30 13:09:10 +03:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
2011-12-02 18:23:15 +04:00
|
|
|
VirtIOSCSIReq *req;
|
2012-04-06 12:20:43 +04:00
|
|
|
uint32_t n;
|
2011-12-02 18:23:15 +04:00
|
|
|
|
2012-04-06 12:20:43 +04:00
|
|
|
qemu_get_be32s(f, &n);
|
2013-03-29 05:08:15 +04:00
|
|
|
assert(n < vs->conf.num_queues);
|
2016-12-30 13:09:10 +03:00
|
|
|
req = qemu_get_virtqueue_element(vdev, f,
|
|
|
|
sizeof(VirtIOSCSIReq) + vs->cdb_size);
|
2016-02-04 17:26:51 +03:00
|
|
|
virtio_scsi_init_req(s, vs->cmd_vqs[n], req);
|
2015-10-27 11:22:13 +03:00
|
|
|
|
2014-06-10 18:21:18 +04:00
|
|
|
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);
|
|
|
|
}
|
2011-12-02 18:23:15 +04:00
|
|
|
|
|
|
|
scsi_req_ref(sreq);
|
|
|
|
req->sreq = sreq;
|
|
|
|
if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
|
2014-06-10 18:40:31 +04:00
|
|
|
assert(req->sreq->cmd.mode == req->mode);
|
2011-12-02 18:23:15 +04:00
|
|
|
}
|
|
|
|
return req;
|
|
|
|
}
|
|
|
|
|
2014-09-30 07:40:23 +04:00
|
|
|
typedef struct {
|
|
|
|
Notifier notifier;
|
|
|
|
VirtIOSCSIReq *tmf_req;
|
|
|
|
} VirtIOSCSICancelNotifier;
|
|
|
|
|
|
|
|
static void virtio_scsi_cancel_notify(Notifier *notifier, void *data)
|
|
|
|
{
|
|
|
|
VirtIOSCSICancelNotifier *n = container_of(notifier,
|
|
|
|
VirtIOSCSICancelNotifier,
|
|
|
|
notifier);
|
|
|
|
|
|
|
|
if (--n->tmf_req->remaining == 0) {
|
|
|
|
virtio_scsi_complete_req(n->tmf_req);
|
|
|
|
}
|
2015-10-01 13:59:01 +03:00
|
|
|
g_free(n);
|
2014-09-30 07:40:23 +04:00
|
|
|
}
|
|
|
|
|
2016-09-14 13:17:04 +03:00
|
|
|
static inline void virtio_scsi_ctx_check(VirtIOSCSI *s, SCSIDevice *d)
|
|
|
|
{
|
|
|
|
if (s->dataplane_started && d && blk_is_available(d->conf.blk)) {
|
|
|
|
assert(blk_get_aio_context(d->conf.blk) == s->ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-30 07:40:23 +04:00
|
|
|
/* Return 0 if the request is ready to be completed and return to guest;
|
|
|
|
* -EINPROGRESS if the request is submitted and will be completed later, in the
|
|
|
|
* case of async cancellation. */
|
|
|
|
static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
|
2011-02-13 13:55:52 +03:00
|
|
|
{
|
2014-06-10 18:40:31 +04:00
|
|
|
SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf.lun);
|
2011-11-14 20:44:09 +04:00
|
|
|
SCSIRequest *r, *next;
|
2011-12-24 01:34:39 +04:00
|
|
|
BusChild *kid;
|
2011-11-14 20:44:09 +04:00
|
|
|
int target;
|
2014-09-30 07:40:23 +04:00
|
|
|
int ret = 0;
|
2011-11-14 20:44:09 +04:00
|
|
|
|
2016-09-14 13:17:04 +03:00
|
|
|
virtio_scsi_ctx_check(s, d);
|
2011-11-14 20:44:09 +04:00
|
|
|
/* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.tmf.response = VIRTIO_SCSI_S_OK;
|
2011-11-14 20:44:09 +04:00
|
|
|
|
2019-02-28 20:59:42 +03:00
|
|
|
/*
|
|
|
|
* req->req.tmf has the QEMU_PACKED attribute. Don't use virtio_tswap32s()
|
|
|
|
* to avoid compiler errors.
|
|
|
|
*/
|
|
|
|
req->req.tmf.subtype =
|
|
|
|
virtio_tswap32(VIRTIO_DEVICE(s), req->req.tmf.subtype);
|
|
|
|
|
2014-06-10 18:40:31 +04:00
|
|
|
switch (req->req.tmf.subtype) {
|
2011-11-14 20:44:09 +04:00
|
|
|
case VIRTIO_SCSI_T_TMF_ABORT_TASK:
|
|
|
|
case VIRTIO_SCSI_T_TMF_QUERY_TASK:
|
|
|
|
if (!d) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2014-06-10 18:40:31 +04:00
|
|
|
if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
|
2011-11-14 20:44:09 +04:00
|
|
|
goto incorrect_lun;
|
|
|
|
}
|
|
|
|
QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
|
2012-08-08 18:26:16 +04:00
|
|
|
VirtIOSCSIReq *cmd_req = r->hba_private;
|
2014-06-10 18:40:31 +04:00
|
|
|
if (cmd_req && cmd_req->req.cmd.tag == req->req.tmf.tag) {
|
2011-11-14 20:44:09 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-08-08 18:26:16 +04:00
|
|
|
if (r) {
|
|
|
|
/*
|
|
|
|
* Assert that the request has not been completed yet, we
|
|
|
|
* check for it in the loop above.
|
|
|
|
*/
|
|
|
|
assert(r->hba_private);
|
2014-06-10 18:40:31 +04:00
|
|
|
if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
|
2011-11-14 20:44:09 +04:00
|
|
|
/* "If the specified command is present in the task set, then
|
|
|
|
* return a service response set to FUNCTION SUCCEEDED".
|
|
|
|
*/
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
|
2011-11-14 20:44:09 +04:00
|
|
|
} else {
|
2014-09-30 07:40:23 +04:00
|
|
|
VirtIOSCSICancelNotifier *notifier;
|
|
|
|
|
|
|
|
req->remaining = 1;
|
2015-10-01 13:59:01 +03:00
|
|
|
notifier = g_new(VirtIOSCSICancelNotifier, 1);
|
2014-09-30 07:40:23 +04:00
|
|
|
notifier->tmf_req = req;
|
|
|
|
notifier->notifier.notify = virtio_scsi_cancel_notify;
|
|
|
|
scsi_req_cancel_async(r, ¬ifier->notifier);
|
|
|
|
ret = -EINPROGRESS;
|
2011-11-14 20:44:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
|
|
|
|
if (!d) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2014-06-10 18:40:31 +04:00
|
|
|
if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
|
2011-11-14 20:44:09 +04:00
|
|
|
goto incorrect_lun;
|
|
|
|
}
|
|
|
|
s->resetting++;
|
|
|
|
qdev_reset_all(&d->qdev);
|
|
|
|
s->resetting--;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
|
|
|
|
case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
|
|
|
|
case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
|
|
|
|
if (!d) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2014-06-10 18:40:31 +04:00
|
|
|
if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) {
|
2011-11-14 20:44:09 +04:00
|
|
|
goto incorrect_lun;
|
|
|
|
}
|
2014-09-30 07:40:23 +04:00
|
|
|
|
|
|
|
/* Add 1 to "remaining" until virtio_scsi_do_tmf returns.
|
|
|
|
* This way, if the bus starts calling back to the notifiers
|
|
|
|
* even before we finish the loop, virtio_scsi_cancel_notify
|
|
|
|
* will not complete the TMF too early.
|
|
|
|
*/
|
|
|
|
req->remaining = 1;
|
2011-11-14 20:44:09 +04:00
|
|
|
QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
|
|
|
|
if (r->hba_private) {
|
2014-06-10 18:40:31 +04:00
|
|
|
if (req->req.tmf.subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) {
|
2011-11-14 20:44:09 +04:00
|
|
|
/* "If there is any command present in the task set, then
|
|
|
|
* return a service response set to FUNCTION SUCCEEDED".
|
|
|
|
*/
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
|
2011-11-14 20:44:09 +04:00
|
|
|
break;
|
|
|
|
} else {
|
2014-09-30 07:40:23 +04:00
|
|
|
VirtIOSCSICancelNotifier *notifier;
|
|
|
|
|
|
|
|
req->remaining++;
|
2015-10-01 13:59:01 +03:00
|
|
|
notifier = g_new(VirtIOSCSICancelNotifier, 1);
|
2014-09-30 07:40:23 +04:00
|
|
|
notifier->notifier.notify = virtio_scsi_cancel_notify;
|
|
|
|
notifier->tmf_req = req;
|
|
|
|
scsi_req_cancel_async(r, ¬ifier->notifier);
|
2011-11-14 20:44:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-30 07:40:23 +04:00
|
|
|
if (--req->remaining > 0) {
|
|
|
|
ret = -EINPROGRESS;
|
|
|
|
}
|
2011-11-14 20:44:09 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
|
2014-06-10 18:40:31 +04:00
|
|
|
target = req->req.tmf.lun[1];
|
2011-11-14 20:44:09 +04:00
|
|
|
s->resetting++;
|
2011-12-24 01:34:39 +04:00
|
|
|
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
|
2016-01-06 12:37:46 +03:00
|
|
|
d = SCSI_DEVICE(kid->child);
|
2011-11-14 20:44:09 +04:00
|
|
|
if (d->channel == 0 && d->id == target) {
|
|
|
|
qdev_reset_all(&d->qdev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s->resetting--;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
|
|
|
|
default:
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
|
2011-11-14 20:44:09 +04:00
|
|
|
break;
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
|
|
|
|
2014-09-30 07:40:23 +04:00
|
|
|
return ret;
|
2011-11-14 20:44:09 +04:00
|
|
|
|
|
|
|
incorrect_lun:
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN;
|
2014-09-30 07:40:23 +04:00
|
|
|
return ret;
|
2011-11-14 20:44:09 +04:00
|
|
|
|
|
|
|
fail:
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET;
|
2014-09-30 07:40:23 +04:00
|
|
|
return ret;
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
|
|
|
|
2016-04-06 13:16:27 +03:00
|
|
|
static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
|
2011-02-11 11:40:59 +03:00
|
|
|
{
|
2014-08-06 09:35:01 +04:00
|
|
|
VirtIODevice *vdev = (VirtIODevice *)s;
|
2014-10-25 06:43:44 +04:00
|
|
|
uint32_t type;
|
2014-09-30 07:40:23 +04:00
|
|
|
int r = 0;
|
2011-02-13 13:55:52 +03:00
|
|
|
|
2014-08-06 09:35:01 +04:00
|
|
|
if (iov_to_buf(req->elem.out_sg, req->elem.out_num, 0,
|
|
|
|
&type, sizeof(type)) < sizeof(type)) {
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
virtio_scsi_bad_req(req);
|
2014-08-06 09:35:01 +04:00
|
|
|
return;
|
|
|
|
}
|
2014-06-10 18:21:18 +04:00
|
|
|
|
2014-10-25 06:43:44 +04:00
|
|
|
virtio_tswap32s(vdev, &type);
|
|
|
|
if (type == VIRTIO_SCSI_T_TMF) {
|
2014-08-06 09:35:01 +04:00
|
|
|
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlTMFReq),
|
|
|
|
sizeof(VirtIOSCSICtrlTMFResp)) < 0) {
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
virtio_scsi_bad_req(req);
|
|
|
|
return;
|
2014-08-06 09:35:01 +04:00
|
|
|
} else {
|
2014-09-30 07:40:23 +04:00
|
|
|
r = virtio_scsi_do_tmf(s, req);
|
2014-06-10 18:53:39 +04:00
|
|
|
}
|
2011-11-14 20:44:09 +04:00
|
|
|
|
2014-10-25 06:43:44 +04:00
|
|
|
} else if (type == VIRTIO_SCSI_T_AN_QUERY ||
|
|
|
|
type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
|
2014-08-06 09:35:01 +04:00
|
|
|
if (virtio_scsi_parse_req(req, sizeof(VirtIOSCSICtrlANReq),
|
|
|
|
sizeof(VirtIOSCSICtrlANResp)) < 0) {
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
virtio_scsi_bad_req(req);
|
|
|
|
return;
|
2014-08-06 09:35:01 +04:00
|
|
|
} else {
|
|
|
|
req->resp.an.event_actual = 0;
|
|
|
|
req->resp.an.response = VIRTIO_SCSI_S_OK;
|
2011-11-14 20:44:09 +04:00
|
|
|
}
|
2014-08-06 09:35:01 +04:00
|
|
|
}
|
2014-09-30 07:40:23 +04:00
|
|
|
if (r == 0) {
|
|
|
|
virtio_scsi_complete_req(req);
|
|
|
|
} else {
|
|
|
|
assert(r == -EINPROGRESS);
|
|
|
|
}
|
2014-08-06 09:35:01 +04:00
|
|
|
}
|
|
|
|
|
2017-02-09 11:40:47 +03:00
|
|
|
bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
|
2014-08-06 09:35:01 +04:00
|
|
|
{
|
|
|
|
VirtIOSCSIReq *req;
|
2017-02-09 11:40:47 +03:00
|
|
|
bool progress = false;
|
2014-08-06 09:35:01 +04:00
|
|
|
|
|
|
|
while ((req = virtio_scsi_pop_req(s, vq))) {
|
2017-02-09 11:40:47 +03:00
|
|
|
progress = true;
|
2014-08-06 09:35:01 +04:00
|
|
|
virtio_scsi_handle_ctrl_req(s, req);
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
2017-02-09 11:40:47 +03:00
|
|
|
return progress;
|
2011-02-13 13:55:52 +03:00
|
|
|
}
|
|
|
|
|
2016-04-06 13:16:27 +03:00
|
|
|
static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
|
|
|
{
|
|
|
|
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
|
|
|
|
|
|
|
|
if (s->ctx) {
|
2016-10-21 23:48:10 +03:00
|
|
|
virtio_device_start_ioeventfd(vdev);
|
2016-04-06 13:16:27 +03:00
|
|
|
if (!s->dataplane_fenced) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_acquire(s);
|
2016-04-06 13:16:27 +03:00
|
|
|
virtio_scsi_handle_ctrl_vq(s, vq);
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_release(s);
|
2016-04-06 13:16:27 +03:00
|
|
|
}
|
|
|
|
|
2014-06-10 22:16:20 +04:00
|
|
|
static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req)
|
|
|
|
{
|
2014-06-10 18:40:31 +04:00
|
|
|
/* Sense data is not in req->resp and is copied separately
|
|
|
|
* in virtio_scsi_command_complete.
|
|
|
|
*/
|
|
|
|
req->resp_size = sizeof(VirtIOSCSICmdResp);
|
2014-06-10 22:16:20 +04:00
|
|
|
virtio_scsi_complete_req(req);
|
|
|
|
}
|
|
|
|
|
2011-11-14 19:58:41 +04:00
|
|
|
static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
|
|
|
|
size_t resid)
|
|
|
|
{
|
|
|
|
VirtIOSCSIReq *req = r->hba_private;
|
2014-06-10 18:58:19 +04:00
|
|
|
uint8_t sense[SCSI_SENSE_BUF_SIZE];
|
2012-11-23 09:08:44 +04:00
|
|
|
uint32_t sense_len;
|
2014-06-24 21:48:53 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
|
2011-11-14 19:58:41 +04:00
|
|
|
|
2014-01-14 23:16:25 +04:00
|
|
|
if (r->io_canceled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.cmd.response = VIRTIO_SCSI_S_OK;
|
|
|
|
req->resp.cmd.status = status;
|
|
|
|
if (req->resp.cmd.status == GOOD) {
|
2014-06-24 21:48:53 +04:00
|
|
|
req->resp.cmd.resid = virtio_tswap32(vdev, resid);
|
2011-11-14 19:58:41 +04:00
|
|
|
} else {
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.cmd.resid = 0;
|
2014-06-10 18:58:19 +04:00
|
|
|
sense_len = scsi_req_get_sense(r, sense, sizeof(sense));
|
2014-06-10 18:40:31 +04:00
|
|
|
sense_len = MIN(sense_len, req->resp_iov.size - sizeof(req->resp.cmd));
|
|
|
|
qemu_iovec_from_buf(&req->resp_iov, sizeof(req->resp.cmd),
|
2014-10-27 11:51:41 +03:00
|
|
|
sense, sense_len);
|
2014-06-24 21:48:53 +04:00
|
|
|
req->resp.cmd.sense_len = virtio_tswap32(vdev, sense_len);
|
2011-11-14 19:58:41 +04:00
|
|
|
}
|
2014-06-10 22:16:20 +04:00
|
|
|
virtio_scsi_complete_cmd_req(req);
|
2011-11-14 19:58:41 +04:00
|
|
|
}
|
|
|
|
|
2014-07-16 13:04:37 +04:00
|
|
|
static int virtio_scsi_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
|
|
|
|
uint8_t *buf, void *hba_private)
|
|
|
|
{
|
|
|
|
VirtIOSCSIReq *req = hba_private;
|
|
|
|
|
|
|
|
if (cmd->len == 0) {
|
2015-03-11 16:31:29 +03:00
|
|
|
cmd->len = MIN(VIRTIO_SCSI_CDB_DEFAULT_SIZE, SCSI_CMD_BUF_SIZE);
|
2014-07-16 13:04:37 +04:00
|
|
|
memcpy(cmd->buf, buf, cmd->len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract the direction and mode directly from the request, for
|
|
|
|
* host device passthrough.
|
|
|
|
*/
|
|
|
|
cmd->xfer = req->qsgl.size;
|
2014-09-17 20:10:37 +04:00
|
|
|
cmd->mode = req->mode;
|
2014-07-16 13:04:37 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-14 19:58:41 +04:00
|
|
|
static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r)
|
|
|
|
{
|
|
|
|
VirtIOSCSIReq *req = r->hba_private;
|
|
|
|
|
|
|
|
return &req->qsgl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_scsi_request_cancelled(SCSIRequest *r)
|
|
|
|
{
|
|
|
|
VirtIOSCSIReq *req = r->hba_private;
|
|
|
|
|
|
|
|
if (!req) {
|
|
|
|
return;
|
|
|
|
}
|
2011-11-14 20:44:09 +04:00
|
|
|
if (req->dev->resetting) {
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.cmd.response = VIRTIO_SCSI_S_RESET;
|
2011-11-14 20:44:09 +04:00
|
|
|
} else {
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED;
|
2011-11-14 20:44:09 +04:00
|
|
|
}
|
2014-06-10 22:16:20 +04:00
|
|
|
virtio_scsi_complete_cmd_req(req);
|
2011-11-14 19:58:41 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
|
2011-02-13 13:55:52 +03:00
|
|
|
{
|
2014-06-10 18:40:31 +04:00
|
|
|
req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE;
|
2014-06-10 22:16:20 +04:00
|
|
|
virtio_scsi_complete_cmd_req(req);
|
2011-02-11 11:40:59 +03:00
|
|
|
}
|
|
|
|
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
|
2014-08-06 09:35:00 +04:00
|
|
|
{
|
|
|
|
VirtIOSCSICommon *vs = &s->parent_obj;
|
|
|
|
SCSIDevice *d;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = virtio_scsi_parse_req(req, sizeof(VirtIOSCSICmdReq) + vs->cdb_size,
|
|
|
|
sizeof(VirtIOSCSICmdResp) + vs->sense_size);
|
|
|
|
if (rc < 0) {
|
|
|
|
if (rc == -ENOTSUP) {
|
|
|
|
virtio_scsi_fail_cmd_req(req);
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
return -ENOTSUP;
|
2014-08-06 09:35:00 +04:00
|
|
|
} else {
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
virtio_scsi_bad_req(req);
|
|
|
|
return -EINVAL;
|
2014-08-06 09:35:00 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d = virtio_scsi_device_find(s, req->req.cmd.lun);
|
|
|
|
if (!d) {
|
|
|
|
req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
|
|
|
|
virtio_scsi_complete_cmd_req(req);
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
return -ENOENT;
|
2014-08-06 09:35:00 +04:00
|
|
|
}
|
2016-09-14 13:17:04 +03:00
|
|
|
virtio_scsi_ctx_check(s, d);
|
2014-08-06 09:35:00 +04:00
|
|
|
req->sreq = scsi_req_new(d, req->req.cmd.tag,
|
|
|
|
virtio_scsi_get_lun(req->req.cmd.lun),
|
2015-03-11 16:35:47 +03:00
|
|
|
req->req.cmd.cdb, req);
|
2014-08-06 09:35:00 +04:00
|
|
|
|
|
|
|
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);
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
return -ENOBUFS;
|
2014-08-06 09:35:00 +04:00
|
|
|
}
|
2014-09-23 11:49:29 +04:00
|
|
|
scsi_req_ref(req->sreq);
|
2014-10-07 15:59:18 +04:00
|
|
|
blk_io_plug(d->conf.blk);
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
return 0;
|
2014-09-23 11:49:27 +04:00
|
|
|
}
|
2014-08-06 09:35:00 +04:00
|
|
|
|
2016-04-06 13:16:27 +03:00
|
|
|
static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req)
|
2014-09-23 11:49:27 +04:00
|
|
|
{
|
2014-10-08 03:19:00 +04:00
|
|
|
SCSIRequest *sreq = req->sreq;
|
|
|
|
if (scsi_req_enqueue(sreq)) {
|
|
|
|
scsi_req_continue(sreq);
|
2014-08-06 09:35:00 +04:00
|
|
|
}
|
2014-10-07 15:59:18 +04:00
|
|
|
blk_io_unplug(sreq->dev->conf.blk);
|
2014-10-08 03:19:00 +04:00
|
|
|
scsi_req_unref(sreq);
|
2014-08-06 09:35:00 +04:00
|
|
|
}
|
|
|
|
|
2017-02-09 11:40:47 +03:00
|
|
|
bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
|
2011-02-11 11:40:59 +03:00
|
|
|
{
|
2014-09-23 11:49:28 +04:00
|
|
|
VirtIOSCSIReq *req, *next;
|
2016-12-01 22:26:47 +03:00
|
|
|
int ret = 0;
|
2017-02-09 11:40:47 +03:00
|
|
|
bool progress = false;
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
|
2014-09-23 11:49:28 +04:00
|
|
|
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
|
2011-02-13 13:55:52 +03:00
|
|
|
|
2016-12-01 22:26:47 +03:00
|
|
|
do {
|
|
|
|
virtio_queue_set_notification(vq, 0);
|
|
|
|
|
|
|
|
while ((req = virtio_scsi_pop_req(s, vq))) {
|
2017-02-09 11:40:47 +03:00
|
|
|
progress = true;
|
2016-12-01 22:26:47 +03:00
|
|
|
ret = virtio_scsi_handle_cmd_req_prepare(s, req);
|
|
|
|
if (!ret) {
|
|
|
|
QTAILQ_INSERT_TAIL(&reqs, req, next);
|
|
|
|
} else if (ret == -EINVAL) {
|
|
|
|
/* The device is broken and shouldn't process any request */
|
|
|
|
while (!QTAILQ_EMPTY(&reqs)) {
|
|
|
|
req = QTAILQ_FIRST(&reqs);
|
|
|
|
QTAILQ_REMOVE(&reqs, req, next);
|
|
|
|
blk_io_unplug(req->sreq->dev->conf.blk);
|
|
|
|
scsi_req_unref(req->sreq);
|
|
|
|
virtqueue_detach_element(req->vq, &req->elem, 0);
|
|
|
|
virtio_scsi_free_req(req);
|
|
|
|
}
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
}
|
2014-09-23 11:49:27 +04:00
|
|
|
}
|
2016-12-01 22:26:47 +03:00
|
|
|
|
|
|
|
virtio_queue_set_notification(vq, 1);
|
|
|
|
} while (ret != -EINVAL && !virtio_queue_empty(vq));
|
2014-09-23 11:49:28 +04:00
|
|
|
|
|
|
|
QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
|
|
|
|
virtio_scsi_handle_cmd_req_submit(s, req);
|
|
|
|
}
|
2017-02-09 11:40:47 +03:00
|
|
|
return progress;
|
2011-02-11 11:40:59 +03:00
|
|
|
}
|
|
|
|
|
2016-04-06 13:16:27 +03:00
|
|
|
static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
|
|
|
|
{
|
|
|
|
/* use non-QOM casts in the data path */
|
|
|
|
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
|
|
|
|
|
|
|
|
if (s->ctx) {
|
2016-10-21 23:48:10 +03:00
|
|
|
virtio_device_start_ioeventfd(vdev);
|
2016-04-06 13:16:27 +03:00
|
|
|
if (!s->dataplane_fenced) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_acquire(s);
|
2016-04-06 13:16:27 +03:00
|
|
|
virtio_scsi_handle_cmd_vq(s, vq);
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_release(s);
|
2016-04-06 13:16:27 +03:00
|
|
|
}
|
|
|
|
|
2011-02-11 11:40:59 +03:00
|
|
|
static void virtio_scsi_get_config(VirtIODevice *vdev,
|
|
|
|
uint8_t *config)
|
|
|
|
{
|
|
|
|
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
|
2013-03-29 05:08:15 +04:00
|
|
|
VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(vdev);
|
2011-02-11 11:40:59 +03:00
|
|
|
|
2014-06-24 21:48:53 +04:00
|
|
|
virtio_stl_p(vdev, &scsiconf->num_queues, s->conf.num_queues);
|
|
|
|
virtio_stl_p(vdev, &scsiconf->seg_max, 128 - 2);
|
|
|
|
virtio_stl_p(vdev, &scsiconf->max_sectors, s->conf.max_sectors);
|
|
|
|
virtio_stl_p(vdev, &scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
|
|
|
|
virtio_stl_p(vdev, &scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
|
|
|
|
virtio_stl_p(vdev, &scsiconf->sense_size, s->sense_size);
|
|
|
|
virtio_stl_p(vdev, &scsiconf->cdb_size, s->cdb_size);
|
|
|
|
virtio_stw_p(vdev, &scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
|
|
|
|
virtio_stw_p(vdev, &scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
|
|
|
|
virtio_stl_p(vdev, &scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
|
2011-02-11 11:40:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_scsi_set_config(VirtIODevice *vdev,
|
|
|
|
const uint8_t *config)
|
|
|
|
{
|
|
|
|
VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
|
2013-03-29 05:08:15 +04:00
|
|
|
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
2011-02-11 11:40:59 +03:00
|
|
|
|
2014-06-24 21:48:53 +04:00
|
|
|
if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) >= 65536 ||
|
|
|
|
(uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) >= 256) {
|
2016-09-30 18:13:48 +03:00
|
|
|
virtio_error(vdev,
|
|
|
|
"bad data written to virtio-scsi configuration space");
|
|
|
|
return;
|
2011-02-11 11:40:59 +03:00
|
|
|
}
|
|
|
|
|
2014-06-24 21:48:53 +04:00
|
|
|
vs->sense_size = virtio_ldl_p(vdev, &scsiconf->sense_size);
|
|
|
|
vs->cdb_size = virtio_ldl_p(vdev, &scsiconf->cdb_size);
|
2011-02-11 11:40:59 +03:00
|
|
|
}
|
|
|
|
|
2015-06-01 11:45:40 +03:00
|
|
|
static uint64_t virtio_scsi_get_features(VirtIODevice *vdev,
|
2015-07-27 12:49:19 +03:00
|
|
|
uint64_t requested_features,
|
|
|
|
Error **errp)
|
2011-02-11 11:40:59 +03:00
|
|
|
{
|
2015-04-28 14:51:13 +03:00
|
|
|
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
|
|
|
|
|
|
|
/* Firstly sync all virtio-scsi possible supported features */
|
|
|
|
requested_features |= s->host_features;
|
2011-02-11 11:40:59 +03:00
|
|
|
return requested_features;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_scsi_reset(VirtIODevice *vdev)
|
|
|
|
{
|
2013-03-29 05:08:15 +04:00
|
|
|
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
|
|
|
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
|
2011-02-11 11:40:59 +03:00
|
|
|
|
2016-10-21 23:48:10 +03:00
|
|
|
assert(!s->dataplane_started);
|
2013-01-10 18:49:08 +04:00
|
|
|
s->resetting++;
|
|
|
|
qbus_reset_all(&s->bus.qbus);
|
|
|
|
s->resetting--;
|
|
|
|
|
2015-03-11 16:31:29 +03:00
|
|
|
vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
|
|
|
|
vs->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
|
2012-07-16 16:50:27 +04:00
|
|
|
s->events_dropped = false;
|
2011-02-11 11:40:59 +03:00
|
|
|
}
|
|
|
|
|
2014-08-06 09:35:05 +04:00
|
|
|
void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
|
|
|
|
uint32_t event, uint32_t reason)
|
2012-06-20 10:47:11 +04:00
|
|
|
{
|
2013-03-29 05:08:15 +04:00
|
|
|
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
|
2014-05-16 19:44:06 +04:00
|
|
|
VirtIOSCSIReq *req;
|
2012-06-20 10:47:11 +04:00
|
|
|
VirtIOSCSIEvent *evt;
|
2013-03-21 18:15:18 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
2012-06-20 10:47:11 +04:00
|
|
|
|
2013-03-21 18:15:18 +04:00
|
|
|
if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
|
2012-10-08 18:50:51 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-14 20:17:10 +03:00
|
|
|
req = virtio_scsi_pop_req(s, vs->event_vq);
|
2012-07-02 12:47:35 +04:00
|
|
|
if (!req) {
|
|
|
|
s->events_dropped = true;
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
return;
|
2012-07-02 12:47:35 +04:00
|
|
|
}
|
2012-06-20 10:47:11 +04:00
|
|
|
|
2012-07-02 12:47:35 +04:00
|
|
|
if (s->events_dropped) {
|
|
|
|
event |= VIRTIO_SCSI_T_EVENTS_MISSED;
|
|
|
|
s->events_dropped = false;
|
|
|
|
}
|
|
|
|
|
2014-06-30 19:33:18 +04:00
|
|
|
if (virtio_scsi_parse_req(req, 0, sizeof(VirtIOSCSIEvent))) {
|
virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()
The virtio_scsi_bad_req() function is called when a guest sends a
request with missing or ill-sized headers. This generally happens
when the virtio_scsi_parse_req() function returns an error.
With this patch, virtio_scsi_bad_req() will mark the device as broken,
detach the request from the virtqueue and free it, instead of forcing
QEMU to exit.
In nearly all locations where virtio_scsi_bad_req() is called, the only
thing to do next is to return to the caller.
The virtio_scsi_handle_cmd_req_prepare() function is an exception though.
It is called in a loop by virtio_scsi_handle_cmd_vq() and passed requests
freshly popped from a cmd virtqueue; virtio_scsi_handle_cmd_req_prepare()
does some sanity checks on the request and returns a boolean flag to
indicate whether the request should be queued or not. In the latter case,
virtio_scsi_handle_cmd_req_prepare() has detected a non-fatal error and
sent a response back to the guest.
We have now a new condition to take into account: the device is broken
and should stop all processing.
The return value of virtio_scsi_handle_cmd_req_prepare() is hence changed
to an int. A return value of zero means that the request should be queued.
Other non-fatal error cases where the request shoudn't be queued return
a negative errno (values are vaguely inspired by the error condition, but
the only goal here is to discriminate the case we're interested in).
And finally, if virtio_scsi_bad_req() was called, -EINVAL is returned. In
this case, virtio_scsi_handle_cmd_vq() detaches and frees already queued
requests, instead of submitting them.
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2016-09-30 18:13:40 +03:00
|
|
|
virtio_scsi_bad_req(req);
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
return;
|
2012-07-02 12:47:35 +04:00
|
|
|
}
|
|
|
|
|
2014-06-10 18:40:31 +04:00
|
|
|
evt = &req->resp.event;
|
2012-07-02 12:47:35 +04:00
|
|
|
memset(evt, 0, sizeof(VirtIOSCSIEvent));
|
2014-06-30 19:17:17 +04:00
|
|
|
evt->event = virtio_tswap32(vdev, event);
|
|
|
|
evt->reason = virtio_tswap32(vdev, reason);
|
2012-07-02 12:47:35 +04:00
|
|
|
if (!dev) {
|
2014-01-14 23:16:26 +04:00
|
|
|
assert(event == VIRTIO_SCSI_T_EVENTS_MISSED);
|
2012-07-02 12:47:35 +04:00
|
|
|
} else {
|
2012-06-20 10:47:11 +04:00
|
|
|
evt->lun[0] = 1;
|
|
|
|
evt->lun[1] = dev->id;
|
|
|
|
|
|
|
|
/* Linux wants us to keep the same encoding we use for REPORT LUNS. */
|
|
|
|
if (dev->lun >= 256) {
|
|
|
|
evt->lun[2] = (dev->lun >> 8) | 0x40;
|
|
|
|
}
|
|
|
|
evt->lun[3] = dev->lun & 0xFF;
|
2012-07-02 12:47:35 +04:00
|
|
|
}
|
|
|
|
virtio_scsi_complete_req(req);
|
|
|
|
}
|
|
|
|
|
2017-02-09 11:40:47 +03:00
|
|
|
bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
|
2016-04-06 13:16:27 +03:00
|
|
|
{
|
|
|
|
if (s->events_dropped) {
|
|
|
|
virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
|
2017-02-09 11:40:47 +03:00
|
|
|
return true;
|
2016-04-06 13:16:27 +03:00
|
|
|
}
|
2017-02-09 11:40:47 +03:00
|
|
|
return false;
|
2016-04-06 13:16:27 +03:00
|
|
|
}
|
|
|
|
|
2012-07-02 12:47:35 +04:00
|
|
|
static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
|
|
|
|
{
|
2013-03-21 18:15:18 +04:00
|
|
|
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
2012-07-02 12:47:35 +04:00
|
|
|
|
2016-04-06 13:16:27 +03:00
|
|
|
if (s->ctx) {
|
2016-10-21 23:48:10 +03:00
|
|
|
virtio_device_start_ioeventfd(vdev);
|
2016-04-06 13:16:27 +03:00
|
|
|
if (!s->dataplane_fenced) {
|
|
|
|
return;
|
|
|
|
}
|
2012-06-20 10:47:11 +04:00
|
|
|
}
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_acquire(s);
|
2016-04-06 13:16:27 +03:00
|
|
|
virtio_scsi_handle_event_vq(s, vq);
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_release(s);
|
2012-06-20 10:47:11 +04:00
|
|
|
}
|
|
|
|
|
2012-07-16 16:22:52 +04:00
|
|
|
static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
|
|
|
|
{
|
|
|
|
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
|
2013-03-21 18:15:18 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
2012-07-16 16:22:52 +04:00
|
|
|
|
2015-08-17 12:48:29 +03:00
|
|
|
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
|
2012-07-16 16:22:52 +04:00
|
|
|
dev->type != TYPE_ROM) {
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_acquire(s);
|
2012-07-16 16:22:52 +04:00
|
|
|
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
|
|
|
|
sense.asc | (sense.ascq << 8));
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_release(s);
|
2012-07-16 16:22:52 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-26 13:28:33 +04:00
|
|
|
static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
|
|
Error **errp)
|
2012-06-20 10:47:11 +04:00
|
|
|
{
|
2014-09-26 13:28:33 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
|
2014-10-19 08:47:42 +04:00
|
|
|
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
|
|
|
SCSIDevice *sd = SCSI_DEVICE(dev);
|
|
|
|
|
2016-04-06 13:16:24 +03:00
|
|
|
if (s->ctx && !s->dataplane_fenced) {
|
2019-01-22 18:53:23 +03:00
|
|
|
AioContext *ctx;
|
2014-10-19 08:47:42 +04:00
|
|
|
if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
|
|
|
|
return;
|
2019-01-22 18:53:23 +03:00
|
|
|
}
|
|
|
|
ctx = blk_get_aio_context(sd->conf.blk);
|
|
|
|
if (ctx != s->ctx && ctx != qemu_get_aio_context()) {
|
|
|
|
error_setg(errp, "Cannot attach a blockdev that is using "
|
|
|
|
"a different iothread");
|
|
|
|
return;
|
2014-10-19 08:47:42 +04:00
|
|
|
}
|
2015-12-10 21:13:17 +03:00
|
|
|
virtio_scsi_acquire(s);
|
2015-02-15 06:06:31 +03:00
|
|
|
blk_set_aio_context(sd->conf.blk, s->ctx);
|
2015-12-10 21:13:17 +03:00
|
|
|
virtio_scsi_release(s);
|
2018-07-16 11:37:32 +03:00
|
|
|
|
2018-10-16 16:33:40 +03:00
|
|
|
}
|
2012-06-20 10:47:11 +04:00
|
|
|
|
2015-08-17 12:48:29 +03:00
|
|
|
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_acquire(s);
|
2014-10-19 08:47:42 +04:00
|
|
|
virtio_scsi_push_event(s, sd,
|
2014-09-26 13:28:33 +04:00
|
|
|
VIRTIO_SCSI_T_TRANSPORT_RESET,
|
2012-06-20 10:47:11 +04:00
|
|
|
VIRTIO_SCSI_EVT_RESET_RESCAN);
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_release(s);
|
2012-06-20 10:47:11 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-26 13:28:33 +04:00
|
|
|
static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
|
|
Error **errp)
|
2012-06-20 10:47:11 +04:00
|
|
|
{
|
2014-09-26 13:28:33 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
|
2014-10-19 08:47:42 +04:00
|
|
|
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
|
|
|
SCSIDevice *sd = SCSI_DEVICE(dev);
|
2012-06-20 10:47:11 +04:00
|
|
|
|
2015-08-17 12:48:29 +03:00
|
|
|
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_acquire(s);
|
2014-10-19 08:47:42 +04:00
|
|
|
virtio_scsi_push_event(s, sd,
|
2014-09-26 13:28:33 +04:00
|
|
|
VIRTIO_SCSI_T_TRANSPORT_RESET,
|
2012-06-20 10:47:11 +04:00
|
|
|
VIRTIO_SCSI_EVT_RESET_REMOVED);
|
virtio-scsi: Fix acquire/release in dataplane handlers
After the AioContext lock push down, there is a race between
virtio_scsi_dataplane_start and those "assert(s->ctx &&
s->dataplane_started)", because the latter doesn't isn't wrapped in
aio_context_acquire.
Reproducer is simply booting a Fedora guest with an empty
virtio-scsi-dataplane controller:
qemu-system-x86_64 \
-drive if=none,id=root,format=raw,file=Fedora-Cloud-Base-25-1.3.x86_64.raw \
-device virtio-scsi \
-device scsi-disk,drive=root,bootindex=1 \
-object iothread,id=io \
-device virtio-scsi-pci,iothread=io \
-net user,hostfwd=tcp::10022-:22 -net nic,model=virtio -m 2048 \
--enable-kvm
Fix this by moving acquire/release pairs from virtio_scsi_handle_*_vq to
their callers - and wrap the broken assertions in.
Signed-off-by: Fam Zheng <famz@redhat.com>
Message-Id: <20170317061447.16243-3-famz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2017-03-17 09:14:47 +03:00
|
|
|
virtio_scsi_release(s);
|
2012-06-20 10:47:11 +04:00
|
|
|
}
|
2014-10-19 08:47:42 +04:00
|
|
|
|
2019-01-22 18:53:21 +03:00
|
|
|
if (s->ctx) {
|
|
|
|
virtio_scsi_acquire(s);
|
|
|
|
blk_set_aio_context(sd->conf.blk, qemu_get_aio_context());
|
|
|
|
virtio_scsi_release(s);
|
|
|
|
}
|
|
|
|
|
2014-09-26 13:28:33 +04:00
|
|
|
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
|
2012-06-20 10:47:11 +04:00
|
|
|
}
|
|
|
|
|
2011-11-14 19:58:41 +04:00
|
|
|
static struct SCSIBusInfo virtio_scsi_scsi_info = {
|
|
|
|
.tcq = true,
|
|
|
|
.max_channel = VIRTIO_SCSI_MAX_CHANNEL,
|
|
|
|
.max_target = VIRTIO_SCSI_MAX_TARGET,
|
|
|
|
.max_lun = VIRTIO_SCSI_MAX_LUN,
|
|
|
|
|
|
|
|
.complete = virtio_scsi_command_complete,
|
|
|
|
.cancel = virtio_scsi_request_cancelled,
|
2012-07-16 16:22:52 +04:00
|
|
|
.change = virtio_scsi_change,
|
2014-07-16 13:04:37 +04:00
|
|
|
.parse_cdb = virtio_scsi_parse_cdb,
|
2011-11-14 19:58:41 +04:00
|
|
|
.get_sg_list = virtio_scsi_get_sg_list,
|
2011-12-02 18:23:15 +04:00
|
|
|
.save_request = virtio_scsi_save_request,
|
|
|
|
.load_request = virtio_scsi_load_request,
|
2011-11-14 19:58:41 +04:00
|
|
|
};
|
|
|
|
|
2017-04-21 15:27:07 +03:00
|
|
|
void virtio_scsi_common_realize(DeviceState *dev,
|
2016-07-13 08:09:48 +03:00
|
|
|
VirtIOHandleOutput ctrl,
|
|
|
|
VirtIOHandleOutput evt,
|
2017-04-21 15:27:07 +03:00
|
|
|
VirtIOHandleOutput cmd,
|
|
|
|
Error **errp)
|
2011-02-11 11:40:59 +03:00
|
|
|
{
|
2013-07-30 05:19:55 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
|
|
|
VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev);
|
2012-04-06 12:39:46 +04:00
|
|
|
int i;
|
2011-02-11 11:40:59 +03:00
|
|
|
|
2013-07-30 07:41:42 +04:00
|
|
|
virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI,
|
2013-03-21 18:15:19 +04:00
|
|
|
sizeof(VirtIOSCSIConfig));
|
2013-03-21 18:15:14 +04:00
|
|
|
|
2014-10-31 06:04:31 +03:00
|
|
|
if (s->conf.num_queues == 0 ||
|
2015-05-29 09:15:31 +03:00
|
|
|
s->conf.num_queues > VIRTIO_QUEUE_MAX - 2) {
|
2014-10-31 06:04:31 +03:00
|
|
|
error_setg(errp, "Invalid number of queues (= %" PRIu32 "), "
|
2014-08-26 10:30:30 +04:00
|
|
|
"must be a positive integer less than %d.",
|
2015-05-29 09:15:31 +03:00
|
|
|
s->conf.num_queues, VIRTIO_QUEUE_MAX - 2);
|
2014-10-30 14:50:26 +03:00
|
|
|
virtio_cleanup(vdev);
|
2014-08-26 10:30:30 +04:00
|
|
|
return;
|
|
|
|
}
|
2014-12-04 16:12:45 +03:00
|
|
|
s->cmd_vqs = g_new0(VirtQueue *, s->conf.num_queues);
|
2015-03-11 16:31:29 +03:00
|
|
|
s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
|
|
|
|
s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
|
2013-03-21 18:15:14 +04:00
|
|
|
|
2017-08-10 19:52:55 +03:00
|
|
|
s->ctrl_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, ctrl);
|
|
|
|
s->event_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, evt);
|
2013-03-21 18:15:11 +04:00
|
|
|
for (i = 0; i < s->conf.num_queues; i++) {
|
2017-08-10 19:52:55 +03:00
|
|
|
s->cmd_vqs[i] = virtio_add_queue(vdev, s->conf.virtqueue_size, cmd);
|
2014-09-23 11:49:30 +04:00
|
|
|
}
|
2013-03-29 05:08:15 +04:00
|
|
|
}
|
|
|
|
|
2013-07-30 05:19:55 +04:00
|
|
|
static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
|
2013-03-29 05:08:15 +04:00
|
|
|
{
|
2013-07-30 05:19:55 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
2013-07-30 07:41:42 +04:00
|
|
|
VirtIOSCSI *s = VIRTIO_SCSI(dev);
|
2013-07-21 14:16:34 +04:00
|
|
|
Error *err = NULL;
|
2013-03-29 05:08:15 +04:00
|
|
|
|
2017-04-21 15:27:07 +03:00
|
|
|
virtio_scsi_common_realize(dev,
|
|
|
|
virtio_scsi_handle_ctrl,
|
2014-06-19 12:12:00 +04:00
|
|
|
virtio_scsi_handle_event,
|
2017-04-21 15:27:07 +03:00
|
|
|
virtio_scsi_handle_cmd,
|
|
|
|
&err);
|
2013-07-30 05:19:55 +04:00
|
|
|
if (err != NULL) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
return;
|
2013-03-29 05:08:15 +04:00
|
|
|
}
|
|
|
|
|
2013-07-30 07:41:42 +04:00
|
|
|
scsi_bus_new(&s->bus, sizeof(s->bus), dev,
|
2013-08-23 22:30:03 +04:00
|
|
|
&virtio_scsi_scsi_info, vdev->bus_name);
|
2014-09-26 13:28:33 +04:00
|
|
|
/* override default SCSI bus hotplug-handler, with virtio-scsi's one */
|
2019-02-12 21:24:59 +03:00
|
|
|
qbus_set_hotplug_handler(BUS(&s->bus), OBJECT(dev), &error_abort);
|
2013-04-30 18:08:51 +04:00
|
|
|
|
2016-10-21 23:48:10 +03:00
|
|
|
virtio_scsi_dataplane_setup(s, errp);
|
2013-03-21 18:15:14 +04:00
|
|
|
}
|
|
|
|
|
2013-07-30 05:50:44 +04:00
|
|
|
void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp)
|
2013-03-29 05:08:15 +04:00
|
|
|
{
|
2013-07-30 05:50:44 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
|
|
|
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
|
2013-03-29 05:08:15 +04:00
|
|
|
|
|
|
|
g_free(vs->cmd_vqs);
|
2013-04-24 12:21:22 +04:00
|
|
|
virtio_cleanup(vdev);
|
2013-03-29 05:08:15 +04:00
|
|
|
}
|
|
|
|
|
2013-07-30 05:50:44 +04:00
|
|
|
static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
|
2013-03-21 18:15:14 +04:00
|
|
|
{
|
2017-05-18 13:28:08 +03:00
|
|
|
VirtIOSCSI *s = VIRTIO_SCSI(dev);
|
|
|
|
|
|
|
|
qbus_set_hotplug_handler(BUS(&s->bus), NULL, &error_abort);
|
2013-07-30 05:50:44 +04:00
|
|
|
virtio_scsi_common_unrealize(dev, errp);
|
2013-03-21 18:15:14 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static Property virtio_scsi_properties[] = {
|
2015-06-10 18:04:32 +03:00
|
|
|
DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1),
|
2017-08-10 19:52:55 +03:00
|
|
|
DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
|
|
|
|
parent_obj.conf.virtqueue_size, 128),
|
2015-06-10 18:04:32 +03:00
|
|
|
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
|
|
|
|
0xFFFF),
|
|
|
|
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
|
|
|
|
128),
|
|
|
|
DEFINE_PROP_BIT("hotplug", VirtIOSCSI, host_features,
|
|
|
|
VIRTIO_SCSI_F_HOTPLUG, true),
|
|
|
|
DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features,
|
|
|
|
VIRTIO_SCSI_F_CHANGE, true),
|
2017-07-14 05:14:56 +03:00
|
|
|
DEFINE_PROP_LINK("iothread", VirtIOSCSI, parent_obj.conf.iothread,
|
|
|
|
TYPE_IOTHREAD, IOThread *),
|
2013-03-21 18:15:14 +04:00
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
};
|
|
|
|
|
2016-10-06 15:55:46 +03:00
|
|
|
static const VMStateDescription vmstate_virtio_scsi = {
|
|
|
|
.name = "virtio-scsi",
|
|
|
|
.minimum_version_id = 1,
|
|
|
|
.version_id = 1,
|
|
|
|
.fields = (VMStateField[]) {
|
|
|
|
VMSTATE_VIRTIO_DEVICE,
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
2016-07-14 20:22:46 +03:00
|
|
|
|
2013-03-29 05:08:15 +04:00
|
|
|
static void virtio_scsi_common_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
2013-07-29 18:17:45 +04:00
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
2013-03-29 05:08:15 +04:00
|
|
|
|
|
|
|
vdc->get_config = virtio_scsi_get_config;
|
2013-07-29 18:17:45 +04:00
|
|
|
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
2013-03-29 05:08:15 +04:00
|
|
|
}
|
|
|
|
|
2013-03-21 18:15:14 +04:00
|
|
|
static void virtio_scsi_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
2014-09-26 13:28:33 +04:00
|
|
|
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
|
2013-07-30 05:19:55 +04:00
|
|
|
|
2013-03-21 18:15:14 +04:00
|
|
|
dc->props = virtio_scsi_properties;
|
2016-07-14 20:22:46 +03:00
|
|
|
dc->vmsd = &vmstate_virtio_scsi;
|
2013-07-29 18:17:45 +04:00
|
|
|
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
2013-07-30 05:19:55 +04:00
|
|
|
vdc->realize = virtio_scsi_device_realize;
|
2013-07-30 05:50:44 +04:00
|
|
|
vdc->unrealize = virtio_scsi_device_unrealize;
|
2013-03-21 18:15:14 +04:00
|
|
|
vdc->set_config = virtio_scsi_set_config;
|
|
|
|
vdc->get_features = virtio_scsi_get_features;
|
|
|
|
vdc->reset = virtio_scsi_reset;
|
2016-10-21 23:48:10 +03:00
|
|
|
vdc->start_ioeventfd = virtio_scsi_dataplane_start;
|
|
|
|
vdc->stop_ioeventfd = virtio_scsi_dataplane_stop;
|
2014-09-26 13:28:33 +04:00
|
|
|
hc->plug = virtio_scsi_hotplug;
|
|
|
|
hc->unplug = virtio_scsi_hotunplug;
|
2013-03-21 18:15:14 +04:00
|
|
|
}
|
|
|
|
|
2013-03-29 05:08:15 +04:00
|
|
|
static const TypeInfo virtio_scsi_common_info = {
|
|
|
|
.name = TYPE_VIRTIO_SCSI_COMMON,
|
|
|
|
.parent = TYPE_VIRTIO_DEVICE,
|
|
|
|
.instance_size = sizeof(VirtIOSCSICommon),
|
2013-08-19 19:53:15 +04:00
|
|
|
.abstract = true,
|
2013-03-29 05:08:15 +04:00
|
|
|
.class_init = virtio_scsi_common_class_init,
|
|
|
|
};
|
|
|
|
|
2013-03-21 18:15:14 +04:00
|
|
|
static const TypeInfo virtio_scsi_info = {
|
|
|
|
.name = TYPE_VIRTIO_SCSI,
|
2013-03-29 05:08:15 +04:00
|
|
|
.parent = TYPE_VIRTIO_SCSI_COMMON,
|
2013-03-21 18:15:14 +04:00
|
|
|
.instance_size = sizeof(VirtIOSCSI),
|
|
|
|
.class_init = virtio_scsi_class_init,
|
2014-09-26 13:28:33 +04:00
|
|
|
.interfaces = (InterfaceInfo[]) {
|
|
|
|
{ TYPE_HOTPLUG_HANDLER },
|
|
|
|
{ }
|
|
|
|
}
|
2013-03-21 18:15:14 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static void virtio_register_types(void)
|
|
|
|
{
|
2013-03-29 05:08:15 +04:00
|
|
|
type_register_static(&virtio_scsi_common_info);
|
2013-03-21 18:15:14 +04:00
|
|
|
type_register_static(&virtio_scsi_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(virtio_register_types)
|