qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation
@ 2009-01-28 14:51 Rik van Riel
  2009-01-28 14:51 ` [Qemu-devel] [PATCH 1/3] fix signed/unsigned overflows in SCSI disk Rik van Riel
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Rik van Riel @ 2009-01-28 14:51 UTC (permalink / raw)
  To: qemu-devel

This small patch series contains several fixes for the
SCSI disk emulation:
- fixes for signed/unsigned overflows
- support for >2TB SCSI disks
- report the correct number of sectors in read capacity

Thanks go out to Paul Brook and Jamie Lokier for reviewing
earlier versions of these patches and pointing additional
TODOs.

-- 
All rights reversed.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 1/3] fix signed/unsigned overflows in SCSI disk
  2009-01-28 14:51 [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation Rik van Riel
@ 2009-01-28 14:51 ` Rik van Riel
  2009-01-28 14:51 ` [Qemu-devel] [PATCH 2/3] support >2TB SCSI disks Rik van Riel
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Rik van Riel @ 2009-01-28 14:51 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: qemu-upstream.diff --]
[-- Type: text/plain, Size: 1784 bytes --]

Sector numbers can overflow on a virtual scsi disk of over 1TB
in size.  Qemu's bdrv_read expects an int64_t, so fix the overflow
by going to that data type.

On large disks, we clip the capacity to 2TB instead of returning
"capacity modulo 2TB".

Turn sector_count into an unsigned to prevent a signed/unsigned
overflow with SCSI transfers larger than 2TB.  We're unlikely to
ever hit this bug, but fixing it is just one line.

Signed-off-by: Rik van Riel <riel@redhat.com>


Index: qemu/trunk/hw/scsi-disk.c
===================================================================
--- qemu.orig/trunk/hw/scsi-disk.c
+++ qemu/trunk/hw/scsi-disk.c
@@ -47,11 +47,11 @@ do { fprintf(stderr, "scsi-disk: " fmt ,
 typedef struct SCSIRequest {
     SCSIDeviceState *dev;
     uint32_t tag;
-    /* ??? We should probably keep track of whether the data trasfer is
+    /* ??? We should probably keep track of whether the data transfer is
        a read or a write.  Currently we rely on the host getting it right.  */
     /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
-    int sector;
-    int sector_count;
+    uint64_t sector;
+    uint32_t sector_count;
     /* The amounnt of data in the buffer.  */
     int buf_len;
     uint8_t *dma_buf;
@@ -731,6 +731,9 @@ static int32_t scsi_send_command(SCSIDev
         /* Returned value is the address of the last sector.  */
         if (nb_sectors) {
             nb_sectors--;
+            /* Clip to 2TB, instead of returning capacity modulo 2TB. */
+            if (nb_sectors > UINT32_MAX)
+                nb_sectors = UINT32_MAX;
             outbuf[0] = (nb_sectors >> 24) & 0xff;
             outbuf[1] = (nb_sectors >> 16) & 0xff;
             outbuf[2] = (nb_sectors >> 8) & 0xff;

-- 
All rights reversed.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 2/3] support >2TB SCSI disks
  2009-01-28 14:51 [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation Rik van Riel
  2009-01-28 14:51 ` [Qemu-devel] [PATCH 1/3] fix signed/unsigned overflows in SCSI disk Rik van Riel
@ 2009-01-28 14:51 ` Rik van Riel
  2009-01-28 14:51 ` [Qemu-devel] [PATCH 3/3] SCSI divide capacity by s->cluster_size Rik van Riel
  2009-01-28 21:59 ` [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation Anthony Liguori
  3 siblings, 0 replies; 8+ messages in thread
From: Rik van Riel @ 2009-01-28 14:51 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: qemu-scsi-largedisks.patch --]
[-- Type: text/plain, Size: 4543 bytes --]

Implement SCSI READ(16), WRITE(16) and SAI READ CAPACITY(16) commands,
so SCSI disks larger than 2TB can work with guests that support these
newer SCSI commands.

The cast to (uint64_t) is needed because otherwise gcc will use a
signed int, which gets sign extended into uint64_t lba, resulting
in bad block numbers for READ 10 and READ 16 with block numbers
larger than 2^31.

Signed-off-by: Rik van Riel <riel@redhat.com>


Index: qemu/trunk/hw/scsi-disk.c
===================================================================
--- qemu.orig/trunk/hw/scsi-disk.c
+++ qemu/trunk/hw/scsi-disk.c
@@ -346,7 +346,7 @@ static int32_t scsi_send_command(SCSIDev
 {
     SCSIDeviceState *s = d->state;
     uint64_t nb_sectors;
-    uint32_t lba;
+    uint64_t lba;
     uint32_t len;
     int cmdlen;
     int is_write;
@@ -368,23 +368,29 @@ static int32_t scsi_send_command(SCSIDev
     DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
     switch (command >> 5) {
     case 0:
-        lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
+        lba = (uint64_t) buf[3] | ((uint64_t) buf[2] << 8) |
+              (((uint64_t) buf[1] & 0x1f) << 16);
         len = buf[4];
         cmdlen = 6;
         break;
     case 1:
     case 2:
-        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
+              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
         len = buf[8] | (buf[7] << 8);
         cmdlen = 10;
         break;
     case 4:
-        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+        lba = (uint64_t) buf[9] | ((uint64_t) buf[8] << 8) |
+              ((uint64_t) buf[7] << 16) | ((uint64_t) buf[6] << 24) |
+              ((uint64_t) buf[5] << 32) | ((uint64_t) buf[4] << 40) |
+              ((uint64_t) buf[3] << 48) | ((uint64_t) buf[2] << 56);
         len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
         cmdlen = 16;
         break;
     case 5:
-        lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
+        lba = (uint64_t) buf[5] | ((uint64_t) buf[4] << 8) |
+              ((uint64_t) buf[3] << 16) | ((uint64_t) buf[2] << 24);
         len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
         cmdlen = 12;
         break;
@@ -750,13 +756,15 @@ static int32_t scsi_send_command(SCSIDev
 	break;
     case 0x08:
     case 0x28:
-        DPRINTF("Read (sector %d, count %d)\n", lba, len);
+    case 0x88:
+        DPRINTF("Read (sector %lld, count %d)\n", lba, len);
         r->sector = lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         break;
     case 0x0a:
     case 0x2a:
-        DPRINTF("Write (sector %d, count %d)\n", lba, len);
+    case 0x8a:
+        DPRINTF("Write (sector %lld, count %d)\n", lba, len);
         r->sector = lba * s->cluster_size;
         r->sector_count = len * s->cluster_size;
         is_write = 1;
@@ -820,6 +828,37 @@ static int32_t scsi_send_command(SCSIDev
         if (buf[1] & 3)
             goto fail;
         break;
+    case 0x9e:
+        /* Service Action In subcommands. */
+        if ((buf[1] & 31) == 0x10) {
+            DPRINTF("SAI READ CAPACITY(16)\n");
+            memset(outbuf, 0, len);
+            bdrv_get_geometry(s->bdrv, &nb_sectors);
+            /* Returned value is the address of the last sector.  */
+            if (nb_sectors) {
+                nb_sectors--;
+                outbuf[0] = (nb_sectors >> 56) & 0xff;
+                outbuf[1] = (nb_sectors >> 48) & 0xff;
+                outbuf[2] = (nb_sectors >> 40) & 0xff;
+                outbuf[3] = (nb_sectors >> 32) & 0xff;
+                outbuf[4] = (nb_sectors >> 24) & 0xff;
+                outbuf[5] = (nb_sectors >> 16) & 0xff;
+                outbuf[6] = (nb_sectors >> 8) & 0xff;
+                outbuf[7] = nb_sectors & 0xff;
+                outbuf[8] = 0;
+                outbuf[9] = 0;
+                outbuf[10] = s->cluster_size * 2;
+                outbuf[11] = 0;
+                /* Protection, exponent and lowest lba field left blank. */
+                r->buf_len = len;
+            } else {
+                scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
+                return 0;
+            }
+            break;
+        }
+        DPRINTF("Unsupported Service Action In\n");
+        goto fail;
     case 0xa0:
         DPRINTF("Report LUNs (len %d)\n", len);
         if (len < 16)

-- 
All rights reversed.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 3/3] SCSI divide capacity by s->cluster_size
  2009-01-28 14:51 [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation Rik van Riel
  2009-01-28 14:51 ` [Qemu-devel] [PATCH 1/3] fix signed/unsigned overflows in SCSI disk Rik van Riel
  2009-01-28 14:51 ` [Qemu-devel] [PATCH 2/3] support >2TB SCSI disks Rik van Riel
@ 2009-01-28 14:51 ` Rik van Riel
  2009-01-28 16:49   ` Rene Rebe
  2009-01-28 21:42   ` Anthony Liguori
  2009-01-28 21:59 ` [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation Anthony Liguori
  3 siblings, 2 replies; 8+ messages in thread
From: Rik van Riel @ 2009-01-28 14:51 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: qemu-capacity-sectors.patch --]
[-- Type: text/plain, Size: 1316 bytes --]

Paul Brook pointed out that the number of sectors reported
by the SCSI read capacity commands needs to be divided by
s->cluster_size, because bdrv_get_geometry reports the number
of 512 byte sectors, while emulated CDROMs report 2048 byte
sectors back to the guest.

This has no consequences for emulated hard disks, which use
a cluster size of 1.

Signed-off-by: Rik van Riel <riel@redhat.com>

Index: qemu/trunk/hw/scsi-disk.c
===================================================================
--- qemu.orig/trunk/hw/scsi-disk.c
+++ qemu/trunk/hw/scsi-disk.c
@@ -734,6 +734,7 @@ static int32_t scsi_send_command(SCSIDev
         /* The normal LEN field for this command is zero.  */
 	memset(outbuf, 0, 8);
 	bdrv_get_geometry(s->bdrv, &nb_sectors);
+        nb_sectors =/ s->cluster_size;
         /* Returned value is the address of the last sector.  */
         if (nb_sectors) {
             nb_sectors--;
@@ -834,6 +835,7 @@ static int32_t scsi_send_command(SCSIDev
             DPRINTF("SAI READ CAPACITY(16)\n");
             memset(outbuf, 0, len);
             bdrv_get_geometry(s->bdrv, &nb_sectors);
+            nb_sectors =/ s->cluster_size;
             /* Returned value is the address of the last sector.  */
             if (nb_sectors) {
                 nb_sectors--;

-- 
All rights reversed.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 3/3] SCSI divide capacity by s->cluster_size
  2009-01-28 14:51 ` [Qemu-devel] [PATCH 3/3] SCSI divide capacity by s->cluster_size Rik van Riel
@ 2009-01-28 16:49   ` Rene Rebe
  2009-01-28 16:52     ` Rik van Riel
  2009-01-28 21:42   ` Anthony Liguori
  1 sibling, 1 reply; 8+ messages in thread
From: Rene Rebe @ 2009-01-28 16:49 UTC (permalink / raw)
  To: qemu-devel

Hi,

 > --- qemu.orig/trunk/hw/scsi-disk.c
 > +++ qemu/trunk/hw/scsi-disk.c
 > @@ -734,6 +734,7 @@ static int32_t scsi_send_command(SCSIDev
 >          /* The normal LEN field for this command is zero.  */
 >  	memset(outbuf, 0, 8);
 >  	bdrv_get_geometry(s->bdrv, &nb_sectors);
 > +        nb_sectors =/ s->cluster_size;

/=

 >          /* Returned value is the address of the last sector.  */
 >          if (nb_sectors) {
 >              nb_sectors--;
 > @@ -834,6 +835,7 @@ static int32_t scsi_send_command(SCSIDev
 >              DPRINTF("SAI READ CAPACITY(16)\n");
 >              memset(outbuf, 0, len);
 >              bdrv_get_geometry(s->bdrv, &nb_sectors);
 > +            nb_sectors =/ s->cluster_size;

dito?

 >              /* Returned value is the address of the last sector.  */
 >              if (nb_sectors) {
 >                  nb_sectors--;

-- 
   René Rebe - ExactCODE GmbH - Europe, Germany, Berlin
   http://exactcode.de | http://t2-project.org | http://rene.rebe.name

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 3/3] SCSI divide capacity by s->cluster_size
  2009-01-28 16:49   ` Rene Rebe
@ 2009-01-28 16:52     ` Rik van Riel
  0 siblings, 0 replies; 8+ messages in thread
From: Rik van Riel @ 2009-01-28 16:52 UTC (permalink / raw)
  To: Rene Rebe; +Cc: qemu-devel

Rene Rebe wrote:
> Hi,
> 
>  > --- qemu.orig/trunk/hw/scsi-disk.c
>  > +++ qemu/trunk/hw/scsi-disk.c
>  > @@ -734,6 +734,7 @@ static int32_t scsi_send_command(SCSIDev
>  >          /* The normal LEN field for this command is zero.  */
>  >      memset(outbuf, 0, 8);
>  >      bdrv_get_geometry(s->bdrv, &nb_sectors);
>  > +        nb_sectors =/ s->cluster_size;
> 
> /=

Doh!  That's what I get for trying to make the code a little
nicer after compiling it.

-- 
All rights reversed.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 3/3] SCSI divide capacity by s->cluster_size
  2009-01-28 14:51 ` [Qemu-devel] [PATCH 3/3] SCSI divide capacity by s->cluster_size Rik van Riel
  2009-01-28 16:49   ` Rene Rebe
@ 2009-01-28 21:42   ` Anthony Liguori
  1 sibling, 0 replies; 8+ messages in thread
From: Anthony Liguori @ 2009-01-28 21:42 UTC (permalink / raw)
  To: qemu-devel

Rik van Riel wrote:
> ndex: qemu/trunk/hw/scsi-disk.c
> ===================================================================
> --- qemu.orig/trunk/hw/scsi-disk.c
> +++ qemu/trunk/hw/scsi-disk.c
> @@ -734,6 +734,7 @@ static int32_t scsi_send_command(SCSIDev
>          /* The normal LEN field for this command is zero.  */
>      memset(outbuf, 0, 8);
>      bdrv_get_geometry(s->bdrv, &nb_sectors);
> +        nb_sectors =/ s->cluster_size;

An emoticon, perhaps, but certainly not a C operator.. :-)

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation
  2009-01-28 14:51 [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation Rik van Riel
                   ` (2 preceding siblings ...)
  2009-01-28 14:51 ` [Qemu-devel] [PATCH 3/3] SCSI divide capacity by s->cluster_size Rik van Riel
@ 2009-01-28 21:59 ` Anthony Liguori
  3 siblings, 0 replies; 8+ messages in thread
From: Anthony Liguori @ 2009-01-28 21:59 UTC (permalink / raw)
  To: qemu-devel

Rik van Riel wrote:
> This small patch series contains several fixes for the
> SCSI disk emulation:
> - fixes for signed/unsigned overflows
> - support for >2TB SCSI disks
> - report the correct number of sectors in read capacity
>
> Thanks go out to Paul Brook and Jamie Lokier for reviewing
> earlier versions of these patches and pointing additional
> TODOs.
>
>   
Applied (fixing patch 3).  Thanks.

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2009-01-28 22:00 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-28 14:51 [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation Rik van Riel
2009-01-28 14:51 ` [Qemu-devel] [PATCH 1/3] fix signed/unsigned overflows in SCSI disk Rik van Riel
2009-01-28 14:51 ` [Qemu-devel] [PATCH 2/3] support >2TB SCSI disks Rik van Riel
2009-01-28 14:51 ` [Qemu-devel] [PATCH 3/3] SCSI divide capacity by s->cluster_size Rik van Riel
2009-01-28 16:49   ` Rene Rebe
2009-01-28 16:52     ` Rik van Riel
2009-01-28 21:42   ` Anthony Liguori
2009-01-28 21:59 ` [Qemu-devel] [PATCH 0/3] fixes for the SCSI disk emulation Anthony Liguori

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).