forked from rpms/qemu-kvm
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
4.9 KiB
133 lines
4.9 KiB
From 562ea3a2d602cf41c548f3ddf52c43c04fded347 Mon Sep 17 00:00:00 2001
|
|
From: Stefano Garzarella <sgarzare@redhat.com>
|
|
Date: Wed, 12 Jul 2023 15:43:50 +0200
|
|
Subject: [PATCH 01/12] scsi: fetch unit attention when creating the request
|
|
|
|
RH-Author: Stefano Garzarella <sgarzare@redhat.com>
|
|
RH-MergeRequest: 184: scsi: fix issue with Linux guest and unit attention
|
|
RH-Bugzilla: 2176702
|
|
RH-Acked-by: Thomas Huth <thuth@redhat.com>
|
|
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
RH-Commit: [1/3] 04563caac45d0110ea65eda8e55472556cd317c0 (sgarzarella/qemu-kvm-c-9-s)
|
|
|
|
Commit 1880ad4f4e ("virtio-scsi: Batched prepare for cmd reqs") split
|
|
calls to scsi_req_new() and scsi_req_enqueue() in the virtio-scsi device.
|
|
No ill effects were observed until commit 8cc5583abe ("virtio-scsi: Send
|
|
"REPORTED LUNS CHANGED" sense data upon disk hotplug events") added a
|
|
unit attention that was easy to trigger with device hotplug and
|
|
hot-unplug.
|
|
|
|
Because the two calls were separated, all requests in the batch were
|
|
prepared calling scsi_req_new() to report a sense. The first one
|
|
submitted would report the right sense and reset it to NO_SENSE, while
|
|
the others reported CHECK_CONDITION with no sense data. This caused
|
|
SCSI errors in Linux.
|
|
|
|
To solve this issue, let's fetch the unit attention as early as possible
|
|
when we prepare the request, so that only the first request in the batch
|
|
will use the unit attention SCSIReqOps and the others will not report
|
|
CHECK CONDITION.
|
|
|
|
Fixes: 1880ad4f4e ("virtio-scsi: Batched prepare for cmd reqs")
|
|
Fixes: 8cc5583abe ("virtio-scsi: Send "REPORTED LUNS CHANGED" sense data upon disk hotplug events")
|
|
Reported-by: Thomas Huth <thuth@redhat.com>
|
|
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2176702
|
|
Co-developed-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
|
|
Message-ID: <20230712134352.118655-2-sgarzare@redhat.com>
|
|
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
(cherry picked from commit 9472083e642bfb9bc836b38662baddd9bc964ebc)
|
|
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
|
|
---
|
|
hw/scsi/scsi-bus.c | 36 +++++++++++++++++++++++++++++++++---
|
|
include/hw/scsi/scsi.h | 1 +
|
|
2 files changed, 34 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
|
|
index 3c20b47ad0..5d22313b9d 100644
|
|
--- a/hw/scsi/scsi-bus.c
|
|
+++ b/hw/scsi/scsi-bus.c
|
|
@@ -413,19 +413,35 @@ static const struct SCSIReqOps reqops_invalid_opcode = {
|
|
|
|
/* SCSIReqOps implementation for unit attention conditions. */
|
|
|
|
-static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
|
|
+static void scsi_fetch_unit_attention_sense(SCSIRequest *req)
|
|
{
|
|
+ SCSISense *ua = NULL;
|
|
+
|
|
if (req->dev->unit_attention.key == UNIT_ATTENTION) {
|
|
- scsi_req_build_sense(req, req->dev->unit_attention);
|
|
+ ua = &req->dev->unit_attention;
|
|
} else if (req->bus->unit_attention.key == UNIT_ATTENTION) {
|
|
- scsi_req_build_sense(req, req->bus->unit_attention);
|
|
+ ua = &req->bus->unit_attention;
|
|
}
|
|
+
|
|
+ /*
|
|
+ * Fetch the unit attention sense immediately so that another
|
|
+ * scsi_req_new does not use reqops_unit_attention.
|
|
+ */
|
|
+ if (ua) {
|
|
+ scsi_req_build_sense(req, *ua);
|
|
+ *ua = SENSE_CODE(NO_SENSE);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
|
|
+{
|
|
scsi_req_complete(req, CHECK_CONDITION);
|
|
return 0;
|
|
}
|
|
|
|
static const struct SCSIReqOps reqops_unit_attention = {
|
|
.size = sizeof(SCSIRequest),
|
|
+ .init_req = scsi_fetch_unit_attention_sense,
|
|
.send_command = scsi_unit_attention
|
|
};
|
|
|
|
@@ -699,6 +715,11 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
|
|
object_ref(OBJECT(d));
|
|
object_ref(OBJECT(qbus->parent));
|
|
notifier_list_init(&req->cancel_notifiers);
|
|
+
|
|
+ if (reqops->init_req) {
|
|
+ reqops->init_req(req);
|
|
+ }
|
|
+
|
|
trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
|
|
return req;
|
|
}
|
|
@@ -798,6 +819,15 @@ uint8_t *scsi_req_get_buf(SCSIRequest *req)
|
|
static void scsi_clear_unit_attention(SCSIRequest *req)
|
|
{
|
|
SCSISense *ua;
|
|
+
|
|
+ /*
|
|
+ * scsi_fetch_unit_attention_sense() already cleaned the unit attention
|
|
+ * in this case.
|
|
+ */
|
|
+ if (req->ops == &reqops_unit_attention) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
if (req->dev->unit_attention.key != UNIT_ATTENTION &&
|
|
req->bus->unit_attention.key != UNIT_ATTENTION) {
|
|
return;
|
|
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
|
|
index 6f23a7a73e..1787ddd01e 100644
|
|
--- a/include/hw/scsi/scsi.h
|
|
+++ b/include/hw/scsi/scsi.h
|
|
@@ -108,6 +108,7 @@ int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
|
|
/* scsi-bus.c */
|
|
struct SCSIReqOps {
|
|
size_t size;
|
|
+ void (*init_req)(SCSIRequest *req);
|
|
void (*free_req)(SCSIRequest *req);
|
|
int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
|
|
void (*read_data)(SCSIRequest *req);
|
|
--
|
|
2.39.3
|
|
|