|
|
8535f5 |
From 968575c7d427c476522e8bfef0aeb3a0bc09fb4a Mon Sep 17 00:00:00 2001
|
|
|
8535f5 |
From: David Gibson <dgibson@redhat.com>
|
|
|
8535f5 |
Date: Mon, 25 Jun 2018 04:18:24 +0200
|
|
|
8535f5 |
Subject: [PATCH 2/3] hw/scsi: support SCSI-2 passthrough without PI
|
|
|
8535f5 |
|
|
|
8535f5 |
RH-Author: David Gibson <dgibson@redhat.com>
|
|
|
8535f5 |
Message-id: <20180625041824.5072-3-dgibson@redhat.com>
|
|
|
8535f5 |
Patchwork-id: 81030
|
|
|
8535f5 |
O-Subject: [RHEL-7.5.z qemu-kvm-ma PATCH 2/2] hw/scsi: support SCSI-2 passthrough without PI
|
|
|
8535f5 |
Bugzilla: 1593193
|
|
|
8535f5 |
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
|
|
|
8535f5 |
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
8535f5 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
8535f5 |
|
|
|
8535f5 |
From: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
|
|
|
8535f5 |
|
|
|
8535f5 |
QEMU SCSI code makes assumptions about how the PROTECT and BYTCHK
|
|
|
8535f5 |
works in the protocol, denying support for PI (Protection
|
|
|
8535f5 |
Information) in case the guest OS requests it. However, in SCSI versions 2
|
|
|
8535f5 |
and older, there is no PI concept in the protocol.
|
|
|
8535f5 |
|
|
|
8535f5 |
This means that when dealing with such devices:
|
|
|
8535f5 |
|
|
|
8535f5 |
- there is no PROTECT bit in byte 5 of the standard INQUIRY response. The
|
|
|
8535f5 |
whole byte is marked as "Reserved";
|
|
|
8535f5 |
|
|
|
8535f5 |
- there is no RDPROTECT in byte 2 of READ. We have 'Logical Unit Number'
|
|
|
8535f5 |
in this field instead;
|
|
|
8535f5 |
|
|
|
8535f5 |
- there is no VRPROTECT in byte 2 of VERIFY. We have 'Logical Unit Number'
|
|
|
8535f5 |
in this field instead. This also means that the BYTCHK bit in this case
|
|
|
8535f5 |
is not related to PI.
|
|
|
8535f5 |
|
|
|
8535f5 |
Since QEMU does not consider these changes, a SCSI passthrough using
|
|
|
8535f5 |
a SCSI-2 device will not work. It will mistake these fields with
|
|
|
8535f5 |
PI information and return Illegal Request SCSI SENSE thinking
|
|
|
8535f5 |
that the driver is asking for PI support.
|
|
|
8535f5 |
|
|
|
8535f5 |
This patch fixes it by adding a new attribute called 'scsi_version'
|
|
|
8535f5 |
that is read from the standard INQUIRY response of passthrough
|
|
|
8535f5 |
devices. This allows for a version verification before applying
|
|
|
8535f5 |
conditions related to PI that doesn't apply for older versions.
|
|
|
8535f5 |
|
|
|
8535f5 |
Reported-by: Dac Nguyen <dacng@us.ibm.com>
|
|
|
8535f5 |
Signed-off-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
|
|
|
8535f5 |
Message-Id: <20180327211451.14647-1-danielhb@linux.vnet.ibm.com>
|
|
|
8535f5 |
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
8535f5 |
(cherry picked from commit 29e560f00e2bc1b5731c8276031aaf192de55d9d)
|
|
|
8535f5 |
|
|
|
8535f5 |
Signed-off-by: David Gibson <dgibson@redhat.com>
|
|
|
8535f5 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
8535f5 |
---
|
|
|
8535f5 |
hw/scsi/scsi-disk.c | 2 +-
|
|
|
8535f5 |
hw/scsi/scsi-generic.c | 47 ++++++++++++++++++++++++++++++++++++-----------
|
|
|
8535f5 |
2 files changed, 37 insertions(+), 12 deletions(-)
|
|
|
8535f5 |
|
|
|
8535f5 |
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
|
|
|
8535f5 |
index f906ffb..d89e4f0 100644
|
|
|
8535f5 |
--- a/hw/scsi/scsi-disk.c
|
|
|
8535f5 |
+++ b/hw/scsi/scsi-disk.c
|
|
|
8535f5 |
@@ -3011,7 +3011,7 @@ static Property scsi_block_properties[] = {
|
|
|
8535f5 |
DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false),
|
|
|
8535f5 |
DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0),
|
|
|
8535f5 |
DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
|
|
|
8535f5 |
- 5),
|
|
|
8535f5 |
+ -1),
|
|
|
8535f5 |
DEFINE_PROP_END_OF_LIST(),
|
|
|
8535f5 |
};
|
|
|
8535f5 |
|
|
|
8535f5 |
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
|
|
|
8535f5 |
index fe11efe..e38829a 100644
|
|
|
8535f5 |
--- a/hw/scsi/scsi-generic.c
|
|
|
8535f5 |
+++ b/hw/scsi/scsi-generic.c
|
|
|
8535f5 |
@@ -194,17 +194,40 @@ static void scsi_read_complete(void * opaque, int ret)
|
|
|
8535f5 |
r->buf[3] |= 0x80;
|
|
|
8535f5 |
}
|
|
|
8535f5 |
}
|
|
|
8535f5 |
- if (s->type == TYPE_DISK &&
|
|
|
8535f5 |
- r->req.cmd.buf[0] == INQUIRY &&
|
|
|
8535f5 |
- r->req.cmd.buf[2] == 0xb0) {
|
|
|
8535f5 |
- uint32_t max_transfer =
|
|
|
8535f5 |
- blk_get_max_transfer(s->conf.blk) / s->blocksize;
|
|
|
8535f5 |
-
|
|
|
8535f5 |
- assert(max_transfer);
|
|
|
8535f5 |
- stl_be_p(&r->buf[8], max_transfer);
|
|
|
8535f5 |
- /* Also take care of the opt xfer len. */
|
|
|
8535f5 |
- stl_be_p(&r->buf[12],
|
|
|
8535f5 |
- MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
|
|
|
8535f5 |
+ if (r->req.cmd.buf[0] == INQUIRY) {
|
|
|
8535f5 |
+ /*
|
|
|
8535f5 |
+ * EVPD set to zero returns the standard INQUIRY data.
|
|
|
8535f5 |
+ *
|
|
|
8535f5 |
+ * Check if scsi_version is unset (-1) to avoid re-defining it
|
|
|
8535f5 |
+ * each time an INQUIRY with standard data is received.
|
|
|
8535f5 |
+ * scsi_version is initialized with -1 in scsi_generic_reset
|
|
|
8535f5 |
+ * and scsi_disk_reset, making sure that we'll set the
|
|
|
8535f5 |
+ * scsi_version after a reset. If the version field of the
|
|
|
8535f5 |
+ * INQUIRY response somehow changes after a guest reboot,
|
|
|
8535f5 |
+ * we'll be able to keep track of it.
|
|
|
8535f5 |
+ *
|
|
|
8535f5 |
+ * On SCSI-2 and older, first 3 bits of byte 2 is the
|
|
|
8535f5 |
+ * ANSI-approved version, while on later versions the
|
|
|
8535f5 |
+ * whole byte 2 contains the version. Check if we're dealing
|
|
|
8535f5 |
+ * with a newer version and, in that case, assign the
|
|
|
8535f5 |
+ * whole byte.
|
|
|
8535f5 |
+ */
|
|
|
8535f5 |
+ if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) {
|
|
|
8535f5 |
+ s->scsi_version = r->buf[2] & 0x07;
|
|
|
8535f5 |
+ if (s->scsi_version > 2) {
|
|
|
8535f5 |
+ s->scsi_version = r->buf[2];
|
|
|
8535f5 |
+ }
|
|
|
8535f5 |
+ }
|
|
|
8535f5 |
+ if (s->type == TYPE_DISK && r->req.cmd.buf[2] == 0xb0) {
|
|
|
8535f5 |
+ uint32_t max_transfer =
|
|
|
8535f5 |
+ blk_get_max_transfer(s->conf.blk) / s->blocksize;
|
|
|
8535f5 |
+
|
|
|
8535f5 |
+ assert(max_transfer);
|
|
|
8535f5 |
+ stl_be_p(&r->buf[8], max_transfer);
|
|
|
8535f5 |
+ /* Also take care of the opt xfer len. */
|
|
|
8535f5 |
+ stl_be_p(&r->buf[12],
|
|
|
8535f5 |
+ MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
|
|
|
8535f5 |
+ }
|
|
|
8535f5 |
}
|
|
|
8535f5 |
scsi_req_data(&r->req, len);
|
|
|
8535f5 |
scsi_req_unref(&r->req);
|
|
|
8535f5 |
@@ -552,6 +575,8 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp)
|
|
|
8535f5 |
|
|
|
8535f5 |
DPRINTF("block size %d\n", s->blocksize);
|
|
|
8535f5 |
|
|
|
8535f5 |
+ /* Only used by scsi-block, but initialize it nevertheless to be clean. */
|
|
|
8535f5 |
+ s->default_scsi_version = -1;
|
|
|
8535f5 |
scsi_generic_read_device_identification(s);
|
|
|
8535f5 |
}
|
|
|
8535f5 |
|
|
|
8535f5 |
--
|
|
|
8535f5 |
1.8.3.1
|
|
|
8535f5 |
|