qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/5] scsi: More reset and hotplug fixes
@ 2010-05-04 12:20 Jan Kiszka
  2010-05-04 12:20 ` [Qemu-devel] [PATCH 1/5] SCSI: Add disk reset handler Jan Kiszka
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Jan Kiszka @ 2010-05-04 12:20 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, Gerd Hoffmann

This series finally stabilizes system reset during ongoing SCSI I/O
here. The first patch is a repost, the others include missing reset
related bits that mostly concern the LSI controller. And the last patch
addresses a disk hotplugging issue: The LSI used to keep pointers to the
selected device, pointer that can become invalid it the device is
removed in the middle of ongoing I/O.

Jan Kiszka (5):
  SCSI: Add disk reset handler
  scsi-disk: Clear aiocb on read completion
  lsi: Purge message queue on reset
  lsi: Adjust some register reset values
  lsi: Handle removal of selected devices

 hw/lsi53c895a.c |   70 +++++++++++++++++++++++++++++++++++-------------------
 hw/scsi-disk.c  |   37 ++++++++++++++++++++++------
 2 files changed, 74 insertions(+), 33 deletions(-)

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

* [Qemu-devel] [PATCH 1/5] SCSI: Add disk reset handler
  2010-05-04 12:20 [Qemu-devel] [PATCH 0/5] scsi: More reset and hotplug fixes Jan Kiszka
@ 2010-05-04 12:20 ` Jan Kiszka
  2010-05-10 20:19   ` Anthony Liguori
  2010-05-04 12:21 ` [Qemu-devel] [PATCH 2/5] scsi-disk: Clear aiocb on read completion Jan Kiszka
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 9+ messages in thread
From: Jan Kiszka @ 2010-05-04 12:20 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, Gerd Hoffmann

Ensure that pending requests of an SCSI disk are purged on system reset
and also restore max_lba. The latter is no only present in the reset
handler as that one is called after init as well.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/scsi-disk.c |   35 +++++++++++++++++++++++++++--------
 1 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 77cb1da..b8d805f 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1010,22 +1010,45 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     }
 }
 
-static void scsi_destroy(SCSIDevice *dev)
+static void scsi_disk_purge_requests(SCSIDiskState *s)
 {
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
     SCSIDiskReq *r;
 
     while (!QTAILQ_EMPTY(&s->qdev.requests)) {
         r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests));
+        if (r->req.aiocb) {
+            bdrv_aio_cancel(r->req.aiocb);
+        }
         scsi_remove_request(r);
     }
+}
+
+static void scsi_disk_reset(DeviceState *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
+    uint64_t nb_sectors;
+
+    scsi_disk_purge_requests(s);
+
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    nb_sectors /= s->cluster_size;
+    if (nb_sectors) {
+        nb_sectors--;
+    }
+    s->max_lba = nb_sectors;
+}
+
+static void scsi_destroy(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+
+    scsi_disk_purge_requests(s);
     drive_uninit(s->qdev.conf.dinfo);
 }
 
 static int scsi_disk_initfn(SCSIDevice *dev)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-    uint64_t nb_sectors;
 
     if (!s->qdev.conf.dinfo || !s->qdev.conf.dinfo->bdrv) {
         error_report("scsi-disk: drive property not set");
@@ -1046,11 +1069,6 @@ static int scsi_disk_initfn(SCSIDevice *dev)
     s->cluster_size = s->qdev.blocksize / 512;
 
     s->qdev.type = TYPE_DISK;
-    bdrv_get_geometry(s->bs, &nb_sectors);
-    nb_sectors /= s->cluster_size;
-    if (nb_sectors)
-        nb_sectors--;
-    s->max_lba = nb_sectors;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
     return 0;
 }
@@ -1059,6 +1077,7 @@ static SCSIDeviceInfo scsi_disk_info = {
     .qdev.name    = "scsi-disk",
     .qdev.desc    = "virtual scsi disk or cdrom",
     .qdev.size    = sizeof(SCSIDiskState),
+    .qdev.reset   = scsi_disk_reset,
     .init         = scsi_disk_initfn,
     .destroy      = scsi_destroy,
     .send_command = scsi_send_command,
-- 
1.6.0.2

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

* [Qemu-devel] [PATCH 2/5] scsi-disk: Clear aiocb on read completion
  2010-05-04 12:20 [Qemu-devel] [PATCH 0/5] scsi: More reset and hotplug fixes Jan Kiszka
  2010-05-04 12:20 ` [Qemu-devel] [PATCH 1/5] SCSI: Add disk reset handler Jan Kiszka
@ 2010-05-04 12:21 ` Jan Kiszka
  2010-05-04 12:21 ` [Qemu-devel] [PATCH 3/5] lsi: Purge message queue on reset Jan Kiszka
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2010-05-04 12:21 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, Gerd Hoffmann

Once the I/O completion callback returned, aiocb will be released by the
controller. So we have to clear the reference not only in
scsi_write_complete, but also in scsi_read_complete. Otherwise we risk
inconsistencies when a reset hits us before the related request is
released.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/scsi-disk.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index b8d805f..4d20919 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -125,6 +125,8 @@ static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
 
+    r->req.aiocb = NULL;
+
     if (ret) {
         DPRINTF("IO error\n");
         r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
-- 
1.6.0.2

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

* [Qemu-devel] [PATCH 3/5] lsi: Purge message queue on reset
  2010-05-04 12:20 [Qemu-devel] [PATCH 0/5] scsi: More reset and hotplug fixes Jan Kiszka
  2010-05-04 12:20 ` [Qemu-devel] [PATCH 1/5] SCSI: Add disk reset handler Jan Kiszka
  2010-05-04 12:21 ` [Qemu-devel] [PATCH 2/5] scsi-disk: Clear aiocb on read completion Jan Kiszka
@ 2010-05-04 12:21 ` Jan Kiszka
  2010-05-04 12:21 ` [Qemu-devel] [PATCH 4/5] lsi: Adjust some register reset values Jan Kiszka
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2010-05-04 12:21 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, Gerd Hoffmann

Declare the input message queue empty and initialize the related state
machine properly on controller reset. This fixes unrecoverable errors
when the controller was reset during ongoing requests.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/lsi53c895a.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 85eea15..61de23e 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -288,6 +288,8 @@ static void lsi_soft_reset(LSIState *s)
     DPRINTF("Reset\n");
     s->carry = 0;
 
+    s->msg_action = 0;
+    s->msg_len = 0;
     s->waiting = 0;
     s->dsa = 0;
     s->dnad = 0;
-- 
1.6.0.2

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

* [Qemu-devel] [PATCH 4/5] lsi: Adjust some register reset values
  2010-05-04 12:20 [Qemu-devel] [PATCH 0/5] scsi: More reset and hotplug fixes Jan Kiszka
                   ` (2 preceding siblings ...)
  2010-05-04 12:21 ` [Qemu-devel] [PATCH 3/5] lsi: Purge message queue on reset Jan Kiszka
@ 2010-05-04 12:21 ` Jan Kiszka
  2010-05-04 12:21 ` [Qemu-devel] [PATCH 5/5] lsi: Handle removal of selected devices Jan Kiszka
  2010-05-04 13:31 ` [Qemu-devel] Re: [PATCH 0/5] scsi: More reset and hotplug fixes Gerd Hoffmann
  5 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2010-05-04 12:21 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, Gerd Hoffmann

According to the LSI spec, the reset value of dcmd, dstat, and ctest2
were wrong, and sdid as well as ssid require zero initialization. There
are surely more discrepancies, this is just another increment.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/lsi53c895a.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 61de23e..f088d06 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -298,8 +298,8 @@ static void lsi_soft_reset(LSIState *s)
     memset(s->scratch, 0, sizeof(s->scratch));
     s->istat0 = 0;
     s->istat1 = 0;
-    s->dcmd = 0;
-    s->dstat = 0;
+    s->dcmd = 0x40;
+    s->dstat = LSI_DSTAT_DFE;
     s->dien = 0;
     s->sist0 = 0;
     s->sist1 = 0;
@@ -308,7 +308,7 @@ static void lsi_soft_reset(LSIState *s)
     s->mbox0 = 0;
     s->mbox1 = 0;
     s->dfifo = 0;
-    s->ctest2 = 0;
+    s->ctest2 = LSI_CTEST2_DACK;
     s->ctest3 = 0;
     s->ctest4 = 0;
     s->ctest5 = 0;
@@ -327,6 +327,8 @@ static void lsi_soft_reset(LSIState *s)
     s->scid = 7;
     s->sxfer = 0;
     s->socl = 0;
+    s->sdid = 0;
+    s->ssid = 0;
     s->stest1 = 0;
     s->stest2 = 0;
     s->stest3 = 0;
-- 
1.6.0.2

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

* [Qemu-devel] [PATCH 5/5] lsi: Handle removal of selected devices
  2010-05-04 12:20 [Qemu-devel] [PATCH 0/5] scsi: More reset and hotplug fixes Jan Kiszka
                   ` (3 preceding siblings ...)
  2010-05-04 12:21 ` [Qemu-devel] [PATCH 4/5] lsi: Adjust some register reset values Jan Kiszka
@ 2010-05-04 12:21 ` Jan Kiszka
  2010-05-05 14:02   ` [Qemu-devel] [PATCH v2 " Jan Kiszka
  2010-05-04 13:31 ` [Qemu-devel] Re: [PATCH 0/5] scsi: More reset and hotplug fixes Gerd Hoffmann
  5 siblings, 1 reply; 9+ messages in thread
From: Jan Kiszka @ 2010-05-04 12:21 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, Gerd Hoffmann

We must not store references to selected devices as they may be
hot-removed. Instead, look up the device based on its tag right before
using it. If the device disappeared, throw an interrupt and disconnect.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/lsi53c895a.c |   60 ++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index f088d06..9d3c44d 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -175,7 +175,6 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
 
 typedef struct lsi_request {
     uint32_t tag;
-    SCSIDevice *dev;
     uint32_t dma_len;
     uint8_t *dma_buf;
     uint32_t pending;
@@ -202,7 +201,6 @@ typedef struct {
      * 3 if a DMA operation is in progress.  */
     int waiting;
     SCSIBus bus;
-    SCSIDevice *select_dev;
     int current_lun;
     /* The tag is a combination of the device ID and the SCSI tag.  */
     uint32_t select_tag;
@@ -518,11 +516,25 @@ static void lsi_resume_script(LSIState *s)
     }
 }
 
+static void lsi_disconnect(LSIState *s)
+{
+    s->scntl1 &= ~LSI_SCNTL1_CON;
+    s->sstat1 &= ~PHASE_MASK;
+}
+
+static void lsi_bad_selection(LSIState *s, uint32_t id)
+{
+    DPRINTF("Selected absent target %d\n", id);
+    lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
+    lsi_disconnect(s);
+}
+
 /* Initiate a SCSI layer data transfer.  */
 static void lsi_do_dma(LSIState *s, int out)
 {
-    uint32_t count;
+    uint32_t count, id;
     target_phys_addr_t addr;
+    SCSIDevice *dev;
 
     assert(s->current);
     if (!s->current->dma_len) {
@@ -531,6 +543,13 @@ static void lsi_do_dma(LSIState *s, int out)
         return;
     }
 
+    id = s->current->tag >> 8;
+    dev = s->bus.devs[id];
+    if (!dev) {
+        lsi_bad_selection(s, id);
+        return;
+    }
+
     count = s->dbc;
     if (count > s->current->dma_len)
         count = s->current->dma_len;
@@ -550,8 +569,7 @@ static void lsi_do_dma(LSIState *s, int out)
     s->dbc -= count;
 
     if (s->current->dma_buf == NULL) {
-        s->current->dma_buf = s->current->dev->info->get_buf(s->current->dev,
-                                                             s->current->tag);
+        s->current->dma_buf = dev->info->get_buf(dev, s->current->tag);
     }
 
     /* ??? Set SFBR to first data byte.  */
@@ -565,10 +583,10 @@ static void lsi_do_dma(LSIState *s, int out)
         s->current->dma_buf = NULL;
         if (out) {
             /* Write the data.  */
-            s->current->dev->info->write_data(s->current->dev, s->current->tag);
+            dev->info->write_data(dev, s->current->tag);
         } else {
             /* Request any remaining data.  */
-            s->current->dev->info->read_data(s->current->dev, s->current->tag);
+            dev->info->read_data(dev, s->current->tag);
         }
     } else {
         s->current->dma_buf += count;
@@ -715,7 +733,9 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
 
 static void lsi_do_command(LSIState *s)
 {
+    SCSIDevice *dev;
     uint8_t buf[16];
+    uint32_t id;
     int n;
 
     DPRINTF("Send command len=%d\n", s->dbc);
@@ -725,19 +745,24 @@ static void lsi_do_command(LSIState *s)
     s->sfbr = buf[0];
     s->command_complete = 0;
 
+    id = s->select_tag >> 8;
+    dev = s->bus.devs[id];
+    if (!dev) {
+        lsi_bad_selection(s, id);
+        return;
+    }
+
     assert(s->current == NULL);
     s->current = qemu_mallocz(sizeof(lsi_request));
     s->current->tag = s->select_tag;
-    s->current->dev = s->select_dev;
 
-    n = s->current->dev->info->send_command(s->current->dev, s->current->tag, buf,
-                                            s->current_lun);
+    n = dev->info->send_command(dev, s->current->tag, buf, s->current_lun);
     if (n > 0) {
         lsi_set_phase(s, PHASE_DI);
-        s->current->dev->info->read_data(s->current->dev, s->current->tag);
+        dev->info->read_data(dev, s->current->tag);
     } else if (n < 0) {
         lsi_set_phase(s, PHASE_DO);
-        s->current->dev->info->write_data(s->current->dev, s->current->tag);
+        dev->info->write_data(dev, s->current->tag);
     }
 
     if (!s->command_complete) {
@@ -771,12 +796,6 @@ static void lsi_do_status(LSIState *s)
     lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
 }
 
-static void lsi_disconnect(LSIState *s)
-{
-    s->scntl1 &= ~LSI_SCNTL1_CON;
-    s->sstat1 &= ~PHASE_MASK;
-}
-
 static void lsi_do_msgin(LSIState *s)
 {
     int len;
@@ -1092,9 +1111,7 @@ again:
                 s->sstat0 |= LSI_SSTAT0_WOA;
                 s->scntl1 &= ~LSI_SCNTL1_IARB;
                 if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) {
-                    DPRINTF("Selected absent target %d\n", id);
-                    lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
-                    lsi_disconnect(s);
+                    lsi_bad_selection(s, id);
                     break;
                 }
                 DPRINTF("Selected target %d%s\n",
@@ -1102,7 +1119,6 @@ again:
                 /* ??? Linux drivers compain when this is set.  Maybe
                    it only applies in low-level mode (unimplemented).
                 lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
-                s->select_dev = s->bus.devs[id];
                 s->select_tag = id << 8;
                 s->scntl1 |= LSI_SCNTL1_CON;
                 if (insn & (1 << 3)) {
-- 
1.6.0.2

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

* [Qemu-devel] Re: [PATCH 0/5] scsi: More reset and hotplug fixes
  2010-05-04 12:20 [Qemu-devel] [PATCH 0/5] scsi: More reset and hotplug fixes Jan Kiszka
                   ` (4 preceding siblings ...)
  2010-05-04 12:21 ` [Qemu-devel] [PATCH 5/5] lsi: Handle removal of selected devices Jan Kiszka
@ 2010-05-04 13:31 ` Gerd Hoffmann
  5 siblings, 0 replies; 9+ messages in thread
From: Gerd Hoffmann @ 2010-05-04 13:31 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Anthony Liguori, qemu-devel

On 05/04/10 14:20, Jan Kiszka wrote:
> This series finally stabilizes system reset during ongoing SCSI I/O
> here. The first patch is a repost, the others include missing reset
> related bits that mostly concern the LSI controller. And the last patch
> addresses a disk hotplugging issue: The LSI used to keep pointers to the
> selected device, pointer that can become invalid it the device is
> removed in the middle of ongoing I/O.
>
> Jan Kiszka (5):
>    SCSI: Add disk reset handler
>    scsi-disk: Clear aiocb on read completion
>    lsi: Purge message queue on reset
>    lsi: Adjust some register reset values
>    lsi: Handle removal of selected devices

Nice.

Acked-by: Gerd Hoffmann <kraxel@redhat.com>

cheers,
   Gerd

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

* [Qemu-devel] [PATCH v2 5/5] lsi: Handle removal of selected devices
  2010-05-04 12:21 ` [Qemu-devel] [PATCH 5/5] lsi: Handle removal of selected devices Jan Kiszka
@ 2010-05-05 14:02   ` Jan Kiszka
  0 siblings, 0 replies; 9+ messages in thread
From: Jan Kiszka @ 2010-05-05 14:02 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: qemu-devel, Gerd Hoffmann

We must not store references to selected devices as they may be
hot-removed. Instead, look up the device based on its tag right before
using it. If the device disappeared, throw an interrupt and disconnect.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

Changes in v2:
 - Fixed incorrect tag->id conversion (missing LSI_TAG_VALID masking)

 hw/lsi53c895a.c |   60 +++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index f088d06..f5a91ba 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -175,7 +175,6 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
 
 typedef struct lsi_request {
     uint32_t tag;
-    SCSIDevice *dev;
     uint32_t dma_len;
     uint8_t *dma_buf;
     uint32_t pending;
@@ -202,7 +201,6 @@ typedef struct {
      * 3 if a DMA operation is in progress.  */
     int waiting;
     SCSIBus bus;
-    SCSIDevice *select_dev;
     int current_lun;
     /* The tag is a combination of the device ID and the SCSI tag.  */
     uint32_t select_tag;
@@ -518,11 +516,25 @@ static void lsi_resume_script(LSIState *s)
     }
 }
 
+static void lsi_disconnect(LSIState *s)
+{
+    s->scntl1 &= ~LSI_SCNTL1_CON;
+    s->sstat1 &= ~PHASE_MASK;
+}
+
+static void lsi_bad_selection(LSIState *s, uint32_t id)
+{
+    DPRINTF("Selected absent target %d\n", id);
+    lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
+    lsi_disconnect(s);
+}
+
 /* Initiate a SCSI layer data transfer.  */
 static void lsi_do_dma(LSIState *s, int out)
 {
-    uint32_t count;
+    uint32_t count, id;
     target_phys_addr_t addr;
+    SCSIDevice *dev;
 
     assert(s->current);
     if (!s->current->dma_len) {
@@ -531,6 +543,13 @@ static void lsi_do_dma(LSIState *s, int out)
         return;
     }
 
+    id = (s->current->tag >> 8) & 0xf;
+    dev = s->bus.devs[id];
+    if (!dev) {
+        lsi_bad_selection(s, id);
+        return;
+    }
+
     count = s->dbc;
     if (count > s->current->dma_len)
         count = s->current->dma_len;
@@ -550,8 +569,7 @@ static void lsi_do_dma(LSIState *s, int out)
     s->dbc -= count;
 
     if (s->current->dma_buf == NULL) {
-        s->current->dma_buf = s->current->dev->info->get_buf(s->current->dev,
-                                                             s->current->tag);
+        s->current->dma_buf = dev->info->get_buf(dev, s->current->tag);
     }
 
     /* ??? Set SFBR to first data byte.  */
@@ -565,10 +583,10 @@ static void lsi_do_dma(LSIState *s, int out)
         s->current->dma_buf = NULL;
         if (out) {
             /* Write the data.  */
-            s->current->dev->info->write_data(s->current->dev, s->current->tag);
+            dev->info->write_data(dev, s->current->tag);
         } else {
             /* Request any remaining data.  */
-            s->current->dev->info->read_data(s->current->dev, s->current->tag);
+            dev->info->read_data(dev, s->current->tag);
         }
     } else {
         s->current->dma_buf += count;
@@ -715,7 +733,9 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
 
 static void lsi_do_command(LSIState *s)
 {
+    SCSIDevice *dev;
     uint8_t buf[16];
+    uint32_t id;
     int n;
 
     DPRINTF("Send command len=%d\n", s->dbc);
@@ -725,19 +745,24 @@ static void lsi_do_command(LSIState *s)
     s->sfbr = buf[0];
     s->command_complete = 0;
 
+    id = (s->select_tag >> 8) & 0xf;
+    dev = s->bus.devs[id];
+    if (!dev) {
+        lsi_bad_selection(s, id);
+        return;
+    }
+
     assert(s->current == NULL);
     s->current = qemu_mallocz(sizeof(lsi_request));
     s->current->tag = s->select_tag;
-    s->current->dev = s->select_dev;
 
-    n = s->current->dev->info->send_command(s->current->dev, s->current->tag, buf,
-                                            s->current_lun);
+    n = dev->info->send_command(dev, s->current->tag, buf, s->current_lun);
     if (n > 0) {
         lsi_set_phase(s, PHASE_DI);
-        s->current->dev->info->read_data(s->current->dev, s->current->tag);
+        dev->info->read_data(dev, s->current->tag);
     } else if (n < 0) {
         lsi_set_phase(s, PHASE_DO);
-        s->current->dev->info->write_data(s->current->dev, s->current->tag);
+        dev->info->write_data(dev, s->current->tag);
     }
 
     if (!s->command_complete) {
@@ -771,12 +796,6 @@ static void lsi_do_status(LSIState *s)
     lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
 }
 
-static void lsi_disconnect(LSIState *s)
-{
-    s->scntl1 &= ~LSI_SCNTL1_CON;
-    s->sstat1 &= ~PHASE_MASK;
-}
-
 static void lsi_do_msgin(LSIState *s)
 {
     int len;
@@ -1092,9 +1111,7 @@ again:
                 s->sstat0 |= LSI_SSTAT0_WOA;
                 s->scntl1 &= ~LSI_SCNTL1_IARB;
                 if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) {
-                    DPRINTF("Selected absent target %d\n", id);
-                    lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
-                    lsi_disconnect(s);
+                    lsi_bad_selection(s, id);
                     break;
                 }
                 DPRINTF("Selected target %d%s\n",
@@ -1102,7 +1119,6 @@ again:
                 /* ??? Linux drivers compain when this is set.  Maybe
                    it only applies in low-level mode (unimplemented).
                 lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
-                s->select_dev = s->bus.devs[id];
                 s->select_tag = id << 8;
                 s->scntl1 |= LSI_SCNTL1_CON;
                 if (insn & (1 << 3)) {

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

* Re: [Qemu-devel] [PATCH 1/5] SCSI: Add disk reset handler
  2010-05-04 12:20 ` [Qemu-devel] [PATCH 1/5] SCSI: Add disk reset handler Jan Kiszka
@ 2010-05-10 20:19   ` Anthony Liguori
  0 siblings, 0 replies; 9+ messages in thread
From: Anthony Liguori @ 2010-05-10 20:19 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Anthony Liguori, qemu-devel, Gerd Hoffmann

On 05/04/2010 07:20 AM, Jan Kiszka wrote:
> Ensure that pending requests of an SCSI disk are purged on system reset
> and also restore max_lba. The latter is no only present in the reset
> handler as that one is called after init as well.
>
> Signed-off-by: Jan Kiszka<jan.kiszka@siemens.com>
>    

Applied all (including v2 of 5/5).  Thanks.

Regards,

Anthony Liguori

> ---
>   hw/scsi-disk.c |   35 +++++++++++++++++++++++++++--------
>   1 files changed, 27 insertions(+), 8 deletions(-)
>
> diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
> index 77cb1da..b8d805f 100644
> --- a/hw/scsi-disk.c
> +++ b/hw/scsi-disk.c
> @@ -1010,22 +1010,45 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
>       }
>   }
>
> -static void scsi_destroy(SCSIDevice *dev)
> +static void scsi_disk_purge_requests(SCSIDiskState *s)
>   {
> -    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
>       SCSIDiskReq *r;
>
>       while (!QTAILQ_EMPTY(&s->qdev.requests)) {
>           r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests));
> +        if (r->req.aiocb) {
> +            bdrv_aio_cancel(r->req.aiocb);
> +        }
>           scsi_remove_request(r);
>       }
> +}
> +
> +static void scsi_disk_reset(DeviceState *dev)
> +{
> +    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
> +    uint64_t nb_sectors;
> +
> +    scsi_disk_purge_requests(s);
> +
> +    bdrv_get_geometry(s->bs,&nb_sectors);
> +    nb_sectors /= s->cluster_size;
> +    if (nb_sectors) {
> +        nb_sectors--;
> +    }
> +    s->max_lba = nb_sectors;
> +}
> +
> +static void scsi_destroy(SCSIDevice *dev)
> +{
> +    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
> +
> +    scsi_disk_purge_requests(s);
>       drive_uninit(s->qdev.conf.dinfo);
>   }
>
>   static int scsi_disk_initfn(SCSIDevice *dev)
>   {
>       SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
> -    uint64_t nb_sectors;
>
>       if (!s->qdev.conf.dinfo || !s->qdev.conf.dinfo->bdrv) {
>           error_report("scsi-disk: drive property not set");
> @@ -1046,11 +1069,6 @@ static int scsi_disk_initfn(SCSIDevice *dev)
>       s->cluster_size = s->qdev.blocksize / 512;
>
>       s->qdev.type = TYPE_DISK;
> -    bdrv_get_geometry(s->bs,&nb_sectors);
> -    nb_sectors /= s->cluster_size;
> -    if (nb_sectors)
> -        nb_sectors--;
> -    s->max_lba = nb_sectors;
>       qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
>       return 0;
>   }
> @@ -1059,6 +1077,7 @@ static SCSIDeviceInfo scsi_disk_info = {
>       .qdev.name    = "scsi-disk",
>       .qdev.desc    = "virtual scsi disk or cdrom",
>       .qdev.size    = sizeof(SCSIDiskState),
> +    .qdev.reset   = scsi_disk_reset,
>       .init         = scsi_disk_initfn,
>       .destroy      = scsi_destroy,
>       .send_command = scsi_send_command,
>    

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

end of thread, other threads:[~2010-05-10 20:19 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-05-04 12:20 [Qemu-devel] [PATCH 0/5] scsi: More reset and hotplug fixes Jan Kiszka
2010-05-04 12:20 ` [Qemu-devel] [PATCH 1/5] SCSI: Add disk reset handler Jan Kiszka
2010-05-10 20:19   ` Anthony Liguori
2010-05-04 12:21 ` [Qemu-devel] [PATCH 2/5] scsi-disk: Clear aiocb on read completion Jan Kiszka
2010-05-04 12:21 ` [Qemu-devel] [PATCH 3/5] lsi: Purge message queue on reset Jan Kiszka
2010-05-04 12:21 ` [Qemu-devel] [PATCH 4/5] lsi: Adjust some register reset values Jan Kiszka
2010-05-04 12:21 ` [Qemu-devel] [PATCH 5/5] lsi: Handle removal of selected devices Jan Kiszka
2010-05-05 14:02   ` [Qemu-devel] [PATCH v2 " Jan Kiszka
2010-05-04 13:31 ` [Qemu-devel] Re: [PATCH 0/5] scsi: More reset and hotplug fixes Gerd Hoffmann

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).