All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: George Kennedy <george.kennedy@oracle.com>,
	Fam Zheng <famz@redhat.com>,
	qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v2] lsi: Reselection needed to remove pending commands from queue
Date: Thu, 25 Oct 2018 00:27:01 +0200	[thread overview]
Message-ID: <394610f8-1bfd-62ef-247b-8ad6330f3d4a@redhat.com> (raw)
In-Reply-To: <51309caa-23eb-9c3b-329e-2885fe13d905@oracle.com>

On 24/10/2018 15:06, George Kennedy wrote:
>>
>>
>> Why didn't lsi_do_command invoke lsi_queue_command?  That would set
>> s->current to NULL (on the SCSI level, that means the bus is freed; on
>> the QEMU level, the idea is that lsi_transfer_data would then start a
>> reselection).
> 
> Through the extended period of time with no call to lsi_reselect(), the
> check of "s->command_complete" in lsi_do_command() is always "1" and
> therefore no call to lsi_queue_command() occurs.
> 
> "s->command_complete" is set to "1" in lsi_transfer_data().

Ok, I think we're getting closer.  If the data transfer is from the
device (read), then you can disconnect until the read is complete.

If the data transfer however is to the device (write), there will be
immediately a call to scsi_transfer_data, in order to get the written
data, and s->command_complete is set to 1.

However, this is wrong: the DMA transfer doesn't per se prevent a
disconnect and a later reselect, and this might be the bug.  Basically
we want to get rid of the "s->command_complete = 1" case completely.
The patch to do this change in the SCSI bus handling would look
something like this (untested):

diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index d1e6534311..c32ef40e78 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -565,6 +565,21 @@ static void lsi_bad_selection(LSIState *s, uint32_t id)
     lsi_disconnect(s);
 }

+/* Disconnect when DMA has finished but the command did not
+ * complete immediately.
+ */
+static void lsi_maybe_disconnect(LSIState *s)
+{
+    if (!s->current->dma_len && !s->command_complete) {
+        lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
+        lsi_add_msg_byte(s, 4); /* DISCONNECT */
+        /* wait data */
+        lsi_set_phase(s, PHASE_MI);
+        s->msg_action = 1;
+        lsi_queue_command(s);
+    }
+}
+
 /* Initiate a SCSI layer data transfer.  */
 static void lsi_do_dma(LSIState *s, int out)
 {
@@ -612,6 +627,7 @@ static void lsi_do_dma(LSIState *s, int out)
     if (s->current->dma_len == 0) {
         s->current->dma_buf = NULL;
         scsi_req_continue(s->current->req);
+        lsi_maybe_disconnect(s);
     } else {
         s->current->dma_buf += count;
         lsi_resume_script(s);
@@ -631,7 +647,6 @@ static void lsi_queue_command(LSIState *s)
     s->current = NULL;

     p->pending = 0;
-    p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
 }

 /* Queue a byte for a MSG IN phase.  */
@@ -746,7 +761,7 @@ static void lsi_command_complete(SCSIRequest *req,
     out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
     trace_lsi_command_complete(status);
     s->status = status;
-    s->command_complete = 2;
+    s->command_complete = 1;
     if (s->waiting && s->dbc != 0) {
         /* Raise phase mismatch for short transfers.  */
         lsi_bad_phase(s, out, PHASE_ST);
@@ -781,7 +796,6 @@ static void lsi_transfer_data(SCSIRequest *req,
     /* host adapter (re)connected */
     trace_lsi_transfer_data(req->tag, len);
     s->current->dma_len = len;
-    s->command_complete = 1;
     if (s->waiting) {
         if (s->waiting == 1 || s->dbc == 0) {
             lsi_resume_script(s);
@@ -819,28 +833,12 @@ static void lsi_do_command(LSIState *s)
                                    s->current);

     n = scsi_req_enqueue(s->current->req);
+    s->current->out = (n < 0);
+    lsi_set_phase(s, s->current->out ? PHASE_DO : PHASE_DI);
     if (n) {
-        if (n > 0) {
-            lsi_set_phase(s, PHASE_DI);
-        } else if (n < 0) {
-            lsi_set_phase(s, PHASE_DO);
-        }
         scsi_req_continue(s->current->req);
     }
-    if (!s->command_complete) {
-        if (n) {
-            /* Command did not complete immediately so disconnect.  */
-            lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
-            lsi_add_msg_byte(s, 4); /* DISCONNECT */
-            /* wait data */
-            lsi_set_phase(s, PHASE_MI);
-            s->msg_action = 1;
-            lsi_queue_command(s);
-        } else {
-            /* wait command complete */
-            lsi_set_phase(s, PHASE_DI);
-        }
-    }
+    lsi_maybe_disconnect(s);
 }

 static void lsi_do_status(LSIState *s)


Of course, this doesn't include the change to WAIT RESELECT handling.
It only ensures (or attempts to ensure) that the bus is disconnected and
later reselected on long-running I/O, no matter the data direction.

Thanks,

Paolo

      reply	other threads:[~2018-10-24 22:27 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-22 21:28 [Qemu-devel] [PATCH v2] lsi: Reselection needed to remove pending commands from queue George Kennedy
2018-10-23 14:33 ` Paolo Bonzini
2018-10-23 21:36   ` George Kennedy
2018-10-23 21:50     ` Paolo Bonzini
2018-10-23 22:11       ` George Kennedy
2018-10-23 22:31         ` Paolo Bonzini
2018-10-24 13:06           ` George Kennedy
2018-10-24 22:27             ` Paolo Bonzini [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=394610f8-1bfd-62ef-247b-8ad6330f3d4a@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=famz@redhat.com \
    --cc=george.kennedy@oracle.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.