diff mbox series

[1/4] scsi-generic: keep VPD page list sorted

Message ID 20181029173437.32559-2-pbonzini@redhat.com
State New
Headers show
Series scsi-generic: fixes for Block Limits emulation | expand

Commit Message

Paolo Bonzini Oct. 29, 2018, 5:34 p.m. UTC
Block limits emulation is just placing 0xb0 as the final byte of the
VPD pages list.  However, VPD page numbers must be sorted, so change
that to an in-place insert.  Since I couldn't find any disk that triggered
the loop more than once, this was tested by adding manually 0xb1
at the end of the list and checking that 0xb0 was added before.

Reported-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi/scsi-generic.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

Comments

Max Reitz Nov. 6, 2018, 1:45 a.m. UTC | #1
On 29.10.18 18:34, Paolo Bonzini wrote:
> Block limits emulation is just placing 0xb0 as the final byte of the
> VPD pages list.  However, VPD page numbers must be sorted, so change
> that to an in-place insert.  Since I couldn't find any disk that triggered
> the loop more than once, this was tested by adding manually 0xb1
> at the end of the list and checking that 0xb0 was added before.
> 
> Reported-by: Max Reitz <mreitz@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  hw/scsi/scsi-generic.c | 19 +++++++++++++++----
>  1 file changed, 15 insertions(+), 4 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>
Daniel Henrique Barboza Nov. 6, 2018, 3:39 p.m. UTC | #2
On 10/29/18 2:34 PM, Paolo Bonzini wrote:
> Block limits emulation is just placing 0xb0 as the final byte of the
> VPD pages list.  However, VPD page numbers must be sorted, so change
> that to an in-place insert.  Since I couldn't find any disk that triggered
> the loop more than once, this was tested by adding manually 0xb1
> at the end of the list and checking that 0xb0 was added before.
>
> Reported-by: Max Reitz <mreitz@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---

Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>


Out of curiosity: how did you hit an issue with the ordering?

>   hw/scsi/scsi-generic.c | 19 +++++++++++++++----
>   1 file changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
> index d60c4d0fcf..aebb7cdd82 100644
> --- a/hw/scsi/scsi-generic.c
> +++ b/hw/scsi/scsi-generic.c
> @@ -144,7 +144,7 @@ static int execute_command(BlockBackend *blk,
>   
>   static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
>   {
> -    uint8_t page, page_len;
> +    uint8_t page, page_idx;
>   
>       /*
>        *  EVPD set to zero returns the standard INQUIRY data.
> @@ -190,10 +190,21 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
>                *
>                * This way, the guest kernel will be aware of the support
>                * and will use it to proper setup the SCSI device.
> +             *
> +             * VPD page numbers must be sorted, so insert 0xb0 at the
> +             * right place with an in-place insert.  After the initialization
> +             * part of the for loop is executed, the device response is
> +             * at r[0] to r[page_idx - 1].
>                */
> -            page_len = r->buf[3];
> -            r->buf[page_len + 4] = 0xb0;
> -            r->buf[3] = ++page_len;
> +            for (page_idx = lduw_be_p(r->buf + 2) + 4;
> +                 page_idx > 4 && r->buf[page_idx - 1] >= 0xb0;
> +                 page_idx--) {
> +                if (page_idx < r->buflen) {
> +                    r->buf[page_idx] = r->buf[page_idx - 1];
> +                }
> +            }
> +            r->buf[page_idx] = 0xb0;
> +            stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1);
>           }
>       }
>   }
diff mbox series

Patch

diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index d60c4d0fcf..aebb7cdd82 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -144,7 +144,7 @@  static int execute_command(BlockBackend *blk,
 
 static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
 {
-    uint8_t page, page_len;
+    uint8_t page, page_idx;
 
     /*
      *  EVPD set to zero returns the standard INQUIRY data.
@@ -190,10 +190,21 @@  static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
              *
              * This way, the guest kernel will be aware of the support
              * and will use it to proper setup the SCSI device.
+             *
+             * VPD page numbers must be sorted, so insert 0xb0 at the
+             * right place with an in-place insert.  After the initialization
+             * part of the for loop is executed, the device response is
+             * at r[0] to r[page_idx - 1].
              */
-            page_len = r->buf[3];
-            r->buf[page_len + 4] = 0xb0;
-            r->buf[3] = ++page_len;
+            for (page_idx = lduw_be_p(r->buf + 2) + 4;
+                 page_idx > 4 && r->buf[page_idx - 1] >= 0xb0;
+                 page_idx--) {
+                if (page_idx < r->buflen) {
+                    r->buf[page_idx] = r->buf[page_idx - 1];
+                }
+            }
+            r->buf[page_idx] = 0xb0;
+            stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1);
         }
     }
 }