Blame SOURCES/kvm-hw-scsi-support-SCSI-2-passthrough-without-PI.patch

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