diff mbox

virtio-scsi Fix some endian bugs with virtio-scsi

Message ID 1353647324-19840-1-git-send-email-david@gibson.dropbear.id.au
State New
Headers show

Commit Message

David Gibson Nov. 23, 2012, 5:08 a.m. UTC
The virtio-scsi specification does not specify the correct endianness for
fields in the request structure.  It's therefore best to assume that it is
"guest native" endian since that's the (stupid and poorly defined) norm in
virtio.

However, the qemu device for virtio-scsi has no byteswaps at all, and so
will break if the guest has different endianness from the host.  This patch
fixes it by adding tswap() calls for the sense_len and resid fields in
the request structure.  In theory status_qualifier needs swaps as well,
but that field is never actually touched.  The tag field is a uint64_t, but
since its value is completely arbitrary, it might as well be uint8_t[8]
and so it does not need swapping.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Paul 'Rusty' Russell <rusty@rustcorp.com.au>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 hw/virtio-scsi.c |    5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Stefan Hajnoczi Nov. 23, 2012, 7:11 a.m. UTC | #1
On Fri, Nov 23, 2012 at 04:08:44PM +1100, David Gibson wrote:
> The virtio-scsi specification does not specify the correct endianness for
> fields in the request structure.  It's therefore best to assume that it is
> "guest native" endian since that's the (stupid and poorly defined) norm in
> virtio.
> 
> However, the qemu device for virtio-scsi has no byteswaps at all, and so
> will break if the guest has different endianness from the host.  This patch
> fixes it by adding tswap() calls for the sense_len and resid fields in
> the request structure.  In theory status_qualifier needs swaps as well,
> but that field is never actually touched.  The tag field is a uint64_t, but
> since its value is completely arbitrary, it might as well be uint8_t[8]
> and so it does not need swapping.
> 
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Paul 'Rusty' Russell <rusty@rustcorp.com.au>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/virtio-scsi.c |    5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Paolo Bonzini Nov. 23, 2012, 7:29 a.m. UTC | #2
Il 23/11/2012 06:08, David Gibson ha scritto:
> The virtio-scsi specification does not specify the correct endianness for
> fields in the request structure.  It's therefore best to assume that it is
> "guest native" endian since that's the (stupid and poorly defined) norm in
> virtio.

Indeed.

> However, the qemu device for virtio-scsi has no byteswaps at all, and so
> will break if the guest has different endianness from the host.  This patch
> fixes it by adding tswap() calls for the sense_len and resid fields in
> the request structure.  In theory status_qualifier needs swaps as well,
> but that field is never actually touched.  The tag field is a uint64_t, but
> since its value is completely arbitrary, it might as well be uint8_t[8]
> and so it does not need swapping.

Thanks, I adjusted the patch to use a separate variable for the argument
of tswap32 and pushed to the scsi branch.

Paolo

> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Paul 'Rusty' Russell <rusty@rustcorp.com.au>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  hw/virtio-scsi.c |    5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
> index 7d546f6..9d27d1d 100644
> --- a/hw/virtio-scsi.c
> +++ b/hw/virtio-scsi.c
> @@ -428,11 +428,12 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
>      req->resp.cmd->response = VIRTIO_SCSI_S_OK;
>      req->resp.cmd->status = status;
>      if (req->resp.cmd->status == GOOD) {
> -        req->resp.cmd->resid = resid;
> +        req->resp.cmd->resid = tswap32(resid);
>      } else {
>          req->resp.cmd->resid = 0;
>          req->resp.cmd->sense_len =
> -            scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE);
> +            tswap32(scsi_req_get_sense(r, req->resp.cmd->sense,
> +                                       VIRTIO_SCSI_SENSE_SIZE));
>      }
>      virtio_scsi_complete_req(req);
>  }
>
Rusty Russell Dec. 2, 2012, 10:08 p.m. UTC | #3
David Gibson <david@gibson.dropbear.id.au> writes:

> The virtio-scsi specification does not specify the correct endianness for
> fields in the request structure.  It's therefore best to assume that it is
> "guest native" endian since that's the (stupid and poorly defined) norm in
> virtio.
>
> However, the qemu device for virtio-scsi has no byteswaps at all, and so
> will break if the guest has different endianness from the host.  This patch
> fixes it by adding tswap() calls for the sense_len and resid fields in
> the request structure.  In theory status_qualifier needs swaps as well,
> but that field is never actually touched.  The tag field is a uint64_t, but
> since its value is completely arbitrary, it might as well be uint8_t[8]
> and so it does not need swapping.
>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Paul 'Rusty' Russell <rusty@rustcorp.com.au>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Good catch, thanks for this David.

Cheers,
Rusty.
diff mbox

Patch

diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 7d546f6..9d27d1d 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -428,11 +428,12 @@  static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
     req->resp.cmd->response = VIRTIO_SCSI_S_OK;
     req->resp.cmd->status = status;
     if (req->resp.cmd->status == GOOD) {
-        req->resp.cmd->resid = resid;
+        req->resp.cmd->resid = tswap32(resid);
     } else {
         req->resp.cmd->resid = 0;
         req->resp.cmd->sense_len =
-            scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE);
+            tswap32(scsi_req_get_sense(r, req->resp.cmd->sense,
+                                       VIRTIO_SCSI_SENSE_SIZE));
     }
     virtio_scsi_complete_req(req);
 }