diff mbox series

[v2,27/42] esp: fix PDMA target selection

Message ID 20210209193018.31339-28-mark.cave-ayland@ilande.co.uk
State New
Headers show
Series esp: consolidate PDMA transfer buffers and other fixes | expand

Commit Message

Mark Cave-Ayland Feb. 9, 2021, 7:30 p.m. UTC
Currently the target selection for PDMA is done after the SCSI command has been
delivered which is not correct. Perform target selection as part of the initial
get_cmd() call when the command is submitted: if no target is present, don't
raise DRQ.

If the target is present then switch to the command phase since the MacOS toolbox
ROM checks for this before attempting to submit the SCSI command.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c | 53 +++++++++++++++++++++++++++++++++------------------
 1 file changed, 34 insertions(+), 19 deletions(-)

Comments

Laurent Vivier March 2, 2021, 9:57 p.m. UTC | #1
Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> Currently the target selection for PDMA is done after the SCSI command has been
> delivered which is not correct. Perform target selection as part of the initial
> get_cmd() call when the command is submitted: if no target is present, don't
> raise DRQ.
> 
> If the target is present then switch to the command phase since the MacOS toolbox
> ROM checks for this before attempting to submit the SCSI command.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 53 +++++++++++++++++++++++++++++++++------------------
>  1 file changed, 34 insertions(+), 19 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 6736e7142c..b7ab5a5592 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -243,6 +243,9 @@ static uint32_t get_cmd(ESPState *s)
>              s->dma_memory_read(s->dma_opaque, buf, dmalen);
>          } else {
>              set_pdma(s, TI);
> +            if (esp_select(s) < 0) {
> +                return -1;
> +            }
>              esp_raise_drq(s);
>              return 0;
>          }
> @@ -257,7 +260,7 @@ static uint32_t get_cmd(ESPState *s)
>      trace_esp_get_cmd(dmalen, target);
>  
>      if (esp_select(s) < 0) {
> -        return 0;
> +        return -1;
>      }
>      return dmalen;
>  }
> @@ -299,9 +302,6 @@ static void do_cmd(ESPState *s)
>  
>  static void satn_pdma_cb(ESPState *s)
>  {
> -    if (esp_select(s) < 0) {
> -        return;
> -    }
>      s->do_cmd = 0;
>      if (s->cmdlen) {
>          do_cmd(s);
> @@ -310,24 +310,28 @@ static void satn_pdma_cb(ESPState *s)
>  
>  static void handle_satn(ESPState *s)
>  {
> +    int32_t cmdlen;
> +
>      if (s->dma && !s->dma_enabled) {
>          s->dma_cb = handle_satn;
>          return;
>      }
>      s->pdma_cb = satn_pdma_cb;
> -    s->cmdlen = get_cmd(s);
> -    if (s->cmdlen) {
> +    cmdlen = get_cmd(s);
> +    if (cmdlen > 0) {
> +        s->cmdlen = cmdlen;
>          do_cmd(s);
> -    } else {
> +    } else if (cmdlen == 0) {
> +        s->cmdlen = 0;
>          s->do_cmd = 1;
> +        /* Target present, but no cmd yet - switch to command phase */
> +        s->rregs[ESP_RSEQ] = SEQ_CD;
> +        s->rregs[ESP_RSTAT] = STAT_CD;
>      }
>  }
>  
>  static void s_without_satn_pdma_cb(ESPState *s)
>  {
> -    if (esp_select(s) < 0) {
> -        return;
> -    }
>      s->do_cmd = 0;
>      if (s->cmdlen) {
>          do_busid_cmd(s, s->cmdbuf, 0);
> @@ -336,24 +340,28 @@ static void s_without_satn_pdma_cb(ESPState *s)
>  
>  static void handle_s_without_atn(ESPState *s)
>  {
> +    int32_t cmdlen;
> +
>      if (s->dma && !s->dma_enabled) {
>          s->dma_cb = handle_s_without_atn;
>          return;
>      }
>      s->pdma_cb = s_without_satn_pdma_cb;
> -    s->cmdlen = get_cmd(s);
> -    if (s->cmdlen) {
> +    cmdlen = get_cmd(s);
> +    if (cmdlen > 0) {
> +        s->cmdlen = cmdlen;
>          do_busid_cmd(s, s->cmdbuf, 0);
> -    } else {
> +    } else if (cmdlen == 0) {
> +        s->cmdlen = 0;
>          s->do_cmd = 1;
> +        /* Target present, but no cmd yet - switch to command phase */
> +        s->rregs[ESP_RSEQ] = SEQ_CD;
> +        s->rregs[ESP_RSTAT] = STAT_CD;
>      }
>  }
>  
>  static void satn_stop_pdma_cb(ESPState *s)
>  {
> -    if (esp_select(s) < 0) {
> -        return;
> -    }
>      s->do_cmd = 0;
>      if (s->cmdlen) {
>          trace_esp_handle_satn_stop(s->cmdlen);
> @@ -367,21 +375,28 @@ static void satn_stop_pdma_cb(ESPState *s)
>  
>  static void handle_satn_stop(ESPState *s)
>  {
> +    int32_t cmdlen;
> +
>      if (s->dma && !s->dma_enabled) {
>          s->dma_cb = handle_satn_stop;
>          return;
>      }
>      s->pdma_cb = satn_stop_pdma_cb;
> -    s->cmdlen = get_cmd(s);
> -    if (s->cmdlen) {
> +    cmdlen = get_cmd(s);
> +    if (cmdlen > 0) {
>          trace_esp_handle_satn_stop(s->cmdlen);
> +        s->cmdlen = cmdlen;
>          s->do_cmd = 1;
>          s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
>          s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
>          s->rregs[ESP_RSEQ] = SEQ_CD;
>          esp_raise_irq(s);
> -    } else {
> +    } else if (cmdlen == 0) {
> +        s->cmdlen = 0;
>          s->do_cmd = 1;
> +        /* Target present, but no cmd yet - switch to command phase */
> +        s->rregs[ESP_RSEQ] = SEQ_CD;
> +        s->rregs[ESP_RSTAT] = STAT_CD;
>      }
>  }
>  
> 

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
diff mbox series

Patch

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 6736e7142c..b7ab5a5592 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -243,6 +243,9 @@  static uint32_t get_cmd(ESPState *s)
             s->dma_memory_read(s->dma_opaque, buf, dmalen);
         } else {
             set_pdma(s, TI);
+            if (esp_select(s) < 0) {
+                return -1;
+            }
             esp_raise_drq(s);
             return 0;
         }
@@ -257,7 +260,7 @@  static uint32_t get_cmd(ESPState *s)
     trace_esp_get_cmd(dmalen, target);
 
     if (esp_select(s) < 0) {
-        return 0;
+        return -1;
     }
     return dmalen;
 }
@@ -299,9 +302,6 @@  static void do_cmd(ESPState *s)
 
 static void satn_pdma_cb(ESPState *s)
 {
-    if (esp_select(s) < 0) {
-        return;
-    }
     s->do_cmd = 0;
     if (s->cmdlen) {
         do_cmd(s);
@@ -310,24 +310,28 @@  static void satn_pdma_cb(ESPState *s)
 
 static void handle_satn(ESPState *s)
 {
+    int32_t cmdlen;
+
     if (s->dma && !s->dma_enabled) {
         s->dma_cb = handle_satn;
         return;
     }
     s->pdma_cb = satn_pdma_cb;
-    s->cmdlen = get_cmd(s);
-    if (s->cmdlen) {
+    cmdlen = get_cmd(s);
+    if (cmdlen > 0) {
+        s->cmdlen = cmdlen;
         do_cmd(s);
-    } else {
+    } else if (cmdlen == 0) {
+        s->cmdlen = 0;
         s->do_cmd = 1;
+        /* Target present, but no cmd yet - switch to command phase */
+        s->rregs[ESP_RSEQ] = SEQ_CD;
+        s->rregs[ESP_RSTAT] = STAT_CD;
     }
 }
 
 static void s_without_satn_pdma_cb(ESPState *s)
 {
-    if (esp_select(s) < 0) {
-        return;
-    }
     s->do_cmd = 0;
     if (s->cmdlen) {
         do_busid_cmd(s, s->cmdbuf, 0);
@@ -336,24 +340,28 @@  static void s_without_satn_pdma_cb(ESPState *s)
 
 static void handle_s_without_atn(ESPState *s)
 {
+    int32_t cmdlen;
+
     if (s->dma && !s->dma_enabled) {
         s->dma_cb = handle_s_without_atn;
         return;
     }
     s->pdma_cb = s_without_satn_pdma_cb;
-    s->cmdlen = get_cmd(s);
-    if (s->cmdlen) {
+    cmdlen = get_cmd(s);
+    if (cmdlen > 0) {
+        s->cmdlen = cmdlen;
         do_busid_cmd(s, s->cmdbuf, 0);
-    } else {
+    } else if (cmdlen == 0) {
+        s->cmdlen = 0;
         s->do_cmd = 1;
+        /* Target present, but no cmd yet - switch to command phase */
+        s->rregs[ESP_RSEQ] = SEQ_CD;
+        s->rregs[ESP_RSTAT] = STAT_CD;
     }
 }
 
 static void satn_stop_pdma_cb(ESPState *s)
 {
-    if (esp_select(s) < 0) {
-        return;
-    }
     s->do_cmd = 0;
     if (s->cmdlen) {
         trace_esp_handle_satn_stop(s->cmdlen);
@@ -367,21 +375,28 @@  static void satn_stop_pdma_cb(ESPState *s)
 
 static void handle_satn_stop(ESPState *s)
 {
+    int32_t cmdlen;
+
     if (s->dma && !s->dma_enabled) {
         s->dma_cb = handle_satn_stop;
         return;
     }
     s->pdma_cb = satn_stop_pdma_cb;
-    s->cmdlen = get_cmd(s);
-    if (s->cmdlen) {
+    cmdlen = get_cmd(s);
+    if (cmdlen > 0) {
         trace_esp_handle_satn_stop(s->cmdlen);
+        s->cmdlen = cmdlen;
         s->do_cmd = 1;
         s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
         esp_raise_irq(s);
-    } else {
+    } else if (cmdlen == 0) {
+        s->cmdlen = 0;
         s->do_cmd = 1;
+        /* Target present, but no cmd yet - switch to command phase */
+        s->rregs[ESP_RSEQ] = SEQ_CD;
+        s->rregs[ESP_RSTAT] = STAT_CD;
     }
 }