26ba25
From a9bfa7b102f1de3dbff308806099a7529b4e96b4 Mon Sep 17 00:00:00 2001
26ba25
From: Paolo Bonzini <pbonzini@redhat.com>
26ba25
Date: Thu, 20 Dec 2018 12:30:56 +0000
26ba25
Subject: [PATCH 1/8] hw/scsi: cleanups before VPD BL emulation
26ba25
26ba25
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
26ba25
Message-id: <20181220123103.29579-2-pbonzini@redhat.com>
26ba25
Patchwork-id: 83712
26ba25
O-Subject: [PATCH 1/8] hw/scsi: cleanups before VPD BL emulation
26ba25
Bugzilla: 1639957
26ba25
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
26ba25
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
26ba25
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
26ba25
26ba25
From: Daniel Henrique Barboza <danielhb413@gmail.com>
26ba25
26ba25
To add support for the emulation of Block Limits VPD page
26ba25
for passthrough devices, a few adjustments in the current code
26ba25
base is required to avoid repetition and improve clarity.
26ba25
26ba25
In scsi-generic.c, detach the Inquiry handling from
26ba25
scsi_read_complete and put it into a new function called
26ba25
scsi_handle_inquiry_reply. This change aims to avoid
26ba25
cluttering of scsi_read_complete when we more logic in the
26ba25
Inquiry response handling is added in the next patches,
26ba25
centralizing the changes in the new function.
26ba25
26ba25
In scsi-disk.c, take the build of all emulated VPD pages
26ba25
from scsi_disk_emulate_inquiry and make it available to
26ba25
other files into a non-static function called
26ba25
scsi_disk_emulate_vpd_page. Making it public will allow
26ba25
the future VPD BL emulation code for passthrough devices
26ba25
to use it from scsi-generic.c, avoiding copy/pasting this
26ba25
code solely for that purpose. It also has the advantage of
26ba25
providing emulation of all VPD pages in case we need to
26ba25
emulate other pages in other scenarios. As a bonus,
26ba25
scsi_disk_emulate_inquiry got tidier.
26ba25
26ba25
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
26ba25
Message-Id: <20180627172432.11120-2-danielhb413@gmail.com>
26ba25
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
26ba25
(cherry picked from commit 0a96ca2437646bad197b0108c5f4a93e7ead05a9)
26ba25
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
26ba25
---
26ba25
 hw/scsi/scsi-disk.c    | 407 +++++++++++++++++++++++++------------------------
26ba25
 hw/scsi/scsi-generic.c |  71 +++++----
26ba25
 include/hw/scsi/scsi.h |   1 +
26ba25
 3 files changed, 249 insertions(+), 230 deletions(-)
26ba25
26ba25
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
26ba25
index ded23d3..ae5b4c0 100644
26ba25
--- a/hw/scsi/scsi-disk.c
26ba25
+++ b/hw/scsi/scsi-disk.c
26ba25
@@ -585,219 +585,228 @@ static uint8_t *scsi_get_buf(SCSIRequest *req)
26ba25
     return (uint8_t *)r->iov.iov_base;
26ba25
 }
26ba25
 
26ba25
-static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
26ba25
+int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf)
26ba25
 {
26ba25
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
26ba25
-    int buflen = 0;
26ba25
-    int start;
26ba25
-
26ba25
-    if (req->cmd.buf[1] & 0x1) {
26ba25
-        /* Vital product data */
26ba25
-        uint8_t page_code = req->cmd.buf[2];
26ba25
-
26ba25
-        outbuf[buflen++] = s->qdev.type & 0x1f;
26ba25
-        outbuf[buflen++] = page_code ; // this page
26ba25
-        outbuf[buflen++] = 0x00;
26ba25
-        outbuf[buflen++] = 0x00;
26ba25
-        start = buflen;
26ba25
-
26ba25
-        switch (page_code) {
26ba25
-        case 0x00: /* Supported page codes, mandatory */
26ba25
-        {
26ba25
-            DPRINTF("Inquiry EVPD[Supported pages] "
26ba25
-                    "buffer size %zd\n", req->cmd.xfer);
26ba25
-            outbuf[buflen++] = 0x00; // list of supported pages (this page)
26ba25
-            if (s->serial) {
26ba25
-                outbuf[buflen++] = 0x80; // unit serial number
26ba25
-            }
26ba25
-            outbuf[buflen++] = 0x83; // device identification
26ba25
-            if (s->qdev.type == TYPE_DISK) {
26ba25
-                outbuf[buflen++] = 0xb0; // block limits
26ba25
-                outbuf[buflen++] = 0xb1; /* block device characteristics */
26ba25
-                outbuf[buflen++] = 0xb2; // thin provisioning
26ba25
-            }
26ba25
-            break;
26ba25
-        }
26ba25
-        case 0x80: /* Device serial number, optional */
26ba25
-        {
26ba25
-            int l;
26ba25
+    uint8_t page_code = req->cmd.buf[2];
26ba25
+    int start, buflen = 0;
26ba25
 
26ba25
-            if (!s->serial) {
26ba25
-                DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
26ba25
-                return -1;
26ba25
-            }
26ba25
+    outbuf[buflen++] = s->qdev.type & 0x1f;
26ba25
+    outbuf[buflen++] = page_code;
26ba25
+    outbuf[buflen++] = 0x00;
26ba25
+    outbuf[buflen++] = 0x00;
26ba25
+    start = buflen;
26ba25
 
26ba25
-            l = strlen(s->serial);
26ba25
-            if (l > 36) {
26ba25
-                l = 36;
26ba25
-            }
26ba25
+    switch (page_code) {
26ba25
+    case 0x00: /* Supported page codes, mandatory */
26ba25
+    {
26ba25
+        DPRINTF("Inquiry EVPD[Supported pages] "
26ba25
+                "buffer size %zd\n", req->cmd.xfer);
26ba25
+        outbuf[buflen++] = 0x00; /* list of supported pages (this page) */
26ba25
+        if (s->serial) {
26ba25
+            outbuf[buflen++] = 0x80; /* unit serial number */
26ba25
+        }
26ba25
+        outbuf[buflen++] = 0x83; /* device identification */
26ba25
+        if (s->qdev.type == TYPE_DISK) {
26ba25
+            outbuf[buflen++] = 0xb0; /* block limits */
26ba25
+            outbuf[buflen++] = 0xb1; /* block device characteristics */
26ba25
+            outbuf[buflen++] = 0xb2; /* thin provisioning */
26ba25
+        }
26ba25
+        break;
26ba25
+    }
26ba25
+    case 0x80: /* Device serial number, optional */
26ba25
+    {
26ba25
+        int l;
26ba25
 
26ba25
-            DPRINTF("Inquiry EVPD[Serial number] "
26ba25
-                    "buffer size %zd\n", req->cmd.xfer);
26ba25
-            memcpy(outbuf+buflen, s->serial, l);
26ba25
-            buflen += l;
26ba25
-            break;
26ba25
+        if (!s->serial) {
26ba25
+            DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
26ba25
+            return -1;
26ba25
         }
26ba25
 
26ba25
-        case 0x83: /* Device identification page, mandatory */
26ba25
-        {
26ba25
-            const char *str = s->serial ?: blk_name(s->qdev.conf.blk);
26ba25
-            int max_len = s->serial ? 20 : 255 - 8;
26ba25
-            int id_len = strlen(str);
26ba25
+        l = strlen(s->serial);
26ba25
+        if (l > 36) {
26ba25
+            l = 36;
26ba25
+        }
26ba25
 
26ba25
-            if (id_len > max_len) {
26ba25
-                id_len = max_len;
26ba25
-            }
26ba25
-            DPRINTF("Inquiry EVPD[Device identification] "
26ba25
-                    "buffer size %zd\n", req->cmd.xfer);
26ba25
-
26ba25
-            outbuf[buflen++] = 0x2; // ASCII
26ba25
-            outbuf[buflen++] = 0;   // not officially assigned
26ba25
-            outbuf[buflen++] = 0;   // reserved
26ba25
-            outbuf[buflen++] = id_len; // length of data following
26ba25
-            memcpy(outbuf+buflen, str, id_len);
26ba25
-            buflen += id_len;
26ba25
-
26ba25
-            if (s->qdev.wwn) {
26ba25
-                outbuf[buflen++] = 0x1; // Binary
26ba25
-                outbuf[buflen++] = 0x3; // NAA
26ba25
-                outbuf[buflen++] = 0;   // reserved
26ba25
-                outbuf[buflen++] = 8;
26ba25
-                stq_be_p(&outbuf[buflen], s->qdev.wwn);
26ba25
-                buflen += 8;
26ba25
-            }
26ba25
+        DPRINTF("Inquiry EVPD[Serial number] "
26ba25
+                "buffer size %zd\n", req->cmd.xfer);
26ba25
+        memcpy(outbuf + buflen, s->serial, l);
26ba25
+        buflen += l;
26ba25
+        break;
26ba25
+    }
26ba25
 
26ba25
-            if (s->qdev.port_wwn) {
26ba25
-                outbuf[buflen++] = 0x61; // SAS / Binary
26ba25
-                outbuf[buflen++] = 0x93; // PIV / Target port / NAA
26ba25
-                outbuf[buflen++] = 0;    // reserved
26ba25
-                outbuf[buflen++] = 8;
26ba25
-                stq_be_p(&outbuf[buflen], s->qdev.port_wwn);
26ba25
-                buflen += 8;
26ba25
-            }
26ba25
+    case 0x83: /* Device identification page, mandatory */
26ba25
+    {
26ba25
+        const char *str = s->serial ?: blk_name(s->qdev.conf.blk);
26ba25
+        int max_len = s->serial ? 20 : 255 - 8;
26ba25
+        int id_len = strlen(str);
26ba25
 
26ba25
-            if (s->port_index) {
26ba25
-                outbuf[buflen++] = 0x61; // SAS / Binary
26ba25
-                outbuf[buflen++] = 0x94; // PIV / Target port / relative target port
26ba25
-                outbuf[buflen++] = 0;    // reserved
26ba25
-                outbuf[buflen++] = 4;
26ba25
-                stw_be_p(&outbuf[buflen + 2], s->port_index);
26ba25
-                buflen += 4;
26ba25
-            }
26ba25
-            break;
26ba25
+        if (id_len > max_len) {
26ba25
+            id_len = max_len;
26ba25
         }
26ba25
-        case 0xb0: /* block limits */
26ba25
-        {
26ba25
-            unsigned int unmap_sectors =
26ba25
-                    s->qdev.conf.discard_granularity / s->qdev.blocksize;
26ba25
-            unsigned int min_io_size =
26ba25
-                    s->qdev.conf.min_io_size / s->qdev.blocksize;
26ba25
-            unsigned int opt_io_size =
26ba25
-                    s->qdev.conf.opt_io_size / s->qdev.blocksize;
26ba25
-            unsigned int max_unmap_sectors =
26ba25
-                    s->max_unmap_size / s->qdev.blocksize;
26ba25
-            unsigned int max_io_sectors =
26ba25
-                    s->max_io_size / s->qdev.blocksize;
26ba25
-
26ba25
-            if (s->qdev.type == TYPE_ROM) {
26ba25
-                DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
26ba25
-                        page_code);
26ba25
-                return -1;
26ba25
-            }
26ba25
-            if (s->qdev.type == TYPE_DISK) {
26ba25
-                int max_transfer_blk = blk_get_max_transfer(s->qdev.conf.blk);
26ba25
-                int max_io_sectors_blk =
26ba25
-                    max_transfer_blk / s->qdev.blocksize;
26ba25
-
26ba25
-                max_io_sectors =
26ba25
-                    MIN_NON_ZERO(max_io_sectors_blk, max_io_sectors);
26ba25
-
26ba25
-                /* min_io_size and opt_io_size can't be greater than
26ba25
-                 * max_io_sectors */
26ba25
-                if (min_io_size) {
26ba25
-                    min_io_size = MIN(min_io_size, max_io_sectors);
26ba25
-                }
26ba25
-                if (opt_io_size) {
26ba25
-                    opt_io_size = MIN(opt_io_size, max_io_sectors);
26ba25
-                }
26ba25
-            }
26ba25
-            /* required VPD size with unmap support */
26ba25
-            buflen = 0x40;
26ba25
-            memset(outbuf + 4, 0, buflen - 4);
26ba25
-
26ba25
-            outbuf[4] = 0x1; /* wsnz */
26ba25
-
26ba25
-            /* optimal transfer length granularity */
26ba25
-            outbuf[6] = (min_io_size >> 8) & 0xff;
26ba25
-            outbuf[7] = min_io_size & 0xff;
26ba25
-
26ba25
-            /* maximum transfer length */
26ba25
-            outbuf[8] = (max_io_sectors >> 24) & 0xff;
26ba25
-            outbuf[9] = (max_io_sectors >> 16) & 0xff;
26ba25
-            outbuf[10] = (max_io_sectors >> 8) & 0xff;
26ba25
-            outbuf[11] = max_io_sectors & 0xff;
26ba25
-
26ba25
-            /* optimal transfer length */
26ba25
-            outbuf[12] = (opt_io_size >> 24) & 0xff;
26ba25
-            outbuf[13] = (opt_io_size >> 16) & 0xff;
26ba25
-            outbuf[14] = (opt_io_size >> 8) & 0xff;
26ba25
-            outbuf[15] = opt_io_size & 0xff;
26ba25
-
26ba25
-            /* max unmap LBA count, default is 1GB */
26ba25
-            outbuf[20] = (max_unmap_sectors >> 24) & 0xff;
26ba25
-            outbuf[21] = (max_unmap_sectors >> 16) & 0xff;
26ba25
-            outbuf[22] = (max_unmap_sectors >> 8) & 0xff;
26ba25
-            outbuf[23] = max_unmap_sectors & 0xff;
26ba25
-
26ba25
-            /* max unmap descriptors, 255 fit in 4 kb with an 8-byte header.  */
26ba25
-            outbuf[24] = 0;
26ba25
-            outbuf[25] = 0;
26ba25
-            outbuf[26] = 0;
26ba25
-            outbuf[27] = 255;
26ba25
-
26ba25
-            /* optimal unmap granularity */
26ba25
-            outbuf[28] = (unmap_sectors >> 24) & 0xff;
26ba25
-            outbuf[29] = (unmap_sectors >> 16) & 0xff;
26ba25
-            outbuf[30] = (unmap_sectors >> 8) & 0xff;
26ba25
-            outbuf[31] = unmap_sectors & 0xff;
26ba25
-
26ba25
-            /* max write same size */
26ba25
-            outbuf[36] = 0;
26ba25
-            outbuf[37] = 0;
26ba25
-            outbuf[38] = 0;
26ba25
-            outbuf[39] = 0;
26ba25
-
26ba25
-            outbuf[40] = (max_io_sectors >> 24) & 0xff;
26ba25
-            outbuf[41] = (max_io_sectors >> 16) & 0xff;
26ba25
-            outbuf[42] = (max_io_sectors >> 8) & 0xff;
26ba25
-            outbuf[43] = max_io_sectors & 0xff;
26ba25
-            break;
26ba25
+        DPRINTF("Inquiry EVPD[Device identification] "
26ba25
+                "buffer size %zd\n", req->cmd.xfer);
26ba25
+
26ba25
+        outbuf[buflen++] = 0x2; /* ASCII */
26ba25
+        outbuf[buflen++] = 0;   /* not officially assigned */
26ba25
+        outbuf[buflen++] = 0;   /* reserved */
26ba25
+        outbuf[buflen++] = id_len; /* length of data following */
26ba25
+        memcpy(outbuf + buflen, str, id_len);
26ba25
+        buflen += id_len;
26ba25
+
26ba25
+        if (s->qdev.wwn) {
26ba25
+            outbuf[buflen++] = 0x1; /* Binary */
26ba25
+            outbuf[buflen++] = 0x3; /* NAA */
26ba25
+            outbuf[buflen++] = 0;   /* reserved */
26ba25
+            outbuf[buflen++] = 8;
26ba25
+            stq_be_p(&outbuf[buflen], s->qdev.wwn);
26ba25
+            buflen += 8;
26ba25
         }
26ba25
-        case 0xb1: /* block device characteristics */
26ba25
-        {
26ba25
-            buflen = 8;
26ba25
-            outbuf[4] = (s->rotation_rate >> 8) & 0xff;
26ba25
-            outbuf[5] = s->rotation_rate & 0xff;
26ba25
-            outbuf[6] = 0;
26ba25
-            outbuf[7] = 0;
26ba25
-            break;
26ba25
+
26ba25
+        if (s->qdev.port_wwn) {
26ba25
+            outbuf[buflen++] = 0x61; /* SAS / Binary */
26ba25
+            outbuf[buflen++] = 0x93; /* PIV / Target port / NAA */
26ba25
+            outbuf[buflen++] = 0;    /* reserved */
26ba25
+            outbuf[buflen++] = 8;
26ba25
+            stq_be_p(&outbuf[buflen], s->qdev.port_wwn);
26ba25
+            buflen += 8;
26ba25
         }
26ba25
-        case 0xb2: /* thin provisioning */
26ba25
-        {
26ba25
-            buflen = 8;
26ba25
-            outbuf[4] = 0;
26ba25
-            outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
26ba25
-            outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
26ba25
-            outbuf[7] = 0;
26ba25
-            break;
26ba25
+
26ba25
+        if (s->port_index) {
26ba25
+            outbuf[buflen++] = 0x61; /* SAS / Binary */
26ba25
+
26ba25
+            /* PIV/Target port/relative target port */
26ba25
+            outbuf[buflen++] = 0x94;
26ba25
+
26ba25
+            outbuf[buflen++] = 0;    /* reserved */
26ba25
+            outbuf[buflen++] = 4;
26ba25
+            stw_be_p(&outbuf[buflen + 2], s->port_index);
26ba25
+            buflen += 4;
26ba25
         }
26ba25
-        default:
26ba25
+        break;
26ba25
+    }
26ba25
+    case 0xb0: /* block limits */
26ba25
+    {
26ba25
+        unsigned int unmap_sectors =
26ba25
+            s->qdev.conf.discard_granularity / s->qdev.blocksize;
26ba25
+        unsigned int min_io_size =
26ba25
+            s->qdev.conf.min_io_size / s->qdev.blocksize;
26ba25
+        unsigned int opt_io_size =
26ba25
+            s->qdev.conf.opt_io_size / s->qdev.blocksize;
26ba25
+        unsigned int max_unmap_sectors =
26ba25
+            s->max_unmap_size / s->qdev.blocksize;
26ba25
+        unsigned int max_io_sectors =
26ba25
+            s->max_io_size / s->qdev.blocksize;
26ba25
+
26ba25
+        if (s->qdev.type == TYPE_ROM) {
26ba25
+            DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
26ba25
+                    page_code);
26ba25
             return -1;
26ba25
         }
26ba25
-        /* done with EVPD */
26ba25
-        assert(buflen - start <= 255);
26ba25
-        outbuf[start - 1] = buflen - start;
26ba25
-        return buflen;
26ba25
+        if (s->qdev.type == TYPE_DISK) {
26ba25
+            int max_transfer_blk = blk_get_max_transfer(s->qdev.conf.blk);
26ba25
+            int max_io_sectors_blk =
26ba25
+                max_transfer_blk / s->qdev.blocksize;
26ba25
+
26ba25
+            max_io_sectors =
26ba25
+                MIN_NON_ZERO(max_io_sectors_blk, max_io_sectors);
26ba25
+
26ba25
+            /* min_io_size and opt_io_size can't be greater than
26ba25
+             * max_io_sectors */
26ba25
+            if (min_io_size) {
26ba25
+                min_io_size = MIN(min_io_size, max_io_sectors);
26ba25
+            }
26ba25
+            if (opt_io_size) {
26ba25
+                opt_io_size = MIN(opt_io_size, max_io_sectors);
26ba25
+            }
26ba25
+        }
26ba25
+        /* required VPD size with unmap support */
26ba25
+        buflen = 0x40;
26ba25
+        memset(outbuf + 4, 0, buflen - 4);
26ba25
+
26ba25
+        outbuf[4] = 0x1; /* wsnz */
26ba25
+
26ba25
+        /* optimal transfer length granularity */
26ba25
+        outbuf[6] = (min_io_size >> 8) & 0xff;
26ba25
+        outbuf[7] = min_io_size & 0xff;
26ba25
+
26ba25
+        /* maximum transfer length */
26ba25
+        outbuf[8] = (max_io_sectors >> 24) & 0xff;
26ba25
+        outbuf[9] = (max_io_sectors >> 16) & 0xff;
26ba25
+        outbuf[10] = (max_io_sectors >> 8) & 0xff;
26ba25
+        outbuf[11] = max_io_sectors & 0xff;
26ba25
+
26ba25
+        /* optimal transfer length */
26ba25
+        outbuf[12] = (opt_io_size >> 24) & 0xff;
26ba25
+        outbuf[13] = (opt_io_size >> 16) & 0xff;
26ba25
+        outbuf[14] = (opt_io_size >> 8) & 0xff;
26ba25
+        outbuf[15] = opt_io_size & 0xff;
26ba25
+
26ba25
+        /* max unmap LBA count, default is 1GB */
26ba25
+        outbuf[20] = (max_unmap_sectors >> 24) & 0xff;
26ba25
+        outbuf[21] = (max_unmap_sectors >> 16) & 0xff;
26ba25
+        outbuf[22] = (max_unmap_sectors >> 8) & 0xff;
26ba25
+        outbuf[23] = max_unmap_sectors & 0xff;
26ba25
+
26ba25
+        /* max unmap descriptors, 255 fit in 4 kb with an 8-byte header */
26ba25
+        outbuf[24] = 0;
26ba25
+        outbuf[25] = 0;
26ba25
+        outbuf[26] = 0;
26ba25
+        outbuf[27] = 255;
26ba25
+
26ba25
+        /* optimal unmap granularity */
26ba25
+        outbuf[28] = (unmap_sectors >> 24) & 0xff;
26ba25
+        outbuf[29] = (unmap_sectors >> 16) & 0xff;
26ba25
+        outbuf[30] = (unmap_sectors >> 8) & 0xff;
26ba25
+        outbuf[31] = unmap_sectors & 0xff;
26ba25
+
26ba25
+        /* max write same size */
26ba25
+        outbuf[36] = 0;
26ba25
+        outbuf[37] = 0;
26ba25
+        outbuf[38] = 0;
26ba25
+        outbuf[39] = 0;
26ba25
+
26ba25
+        outbuf[40] = (max_io_sectors >> 24) & 0xff;
26ba25
+        outbuf[41] = (max_io_sectors >> 16) & 0xff;
26ba25
+        outbuf[42] = (max_io_sectors >> 8) & 0xff;
26ba25
+        outbuf[43] = max_io_sectors & 0xff;
26ba25
+        break;
26ba25
+    }
26ba25
+    case 0xb1: /* block device characteristics */
26ba25
+    {
26ba25
+        buflen = 8;
26ba25
+        outbuf[4] = (s->rotation_rate >> 8) & 0xff;
26ba25
+        outbuf[5] = s->rotation_rate & 0xff;
26ba25
+        outbuf[6] = 0;
26ba25
+        outbuf[7] = 0;
26ba25
+        break;
26ba25
+    }
26ba25
+    case 0xb2: /* thin provisioning */
26ba25
+    {
26ba25
+        buflen = 8;
26ba25
+        outbuf[4] = 0;
26ba25
+        outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
26ba25
+        outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
26ba25
+        outbuf[7] = 0;
26ba25
+        break;
26ba25
+    }
26ba25
+    default:
26ba25
+        return -1;
26ba25
+    }
26ba25
+    /* done with EVPD */
26ba25
+    assert(buflen - start <= 255);
26ba25
+    outbuf[start - 1] = buflen - start;
26ba25
+    return buflen;
26ba25
+}
26ba25
+
26ba25
+static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
26ba25
+{
26ba25
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
26ba25
+    int buflen = 0;
26ba25
+
26ba25
+    if (req->cmd.buf[1] & 0x1) {
26ba25
+        /* Vital product data */
26ba25
+        return scsi_disk_emulate_vpd_page(req, outbuf);
26ba25
     }
26ba25
 
26ba25
     /* Standard INQUIRY data */
26ba25
@@ -3040,6 +3049,10 @@ static Property scsi_block_properties[] = {
26ba25
     DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk),
26ba25
     DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false),
26ba25
     DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0),
26ba25
+    DEFINE_PROP_UINT64("max_unmap_size", SCSIDiskState, max_unmap_size,
26ba25
+                       DEFAULT_MAX_UNMAP_SIZE),
26ba25
+    DEFINE_PROP_UINT64("max_io_size", SCSIDiskState, max_io_size,
26ba25
+                       DEFAULT_MAX_IO_SIZE),
26ba25
     DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
26ba25
                       -1),
26ba25
     DEFINE_PROP_END_OF_LIST(),
26ba25
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
26ba25
index 381f04e..796162c 100644
26ba25
--- a/hw/scsi/scsi-generic.c
26ba25
+++ b/hw/scsi/scsi-generic.c
26ba25
@@ -143,6 +143,43 @@ static int execute_command(BlockBackend *blk,
26ba25
     return 0;
26ba25
 }
26ba25
 
26ba25
+static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
26ba25
+{
26ba25
+    /*
26ba25
+     *  EVPD set to zero returns the standard INQUIRY data.
26ba25
+     *
26ba25
+     *  Check if scsi_version is unset (-1) to avoid re-defining it
26ba25
+     *  each time an INQUIRY with standard data is received.
26ba25
+     *  scsi_version is initialized with -1 in scsi_generic_reset
26ba25
+     *  and scsi_disk_reset, making sure that we'll set the
26ba25
+     *  scsi_version after a reset. If the version field of the
26ba25
+     *  INQUIRY response somehow changes after a guest reboot,
26ba25
+     *  we'll be able to keep track of it.
26ba25
+     *
26ba25
+     *  On SCSI-2 and older, first 3 bits of byte 2 is the
26ba25
+     *  ANSI-approved version, while on later versions the
26ba25
+     *  whole byte 2 contains the version. Check if we're dealing
26ba25
+     *  with a newer version and, in that case, assign the
26ba25
+     *  whole byte.
26ba25
+     */
26ba25
+    if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) {
26ba25
+        s->scsi_version = r->buf[2] & 0x07;
26ba25
+        if (s->scsi_version > 2) {
26ba25
+            s->scsi_version = r->buf[2];
26ba25
+        }
26ba25
+    }
26ba25
+    if (s->type == TYPE_DISK && r->req.cmd.buf[2] == 0xb0) {
26ba25
+        uint32_t max_transfer =
26ba25
+            blk_get_max_transfer(s->conf.blk) / s->blocksize;
26ba25
+
26ba25
+        assert(max_transfer);
26ba25
+        stl_be_p(&r->buf[8], max_transfer);
26ba25
+        /* Also take care of the opt xfer len. */
26ba25
+        stl_be_p(&r->buf[12],
26ba25
+                 MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
26ba25
+    }
26ba25
+}
26ba25
+
26ba25
 static void scsi_read_complete(void * opaque, int ret)
26ba25
 {
26ba25
     SCSIGenericReq *r = (SCSIGenericReq *)opaque;
26ba25
@@ -195,39 +232,7 @@ static void scsi_read_complete(void * opaque, int ret)
26ba25
         }
26ba25
     }
26ba25
     if (r->req.cmd.buf[0] == INQUIRY) {
26ba25
-        /*
26ba25
-         *  EVPD set to zero returns the standard INQUIRY data.
26ba25
-         *
26ba25
-         *  Check if scsi_version is unset (-1) to avoid re-defining it
26ba25
-         *  each time an INQUIRY with standard data is received.
26ba25
-         *  scsi_version is initialized with -1 in scsi_generic_reset
26ba25
-         *  and scsi_disk_reset, making sure that we'll set the
26ba25
-         *  scsi_version after a reset. If the version field of the
26ba25
-         *  INQUIRY response somehow changes after a guest reboot,
26ba25
-         *  we'll be able to keep track of it.
26ba25
-         *
26ba25
-         *  On SCSI-2 and older, first 3 bits of byte 2 is the
26ba25
-         *  ANSI-approved version, while on later versions the
26ba25
-         *  whole byte 2 contains the version. Check if we're dealing
26ba25
-         *  with a newer version and, in that case, assign the
26ba25
-         *  whole byte.
26ba25
-         */
26ba25
-        if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) {
26ba25
-            s->scsi_version = r->buf[2] & 0x07;
26ba25
-            if (s->scsi_version > 2) {
26ba25
-                s->scsi_version = r->buf[2];
26ba25
-            }
26ba25
-        }
26ba25
-        if (s->type == TYPE_DISK && r->req.cmd.buf[2] == 0xb0) {
26ba25
-            uint32_t max_transfer =
26ba25
-                blk_get_max_transfer(s->conf.blk) / s->blocksize;
26ba25
-
26ba25
-            assert(max_transfer);
26ba25
-            stl_be_p(&r->buf[8], max_transfer);
26ba25
-            /* Also take care of the opt xfer len. */
26ba25
-            stl_be_p(&r->buf[12],
26ba25
-                     MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
26ba25
-        }
26ba25
+        scsi_handle_inquiry_reply(r, s);
26ba25
     }
26ba25
     scsi_req_data(&r->req, len);
26ba25
     scsi_req_unref(&r->req);
26ba25
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
26ba25
index 1a7290d..5930a43 100644
26ba25
--- a/include/hw/scsi/scsi.h
26ba25
+++ b/include/hw/scsi/scsi.h
26ba25
@@ -188,6 +188,7 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense);
26ba25
 void scsi_device_unit_attention_reported(SCSIDevice *dev);
26ba25
 void scsi_generic_read_device_identification(SCSIDevice *dev);
26ba25
 int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
26ba25
+int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf);
26ba25
 SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
26ba25
 
26ba25
 /* scsi-generic.c. */
26ba25
-- 
26ba25
1.8.3.1
26ba25