qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v1 2/3] scsi-block: add VPD Block Limits in INQUIRY


From: Daniel Henrique Barboza
Subject: [Qemu-devel] [PATCH v1 2/3] scsi-block: add VPD Block Limits in INQUIRY Supported Pages reply
Date: Fri, 8 Jun 2018 17:07:39 -0300

The previous commit added Block Limits emulation for scsi-block devices
if the underlying hardware does not implement it. But this is not
enough to fix the issue of max_io_sectors mismatch between the
guest and the host - the guest is not aware of the Block
Limits support we're now providing.

This patch changes the INQUIRY Supported Pages reply to add Block
Limits support. If the host device already supports it, nothing changes.
If it doesn't, add it manually in the reply.

With this patch, the guest now queries the Block Limits page during the
device configuration because it is being advertised in the Supported
Pages response. It will either receive the Block Limits page from the
hardware, if it supports it, or will receive an emulated response
from QEMU. At any rate, the guest now has the information to set the
max_sectors_kb parameter accordingly, sparing the user of SCSI sense
errors that would happen without the emulated response and in the absence
of Block Limits support from the hardware.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1566195
Reported-by: Dac Nguyen <address@hidden>
Signed-off-by: Daniel Henrique Barboza <address@hidden>
---
 hw/scsi/scsi-generic.c | 80 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 52 insertions(+), 28 deletions(-)

diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 579872908c..64d3b79518 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -244,7 +244,8 @@ static void scsi_read_complete(void * opaque, int ret)
     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
     SCSIDevice *s = r->req.dev;
     SCSISense sense;
-    int len;
+    uint8_t page, page_len;
+    int len, i;
 
     assert(r->req.aiocb != NULL);
     r->req.aiocb = NULL;
@@ -315,33 +316,56 @@ static void scsi_read_complete(void * opaque, int ret)
                 s->scsi_version = r->buf[2];
             }
         }
-        if (s->type == TYPE_DISK && r->req.cmd.buf[2] == 0xb0) {
-            /*
-             * Take a look to see if this VPD Block Limits request will
-             * result in a sense error in scsi_command_complete_noio.
-             * In this case, emulate a valid VPD response.
-             *
-             * After that, given that now there are valid contents in the
-             * buffer, clean up the io_header to avoid firing up the
-             * sense error.
-             */
-            if (sg_io_sense_from_errno(-ret, &r->io_header, &sense)) {
-                r->buflen = scsi_emulate_vpd_bl_page(s, r->buf);
-                r->io_header.sb_len_wr = 0;
-
-                /* Clean sg_io_sense */
-                r->io_header.driver_status = 0;
-                r->io_header.status = 0;
-
-            }  else {
-                uint32_t max_transfer =
-                    blk_get_max_transfer(s->conf.blk) / s->blocksize;
-
-                assert(max_transfer);
-                stl_be_p(&r->buf[8], max_transfer);
-                /* Also take care of the opt xfer len. */
-                stl_be_p(&r->buf[12],
-                         MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
+        if (s->type == TYPE_DISK && (r->req.cmd.buf[1] & 0x01)) {
+            page = r->req.cmd.buf[2];
+            if (page == 0xb0) {
+                /*
+                 * Take a look to see if this VPD Block Limits request will
+                 * result in a sense error in scsi_command_complete_noio.
+                 * In this case, emulate a valid VPD response.
+                 *
+                 * After that, given that now there are valid contents in
+                 * the buffer, clean up the io_header to avoid firing up
+                 * the sense error.
+                 */
+                if (sg_io_sense_from_errno(-ret, &r->io_header, &sense)) {
+                    r->buflen = scsi_emulate_vpd_bl_page(s, r->buf);
+                    r->io_header.sb_len_wr = 0;
+
+                    /* Clean sg_io_sense */
+                    r->io_header.driver_status = 0;
+                    r->io_header.status = 0;
+
+                }  else {
+                    uint32_t max_transfer =
+                        blk_get_max_transfer(s->conf.blk) / s->blocksize;
+
+                    assert(max_transfer);
+                    stl_be_p(&r->buf[8], max_transfer);
+                    /* Also take care of the opt xfer len. */
+                    stl_be_p(&r->buf[12],
+                             MIN_NON_ZERO(max_transfer, 
ldl_be_p(&r->buf[12])));
+                }
+            } else if (page == 0x00) {
+                /*
+                 * Now we're capable of supplying the VPD Block Limits
+                 * response if the hardware can't. Inspect if the INQUIRY
+                 * response contains support for the VPD Block Limits page.
+                 * Add it if it doesn't.
+                 *
+                 * This way, the guest kernel will be aware of the support
+                 * and will use it to proper setup the SCSI device.
+                 */
+                page_len = r->buf[3];
+                for (i = 4; i < page_len + 4; i++) {
+                    if (r->buf[i] == 0xb0) {
+                        break;
+                    }
+                }
+                if (i == page_len + 4) {
+                    r->buf[i] = 0xb0;
+                    r->buf[3] = ++page_len;
+                }
             }
         }
     }
-- 
2.14.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]