All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes
@ 2021-02-09 19:29 Mark Cave-Ayland
  2021-02-09 19:29 ` [PATCH v2 01/42] esp: checkpatch fixes Mark Cave-Ayland
                   ` (42 more replies)
  0 siblings, 43 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

This patch series comes from an experimental branch that I've been working on
to try and boot a MacOS toolbox ROM under the QEMU q800 machine. The effort is
far from complete, but it seems worth submitting these patches separately since
they are limited to the ESP device and form a substantial part of the work to
date.

As part of Laurent's recent q800 work so-called PDMA (pseudo-DMA) support was
added to the ESP device. This is whereby the DREQ (DMA request) line is used
to signal to the host CPU that it can transfer data to/from the device over
the SCSI bus.

The existing PDMA tracks 4 separate transfer data sources as indicated by the
ESP pdma_origin variable: PDMA, TI, CMD and ASYNC with an independent variable
pdma_len to store the transfer length. This works well with Linux which uses a
single PDMA request to transfer a number of sectors in a single request.

Unfortunately the MacOS toolbox ROM has other ideas here: it sends data to the
ESP as a mixture of FIFO and PDMA transfers and then uses a mixture of the FIFO
and DMA counters to confirm that the correct number of bytes have been
transferred. For this to work correctly the PDMA buffers and separate pdma_len
transfer counter must be consolidated into the FIFO to allow mixing of both
types of transfer within a single request.

The patchset is split into several sections:

- Patches 1-7 are minor patches which make esp.c checkpatch friendly, QOMify ESPState,
  and also fix up some trace events ready for later patches in the series

- Patches 8-13 unify the DMA transfer count. In particular there are 2 synthetic
  variables dma_counter and dma_left within ESPState which do not need to exist. 
  DMA transfer lengths are programmed into the TC (transfer count) register which is 
  decremented for each byte transferred, generating an interrupt when it reaches zero.
  These patches add helper functions to read the TC and STC registers directly and
  remove these synthetic variables so that the DMA transfer length is now tracked in
  a single place.

- Now that the TC register represents the authoritative DMA transfer length, patches
  14-25 work to eliminate the separate PDMA variables pdma_start, pdma_cur, pdma_len
  and separate PDMA buffers PDMA and CMD. The PDMA position variables can be replaced
  by the existing ESP cmdlen and ti_wptr/ti_rptr, whilst the FIFO (TI) buffer is used
  for incoming data with commands being accumulated in cmdbuf as per standard DMA
  requests.

- Patches 26 and 27 fix the detection of missing SCSI targets by the MacOS toolbox ROM
  on startup at which point it will attempt to start reading information from a CDROM
  attached to the q800 machine.

- Patch 28 is the main rework of the PDMA buffer transfers: instead of tracking the
  SCSI transfers using a separate ASYNC pdma_origin, the contents of the ESPState
  async_buf are copied to the FIFO buffer in 16-byte chunks with the transfer status
  and IRQs being set accordingly.

- Patch 29 removes the last separate PDMA variable pdma_origin, including the separate
  PDMA migration subsection which is no longer required (see note below about migration
  compatibility).
  
- Patch 30 enables 4 byte PDMA reads/writes over the SCSI bus which are used by MacOS
  when reading the next stage bootloader from CDROM (this is an increase from
  2 bytes currently implemented and used by Linux).

- Patches 31-34 fix an issue whereby the MacOS toolbox ROM tries to read incoming data
  from the target within a few instructions of receiving the command complete interrupt.
  Since IO is asynchronous in QEMU, it is necessary to delay the command complete
  interrupt for incoming data to avoid underflow.

- Patches 35-37 fix a problem with the SATN and stop command not changing the SCSI bus
  to message out phase. This actually first manifested itself after the Fifo8 conversion
  with guests that mix DMA/non-DMA commands but it is moved forward to aid bisection.

- Patches 38-39 convert ti_buf and cmdbuf from simple arrays to QEMU's Fifo8 type which
  helped locate a handful of bugs around handling the buffer pointers which are
  incorpated within earlier patches within the series.
  
- Finally patches 40-42 add support for the FIFO count registers, non-DMA transfers and
  unaligned accesses which are required for the MacOS toolbox ROM to successful read
  files from disk.

  
Testing
=======

I've tested this on my SPARC32 OpenBIOS images which include Linux, OpenBSD, NetBSD,
and Solaris and all of these continue to boot as before.

Similarly the q800 m68k Linux test image still boots as before with these patches
applied. It is possible with lots of hacks to load Laurent's EMILE bootloader using
a MacOS toolbox ROM - the hope is to try and start upstreaming more of these changes
as time allows.

Many thanks to Guenter Roeck <linux@roeck-us.net> who provided me a test image for
the deferred interrupt test case, and also confirmed the updated version still
worked fine in his tests.


Migration
=========

The patchset ensures that ESP devices without PDMA (i.e. everything except the q800
machine) will migrate successfully. This is fairly simple: the only change required
here is to copy the old synthetic dma_left value over into the TC.

Unfortunately migrating the PDMA subsection is a lot harder due to the change in the
way that the DMA TC and changes to the point at which transfer counters are updated.
For this reason the patchset will not migrate from older q800 snapshots: I don't
believe this to be a problem since some devices are still missing VMStateDescription
plus there are likely to be more breaking changes as the q800 machine matures.


Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>


v2:
- Rebase onto master
- Add R-B tags from Philippe
- Add QOMification, Fifo8 conversion, deferred interrupt for incoming data, message
  out phase fixes, non-DMA commands, and unaligned access support


Mark Cave-Ayland (42):
  esp: checkpatch fixes
  esp: rename existing ESP QOM type to SYSBUS_ESP
  esp: QOMify the internal ESP device state
  esp: add vmstate_esp version to embedded ESPState
  esp: add trace event when receiving a TI command
  esp: fix esp_reg_read() trace event
  esp: add PDMA trace events
  esp: determine transfer direction directly from SCSI phase
  esp: introduce esp_get_tc() and esp_set_tc()
  esp: introduce esp_get_stc()
  esp: apply transfer length adjustment when STC is zero at TC load time
  esp: remove dma_counter from ESPState
  esp: remove dma_left from ESPState
  esp: remove minlen restriction in handle_ti
  esp: introduce esp_pdma_read() and esp_pdma_write() functions
  esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write()
  esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write()
  esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of
    pdma_buf
  esp: remove buf parameter from do_cmd()
  esp: remove the buf and buflen parameters from get_cmd()
  esp: remove redundant pdma_start from ESPState
  esp: move PDMA length adjustments into
    esp_pdma_read()/esp_pdma_write()
  esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA
  esp: use in-built TC to determine PDMA transfer length
  esp: remove CMD pdma_origin
  esp: rename get_cmd_cb() to esp_select()
  esp: fix PDMA target selection
  esp: use FIFO for PDMA transfers between initiator and device
  esp: remove pdma_origin from ESPState
  esp: add 4 byte PDMA read and write transfers
  esp: implement FIFO flush command
  esp: latch individual bits in ESP_RINTR register
  esp: defer command completion interrupt on incoming data transfers
  esp: remove old deferred command completion mechanism  
  esp: raise interrupt after every non-DMA byte transferred to the FIFO
  esp: add maxlen parameter to get_cmd()
  esp: transition to message out phase after SATN and stop command
  esp: convert ti_buf from array to Fifo8
  esp: convert cmdbuf from array to Fifo8
  esp: add trivial implementation of the ESP_RFLAGS register
  esp: implement non-DMA transfers in PDMA mode
  esp: add support for unaligned accesses

 hw/dma/sparc32_dma.c  |   4 +-
 hw/m68k/q800.c        |   4 +-
 hw/mips/jazz.c        |   4 +-
 hw/scsi/esp-pci.c     |  51 ++-
 hw/scsi/esp.c         | 978 +++++++++++++++++++++++++++++-------------
 hw/scsi/trace-events  |   5 +
 hw/sparc/sun4m.c      |   2 +-
 include/hw/scsi/esp.h |  52 +--
 8 files changed, 750 insertions(+), 350 deletions(-)

-- 
2.20.1



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

* [PATCH v2 01/42] esp: checkpatch fixes
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-03-01 19:43   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 02/42] esp: rename existing ESP QOM type to SYSBUS_ESP Mark Cave-Ayland
                   ` (41 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 hw/scsi/esp.c | 52 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 31 insertions(+), 21 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index b84e0fe33e..7073166ad1 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -241,8 +241,9 @@ static void handle_satn(ESPState *s)
     }
     s->pdma_cb = satn_pdma_cb;
     len = get_cmd(s, buf, sizeof(buf));
-    if (len)
+    if (len) {
         do_cmd(s, buf);
+    }
 }
 
 static void s_without_satn_pdma_cb(ESPState *s)
@@ -398,8 +399,8 @@ static void esp_do_dma(ESPState *s)
          * handle_ti_cmd() with do_cmd != NULL (see the assert())
          */
         trace_esp_do_dma(s->cmdlen, len);
-        assert (s->cmdlen <= sizeof(s->cmdbuf) &&
-                len <= sizeof(s->cmdbuf) - s->cmdlen);
+        assert(s->cmdlen <= sizeof(s->cmdbuf) &&
+               len <= sizeof(s->cmdbuf) - s->cmdlen);
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
         } else {
@@ -445,15 +446,18 @@ static void esp_do_dma(ESPState *s)
     s->dma_left -= len;
     s->async_buf += len;
     s->async_len -= len;
-    if (to_device)
+    if (to_device) {
         s->ti_size += len;
-    else
+    } else {
         s->ti_size -= len;
+    }
     if (s->async_len == 0) {
         scsi_req_continue(s->current_req);
-        /* If there is still data to be read from the device then
-           complete the DMA operation immediately.  Otherwise defer
-           until the scsi layer has completed.  */
+        /*
+         * If there is still data to be read from the device then
+         * complete the DMA operation immediately.  Otherwise defer
+         * until the scsi layer has completed.
+         */
         if (to_device || s->dma_left != 0 || s->ti_size == 0) {
             return;
         }
@@ -491,7 +495,8 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
     ESPState *s = req->hba_private;
 
     if (s->rregs[ESP_RSTAT] & STAT_INT) {
-        /* Defer handling command complete until the previous
+        /*
+         * Defer handling command complete until the previous
          * interrupt has been handled.
          */
         trace_esp_command_complete_deferred();
@@ -513,8 +518,10 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
     if (s->dma_left) {
         esp_do_dma(s);
     } else if (s->dma_counter != 0 && s->ti_size <= 0) {
-        /* If this was the last part of a DMA transfer then the
-           completion interrupt is deferred to here.  */
+        /*
+         * If this was the last part of a DMA transfer then the
+         * completion interrupt is deferred to here.
+         */
         esp_dma_done(s);
     }
 }
@@ -531,17 +538,18 @@ static void handle_ti(ESPState *s)
     dmalen = s->rregs[ESP_TCLO];
     dmalen |= s->rregs[ESP_TCMID] << 8;
     dmalen |= s->rregs[ESP_TCHI] << 16;
-    if (dmalen==0) {
-      dmalen=0x10000;
+    if (dmalen == 0) {
+        dmalen = 0x10000;
     }
     s->dma_counter = dmalen;
 
-    if (s->do_cmd)
+    if (s->do_cmd) {
         minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
-    else if (s->ti_size < 0)
+    } else if (s->ti_size < 0) {
         minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
-    else
+    } else {
         minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
+    }
     trace_esp_handle_ti(minlen);
     if (s->dma) {
         s->dma_left = minlen;
@@ -606,8 +614,10 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
         }
         break;
     case ESP_RINTR:
-        /* Clear sequence step, interrupt register and all status bits
-           except TC */
+        /*
+         * Clear sequence step, interrupt register and all status bits
+         * except TC
+         */
         old_val = s->rregs[ESP_RINTR];
         s->rregs[ESP_RINTR] = 0;
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
@@ -665,13 +675,13 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
         } else {
             s->dma = 0;
         }
-        switch(val & CMD_CMD) {
+        switch (val & CMD_CMD) {
         case CMD_NOP:
             trace_esp_mem_writeb_cmd_nop(val);
             break;
         case CMD_FLUSH:
             trace_esp_mem_writeb_cmd_flush(val);
-            //s->ti_size = 0;
+            /*s->ti_size = 0;*/
             s->rregs[ESP_RINTR] = INTR_FC;
             s->rregs[ESP_RSEQ] = 0;
             s->rregs[ESP_RFLAGS] = 0;
@@ -787,7 +797,7 @@ static const VMStateDescription vmstate_esp_pdma = {
 };
 
 const VMStateDescription vmstate_esp = {
-    .name ="esp",
+    .name = "esp",
     .version_id = 4,
     .minimum_version_id = 3,
     .fields = (VMStateField[]) {
-- 
2.20.1



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

* [PATCH v2 02/42] esp: rename existing ESP QOM type to SYSBUS_ESP
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
  2021-02-09 19:29 ` [PATCH v2 01/42] esp: checkpatch fixes Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-10 22:29   ` Philippe Mathieu-Daudé
  2021-03-01 19:52   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 03/42] esp: QOMify the internal ESP device state Mark Cave-Ayland
                   ` (40 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The existing ESP QOM type currently represents a sysbus device with an embedded
ESP state. Rename the type to SYSBUS_ESP accordingly.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/dma/sparc32_dma.c  | 4 ++--
 hw/m68k/q800.c        | 4 ++--
 hw/mips/jazz.c        | 4 ++--
 hw/scsi/esp.c         | 8 ++++----
 hw/sparc/sun4m.c      | 2 +-
 include/hw/scsi/esp.h | 4 ++--
 6 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c
index b643b413c5..03bc500878 100644
--- a/hw/dma/sparc32_dma.c
+++ b/hw/dma/sparc32_dma.c
@@ -295,13 +295,13 @@ static void sparc32_espdma_device_init(Object *obj)
     memory_region_init_io(&s->iomem, OBJECT(s), &dma_mem_ops, s,
                           "espdma-mmio", DMA_SIZE);
 
-    object_initialize_child(obj, "esp", &es->esp, TYPE_ESP);
+    object_initialize_child(obj, "esp", &es->esp, TYPE_SYSBUS_ESP);
 }
 
 static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp)
 {
     ESPDMADeviceState *es = SPARC32_ESPDMA_DEVICE(dev);
-    SysBusESPState *sysbus = ESP(&es->esp);
+    SysBusESPState *sysbus = SYSBUS_ESP(&es->esp);
     ESPState *esp = &sysbus->esp;
 
     esp->dma_memory_read = espdma_memory_read;
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 2af0e2532e..af54d509ff 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -356,8 +356,8 @@ static void q800_init(MachineState *machine)
 
     /* SCSI */
 
-    dev = qdev_new(TYPE_ESP);
-    sysbus_esp = ESP(dev);
+    dev = qdev_new(TYPE_SYSBUS_ESP);
+    sysbus_esp = SYSBUS_ESP(dev);
     esp = &sysbus_esp->esp;
     esp->dma_memory_read = NULL;
     esp->dma_memory_write = NULL;
diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c
index 83c8086062..1a0888a0fd 100644
--- a/hw/mips/jazz.c
+++ b/hw/mips/jazz.c
@@ -328,8 +328,8 @@ static void mips_jazz_init(MachineState *machine,
     }
 
     /* SCSI adapter */
-    dev = qdev_new(TYPE_ESP);
-    sysbus_esp = ESP(dev);
+    dev = qdev_new(TYPE_SYSBUS_ESP);
+    sysbus_esp = SYSBUS_ESP(dev);
     esp = &sysbus_esp->esp;
     esp->dma_memory_read = rc4030_dma_read;
     esp->dma_memory_write = rc4030_dma_write;
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 7073166ad1..aa38acc660 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -939,7 +939,7 @@ static const struct SCSIBusInfo esp_scsi_info = {
 
 static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
 {
-    SysBusESPState *sysbus = ESP(opaque);
+    SysBusESPState *sysbus = SYSBUS_ESP(opaque);
     ESPState *s = &sysbus->esp;
 
     switch (irq) {
@@ -955,7 +955,7 @@ static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
 static void sysbus_esp_realize(DeviceState *dev, Error **errp)
 {
     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-    SysBusESPState *sysbus = ESP(dev);
+    SysBusESPState *sysbus = SYSBUS_ESP(dev);
     ESPState *s = &sysbus->esp;
 
     sysbus_init_irq(sbd, &s->irq);
@@ -977,7 +977,7 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
 
 static void sysbus_esp_hard_reset(DeviceState *dev)
 {
-    SysBusESPState *sysbus = ESP(dev);
+    SysBusESPState *sysbus = SYSBUS_ESP(dev);
     esp_hard_reset(&sysbus->esp);
 }
 
@@ -1002,7 +1002,7 @@ static void sysbus_esp_class_init(ObjectClass *klass, void *data)
 }
 
 static const TypeInfo sysbus_esp_info = {
-    .name          = TYPE_ESP,
+    .name          = TYPE_SYSBUS_ESP,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(SysBusESPState),
     .class_init    = sysbus_esp_class_init,
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 38ca1e33c7..312e2afaf9 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -334,7 +334,7 @@ static void *sparc32_dma_init(hwaddr dma_base,
                                    OBJECT(dma), "espdma"));
     sysbus_connect_irq(SYS_BUS_DEVICE(espdma), 0, espdma_irq);
 
-    esp = ESP(object_resolve_path_component(OBJECT(espdma), "esp"));
+    esp = SYSBUS_ESP(object_resolve_path_component(OBJECT(espdma), "esp"));
 
     ledma = SPARC32_LEDMA_DEVICE(object_resolve_path_component(
                                  OBJECT(dma), "ledma"));
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 60cc3047a5..9694825e71 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -65,8 +65,8 @@ struct ESPState {
     void (*pdma_cb)(ESPState *s);
 };
 
-#define TYPE_ESP "esp"
-OBJECT_DECLARE_SIMPLE_TYPE(SysBusESPState, ESP)
+#define TYPE_SYSBUS_ESP "sysbus-esp"
+OBJECT_DECLARE_SIMPLE_TYPE(SysBusESPState, SYSBUS_ESP)
 
 struct SysBusESPState {
     /*< private >*/
-- 
2.20.1



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

* [PATCH v2 03/42] esp: QOMify the internal ESP device state
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
  2021-02-09 19:29 ` [PATCH v2 01/42] esp: checkpatch fixes Mark Cave-Ayland
  2021-02-09 19:29 ` [PATCH v2 02/42] esp: rename existing ESP QOM type to SYSBUS_ESP Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-12 18:51   ` Philippe Mathieu-Daudé
  2021-02-09 19:29 ` [PATCH v2 04/42] esp: add vmstate_esp version to embedded ESPState Mark Cave-Ayland
                   ` (39 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Make this new QOM device state a child device of both the sysbus-esp and esp-pci
implementations.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp-pci.c     | 48 +++++++++++++++++++++++++++++++------------
 hw/scsi/esp.c         | 45 +++++++++++++++++++++++++++++++++-------
 include/hw/scsi/esp.h |  5 +++++
 3 files changed, 78 insertions(+), 20 deletions(-)

diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
index 2ce96dc56e..ccf73bb901 100644
--- a/hw/scsi/esp-pci.c
+++ b/hw/scsi/esp-pci.c
@@ -79,8 +79,10 @@ struct PCIESPState {
 
 static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val)
 {
+    ESPState *s = ESP(&pci->esp);
+
     trace_esp_pci_dma_idle(val);
-    esp_dma_enable(&pci->esp, 0, 0);
+    esp_dma_enable(s, 0, 0);
 }
 
 static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
@@ -91,14 +93,18 @@ static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
 
 static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val)
 {
+    ESPState *s = ESP(&pci->esp);
+
     trace_esp_pci_dma_abort(val);
-    if (pci->esp.current_req) {
-        scsi_req_cancel(pci->esp.current_req);
+    if (s->current_req) {
+        scsi_req_cancel(s->current_req);
     }
 }
 
 static void esp_pci_handle_start(PCIESPState *pci, uint32_t val)
 {
+    ESPState *s = ESP(&pci->esp);
+
     trace_esp_pci_dma_start(val);
 
     pci->dma_regs[DMA_WBC] = pci->dma_regs[DMA_STC];
@@ -109,7 +115,7 @@ static void esp_pci_handle_start(PCIESPState *pci, uint32_t val)
                                | DMA_STAT_DONE | DMA_STAT_ABORT
                                | DMA_STAT_ERROR | DMA_STAT_PWDN);
 
-    esp_dma_enable(&pci->esp, 0, 1);
+    esp_dma_enable(s, 0, 1);
 }
 
 static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
@@ -155,11 +161,12 @@ static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
 
 static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
 {
+    ESPState *s = ESP(&pci->esp);
     uint32_t val;
 
     val = pci->dma_regs[saddr];
     if (saddr == DMA_STAT) {
-        if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) {
+        if (s->rregs[ESP_RSTAT] & STAT_INT) {
             val |= DMA_STAT_SCSIINT;
         }
         if (!(pci->sbac & SBAC_STATUS)) {
@@ -176,6 +183,7 @@ static void esp_pci_io_write(void *opaque, hwaddr addr,
                              uint64_t val, unsigned int size)
 {
     PCIESPState *pci = opaque;
+    ESPState *s = ESP(&pci->esp);
 
     if (size < 4 || addr & 3) {
         /* need to upgrade request: we only support 4-bytes accesses */
@@ -183,7 +191,7 @@ static void esp_pci_io_write(void *opaque, hwaddr addr,
         int shift;
 
         if (addr < 0x40) {
-            current = pci->esp.wregs[addr >> 2];
+            current = s->wregs[addr >> 2];
         } else if (addr < 0x60) {
             current = pci->dma_regs[(addr - 0x40) >> 2];
         } else if (addr < 0x74) {
@@ -203,7 +211,7 @@ static void esp_pci_io_write(void *opaque, hwaddr addr,
 
     if (addr < 0x40) {
         /* SCSI core reg */
-        esp_reg_write(&pci->esp, addr >> 2, val);
+        esp_reg_write(s, addr >> 2, val);
     } else if (addr < 0x60) {
         /* PCI DMA CCB */
         esp_pci_dma_write(pci, (addr - 0x40) >> 2, val);
@@ -220,11 +228,12 @@ static uint64_t esp_pci_io_read(void *opaque, hwaddr addr,
                                 unsigned int size)
 {
     PCIESPState *pci = opaque;
+    ESPState *s = ESP(&pci->esp);
     uint32_t ret;
 
     if (addr < 0x40) {
         /* SCSI core reg */
-        ret = esp_reg_read(&pci->esp, addr >> 2);
+        ret = esp_reg_read(s, addr >> 2);
     } else if (addr < 0x60) {
         /* PCI DMA CCB */
         ret = esp_pci_dma_read(pci, (addr - 0x40) >> 2);
@@ -306,7 +315,9 @@ static const MemoryRegionOps esp_pci_io_ops = {
 static void esp_pci_hard_reset(DeviceState *dev)
 {
     PCIESPState *pci = PCI_ESP(dev);
-    esp_hard_reset(&pci->esp);
+    ESPState *s = ESP(&pci->esp);
+
+    esp_hard_reset(s);
     pci->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P
                               | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK);
     pci->dma_regs[DMA_WBC] &= ~0xffff;
@@ -354,9 +365,11 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
 {
     PCIESPState *pci = PCI_ESP(dev);
     DeviceState *d = DEVICE(dev);
-    ESPState *s = &pci->esp;
+    ESPState *s = ESP(&pci->esp);
     uint8_t *pci_conf;
 
+    qdev_realize(DEVICE(s), NULL, errp);
+
     pci_conf = dev->config;
 
     /* Interrupt pin A */
@@ -375,11 +388,19 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
     scsi_bus_new(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info, NULL);
 }
 
-static void esp_pci_scsi_uninit(PCIDevice *d)
+static void esp_pci_scsi_exit(PCIDevice *d)
 {
     PCIESPState *pci = PCI_ESP(d);
+    ESPState *s = ESP(&pci->esp);
+
+    qemu_free_irq(s->irq);
+}
+
+static void esp_pci_init(Object *obj)
+{
+    PCIESPState *pci = PCI_ESP(obj);
 
-    qemu_free_irq(pci->esp.irq);
+    object_initialize_child(obj, "esp", &pci->esp, TYPE_ESP);
 }
 
 static void esp_pci_class_init(ObjectClass *klass, void *data)
@@ -388,7 +409,7 @@ static void esp_pci_class_init(ObjectClass *klass, void *data)
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
     k->realize = esp_pci_scsi_realize;
-    k->exit = esp_pci_scsi_uninit;
+    k->exit = esp_pci_scsi_exit;
     k->vendor_id = PCI_VENDOR_ID_AMD;
     k->device_id = PCI_DEVICE_ID_AMD_SCSI;
     k->revision = 0x10;
@@ -402,6 +423,7 @@ static void esp_pci_class_init(ObjectClass *klass, void *data)
 static const TypeInfo esp_pci_info = {
     .name = TYPE_AM53C974_DEVICE,
     .parent = TYPE_PCI_DEVICE,
+    .instance_init = esp_pci_init,
     .instance_size = sizeof(PCIESPState),
     .class_init = esp_pci_class_init,
     .interfaces = (InterfaceInfo[]) {
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index aa38acc660..1635f86622 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -828,20 +828,22 @@ static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
                                  uint64_t val, unsigned int size)
 {
     SysBusESPState *sysbus = opaque;
+    ESPState *s = ESP(&sysbus->esp);
     uint32_t saddr;
 
     saddr = addr >> sysbus->it_shift;
-    esp_reg_write(&sysbus->esp, saddr, val);
+    esp_reg_write(s, saddr, val);
 }
 
 static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr,
                                     unsigned int size)
 {
     SysBusESPState *sysbus = opaque;
+    ESPState *s = ESP(&sysbus->esp);
     uint32_t saddr;
 
     saddr = addr >> sysbus->it_shift;
-    return esp_reg_read(&sysbus->esp, saddr);
+    return esp_reg_read(s, saddr);
 }
 
 static const MemoryRegionOps sysbus_esp_mem_ops = {
@@ -855,7 +857,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
                                   uint64_t val, unsigned int size)
 {
     SysBusESPState *sysbus = opaque;
-    ESPState *s = &sysbus->esp;
+    ESPState *s = ESP(&sysbus->esp);
     uint32_t dmalen;
     uint8_t *buf = get_pdma_buf(s);
 
@@ -892,7 +894,7 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
                                      unsigned int size)
 {
     SysBusESPState *sysbus = opaque;
-    ESPState *s = &sysbus->esp;
+    ESPState *s = ESP(&sysbus->esp);
     uint8_t *buf = get_pdma_buf(s);
     uint64_t val = 0;
 
@@ -940,7 +942,7 @@ static const struct SCSIBusInfo esp_scsi_info = {
 static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
 {
     SysBusESPState *sysbus = SYSBUS_ESP(opaque);
-    ESPState *s = &sysbus->esp;
+    ESPState *s = ESP(&sysbus->esp);
 
     switch (irq) {
     case 0:
@@ -956,7 +958,9 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
 {
     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
     SysBusESPState *sysbus = SYSBUS_ESP(dev);
-    ESPState *s = &sysbus->esp;
+    ESPState *s = ESP(&sysbus->esp);
+
+    qdev_realize(DEVICE(s), NULL, errp);
 
     sysbus_init_irq(sbd, &s->irq);
     sysbus_init_irq(sbd, &s->irq_data);
@@ -978,7 +982,16 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
 static void sysbus_esp_hard_reset(DeviceState *dev)
 {
     SysBusESPState *sysbus = SYSBUS_ESP(dev);
-    esp_hard_reset(&sysbus->esp);
+    ESPState *s = ESP(&sysbus->esp);
+
+    esp_hard_reset(s);
+}
+
+static void sysbus_esp_init(Object *obj)
+{
+    SysBusESPState *sysbus = SYSBUS_ESP(obj);
+
+    object_initialize_child(obj, "esp", &sysbus->esp, TYPE_ESP);
 }
 
 static const VMStateDescription vmstate_sysbus_esp_scsi = {
@@ -1004,13 +1017,31 @@ static void sysbus_esp_class_init(ObjectClass *klass, void *data)
 static const TypeInfo sysbus_esp_info = {
     .name          = TYPE_SYSBUS_ESP,
     .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_init = sysbus_esp_init,
     .instance_size = sizeof(SysBusESPState),
     .class_init    = sysbus_esp_class_init,
 };
 
+static void esp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    /* internal device for sysbusesp/pciespscsi, not user-creatable */
+    dc->user_creatable = false;
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+}
+
+static const TypeInfo esp_info = {
+    .name = TYPE_ESP,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(ESPState),
+    .class_init = esp_class_init,
+};
+
 static void esp_register_types(void)
 {
     type_register_static(&sysbus_esp_info);
+    type_register_static(&esp_info);
 }
 
 type_init(esp_register_types)
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 9694825e71..11c799d91e 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -22,7 +22,12 @@ enum pdma_origin_id {
     ASYNC,
 };
 
+#define TYPE_ESP "esp"
+OBJECT_DECLARE_SIMPLE_TYPE(ESPState, ESP)
+
 struct ESPState {
+    DeviceState parent_obj;
+
     uint8_t rregs[ESP_REGS];
     uint8_t wregs[ESP_REGS];
     qemu_irq irq;
-- 
2.20.1



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

* [PATCH v2 04/42] esp: add vmstate_esp version to embedded ESPState
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (2 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 03/42] esp: QOMify the internal ESP device state Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-16  7:35   ` Philippe Mathieu-Daudé
  2021-03-01 20:21   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 05/42] esp: add trace event when receiving a TI command Mark Cave-Ayland
                   ` (38 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The QOM object representing ESPState is currently embedded within both the
SYSBUS_ESP and PCI_ESP devices with migration state handled by embedding
vmstate_esp within each device using VMSTATE_STRUCT.

Since the vmstate_esp fields are embedded directly within the migration
stream, the incoming vmstate_esp version_id is lost. The only version information
available is that from vmstate_sysbus_esp_scsi and vmstate_esp_pci_scsi, but
those versions represent their respective devices and not that of the underlying
ESPState.

Resolve this by adding a new version-dependent field in vmstate_sysbus_esp_scsi
and vmstate_esp_pci_scsi which stores the vmstate_esp version_id field within
ESPState to be used to allow migration from older QEMU versions.

Finally bump the vmstate_esp version to 5 to cover the upcoming ESPState changes
within this patch series.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp-pci.c     |  3 ++-
 hw/scsi/esp.c         | 23 +++++++++++++++++++++--
 include/hw/scsi/esp.h |  2 ++
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
index ccf73bb901..8a82404853 100644
--- a/hw/scsi/esp-pci.c
+++ b/hw/scsi/esp-pci.c
@@ -330,11 +330,12 @@ static void esp_pci_hard_reset(DeviceState *dev)
 
 static const VMStateDescription vmstate_esp_pci_scsi = {
     .name = "pciespscsi",
-    .version_id = 1,
+    .version_id = 2,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
         VMSTATE_PCI_DEVICE(parent_obj, PCIESPState),
         VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
+        VMSTATE_UINT8_V(esp.mig_version_id, PCIESPState, 2),
         VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
         VMSTATE_END_OF_LIST()
     }
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 1635f86622..9427c55d1d 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -796,10 +796,28 @@ static const VMStateDescription vmstate_esp_pdma = {
     }
 };
 
+static int esp_pre_save(void *opaque)
+{
+    ESPState *s = ESP(opaque);
+
+    s->mig_version_id = vmstate_esp.version_id;
+    return 0;
+}
+
+static int esp_post_load(void *opaque, int version_id)
+{
+    ESPState *s = ESP(opaque);
+
+    s->mig_version_id = vmstate_esp.version_id;
+    return 0;
+}
+
 const VMStateDescription vmstate_esp = {
     .name = "esp",
-    .version_id = 4,
+    .version_id = 5,
     .minimum_version_id = 3,
+    .pre_save = esp_pre_save,
+    .post_load = esp_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_BUFFER(rregs, ESPState),
         VMSTATE_BUFFER(wregs, ESPState),
@@ -996,9 +1014,10 @@ static void sysbus_esp_init(Object *obj)
 
 static const VMStateDescription vmstate_sysbus_esp_scsi = {
     .name = "sysbusespscsi",
-    .version_id = 1,
+    .version_id = 2,
     .minimum_version_id = 1,
     .fields = (VMStateField[]) {
+        VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2),
         VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
         VMSTATE_END_OF_LIST()
     }
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 11c799d91e..7d92471c5b 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -68,6 +68,8 @@ struct ESPState {
     uint32_t pdma_start;
     uint32_t pdma_cur;
     void (*pdma_cb)(ESPState *s);
+
+    uint8_t mig_version_id;
 };
 
 #define TYPE_SYSBUS_ESP "sysbus-esp"
-- 
2.20.1



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

* [PATCH v2 05/42] esp: add trace event when receiving a TI command
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (3 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 04/42] esp: add vmstate_esp version to embedded ESPState Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-03-01 20:24   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 06/42] esp: fix esp_reg_read() trace event Mark Cave-Ayland
                   ` (37 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

This enables us to determine whether the command being issued is for a DMA or a
non-DMA transfer.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 hw/scsi/esp.c        | 1 +
 hw/scsi/trace-events | 1 +
 2 files changed, 2 insertions(+)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 9427c55d1d..9951472ee6 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -698,6 +698,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
             }
             break;
         case CMD_TI:
+            trace_esp_mem_writeb_cmd_ti(val);
             handle_ti(s);
             break;
         case CMD_ICCS:
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index 0e0aa9847d..762849c7b6 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -189,6 +189,7 @@ esp_mem_writeb_cmd_selatn(uint32_t val) "Select with ATN (0x%2.2x)"
 esp_mem_writeb_cmd_selatns(uint32_t val) "Select with ATN & stop (0x%2.2x)"
 esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (0x%2.2x)"
 esp_mem_writeb_cmd_dissel(uint32_t val) "Disable selection (0x%2.2x)"
+esp_mem_writeb_cmd_ti(uint32_t val) "Transfer Information (0x%2.2x)"
 
 # esp-pci.c
 esp_pci_error_invalid_dma_direction(void) "invalid DMA transfer direction"
-- 
2.20.1



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

* [PATCH v2 06/42] esp: fix esp_reg_read() trace event
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (4 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 05/42] esp: add trace event when receiving a TI command Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-03-01 20:29   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 07/42] esp: add PDMA trace events Mark Cave-Ayland
                   ` (36 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Move the trace event to the end of the function so that it correctly reports
the returned value if it doesn't come directly from the rregs array.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 hw/scsi/esp.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 9951472ee6..c36cb0f238 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -595,9 +595,8 @@ static void parent_esp_reset(ESPState *s, int irq, int level)
 
 uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
 {
-    uint32_t old_val;
+    uint32_t val;
 
-    trace_esp_mem_readb(saddr, s->rregs[saddr]);
     switch (saddr) {
     case ESP_FIFO:
         if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
@@ -612,13 +611,14 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
             s->ti_rptr = 0;
             s->ti_wptr = 0;
         }
+        val = s->rregs[ESP_FIFO];
         break;
     case ESP_RINTR:
         /*
          * Clear sequence step, interrupt register and all status bits
          * except TC
          */
-        old_val = s->rregs[ESP_RINTR];
+        val = s->rregs[ESP_RINTR];
         s->rregs[ESP_RINTR] = 0;
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
@@ -627,16 +627,22 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
             esp_report_command_complete(s, s->deferred_status);
             s->deferred_complete = false;
         }
-        return old_val;
+        break;
     case ESP_TCHI:
         /* Return the unique id if the value has never been written */
         if (!s->tchi_written) {
-            return s->chip_id;
+            val = s->chip_id;
+        } else {
+            val = s->rregs[saddr];
         }
+        break;
     default:
+        val = s->rregs[saddr];
         break;
     }
-    return s->rregs[saddr];
+
+    trace_esp_mem_readb(saddr, val);
+    return val;
 }
 
 void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
-- 
2.20.1



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

* [PATCH v2 07/42] esp: add PDMA trace events
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (5 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 06/42] esp: fix esp_reg_read() trace event Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-03-01 20:32   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 08/42] esp: determine transfer direction directly from SCSI phase Mark Cave-Ayland
                   ` (35 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

This will become more useful later when trying to debug mixed FIFO and PDMA
requests.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 hw/scsi/esp.c        | 6 ++++++
 hw/scsi/trace-events | 4 ++++
 2 files changed, 10 insertions(+)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index c36cb0f238..db2ea02549 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -63,11 +63,13 @@ static void esp_lower_irq(ESPState *s)
 static void esp_raise_drq(ESPState *s)
 {
     qemu_irq_raise(s->irq_data);
+    trace_esp_raise_drq();
 }
 
 static void esp_lower_drq(ESPState *s)
 {
     qemu_irq_lower(s->irq_data);
+    trace_esp_lower_drq();
 }
 
 void esp_dma_enable(ESPState *s, int irq, int level)
@@ -886,6 +888,8 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
     uint32_t dmalen;
     uint8_t *buf = get_pdma_buf(s);
 
+    trace_esp_pdma_write(size);
+
     dmalen = s->rregs[ESP_TCLO];
     dmalen |= s->rregs[ESP_TCMID] << 8;
     dmalen |= s->rregs[ESP_TCHI] << 16;
@@ -923,6 +927,8 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
     uint8_t *buf = get_pdma_buf(s);
     uint64_t val = 0;
 
+    trace_esp_pdma_read(size);
+
     if (s->pdma_len == 0) {
         return 0;
     }
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index 762849c7b6..dff986a643 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -159,8 +159,12 @@ esp_error_unhandled_command(uint32_t val) "unhandled command (0x%2.2x)"
 esp_error_invalid_write(uint32_t val, uint32_t addr) "invalid write of 0x%02x at [0x%x]"
 esp_raise_irq(void) "Raise IRQ"
 esp_lower_irq(void) "Lower IRQ"
+esp_raise_drq(void) "Raise DREQ"
+esp_lower_drq(void) "Lower DREQ"
 esp_dma_enable(void) "Raise enable"
 esp_dma_disable(void) "Lower enable"
+esp_pdma_read(int size) "pDMA read %u bytes"
+esp_pdma_write(int size) "pDMA write %u bytes"
 esp_get_cmd(uint32_t dmalen, int target) "len %d target %d"
 esp_do_busid_cmd(uint8_t busid) "busid 0x%x"
 esp_handle_satn_stop(uint32_t cmdlen) "cmdlen %d"
-- 
2.20.1



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

* [PATCH v2 08/42] esp: determine transfer direction directly from SCSI phase
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (6 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 07/42] esp: add PDMA trace events Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-16  7:36   ` Philippe Mathieu-Daudé
  2021-03-01 21:18   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 09/42] esp: introduce esp_get_tc() and esp_set_tc() Mark Cave-Ayland
                   ` (34 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The transfer direction is currently determined by checking the sign of ti_size
but as this series progresses ti_size can be zero at the end of the transfer.

Use the SCSI phase to determine the transfer direction as used in other SCSI
controller implementations.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index db2ea02549..e82e75d490 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -356,7 +356,7 @@ static void esp_dma_done(ESPState *s)
 
 static void do_dma_pdma_cb(ESPState *s)
 {
-    int to_device = (s->ti_size < 0);
+    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
     int len = s->pdma_cur - s->pdma_start;
     if (s->do_cmd) {
         s->ti_size = 0;
@@ -392,7 +392,7 @@ static void do_dma_pdma_cb(ESPState *s)
 static void esp_do_dma(ESPState *s)
 {
     uint32_t len;
-    int to_device;
+    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
 
     len = s->dma_left;
     if (s->do_cmd) {
@@ -425,7 +425,6 @@ static void esp_do_dma(ESPState *s)
     if (len > s->async_len) {
         len = s->async_len;
     }
-    to_device = (s->ti_size < 0);
     if (to_device) {
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, s->async_buf, len);
-- 
2.20.1



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

* [PATCH v2 09/42] esp: introduce esp_get_tc() and esp_set_tc()
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (7 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 08/42] esp: determine transfer direction directly from SCSI phase Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-03-01 21:24   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 10/42] esp: introduce esp_get_stc() Mark Cave-Ayland
                   ` (33 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

This simplifies reading and writing the TC register value without having to
manually shift each individual 8-bit value.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 hw/scsi/esp.c | 38 +++++++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 15 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index e82e75d490..3a39450930 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -98,6 +98,24 @@ void esp_request_cancelled(SCSIRequest *req)
     }
 }
 
+static uint32_t esp_get_tc(ESPState *s)
+{
+    uint32_t dmalen;
+
+    dmalen = s->rregs[ESP_TCLO];
+    dmalen |= s->rregs[ESP_TCMID] << 8;
+    dmalen |= s->rregs[ESP_TCHI] << 16;
+
+    return dmalen;
+}
+
+static void esp_set_tc(ESPState *s, uint32_t dmalen)
+{
+    s->rregs[ESP_TCLO] = dmalen & 0xff;
+    s->rregs[ESP_TCMID] = dmalen >> 8;
+    s->rregs[ESP_TCHI] = dmalen >> 16;
+}
+
 static void set_pdma(ESPState *s, enum pdma_origin_id origin,
                      uint32_t index, uint32_t len)
 {
@@ -157,9 +175,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
 
     target = s->wregs[ESP_WBUSID] & BUSID_DID;
     if (s->dma) {
-        dmalen = s->rregs[ESP_TCLO];
-        dmalen |= s->rregs[ESP_TCMID] << 8;
-        dmalen |= s->rregs[ESP_TCHI] << 16;
+        dmalen = esp_get_tc(s);
         if (dmalen > buflen) {
             return 0;
         }
@@ -348,9 +364,7 @@ static void esp_dma_done(ESPState *s)
     s->rregs[ESP_RINTR] = INTR_BS;
     s->rregs[ESP_RSEQ] = 0;
     s->rregs[ESP_RFLAGS] = 0;
-    s->rregs[ESP_TCLO] = 0;
-    s->rregs[ESP_TCMID] = 0;
-    s->rregs[ESP_TCHI] = 0;
+    esp_set_tc(s, 0);
     esp_raise_irq(s);
 }
 
@@ -536,9 +550,7 @@ static void handle_ti(ESPState *s)
         return;
     }
 
-    dmalen = s->rregs[ESP_TCLO];
-    dmalen |= s->rregs[ESP_TCMID] << 8;
-    dmalen |= s->rregs[ESP_TCHI] << 16;
+    dmalen = esp_get_tc(s);
     if (dmalen == 0) {
         dmalen = 0x10000;
     }
@@ -889,9 +901,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
 
     trace_esp_pdma_write(size);
 
-    dmalen = s->rregs[ESP_TCLO];
-    dmalen |= s->rregs[ESP_TCMID] << 8;
-    dmalen |= s->rregs[ESP_TCHI] << 16;
+    dmalen = esp_get_tc(s);
     if (dmalen == 0 || s->pdma_len == 0) {
         return;
     }
@@ -908,9 +918,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
         dmalen -= 2;
         break;
     }
-    s->rregs[ESP_TCLO] = dmalen & 0xff;
-    s->rregs[ESP_TCMID] = dmalen >> 8;
-    s->rregs[ESP_TCHI] = dmalen >> 16;
+    esp_set_tc(s, dmalen);
     if (s->pdma_len == 0 && s->pdma_cb) {
         esp_lower_drq(s);
         s->pdma_cb(s);
-- 
2.20.1



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

* [PATCH v2 10/42] esp: introduce esp_get_stc()
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (8 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 09/42] esp: introduce esp_get_tc() and esp_set_tc() Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-10 22:33   ` Philippe Mathieu-Daudé
  2021-03-01 21:28   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time Mark Cave-Ayland
                   ` (32 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

This simplifies reading the STC register value without having to manually shift
each individual 8-bit value.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 3a39450930..a1acc2c9bd 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -116,6 +116,17 @@ static void esp_set_tc(ESPState *s, uint32_t dmalen)
     s->rregs[ESP_TCHI] = dmalen >> 16;
 }
 
+static uint32_t esp_get_stc(ESPState *s)
+{
+    uint32_t dmalen;
+
+    dmalen = s->wregs[ESP_TCLO];
+    dmalen |= s->wregs[ESP_TCMID] << 8;
+    dmalen |= s->wregs[ESP_TCHI] << 16;
+
+    return dmalen;
+}
+
 static void set_pdma(ESPState *s, enum pdma_origin_id origin,
                      uint32_t index, uint32_t len)
 {
@@ -688,9 +699,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
         if (val & CMD_DMA) {
             s->dma = 1;
             /* Reload DMA counter.  */
-            s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
-            s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
-            s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
+            esp_set_tc(s, esp_get_stc(s));
         } else {
             s->dma = 0;
         }
-- 
2.20.1



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

* [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (9 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 10/42] esp: introduce esp_get_stc() Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-16  7:33   ` Philippe Mathieu-Daudé
  2021-03-01 21:35   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 12/42] esp: remove dma_counter from ESPState Mark Cave-Ayland
                   ` (31 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Perform the length adjustment whereby a value of 0 in the STC represents
a transfer length of 0x10000 at the point where the TC is loaded at the
start of a DMA command rather than just when a TI (Transfer Information)
command is executed. This better matches the description as given in the
datasheet.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index a1acc2c9bd..02b7876394 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -562,9 +562,6 @@ static void handle_ti(ESPState *s)
     }
 
     dmalen = esp_get_tc(s);
-    if (dmalen == 0) {
-        dmalen = 0x10000;
-    }
     s->dma_counter = dmalen;
 
     if (s->do_cmd) {
@@ -699,7 +696,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
         if (val & CMD_DMA) {
             s->dma = 1;
             /* Reload DMA counter.  */
-            esp_set_tc(s, esp_get_stc(s));
+            if (esp_get_stc(s) == 0) {
+                esp_set_tc(s, 0x10000);
+            } else {
+                esp_set_tc(s, esp_get_stc(s));
+            }
         } else {
             s->dma = 0;
         }
-- 
2.20.1



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

* [PATCH v2 12/42] esp: remove dma_counter from ESPState
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (10 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-10 22:37   ` Philippe Mathieu-Daudé
  2021-03-01 21:44   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 13/42] esp: remove dma_left " Mark Cave-Ayland
                   ` (30 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The value of dma_counter is set once at the start of the transfer and remains
the same until the transfer is complete. This allows the check in esp_transfer_data
to be simplified since dma_left will always be non-zero until the transfer is
completed.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 4 +---
 include/hw/scsi/esp.h | 3 ---
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 02b7876394..6c495b29c0 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -229,7 +229,6 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
     if (datalen != 0) {
         s->rregs[ESP_RSTAT] = STAT_TC;
         s->dma_left = 0;
-        s->dma_counter = 0;
         if (datalen > 0) {
             s->rregs[ESP_RSTAT] |= STAT_DI;
         } else {
@@ -543,7 +542,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
     s->async_buf = scsi_req_get_buf(req);
     if (s->dma_left) {
         esp_do_dma(s);
-    } else if (s->dma_counter != 0 && s->ti_size <= 0) {
+    } else if (s->ti_size <= 0) {
         /*
          * If this was the last part of a DMA transfer then the
          * completion interrupt is deferred to here.
@@ -562,7 +561,6 @@ static void handle_ti(ESPState *s)
     }
 
     dmalen = esp_get_tc(s);
-    s->dma_counter = dmalen;
 
     if (s->do_cmd) {
         minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 7d92471c5b..b313ef27f2 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -50,9 +50,6 @@ struct ESPState {
 
     /* The amount of data left in the current DMA transfer.  */
     uint32_t dma_left;
-    /* The size of the current DMA transfer.  Zero if no transfer is in
-       progress.  */
-    uint32_t dma_counter;
     int dma_enabled;
 
     uint32_t async_len;
-- 
2.20.1



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

* [PATCH v2 13/42] esp: remove dma_left from ESPState
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (11 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 12/42] esp: remove dma_counter from ESPState Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-23 21:22   ` Philippe Mathieu-Daudé
  2021-03-01 21:50   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 14/42] esp: remove minlen restriction in handle_ti Mark Cave-Ayland
                   ` (29 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The ESP device already keeps track of the remaining bytes left to transfer via
its TC (transfer counter) register which is decremented for each byte that
is transferred across the SCSI bus.

Switch the transfer logic to use the value of TC instead of dma_left and then
remove dma_left completely, adding logic to the vmstate_esp post_load() function
to transfer the old dma_left value to the TC register during migration from
older versions.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 47 ++++++++++++++++++++++++++++---------------
 include/hw/scsi/esp.h |  5 +++--
 2 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 6c495b29c0..fcc99f5fe4 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -228,7 +228,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
     s->ti_size = datalen;
     if (datalen != 0) {
         s->rregs[ESP_RSTAT] = STAT_TC;
-        s->dma_left = 0;
+        esp_set_tc(s, 0);
         if (datalen > 0) {
             s->rregs[ESP_RSTAT] |= STAT_DI;
         } else {
@@ -382,6 +382,7 @@ static void do_dma_pdma_cb(ESPState *s)
 {
     int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
     int len = s->pdma_cur - s->pdma_start;
+
     if (s->do_cmd) {
         s->ti_size = 0;
         s->cmdlen = 0;
@@ -389,7 +390,6 @@ static void do_dma_pdma_cb(ESPState *s)
         do_cmd(s, s->cmdbuf);
         return;
     }
-    s->dma_left -= len;
     s->async_buf += len;
     s->async_len -= len;
     if (to_device) {
@@ -404,7 +404,7 @@ static void do_dma_pdma_cb(ESPState *s)
          * complete the DMA operation immediately.  Otherwise defer
          * until the scsi layer has completed.
          */
-        if (to_device || s->dma_left != 0 || s->ti_size == 0) {
+        if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) {
             return;
         }
     }
@@ -418,7 +418,7 @@ static void esp_do_dma(ESPState *s)
     uint32_t len;
     int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
 
-    len = s->dma_left;
+    len = esp_get_tc(s);
     if (s->do_cmd) {
         /*
          * handle_ti_cmd() case: esp_do_dma() is called only from
@@ -468,7 +468,7 @@ static void esp_do_dma(ESPState *s)
             return;
         }
     }
-    s->dma_left -= len;
+    esp_set_tc(s, esp_get_tc(s) - len);
     s->async_buf += len;
     s->async_len -= len;
     if (to_device) {
@@ -483,7 +483,7 @@ static void esp_do_dma(ESPState *s)
          * complete the DMA operation immediately.  Otherwise defer
          * until the scsi layer has completed.
          */
-        if (to_device || s->dma_left != 0 || s->ti_size == 0) {
+        if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) {
             return;
         }
     }
@@ -499,7 +499,6 @@ static void esp_report_command_complete(ESPState *s, uint32_t status)
         trace_esp_command_complete_unexpected();
     }
     s->ti_size = 0;
-    s->dma_left = 0;
     s->async_len = 0;
     if (status) {
         trace_esp_command_complete_fail();
@@ -535,12 +534,13 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
 void esp_transfer_data(SCSIRequest *req, uint32_t len)
 {
     ESPState *s = req->hba_private;
+    uint32_t dmalen = esp_get_tc(s);
 
     assert(!s->do_cmd);
-    trace_esp_transfer_data(s->dma_left, s->ti_size);
+    trace_esp_transfer_data(dmalen, s->ti_size);
     s->async_len = len;
     s->async_buf = scsi_req_get_buf(req);
-    if (s->dma_left) {
+    if (dmalen) {
         esp_do_dma(s);
     } else if (s->ti_size <= 0) {
         /*
@@ -571,7 +571,6 @@ static void handle_ti(ESPState *s)
     }
     trace_esp_handle_ti(minlen);
     if (s->dma) {
-        s->dma_left = minlen;
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
         esp_do_dma(s);
     } else if (s->do_cmd) {
@@ -824,6 +823,14 @@ static const VMStateDescription vmstate_esp_pdma = {
     }
 };
 
+static bool esp_is_before_version_5(void *opaque, int version_id)
+{
+    ESPState *s = ESP(opaque);
+
+    version_id = MIN(version_id, s->mig_version_id);
+    return version_id < 5;
+}
+
 static int esp_pre_save(void *opaque)
 {
     ESPState *s = ESP(opaque);
@@ -836,6 +843,12 @@ static int esp_post_load(void *opaque, int version_id)
 {
     ESPState *s = ESP(opaque);
 
+    version_id = MIN(version_id, s->mig_version_id);
+
+    if (version_id < 5) {
+        esp_set_tc(s, s->mig_dma_left);
+    }
+
     s->mig_version_id = vmstate_esp.version_id;
     return 0;
 }
@@ -861,7 +874,7 @@ const VMStateDescription vmstate_esp = {
         VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
         VMSTATE_UINT32(cmdlen, ESPState),
         VMSTATE_UINT32(do_cmd, ESPState),
-        VMSTATE_UINT32(dma_left, ESPState),
+        VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
         VMSTATE_END_OF_LIST()
     },
     .subsections = (const VMStateDescription * []) {
@@ -904,12 +917,11 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
 {
     SysBusESPState *sysbus = opaque;
     ESPState *s = ESP(&sysbus->esp);
-    uint32_t dmalen;
+    uint32_t dmalen = esp_get_tc(s);
     uint8_t *buf = get_pdma_buf(s);
 
     trace_esp_pdma_write(size);
 
-    dmalen = esp_get_tc(s);
     if (dmalen == 0 || s->pdma_len == 0) {
         return;
     }
@@ -939,27 +951,30 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
 {
     SysBusESPState *sysbus = opaque;
     ESPState *s = ESP(&sysbus->esp);
+    uint32_t dmalen = esp_get_tc(s);
     uint8_t *buf = get_pdma_buf(s);
     uint64_t val = 0;
 
     trace_esp_pdma_read(size);
 
-    if (s->pdma_len == 0) {
+    if (dmalen == 0 || s->pdma_len == 0) {
         return 0;
     }
     switch (size) {
     case 1:
         val = buf[s->pdma_cur++];
         s->pdma_len--;
+        dmalen--;
         break;
     case 2:
         val = buf[s->pdma_cur++];
         val = (val << 8) | buf[s->pdma_cur++];
         s->pdma_len -= 2;
+        dmalen -= 2;
         break;
     }
-
-    if (s->pdma_len == 0 && s->pdma_cb) {
+    esp_set_tc(s, dmalen);
+    if (dmalen == 0 || (s->pdma_len == 0 && s->pdma_cb)) {
         esp_lower_drq(s);
         s->pdma_cb(s);
         s->pdma_cb = NULL;
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index b313ef27f2..9fad320513 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -48,8 +48,6 @@ struct ESPState {
     uint32_t cmdlen;
     uint32_t do_cmd;
 
-    /* The amount of data left in the current DMA transfer.  */
-    uint32_t dma_left;
     int dma_enabled;
 
     uint32_t async_len;
@@ -67,6 +65,9 @@ struct ESPState {
     void (*pdma_cb)(ESPState *s);
 
     uint8_t mig_version_id;
+
+    /* Legacy fields for vmstate_esp version < 5 */
+    uint32_t mig_dma_left;
 };
 
 #define TYPE_SYSBUS_ESP "sysbus-esp"
-- 
2.20.1



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

* [PATCH v2 14/42] esp: remove minlen restriction in handle_ti
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (12 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 13/42] esp: remove dma_left " Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-23 18:24   ` Philippe Mathieu-Daudé
  2021-03-01 22:04   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions Mark Cave-Ayland
                   ` (28 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The limiting of DMA transfers to the maximum size of the available data is already
handled by esp_do_dma() and do_dma_pdma_cb().

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index fcc99f5fe4..e7cf36f4b8 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -553,7 +553,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
 
 static void handle_ti(ESPState *s)
 {
-    uint32_t dmalen, minlen;
+    uint32_t dmalen;
 
     if (s->dma && !s->dma_enabled) {
         s->dma_cb = handle_ti;
@@ -561,16 +561,8 @@ static void handle_ti(ESPState *s)
     }
 
     dmalen = esp_get_tc(s);
-
-    if (s->do_cmd) {
-        minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
-    } else if (s->ti_size < 0) {
-        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
-    } else {
-        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
-    }
-    trace_esp_handle_ti(minlen);
     if (s->dma) {
+        trace_esp_handle_ti(dmalen);
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
         esp_do_dma(s);
     } else if (s->do_cmd) {
-- 
2.20.1



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

* [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (13 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 14/42] esp: remove minlen restriction in handle_ti Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-10 22:51   ` Philippe Mathieu-Daudé
  2021-03-01 22:06   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 16/42] esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
                   ` (27 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index e7cf36f4b8..b0cba889a9 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -151,6 +151,20 @@ static uint8_t *get_pdma_buf(ESPState *s)
     return NULL;
 }
 
+static uint8_t esp_pdma_read(ESPState *s)
+{
+    uint8_t *buf = get_pdma_buf(s);
+
+    return buf[s->pdma_cur++];
+}
+
+static void esp_pdma_write(ESPState *s, uint8_t val)
+{
+    uint8_t *buf = get_pdma_buf(s);
+
+    buf[s->pdma_cur++] = val;
+}
+
 static int get_cmd_cb(ESPState *s)
 {
     int target;
@@ -910,7 +924,6 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
     SysBusESPState *sysbus = opaque;
     ESPState *s = ESP(&sysbus->esp);
     uint32_t dmalen = esp_get_tc(s);
-    uint8_t *buf = get_pdma_buf(s);
 
     trace_esp_pdma_write(size);
 
@@ -919,13 +932,13 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
     }
     switch (size) {
     case 1:
-        buf[s->pdma_cur++] = val;
+        esp_pdma_write(s, val);
         s->pdma_len--;
         dmalen--;
         break;
     case 2:
-        buf[s->pdma_cur++] = val >> 8;
-        buf[s->pdma_cur++] = val;
+        esp_pdma_write(s, val >> 8);
+        esp_pdma_write(s, val);
         s->pdma_len -= 2;
         dmalen -= 2;
         break;
@@ -944,7 +957,6 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
     SysBusESPState *sysbus = opaque;
     ESPState *s = ESP(&sysbus->esp);
     uint32_t dmalen = esp_get_tc(s);
-    uint8_t *buf = get_pdma_buf(s);
     uint64_t val = 0;
 
     trace_esp_pdma_read(size);
@@ -954,13 +966,13 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
     }
     switch (size) {
     case 1:
-        val = buf[s->pdma_cur++];
+        val = esp_pdma_read(s);
         s->pdma_len--;
         dmalen--;
         break;
     case 2:
-        val = buf[s->pdma_cur++];
-        val = (val << 8) | buf[s->pdma_cur++];
+        val = esp_pdma_read(s);
+        val = (val << 8) | esp_pdma_read(s);
         s->pdma_len -= 2;
         dmalen -= 2;
         break;
-- 
2.20.1



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

* [PATCH v2 16/42] esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write()
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (14 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-23 18:25   ` Philippe Mathieu-Daudé
  2021-03-01 22:07   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 17/42] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
                   ` (26 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

This is the first step in removing get_pdma_buf() from esp.c.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index b0cba889a9..cfeba2feb0 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -153,16 +153,38 @@ static uint8_t *get_pdma_buf(ESPState *s)
 
 static uint8_t esp_pdma_read(ESPState *s)
 {
-    uint8_t *buf = get_pdma_buf(s);
-
-    return buf[s->pdma_cur++];
+    switch (s->pdma_origin) {
+    case PDMA:
+        return s->pdma_buf[s->pdma_cur++];
+    case TI:
+        return s->ti_buf[s->pdma_cur++];
+    case CMD:
+        return s->cmdbuf[s->pdma_cur++];
+    case ASYNC:
+        return s->async_buf[s->pdma_cur++];
+    default:
+        g_assert_not_reached();
+    }
 }
 
 static void esp_pdma_write(ESPState *s, uint8_t val)
 {
-    uint8_t *buf = get_pdma_buf(s);
-
-    buf[s->pdma_cur++] = val;
+    switch (s->pdma_origin) {
+    case PDMA:
+        s->pdma_buf[s->pdma_cur++] = val;
+        break;
+    case TI:
+        s->ti_buf[s->pdma_cur++] = val;
+        break;
+    case CMD:
+        s->cmdbuf[s->pdma_cur++] = val;
+        break;
+    case ASYNC:
+        s->async_buf[s->pdma_cur++] = val;
+        break;
+    default:
+        g_assert_not_reached();
+    }
 }
 
 static int get_cmd_cb(ESPState *s)
-- 
2.20.1



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

* [PATCH v2 17/42] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write()
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (15 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 16/42] esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-23 21:23   ` Philippe Mathieu-Daudé
  2021-03-01 22:09   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf Mark Cave-Ayland
                   ` (25 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index cfeba2feb0..7134c0aff4 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -153,22 +153,45 @@ static uint8_t *get_pdma_buf(ESPState *s)
 
 static uint8_t esp_pdma_read(ESPState *s)
 {
+    uint32_t dmalen = esp_get_tc(s);
+    uint8_t val;
+
+    if (dmalen == 0 || s->pdma_len == 0) {
+        return 0;
+    }
+
     switch (s->pdma_origin) {
     case PDMA:
-        return s->pdma_buf[s->pdma_cur++];
+        val = s->pdma_buf[s->pdma_cur++];
+        break;
     case TI:
-        return s->ti_buf[s->pdma_cur++];
+        val = s->ti_buf[s->pdma_cur++];
+        break;
     case CMD:
-        return s->cmdbuf[s->pdma_cur++];
+        val = s->cmdbuf[s->pdma_cur++];
+        break;
     case ASYNC:
-        return s->async_buf[s->pdma_cur++];
+        val = s->async_buf[s->pdma_cur++];
+        break;
     default:
         g_assert_not_reached();
     }
+
+    s->pdma_len--;
+    dmalen--;
+    esp_set_tc(s, dmalen);
+
+    return val;
 }
 
 static void esp_pdma_write(ESPState *s, uint8_t val)
 {
+    uint32_t dmalen = esp_get_tc(s);
+
+    if (dmalen == 0 || s->pdma_len == 0) {
+        return;
+    }
+
     switch (s->pdma_origin) {
     case PDMA:
         s->pdma_buf[s->pdma_cur++] = val;
@@ -185,6 +208,10 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
     default:
         g_assert_not_reached();
     }
+
+    s->pdma_len--;
+    dmalen--;
+    esp_set_tc(s, dmalen);
 }
 
 static int get_cmd_cb(ESPState *s)
@@ -945,27 +972,18 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
 {
     SysBusESPState *sysbus = opaque;
     ESPState *s = ESP(&sysbus->esp);
-    uint32_t dmalen = esp_get_tc(s);
 
     trace_esp_pdma_write(size);
 
-    if (dmalen == 0 || s->pdma_len == 0) {
-        return;
-    }
     switch (size) {
     case 1:
         esp_pdma_write(s, val);
-        s->pdma_len--;
-        dmalen--;
         break;
     case 2:
         esp_pdma_write(s, val >> 8);
         esp_pdma_write(s, val);
-        s->pdma_len -= 2;
-        dmalen -= 2;
         break;
     }
-    esp_set_tc(s, dmalen);
     if (s->pdma_len == 0 && s->pdma_cb) {
         esp_lower_drq(s);
         s->pdma_cb(s);
@@ -989,17 +1007,13 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
     switch (size) {
     case 1:
         val = esp_pdma_read(s);
-        s->pdma_len--;
-        dmalen--;
         break;
     case 2:
         val = esp_pdma_read(s);
         val = (val << 8) | esp_pdma_read(s);
-        s->pdma_len -= 2;
-        dmalen -= 2;
         break;
     }
-    esp_set_tc(s, dmalen);
+    dmalen = esp_get_tc(s);
     if (dmalen == 0 || (s->pdma_len == 0 && s->pdma_cb)) {
         esp_lower_drq(s);
         s->pdma_cb(s);
-- 
2.20.1



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

* [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (16 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 17/42] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-23 21:25   ` Philippe Mathieu-Daudé
                     ` (2 more replies)
  2021-02-09 19:29 ` [PATCH v2 19/42] esp: remove buf parameter from do_cmd() Mark Cave-Ayland
                   ` (24 subsequent siblings)
  42 siblings, 3 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

ESP SCSI commands are already accumulated in cmdbuf and so there is no need to
keep a separate pdma_buf buffer. Accumulate SCSI commands for PDMA transfers in
cmdbuf instead of pdma_buf so update cmdlen accordingly and change pdma_origin
for PDMA transfers to CMD which allows the PDMA origin to be removed.

This commit also removes a stray memcpy() from get_cmd() which is a no-op because
cmdlen is always zero at the start of a command.

Notionally the removal of pdma_buf from vmstate_esp_pdma also breaks migration
compatibility for the PDMA subsection until its complete removal by the end of
the series.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 56 +++++++++++++++++++------------------------
 include/hw/scsi/esp.h |  2 --
 2 files changed, 25 insertions(+), 33 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 7134c0aff4..b846f022fb 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -139,8 +139,6 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin,
 static uint8_t *get_pdma_buf(ESPState *s)
 {
     switch (s->pdma_origin) {
-    case PDMA:
-        return s->pdma_buf;
     case TI:
         return s->ti_buf;
     case CMD:
@@ -161,14 +159,12 @@ static uint8_t esp_pdma_read(ESPState *s)
     }
 
     switch (s->pdma_origin) {
-    case PDMA:
-        val = s->pdma_buf[s->pdma_cur++];
-        break;
     case TI:
         val = s->ti_buf[s->pdma_cur++];
         break;
     case CMD:
-        val = s->cmdbuf[s->pdma_cur++];
+        val = s->cmdbuf[s->cmdlen++];
+        s->pdma_cur++;
         break;
     case ASYNC:
         val = s->async_buf[s->pdma_cur++];
@@ -193,14 +189,12 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
     }
 
     switch (s->pdma_origin) {
-    case PDMA:
-        s->pdma_buf[s->pdma_cur++] = val;
-        break;
     case TI:
         s->ti_buf[s->pdma_cur++] = val;
         break;
     case CMD:
-        s->cmdbuf[s->pdma_cur++] = val;
+        s->cmdbuf[s->cmdlen++] = val;
+        s->pdma_cur++;
         break;
     case ASYNC:
         s->async_buf[s->pdma_cur++] = val;
@@ -256,8 +250,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, buf, dmalen);
         } else {
-            memcpy(s->pdma_buf, buf, dmalen);
-            set_pdma(s, PDMA, 0, dmalen);
+            set_pdma(s, CMD, 0, dmalen);
             esp_raise_drq(s);
             return 0;
         }
@@ -316,24 +309,24 @@ static void satn_pdma_cb(ESPState *s)
     if (get_cmd_cb(s) < 0) {
         return;
     }
-    if (s->pdma_cur != s->pdma_start) {
-        do_cmd(s, get_pdma_buf(s) + s->pdma_start);
+    s->do_cmd = 0;
+    if (s->cmdlen) {
+        do_cmd(s, s->cmdbuf);
     }
 }
 
 static void handle_satn(ESPState *s)
 {
-    uint8_t buf[32];
-    int len;
-
     if (s->dma && !s->dma_enabled) {
         s->dma_cb = handle_satn;
         return;
     }
     s->pdma_cb = satn_pdma_cb;
-    len = get_cmd(s, buf, sizeof(buf));
-    if (len) {
-        do_cmd(s, buf);
+    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
+    if (s->cmdlen) {
+        do_cmd(s, s->cmdbuf);
+    } else {
+        s->do_cmd = 1;
     }
 }
 
@@ -342,24 +335,24 @@ static void s_without_satn_pdma_cb(ESPState *s)
     if (get_cmd_cb(s) < 0) {
         return;
     }
-    if (s->pdma_cur != s->pdma_start) {
+    s->do_cmd = 0;
+    if (s->cmdlen) {
         do_busid_cmd(s, get_pdma_buf(s) + s->pdma_start, 0);
     }
 }
 
 static void handle_s_without_atn(ESPState *s)
 {
-    uint8_t buf[32];
-    int len;
-
     if (s->dma && !s->dma_enabled) {
         s->dma_cb = handle_s_without_atn;
         return;
     }
     s->pdma_cb = s_without_satn_pdma_cb;
-    len = get_cmd(s, buf, sizeof(buf));
-    if (len) {
-        do_busid_cmd(s, buf, 0);
+    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
+    if (s->cmdlen) {
+        do_busid_cmd(s, s->cmdbuf, 0);
+    } else {
+        s->do_cmd = 1;
     }
 }
 
@@ -368,7 +361,7 @@ static void satn_stop_pdma_cb(ESPState *s)
     if (get_cmd_cb(s) < 0) {
         return;
     }
-    s->cmdlen = s->pdma_cur - s->pdma_start;
+    s->do_cmd = 0;
     if (s->cmdlen) {
         trace_esp_handle_satn_stop(s->cmdlen);
         s->do_cmd = 1;
@@ -394,6 +387,8 @@ static void handle_satn_stop(ESPState *s)
         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
         esp_raise_irq(s);
+    } else {
+        s->do_cmd = 1;
     }
 }
 
@@ -865,11 +860,10 @@ static bool esp_pdma_needed(void *opaque)
 
 static const VMStateDescription vmstate_esp_pdma = {
     .name = "esp/pdma",
-    .version_id = 1,
-    .minimum_version_id = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
     .needed = esp_pdma_needed,
     .fields = (VMStateField[]) {
-        VMSTATE_BUFFER(pdma_buf, ESPState),
         VMSTATE_INT32(pdma_origin, ESPState),
         VMSTATE_UINT32(pdma_len, ESPState),
         VMSTATE_UINT32(pdma_start, ESPState),
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 9fad320513..c323d43f70 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -16,7 +16,6 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
 typedef struct ESPState ESPState;
 
 enum pdma_origin_id {
-    PDMA,
     TI,
     CMD,
     ASYNC,
@@ -57,7 +56,6 @@ struct ESPState {
     ESPDMAMemoryReadWriteFunc dma_memory_write;
     void *dma_opaque;
     void (*dma_cb)(ESPState *s);
-    uint8_t pdma_buf[32];
     int pdma_origin;
     uint32_t pdma_len;
     uint32_t pdma_start;
-- 
2.20.1



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

* [PATCH v2 19/42] esp: remove buf parameter from do_cmd()
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (17 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-23 18:27   ` Philippe Mathieu-Daudé
  2021-03-02 17:03   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 20/42] esp: remove the buf and buflen parameters from get_cmd() Mark Cave-Ayland
                   ` (23 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Now that all SCSI commands are accumulated in cmdbuf, remove the buf parameter
from do_cmd() since this always points to cmdbuf.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index b846f022fb..bb467fbcdf 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -297,8 +297,9 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
     esp_raise_irq(s);
 }
 
-static void do_cmd(ESPState *s, uint8_t *buf)
+static void do_cmd(ESPState *s)
 {
+    uint8_t *buf = s->cmdbuf;
     uint8_t busid = buf[0];
 
     do_busid_cmd(s, &buf[1], busid);
@@ -311,7 +312,7 @@ static void satn_pdma_cb(ESPState *s)
     }
     s->do_cmd = 0;
     if (s->cmdlen) {
-        do_cmd(s, s->cmdbuf);
+        do_cmd(s);
     }
 }
 
@@ -324,7 +325,7 @@ static void handle_satn(ESPState *s)
     s->pdma_cb = satn_pdma_cb;
     s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
     if (s->cmdlen) {
-        do_cmd(s, s->cmdbuf);
+        do_cmd(s);
     } else {
         s->do_cmd = 1;
     }
@@ -445,7 +446,7 @@ static void do_dma_pdma_cb(ESPState *s)
         s->ti_size = 0;
         s->cmdlen = 0;
         s->do_cmd = 0;
-        do_cmd(s, s->cmdbuf);
+        do_cmd(s);
         return;
     }
     s->async_buf += len;
@@ -497,7 +498,7 @@ static void esp_do_dma(ESPState *s)
         s->ti_size = 0;
         s->cmdlen = 0;
         s->do_cmd = 0;
-        do_cmd(s, s->cmdbuf);
+        do_cmd(s);
         return;
     }
     if (s->async_len == 0) {
@@ -628,7 +629,7 @@ static void handle_ti(ESPState *s)
         s->ti_size = 0;
         s->cmdlen = 0;
         s->do_cmd = 0;
-        do_cmd(s, s->cmdbuf);
+        do_cmd(s);
     }
 }
 
-- 
2.20.1



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

* [PATCH v2 20/42] esp: remove the buf and buflen parameters from get_cmd()
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (18 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 19/42] esp: remove buf parameter from do_cmd() Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-16  7:31   ` Philippe Mathieu-Daudé
  2021-03-02 17:03   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 21/42] esp: remove redundant pdma_start from ESPState Mark Cave-Ayland
                   ` (22 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Now that all SCSI commands are accumulated in cmdbuf, remove the buf and buflen
parameters from get_cmd() since these always reference cmdbuf and ESP_CMDBUF_SZ
respectively.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index bb467fbcdf..7055520a26 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -236,15 +236,16 @@ static int get_cmd_cb(ESPState *s)
     return 0;
 }
 
-static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
+static uint32_t get_cmd(ESPState *s)
 {
+    uint8_t *buf = s->cmdbuf;
     uint32_t dmalen;
     int target;
 
     target = s->wregs[ESP_WBUSID] & BUSID_DID;
     if (s->dma) {
         dmalen = esp_get_tc(s);
-        if (dmalen > buflen) {
+        if (dmalen > ESP_CMDBUF_SZ) {
             return 0;
         }
         if (s->dma_memory_read) {
@@ -323,7 +324,7 @@ static void handle_satn(ESPState *s)
         return;
     }
     s->pdma_cb = satn_pdma_cb;
-    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
+    s->cmdlen = get_cmd(s);
     if (s->cmdlen) {
         do_cmd(s);
     } else {
@@ -349,7 +350,7 @@ static void handle_s_without_atn(ESPState *s)
         return;
     }
     s->pdma_cb = s_without_satn_pdma_cb;
-    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
+    s->cmdlen = get_cmd(s);
     if (s->cmdlen) {
         do_busid_cmd(s, s->cmdbuf, 0);
     } else {
@@ -380,7 +381,7 @@ static void handle_satn_stop(ESPState *s)
         return;
     }
     s->pdma_cb = satn_stop_pdma_cb;
-    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
+    s->cmdlen = get_cmd(s);
     if (s->cmdlen) {
         trace_esp_handle_satn_stop(s->cmdlen);
         s->do_cmd = 1;
-- 
2.20.1



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

* [PATCH v2 21/42] esp: remove redundant pdma_start from ESPState
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (19 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 20/42] esp: remove the buf and buflen parameters from get_cmd() Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-03-02 21:22   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 22/42] esp: move PDMA length adjustments into esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
                   ` (21 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Now that PDMA SCSI commands are accumulated in cmdbuf in the same way as normal
commands, the existing logic for locating the start of the SCSI command in
cmdbuf via cmdlen can be used. This enables the PDMA-specific pdma_start and
also get_pdma_buf() to be removed.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 7055520a26..91f65a5d9b 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -131,24 +131,10 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin,
                      uint32_t index, uint32_t len)
 {
     s->pdma_origin = origin;
-    s->pdma_start = index;
     s->pdma_cur = index;
     s->pdma_len = len;
 }
 
-static uint8_t *get_pdma_buf(ESPState *s)
-{
-    switch (s->pdma_origin) {
-    case TI:
-        return s->ti_buf;
-    case CMD:
-        return s->cmdbuf;
-    case ASYNC:
-        return s->async_buf;
-    }
-    return NULL;
-}
-
 static uint8_t esp_pdma_read(ESPState *s)
 {
     uint32_t dmalen = esp_get_tc(s);
@@ -339,7 +325,7 @@ static void s_without_satn_pdma_cb(ESPState *s)
     }
     s->do_cmd = 0;
     if (s->cmdlen) {
-        do_busid_cmd(s, get_pdma_buf(s) + s->pdma_start, 0);
+        do_busid_cmd(s, s->cmdbuf, 0);
     }
 }
 
@@ -441,7 +427,7 @@ static void esp_dma_done(ESPState *s)
 static void do_dma_pdma_cb(ESPState *s)
 {
     int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
-    int len = s->pdma_cur - s->pdma_start;
+    int len = s->pdma_cur;
 
     if (s->do_cmd) {
         s->ti_size = 0;
@@ -868,7 +854,6 @@ static const VMStateDescription vmstate_esp_pdma = {
     .fields = (VMStateField[]) {
         VMSTATE_INT32(pdma_origin, ESPState),
         VMSTATE_UINT32(pdma_len, ESPState),
-        VMSTATE_UINT32(pdma_start, ESPState),
         VMSTATE_UINT32(pdma_cur, ESPState),
         VMSTATE_END_OF_LIST()
     }
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index c323d43f70..578d936214 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -58,7 +58,6 @@ struct ESPState {
     void (*dma_cb)(ESPState *s);
     int pdma_origin;
     uint32_t pdma_len;
-    uint32_t pdma_start;
     uint32_t pdma_cur;
     void (*pdma_cb)(ESPState *s);
 
-- 
2.20.1



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

* [PATCH v2 22/42] esp: move PDMA length adjustments into esp_pdma_read()/esp_pdma_write()
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (20 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 21/42] esp: remove redundant pdma_start from ESPState Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-03-02 21:44   ` Laurent Vivier
  2021-02-09 19:29 ` [PATCH v2 23/42] esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA Mark Cave-Ayland
                   ` (20 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Here the updates to async_len and ti_size are moved into the corresponding
esp_pdma_read()/esp_pdma_write() function to eliminate the reference to
pdma_cur in do_dma_pdma_cb().

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 91f65a5d9b..691a2f4bdc 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -153,12 +153,18 @@ static uint8_t esp_pdma_read(ESPState *s)
         s->pdma_cur++;
         break;
     case ASYNC:
-        val = s->async_buf[s->pdma_cur++];
+        val = s->async_buf[0];
+        if (s->async_len > 0) {
+            s->async_len--;
+            s->async_buf++;
+        }
+        s->pdma_cur++;
         break;
     default:
         g_assert_not_reached();
     }
 
+    s->ti_size--;
     s->pdma_len--;
     dmalen--;
     esp_set_tc(s, dmalen);
@@ -183,12 +189,18 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
         s->pdma_cur++;
         break;
     case ASYNC:
-        s->async_buf[s->pdma_cur++] = val;
+        s->async_buf[0] = val;
+        if (s->async_len > 0) {
+            s->async_len--;
+            s->async_buf++;
+        }
+        s->pdma_cur++;
         break;
     default:
         g_assert_not_reached();
     }
 
+    s->ti_size++;
     s->pdma_len--;
     dmalen--;
     esp_set_tc(s, dmalen);
@@ -427,7 +439,6 @@ static void esp_dma_done(ESPState *s)
 static void do_dma_pdma_cb(ESPState *s)
 {
     int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
-    int len = s->pdma_cur;
 
     if (s->do_cmd) {
         s->ti_size = 0;
@@ -436,13 +447,6 @@ static void do_dma_pdma_cb(ESPState *s)
         do_cmd(s);
         return;
     }
-    s->async_buf += len;
-    s->async_len -= len;
-    if (to_device) {
-        s->ti_size += len;
-    } else {
-        s->ti_size -= len;
-    }
     if (s->async_len == 0) {
         scsi_req_continue(s->current_req);
         /*
-- 
2.20.1



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

* [PATCH v2 23/42] esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (21 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 22/42] esp: move PDMA length adjustments into esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
@ 2021-02-09 19:29 ` Mark Cave-Ayland
  2021-02-23 21:29   ` Philippe Mathieu-Daudé
  2021-03-02 21:47   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 24/42] esp: use in-built TC to determine PDMA transfer length Mark Cave-Ayland
                   ` (19 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:29 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

This eliminates the last user of the PDMA-specific pdma_cur variable which can
now be removed.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 23 ++++++++---------------
 include/hw/scsi/esp.h |  1 -
 2 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 691a2f4bdc..50503a6f53 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -127,11 +127,9 @@ static uint32_t esp_get_stc(ESPState *s)
     return dmalen;
 }
 
-static void set_pdma(ESPState *s, enum pdma_origin_id origin,
-                     uint32_t index, uint32_t len)
+static void set_pdma(ESPState *s, enum pdma_origin_id origin, uint32_t len)
 {
     s->pdma_origin = origin;
-    s->pdma_cur = index;
     s->pdma_len = len;
 }
 
@@ -146,11 +144,10 @@ static uint8_t esp_pdma_read(ESPState *s)
 
     switch (s->pdma_origin) {
     case TI:
-        val = s->ti_buf[s->pdma_cur++];
+        val = s->ti_buf[s->ti_rptr++];
         break;
     case CMD:
         val = s->cmdbuf[s->cmdlen++];
-        s->pdma_cur++;
         break;
     case ASYNC:
         val = s->async_buf[0];
@@ -158,7 +155,6 @@ static uint8_t esp_pdma_read(ESPState *s)
             s->async_len--;
             s->async_buf++;
         }
-        s->pdma_cur++;
         break;
     default:
         g_assert_not_reached();
@@ -182,11 +178,10 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
 
     switch (s->pdma_origin) {
     case TI:
-        s->ti_buf[s->pdma_cur++] = val;
+        s->ti_buf[s->ti_wptr++] = val;
         break;
     case CMD:
         s->cmdbuf[s->cmdlen++] = val;
-        s->pdma_cur++;
         break;
     case ASYNC:
         s->async_buf[0] = val;
@@ -194,7 +189,6 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
             s->async_len--;
             s->async_buf++;
         }
-        s->pdma_cur++;
         break;
     default:
         g_assert_not_reached();
@@ -249,7 +243,7 @@ static uint32_t get_cmd(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, buf, dmalen);
         } else {
-            set_pdma(s, CMD, 0, dmalen);
+            set_pdma(s, CMD, dmalen);
             esp_raise_drq(s);
             return 0;
         }
@@ -412,7 +406,7 @@ static void write_response(ESPState *s)
             s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
             s->rregs[ESP_RSEQ] = SEQ_CD;
         } else {
-            set_pdma(s, TI, 0, 2);
+            set_pdma(s, TI, 2);
             s->pdma_cb = write_response_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -480,7 +474,7 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
         } else {
-            set_pdma(s, CMD, s->cmdlen, len);
+            set_pdma(s, CMD, len);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -503,7 +497,7 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, s->async_buf, len);
         } else {
-            set_pdma(s, ASYNC, 0, len);
+            set_pdma(s, ASYNC, len);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -512,7 +506,7 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_write) {
             s->dma_memory_write(s->dma_opaque, s->async_buf, len);
         } else {
-            set_pdma(s, ASYNC, 0, len);
+            set_pdma(s, ASYNC, len);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -858,7 +852,6 @@ static const VMStateDescription vmstate_esp_pdma = {
     .fields = (VMStateField[]) {
         VMSTATE_INT32(pdma_origin, ESPState),
         VMSTATE_UINT32(pdma_len, ESPState),
-        VMSTATE_UINT32(pdma_cur, ESPState),
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 578d936214..5908d59a0a 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -58,7 +58,6 @@ struct ESPState {
     void (*dma_cb)(ESPState *s);
     int pdma_origin;
     uint32_t pdma_len;
-    uint32_t pdma_cur;
     void (*pdma_cb)(ESPState *s);
 
     uint8_t mig_version_id;
-- 
2.20.1



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

* [PATCH v2 24/42] esp: use in-built TC to determine PDMA transfer length
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (22 preceding siblings ...)
  2021-02-09 19:29 ` [PATCH v2 23/42] esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-02-23 18:32   ` Philippe Mathieu-Daudé
  2021-03-02 21:48   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 25/42] esp: remove CMD pdma_origin Mark Cave-Ayland
                   ` (18 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Real hardware simply counts down using the in-built TC to determine when the
the PDMA request is complete. Use the TC to determine the PDMA transfer length
which then enables us to remove the redundant pdma_len variable.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 28 +++++++++++++---------------
 include/hw/scsi/esp.h |  1 -
 2 files changed, 13 insertions(+), 16 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 50503a6f53..bff330733f 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -127,10 +127,9 @@ static uint32_t esp_get_stc(ESPState *s)
     return dmalen;
 }
 
-static void set_pdma(ESPState *s, enum pdma_origin_id origin, uint32_t len)
+static void set_pdma(ESPState *s, enum pdma_origin_id origin)
 {
     s->pdma_origin = origin;
-    s->pdma_len = len;
 }
 
 static uint8_t esp_pdma_read(ESPState *s)
@@ -138,7 +137,7 @@ static uint8_t esp_pdma_read(ESPState *s)
     uint32_t dmalen = esp_get_tc(s);
     uint8_t val;
 
-    if (dmalen == 0 || s->pdma_len == 0) {
+    if (dmalen == 0) {
         return 0;
     }
 
@@ -161,7 +160,6 @@ static uint8_t esp_pdma_read(ESPState *s)
     }
 
     s->ti_size--;
-    s->pdma_len--;
     dmalen--;
     esp_set_tc(s, dmalen);
 
@@ -172,7 +170,7 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
 {
     uint32_t dmalen = esp_get_tc(s);
 
-    if (dmalen == 0 || s->pdma_len == 0) {
+    if (dmalen == 0) {
         return;
     }
 
@@ -195,7 +193,6 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
     }
 
     s->ti_size++;
-    s->pdma_len--;
     dmalen--;
     esp_set_tc(s, dmalen);
 }
@@ -243,7 +240,7 @@ static uint32_t get_cmd(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, buf, dmalen);
         } else {
-            set_pdma(s, CMD, dmalen);
+            set_pdma(s, CMD);
             esp_raise_drq(s);
             return 0;
         }
@@ -406,7 +403,7 @@ static void write_response(ESPState *s)
             s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
             s->rregs[ESP_RSEQ] = SEQ_CD;
         } else {
-            set_pdma(s, TI, 2);
+            set_pdma(s, TI);
             s->pdma_cb = write_response_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -474,7 +471,7 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
         } else {
-            set_pdma(s, CMD, len);
+            set_pdma(s, CMD);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -497,7 +494,7 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, s->async_buf, len);
         } else {
-            set_pdma(s, ASYNC, len);
+            set_pdma(s, ASYNC);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -506,7 +503,7 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_write) {
             s->dma_memory_write(s->dma_opaque, s->async_buf, len);
         } else {
-            set_pdma(s, ASYNC, len);
+            set_pdma(s, ASYNC);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -851,7 +848,6 @@ static const VMStateDescription vmstate_esp_pdma = {
     .needed = esp_pdma_needed,
     .fields = (VMStateField[]) {
         VMSTATE_INT32(pdma_origin, ESPState),
-        VMSTATE_UINT32(pdma_len, ESPState),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -950,6 +946,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
 {
     SysBusESPState *sysbus = opaque;
     ESPState *s = ESP(&sysbus->esp);
+    uint32_t dmalen;
 
     trace_esp_pdma_write(size);
 
@@ -962,7 +959,8 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
         esp_pdma_write(s, val);
         break;
     }
-    if (s->pdma_len == 0 && s->pdma_cb) {
+    dmalen = esp_get_tc(s);
+    if (dmalen == 0 && s->pdma_cb) {
         esp_lower_drq(s);
         s->pdma_cb(s);
         s->pdma_cb = NULL;
@@ -979,7 +977,7 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
 
     trace_esp_pdma_read(size);
 
-    if (dmalen == 0 || s->pdma_len == 0) {
+    if (dmalen == 0) {
         return 0;
     }
     switch (size) {
@@ -992,7 +990,7 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
         break;
     }
     dmalen = esp_get_tc(s);
-    if (dmalen == 0 || (s->pdma_len == 0 && s->pdma_cb)) {
+    if (dmalen == 0 && s->pdma_cb) {
         esp_lower_drq(s);
         s->pdma_cb(s);
         s->pdma_cb = NULL;
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 5908d59a0a..1e84b7bfb0 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -57,7 +57,6 @@ struct ESPState {
     void *dma_opaque;
     void (*dma_cb)(ESPState *s);
     int pdma_origin;
-    uint32_t pdma_len;
     void (*pdma_cb)(ESPState *s);
 
     uint8_t mig_version_id;
-- 
2.20.1



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

* [PATCH v2 25/42] esp: remove CMD pdma_origin
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (23 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 24/42] esp: use in-built TC to determine PDMA transfer length Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-02-23 18:34   ` Philippe Mathieu-Daudé
  2021-03-02 21:49   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 26/42] esp: rename get_cmd_cb() to esp_select() Mark Cave-Ayland
                   ` (17 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The cmdbuf is really just a copy of FIFO data (including extra message phase
bytes) so its pdma_origin is effectively TI. Fortunately we already know when
we are receiving a SCSI command since do_cmd == 1 which enables us to
distinguish between the two cases in esp_pdma_read()/esp_pdma_write().

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 22 ++++++++++++----------
 include/hw/scsi/esp.h |  1 -
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index bff330733f..921f79ae89 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -143,10 +143,11 @@ static uint8_t esp_pdma_read(ESPState *s)
 
     switch (s->pdma_origin) {
     case TI:
-        val = s->ti_buf[s->ti_rptr++];
-        break;
-    case CMD:
-        val = s->cmdbuf[s->cmdlen++];
+        if (s->do_cmd) {
+            val = s->cmdbuf[s->cmdlen++];
+        } else {
+            val = s->ti_buf[s->ti_rptr++];
+        }
         break;
     case ASYNC:
         val = s->async_buf[0];
@@ -176,10 +177,11 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
 
     switch (s->pdma_origin) {
     case TI:
-        s->ti_buf[s->ti_wptr++] = val;
-        break;
-    case CMD:
-        s->cmdbuf[s->cmdlen++] = val;
+        if (s->do_cmd) {
+            s->cmdbuf[s->cmdlen++] = val;
+        } else {
+            s->ti_buf[s->ti_wptr++] = val;
+        }
         break;
     case ASYNC:
         s->async_buf[0] = val;
@@ -240,7 +242,7 @@ static uint32_t get_cmd(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, buf, dmalen);
         } else {
-            set_pdma(s, CMD);
+            set_pdma(s, TI);
             esp_raise_drq(s);
             return 0;
         }
@@ -471,7 +473,7 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
         } else {
-            set_pdma(s, CMD);
+            set_pdma(s, TI);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 1e84b7bfb0..a8d5bf8a63 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -17,7 +17,6 @@ typedef struct ESPState ESPState;
 
 enum pdma_origin_id {
     TI,
-    CMD,
     ASYNC,
 };
 
-- 
2.20.1



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

* [PATCH v2 26/42] esp: rename get_cmd_cb() to esp_select()
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (24 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 25/42] esp: remove CMD pdma_origin Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-02 21:51   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 27/42] esp: fix PDMA target selection Mark Cave-Ayland
                   ` (16 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

This better describes the purpose of the function.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 hw/scsi/esp.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 921f79ae89..6736e7142c 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -199,7 +199,7 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
     esp_set_tc(s, dmalen);
 }
 
-static int get_cmd_cb(ESPState *s)
+static int esp_select(ESPState *s)
 {
     int target;
 
@@ -256,7 +256,7 @@ static uint32_t get_cmd(ESPState *s)
     }
     trace_esp_get_cmd(dmalen, target);
 
-    if (get_cmd_cb(s) < 0) {
+    if (esp_select(s) < 0) {
         return 0;
     }
     return dmalen;
@@ -299,7 +299,7 @@ static void do_cmd(ESPState *s)
 
 static void satn_pdma_cb(ESPState *s)
 {
-    if (get_cmd_cb(s) < 0) {
+    if (esp_select(s) < 0) {
         return;
     }
     s->do_cmd = 0;
@@ -325,7 +325,7 @@ static void handle_satn(ESPState *s)
 
 static void s_without_satn_pdma_cb(ESPState *s)
 {
-    if (get_cmd_cb(s) < 0) {
+    if (esp_select(s) < 0) {
         return;
     }
     s->do_cmd = 0;
@@ -351,7 +351,7 @@ static void handle_s_without_atn(ESPState *s)
 
 static void satn_stop_pdma_cb(ESPState *s)
 {
-    if (get_cmd_cb(s) < 0) {
+    if (esp_select(s) < 0) {
         return;
     }
     s->do_cmd = 0;
-- 
2.20.1



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

* [PATCH v2 27/42] esp: fix PDMA target selection
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (25 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 26/42] esp: rename get_cmd_cb() to esp_select() Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-02 21:57   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 28/42] esp: use FIFO for PDMA transfers between initiator and device Mark Cave-Ayland
                   ` (15 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

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;
     }
 }
 
-- 
2.20.1



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

* [PATCH v2 28/42] esp: use FIFO for PDMA transfers between initiator and device
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (26 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 27/42] esp: fix PDMA target selection Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-02 22:02   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 29/42] esp: remove pdma_origin from ESPState Mark Cave-Ayland
                   ` (14 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

PDMA as implemented on the Quadra 800 uses DREQ to load data into the FIFO
up to a maximum of 16 bytes at a time. The MacOS toolbox ROM requires this
because it mixes FIFO and PDMA transfers whilst checking the FIFO status
and counter registers to ensure success.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index b7ab5a5592..5dcd4cd651 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -134,13 +134,8 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin)
 
 static uint8_t esp_pdma_read(ESPState *s)
 {
-    uint32_t dmalen = esp_get_tc(s);
     uint8_t val;
 
-    if (dmalen == 0) {
-        return 0;
-    }
-
     switch (s->pdma_origin) {
     case TI:
         if (s->do_cmd) {
@@ -160,10 +155,6 @@ static uint8_t esp_pdma_read(ESPState *s)
         g_assert_not_reached();
     }
 
-    s->ti_size--;
-    dmalen--;
-    esp_set_tc(s, dmalen);
-
     return val;
 }
 
@@ -194,7 +185,6 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
         g_assert_not_reached();
     }
 
-    s->ti_size++;
     dmalen--;
     esp_set_tc(s, dmalen);
 }
@@ -290,6 +280,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
     s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
     s->rregs[ESP_RSEQ] = SEQ_CD;
     esp_raise_irq(s);
+    esp_lower_drq(s);
 }
 
 static void do_cmd(ESPState *s)
@@ -447,28 +438,71 @@ static void esp_dma_done(ESPState *s)
 static void do_dma_pdma_cb(ESPState *s)
 {
     int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
+    int len;
 
     if (s->do_cmd) {
         s->ti_size = 0;
         s->cmdlen = 0;
         s->do_cmd = 0;
         do_cmd(s);
+        esp_lower_drq(s);
         return;
     }
-    if (s->async_len == 0) {
-        scsi_req_continue(s->current_req);
-        /*
-         * If there is still data to be read from the device then
-         * complete the DMA operation immediately.  Otherwise defer
-         * until the scsi layer has completed.
-         */
-        if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) {
+
+    if (to_device) {
+        /* Copy FIFO data to device */
+        len = MIN(s->ti_wptr, TI_BUFSZ);
+        memcpy(s->async_buf, s->ti_buf, len);
+        s->ti_wptr = 0;
+        s->ti_rptr = 0;
+        s->async_buf += len;
+        s->async_len -= len;
+        s->ti_size += len;
+        if (s->async_len == 0) {
+            scsi_req_continue(s->current_req);
             return;
         }
-    }
 
-    /* Partially filled a scsi buffer. Complete immediately.  */
-    esp_dma_done(s);
+        if (esp_get_tc(s) == 0) {
+            esp_lower_drq(s);
+            esp_dma_done(s);
+        }
+
+        return;
+    } else {
+        if (s->async_len == 0) {
+            if (s->current_req) {
+                scsi_req_continue(s->current_req);
+            }
+
+            /*
+             * If there is still data to be read from the device then
+             * complete the DMA operation immediately.  Otherwise defer
+             * until the scsi layer has completed.
+             */
+            if (esp_get_tc(s) != 0 || s->ti_size == 0) {
+                return;
+            }
+        }
+
+        if (esp_get_tc(s) != 0) {
+            /* Copy device data to FIFO */
+            s->ti_wptr = 0;
+            s->ti_rptr = 0;
+            len = MIN(s->async_len, TI_BUFSZ);
+            memcpy(s->ti_buf, s->async_buf, len);
+            s->ti_wptr += len;
+            s->async_buf += len;
+            s->async_len -= len;
+            s->ti_size -= len;
+            esp_set_tc(s, esp_get_tc(s) - len);
+            return;
+        }
+
+        /* Partially filled a scsi buffer. Complete immediately.  */
+        esp_lower_drq(s);
+        esp_dma_done(s);
+    }
 }
 
 static void esp_do_dma(ESPState *s)
@@ -511,7 +545,7 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, s->async_buf, len);
         } else {
-            set_pdma(s, ASYNC);
+            set_pdma(s, TI);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -520,9 +554,20 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_write) {
             s->dma_memory_write(s->dma_opaque, s->async_buf, len);
         } else {
-            set_pdma(s, ASYNC);
+            /* Copy device data to FIFO */
+            len = MIN(len, TI_BUFSZ - s->ti_wptr);
+            memcpy(&s->ti_buf[s->ti_wptr], s->async_buf, len);
+            s->ti_wptr += len;
+            s->async_buf += len;
+            s->async_len -= len;
+            s->ti_size -= len;
+            esp_set_tc(s, esp_get_tc(s) - len);
+            set_pdma(s, TI);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
+
+            /* Indicate transfer to FIFO is complete */
+            s->rregs[ESP_RSTAT] |= STAT_TC;
             return;
         }
     }
@@ -548,6 +593,7 @@ static void esp_do_dma(ESPState *s)
 
     /* Partially filled a scsi buffer. Complete immediately.  */
     esp_dma_done(s);
+    esp_lower_drq(s);
 }
 
 static void esp_report_command_complete(ESPState *s, uint32_t status)
@@ -564,6 +610,7 @@ static void esp_report_command_complete(ESPState *s, uint32_t status)
     s->status = status;
     s->rregs[ESP_RSTAT] = STAT_ST;
     esp_dma_done(s);
+    esp_lower_drq(s);
     if (s->current_req) {
         scsi_req_unref(s->current_req);
         s->current_req = NULL;
@@ -606,6 +653,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
          * completion interrupt is deferred to here.
          */
         esp_dma_done(s);
+        esp_lower_drq(s);
     }
 }
 
@@ -977,10 +1025,8 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
         break;
     }
     dmalen = esp_get_tc(s);
-    if (dmalen == 0 && s->pdma_cb) {
-        esp_lower_drq(s);
+    if (dmalen == 0 || (s->ti_wptr == TI_BUFSZ)) {
         s->pdma_cb(s);
-        s->pdma_cb = NULL;
     }
 }
 
@@ -989,14 +1035,10 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
 {
     SysBusESPState *sysbus = opaque;
     ESPState *s = ESP(&sysbus->esp);
-    uint32_t dmalen = esp_get_tc(s);
     uint64_t val = 0;
 
     trace_esp_pdma_read(size);
 
-    if (dmalen == 0) {
-        return 0;
-    }
     switch (size) {
     case 1:
         val = esp_pdma_read(s);
@@ -1006,11 +1048,10 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
         val = (val << 8) | esp_pdma_read(s);
         break;
     }
-    dmalen = esp_get_tc(s);
-    if (dmalen == 0 && s->pdma_cb) {
-        esp_lower_drq(s);
+    if (s->ti_rptr == s->ti_wptr) {
+        s->ti_wptr = 0;
+        s->ti_rptr = 0;
         s->pdma_cb(s);
-        s->pdma_cb = NULL;
     }
     return val;
 }
-- 
2.20.1



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

* [PATCH v2 29/42] esp: remove pdma_origin from ESPState
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (27 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 28/42] esp: use FIFO for PDMA transfers between initiator and device Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-02 22:03   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers Mark Cave-Ayland
                   ` (13 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Now that all data is transferred via the FIFO (ti_buf) there is no need to track
the source buffer being used for the data transfer. This also eliminates the
need for a separate subsection for PDMA state migration.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 74 +++++--------------------------------------
 include/hw/scsi/esp.h |  6 ----
 2 files changed, 8 insertions(+), 72 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 5dcd4cd651..7671cc398d 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -127,32 +127,14 @@ static uint32_t esp_get_stc(ESPState *s)
     return dmalen;
 }
 
-static void set_pdma(ESPState *s, enum pdma_origin_id origin)
-{
-    s->pdma_origin = origin;
-}
-
 static uint8_t esp_pdma_read(ESPState *s)
 {
     uint8_t val;
 
-    switch (s->pdma_origin) {
-    case TI:
-        if (s->do_cmd) {
-            val = s->cmdbuf[s->cmdlen++];
-        } else {
-            val = s->ti_buf[s->ti_rptr++];
-        }
-        break;
-    case ASYNC:
-        val = s->async_buf[0];
-        if (s->async_len > 0) {
-            s->async_len--;
-            s->async_buf++;
-        }
-        break;
-    default:
-        g_assert_not_reached();
+    if (s->do_cmd) {
+        val = s->cmdbuf[s->cmdlen++];
+    } else {
+        val = s->ti_buf[s->ti_rptr++];
     }
 
     return val;
@@ -166,23 +148,10 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
         return;
     }
 
-    switch (s->pdma_origin) {
-    case TI:
-        if (s->do_cmd) {
-            s->cmdbuf[s->cmdlen++] = val;
-        } else {
-            s->ti_buf[s->ti_wptr++] = val;
-        }
-        break;
-    case ASYNC:
-        s->async_buf[0] = val;
-        if (s->async_len > 0) {
-            s->async_len--;
-            s->async_buf++;
-        }
-        break;
-    default:
-        g_assert_not_reached();
+    if (s->do_cmd) {
+        s->cmdbuf[s->cmdlen++] = val;
+    } else {
+        s->ti_buf[s->ti_wptr++] = val;
     }
 
     dmalen--;
@@ -232,7 +201,6 @@ static uint32_t get_cmd(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, buf, dmalen);
         } else {
-            set_pdma(s, TI);
             if (esp_select(s) < 0) {
                 return -1;
             }
@@ -411,7 +379,6 @@ static void write_response(ESPState *s)
             s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
             s->rregs[ESP_RSEQ] = SEQ_CD;
         } else {
-            set_pdma(s, TI);
             s->pdma_cb = write_response_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -522,7 +489,6 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
         } else {
-            set_pdma(s, TI);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -545,7 +511,6 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, s->async_buf, len);
         } else {
-            set_pdma(s, TI);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
@@ -562,7 +527,6 @@ static void esp_do_dma(ESPState *s)
             s->async_len -= len;
             s->ti_size -= len;
             esp_set_tc(s, esp_get_tc(s) - len);
-            set_pdma(s, TI);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
 
@@ -899,24 +863,6 @@ static bool esp_mem_accepts(void *opaque, hwaddr addr,
     return (size == 1) || (is_write && size == 4);
 }
 
-static bool esp_pdma_needed(void *opaque)
-{
-    ESPState *s = opaque;
-    return s->dma_memory_read == NULL && s->dma_memory_write == NULL &&
-           s->dma_enabled;
-}
-
-static const VMStateDescription vmstate_esp_pdma = {
-    .name = "esp/pdma",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .needed = esp_pdma_needed,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32(pdma_origin, ESPState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
 static bool esp_is_before_version_5(void *opaque, int version_id)
 {
     ESPState *s = ESP(opaque);
@@ -971,10 +917,6 @@ const VMStateDescription vmstate_esp = {
         VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
         VMSTATE_END_OF_LIST()
     },
-    .subsections = (const VMStateDescription * []) {
-        &vmstate_esp_pdma,
-        NULL
-    }
 };
 
 static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index a8d5bf8a63..6618f4e091 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -15,11 +15,6 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
 
 typedef struct ESPState ESPState;
 
-enum pdma_origin_id {
-    TI,
-    ASYNC,
-};
-
 #define TYPE_ESP "esp"
 OBJECT_DECLARE_SIMPLE_TYPE(ESPState, ESP)
 
@@ -55,7 +50,6 @@ struct ESPState {
     ESPDMAMemoryReadWriteFunc dma_memory_write;
     void *dma_opaque;
     void (*dma_cb)(ESPState *s);
-    int pdma_origin;
     void (*pdma_cb)(ESPState *s);
 
     uint8_t mig_version_id;
-- 
2.20.1



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

* [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (28 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 29/42] esp: remove pdma_origin from ESPState Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-02-12 18:56   ` Philippe Mathieu-Daudé
  2021-03-02 22:05   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 31/42] esp: implement FIFO flush command Mark Cave-Ayland
                   ` (12 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The MacOS toolbox ROM performs 4 byte reads/writes when transferring data to
and from the target. Since the SCSI bus is 16-bits wide, use the memory API
to split a 4 byte access into 2 x 2 byte accesses.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 7671cc398d..1d56c99527 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -1003,7 +1003,9 @@ static const MemoryRegionOps sysbus_esp_pdma_ops = {
     .write = sysbus_esp_pdma_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
     .valid.min_access_size = 1,
-    .valid.max_access_size = 2,
+    .valid.max_access_size = 4,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 2,
 };
 
 static const struct SCSIBusInfo esp_scsi_info = {
@@ -1048,7 +1050,7 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
                           sysbus, "esp-regs", ESP_REGS << sysbus->it_shift);
     sysbus_init_mmio(sbd, &sysbus->iomem);
     memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops,
-                          sysbus, "esp-pdma", 2);
+                          sysbus, "esp-pdma", 4);
     sysbus_init_mmio(sbd, &sysbus->pdma);
 
     qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2);
-- 
2.20.1



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

* [PATCH v2 31/42] esp: implement FIFO flush command
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (29 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-03 19:32   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 32/42] esp: latch individual bits in ESP_RINTR register Mark Cave-Ayland
                   ` (11 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

At this point it is now possible to properly implement the FIFO flush command
without causing guest errors.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 1d56c99527..0994673ff8 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -770,6 +770,8 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
         case CMD_FLUSH:
             trace_esp_mem_writeb_cmd_flush(val);
             /*s->ti_size = 0;*/
+            s->ti_wptr = 0;
+            s->ti_rptr = 0;
             s->rregs[ESP_RINTR] = INTR_FC;
             s->rregs[ESP_RSEQ] = 0;
             s->rregs[ESP_RFLAGS] = 0;
-- 
2.20.1



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

* [PATCH v2 32/42] esp: latch individual bits in ESP_RINTR register
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (30 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 31/42] esp: implement FIFO flush command Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-03 19:48   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 33/42] esp: defer command completion interrupt on incoming data transfers Mark Cave-Ayland
                   ` (10 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Currently the ESP_RINTR register is set to a specific value as required within
the ESP state machine. In order to implement the upcoming deferred interrupt
functionality it is necessary to set individual bits within ESP_RINTR so that
a deferred interrupt will not overwrite the value of any other interrupt bits.

This also requires fixing up a few locations where the ESP_RINTR and ESP_RSEQ
registers are set/reset unexpectedly.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 0994673ff8..728d4ddf99 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -178,7 +178,7 @@ static int esp_select(ESPState *s)
     if (!s->current_dev) {
         /* No such drive */
         s->rregs[ESP_RSTAT] = 0;
-        s->rregs[ESP_RINTR] = INTR_DC;
+        s->rregs[ESP_RINTR] |= INTR_DC;
         s->rregs[ESP_RSEQ] = SEQ_0;
         esp_raise_irq(s);
         return -1;
@@ -245,7 +245,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
         }
         scsi_req_continue(s->current_req);
     }
-    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+    s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
     s->rregs[ESP_RSEQ] = SEQ_CD;
     esp_raise_irq(s);
     esp_lower_drq(s);
@@ -326,7 +326,7 @@ static void satn_stop_pdma_cb(ESPState *s)
         trace_esp_handle_satn_stop(s->cmdlen);
         s->do_cmd = 1;
         s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
-        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+        s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
         esp_raise_irq(s);
     }
@@ -346,8 +346,8 @@ static void handle_satn_stop(ESPState *s)
         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_RSTAT] = STAT_CD;
+        s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
         esp_raise_irq(s);
     } else if (cmdlen == 0) {
@@ -362,7 +362,7 @@ static void handle_satn_stop(ESPState *s)
 static void write_response_pdma_cb(ESPState *s)
 {
     s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
-    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+    s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
     s->rregs[ESP_RSEQ] = SEQ_CD;
     esp_raise_irq(s);
 }
@@ -376,7 +376,7 @@ static void write_response(ESPState *s)
         if (s->dma_memory_write) {
             s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
             s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
-            s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+            s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
             s->rregs[ESP_RSEQ] = SEQ_CD;
         } else {
             s->pdma_cb = write_response_pdma_cb;
@@ -395,7 +395,7 @@ static void write_response(ESPState *s)
 static void esp_dma_done(ESPState *s)
 {
     s->rregs[ESP_RSTAT] |= STAT_TC;
-    s->rregs[ESP_RINTR] = INTR_BS;
+    s->rregs[ESP_RINTR] |= INTR_BS;
     s->rregs[ESP_RSEQ] = 0;
     s->rregs[ESP_RFLAGS] = 0;
     esp_set_tc(s, 0);
@@ -701,7 +701,7 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
         val = s->rregs[ESP_RINTR];
         s->rregs[ESP_RINTR] = 0;
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
-        s->rregs[ESP_RSEQ] = SEQ_CD;
+        s->rregs[ESP_RSEQ] = SEQ_0;
         esp_lower_irq(s);
         if (s->deferred_complete) {
             esp_report_command_complete(s, s->deferred_status);
@@ -772,9 +772,6 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
             /*s->ti_size = 0;*/
             s->ti_wptr = 0;
             s->ti_rptr = 0;
-            s->rregs[ESP_RINTR] = INTR_FC;
-            s->rregs[ESP_RSEQ] = 0;
-            s->rregs[ESP_RFLAGS] = 0;
             break;
         case CMD_RESET:
             trace_esp_mem_writeb_cmd_reset(val);
@@ -782,8 +779,8 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
             break;
         case CMD_BUSRESET:
             trace_esp_mem_writeb_cmd_bus_reset(val);
-            s->rregs[ESP_RINTR] = INTR_RST;
             if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
+                s->rregs[ESP_RINTR] |= INTR_RST;
                 esp_raise_irq(s);
             }
             break;
@@ -794,12 +791,12 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
         case CMD_ICCS:
             trace_esp_mem_writeb_cmd_iccs(val);
             write_response(s);
-            s->rregs[ESP_RINTR] = INTR_FC;
+            s->rregs[ESP_RINTR] |= INTR_FC;
             s->rregs[ESP_RSTAT] |= STAT_MI;
             break;
         case CMD_MSGACC:
             trace_esp_mem_writeb_cmd_msgacc(val);
-            s->rregs[ESP_RINTR] = INTR_DC;
+            s->rregs[ESP_RINTR] |= INTR_DC;
             s->rregs[ESP_RSEQ] = 0;
             s->rregs[ESP_RFLAGS] = 0;
             esp_raise_irq(s);
@@ -807,7 +804,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
         case CMD_PAD:
             trace_esp_mem_writeb_cmd_pad(val);
             s->rregs[ESP_RSTAT] = STAT_TC;
-            s->rregs[ESP_RINTR] = INTR_FC;
+            s->rregs[ESP_RINTR] |= INTR_FC;
             s->rregs[ESP_RSEQ] = 0;
             break;
         case CMD_SATN:
-- 
2.20.1



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

* [PATCH v2 33/42] esp: defer command completion interrupt on incoming data transfers
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (31 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 32/42] esp: latch individual bits in ESP_RINTR register Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-02-18 17:25   ` Mark Cave-Ayland
  2021-02-09 19:30 ` [PATCH v2 34/42] esp: remove old deferred command completion mechanism Mark Cave-Ayland
                   ` (9 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The MacOS toolbox ROM issues a command to the ESP controller as part of its
"FAST" SCSI routines and then proceeds to read the incoming data soon after
receiving the command completion interrupt.

Unfortunately due to SCSI block transfers being asynchronous the incoming data
may not yet be present causing an underflow error. Resolve this by waiting for
the SCSI subsystem transfer_data callback before raising the command completion
interrupt.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 54 +++++++++++++++++++++++++++++++++++++++----
 include/hw/scsi/esp.h |  1 +
 2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 728d4ddf99..ce6a7a1ed0 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -183,6 +183,14 @@ static int esp_select(ESPState *s)
         esp_raise_irq(s);
         return -1;
     }
+
+    /*
+     * Note that we deliberately don't raise the IRQ here: this will be done
+     * either in do_busid_cmd() for DATA OUT transfers or by the deferred
+     * IRQ mechanism in esp_transfer_data() for DATA IN transfers
+     */
+    s->rregs[ESP_RINTR] |= INTR_FC;
+    s->rregs[ESP_RSEQ] = SEQ_CD;
     return 0;
 }
 
@@ -237,18 +245,24 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
     s->ti_size = datalen;
     if (datalen != 0) {
         s->rregs[ESP_RSTAT] = STAT_TC;
+        s->rregs[ESP_RSEQ] = SEQ_CD;
         esp_set_tc(s, 0);
         if (datalen > 0) {
+            /*
+             * Switch to DATA IN phase but wait until initial data xfer is
+             * complete before raising the command completion interrupt
+             */
+            s->data_in_ready = false;
             s->rregs[ESP_RSTAT] |= STAT_DI;
         } else {
             s->rregs[ESP_RSTAT] |= STAT_DO;
+            s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
+            esp_raise_irq(s);
+            esp_lower_drq(s);
         }
         scsi_req_continue(s->current_req);
+        return;
     }
-    s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
-    s->rregs[ESP_RSEQ] = SEQ_CD;
-    esp_raise_irq(s);
-    esp_lower_drq(s);
 }
 
 static void do_cmd(ESPState *s)
@@ -603,12 +617,35 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
 void esp_transfer_data(SCSIRequest *req, uint32_t len)
 {
     ESPState *s = req->hba_private;
+    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
     uint32_t dmalen = esp_get_tc(s);
 
     assert(!s->do_cmd);
     trace_esp_transfer_data(dmalen, s->ti_size);
     s->async_len = len;
     s->async_buf = scsi_req_get_buf(req);
+
+    if (!to_device && !s->data_in_ready) {
+        /*
+         * Initial incoming data xfer is complete so raise command
+         * completion interrupt
+         */
+        s->data_in_ready = true;
+        s->rregs[ESP_RSTAT] |= STAT_TC;
+        s->rregs[ESP_RINTR] |= INTR_BS;
+        esp_raise_irq(s);
+
+        /*
+         * If data is ready to transfer and the TI command has already
+         * been executed, start DMA immediately. Otherwise DMA will start
+         * when host sends the TI command
+         */
+        if (s->ti_size && (s->rregs[ESP_CMD] == (CMD_TI | CMD_DMA))) {
+            esp_do_dma(s);
+        }
+        return;
+    }
+
     if (dmalen) {
         esp_do_dma(s);
     } else if (s->ti_size <= 0) {
@@ -870,6 +907,14 @@ static bool esp_is_before_version_5(void *opaque, int version_id)
     return version_id < 5;
 }
 
+static bool esp_is_version_5(void *opaque, int version_id)
+{
+    ESPState *s = ESP(opaque);
+
+    version_id = MIN(version_id, s->mig_version_id);
+    return version_id == 5;
+}
+
 static int esp_pre_save(void *opaque)
 {
     ESPState *s = ESP(opaque);
@@ -914,6 +959,7 @@ const VMStateDescription vmstate_esp = {
         VMSTATE_UINT32(cmdlen, ESPState),
         VMSTATE_UINT32(do_cmd, ESPState),
         VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
+        VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
         VMSTATE_END_OF_LIST()
     },
 };
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 6618f4e091..3b69aedebe 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -41,6 +41,7 @@ struct ESPState {
     uint32_t cmdlen;
     uint32_t do_cmd;
 
+    bool data_in_ready;
     int dma_enabled;
 
     uint32_t async_len;
-- 
2.20.1



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

* [PATCH v2 34/42] esp: remove old deferred command completion mechanism
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (32 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 33/42] esp: defer command completion interrupt on incoming data transfers Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-03 19:55   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 35/42] esp: raise interrupt after every non-DMA byte transferred to the FIFO Mark Cave-Ayland
                   ` (8 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Commit ea84a44250 "scsi: esp: Defer command completion until previous interrupts
have been handled" provided a mechanism to delay the command completion interrupt
until ESP_RINTR is read after the command has completed.

With the previous fixes for latching the ESP_RINTR bits and deferring the setting
of the command completion interrupt for incoming data to the SCSI callback, this
workaround is no longer required and can be removed.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 33 ++++++++-------------------------
 include/hw/scsi/esp.h |  4 ++--
 2 files changed, 10 insertions(+), 27 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index ce6a7a1ed0..8b856155d1 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -574,8 +574,11 @@ static void esp_do_dma(ESPState *s)
     esp_lower_drq(s);
 }
 
-static void esp_report_command_complete(ESPState *s, uint32_t status)
+void esp_command_complete(SCSIRequest *req, uint32_t status,
+                          size_t resid)
 {
+    ESPState *s = req->hba_private;
+
     trace_esp_command_complete();
     if (s->ti_size != 0) {
         trace_esp_command_complete_unexpected();
@@ -596,24 +599,6 @@ static void esp_report_command_complete(ESPState *s, uint32_t status)
     }
 }
 
-void esp_command_complete(SCSIRequest *req, uint32_t status,
-                          size_t resid)
-{
-    ESPState *s = req->hba_private;
-
-    if (s->rregs[ESP_RSTAT] & STAT_INT) {
-        /*
-         * Defer handling command complete until the previous
-         * interrupt has been handled.
-         */
-        trace_esp_command_complete_deferred();
-        s->deferred_status = status;
-        s->deferred_complete = true;
-        return;
-    }
-    esp_report_command_complete(s, status);
-}
-
 void esp_transfer_data(SCSIRequest *req, uint32_t len)
 {
     ESPState *s = req->hba_private;
@@ -740,10 +725,6 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
         s->rregs[ESP_RSEQ] = SEQ_0;
         esp_lower_irq(s);
-        if (s->deferred_complete) {
-            esp_report_command_complete(s, s->deferred_status);
-            s->deferred_complete = false;
-        }
         break;
     case ESP_TCHI:
         /* Return the unique id if the value has never been written */
@@ -951,8 +932,10 @@ const VMStateDescription vmstate_esp = {
         VMSTATE_UINT32(ti_wptr, ESPState),
         VMSTATE_BUFFER(ti_buf, ESPState),
         VMSTATE_UINT32(status, ESPState),
-        VMSTATE_UINT32(deferred_status, ESPState),
-        VMSTATE_BOOL(deferred_complete, ESPState),
+        VMSTATE_UINT32_TEST(mig_deferred_status, ESPState,
+                            esp_is_before_version_5),
+        VMSTATE_BOOL_TEST(mig_deferred_complete, ESPState,
+                          esp_is_before_version_5),
         VMSTATE_UINT32(dma, ESPState),
         VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16),
         VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 3b69aedebe..5e68908fcb 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -30,8 +30,6 @@ struct ESPState {
     int32_t ti_size;
     uint32_t ti_rptr, ti_wptr;
     uint32_t status;
-    uint32_t deferred_status;
-    bool deferred_complete;
     uint32_t dma;
     uint8_t ti_buf[TI_BUFSZ];
     SCSIBus bus;
@@ -57,6 +55,8 @@ struct ESPState {
 
     /* Legacy fields for vmstate_esp version < 5 */
     uint32_t mig_dma_left;
+    uint32_t mig_deferred_status;
+    bool mig_deferred_complete;
 };
 
 #define TYPE_SYSBUS_ESP "sysbus-esp"
-- 
2.20.1



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

* [PATCH v2 35/42] esp: raise interrupt after every non-DMA byte transferred to the FIFO
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (33 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 34/42] esp: remove old deferred command completion mechanism Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-03 19:59   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 36/42] esp: add maxlen parameter to get_cmd() Mark Cave-Ayland
                   ` (7 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

This matches the description in the datasheet and is required as support for
non-DMA transfers is added.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 8b856155d1..617fdcb3ed 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -767,6 +767,12 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
             s->ti_size++;
             s->ti_buf[s->ti_wptr++] = val & 0xff;
         }
+
+        /* Non-DMA transfers raise an interrupt after every byte */
+        if (s->rregs[ESP_CMD] == CMD_TI) {
+            s->rregs[ESP_RINTR] |= INTR_FC | INTR_BS;
+            esp_raise_irq(s);
+        }
         break;
     case ESP_CMD:
         s->rregs[saddr] = val;
-- 
2.20.1



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

* [PATCH v2 36/42] esp: add maxlen parameter to get_cmd()
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (34 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 35/42] esp: raise interrupt after every non-DMA byte transferred to the FIFO Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-02-23 18:43   ` Philippe Mathieu-Daudé
  2021-03-03 20:04   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 37/42] esp: transition to message out phase after SATN and stop command Mark Cave-Ayland
                   ` (6 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Some guests use a mixture of DMA and non-DMA transfers in combination with the
SATN and stop command to transfer message out phase and command phase bytes to
the target. Prepare for the next commit by adding a maxlen parameter to
get_cmd() to allow partial transfers.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 617fdcb3ed..058b482fda 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -194,7 +194,7 @@ static int esp_select(ESPState *s)
     return 0;
 }
 
-static uint32_t get_cmd(ESPState *s)
+static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
 {
     uint8_t *buf = s->cmdbuf;
     uint32_t dmalen;
@@ -202,8 +202,8 @@ static uint32_t get_cmd(ESPState *s)
 
     target = s->wregs[ESP_WBUSID] & BUSID_DID;
     if (s->dma) {
-        dmalen = esp_get_tc(s);
-        if (dmalen > ESP_CMDBUF_SZ) {
+        dmalen = MIN(esp_get_tc(s), maxlen);
+        if (dmalen == 0) {
             return 0;
         }
         if (s->dma_memory_read) {
@@ -216,12 +216,14 @@ static uint32_t get_cmd(ESPState *s)
             return 0;
         }
     } else {
-        dmalen = s->ti_size;
-        if (dmalen > TI_BUFSZ) {
+        dmalen = MIN(s->ti_size, maxlen);
+        if (dmalen == 0) {
             return 0;
         }
         memcpy(buf, s->ti_buf, dmalen);
-        buf[0] = buf[2] >> 5;
+        if (dmalen >= 3) {
+            buf[0] = buf[2] >> 5;
+        }
     }
     trace_esp_get_cmd(dmalen, target);
 
@@ -290,7 +292,7 @@ static void handle_satn(ESPState *s)
         return;
     }
     s->pdma_cb = satn_pdma_cb;
-    cmdlen = get_cmd(s);
+    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
     if (cmdlen > 0) {
         s->cmdlen = cmdlen;
         do_cmd(s);
@@ -320,7 +322,7 @@ static void handle_s_without_atn(ESPState *s)
         return;
     }
     s->pdma_cb = s_without_satn_pdma_cb;
-    cmdlen = get_cmd(s);
+    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
     if (cmdlen > 0) {
         s->cmdlen = cmdlen;
         do_busid_cmd(s, s->cmdbuf, 0);
@@ -355,7 +357,7 @@ static void handle_satn_stop(ESPState *s)
         return;
     }
     s->pdma_cb = satn_stop_pdma_cb;
-    cmdlen = get_cmd(s);
+    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
     if (cmdlen > 0) {
         trace_esp_handle_satn_stop(s->cmdlen);
         s->cmdlen = cmdlen;
-- 
2.20.1



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

* [PATCH v2 37/42] esp: transition to message out phase after SATN and stop command
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (35 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 36/42] esp: add maxlen parameter to get_cmd() Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-03 20:06   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 38/42] esp: convert ti_buf from array to Fifo8 Mark Cave-Ayland
                   ` (5 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The SCSI bus should remain in the message out phase after the SATN and stop
command rather than transitioning to the command phase. A new ESPState variable
cmdbuf_cdb_offset is added which stores the offset of the CDB from the start
of cmdbuf when accumulating extended message out phase data.

Currently any extended message out data is discarded in do_cmd() before the CDB
is processed in do_busid_cmd().

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 72 ++++++++++++++++++++++++++++++++++---------
 include/hw/scsi/esp.h |  2 ++
 2 files changed, 60 insertions(+), 14 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 058b482fda..5a66b7d710 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -272,13 +272,15 @@ static void do_cmd(ESPState *s)
     uint8_t *buf = s->cmdbuf;
     uint8_t busid = buf[0];
 
-    do_busid_cmd(s, &buf[1], busid);
+    /* Ignore extended messages for now */
+    do_busid_cmd(s, &buf[s->cmdbuf_cdb_offset], busid);
 }
 
 static void satn_pdma_cb(ESPState *s)
 {
     s->do_cmd = 0;
     if (s->cmdlen) {
+        s->cmdbuf_cdb_offset = 1;
         do_cmd(s);
     }
 }
@@ -295,6 +297,7 @@ static void handle_satn(ESPState *s)
     cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
     if (cmdlen > 0) {
         s->cmdlen = cmdlen;
+        s->cmdbuf_cdb_offset = 1;
         do_cmd(s);
     } else if (cmdlen == 0) {
         s->cmdlen = 0;
@@ -309,6 +312,7 @@ static void s_without_satn_pdma_cb(ESPState *s)
 {
     s->do_cmd = 0;
     if (s->cmdlen) {
+        s->cmdbuf_cdb_offset = 0;
         do_busid_cmd(s, s->cmdbuf, 0);
     }
 }
@@ -325,6 +329,7 @@ static void handle_s_without_atn(ESPState *s)
     cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
     if (cmdlen > 0) {
         s->cmdlen = cmdlen;
+        s->cmdbuf_cdb_offset = 0;
         do_busid_cmd(s, s->cmdbuf, 0);
     } else if (cmdlen == 0) {
         s->cmdlen = 0;
@@ -341,6 +346,7 @@ static void satn_stop_pdma_cb(ESPState *s)
     if (s->cmdlen) {
         trace_esp_handle_satn_stop(s->cmdlen);
         s->do_cmd = 1;
+        s->cmdbuf_cdb_offset = 1;
         s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
         s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
@@ -357,21 +363,22 @@ static void handle_satn_stop(ESPState *s)
         return;
     }
     s->pdma_cb = satn_stop_pdma_cb;
-    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
+    cmdlen = get_cmd(s, 1);
     if (cmdlen > 0) {
-        trace_esp_handle_satn_stop(s->cmdlen);
+        trace_esp_handle_satn_stop(cmdlen);
         s->cmdlen = cmdlen;
         s->do_cmd = 1;
-        s->rregs[ESP_RSTAT] = STAT_CD;
+        s->cmdbuf_cdb_offset = 1;
+        s->rregs[ESP_RSTAT] = STAT_MO;
         s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
-        s->rregs[ESP_RSEQ] = SEQ_CD;
+        s->rregs[ESP_RSEQ] = SEQ_MO;
         esp_raise_irq(s);
     } 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;
+        /* Target present, switch to message out phase */
+        s->rregs[ESP_RSEQ] = SEQ_MO;
+        s->rregs[ESP_RSTAT] = STAT_MO;
     }
 }
 
@@ -511,9 +518,27 @@ static void esp_do_dma(ESPState *s)
         }
         trace_esp_handle_ti_cmd(s->cmdlen);
         s->ti_size = 0;
-        s->cmdlen = 0;
-        s->do_cmd = 0;
-        do_cmd(s);
+        if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
+            /* No command received */
+            if (s->cmdbuf_cdb_offset == s->cmdlen) {
+                return;
+            }
+
+            /* Command has been received */
+            s->cmdlen = 0;
+            s->do_cmd = 0;
+            do_cmd(s);
+        } else {
+            /*
+             * Extra message out bytes received: update cmdbuf_cdb_offset
+             * and then switch to commmand phase
+             */
+            s->cmdbuf_cdb_offset = s->cmdlen;
+            s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
+            s->rregs[ESP_RSEQ] = SEQ_CD;
+            s->rregs[ESP_RINTR] |= INTR_BS;
+            esp_raise_irq(s);
+        }
         return;
     }
     if (s->async_len == 0) {
@@ -662,9 +687,27 @@ static void handle_ti(ESPState *s)
     } else if (s->do_cmd) {
         trace_esp_handle_ti_cmd(s->cmdlen);
         s->ti_size = 0;
-        s->cmdlen = 0;
-        s->do_cmd = 0;
-        do_cmd(s);
+        if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
+            /* No command received */
+            if (s->cmdbuf_cdb_offset == s->cmdlen) {
+                return;
+            }
+
+            /* Command has been received */
+            s->cmdlen = 0;
+            s->do_cmd = 0;
+            do_cmd(s);
+        } else {
+            /*
+             * Extra message out bytes received: update cmdbuf_cdb_offset
+             * and then switch to commmand phase
+             */
+            s->cmdbuf_cdb_offset = s->cmdlen;
+            s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
+            s->rregs[ESP_RSEQ] = SEQ_CD;
+            s->rregs[ESP_RINTR] |= INTR_BS;
+            esp_raise_irq(s);
+        }
     }
 }
 
@@ -951,6 +994,7 @@ const VMStateDescription vmstate_esp = {
         VMSTATE_UINT32(do_cmd, ESPState),
         VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
         VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
+        VMSTATE_UINT8_TEST(cmdbuf_cdb_offset, ESPState, esp_is_version_5),
         VMSTATE_END_OF_LIST()
     },
 };
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 5e68908fcb..6f3bf4a0ce 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -37,6 +37,7 @@ struct ESPState {
     SCSIRequest *current_req;
     uint8_t cmdbuf[ESP_CMDBUF_SZ];
     uint32_t cmdlen;
+    uint8_t cmdbuf_cdb_offset;
     uint32_t do_cmd;
 
     bool data_in_ready;
@@ -136,6 +137,7 @@ struct SysBusESPState {
 #define INTR_RST 0x80
 
 #define SEQ_0 0x0
+#define SEQ_MO 0x1
 #define SEQ_CD 0x4
 
 #define CFG1_RESREPT 0x40
-- 
2.20.1



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

* [PATCH v2 38/42] esp: convert ti_buf from array to Fifo8
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (36 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 37/42] esp: transition to message out phase after SATN and stop command Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-02-23 18:49   ` Philippe Mathieu-Daudé
  2021-03-03 20:11   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 39/42] esp: convert cmdbuf " Mark Cave-Ayland
                   ` (4 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Rename TI_BUFSZ to ESP_FIFO_SZ since this constant is really describing the size
of the FIFO and is not directly related to the TI size.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 117 ++++++++++++++++++++++++++----------------
 include/hw/scsi/esp.h |   8 +--
 2 files changed, 79 insertions(+), 46 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 5a66b7d710..98df357276 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -98,6 +98,25 @@ void esp_request_cancelled(SCSIRequest *req)
     }
 }
 
+static void esp_fifo_push(ESPState *s, uint8_t val)
+{
+    if (fifo8_num_used(&s->fifo) == ESP_FIFO_SZ) {
+        trace_esp_error_fifo_overrun();
+        return;
+    }
+
+    fifo8_push(&s->fifo, val);
+}
+
+static uint8_t esp_fifo_pop(ESPState *s)
+{
+    if (fifo8_is_empty(&s->fifo)) {
+        return 0;
+    }
+
+    return fifo8_pop(&s->fifo);
+}
+
 static uint32_t esp_get_tc(ESPState *s)
 {
     uint32_t dmalen;
@@ -134,7 +153,7 @@ static uint8_t esp_pdma_read(ESPState *s)
     if (s->do_cmd) {
         val = s->cmdbuf[s->cmdlen++];
     } else {
-        val = s->ti_buf[s->ti_rptr++];
+        val = esp_fifo_pop(s);
     }
 
     return val;
@@ -151,7 +170,7 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
     if (s->do_cmd) {
         s->cmdbuf[s->cmdlen++] = val;
     } else {
-        s->ti_buf[s->ti_wptr++] = val;
+        esp_fifo_push(s, val);
     }
 
     dmalen--;
@@ -165,8 +184,7 @@ static int esp_select(ESPState *s)
     target = s->wregs[ESP_WBUSID] & BUSID_DID;
 
     s->ti_size = 0;
-    s->ti_rptr = 0;
-    s->ti_wptr = 0;
+    fifo8_reset(&s->fifo);
 
     if (s->current_req) {
         /* Started a new command before the old one finished.  Cancel it.  */
@@ -197,7 +215,7 @@ static int esp_select(ESPState *s)
 static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
 {
     uint8_t *buf = s->cmdbuf;
-    uint32_t dmalen;
+    uint32_t dmalen, n;
     int target;
 
     target = s->wregs[ESP_WBUSID] & BUSID_DID;
@@ -220,7 +238,7 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
         if (dmalen == 0) {
             return 0;
         }
-        memcpy(buf, s->ti_buf, dmalen);
+        memcpy(buf, fifo8_pop_buf(&s->fifo, dmalen, &n), dmalen);
         if (dmalen >= 3) {
             buf[0] = buf[2] >> 5;
         }
@@ -392,12 +410,18 @@ static void write_response_pdma_cb(ESPState *s)
 
 static void write_response(ESPState *s)
 {
+    uint32_t n;
+
     trace_esp_write_response(s->status);
-    s->ti_buf[0] = s->status;
-    s->ti_buf[1] = 0;
+
+    fifo8_reset(&s->fifo);
+    esp_fifo_push(s, s->status);
+    esp_fifo_push(s, 0);
+
     if (s->dma) {
         if (s->dma_memory_write) {
-            s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
+            s->dma_memory_write(s->dma_opaque,
+                                (uint8_t *)fifo8_pop_buf(&s->fifo, 2, &n), 2);
             s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
             s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
             s->rregs[ESP_RSEQ] = SEQ_CD;
@@ -408,8 +432,6 @@ static void write_response(ESPState *s)
         }
     } else {
         s->ti_size = 2;
-        s->ti_rptr = 0;
-        s->ti_wptr = 2;
         s->rregs[ESP_RFLAGS] = 2;
     }
     esp_raise_irq(s);
@@ -429,6 +451,7 @@ static void do_dma_pdma_cb(ESPState *s)
 {
     int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
     int len;
+    uint32_t n;
 
     if (s->do_cmd) {
         s->ti_size = 0;
@@ -441,10 +464,8 @@ static void do_dma_pdma_cb(ESPState *s)
 
     if (to_device) {
         /* Copy FIFO data to device */
-        len = MIN(s->ti_wptr, TI_BUFSZ);
-        memcpy(s->async_buf, s->ti_buf, len);
-        s->ti_wptr = 0;
-        s->ti_rptr = 0;
+        len = MIN(fifo8_num_used(&s->fifo), ESP_FIFO_SZ);
+        memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
         s->async_buf += len;
         s->async_len -= len;
         s->ti_size += len;
@@ -477,11 +498,8 @@ static void do_dma_pdma_cb(ESPState *s)
 
         if (esp_get_tc(s) != 0) {
             /* Copy device data to FIFO */
-            s->ti_wptr = 0;
-            s->ti_rptr = 0;
-            len = MIN(s->async_len, TI_BUFSZ);
-            memcpy(s->ti_buf, s->async_buf, len);
-            s->ti_wptr += len;
+            len = MIN(s->async_len, fifo8_num_free(&s->fifo));
+            fifo8_push_all(&s->fifo, s->async_buf, len);
             s->async_buf += len;
             s->async_len -= len;
             s->ti_size -= len;
@@ -561,9 +579,8 @@ static void esp_do_dma(ESPState *s)
             s->dma_memory_write(s->dma_opaque, s->async_buf, len);
         } else {
             /* Copy device data to FIFO */
-            len = MIN(len, TI_BUFSZ - s->ti_wptr);
-            memcpy(&s->ti_buf[s->ti_wptr], s->async_buf, len);
-            s->ti_wptr += len;
+            len = MIN(len, fifo8_num_free(&s->fifo));
+            fifo8_push_all(&s->fifo, s->async_buf, len);
             s->async_buf += len;
             s->async_len -= len;
             s->ti_size -= len;
@@ -717,8 +734,7 @@ void esp_hard_reset(ESPState *s)
     memset(s->wregs, 0, ESP_REGS);
     s->tchi_written = 0;
     s->ti_size = 0;
-    s->ti_rptr = 0;
-    s->ti_wptr = 0;
+    fifo8_reset(&s->fifo);
     s->dma = 0;
     s->do_cmd = 0;
     s->dma_cb = NULL;
@@ -750,13 +766,9 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
             /* Data out.  */
             qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
             s->rregs[ESP_FIFO] = 0;
-        } else if (s->ti_rptr < s->ti_wptr) {
+        } else {
             s->ti_size--;
-            s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
-        }
-        if (s->ti_rptr == s->ti_wptr) {
-            s->ti_rptr = 0;
-            s->ti_wptr = 0;
+            s->rregs[ESP_FIFO] = esp_fifo_pop(s);
         }
         val = s->rregs[ESP_FIFO];
         break;
@@ -806,11 +818,9 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
             } else {
                 trace_esp_error_fifo_overrun();
             }
-        } else if (s->ti_wptr == TI_BUFSZ - 1) {
-            trace_esp_error_fifo_overrun();
         } else {
             s->ti_size++;
-            s->ti_buf[s->ti_wptr++] = val & 0xff;
+            esp_fifo_push(s, val & 0xff);
         }
 
         /* Non-DMA transfers raise an interrupt after every byte */
@@ -839,8 +849,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
         case CMD_FLUSH:
             trace_esp_mem_writeb_cmd_flush(val);
             /*s->ti_size = 0;*/
-            s->ti_wptr = 0;
-            s->ti_rptr = 0;
+            fifo8_reset(&s->fifo);
             break;
         case CMD_RESET:
             trace_esp_mem_writeb_cmd_reset(val);
@@ -958,11 +967,18 @@ static int esp_pre_save(void *opaque)
 static int esp_post_load(void *opaque, int version_id)
 {
     ESPState *s = ESP(opaque);
+    int len, i;
 
     version_id = MIN(version_id, s->mig_version_id);
 
     if (version_id < 5) {
         esp_set_tc(s, s->mig_dma_left);
+
+        /* Migrate ti_buf to fifo */
+        len = s->mig_ti_wptr - s->mig_ti_rptr;
+        for (i = 0; i < len; i++) {
+            fifo8_push(&s->fifo, s->mig_ti_buf[i]);
+        }
     }
 
     s->mig_version_id = vmstate_esp.version_id;
@@ -979,9 +995,9 @@ const VMStateDescription vmstate_esp = {
         VMSTATE_BUFFER(rregs, ESPState),
         VMSTATE_BUFFER(wregs, ESPState),
         VMSTATE_INT32(ti_size, ESPState),
-        VMSTATE_UINT32(ti_rptr, ESPState),
-        VMSTATE_UINT32(ti_wptr, ESPState),
-        VMSTATE_BUFFER(ti_buf, ESPState),
+        VMSTATE_UINT32_TEST(mig_ti_rptr, ESPState, esp_is_before_version_5),
+        VMSTATE_UINT32_TEST(mig_ti_wptr, ESPState, esp_is_before_version_5),
+        VMSTATE_BUFFER_TEST(mig_ti_buf, ESPState, esp_is_before_version_5),
         VMSTATE_UINT32(status, ESPState),
         VMSTATE_UINT32_TEST(mig_deferred_status, ESPState,
                             esp_is_before_version_5),
@@ -995,6 +1011,7 @@ const VMStateDescription vmstate_esp = {
         VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
         VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
         VMSTATE_UINT8_TEST(cmdbuf_cdb_offset, ESPState, esp_is_version_5),
+        VMSTATE_FIFO8_TEST(fifo, ESPState, esp_is_version_5),
         VMSTATE_END_OF_LIST()
     },
 };
@@ -1047,7 +1064,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
         break;
     }
     dmalen = esp_get_tc(s);
-    if (dmalen == 0 || (s->ti_wptr == TI_BUFSZ)) {
+    if (dmalen == 0 || fifo8_is_full(&s->fifo)) {
         s->pdma_cb(s);
     }
 }
@@ -1070,9 +1087,7 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
         val = (val << 8) | esp_pdma_read(s);
         break;
     }
-    if (s->ti_rptr == s->ti_wptr) {
-        s->ti_wptr = 0;
-        s->ti_rptr = 0;
+    if (fifo8_is_empty(&s->fifo)) {
         s->pdma_cb(s);
     }
     return val;
@@ -1182,6 +1197,20 @@ static const TypeInfo sysbus_esp_info = {
     .class_init    = sysbus_esp_class_init,
 };
 
+static void esp_finalize(Object *obj)
+{
+    ESPState *s = ESP(obj);
+
+    fifo8_destroy(&s->fifo);
+}
+
+static void esp_init(Object *obj)
+{
+    ESPState *s = ESP(obj);
+
+    fifo8_create(&s->fifo, ESP_FIFO_SZ);
+}
+
 static void esp_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1194,6 +1223,8 @@ static void esp_class_init(ObjectClass *klass, void *data)
 static const TypeInfo esp_info = {
     .name = TYPE_ESP,
     .parent = TYPE_DEVICE,
+    .instance_init = esp_init,
+    .instance_finalize = esp_finalize,
     .instance_size = sizeof(ESPState),
     .class_init = esp_class_init,
 };
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 6f3bf4a0ce..063d9b1caa 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -3,6 +3,7 @@
 
 #include "hw/scsi/scsi.h"
 #include "hw/sysbus.h"
+#include "qemu/fifo8.h"
 #include "qom/object.h"
 
 /* esp.c */
@@ -10,7 +11,7 @@
 typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
 
 #define ESP_REGS 16
-#define TI_BUFSZ 16
+#define ESP_FIFO_SZ 16
 #define ESP_CMDBUF_SZ 32
 
 typedef struct ESPState ESPState;
@@ -28,10 +29,9 @@ struct ESPState {
     uint8_t chip_id;
     bool tchi_written;
     int32_t ti_size;
-    uint32_t ti_rptr, ti_wptr;
     uint32_t status;
     uint32_t dma;
-    uint8_t ti_buf[TI_BUFSZ];
+    Fifo8 fifo;
     SCSIBus bus;
     SCSIDevice *current_dev;
     SCSIRequest *current_req;
@@ -58,6 +58,8 @@ struct ESPState {
     uint32_t mig_dma_left;
     uint32_t mig_deferred_status;
     bool mig_deferred_complete;
+    uint32_t mig_ti_rptr, mig_ti_wptr;
+    uint8_t mig_ti_buf[ESP_FIFO_SZ];
 };
 
 #define TYPE_SYSBUS_ESP "sysbus-esp"
-- 
2.20.1



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

* [PATCH v2 39/42] esp: convert cmdbuf from array to Fifo8
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (37 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 38/42] esp: convert ti_buf from array to Fifo8 Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-03 20:16   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 40/42] esp: add trivial implementation of the ESP_RFLAGS register Mark Cave-Ayland
                   ` (3 subsequent siblings)
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

Rename ESP_CMDBUF_SZ to ESP_CMDFIFO_SZ and cmdbuf_cdb_offset to cmdfifo_cdb_offset
to indicate that the command buffer type has changed from an array to a Fifo8.

This also enables us to remove the ESPState field cmdlen since the command length
is now simply the number of elements used in cmdfifo.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 151 +++++++++++++++++++++++++++---------------
 include/hw/scsi/esp.h |   9 +--
 2 files changed, 101 insertions(+), 59 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 98df357276..9dd9947307 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -117,6 +117,25 @@ static uint8_t esp_fifo_pop(ESPState *s)
     return fifo8_pop(&s->fifo);
 }
 
+static void esp_cmdfifo_push(ESPState *s, uint8_t val)
+{
+    if (fifo8_num_used(&s->cmdfifo) == ESP_CMDFIFO_SZ) {
+        trace_esp_error_fifo_overrun();
+        return;
+    }
+
+    fifo8_push(&s->cmdfifo, val);
+}
+
+static uint8_t esp_cmdfifo_pop(ESPState *s)
+{
+    if (fifo8_is_empty(&s->cmdfifo)) {
+        return 0;
+    }
+
+    return fifo8_pop(&s->cmdfifo);
+}
+
 static uint32_t esp_get_tc(ESPState *s)
 {
     uint32_t dmalen;
@@ -151,7 +170,7 @@ static uint8_t esp_pdma_read(ESPState *s)
     uint8_t val;
 
     if (s->do_cmd) {
-        val = s->cmdbuf[s->cmdlen++];
+        val = esp_cmdfifo_pop(s);
     } else {
         val = esp_fifo_pop(s);
     }
@@ -168,7 +187,7 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
     }
 
     if (s->do_cmd) {
-        s->cmdbuf[s->cmdlen++] = val;
+        esp_cmdfifo_push(s, val);
     } else {
         esp_fifo_push(s, val);
     }
@@ -214,7 +233,7 @@ static int esp_select(ESPState *s)
 
 static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
 {
-    uint8_t *buf = s->cmdbuf;
+    uint8_t buf[ESP_CMDFIFO_SZ];
     uint32_t dmalen, n;
     int target;
 
@@ -226,15 +245,18 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
         }
         if (s->dma_memory_read) {
             s->dma_memory_read(s->dma_opaque, buf, dmalen);
+            fifo8_push_all(&s->cmdfifo, buf, dmalen);
         } else {
             if (esp_select(s) < 0) {
+                fifo8_reset(&s->cmdfifo);
                 return -1;
             }
             esp_raise_drq(s);
+            fifo8_reset(&s->cmdfifo);
             return 0;
         }
     } else {
-        dmalen = MIN(s->ti_size, maxlen);
+        dmalen = MIN(fifo8_num_used(&s->fifo), maxlen);
         if (dmalen == 0) {
             return 0;
         }
@@ -242,27 +264,35 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
         if (dmalen >= 3) {
             buf[0] = buf[2] >> 5;
         }
+        fifo8_push_all(&s->cmdfifo, buf, dmalen);
     }
     trace_esp_get_cmd(dmalen, target);
 
     if (esp_select(s) < 0) {
+        fifo8_reset(&s->cmdfifo);
         return -1;
     }
     return dmalen;
 }
 
-static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
+static void do_busid_cmd(ESPState *s, uint8_t busid)
 {
+    uint32_t n, cmdlen;
     int32_t datalen;
     int lun;
     SCSIDevice *current_lun;
+    uint8_t *buf;
 
     trace_esp_do_busid_cmd(busid);
     lun = busid & 7;
+    cmdlen = fifo8_num_used(&s->cmdfifo);
+    buf = (uint8_t *)fifo8_pop_buf(&s->cmdfifo, cmdlen, &n);
+
     current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
     s->current_req = scsi_req_new(current_lun, 0, lun, buf, s);
     datalen = scsi_req_enqueue(s->current_req);
     s->ti_size = datalen;
+    fifo8_reset(&s->cmdfifo);
     if (datalen != 0) {
         s->rregs[ESP_RSTAT] = STAT_TC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
@@ -287,18 +317,25 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
 
 static void do_cmd(ESPState *s)
 {
-    uint8_t *buf = s->cmdbuf;
-    uint8_t busid = buf[0];
+    uint8_t busid = fifo8_pop(&s->cmdfifo);
+    uint32_t n;
+
+    s->cmdfifo_cdb_offset--;
 
     /* Ignore extended messages for now */
-    do_busid_cmd(s, &buf[s->cmdbuf_cdb_offset], busid);
+    if (s->cmdfifo_cdb_offset) {
+        fifo8_pop_buf(&s->cmdfifo, s->cmdfifo_cdb_offset, &n);
+        s->cmdfifo_cdb_offset = 0;
+    }
+
+    do_busid_cmd(s, busid);
 }
 
 static void satn_pdma_cb(ESPState *s)
 {
     s->do_cmd = 0;
-    if (s->cmdlen) {
-        s->cmdbuf_cdb_offset = 1;
+    if (!fifo8_is_empty(&s->cmdfifo)) {
+        s->cmdfifo_cdb_offset = 1;
         do_cmd(s);
     }
 }
@@ -312,13 +349,11 @@ static void handle_satn(ESPState *s)
         return;
     }
     s->pdma_cb = satn_pdma_cb;
-    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
+    cmdlen = get_cmd(s, ESP_CMDFIFO_SZ);
     if (cmdlen > 0) {
-        s->cmdlen = cmdlen;
-        s->cmdbuf_cdb_offset = 1;
+        s->cmdfifo_cdb_offset = 1;
         do_cmd(s);
     } 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;
@@ -328,10 +363,13 @@ static void handle_satn(ESPState *s)
 
 static void s_without_satn_pdma_cb(ESPState *s)
 {
+    uint32_t len;
+
     s->do_cmd = 0;
-    if (s->cmdlen) {
-        s->cmdbuf_cdb_offset = 0;
-        do_busid_cmd(s, s->cmdbuf, 0);
+    len = fifo8_num_used(&s->cmdfifo);
+    if (len) {
+        s->cmdfifo_cdb_offset = 0;
+        do_busid_cmd(s, 0);
     }
 }
 
@@ -344,13 +382,11 @@ static void handle_s_without_atn(ESPState *s)
         return;
     }
     s->pdma_cb = s_without_satn_pdma_cb;
-    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
+    cmdlen = get_cmd(s, ESP_CMDFIFO_SZ);
     if (cmdlen > 0) {
-        s->cmdlen = cmdlen;
-        s->cmdbuf_cdb_offset = 0;
-        do_busid_cmd(s, s->cmdbuf, 0);
+        s->cmdfifo_cdb_offset = 0;
+        do_busid_cmd(s, 0);
     } 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;
@@ -361,10 +397,10 @@ static void handle_s_without_atn(ESPState *s)
 static void satn_stop_pdma_cb(ESPState *s)
 {
     s->do_cmd = 0;
-    if (s->cmdlen) {
-        trace_esp_handle_satn_stop(s->cmdlen);
+    if (!fifo8_is_empty(&s->cmdfifo)) {
+        trace_esp_handle_satn_stop(fifo8_num_used(&s->cmdfifo));
         s->do_cmd = 1;
-        s->cmdbuf_cdb_offset = 1;
+        s->cmdfifo_cdb_offset = 1;
         s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
         s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
@@ -383,16 +419,14 @@ static void handle_satn_stop(ESPState *s)
     s->pdma_cb = satn_stop_pdma_cb;
     cmdlen = get_cmd(s, 1);
     if (cmdlen > 0) {
-        trace_esp_handle_satn_stop(cmdlen);
-        s->cmdlen = cmdlen;
+        trace_esp_handle_satn_stop(fifo8_num_used(&s->cmdfifo));
         s->do_cmd = 1;
-        s->cmdbuf_cdb_offset = 1;
+        s->cmdfifo_cdb_offset = 1;
         s->rregs[ESP_RSTAT] = STAT_MO;
         s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
         s->rregs[ESP_RSEQ] = SEQ_MO;
         esp_raise_irq(s);
     } else if (cmdlen == 0) {
-        s->cmdlen = 0;
         s->do_cmd = 1;
         /* Target present, switch to message out phase */
         s->rregs[ESP_RSEQ] = SEQ_MO;
@@ -455,7 +489,6 @@ static void do_dma_pdma_cb(ESPState *s)
 
     if (s->do_cmd) {
         s->ti_size = 0;
-        s->cmdlen = 0;
         s->do_cmd = 0;
         do_cmd(s);
         esp_lower_drq(s);
@@ -515,8 +548,9 @@ static void do_dma_pdma_cb(ESPState *s)
 
 static void esp_do_dma(ESPState *s)
 {
-    uint32_t len;
+    uint32_t len, cmdlen;
     int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
+    uint8_t buf[ESP_CMDFIFO_SZ];
 
     len = esp_get_tc(s);
     if (s->do_cmd) {
@@ -524,34 +558,33 @@ static void esp_do_dma(ESPState *s)
          * handle_ti_cmd() case: esp_do_dma() is called only from
          * handle_ti_cmd() with do_cmd != NULL (see the assert())
          */
-        trace_esp_do_dma(s->cmdlen, len);
-        assert(s->cmdlen <= sizeof(s->cmdbuf) &&
-               len <= sizeof(s->cmdbuf) - s->cmdlen);
+        cmdlen = fifo8_num_used(&s->cmdfifo);
+        trace_esp_do_dma(cmdlen, len);
         if (s->dma_memory_read) {
-            s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
+            s->dma_memory_read(s->dma_opaque, buf, len);
+            fifo8_push_all(&s->cmdfifo, buf, len);
         } else {
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
             return;
         }
-        trace_esp_handle_ti_cmd(s->cmdlen);
+        trace_esp_handle_ti_cmd(cmdlen);
         s->ti_size = 0;
         if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
             /* No command received */
-            if (s->cmdbuf_cdb_offset == s->cmdlen) {
+            if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
                 return;
             }
 
             /* Command has been received */
-            s->cmdlen = 0;
             s->do_cmd = 0;
             do_cmd(s);
         } else {
             /*
-             * Extra message out bytes received: update cmdbuf_cdb_offset
+             * Extra message out bytes received: update cmdfifo_cdb_offset
              * and then switch to commmand phase
              */
-            s->cmdbuf_cdb_offset = s->cmdlen;
+            s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
             s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
             s->rregs[ESP_RSEQ] = SEQ_CD;
             s->rregs[ESP_RINTR] |= INTR_BS;
@@ -689,7 +722,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
 
 static void handle_ti(ESPState *s)
 {
-    uint32_t dmalen;
+    uint32_t dmalen, cmdlen;
 
     if (s->dma && !s->dma_enabled) {
         s->dma_cb = handle_ti;
@@ -702,24 +735,24 @@ static void handle_ti(ESPState *s)
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
         esp_do_dma(s);
     } else if (s->do_cmd) {
-        trace_esp_handle_ti_cmd(s->cmdlen);
+        cmdlen = fifo8_num_used(&s->cmdfifo);
+        trace_esp_handle_ti_cmd(cmdlen);
         s->ti_size = 0;
         if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
             /* No command received */
-            if (s->cmdbuf_cdb_offset == s->cmdlen) {
+            if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
                 return;
             }
 
             /* Command has been received */
-            s->cmdlen = 0;
             s->do_cmd = 0;
             do_cmd(s);
         } else {
             /*
-             * Extra message out bytes received: update cmdbuf_cdb_offset
+             * Extra message out bytes received: update cmdfifo_cdb_offset
              * and then switch to commmand phase
              */
-            s->cmdbuf_cdb_offset = s->cmdlen;
+            s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
             s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
             s->rregs[ESP_RSEQ] = SEQ_CD;
             s->rregs[ESP_RINTR] |= INTR_BS;
@@ -735,6 +768,7 @@ void esp_hard_reset(ESPState *s)
     s->tchi_written = 0;
     s->ti_size = 0;
     fifo8_reset(&s->fifo);
+    fifo8_reset(&s->cmdfifo);
     s->dma = 0;
     s->do_cmd = 0;
     s->dma_cb = NULL;
@@ -813,11 +847,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
         break;
     case ESP_FIFO:
         if (s->do_cmd) {
-            if (s->cmdlen < ESP_CMDBUF_SZ) {
-                s->cmdbuf[s->cmdlen++] = val & 0xff;
-            } else {
-                trace_esp_error_fifo_overrun();
-            }
+            esp_cmdfifo_push(s, val & 0xff);
         } else {
             s->ti_size++;
             esp_fifo_push(s, val & 0xff);
@@ -979,6 +1009,11 @@ static int esp_post_load(void *opaque, int version_id)
         for (i = 0; i < len; i++) {
             fifo8_push(&s->fifo, s->mig_ti_buf[i]);
         }
+
+        /* Migrate cmdbuf to cmdfifo */
+        for (i = 0; i < s->mig_cmdlen; i++) {
+            fifo8_push(&s->cmdfifo, s->mig_cmdbuf[i]);
+        }
     }
 
     s->mig_version_id = vmstate_esp.version_id;
@@ -1004,14 +1039,18 @@ const VMStateDescription vmstate_esp = {
         VMSTATE_BOOL_TEST(mig_deferred_complete, ESPState,
                           esp_is_before_version_5),
         VMSTATE_UINT32(dma, ESPState),
-        VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16),
-        VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
-        VMSTATE_UINT32(cmdlen, ESPState),
+        VMSTATE_STATIC_BUFFER(mig_cmdbuf, ESPState, 0,
+                              esp_is_before_version_5, 0, 16),
+        VMSTATE_STATIC_BUFFER(mig_cmdbuf, ESPState, 4,
+                              esp_is_before_version_5, 16,
+                              sizeof(typeof_field(ESPState, mig_cmdbuf))),
+        VMSTATE_UINT32_TEST(mig_cmdlen, ESPState, esp_is_before_version_5),
         VMSTATE_UINT32(do_cmd, ESPState),
         VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
         VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
-        VMSTATE_UINT8_TEST(cmdbuf_cdb_offset, ESPState, esp_is_version_5),
+        VMSTATE_UINT8_TEST(cmdfifo_cdb_offset, ESPState, esp_is_version_5),
         VMSTATE_FIFO8_TEST(fifo, ESPState, esp_is_version_5),
+        VMSTATE_FIFO8_TEST(cmdfifo, ESPState, esp_is_version_5),
         VMSTATE_END_OF_LIST()
     },
 };
@@ -1202,6 +1241,7 @@ static void esp_finalize(Object *obj)
     ESPState *s = ESP(obj);
 
     fifo8_destroy(&s->fifo);
+    fifo8_destroy(&s->cmdfifo);
 }
 
 static void esp_init(Object *obj)
@@ -1209,6 +1249,7 @@ static void esp_init(Object *obj)
     ESPState *s = ESP(obj);
 
     fifo8_create(&s->fifo, ESP_FIFO_SZ);
+    fifo8_create(&s->cmdfifo, ESP_CMDFIFO_SZ);
 }
 
 static void esp_class_init(ObjectClass *klass, void *data)
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 063d9b1caa..9da2905f14 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -12,7 +12,7 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
 
 #define ESP_REGS 16
 #define ESP_FIFO_SZ 16
-#define ESP_CMDBUF_SZ 32
+#define ESP_CMDFIFO_SZ 32
 
 typedef struct ESPState ESPState;
 
@@ -35,9 +35,8 @@ struct ESPState {
     SCSIBus bus;
     SCSIDevice *current_dev;
     SCSIRequest *current_req;
-    uint8_t cmdbuf[ESP_CMDBUF_SZ];
-    uint32_t cmdlen;
-    uint8_t cmdbuf_cdb_offset;
+    Fifo8 cmdfifo;
+    uint8_t cmdfifo_cdb_offset;
     uint32_t do_cmd;
 
     bool data_in_ready;
@@ -60,6 +59,8 @@ struct ESPState {
     bool mig_deferred_complete;
     uint32_t mig_ti_rptr, mig_ti_wptr;
     uint8_t mig_ti_buf[ESP_FIFO_SZ];
+    uint8_t mig_cmdbuf[ESP_CMDFIFO_SZ];
+    uint32_t mig_cmdlen;
 };
 
 #define TYPE_SYSBUS_ESP "sysbus-esp"
-- 
2.20.1



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

* [PATCH v2 40/42] esp: add trivial implementation of the ESP_RFLAGS register
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (38 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 39/42] esp: convert cmdbuf " Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-02-23 18:51   ` Philippe Mathieu-Daudé
  2021-03-03 20:19   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 41/42] esp: implement non-DMA transfers in PDMA mode Mark Cave-Ayland
                   ` (2 subsequent siblings)
  42 siblings, 2 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The bottom 5 bits contain the number of bytes remaining in the FIFO which is
trivial to implement with Fifo8 (the remaining bits are unimplemented and left
as 0 for now).

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 9dd9947307..1f01f2314b 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -825,6 +825,10 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
             val = s->rregs[saddr];
         }
         break;
+     case ESP_RFLAGS:
+        /* Bottom 5 bits indicate number of bytes in FIFO */
+        val = fifo8_num_used(&s->fifo);
+        break;
     default:
         val = s->rregs[saddr];
         break;
-- 
2.20.1



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

* [PATCH v2 41/42] esp: implement non-DMA transfers in PDMA mode
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (39 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 40/42] esp: add trivial implementation of the ESP_RFLAGS register Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-03 20:22   ` Laurent Vivier
  2021-02-09 19:30 ` [PATCH v2 42/42] esp: add support for unaligned accesses Mark Cave-Ayland
  2021-02-23 21:32 ` [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Philippe Mathieu-Daudé
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

The MacOS toolbox ROM uses non-DMA TI commands to handle the first/last byte
of an unaligned 16-bit transfer to memory.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/scsi/esp.c         | 133 ++++++++++++++++++++++++++++++------------
 include/hw/scsi/esp.h |   1 +
 2 files changed, 98 insertions(+), 36 deletions(-)

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 1f01f2314b..ae9e265a5d 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -296,6 +296,7 @@ static void do_busid_cmd(ESPState *s, uint8_t busid)
     if (datalen != 0) {
         s->rregs[ESP_RSTAT] = STAT_TC;
         s->rregs[ESP_RSEQ] = SEQ_CD;
+        s->ti_cmd = 0;
         esp_set_tc(s, 0);
         if (datalen > 0) {
             /*
@@ -651,6 +652,71 @@ static void esp_do_dma(ESPState *s)
     esp_lower_drq(s);
 }
 
+static void esp_do_nodma(ESPState *s)
+{
+    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
+    uint32_t cmdlen, n;
+    int len;
+
+    if (s->do_cmd) {
+        cmdlen = fifo8_num_used(&s->cmdfifo);
+        trace_esp_handle_ti_cmd(cmdlen);
+        s->ti_size = 0;
+        if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
+            /* No command received */
+            if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
+                return;
+            }
+
+            /* Command has been received */
+            s->do_cmd = 0;
+            do_cmd(s);
+        } else {
+            /*
+             * Extra message out bytes received: update cmdfifo_cdb_offset
+             * and then switch to commmand phase
+             */
+            s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
+            s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
+            s->rregs[ESP_RSEQ] = SEQ_CD;
+            s->rregs[ESP_RINTR] |= INTR_BS;
+            esp_raise_irq(s);
+        }
+        return;
+    }
+
+    if (s->async_len == 0) {
+        /* Defer until data is available.  */
+        return;
+    }
+
+    if (to_device) {
+        len = MIN(fifo8_num_used(&s->fifo), ESP_FIFO_SZ);
+        memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
+        s->async_buf += len;
+        s->async_len -= len;
+        s->ti_size += len;
+    } else {
+        len = MIN(s->ti_size, s->async_len);
+        len = MIN(len, fifo8_num_free(&s->fifo));
+        fifo8_push_all(&s->fifo, s->async_buf, len);
+        s->async_buf += len;
+        s->async_len -= len;
+        s->ti_size -= len;
+    }
+
+    if (s->async_len == 0) {
+        scsi_req_continue(s->current_req);
+
+        if (to_device || s->ti_size == 0) {
+            return;
+        }
+    }
+
+    s->rregs[ESP_RINTR] |= INTR_BS;
+    esp_raise_irq(s);
+}
+
 void esp_command_complete(SCSIRequest *req, uint32_t status,
                           size_t resid)
 {
@@ -708,56 +774,51 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
         return;
     }
 
-    if (dmalen) {
-        esp_do_dma(s);
-    } else if (s->ti_size <= 0) {
+    if (s->ti_cmd == 0) {
         /*
-         * If this was the last part of a DMA transfer then the
-         * completion interrupt is deferred to here.
+         * Always perform the initial transfer upon reception of the next TI
+         * command to ensure the DMA/non-DMA status of the command is correct.
+         * It is not possible to use s->dma directly in the section below as
+         * some OSs send non-DMA NOP commands after a DMA transfer. Hence if the
+         * async data transfer is delayed then s->dma is set incorrectly.
          */
-        esp_dma_done(s);
-        esp_lower_drq(s);
+        return;
+    }
+
+    if (s->ti_cmd & CMD_DMA) {
+        if (dmalen) {
+            esp_do_dma(s);
+        } else if (s->ti_size <= 0) {
+            /*
+             * If this was the last part of a DMA transfer then the
+             * completion interrupt is deferred to here.
+             */
+            esp_dma_done(s);
+            esp_lower_drq(s);
+        }
+    } else {
+        esp_do_nodma(s);
     }
 }
 
 static void handle_ti(ESPState *s)
 {
-    uint32_t dmalen, cmdlen;
+    uint32_t dmalen;
 
     if (s->dma && !s->dma_enabled) {
         s->dma_cb = handle_ti;
         return;
     }
 
-    dmalen = esp_get_tc(s);
+    s->ti_cmd = s->rregs[ESP_CMD];
     if (s->dma) {
+        dmalen = esp_get_tc(s);
         trace_esp_handle_ti(dmalen);
         s->rregs[ESP_RSTAT] &= ~STAT_TC;
         esp_do_dma(s);
-    } else if (s->do_cmd) {
-        cmdlen = fifo8_num_used(&s->cmdfifo);
-        trace_esp_handle_ti_cmd(cmdlen);
-        s->ti_size = 0;
-        if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
-            /* No command received */
-            if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
-                return;
-            }
-
-            /* Command has been received */
-            s->do_cmd = 0;
-            do_cmd(s);
-        } else {
-            /*
-             * Extra message out bytes received: update cmdfifo_cdb_offset
-             * and then switch to commmand phase
-             */
-            s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
-            s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
-            s->rregs[ESP_RSEQ] = SEQ_CD;
-            s->rregs[ESP_RINTR] |= INTR_BS;
-            esp_raise_irq(s);
-        }
+    } else {
+        trace_esp_handle_ti(s->ti_size);
+        esp_do_nodma(s);
     }
 }
 
@@ -796,12 +857,12 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
 
     switch (saddr) {
     case ESP_FIFO:
-        if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
+        if (s->dma_memory_read && s->dma_memory_write &&
+                (s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
             /* Data out.  */
             qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
             s->rregs[ESP_FIFO] = 0;
         } else {
-            s->ti_size--;
             s->rregs[ESP_FIFO] = esp_fifo_pop(s);
         }
         val = s->rregs[ESP_FIFO];
@@ -853,7 +914,6 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
         if (s->do_cmd) {
             esp_cmdfifo_push(s, val & 0xff);
         } else {
-            s->ti_size++;
             esp_fifo_push(s, val & 0xff);
         }
 
@@ -1055,6 +1115,7 @@ const VMStateDescription vmstate_esp = {
         VMSTATE_UINT8_TEST(cmdfifo_cdb_offset, ESPState, esp_is_version_5),
         VMSTATE_FIFO8_TEST(fifo, ESPState, esp_is_version_5),
         VMSTATE_FIFO8_TEST(cmdfifo, ESPState, esp_is_version_5),
+        VMSTATE_UINT8_TEST(ti_cmd, ESPState, esp_is_version_5),
         VMSTATE_END_OF_LIST()
     },
 };
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
index 9da2905f14..a387eb5292 100644
--- a/include/hw/scsi/esp.h
+++ b/include/hw/scsi/esp.h
@@ -40,6 +40,7 @@ struct ESPState {
     uint32_t do_cmd;
 
     bool data_in_ready;
+    uint8_t ti_cmd;
     int dma_enabled;
 
     uint32_t async_len;
-- 
2.20.1



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

* [PATCH v2 42/42] esp: add support for unaligned accesses
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (40 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 41/42] esp: implement non-DMA transfers in PDMA mode Mark Cave-Ayland
@ 2021-02-09 19:30 ` Mark Cave-Ayland
  2021-03-03 20:22   ` Laurent Vivier
  2021-02-23 21:32 ` [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Philippe Mathieu-Daudé
  42 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-09 19:30 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

When the MacOS toolbox ROM transfers data from a target device to an unaligned
memory address, the first/last byte of a 16-bit transfer needs to be handled
separately. This means that the first byte is preloaded into the FIFO before
the transfer, or the last byte remains in the FIFO after the transfer.

The result of this is that the PDMA routines must be updated so that the FIFO
is loaded/unloaded if the last 16-bit word is used (rather than the last byte)
and any remaining byte from a FIFO wraparound is handled correctly.

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

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index ae9e265a5d..d2d6366525 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -498,11 +498,22 @@ static void do_dma_pdma_cb(ESPState *s)
 
     if (to_device) {
         /* Copy FIFO data to device */
-        len = MIN(fifo8_num_used(&s->fifo), ESP_FIFO_SZ);
+        len = MIN(s->async_len, ESP_FIFO_SZ);
+        len = MIN(len, fifo8_num_used(&s->fifo));
         memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
-        s->async_buf += len;
-        s->async_len -= len;
-        s->ti_size += len;
+        s->async_buf += n;
+        s->async_len -= n;
+        s->ti_size += n;
+
+        if (n < len) {
+            /* Unaligned accesses can cause FIFO wraparound */
+            len = len - n;
+            memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
+            s->async_buf += n;
+            s->async_len -= n;
+            s->ti_size += n;
+        }
+
         if (s->async_len == 0) {
             scsi_req_continue(s->current_req);
             return;
@@ -532,12 +543,18 @@ static void do_dma_pdma_cb(ESPState *s)
 
         if (esp_get_tc(s) != 0) {
             /* Copy device data to FIFO */
-            len = MIN(s->async_len, fifo8_num_free(&s->fifo));
+            len = MIN(s->async_len, esp_get_tc(s));
+            len = MIN(len, fifo8_num_free(&s->fifo));
             fifo8_push_all(&s->fifo, s->async_buf, len);
             s->async_buf += len;
             s->async_len -= len;
             s->ti_size -= len;
             esp_set_tc(s, esp_get_tc(s) - len);
+
+            if (esp_get_tc(s) == 0) {
+                /* Indicate transfer to FIFO is complete */
+                 s->rregs[ESP_RSTAT] |= STAT_TC;
+            }
             return;
         }
 
@@ -612,12 +629,29 @@ static void esp_do_dma(ESPState *s)
         if (s->dma_memory_write) {
             s->dma_memory_write(s->dma_opaque, s->async_buf, len);
         } else {
+            /* Adjust TC for any leftover data in the FIFO */
+            if (!fifo8_is_empty(&s->fifo)) {
+                esp_set_tc(s, esp_get_tc(s) - fifo8_num_used(&s->fifo));
+            }
+
             /* Copy device data to FIFO */
             len = MIN(len, fifo8_num_free(&s->fifo));
             fifo8_push_all(&s->fifo, s->async_buf, len);
             s->async_buf += len;
             s->async_len -= len;
             s->ti_size -= len;
+
+            /*
+             * MacOS toolbox uses a TI length of 16 bytes for all commands, so
+             * commands shorter than this must be padded accordingly
+             */
+            if (len < esp_get_tc(s) && esp_get_tc(s) <= ESP_FIFO_SZ) {
+                while (fifo8_num_used(&s->fifo) < ESP_FIFO_SZ) {
+                    esp_fifo_push(s, 0);
+                    len++;
+                }
+            }
+
             esp_set_tc(s, esp_get_tc(s) - len);
             s->pdma_cb = do_dma_pdma_cb;
             esp_raise_drq(s);
@@ -1168,7 +1202,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
         break;
     }
     dmalen = esp_get_tc(s);
-    if (dmalen == 0 || fifo8_is_full(&s->fifo)) {
+    if (dmalen == 0 || fifo8_num_free(&s->fifo) < 2) {
         s->pdma_cb(s);
     }
 }
@@ -1191,7 +1225,7 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
         val = (val << 8) | esp_pdma_read(s);
         break;
     }
-    if (fifo8_is_empty(&s->fifo)) {
+    if (fifo8_num_used(&s->fifo) < 2) {
         s->pdma_cb(s);
     }
     return val;
-- 
2.20.1



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

* Re: [PATCH v2 02/42] esp: rename existing ESP QOM type to SYSBUS_ESP
  2021-02-09 19:29 ` [PATCH v2 02/42] esp: rename existing ESP QOM type to SYSBUS_ESP Mark Cave-Ayland
@ 2021-02-10 22:29   ` Philippe Mathieu-Daudé
  2021-03-01 19:52   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-10 22:29 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> The existing ESP QOM type currently represents a sysbus device with an embedded
> ESP state. Rename the type to SYSBUS_ESP accordingly.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/dma/sparc32_dma.c  | 4 ++--
>  hw/m68k/q800.c        | 4 ++--
>  hw/mips/jazz.c        | 4 ++--
>  hw/scsi/esp.c         | 8 ++++----
>  hw/sparc/sun4m.c      | 2 +-
>  include/hw/scsi/esp.h | 4 ++--
>  6 files changed, 13 insertions(+), 13 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 10/42] esp: introduce esp_get_stc()
  2021-02-09 19:29 ` [PATCH v2 10/42] esp: introduce esp_get_stc() Mark Cave-Ayland
@ 2021-02-10 22:33   ` Philippe Mathieu-Daudé
  2021-02-11  7:53     ` Mark Cave-Ayland
  2021-03-01 21:28   ` Laurent Vivier
  1 sibling, 1 reply; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-10 22:33 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> This simplifies reading the STC register value without having to manually shift
> each individual 8-bit value.

If possible repeat the subject so the sentence is easier to understand.

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

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 12/42] esp: remove dma_counter from ESPState
  2021-02-09 19:29 ` [PATCH v2 12/42] esp: remove dma_counter from ESPState Mark Cave-Ayland
@ 2021-02-10 22:37   ` Philippe Mathieu-Daudé
  2021-03-01 21:44   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-10 22:37 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> The value of dma_counter is set once at the start of the transfer and remains
> the same until the transfer is complete. This allows the check in esp_transfer_data
> to be simplified since dma_left will always be non-zero until the transfer is
> completed.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 4 +---
>  include/hw/scsi/esp.h | 3 ---
>  2 files changed, 1 insertion(+), 6 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions
  2021-02-09 19:29 ` [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions Mark Cave-Ayland
@ 2021-02-10 22:51   ` Philippe Mathieu-Daudé
  2021-02-11  8:01     ` Mark Cave-Ayland
  2021-03-01 22:06   ` Laurent Vivier
  1 sibling, 1 reply; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-10 22:51 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

Hi Mark,

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 28 ++++++++++++++++++++--------
>  1 file changed, 20 insertions(+), 8 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index e7cf36f4b8..b0cba889a9 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -151,6 +151,20 @@ static uint8_t *get_pdma_buf(ESPState *s)
>      return NULL;
>  }
>  

Can you add get_pdma_len() (similar to get_pdma_buf) and ...

> +static uint8_t esp_pdma_read(ESPState *s)
> +{
> +    uint8_t *buf = get_pdma_buf(s);
> +

       assert(s->pdma_cur < get_pdma_len(s));

> +    return buf[s->pdma_cur++];
> +}
> +
> +static void esp_pdma_write(ESPState *s, uint8_t val)
> +{
> +    uint8_t *buf = get_pdma_buf(s);
> +

Ditto.

> +    buf[s->pdma_cur++] = val;
> +}

Otherwise:

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 10/42] esp: introduce esp_get_stc()
  2021-02-10 22:33   ` Philippe Mathieu-Daudé
@ 2021-02-11  7:53     ` Mark Cave-Ayland
  2021-02-11 10:07       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-11  7:53 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam, laurent

On 10/02/2021 22:33, Philippe Mathieu-Daudé wrote:

> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>> This simplifies reading the STC register value without having to manually shift
>> each individual 8-bit value.
> 
> If possible repeat the subject so the sentence is easier to understand.

I've always read commit messages as summary followed detail, so I've tended to avoid 
repetition if the context is obvious from the summary (a quick glance through my 
inbox suggest that quite a few authors also do the same).

Perhaps adding in the word "function" would help readability here, e.g. "This 
function simplifies reading the STC register value..."?

>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp.c | 15 ++++++++++++---
>>   1 file changed, 12 insertions(+), 3 deletions(-)
> 
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


ATB,

Mark.


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

* Re: [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions
  2021-02-10 22:51   ` Philippe Mathieu-Daudé
@ 2021-02-11  8:01     ` Mark Cave-Ayland
  2021-02-11 10:09       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-11  8:01 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam, laurent

On 10/02/2021 22:51, Philippe Mathieu-Daudé wrote:

> Hi Mark,
> 
> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp.c | 28 ++++++++++++++++++++--------
>>   1 file changed, 20 insertions(+), 8 deletions(-)
>>
>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>> index e7cf36f4b8..b0cba889a9 100644
>> --- a/hw/scsi/esp.c
>> +++ b/hw/scsi/esp.c
>> @@ -151,6 +151,20 @@ static uint8_t *get_pdma_buf(ESPState *s)
>>       return NULL;
>>   }
>>   
> 
> Can you add get_pdma_len() (similar to get_pdma_buf) and ...
> 
>> +static uint8_t esp_pdma_read(ESPState *s)
>> +{
>> +    uint8_t *buf = get_pdma_buf(s);
>> +
> 
>         assert(s->pdma_cur < get_pdma_len(s));
> 
>> +    return buf[s->pdma_cur++];
>> +}
>> +
>> +static void esp_pdma_write(ESPState *s, uint8_t val)
>> +{
>> +    uint8_t *buf = get_pdma_buf(s);
>> +
> 
> Ditto.
> 
>> +    buf[s->pdma_cur++] = val;
>> +}
> 
> Otherwise:
> 
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

One of the main purposes of this patchset is actually to completely remove all of 
these pdma_* variables and integrate everything into the existing FIFO and cmd 
buffers, so if you continue reading through the patchset you'll see that this soon 
disappears.

Even better towards the end you can see that both of these buffers are eventually 
replaced with QEMU's Fifo8 which has in-built assert()s to protect from underflow and 
overflow which should protect against memory corruption.


ATB,

Mark.


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

* Re: [PATCH v2 10/42] esp: introduce esp_get_stc()
  2021-02-11  7:53     ` Mark Cave-Ayland
@ 2021-02-11 10:07       ` Philippe Mathieu-Daudé
  2021-02-15 22:27         ` Mark Cave-Ayland
  0 siblings, 1 reply; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-11 10:07 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/11/21 8:53 AM, Mark Cave-Ayland wrote:
> On 10/02/2021 22:33, Philippe Mathieu-Daudé wrote:
> 
>> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>>> This simplifies reading the STC register value without having to
>>> manually shift
>>> each individual 8-bit value.
>>
>> If possible repeat the subject so the sentence is easier to understand.
> 
> I've always read commit messages as summary followed detail, so I've
> tended to avoid repetition if the context is obvious from the summary (a
> quick glance through my inbox suggest that quite a few authors also do
> the same).

Not because other do it means it is a good practice ;)

I suppose it depends on personal review workflow and email client used
or gitk layout. In the one I use the commit description is displayed
first, so I have to look elsewhere to prepend the patch subject which
is using another font.
I'm using Thunderbird on Fedora and X1 carbon but had to do some config
change in the default config because the font was too small, unreadable,
then I added some 1.5x zoom factor. It always looked ugly. Apparently
checking that again it seems the Fedora I used was not supporting these
now displays well but now it should work OK, but I'm still using this
old config. Well, my bad. Not in mood to reinstall. Forget my comment
about having "atomic" commit descriptions then.

> 
> Perhaps adding in the word "function" would help readability here, e.g.
> "This function simplifies reading the STC register value..."?

Sounds better to me :)

> 
>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>> ---
>>>   hw/scsi/esp.c | 15 ++++++++++++---
>>>   1 file changed, 12 insertions(+), 3 deletions(-)
>>
>> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> 
> 
> ATB,
> 
> Mark.
> 


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

* Re: [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions
  2021-02-11  8:01     ` Mark Cave-Ayland
@ 2021-02-11 10:09       ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-11 10:09 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/11/21 9:01 AM, Mark Cave-Ayland wrote:
> On 10/02/2021 22:51, Philippe Mathieu-Daudé wrote:
> 
>> Hi Mark,
>>
>> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>> ---
>>>   hw/scsi/esp.c | 28 ++++++++++++++++++++--------
>>>   1 file changed, 20 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>>> index e7cf36f4b8..b0cba889a9 100644
>>> --- a/hw/scsi/esp.c
>>> +++ b/hw/scsi/esp.c
>>> @@ -151,6 +151,20 @@ static uint8_t *get_pdma_buf(ESPState *s)
>>>       return NULL;
>>>   }
>>>   
>>
>> Can you add get_pdma_len() (similar to get_pdma_buf) and ...
>>
>>> +static uint8_t esp_pdma_read(ESPState *s)
>>> +{
>>> +    uint8_t *buf = get_pdma_buf(s);
>>> +
>>
>>         assert(s->pdma_cur < get_pdma_len(s));
>>
>>> +    return buf[s->pdma_cur++];
>>> +}
>>> +
>>> +static void esp_pdma_write(ESPState *s, uint8_t val)
>>> +{
>>> +    uint8_t *buf = get_pdma_buf(s);
>>> +
>>
>> Ditto.
>>
>>> +    buf[s->pdma_cur++] = val;
>>> +}
>>
>> Otherwise:
>>
>> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> 
> One of the main purposes of this patchset is actually to completely
> remove all of these pdma_* variables and integrate everything into the
> existing FIFO and cmd buffers, so if you continue reading through the
> patchset you'll see that this soon disappears.
> 
> Even better towards the end you can see that both of these buffers are
> eventually replaced with QEMU's Fifo8 which has in-built assert()s to
> protect from underflow and overflow which should protect against memory
> corruption.

OK great! I planed to review half of it (21/42) but was too tired so
stopped at this one :D My bad for missing in the cover:

- Now that the TC register represents the authoritative DMA transfer
  length, patches 14-25 work to eliminate the separate PDMA variables
  pdma_start, pdma_cur, pdma_len and separate PDMA buffers PDMA and CMD.
  The PDMA position variables can be replaced by the existing ESP cmdlen
  and ti_wptr/ti_rptr, whilst the FIFO (TI) buffer is used for incoming
  data with commands being accumulated in cmdbuf as per standard DMA
  requests.

Regards,

Phil.


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

* Re: [PATCH v2 03/42] esp: QOMify the internal ESP device state
  2021-02-09 19:29 ` [PATCH v2 03/42] esp: QOMify the internal ESP device state Mark Cave-Ayland
@ 2021-02-12 18:51   ` Philippe Mathieu-Daudé
  2021-02-15 22:29     ` Mark Cave-Ayland
  0 siblings, 1 reply; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-12 18:51 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> Make this new QOM device state a child device of both the sysbus-esp and esp-pci
> implementations.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp-pci.c     | 48 +++++++++++++++++++++++++++++++------------
>  hw/scsi/esp.c         | 45 +++++++++++++++++++++++++++++++++-------
>  include/hw/scsi/esp.h |  5 +++++
>  3 files changed, 78 insertions(+), 20 deletions(-)

Please setup scripts/git.orderfile ;)

...
> @@ -354,9 +365,11 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
>  {
>      PCIESPState *pci = PCI_ESP(dev);
>      DeviceState *d = DEVICE(dev);
> -    ESPState *s = &pci->esp;
> +    ESPState *s = ESP(&pci->esp);
>      uint8_t *pci_conf;
>  
> +    qdev_realize(DEVICE(s), NULL, errp);

       if (!qdev_realize(DEVICE(s), NULL, errp)) {
           return;
       }

>      pci_conf = dev->config;
>  
>      /* Interrupt pin A */
> @@ -375,11 +388,19 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
>      scsi_bus_new(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info, NULL);
>  }
...

> @@ -956,7 +958,9 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
>  {
>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>      SysBusESPState *sysbus = SYSBUS_ESP(dev);
> -    ESPState *s = &sysbus->esp;
> +    ESPState *s = ESP(&sysbus->esp);
> +
> +    qdev_realize(DEVICE(s), NULL, errp);

       if (!qdev_realize(DEVICE(s), NULL, errp)) {
           return;
       }

With both if():
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers
  2021-02-09 19:30 ` [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers Mark Cave-Ayland
@ 2021-02-12 18:56   ` Philippe Mathieu-Daudé
  2021-02-15 22:35     ` Mark Cave-Ayland
  2021-03-02 22:05   ` Laurent Vivier
  1 sibling, 1 reply; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-12 18:56 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:30 PM, Mark Cave-Ayland wrote:
> The MacOS toolbox ROM performs 4 byte reads/writes when transferring data to
> and from the target. Since the SCSI bus is 16-bits wide, use the memory API
> to split a 4 byte access into 2 x 2 byte accesses.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

Out of curiosity, what is the bus used?


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

* Re: [PATCH v2 10/42] esp: introduce esp_get_stc()
  2021-02-11 10:07       ` Philippe Mathieu-Daudé
@ 2021-02-15 22:27         ` Mark Cave-Ayland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-15 22:27 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam, laurent

On 11/02/2021 10:07, Philippe Mathieu-Daudé wrote:
> On 2/11/21 8:53 AM, Mark Cave-Ayland wrote:
>> On 10/02/2021 22:33, Philippe Mathieu-Daudé wrote:
>>
>>> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>>>> This simplifies reading the STC register value without having to
>>>> manually shift
>>>> each individual 8-bit value.
>>>
>>> If possible repeat the subject so the sentence is easier to understand.
>>
>> I've always read commit messages as summary followed detail, so I've
>> tended to avoid repetition if the context is obvious from the summary (a
>> quick glance through my inbox suggest that quite a few authors also do
>> the same).
> 
> Not because other do it means it is a good practice ;)
> 
> I suppose it depends on personal review workflow and email client used
> or gitk layout. In the one I use the commit description is displayed
> first, so I have to look elsewhere to prepend the patch subject which
> is using another font.
> I'm using Thunderbird on Fedora and X1 carbon but had to do some config
> change in the default config because the font was too small, unreadable,
> then I added some 1.5x zoom factor. It always looked ugly. Apparently
> checking that again it seems the Fedora I used was not supporting these
> now displays well but now it should work OK, but I'm still using this
> old config. Well, my bad. Not in mood to reinstall. Forget my comment
> about having "atomic" commit descriptions then.
> 
>>
>> Perhaps adding in the word "function" would help readability here, e.g.
>> "This function simplifies reading the STC register value..."?
> 
> Sounds better to me :)

Okay - I've made this change, along with a similar change to the patch before which 
had similar wording.

>>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>>> ---
>>>>    hw/scsi/esp.c | 15 ++++++++++++---
>>>>    1 file changed, 12 insertions(+), 3 deletions(-)
>>>
>>> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


ATB,

Mark.


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

* Re: [PATCH v2 03/42] esp: QOMify the internal ESP device state
  2021-02-12 18:51   ` Philippe Mathieu-Daudé
@ 2021-02-15 22:29     ` Mark Cave-Ayland
  2021-03-01 20:11       ` Laurent Vivier
  0 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-15 22:29 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam, laurent

On 12/02/2021 18:51, Philippe Mathieu-Daudé wrote:

> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>> Make this new QOM device state a child device of both the sysbus-esp and esp-pci
>> implementations.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp-pci.c     | 48 +++++++++++++++++++++++++++++++------------
>>   hw/scsi/esp.c         | 45 +++++++++++++++++++++++++++++++++-------
>>   include/hw/scsi/esp.h |  5 +++++
>>   3 files changed, 78 insertions(+), 20 deletions(-)
> 
> Please setup scripts/git.orderfile ;)

I will have to take a look at this at some point - it has been on my TODO list for a 
while :)

>> @@ -354,9 +365,11 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
>>   {
>>       PCIESPState *pci = PCI_ESP(dev);
>>       DeviceState *d = DEVICE(dev);
>> -    ESPState *s = &pci->esp;
>> +    ESPState *s = ESP(&pci->esp);
>>       uint8_t *pci_conf;
>>   
>> +    qdev_realize(DEVICE(s), NULL, errp);
> 
>         if (!qdev_realize(DEVICE(s), NULL, errp)) {
>             return;
>         }
> 
>>       pci_conf = dev->config;
>>   
>>       /* Interrupt pin A */
>> @@ -375,11 +388,19 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
>>       scsi_bus_new(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info, NULL);
>>   }
> ...
> 
>> @@ -956,7 +958,9 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
>>   {
>>       SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>>       SysBusESPState *sysbus = SYSBUS_ESP(dev);
>> -    ESPState *s = &sysbus->esp;
>> +    ESPState *s = ESP(&sysbus->esp);
>> +
>> +    qdev_realize(DEVICE(s), NULL, errp);
> 
>         if (!qdev_realize(DEVICE(s), NULL, errp)) {
>             return;
>         }
> 
> With both if():
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

Great! I've added the if() statements and added your R-B to the patch.


ATB,

Mark.


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

* Re: [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers
  2021-02-12 18:56   ` Philippe Mathieu-Daudé
@ 2021-02-15 22:35     ` Mark Cave-Ayland
  2021-02-16  7:30       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-15 22:35 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam, laurent

On 12/02/2021 18:56, Philippe Mathieu-Daudé wrote:

> On 2/9/21 8:30 PM, Mark Cave-Ayland wrote:
>> The MacOS toolbox ROM performs 4 byte reads/writes when transferring data to
>> and from the target. Since the SCSI bus is 16-bits wide, use the memory API
>> to split a 4 byte access into 2 x 2 byte accesses.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp.c | 6 ++++--
>>   1 file changed, 4 insertions(+), 2 deletions(-)
> 
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> 
> Out of curiosity, what is the bus used?

AFAICT it's a custom logic chip that sits on the CPU address/data buses that does the 
decoding between the CPU and ESP chip. Other than a simple block diagram of the 
Quadra there isn't much official documentation out there :/

Are you planning to review any more of this series? I'm keen to put out a (hopefully 
final) v3 soon, but I'll hold off for little while if you want more time to look over 
the remaining patches.


ATB,

Mark.


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

* Re: [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers
  2021-02-15 22:35     ` Mark Cave-Ayland
@ 2021-02-16  7:30       ` Philippe Mathieu-Daudé
  2021-02-16 21:36         ` Mark Cave-Ayland
  2021-02-23  8:24         ` Mark Cave-Ayland
  0 siblings, 2 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-16  7:30 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, laurent; +Cc: fam, pbonzini

Hi Mark,

On 2/15/21 11:35 PM, Mark Cave-Ayland wrote:
> On 12/02/2021 18:56, Philippe Mathieu-Daudé wrote:
> 
>> On 2/9/21 8:30 PM, Mark Cave-Ayland wrote:
>>> The MacOS toolbox ROM performs 4 byte reads/writes when transferring
>>> data to
>>> and from the target. Since the SCSI bus is 16-bits wide, use the
>>> memory API
>>> to split a 4 byte access into 2 x 2 byte accesses.
>>>
>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>> ---
>>>   hw/scsi/esp.c | 6 ++++--
>>>   1 file changed, 4 insertions(+), 2 deletions(-)
>>
>> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>>
>> Out of curiosity, what is the bus used?
> 
> AFAICT it's a custom logic chip that sits on the CPU address/data buses
> that does the decoding between the CPU and ESP chip. Other than a simple
> block diagram of the Quadra there isn't much official documentation out
> there :/

OK.

> Are you planning to review any more of this series? I'm keen to put out
> a (hopefully final) v3 soon, but I'll hold off for little while if you
> want more time to look over the remaining patches.

I talked about this series with Laurent on Sunday, asking him for
review help ;) I don't remember if there is any big comment to
address in patches 1-14. If not I can review the missing ones
there today and you could send directly a pull request for this
first set, then send the rest as v3. Does that help?
For the rest I doubt having time to focus before Friday.

Regards,

Phil.


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

* Re: [PATCH v2 20/42] esp: remove the buf and buflen parameters from get_cmd()
  2021-02-09 19:29 ` [PATCH v2 20/42] esp: remove the buf and buflen parameters from get_cmd() Mark Cave-Ayland
@ 2021-02-16  7:31   ` Philippe Mathieu-Daudé
  2021-03-02 17:03   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-16  7:31 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> Now that all SCSI commands are accumulated in cmdbuf, remove the buf and buflen
> parameters from get_cmd() since these always reference cmdbuf and ESP_CMDBUF_SZ
> respectively.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time
  2021-02-09 19:29 ` [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time Mark Cave-Ayland
@ 2021-02-16  7:33   ` Philippe Mathieu-Daudé
  2021-02-16 21:52     ` Mark Cave-Ayland
  2021-03-01 21:35   ` Laurent Vivier
  1 sibling, 1 reply; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-16  7:33 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> Perform the length adjustment whereby a value of 0 in the STC represents
> a transfer length of 0x10000 at the point where the TC is loaded at the

0x10000 -> 64 KiB?

> start of a DMA command rather than just when a TI (Transfer Information)
> command is executed. This better matches the description as given in the
> datasheet.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index a1acc2c9bd..02b7876394 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -562,9 +562,6 @@ static void handle_ti(ESPState *s)
>      }
>  
>      dmalen = esp_get_tc(s);
> -    if (dmalen == 0) {
> -        dmalen = 0x10000;
> -    }
>      s->dma_counter = dmalen;
>  
>      if (s->do_cmd) {
> @@ -699,7 +696,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          if (val & CMD_DMA) {
>              s->dma = 1;
>              /* Reload DMA counter.  */
> -            esp_set_tc(s, esp_get_stc(s));
> +            if (esp_get_stc(s) == 0) {
> +                esp_set_tc(s, 0x10000);

0x10000 -> 64 * KiB

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 04/42] esp: add vmstate_esp version to embedded ESPState
  2021-02-09 19:29 ` [PATCH v2 04/42] esp: add vmstate_esp version to embedded ESPState Mark Cave-Ayland
@ 2021-02-16  7:35   ` Philippe Mathieu-Daudé
  2021-03-01 20:21   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-16  7:35 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent
  Cc: Dr. David Alan Gilbert

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> The QOM object representing ESPState is currently embedded within both the
> SYSBUS_ESP and PCI_ESP devices with migration state handled by embedding
> vmstate_esp within each device using VMSTATE_STRUCT.
> 
> Since the vmstate_esp fields are embedded directly within the migration
> stream, the incoming vmstate_esp version_id is lost. The only version information
> available is that from vmstate_sysbus_esp_scsi and vmstate_esp_pci_scsi, but
> those versions represent their respective devices and not that of the underlying
> ESPState.
> 
> Resolve this by adding a new version-dependent field in vmstate_sysbus_esp_scsi
> and vmstate_esp_pci_scsi which stores the vmstate_esp version_id field within
> ESPState to be used to allow migration from older QEMU versions.
> 
> Finally bump the vmstate_esp version to 5 to cover the upcoming ESPState changes
> within this patch series.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>  hw/scsi/esp-pci.c     |  3 ++-
>  hw/scsi/esp.c         | 23 +++++++++++++++++++++--
>  include/hw/scsi/esp.h |  2 ++
>  3 files changed, 25 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
> index ccf73bb901..8a82404853 100644
> --- a/hw/scsi/esp-pci.c
> +++ b/hw/scsi/esp-pci.c
> @@ -330,11 +330,12 @@ static void esp_pci_hard_reset(DeviceState *dev)
>  
>  static const VMStateDescription vmstate_esp_pci_scsi = {
>      .name = "pciespscsi",
> -    .version_id = 1,
> +    .version_id = 2,
>      .minimum_version_id = 1,
>      .fields = (VMStateField[]) {
>          VMSTATE_PCI_DEVICE(parent_obj, PCIESPState),
>          VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
> +        VMSTATE_UINT8_V(esp.mig_version_id, PCIESPState, 2),
>          VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
>          VMSTATE_END_OF_LIST()
>      }
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 1635f86622..9427c55d1d 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -796,10 +796,28 @@ static const VMStateDescription vmstate_esp_pdma = {
>      }
>  };
>  
> +static int esp_pre_save(void *opaque)
> +{
> +    ESPState *s = ESP(opaque);
> +
> +    s->mig_version_id = vmstate_esp.version_id;
> +    return 0;
> +}
> +
> +static int esp_post_load(void *opaque, int version_id)
> +{
> +    ESPState *s = ESP(opaque);
> +
> +    s->mig_version_id = vmstate_esp.version_id;
> +    return 0;
> +}
> +
>  const VMStateDescription vmstate_esp = {
>      .name = "esp",
> -    .version_id = 4,
> +    .version_id = 5,
>      .minimum_version_id = 3,
> +    .pre_save = esp_pre_save,
> +    .post_load = esp_post_load,
>      .fields = (VMStateField[]) {
>          VMSTATE_BUFFER(rregs, ESPState),
>          VMSTATE_BUFFER(wregs, ESPState),
> @@ -996,9 +1014,10 @@ static void sysbus_esp_init(Object *obj)
>  
>  static const VMStateDescription vmstate_sysbus_esp_scsi = {
>      .name = "sysbusespscsi",
> -    .version_id = 1,
> +    .version_id = 2,
>      .minimum_version_id = 1,
>      .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2),
>          VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
>          VMSTATE_END_OF_LIST()
>      }
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 11c799d91e..7d92471c5b 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -68,6 +68,8 @@ struct ESPState {
>      uint32_t pdma_start;
>      uint32_t pdma_cur;
>      void (*pdma_cb)(ESPState *s);
> +
> +    uint8_t mig_version_id;
>  };
>  
>  #define TYPE_SYSBUS_ESP "sysbus-esp"
> 



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

* Re: [PATCH v2 08/42] esp: determine transfer direction directly from SCSI phase
  2021-02-09 19:29 ` [PATCH v2 08/42] esp: determine transfer direction directly from SCSI phase Mark Cave-Ayland
@ 2021-02-16  7:36   ` Philippe Mathieu-Daudé
  2021-03-01 21:18   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-16  7:36 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> The transfer direction is currently determined by checking the sign of ti_size
> but as this series progresses ti_size can be zero at the end of the transfer.
> 
> Use the SCSI phase to determine the transfer direction as used in other SCSI
> controller implementations.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers
  2021-02-16  7:30       ` Philippe Mathieu-Daudé
@ 2021-02-16 21:36         ` Mark Cave-Ayland
  2021-02-23  8:24         ` Mark Cave-Ayland
  1 sibling, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-16 21:36 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, laurent; +Cc: fam, pbonzini

On 16/02/2021 07:30, Philippe Mathieu-Daudé wrote:

>> Are you planning to review any more of this series? I'm keen to put out
>> a (hopefully final) v3 soon, but I'll hold off for little while if you
>> want more time to look over the remaining patches.
> 
> I talked about this series with Laurent on Sunday, asking him for
> review help ;) I don't remember if there is any big comment to
> address in patches 1-14. If not I can review the missing ones
> there today and you could send directly a pull request for this
> first set, then send the rest as v3. Does that help?
> For the rest I doubt having time to focus before Friday.

I'd prefer to merge the entire series, since there is more than one migration 
compatibility break for the q800 machine and I think it would be almost impossible to 
ensure that all test images didn't regress at some point until all patches have been 
applied.

I should probably add that I expanded the test suite to booting 10 images from v1 to 
v2 across a mix of SPARC, m68k, x86_64 and hppa including both commercial and free OSs.


ATB,

Mark.


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

* Re: [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time
  2021-02-16  7:33   ` Philippe Mathieu-Daudé
@ 2021-02-16 21:52     ` Mark Cave-Ayland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-16 21:52 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam, laurent

On 16/02/2021 07:33, Philippe Mathieu-Daudé wrote:

> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>> Perform the length adjustment whereby a value of 0 in the STC represents
>> a transfer length of 0x10000 at the point where the TC is loaded at the
> 
> 0x10000 -> 64 KiB?

I'd prefer to keep these as they are, since TC is described in the documentation as 
16-bit counter: it is the number of bits that is relevant here as opposed to the 
absolute size.

There is a slight bit of trickery here in that the ESP emulation already handles a 
later variant of the chip which has a 24-bit counter which is why we can get away 
with setting its value to 0x10000 - guests that don't check for this will simply 
ignore the register containing the MSB.

>> start of a DMA command rather than just when a TI (Transfer Information)
>> command is executed. This better matches the description as given in the
>> datasheet.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp.c | 9 +++++----
>>   1 file changed, 5 insertions(+), 4 deletions(-)
>>
>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>> index a1acc2c9bd..02b7876394 100644
>> --- a/hw/scsi/esp.c
>> +++ b/hw/scsi/esp.c
>> @@ -562,9 +562,6 @@ static void handle_ti(ESPState *s)
>>       }
>>   
>>       dmalen = esp_get_tc(s);
>> -    if (dmalen == 0) {
>> -        dmalen = 0x10000;
>> -    }
>>       s->dma_counter = dmalen;
>>   
>>       if (s->do_cmd) {
>> @@ -699,7 +696,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>>           if (val & CMD_DMA) {
>>               s->dma = 1;
>>               /* Reload DMA counter.  */
>> -            esp_set_tc(s, esp_get_stc(s));
>> +            if (esp_get_stc(s) == 0) {
>> +                esp_set_tc(s, 0x10000);
> 
> 0x10000 -> 64 * KiB

And same here too.

> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


ATB,

Mark.


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

* Re: [PATCH v2 33/42] esp: defer command completion interrupt on incoming data transfers
  2021-02-09 19:30 ` [PATCH v2 33/42] esp: defer command completion interrupt on incoming data transfers Mark Cave-Ayland
@ 2021-02-18 17:25   ` Mark Cave-Ayland
  2021-03-03 19:52     ` Laurent Vivier
  0 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-18 17:25 UTC (permalink / raw)
  To: qemu-devel, pbonzini, fam, laurent

On 09/02/2021 19:30, Mark Cave-Ayland wrote:

> The MacOS toolbox ROM issues a command to the ESP controller as part of its
> "FAST" SCSI routines and then proceeds to read the incoming data soon after
> receiving the command completion interrupt.
> 
> Unfortunately due to SCSI block transfers being asynchronous the incoming data
> may not yet be present causing an underflow error. Resolve this by waiting for
> the SCSI subsystem transfer_data callback before raising the command completion
> interrupt.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>   hw/scsi/esp.c         | 54 +++++++++++++++++++++++++++++++++++++++----
>   include/hw/scsi/esp.h |  1 +
>   2 files changed, 51 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 728d4ddf99..ce6a7a1ed0 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -183,6 +183,14 @@ static int esp_select(ESPState *s)
>           esp_raise_irq(s);
>           return -1;
>       }
> +
> +    /*
> +     * Note that we deliberately don't raise the IRQ here: this will be done
> +     * either in do_busid_cmd() for DATA OUT transfers or by the deferred
> +     * IRQ mechanism in esp_transfer_data() for DATA IN transfers
> +     */
> +    s->rregs[ESP_RINTR] |= INTR_FC;
> +    s->rregs[ESP_RSEQ] = SEQ_CD;
>       return 0;
>   }
>   
> @@ -237,18 +245,24 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
>       s->ti_size = datalen;
>       if (datalen != 0) {
>           s->rregs[ESP_RSTAT] = STAT_TC;
> +        s->rregs[ESP_RSEQ] = SEQ_CD;
>           esp_set_tc(s, 0);
>           if (datalen > 0) {
> +            /*
> +             * Switch to DATA IN phase but wait until initial data xfer is
> +             * complete before raising the command completion interrupt
> +             */
> +            s->data_in_ready = false;
>               s->rregs[ESP_RSTAT] |= STAT_DI;
>           } else {
>               s->rregs[ESP_RSTAT] |= STAT_DO;
> +            s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
> +            esp_raise_irq(s);
> +            esp_lower_drq(s);
>           }
>           scsi_req_continue(s->current_req);
> +        return;
>       }
> -    s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
> -    s->rregs[ESP_RSEQ] = SEQ_CD;
> -    esp_raise_irq(s);
> -    esp_lower_drq(s);
>   }
>   
>   static void do_cmd(ESPState *s)
> @@ -603,12 +617,35 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
>   void esp_transfer_data(SCSIRequest *req, uint32_t len)
>   {
>       ESPState *s = req->hba_private;
> +    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
>       uint32_t dmalen = esp_get_tc(s);
>   
>       assert(!s->do_cmd);
>       trace_esp_transfer_data(dmalen, s->ti_size);
>       s->async_len = len;
>       s->async_buf = scsi_req_get_buf(req);
> +
> +    if (!to_device && !s->data_in_ready) {
> +        /*
> +         * Initial incoming data xfer is complete so raise command
> +         * completion interrupt
> +         */
> +        s->data_in_ready = true;
> +        s->rregs[ESP_RSTAT] |= STAT_TC;
> +        s->rregs[ESP_RINTR] |= INTR_BS;
> +        esp_raise_irq(s);
> +
> +        /*
> +         * If data is ready to transfer and the TI command has already
> +         * been executed, start DMA immediately. Otherwise DMA will start
> +         * when host sends the TI command
> +         */
> +        if (s->ti_size && (s->rregs[ESP_CMD] == (CMD_TI | CMD_DMA))) {
> +            esp_do_dma(s);
> +        }
> +        return;
> +    }
> +
>       if (dmalen) {
>           esp_do_dma(s);
>       } else if (s->ti_size <= 0) {
> @@ -870,6 +907,14 @@ static bool esp_is_before_version_5(void *opaque, int version_id)
>       return version_id < 5;
>   }
>   
> +static bool esp_is_version_5(void *opaque, int version_id)
> +{
> +    ESPState *s = ESP(opaque);
> +
> +    version_id = MIN(version_id, s->mig_version_id);
> +    return version_id == 5;
> +}
> +
>   static int esp_pre_save(void *opaque)
>   {
>       ESPState *s = ESP(opaque);
> @@ -914,6 +959,7 @@ const VMStateDescription vmstate_esp = {
>           VMSTATE_UINT32(cmdlen, ESPState),
>           VMSTATE_UINT32(do_cmd, ESPState),
>           VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
> +        VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
>           VMSTATE_END_OF_LIST()
>       },
>   };
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 6618f4e091..3b69aedebe 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -41,6 +41,7 @@ struct ESPState {
>       uint32_t cmdlen;
>       uint32_t do_cmd;
>   
> +    bool data_in_ready;
>       int dma_enabled;
>   
>       uint32_t async_len;

Whilst doing some testing earlier, I discovered that the same change is required in 
do_dma_pdma_cb(): it seems during boot the ROM attempts several 128k DMA requests in 
a row, and with heavy debugging enabled it's enough to trigger the same underflow 
problem.

Fortunately the fix is easy, and I'll squash this into the v3 series:

diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index a175191718..248c1ce27a 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -453,17 +453,13 @@ static void do_dma_pdma_cb(ESPState *s)
      } else {
          if (s->async_len == 0) {
              if (s->current_req) {
+               /*
+                * Defer until the scsi layer has completed.
+                */
                  scsi_req_continue(s->current_req);
+                s->data_in_ready = false;
              }
-
-            /*
-             * If there is still data to be read from the device then
-             * complete the DMA operation immediately.  Otherwise defer
-             * until the scsi layer has completed.
-             */
-            if (esp_get_tc(s) != 0 || s->ti_size == 0) {
-                return;
-            }
+            return;
          }

          if (esp_get_tc(s) != 0) {


ATB,

Mark.


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

* Re: [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers
  2021-02-16  7:30       ` Philippe Mathieu-Daudé
  2021-02-16 21:36         ` Mark Cave-Ayland
@ 2021-02-23  8:24         ` Mark Cave-Ayland
  2021-02-23 18:55           ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-23  8:24 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, laurent; +Cc: fam, pbonzini

On 16/02/2021 07:30, Philippe Mathieu-Daudé wrote:

>> Are you planning to review any more of this series? I'm keen to put out
>> a (hopefully final) v3 soon, but I'll hold off for little while if you
>> want more time to look over the remaining patches.
> 
> I talked about this series with Laurent on Sunday, asking him for
> review help ;) I don't remember if there is any big comment to
> address in patches 1-14. If not I can review the missing ones
> there today and you could send directly a pull request for this
> first set, then send the rest as v3. Does that help?
> For the rest I doubt having time to focus before Friday.

Hi Phil/Laurent,

I know you're both really busy, but gentle ping to ask if anyone is still planning to 
review the second half of this patchset? :)


ATB,

Mark.


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

* Re: [PATCH v2 14/42] esp: remove minlen restriction in handle_ti
  2021-02-09 19:29 ` [PATCH v2 14/42] esp: remove minlen restriction in handle_ti Mark Cave-Ayland
@ 2021-02-23 18:24   ` Philippe Mathieu-Daudé
  2021-03-01 22:04   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 18:24 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> The limiting of DMA transfers to the maximum size of the available data is already
> handled by esp_do_dma() and do_dma_pdma_cb().
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 12 ++----------
>  1 file changed, 2 insertions(+), 10 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 16/42] esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write()
  2021-02-09 19:29 ` [PATCH v2 16/42] esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
@ 2021-02-23 18:25   ` Philippe Mathieu-Daudé
  2021-03-01 22:07   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 18:25 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> This is the first step in removing get_pdma_buf() from esp.c.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 34 ++++++++++++++++++++++++++++------
>  1 file changed, 28 insertions(+), 6 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 19/42] esp: remove buf parameter from do_cmd()
  2021-02-09 19:29 ` [PATCH v2 19/42] esp: remove buf parameter from do_cmd() Mark Cave-Ayland
@ 2021-02-23 18:27   ` Philippe Mathieu-Daudé
  2021-03-02 17:03   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 18:27 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> Now that all SCSI commands are accumulated in cmdbuf, remove the buf parameter
> from do_cmd() since this always points to cmdbuf.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 13 +++++++------
>  1 file changed, 7 insertions(+), 6 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 24/42] esp: use in-built TC to determine PDMA transfer length
  2021-02-09 19:30 ` [PATCH v2 24/42] esp: use in-built TC to determine PDMA transfer length Mark Cave-Ayland
@ 2021-02-23 18:32   ` Philippe Mathieu-Daudé
  2021-03-02 21:48   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 18:32 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:30 PM, Mark Cave-Ayland wrote:
> Real hardware simply counts down using the in-built TC to determine when the
> the PDMA request is complete. Use the TC to determine the PDMA transfer length
> which then enables us to remove the redundant pdma_len variable.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 28 +++++++++++++---------------
>  include/hw/scsi/esp.h |  1 -
>  2 files changed, 13 insertions(+), 16 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 25/42] esp: remove CMD pdma_origin
  2021-02-09 19:30 ` [PATCH v2 25/42] esp: remove CMD pdma_origin Mark Cave-Ayland
@ 2021-02-23 18:34   ` Philippe Mathieu-Daudé
  2021-03-02 21:49   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 18:34 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:30 PM, Mark Cave-Ayland wrote:
> The cmdbuf is really just a copy of FIFO data (including extra message phase
> bytes) so its pdma_origin is effectively TI. Fortunately we already know when
> we are receiving a SCSI command since do_cmd == 1 which enables us to
> distinguish between the two cases in esp_pdma_read()/esp_pdma_write().
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 22 ++++++++++++----------
>  include/hw/scsi/esp.h |  1 -
>  2 files changed, 12 insertions(+), 11 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 36/42] esp: add maxlen parameter to get_cmd()
  2021-02-09 19:30 ` [PATCH v2 36/42] esp: add maxlen parameter to get_cmd() Mark Cave-Ayland
@ 2021-02-23 18:43   ` Philippe Mathieu-Daudé
  2021-03-03 20:04   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 18:43 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:30 PM, Mark Cave-Ayland wrote:
> Some guests use a mixture of DMA and non-DMA transfers in combination with the
> SATN and stop command to transfer message out phase and command phase bytes to
> the target. Prepare for the next commit by adding a maxlen parameter to
> get_cmd() to allow partial transfers.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 20 +++++++++++---------
>  1 file changed, 11 insertions(+), 9 deletions(-)

I dare to add:
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 38/42] esp: convert ti_buf from array to Fifo8
  2021-02-09 19:30 ` [PATCH v2 38/42] esp: convert ti_buf from array to Fifo8 Mark Cave-Ayland
@ 2021-02-23 18:49   ` Philippe Mathieu-Daudé
  2021-02-25  9:15     ` Mark Cave-Ayland
  2021-03-03 20:11   ` Laurent Vivier
  1 sibling, 1 reply; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 18:49 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:30 PM, Mark Cave-Ayland wrote:
> Rename TI_BUFSZ to ESP_FIFO_SZ since this constant is really describing the size
> of the FIFO and is not directly related to the TI size.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 117 ++++++++++++++++++++++++++----------------
>  include/hw/scsi/esp.h |   8 +--
>  2 files changed, 79 insertions(+), 46 deletions(-)

> @@ -806,11 +818,9 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>              } else {
>                  trace_esp_error_fifo_overrun();
>              }
> -        } else if (s->ti_wptr == TI_BUFSZ - 1) {
> -            trace_esp_error_fifo_overrun();
>          } else {
>              s->ti_size++;
> -            s->ti_buf[s->ti_wptr++] = val & 0xff;
> +            esp_fifo_push(s, val & 0xff);

Personally I'd drop the '& 0xff' part.

>          }
>  
>          /* Non-DMA transfers raise an interrupt after every byte */
> @@ -839,8 +849,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          case CMD_FLUSH:
>              trace_esp_mem_writeb_cmd_flush(val);
>              /*s->ti_size = 0;*/

Is this comment still meaningful?

> -            s->ti_wptr = 0;
> -            s->ti_rptr = 0;
> +            fifo8_reset(&s->fifo);
>              break;
>          case CMD_RESET:
>              trace_esp_mem_writeb_cmd_reset(val);
> @@ -958,11 +967,18 @@ static int esp_pre_save(void *opaque)
>  static int esp_post_load(void *opaque, int version_id)
>  {
>      ESPState *s = ESP(opaque);
> +    int len, i;
>  
>      version_id = MIN(version_id, s->mig_version_id);
>  
>      if (version_id < 5) {
>          esp_set_tc(s, s->mig_dma_left);
> +
> +        /* Migrate ti_buf to fifo */
> +        len = s->mig_ti_wptr - s->mig_ti_rptr;
> +        for (i = 0; i < len; i++) {
> +            fifo8_push(&s->fifo, s->mig_ti_buf[i]);

Again I dare to add:
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> +        }
>      }


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

* Re: [PATCH v2 40/42] esp: add trivial implementation of the ESP_RFLAGS register
  2021-02-09 19:30 ` [PATCH v2 40/42] esp: add trivial implementation of the ESP_RFLAGS register Mark Cave-Ayland
@ 2021-02-23 18:51   ` Philippe Mathieu-Daudé
  2021-03-03 20:19   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 18:51 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:30 PM, Mark Cave-Ayland wrote:
> The bottom 5 bits contain the number of bytes remaining in the FIFO which is
> trivial to implement with Fifo8 (the remaining bits are unimplemented and left
> as 0 for now).
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 4 ++++
>  1 file changed, 4 insertions(+)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers
  2021-02-23  8:24         ` Mark Cave-Ayland
@ 2021-02-23 18:55           ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 18:55 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, laurent; +Cc: fam, pbonzini

On 2/23/21 9:24 AM, Mark Cave-Ayland wrote:
> On 16/02/2021 07:30, Philippe Mathieu-Daudé wrote:
> 
>>> Are you planning to review any more of this series? I'm keen to put out
>>> a (hopefully final) v3 soon, but I'll hold off for little while if you
>>> want more time to look over the remaining patches.
>>
>> I talked about this series with Laurent on Sunday, asking him for
>> review help ;) I don't remember if there is any big comment to
>> address in patches 1-14. If not I can review the missing ones
>> there today and you could send directly a pull request for this
>> first set, then send the rest as v3. Does that help?
>> For the rest I doubt having time to focus before Friday.
> 
> Hi Phil/Laurent,
> 
> I know you're both really busy, but gentle ping to ask if anyone is
> still planning to review the second half of this patchset? :)

At this point I reviewed more than half of the series :)

Laurent, can you have a look at the upper half?


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

* Re: [PATCH v2 13/42] esp: remove dma_left from ESPState
  2021-02-09 19:29 ` [PATCH v2 13/42] esp: remove dma_left " Mark Cave-Ayland
@ 2021-02-23 21:22   ` Philippe Mathieu-Daudé
  2021-03-01 21:50   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 21:22 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> The ESP device already keeps track of the remaining bytes left to transfer via
> its TC (transfer counter) register which is decremented for each byte that
> is transferred across the SCSI bus.
> 
> Switch the transfer logic to use the value of TC instead of dma_left and then
> remove dma_left completely, adding logic to the vmstate_esp post_load() function
> to transfer the old dma_left value to the TC register during migration from
> older versions.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 47 ++++++++++++++++++++++++++++---------------
>  include/hw/scsi/esp.h |  5 +++--
>  2 files changed, 34 insertions(+), 18 deletions(-)

I dare to add:
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 17/42] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write()
  2021-02-09 19:29 ` [PATCH v2 17/42] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
@ 2021-02-23 21:23   ` Philippe Mathieu-Daudé
  2021-03-01 22:09   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 21:23 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 50 ++++++++++++++++++++++++++++++++------------------
>  1 file changed, 32 insertions(+), 18 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index cfeba2feb0..7134c0aff4 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -153,22 +153,45 @@ static uint8_t *get_pdma_buf(ESPState *s)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf
  2021-02-09 19:29 ` [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf Mark Cave-Ayland
@ 2021-02-23 21:25   ` Philippe Mathieu-Daudé
  2021-03-02 17:02   ` Laurent Vivier
  2021-03-02 21:22   ` Laurent Vivier
  2 siblings, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 21:25 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> ESP SCSI commands are already accumulated in cmdbuf and so there is no need to
> keep a separate pdma_buf buffer. Accumulate SCSI commands for PDMA transfers in
> cmdbuf instead of pdma_buf so update cmdlen accordingly and change pdma_origin
> for PDMA transfers to CMD which allows the PDMA origin to be removed.
> 
> This commit also removes a stray memcpy() from get_cmd() which is a no-op because
> cmdlen is always zero at the start of a command.
> 
> Notionally the removal of pdma_buf from vmstate_esp_pdma also breaks migration
> compatibility for the PDMA subsection until its complete removal by the end of
> the series.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 56 +++++++++++++++++++------------------------
>  include/hw/scsi/esp.h |  2 --
>  2 files changed, 25 insertions(+), 33 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 23/42] esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA
  2021-02-09 19:29 ` [PATCH v2 23/42] esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA Mark Cave-Ayland
@ 2021-02-23 21:29   ` Philippe Mathieu-Daudé
  2021-03-02 21:47   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 21:29 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> This eliminates the last user of the PDMA-specific pdma_cur variable which can
> now be removed.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 23 ++++++++---------------
>  include/hw/scsi/esp.h |  1 -
>  2 files changed, 8 insertions(+), 16 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


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

* Re: [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes
  2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
                   ` (41 preceding siblings ...)
  2021-02-09 19:30 ` [PATCH v2 42/42] esp: add support for unaligned accesses Mark Cave-Ayland
@ 2021-02-23 21:32 ` Philippe Mathieu-Daudé
  2021-02-25  9:54   ` Mark Cave-Ayland
  42 siblings, 1 reply; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-23 21:32 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

Hi Mark,

On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
> This patch series comes from an experimental branch that I've been working on
> to try and boot a MacOS toolbox ROM under the QEMU q800 machine. The effort is
> far from complete, but it seems worth submitting these patches separately since
> they are limited to the ESP device and form a substantial part of the work to
> date.
> 
> As part of Laurent's recent q800 work so-called PDMA (pseudo-DMA) support was
> added to the ESP device. This is whereby the DREQ (DMA request) line is used
> to signal to the host CPU that it can transfer data to/from the device over
> the SCSI bus.
> 
> The existing PDMA tracks 4 separate transfer data sources as indicated by the
> ESP pdma_origin variable: PDMA, TI, CMD and ASYNC with an independent variable
> pdma_len to store the transfer length. This works well with Linux which uses a
> single PDMA request to transfer a number of sectors in a single request.
> 
> Unfortunately the MacOS toolbox ROM has other ideas here: it sends data to the
> ESP as a mixture of FIFO and PDMA transfers and then uses a mixture of the FIFO
> and DMA counters to confirm that the correct number of bytes have been
> transferred. For this to work correctly the PDMA buffers and separate pdma_len
> transfer counter must be consolidated into the FIFO to allow mixing of both
> types of transfer within a single request.
> 
> The patchset is split into several sections:
> 
> - Patches 1-7 are minor patches which make esp.c checkpatch friendly, QOMify ESPState,
>   and also fix up some trace events ready for later patches in the series
> 
> - Patches 8-13 unify the DMA transfer count. In particular there are 2 synthetic
>   variables dma_counter and dma_left within ESPState which do not need to exist. 
>   DMA transfer lengths are programmed into the TC (transfer count) register which is 
>   decremented for each byte transferred, generating an interrupt when it reaches zero.
>   These patches add helper functions to read the TC and STC registers directly and
>   remove these synthetic variables so that the DMA transfer length is now tracked in
>   a single place.
> 
> - Now that the TC register represents the authoritative DMA transfer length, patches
>   14-25 work to eliminate the separate PDMA variables pdma_start, pdma_cur, pdma_len
>   and separate PDMA buffers PDMA and CMD. The PDMA position variables can be replaced
>   by the existing ESP cmdlen and ti_wptr/ti_rptr, whilst the FIFO (TI) buffer is used
>   for incoming data with commands being accumulated in cmdbuf as per standard DMA
>   requests.

I tried to help reviewing up to this point.

The next parts are too specific to me.

> - Patches 26 and 27 fix the detection of missing SCSI targets by the MacOS toolbox ROM
>   on startup at which point it will attempt to start reading information from a CDROM
>   attached to the q800 machine.
> 
> - Patch 28 is the main rework of the PDMA buffer transfers: instead of tracking the
>   SCSI transfers using a separate ASYNC pdma_origin, the contents of the ESPState
>   async_buf are copied to the FIFO buffer in 16-byte chunks with the transfer status
>   and IRQs being set accordingly.
> 
> - Patch 29 removes the last separate PDMA variable pdma_origin, including the separate
>   PDMA migration subsection which is no longer required (see note below about migration
>   compatibility).
>   
> - Patch 30 enables 4 byte PDMA reads/writes over the SCSI bus which are used by MacOS
>   when reading the next stage bootloader from CDROM (this is an increase from
>   2 bytes currently implemented and used by Linux).
> 
> - Patches 31-34 fix an issue whereby the MacOS toolbox ROM tries to read incoming data
>   from the target within a few instructions of receiving the command complete interrupt.
>   Since IO is asynchronous in QEMU, it is necessary to delay the command complete
>   interrupt for incoming data to avoid underflow.
> 
> - Patches 35-37 fix a problem with the SATN and stop command not changing the SCSI bus
>   to message out phase. This actually first manifested itself after the Fifo8 conversion
>   with guests that mix DMA/non-DMA commands but it is moved forward to aid bisection.
> 
> - Patches 38-39 convert ti_buf and cmdbuf from simple arrays to QEMU's Fifo8 type which
>   helped locate a handful of bugs around handling the buffer pointers which are
>   incorpated within earlier patches within the series.
>   
> - Finally patches 40-42 add support for the FIFO count registers, non-DMA transfers and
>   unaligned accesses which are required for the MacOS toolbox ROM to successful read
>   files from disk.


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

* Re: [PATCH v2 38/42] esp: convert ti_buf from array to Fifo8
  2021-02-23 18:49   ` Philippe Mathieu-Daudé
@ 2021-02-25  9:15     ` Mark Cave-Ayland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-25  9:15 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam, laurent

On 23/02/2021 18:49, Philippe Mathieu-Daudé wrote:

> On 2/9/21 8:30 PM, Mark Cave-Ayland wrote:
>> Rename TI_BUFSZ to ESP_FIFO_SZ since this constant is really describing the size
>> of the FIFO and is not directly related to the TI size.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp.c         | 117 ++++++++++++++++++++++++++----------------
>>   include/hw/scsi/esp.h |   8 +--
>>   2 files changed, 79 insertions(+), 46 deletions(-)
> 
>> @@ -806,11 +818,9 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>>               } else {
>>                   trace_esp_error_fifo_overrun();
>>               }
>> -        } else if (s->ti_wptr == TI_BUFSZ - 1) {
>> -            trace_esp_error_fifo_overrun();
>>           } else {
>>               s->ti_size++;
>> -            s->ti_buf[s->ti_wptr++] = val & 0xff;
>> +            esp_fifo_push(s, val & 0xff);
> 
> Personally I'd drop the '& 0xff' part.

I left it as it was so that it was direct translation of the code it was replacing, 
but I can easily drop it.

>>           }
>>   
>>           /* Non-DMA transfers raise an interrupt after every byte */
>> @@ -839,8 +849,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>>           case CMD_FLUSH:
>>               trace_esp_mem_writeb_cmd_flush(val);
>>               /*s->ti_size = 0;*/
> 
> Is this comment still meaningful?

This line can also be removed, so I will make this change for v3.

>> -            s->ti_wptr = 0;
>> -            s->ti_rptr = 0;
>> +            fifo8_reset(&s->fifo);
>>               break;
>>           case CMD_RESET:
>>               trace_esp_mem_writeb_cmd_reset(val);
>> @@ -958,11 +967,18 @@ static int esp_pre_save(void *opaque)
>>   static int esp_post_load(void *opaque, int version_id)
>>   {
>>       ESPState *s = ESP(opaque);
>> +    int len, i;
>>   
>>       version_id = MIN(version_id, s->mig_version_id);
>>   
>>       if (version_id < 5) {
>>           esp_set_tc(s, s->mig_dma_left);
>> +
>> +        /* Migrate ti_buf to fifo */
>> +        len = s->mig_ti_wptr - s->mig_ti_rptr;
>> +        for (i = 0; i < len; i++) {
>> +            fifo8_push(&s->fifo, s->mig_ti_buf[i]);
> 
> Again I dare to add:
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

Thank you :)


ATB,

Mark.


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

* Re: [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes
  2021-02-23 21:32 ` [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Philippe Mathieu-Daudé
@ 2021-02-25  9:54   ` Mark Cave-Ayland
  2021-02-25 10:50     ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-25  9:54 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam, laurent

On 23/02/2021 21:32, Philippe Mathieu-Daudé wrote:

> Hi Mark,
> 
> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>> This patch series comes from an experimental branch that I've been working on
>> to try and boot a MacOS toolbox ROM under the QEMU q800 machine. The effort is
>> far from complete, but it seems worth submitting these patches separately since
>> they are limited to the ESP device and form a substantial part of the work to
>> date.
>>
>> As part of Laurent's recent q800 work so-called PDMA (pseudo-DMA) support was
>> added to the ESP device. This is whereby the DREQ (DMA request) line is used
>> to signal to the host CPU that it can transfer data to/from the device over
>> the SCSI bus.
>>
>> The existing PDMA tracks 4 separate transfer data sources as indicated by the
>> ESP pdma_origin variable: PDMA, TI, CMD and ASYNC with an independent variable
>> pdma_len to store the transfer length. This works well with Linux which uses a
>> single PDMA request to transfer a number of sectors in a single request.
>>
>> Unfortunately the MacOS toolbox ROM has other ideas here: it sends data to the
>> ESP as a mixture of FIFO and PDMA transfers and then uses a mixture of the FIFO
>> and DMA counters to confirm that the correct number of bytes have been
>> transferred. For this to work correctly the PDMA buffers and separate pdma_len
>> transfer counter must be consolidated into the FIFO to allow mixing of both
>> types of transfer within a single request.
>>
>> The patchset is split into several sections:
>>
>> - Patches 1-7 are minor patches which make esp.c checkpatch friendly, QOMify ESPState,
>>    and also fix up some trace events ready for later patches in the series
>>
>> - Patches 8-13 unify the DMA transfer count. In particular there are 2 synthetic
>>    variables dma_counter and dma_left within ESPState which do not need to exist.
>>    DMA transfer lengths are programmed into the TC (transfer count) register which is
>>    decremented for each byte transferred, generating an interrupt when it reaches zero.
>>    These patches add helper functions to read the TC and STC registers directly and
>>    remove these synthetic variables so that the DMA transfer length is now tracked in
>>    a single place.
>>
>> - Now that the TC register represents the authoritative DMA transfer length, patches
>>    14-25 work to eliminate the separate PDMA variables pdma_start, pdma_cur, pdma_len
>>    and separate PDMA buffers PDMA and CMD. The PDMA position variables can be replaced
>>    by the existing ESP cmdlen and ti_wptr/ti_rptr, whilst the FIFO (TI) buffer is used
>>    for incoming data with commands being accumulated in cmdbuf as per standard DMA
>>    requests.
> 
> I tried to help reviewing up to this point.
> 
> The next parts are too specific to me.

Thanks Phil - I understand that a set of 42 patches for a 25 year old disk controller 
is never going to be the top of most people's review list, and some parts are almost 
impossible to review unless you have a good understanding of the datasheet.

I'll see if Laurent has any comments over the next few days, but other than that I'd 
be inclined to send a v3 followed soon by a PR to avoid me having to update these 
regularly (I already see a slight conflict with Paolo's SCSI error handling changes, 
for example).


ATB,

Mark.


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

* Re: [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes
  2021-02-25  9:54   ` Mark Cave-Ayland
@ 2021-02-25 10:50     ` Philippe Mathieu-Daudé
  2021-02-25 19:17       ` Mark Cave-Ayland
  0 siblings, 1 reply; 135+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-02-25 10:50 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam, laurent

On 2/25/21 10:54 AM, Mark Cave-Ayland wrote:
> On 23/02/2021 21:32, Philippe Mathieu-Daudé wrote:
> 
>> Hi Mark,
>>
>> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>>> This patch series comes from an experimental branch that I've been
>>> working on
>>> to try and boot a MacOS toolbox ROM under the QEMU q800 machine. The
>>> effort is
>>> far from complete, but it seems worth submitting these patches
>>> separately since
>>> they are limited to the ESP device and form a substantial part of the
>>> work to
>>> date.
>>>
>>> As part of Laurent's recent q800 work so-called PDMA (pseudo-DMA)
>>> support was
>>> added to the ESP device. This is whereby the DREQ (DMA request) line
>>> is used
>>> to signal to the host CPU that it can transfer data to/from the
>>> device over
>>> the SCSI bus.
>>>
>>> The existing PDMA tracks 4 separate transfer data sources as
>>> indicated by the
>>> ESP pdma_origin variable: PDMA, TI, CMD and ASYNC with an independent
>>> variable
>>> pdma_len to store the transfer length. This works well with Linux
>>> which uses a
>>> single PDMA request to transfer a number of sectors in a single request.
>>>
>>> Unfortunately the MacOS toolbox ROM has other ideas here: it sends
>>> data to the
>>> ESP as a mixture of FIFO and PDMA transfers and then uses a mixture
>>> of the FIFO
>>> and DMA counters to confirm that the correct number of bytes have been
>>> transferred. For this to work correctly the PDMA buffers and separate
>>> pdma_len
>>> transfer counter must be consolidated into the FIFO to allow mixing
>>> of both
>>> types of transfer within a single request.
>>>
>>> The patchset is split into several sections:
>>>
>>> - Patches 1-7 are minor patches which make esp.c checkpatch friendly,
>>> QOMify ESPState,
>>>    and also fix up some trace events ready for later patches in the
>>> series
>>>
>>> - Patches 8-13 unify the DMA transfer count. In particular there are
>>> 2 synthetic
>>>    variables dma_counter and dma_left within ESPState which do not
>>> need to exist.
>>>    DMA transfer lengths are programmed into the TC (transfer count)
>>> register which is
>>>    decremented for each byte transferred, generating an interrupt
>>> when it reaches zero.
>>>    These patches add helper functions to read the TC and STC
>>> registers directly and
>>>    remove these synthetic variables so that the DMA transfer length
>>> is now tracked in
>>>    a single place.
>>>
>>> - Now that the TC register represents the authoritative DMA transfer
>>> length, patches
>>>    14-25 work to eliminate the separate PDMA variables pdma_start,
>>> pdma_cur, pdma_len
>>>    and separate PDMA buffers PDMA and CMD. The PDMA position
>>> variables can be replaced
>>>    by the existing ESP cmdlen and ti_wptr/ti_rptr, whilst the FIFO
>>> (TI) buffer is used
>>>    for incoming data with commands being accumulated in cmdbuf as per
>>> standard DMA
>>>    requests.
>>
>> I tried to help reviewing up to this point.
>>
>> The next parts are too specific to me.
> 
> Thanks Phil - I understand that a set of 42 patches for a 25 year old
> disk controller is never going to be the top of most people's review
> list, and some parts are almost impossible to review unless you have a
> good understanding of the datasheet.

Well I also have a series for a 30+ years old MIPS board and am
not confident to post it because probably little interest for
the community, although it is very interesting to compare with
actual SoC and see how the IP blocks are indeed reused and improved
over the time -- or not... i.e. when someone report a hw bug in a 2020
product and the same bug is present in the IP core from the 80th it
inherited ;)

> I'll see if Laurent has any comments over the next few days, but other
> than that I'd be inclined to send a v3 followed soon by a PR to avoid me
> having to update these regularly (I already see a slight conflict with
> Paolo's SCSI error handling changes, for example).

I'll have a look at your v3 and Cc you when I post this MIPS board :D

Regards,

Phil.


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

* Re: [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes
  2021-02-25 10:50     ` Philippe Mathieu-Daudé
@ 2021-02-25 19:17       ` Mark Cave-Ayland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-02-25 19:17 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam, laurent

On 25/02/2021 10:50, Philippe Mathieu-Daudé wrote:

>> Thanks Phil - I understand that a set of 42 patches for a 25 year old
>> disk controller is never going to be the top of most people's review
>> list, and some parts are almost impossible to review unless you have a
>> good understanding of the datasheet.
> 
> Well I also have a series for a 30+ years old MIPS board and am
> not confident to post it because probably little interest for
> the community, although it is very interesting to compare with
> actual SoC and see how the IP blocks are indeed reused and improved
> over the time -- or not... i.e. when someone report a hw bug in a 2020
> product and the same bug is present in the IP core from the 80th it
> inherited ;)
> 
>> I'll see if Laurent has any comments over the next few days, but other
>> than that I'd be inclined to send a v3 followed soon by a PR to avoid me
>> having to update these regularly (I already see a slight conflict with
>> Paolo's SCSI error handling changes, for example).
> 
> I'll have a look at your v3 and Cc you when I post this MIPS board :D

Well I can do a cursory review of the patches, but I can't really say I've got much 
in the way of MIPS experience to be able to review in depth. If you feel that you 
would like some R-B tags before sending a PR then I can certainly give it another set 
of eyeballs.


ATB,

Mark.


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

* Re: [PATCH v2 01/42] esp: checkpatch fixes
  2021-02-09 19:29 ` [PATCH v2 01/42] esp: checkpatch fixes Mark Cave-Ayland
@ 2021-03-01 19:43   ` Laurent Vivier
  2021-03-03  8:33     ` Mark Cave-Ayland
  0 siblings, 1 reply; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 19:43 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>  hw/scsi/esp.c | 52 ++++++++++++++++++++++++++++++---------------------
>  1 file changed, 31 insertions(+), 21 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index b84e0fe33e..7073166ad1 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -241,8 +241,9 @@ static void handle_satn(ESPState *s)
>      }
>      s->pdma_cb = satn_pdma_cb;
>      len = get_cmd(s, buf, sizeof(buf));
> -    if (len)
> +    if (len) {
>          do_cmd(s, buf);
> +    }
>  }
>  
>  static void s_without_satn_pdma_cb(ESPState *s)
> @@ -398,8 +399,8 @@ static void esp_do_dma(ESPState *s)
>           * handle_ti_cmd() with do_cmd != NULL (see the assert())
>           */
>          trace_esp_do_dma(s->cmdlen, len);
> -        assert (s->cmdlen <= sizeof(s->cmdbuf) &&
> -                len <= sizeof(s->cmdbuf) - s->cmdlen);
> +        assert(s->cmdlen <= sizeof(s->cmdbuf) &&
> +               len <= sizeof(s->cmdbuf) - s->cmdlen);
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
>          } else {
> @@ -445,15 +446,18 @@ static void esp_do_dma(ESPState *s)
>      s->dma_left -= len;
>      s->async_buf += len;
>      s->async_len -= len;
> -    if (to_device)
> +    if (to_device) {
>          s->ti_size += len;
> -    else
> +    } else {
>          s->ti_size -= len;
> +    }
>      if (s->async_len == 0) {
>          scsi_req_continue(s->current_req);
> -        /* If there is still data to be read from the device then
> -           complete the DMA operation immediately.  Otherwise defer
> -           until the scsi layer has completed.  */
> +        /*
> +         * If there is still data to be read from the device then
> +         * complete the DMA operation immediately.  Otherwise defer
> +         * until the scsi layer has completed.
> +         */
>          if (to_device || s->dma_left != 0 || s->ti_size == 0) {
>              return;
>          }
> @@ -491,7 +495,8 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
>      ESPState *s = req->hba_private;
>  
>      if (s->rregs[ESP_RSTAT] & STAT_INT) {
> -        /* Defer handling command complete until the previous
> +        /*
> +         * Defer handling command complete until the previous
>           * interrupt has been handled.
>           */
>          trace_esp_command_complete_deferred();
> @@ -513,8 +518,10 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
>      if (s->dma_left) {
>          esp_do_dma(s);
>      } else if (s->dma_counter != 0 && s->ti_size <= 0) {
> -        /* If this was the last part of a DMA transfer then the
> -           completion interrupt is deferred to here.  */
> +        /*
> +         * If this was the last part of a DMA transfer then the
> +         * completion interrupt is deferred to here.
> +         */
>          esp_dma_done(s);
>      }
>  }
> @@ -531,17 +538,18 @@ static void handle_ti(ESPState *s)
>      dmalen = s->rregs[ESP_TCLO];
>      dmalen |= s->rregs[ESP_TCMID] << 8;
>      dmalen |= s->rregs[ESP_TCHI] << 16;
> -    if (dmalen==0) {
> -      dmalen=0x10000;
> +    if (dmalen == 0) {
> +        dmalen = 0x10000;
>      }
>      s->dma_counter = dmalen;
>  
> -    if (s->do_cmd)
> +    if (s->do_cmd) {
>          minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
> -    else if (s->ti_size < 0)
> +    } else if (s->ti_size < 0) {
>          minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
> -    else
> +    } else {
>          minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
> +    }
>      trace_esp_handle_ti(minlen);
>      if (s->dma) {
>          s->dma_left = minlen;
> @@ -606,8 +614,10 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>          }
>          break;
>      case ESP_RINTR:
> -        /* Clear sequence step, interrupt register and all status bits
> -           except TC */
> +        /*
> +         * Clear sequence step, interrupt register and all status bits
> +         * except TC
> +         */
>          old_val = s->rregs[ESP_RINTR];
>          s->rregs[ESP_RINTR] = 0;
>          s->rregs[ESP_RSTAT] &= ~STAT_TC;
> @@ -665,13 +675,13 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          } else {
>              s->dma = 0;
>          }
> -        switch(val & CMD_CMD) {
> +        switch (val & CMD_CMD) {
>          case CMD_NOP:
>              trace_esp_mem_writeb_cmd_nop(val);
>              break;
>          case CMD_FLUSH:
>              trace_esp_mem_writeb_cmd_flush(val);
> -            //s->ti_size = 0;
> +            /*s->ti_size = 0;*/

Perhaps the line can simply be removed?

>              s->rregs[ESP_RINTR] = INTR_FC;
>              s->rregs[ESP_RSEQ] = 0;
>              s->rregs[ESP_RFLAGS] = 0;
> @@ -787,7 +797,7 @@ static const VMStateDescription vmstate_esp_pdma = {
>  };
>  
>  const VMStateDescription vmstate_esp = {
> -    .name ="esp",
> +    .name = "esp",
>      .version_id = 4,
>      .minimum_version_id = 3,
>      .fields = (VMStateField[]) {
> 

Anyway:

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


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

* Re: [PATCH v2 02/42] esp: rename existing ESP QOM type to SYSBUS_ESP
  2021-02-09 19:29 ` [PATCH v2 02/42] esp: rename existing ESP QOM type to SYSBUS_ESP Mark Cave-Ayland
  2021-02-10 22:29   ` Philippe Mathieu-Daudé
@ 2021-03-01 19:52   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 19:52 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> The existing ESP QOM type currently represents a sysbus device with an embedded
> ESP state. Rename the type to SYSBUS_ESP accordingly.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/dma/sparc32_dma.c  | 4 ++--
>  hw/m68k/q800.c        | 4 ++--
>  hw/mips/jazz.c        | 4 ++--
>  hw/scsi/esp.c         | 8 ++++----
>  hw/sparc/sun4m.c      | 2 +-
>  include/hw/scsi/esp.h | 4 ++--
>  6 files changed, 13 insertions(+), 13 deletions(-)
> 
> diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c
> index b643b413c5..03bc500878 100644
> --- a/hw/dma/sparc32_dma.c
> +++ b/hw/dma/sparc32_dma.c
> @@ -295,13 +295,13 @@ static void sparc32_espdma_device_init(Object *obj)
>      memory_region_init_io(&s->iomem, OBJECT(s), &dma_mem_ops, s,
>                            "espdma-mmio", DMA_SIZE);
>  
> -    object_initialize_child(obj, "esp", &es->esp, TYPE_ESP);
> +    object_initialize_child(obj, "esp", &es->esp, TYPE_SYSBUS_ESP);
>  }
>  
>  static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp)
>  {
>      ESPDMADeviceState *es = SPARC32_ESPDMA_DEVICE(dev);
> -    SysBusESPState *sysbus = ESP(&es->esp);
> +    SysBusESPState *sysbus = SYSBUS_ESP(&es->esp);
>      ESPState *esp = &sysbus->esp;
>  
>      esp->dma_memory_read = espdma_memory_read;
> diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
> index 2af0e2532e..af54d509ff 100644
> --- a/hw/m68k/q800.c
> +++ b/hw/m68k/q800.c
> @@ -356,8 +356,8 @@ static void q800_init(MachineState *machine)
>  
>      /* SCSI */
>  
> -    dev = qdev_new(TYPE_ESP);
> -    sysbus_esp = ESP(dev);
> +    dev = qdev_new(TYPE_SYSBUS_ESP);
> +    sysbus_esp = SYSBUS_ESP(dev);
>      esp = &sysbus_esp->esp;
>      esp->dma_memory_read = NULL;
>      esp->dma_memory_write = NULL;
> diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c
> index 83c8086062..1a0888a0fd 100644
> --- a/hw/mips/jazz.c
> +++ b/hw/mips/jazz.c
> @@ -328,8 +328,8 @@ static void mips_jazz_init(MachineState *machine,
>      }
>  
>      /* SCSI adapter */
> -    dev = qdev_new(TYPE_ESP);
> -    sysbus_esp = ESP(dev);
> +    dev = qdev_new(TYPE_SYSBUS_ESP);
> +    sysbus_esp = SYSBUS_ESP(dev);
>      esp = &sysbus_esp->esp;
>      esp->dma_memory_read = rc4030_dma_read;
>      esp->dma_memory_write = rc4030_dma_write;
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 7073166ad1..aa38acc660 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -939,7 +939,7 @@ static const struct SCSIBusInfo esp_scsi_info = {
>  
>  static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
>  {
> -    SysBusESPState *sysbus = ESP(opaque);
> +    SysBusESPState *sysbus = SYSBUS_ESP(opaque);
>      ESPState *s = &sysbus->esp;
>  
>      switch (irq) {
> @@ -955,7 +955,7 @@ static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
>  static void sysbus_esp_realize(DeviceState *dev, Error **errp)
>  {
>      SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> -    SysBusESPState *sysbus = ESP(dev);
> +    SysBusESPState *sysbus = SYSBUS_ESP(dev);
>      ESPState *s = &sysbus->esp;
>  
>      sysbus_init_irq(sbd, &s->irq);
> @@ -977,7 +977,7 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
>  
>  static void sysbus_esp_hard_reset(DeviceState *dev)
>  {
> -    SysBusESPState *sysbus = ESP(dev);
> +    SysBusESPState *sysbus = SYSBUS_ESP(dev);
>      esp_hard_reset(&sysbus->esp);
>  }
>  
> @@ -1002,7 +1002,7 @@ static void sysbus_esp_class_init(ObjectClass *klass, void *data)
>  }
>  
>  static const TypeInfo sysbus_esp_info = {
> -    .name          = TYPE_ESP,
> +    .name          = TYPE_SYSBUS_ESP,
>      .parent        = TYPE_SYS_BUS_DEVICE,
>      .instance_size = sizeof(SysBusESPState),
>      .class_init    = sysbus_esp_class_init,
> diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
> index 38ca1e33c7..312e2afaf9 100644
> --- a/hw/sparc/sun4m.c
> +++ b/hw/sparc/sun4m.c
> @@ -334,7 +334,7 @@ static void *sparc32_dma_init(hwaddr dma_base,
>                                     OBJECT(dma), "espdma"));
>      sysbus_connect_irq(SYS_BUS_DEVICE(espdma), 0, espdma_irq);
>  
> -    esp = ESP(object_resolve_path_component(OBJECT(espdma), "esp"));
> +    esp = SYSBUS_ESP(object_resolve_path_component(OBJECT(espdma), "esp"));
>  
>      ledma = SPARC32_LEDMA_DEVICE(object_resolve_path_component(
>                                   OBJECT(dma), "ledma"));
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 60cc3047a5..9694825e71 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -65,8 +65,8 @@ struct ESPState {
>      void (*pdma_cb)(ESPState *s);
>  };
>  
> -#define TYPE_ESP "esp"
> -OBJECT_DECLARE_SIMPLE_TYPE(SysBusESPState, ESP)
> +#define TYPE_SYSBUS_ESP "sysbus-esp"
> +OBJECT_DECLARE_SIMPLE_TYPE(SysBusESPState, SYSBUS_ESP)
>  
>  struct SysBusESPState {
>      /*< private >*/
> 

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


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

* Re: [PATCH v2 03/42] esp: QOMify the internal ESP device state
  2021-02-15 22:29     ` Mark Cave-Ayland
@ 2021-03-01 20:11       ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 20:11 UTC (permalink / raw)
  To: Mark Cave-Ayland, Philippe Mathieu-Daudé, qemu-devel, pbonzini, fam

Le 15/02/2021 à 23:29, Mark Cave-Ayland a écrit :
> On 12/02/2021 18:51, Philippe Mathieu-Daudé wrote:
> 
>> On 2/9/21 8:29 PM, Mark Cave-Ayland wrote:
>>> Make this new QOM device state a child device of both the sysbus-esp and esp-pci
>>> implementations.
>>>
>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>> ---
>>>   hw/scsi/esp-pci.c     | 48 +++++++++++++++++++++++++++++++------------
>>>   hw/scsi/esp.c         | 45 +++++++++++++++++++++++++++++++++-------
>>>   include/hw/scsi/esp.h |  5 +++++
>>>   3 files changed, 78 insertions(+), 20 deletions(-)
>>
>> Please setup scripts/git.orderfile ;)
> 
> I will have to take a look at this at some point - it has been on my TODO list for a while :)
> 
>>> @@ -354,9 +365,11 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
>>>   {
>>>       PCIESPState *pci = PCI_ESP(dev);
>>>       DeviceState *d = DEVICE(dev);
>>> -    ESPState *s = &pci->esp;
>>> +    ESPState *s = ESP(&pci->esp);
>>>       uint8_t *pci_conf;
>>>   +    qdev_realize(DEVICE(s), NULL, errp);
>>
>>         if (!qdev_realize(DEVICE(s), NULL, errp)) {
>>             return;
>>         }
>>
>>>       pci_conf = dev->config;
>>>         /* Interrupt pin A */
>>> @@ -375,11 +388,19 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
>>>       scsi_bus_new(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info, NULL);
>>>   }
>> ...
>>
>>> @@ -956,7 +958,9 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
>>>   {
>>>       SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
>>>       SysBusESPState *sysbus = SYSBUS_ESP(dev);
>>> -    ESPState *s = &sysbus->esp;
>>> +    ESPState *s = ESP(&sysbus->esp);
>>> +
>>> +    qdev_realize(DEVICE(s), NULL, errp);
>>
>>         if (!qdev_realize(DEVICE(s), NULL, errp)) {
>>             return;
>>         }
>>
>> With both if():
>> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> 
> Great! I've added the if() statements and added your R-B to the patch.

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


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

* Re: [PATCH v2 04/42] esp: add vmstate_esp version to embedded ESPState
  2021-02-09 19:29 ` [PATCH v2 04/42] esp: add vmstate_esp version to embedded ESPState Mark Cave-Ayland
  2021-02-16  7:35   ` Philippe Mathieu-Daudé
@ 2021-03-01 20:21   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 20:21 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> The QOM object representing ESPState is currently embedded within both the
> SYSBUS_ESP and PCI_ESP devices with migration state handled by embedding
> vmstate_esp within each device using VMSTATE_STRUCT.
> 
> Since the vmstate_esp fields are embedded directly within the migration
> stream, the incoming vmstate_esp version_id is lost. The only version information
> available is that from vmstate_sysbus_esp_scsi and vmstate_esp_pci_scsi, but
> those versions represent their respective devices and not that of the underlying
> ESPState.
> 
> Resolve this by adding a new version-dependent field in vmstate_sysbus_esp_scsi
> and vmstate_esp_pci_scsi which stores the vmstate_esp version_id field within
> ESPState to be used to allow migration from older QEMU versions.
> 
> Finally bump the vmstate_esp version to 5 to cover the upcoming ESPState changes
> within this patch series.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp-pci.c     |  3 ++-
>  hw/scsi/esp.c         | 23 +++++++++++++++++++++--
>  include/hw/scsi/esp.h |  2 ++
>  3 files changed, 25 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
> index ccf73bb901..8a82404853 100644
> --- a/hw/scsi/esp-pci.c
> +++ b/hw/scsi/esp-pci.c
> @@ -330,11 +330,12 @@ static void esp_pci_hard_reset(DeviceState *dev)
>  
>  static const VMStateDescription vmstate_esp_pci_scsi = {
>      .name = "pciespscsi",
> -    .version_id = 1,
> +    .version_id = 2,
>      .minimum_version_id = 1,
>      .fields = (VMStateField[]) {
>          VMSTATE_PCI_DEVICE(parent_obj, PCIESPState),
>          VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
> +        VMSTATE_UINT8_V(esp.mig_version_id, PCIESPState, 2),
>          VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
>          VMSTATE_END_OF_LIST()
>      }
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 1635f86622..9427c55d1d 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -796,10 +796,28 @@ static const VMStateDescription vmstate_esp_pdma = {
>      }
>  };
>  
> +static int esp_pre_save(void *opaque)
> +{
> +    ESPState *s = ESP(opaque);
> +
> +    s->mig_version_id = vmstate_esp.version_id;
> +    return 0;
> +}
> +
> +static int esp_post_load(void *opaque, int version_id)
> +{
> +    ESPState *s = ESP(opaque);
> +
> +    s->mig_version_id = vmstate_esp.version_id;
> +    return 0;
> +}
> +
>  const VMStateDescription vmstate_esp = {
>      .name = "esp",
> -    .version_id = 4,
> +    .version_id = 5,
>      .minimum_version_id = 3,
> +    .pre_save = esp_pre_save,
> +    .post_load = esp_post_load,
>      .fields = (VMStateField[]) {
>          VMSTATE_BUFFER(rregs, ESPState),
>          VMSTATE_BUFFER(wregs, ESPState),
> @@ -996,9 +1014,10 @@ static void sysbus_esp_init(Object *obj)
>  
>  static const VMStateDescription vmstate_sysbus_esp_scsi = {
>      .name = "sysbusespscsi",
> -    .version_id = 1,
> +    .version_id = 2,
>      .minimum_version_id = 1,
>      .fields = (VMStateField[]) {
> +        VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2),
>          VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
>          VMSTATE_END_OF_LIST()
>      }
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 11c799d91e..7d92471c5b 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -68,6 +68,8 @@ struct ESPState {
>      uint32_t pdma_start;
>      uint32_t pdma_cur;
>      void (*pdma_cb)(ESPState *s);
> +
> +    uint8_t mig_version_id;
>  };
>  
>  #define TYPE_SYSBUS_ESP "sysbus-esp"
> 

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


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

* Re: [PATCH v2 05/42] esp: add trace event when receiving a TI command
  2021-02-09 19:29 ` [PATCH v2 05/42] esp: add trace event when receiving a TI command Mark Cave-Ayland
@ 2021-03-01 20:24   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 20:24 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> This enables us to determine whether the command being issued is for a DMA or a
> non-DMA transfer.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>  hw/scsi/esp.c        | 1 +
>  hw/scsi/trace-events | 1 +
>  2 files changed, 2 insertions(+)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 9427c55d1d..9951472ee6 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -698,6 +698,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>              }
>              break;
>          case CMD_TI:
> +            trace_esp_mem_writeb_cmd_ti(val);
>              handle_ti(s);
>              break;
>          case CMD_ICCS:
> diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
> index 0e0aa9847d..762849c7b6 100644
> --- a/hw/scsi/trace-events
> +++ b/hw/scsi/trace-events
> @@ -189,6 +189,7 @@ esp_mem_writeb_cmd_selatn(uint32_t val) "Select with ATN (0x%2.2x)"
>  esp_mem_writeb_cmd_selatns(uint32_t val) "Select with ATN & stop (0x%2.2x)"
>  esp_mem_writeb_cmd_ensel(uint32_t val) "Enable selection (0x%2.2x)"
>  esp_mem_writeb_cmd_dissel(uint32_t val) "Disable selection (0x%2.2x)"
> +esp_mem_writeb_cmd_ti(uint32_t val) "Transfer Information (0x%2.2x)"
>  
>  # esp-pci.c
>  esp_pci_error_invalid_dma_direction(void) "invalid DMA transfer direction"
> 

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


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

* Re: [PATCH v2 06/42] esp: fix esp_reg_read() trace event
  2021-02-09 19:29 ` [PATCH v2 06/42] esp: fix esp_reg_read() trace event Mark Cave-Ayland
@ 2021-03-01 20:29   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 20:29 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> Move the trace event to the end of the function so that it correctly reports
> the returned value if it doesn't come directly from the rregs array.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>  hw/scsi/esp.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 9951472ee6..c36cb0f238 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -595,9 +595,8 @@ static void parent_esp_reset(ESPState *s, int irq, int level)
>  
>  uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>  {
> -    uint32_t old_val;
> +    uint32_t val;
>  
> -    trace_esp_mem_readb(saddr, s->rregs[saddr]);
>      switch (saddr) {
>      case ESP_FIFO:
>          if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
> @@ -612,13 +611,14 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>              s->ti_rptr = 0;
>              s->ti_wptr = 0;
>          }
> +        val = s->rregs[ESP_FIFO];
>          break;
>      case ESP_RINTR:
>          /*
>           * Clear sequence step, interrupt register and all status bits
>           * except TC
>           */
> -        old_val = s->rregs[ESP_RINTR];
> +        val = s->rregs[ESP_RINTR];
>          s->rregs[ESP_RINTR] = 0;
>          s->rregs[ESP_RSTAT] &= ~STAT_TC;
>          s->rregs[ESP_RSEQ] = SEQ_CD;
> @@ -627,16 +627,22 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>              esp_report_command_complete(s, s->deferred_status);
>              s->deferred_complete = false;
>          }
> -        return old_val;
> +        break;
>      case ESP_TCHI:
>          /* Return the unique id if the value has never been written */
>          if (!s->tchi_written) {
> -            return s->chip_id;
> +            val = s->chip_id;
> +        } else {
> +            val = s->rregs[saddr];
>          }
> +        break;
>      default:
> +        val = s->rregs[saddr];
>          break;
>      }
> -    return s->rregs[saddr];
> +
> +    trace_esp_mem_readb(saddr, val);
> +    return val;
>  }
>  
>  void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
> 

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


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

* Re: [PATCH v2 07/42] esp: add PDMA trace events
  2021-02-09 19:29 ` [PATCH v2 07/42] esp: add PDMA trace events Mark Cave-Ayland
@ 2021-03-01 20:32   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 20:32 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> This will become more useful later when trying to debug mixed FIFO and PDMA
> requests.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>  hw/scsi/esp.c        | 6 ++++++
>  hw/scsi/trace-events | 4 ++++
>  2 files changed, 10 insertions(+)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index c36cb0f238..db2ea02549 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -63,11 +63,13 @@ static void esp_lower_irq(ESPState *s)
>  static void esp_raise_drq(ESPState *s)
>  {
>      qemu_irq_raise(s->irq_data);
> +    trace_esp_raise_drq();
>  }
>  
>  static void esp_lower_drq(ESPState *s)
>  {
>      qemu_irq_lower(s->irq_data);
> +    trace_esp_lower_drq();
>  }
>  
>  void esp_dma_enable(ESPState *s, int irq, int level)
> @@ -886,6 +888,8 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>      uint32_t dmalen;
>      uint8_t *buf = get_pdma_buf(s);
>  
> +    trace_esp_pdma_write(size);
> +
>      dmalen = s->rregs[ESP_TCLO];
>      dmalen |= s->rregs[ESP_TCMID] << 8;
>      dmalen |= s->rregs[ESP_TCHI] << 16;
> @@ -923,6 +927,8 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>      uint8_t *buf = get_pdma_buf(s);
>      uint64_t val = 0;
>  
> +    trace_esp_pdma_read(size);
> +
>      if (s->pdma_len == 0) {
>          return 0;
>      }
> diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
> index 762849c7b6..dff986a643 100644
> --- a/hw/scsi/trace-events
> +++ b/hw/scsi/trace-events
> @@ -159,8 +159,12 @@ esp_error_unhandled_command(uint32_t val) "unhandled command (0x%2.2x)"
>  esp_error_invalid_write(uint32_t val, uint32_t addr) "invalid write of 0x%02x at [0x%x]"
>  esp_raise_irq(void) "Raise IRQ"
>  esp_lower_irq(void) "Lower IRQ"
> +esp_raise_drq(void) "Raise DREQ"
> +esp_lower_drq(void) "Lower DREQ"
>  esp_dma_enable(void) "Raise enable"
>  esp_dma_disable(void) "Lower enable"
> +esp_pdma_read(int size) "pDMA read %u bytes"
> +esp_pdma_write(int size) "pDMA write %u bytes"
>  esp_get_cmd(uint32_t dmalen, int target) "len %d target %d"
>  esp_do_busid_cmd(uint8_t busid) "busid 0x%x"
>  esp_handle_satn_stop(uint32_t cmdlen) "cmdlen %d"
> 

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


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

* Re: [PATCH v2 08/42] esp: determine transfer direction directly from SCSI phase
  2021-02-09 19:29 ` [PATCH v2 08/42] esp: determine transfer direction directly from SCSI phase Mark Cave-Ayland
  2021-02-16  7:36   ` Philippe Mathieu-Daudé
@ 2021-03-01 21:18   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 21:18 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> The transfer direction is currently determined by checking the sign of ti_size
> but as this series progresses ti_size can be zero at the end of the transfer.
> 
> Use the SCSI phase to determine the transfer direction as used in other SCSI
> controller implementations.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index db2ea02549..e82e75d490 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -356,7 +356,7 @@ static void esp_dma_done(ESPState *s)
>  
>  static void do_dma_pdma_cb(ESPState *s)
>  {
> -    int to_device = (s->ti_size < 0);
> +    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
>      int len = s->pdma_cur - s->pdma_start;
>      if (s->do_cmd) {
>          s->ti_size = 0;
> @@ -392,7 +392,7 @@ static void do_dma_pdma_cb(ESPState *s)
>  static void esp_do_dma(ESPState *s)
>  {
>      uint32_t len;
> -    int to_device;
> +    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
>  
>      len = s->dma_left;
>      if (s->do_cmd) {
> @@ -425,7 +425,6 @@ static void esp_do_dma(ESPState *s)
>      if (len > s->async_len) {
>          len = s->async_len;
>      }
> -    to_device = (s->ti_size < 0);
>      if (to_device) {
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, s->async_buf, len);
> 

Reviewed-by: Laurent Vivier <laurent@vivier.Eu>


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

* Re: [PATCH v2 09/42] esp: introduce esp_get_tc() and esp_set_tc()
  2021-02-09 19:29 ` [PATCH v2 09/42] esp: introduce esp_get_tc() and esp_set_tc() Mark Cave-Ayland
@ 2021-03-01 21:24   ` Laurent Vivier
  2021-03-03  8:35     ` Mark Cave-Ayland
  0 siblings, 1 reply; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 21:24 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> This simplifies reading and writing the TC register value without having to
> manually shift each individual 8-bit value.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>  hw/scsi/esp.c | 38 +++++++++++++++++++++++---------------
>  1 file changed, 23 insertions(+), 15 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index e82e75d490..3a39450930 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -98,6 +98,24 @@ void esp_request_cancelled(SCSIRequest *req)
>      }
>  }
>  
> +static uint32_t esp_get_tc(ESPState *s)
> +{
> +    uint32_t dmalen;
> +
> +    dmalen = s->rregs[ESP_TCLO];
> +    dmalen |= s->rregs[ESP_TCMID] << 8;
> +    dmalen |= s->rregs[ESP_TCHI] << 16;
> +
> +    return dmalen;
> +}
> +
> +static void esp_set_tc(ESPState *s, uint32_t dmalen)
> +{
> +    s->rregs[ESP_TCLO] = dmalen & 0xff;

The "& 0xff" is not needed as rregs is uint8_t.

> +    s->rregs[ESP_TCMID] = dmalen >> 8;
> +    s->rregs[ESP_TCHI] = dmalen >> 16;
> +}
> +
>  static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>                       uint32_t index, uint32_t len)
>  {
> @@ -157,9 +175,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
>  
>      target = s->wregs[ESP_WBUSID] & BUSID_DID;
>      if (s->dma) {
> -        dmalen = s->rregs[ESP_TCLO];
> -        dmalen |= s->rregs[ESP_TCMID] << 8;
> -        dmalen |= s->rregs[ESP_TCHI] << 16;
> +        dmalen = esp_get_tc(s);
>          if (dmalen > buflen) {
>              return 0;
>          }
> @@ -348,9 +364,7 @@ static void esp_dma_done(ESPState *s)
>      s->rregs[ESP_RINTR] = INTR_BS;
>      s->rregs[ESP_RSEQ] = 0;
>      s->rregs[ESP_RFLAGS] = 0;
> -    s->rregs[ESP_TCLO] = 0;
> -    s->rregs[ESP_TCMID] = 0;
> -    s->rregs[ESP_TCHI] = 0;
> +    esp_set_tc(s, 0);
>      esp_raise_irq(s);
>  }
>  
> @@ -536,9 +550,7 @@ static void handle_ti(ESPState *s)
>          return;
>      }
>  
> -    dmalen = s->rregs[ESP_TCLO];
> -    dmalen |= s->rregs[ESP_TCMID] << 8;
> -    dmalen |= s->rregs[ESP_TCHI] << 16;
> +    dmalen = esp_get_tc(s);
>      if (dmalen == 0) {
>          dmalen = 0x10000;
>      }
> @@ -889,9 +901,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>  
>      trace_esp_pdma_write(size);
>  
> -    dmalen = s->rregs[ESP_TCLO];
> -    dmalen |= s->rregs[ESP_TCMID] << 8;
> -    dmalen |= s->rregs[ESP_TCHI] << 16;
> +    dmalen = esp_get_tc(s);
>      if (dmalen == 0 || s->pdma_len == 0) {
>          return;
>      }
> @@ -908,9 +918,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>          dmalen -= 2;
>          break;
>      }
> -    s->rregs[ESP_TCLO] = dmalen & 0xff;
> -    s->rregs[ESP_TCMID] = dmalen >> 8;
> -    s->rregs[ESP_TCHI] = dmalen >> 16;
> +    esp_set_tc(s, dmalen);
>      if (s->pdma_len == 0 && s->pdma_cb) {
>          esp_lower_drq(s);
>          s->pdma_cb(s);
> 

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


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

* Re: [PATCH v2 10/42] esp: introduce esp_get_stc()
  2021-02-09 19:29 ` [PATCH v2 10/42] esp: introduce esp_get_stc() Mark Cave-Ayland
  2021-02-10 22:33   ` Philippe Mathieu-Daudé
@ 2021-03-01 21:28   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 21:28 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> This simplifies reading the STC register value without having to manually shift
> each individual 8-bit value.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 3a39450930..a1acc2c9bd 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -116,6 +116,17 @@ static void esp_set_tc(ESPState *s, uint32_t dmalen)
>      s->rregs[ESP_TCHI] = dmalen >> 16;
>  }
>  
> +static uint32_t esp_get_stc(ESPState *s)
> +{
> +    uint32_t dmalen;
> +
> +    dmalen = s->wregs[ESP_TCLO];
> +    dmalen |= s->wregs[ESP_TCMID] << 8;
> +    dmalen |= s->wregs[ESP_TCHI] << 16;
> +
> +    return dmalen;
> +}
> +
>  static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>                       uint32_t index, uint32_t len)
>  {
> @@ -688,9 +699,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          if (val & CMD_DMA) {
>              s->dma = 1;
>              /* Reload DMA counter.  */
> -            s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
> -            s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
> -            s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
> +            esp_set_tc(s, esp_get_stc(s));
>          } else {
>              s->dma = 0;
>          }
> 

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


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

* Re: [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time
  2021-02-09 19:29 ` [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time Mark Cave-Ayland
  2021-02-16  7:33   ` Philippe Mathieu-Daudé
@ 2021-03-01 21:35   ` Laurent Vivier
  2021-03-03  8:44     ` Mark Cave-Ayland
  1 sibling, 1 reply; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 21:35 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> Perform the length adjustment whereby a value of 0 in the STC represents
> a transfer length of 0x10000 at the point where the TC is loaded at the
> start of a DMA command rather than just when a TI (Transfer Information)
> command is executed. This better matches the description as given in the
> datasheet.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index a1acc2c9bd..02b7876394 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -562,9 +562,6 @@ static void handle_ti(ESPState *s)
>      }
>  
>      dmalen = esp_get_tc(s);
> -    if (dmalen == 0) {
> -        dmalen = 0x10000;
> -    }
>      s->dma_counter = dmalen;
>  
>      if (s->do_cmd) {
> @@ -699,7 +696,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          if (val & CMD_DMA) {
>              s->dma = 1;
>              /* Reload DMA counter.  */
> -            esp_set_tc(s, esp_get_stc(s));
> +            if (esp_get_stc(s) == 0) {
> +                esp_set_tc(s, 0x10000);
> +            } else {
> +                esp_set_tc(s, esp_get_stc(s));
> +            }

More fun?

    esp_set_tc(s, esp_get_stc(s) ?: 0x10000);

>          } else {
>              s->dma = 0;
>          }
> 

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


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

* Re: [PATCH v2 12/42] esp: remove dma_counter from ESPState
  2021-02-09 19:29 ` [PATCH v2 12/42] esp: remove dma_counter from ESPState Mark Cave-Ayland
  2021-02-10 22:37   ` Philippe Mathieu-Daudé
@ 2021-03-01 21:44   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 21:44 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> The value of dma_counter is set once at the start of the transfer and remains
> the same until the transfer is complete. This allows the check in esp_transfer_data
> to be simplified since dma_left will always be non-zero until the transfer is
> completed.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 4 +---
>  include/hw/scsi/esp.h | 3 ---
>  2 files changed, 1 insertion(+), 6 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 02b7876394..6c495b29c0 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -229,7 +229,6 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
>      if (datalen != 0) {
>          s->rregs[ESP_RSTAT] = STAT_TC;
>          s->dma_left = 0;
> -        s->dma_counter = 0;
>          if (datalen > 0) {
>              s->rregs[ESP_RSTAT] |= STAT_DI;
>          } else {
> @@ -543,7 +542,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
>      s->async_buf = scsi_req_get_buf(req);
>      if (s->dma_left) {
>          esp_do_dma(s);
> -    } else if (s->dma_counter != 0 && s->ti_size <= 0) {
> +    } else if (s->ti_size <= 0) {
>          /*
>           * If this was the last part of a DMA transfer then the
>           * completion interrupt is deferred to here.
> @@ -562,7 +561,6 @@ static void handle_ti(ESPState *s)
>      }
>  
>      dmalen = esp_get_tc(s);
> -    s->dma_counter = dmalen;
>  
>      if (s->do_cmd) {
>          minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 7d92471c5b..b313ef27f2 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -50,9 +50,6 @@ struct ESPState {
>  
>      /* The amount of data left in the current DMA transfer.  */
>      uint32_t dma_left;
> -    /* The size of the current DMA transfer.  Zero if no transfer is in
> -       progress.  */
> -    uint32_t dma_counter;
>      int dma_enabled;
>  
>      uint32_t async_len;
> 

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


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

* Re: [PATCH v2 13/42] esp: remove dma_left from ESPState
  2021-02-09 19:29 ` [PATCH v2 13/42] esp: remove dma_left " Mark Cave-Ayland
  2021-02-23 21:22   ` Philippe Mathieu-Daudé
@ 2021-03-01 21:50   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 21:50 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> The ESP device already keeps track of the remaining bytes left to transfer via
> its TC (transfer counter) register which is decremented for each byte that
> is transferred across the SCSI bus.
> 
> Switch the transfer logic to use the value of TC instead of dma_left and then
> remove dma_left completely, adding logic to the vmstate_esp post_load() function
> to transfer the old dma_left value to the TC register during migration from
> older versions.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 47 ++++++++++++++++++++++++++++---------------
>  include/hw/scsi/esp.h |  5 +++--
>  2 files changed, 34 insertions(+), 18 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 6c495b29c0..fcc99f5fe4 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -228,7 +228,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
>      s->ti_size = datalen;
>      if (datalen != 0) {
>          s->rregs[ESP_RSTAT] = STAT_TC;
> -        s->dma_left = 0;
> +        esp_set_tc(s, 0);
>          if (datalen > 0) {
>              s->rregs[ESP_RSTAT] |= STAT_DI;
>          } else {
> @@ -382,6 +382,7 @@ static void do_dma_pdma_cb(ESPState *s)
>  {
>      int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
>      int len = s->pdma_cur - s->pdma_start;
> +
>      if (s->do_cmd) {
>          s->ti_size = 0;
>          s->cmdlen = 0;
> @@ -389,7 +390,6 @@ static void do_dma_pdma_cb(ESPState *s)
>          do_cmd(s, s->cmdbuf);
>          return;
>      }
> -    s->dma_left -= len;
>      s->async_buf += len;
>      s->async_len -= len;
>      if (to_device) {
> @@ -404,7 +404,7 @@ static void do_dma_pdma_cb(ESPState *s)
>           * complete the DMA operation immediately.  Otherwise defer
>           * until the scsi layer has completed.
>           */
> -        if (to_device || s->dma_left != 0 || s->ti_size == 0) {
> +        if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) {
>              return;
>          }
>      }
> @@ -418,7 +418,7 @@ static void esp_do_dma(ESPState *s)
>      uint32_t len;
>      int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
>  
> -    len = s->dma_left;
> +    len = esp_get_tc(s);
>      if (s->do_cmd) {
>          /*
>           * handle_ti_cmd() case: esp_do_dma() is called only from
> @@ -468,7 +468,7 @@ static void esp_do_dma(ESPState *s)
>              return;
>          }
>      }
> -    s->dma_left -= len;
> +    esp_set_tc(s, esp_get_tc(s) - len);
>      s->async_buf += len;
>      s->async_len -= len;
>      if (to_device) {
> @@ -483,7 +483,7 @@ static void esp_do_dma(ESPState *s)
>           * complete the DMA operation immediately.  Otherwise defer
>           * until the scsi layer has completed.
>           */
> -        if (to_device || s->dma_left != 0 || s->ti_size == 0) {
> +        if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) {
>              return;
>          }
>      }
> @@ -499,7 +499,6 @@ static void esp_report_command_complete(ESPState *s, uint32_t status)
>          trace_esp_command_complete_unexpected();
>      }
>      s->ti_size = 0;
> -    s->dma_left = 0;
>      s->async_len = 0;
>      if (status) {
>          trace_esp_command_complete_fail();
> @@ -535,12 +534,13 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
>  void esp_transfer_data(SCSIRequest *req, uint32_t len)
>  {
>      ESPState *s = req->hba_private;
> +    uint32_t dmalen = esp_get_tc(s);
>  
>      assert(!s->do_cmd);
> -    trace_esp_transfer_data(s->dma_left, s->ti_size);
> +    trace_esp_transfer_data(dmalen, s->ti_size);
>      s->async_len = len;
>      s->async_buf = scsi_req_get_buf(req);
> -    if (s->dma_left) {
> +    if (dmalen) {
>          esp_do_dma(s);
>      } else if (s->ti_size <= 0) {
>          /*
> @@ -571,7 +571,6 @@ static void handle_ti(ESPState *s)
>      }
>      trace_esp_handle_ti(minlen);
>      if (s->dma) {
> -        s->dma_left = minlen;
>          s->rregs[ESP_RSTAT] &= ~STAT_TC;
>          esp_do_dma(s);
>      } else if (s->do_cmd) {
> @@ -824,6 +823,14 @@ static const VMStateDescription vmstate_esp_pdma = {
>      }
>  };
>  
> +static bool esp_is_before_version_5(void *opaque, int version_id)
> +{
> +    ESPState *s = ESP(opaque);
> +
> +    version_id = MIN(version_id, s->mig_version_id);
> +    return version_id < 5;
> +}
> +
>  static int esp_pre_save(void *opaque)
>  {
>      ESPState *s = ESP(opaque);
> @@ -836,6 +843,12 @@ static int esp_post_load(void *opaque, int version_id)
>  {
>      ESPState *s = ESP(opaque);
>  
> +    version_id = MIN(version_id, s->mig_version_id);
> +
> +    if (version_id < 5) {
> +        esp_set_tc(s, s->mig_dma_left);
> +    }
> +
>      s->mig_version_id = vmstate_esp.version_id;
>      return 0;
>  }
> @@ -861,7 +874,7 @@ const VMStateDescription vmstate_esp = {
>          VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
>          VMSTATE_UINT32(cmdlen, ESPState),
>          VMSTATE_UINT32(do_cmd, ESPState),
> -        VMSTATE_UINT32(dma_left, ESPState),
> +        VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
>          VMSTATE_END_OF_LIST()
>      },
>      .subsections = (const VMStateDescription * []) {
> @@ -904,12 +917,11 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>  {
>      SysBusESPState *sysbus = opaque;
>      ESPState *s = ESP(&sysbus->esp);
> -    uint32_t dmalen;
> +    uint32_t dmalen = esp_get_tc(s);
>      uint8_t *buf = get_pdma_buf(s);
>  
>      trace_esp_pdma_write(size);
>  
> -    dmalen = esp_get_tc(s);
>      if (dmalen == 0 || s->pdma_len == 0) {
>          return;
>      }
> @@ -939,27 +951,30 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>  {
>      SysBusESPState *sysbus = opaque;
>      ESPState *s = ESP(&sysbus->esp);
> +    uint32_t dmalen = esp_get_tc(s);
>      uint8_t *buf = get_pdma_buf(s);
>      uint64_t val = 0;
>  
>      trace_esp_pdma_read(size);
>  
> -    if (s->pdma_len == 0) {
> +    if (dmalen == 0 || s->pdma_len == 0) {
>          return 0;
>      }
>      switch (size) {
>      case 1:
>          val = buf[s->pdma_cur++];
>          s->pdma_len--;
> +        dmalen--;
>          break;
>      case 2:
>          val = buf[s->pdma_cur++];
>          val = (val << 8) | buf[s->pdma_cur++];
>          s->pdma_len -= 2;
> +        dmalen -= 2;
>          break;
>      }
> -
> -    if (s->pdma_len == 0 && s->pdma_cb) {
> +    esp_set_tc(s, dmalen);
> +    if (dmalen == 0 || (s->pdma_len == 0 && s->pdma_cb)) {
>          esp_lower_drq(s);
>          s->pdma_cb(s);
>          s->pdma_cb = NULL;
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index b313ef27f2..9fad320513 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -48,8 +48,6 @@ struct ESPState {
>      uint32_t cmdlen;
>      uint32_t do_cmd;
>  
> -    /* The amount of data left in the current DMA transfer.  */
> -    uint32_t dma_left;
>      int dma_enabled;
>  
>      uint32_t async_len;
> @@ -67,6 +65,9 @@ struct ESPState {
>      void (*pdma_cb)(ESPState *s);
>  
>      uint8_t mig_version_id;
> +
> +    /* Legacy fields for vmstate_esp version < 5 */
> +    uint32_t mig_dma_left;
>  };
>  
>  #define TYPE_SYSBUS_ESP "sysbus-esp"
> 

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


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

* Re: [PATCH v2 14/42] esp: remove minlen restriction in handle_ti
  2021-02-09 19:29 ` [PATCH v2 14/42] esp: remove minlen restriction in handle_ti Mark Cave-Ayland
  2021-02-23 18:24   ` Philippe Mathieu-Daudé
@ 2021-03-01 22:04   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 22:04 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> The limiting of DMA transfers to the maximum size of the available data is already
> handled by esp_do_dma() and do_dma_pdma_cb().
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 12 ++----------
>  1 file changed, 2 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index fcc99f5fe4..e7cf36f4b8 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -553,7 +553,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
>  
>  static void handle_ti(ESPState *s)
>  {
> -    uint32_t dmalen, minlen;
> +    uint32_t dmalen;
>  
>      if (s->dma && !s->dma_enabled) {
>          s->dma_cb = handle_ti;
> @@ -561,16 +561,8 @@ static void handle_ti(ESPState *s)
>      }
>  
>      dmalen = esp_get_tc(s);
> -
> -    if (s->do_cmd) {
> -        minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
> -    } else if (s->ti_size < 0) {
> -        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
> -    } else {
> -        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
> -    }
> -    trace_esp_handle_ti(minlen);
>      if (s->dma) {
> +        trace_esp_handle_ti(dmalen);
>          s->rregs[ESP_RSTAT] &= ~STAT_TC;
>          esp_do_dma(s);
>      } else if (s->do_cmd) {
> 

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


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

* Re: [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions
  2021-02-09 19:29 ` [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions Mark Cave-Ayland
  2021-02-10 22:51   ` Philippe Mathieu-Daudé
@ 2021-03-01 22:06   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 22:06 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 28 ++++++++++++++++++++--------
>  1 file changed, 20 insertions(+), 8 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index e7cf36f4b8..b0cba889a9 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -151,6 +151,20 @@ static uint8_t *get_pdma_buf(ESPState *s)
>      return NULL;
>  }
>  
> +static uint8_t esp_pdma_read(ESPState *s)
> +{
> +    uint8_t *buf = get_pdma_buf(s);
> +
> +    return buf[s->pdma_cur++];
> +}
> +
> +static void esp_pdma_write(ESPState *s, uint8_t val)
> +{
> +    uint8_t *buf = get_pdma_buf(s);
> +
> +    buf[s->pdma_cur++] = val;
> +}
> +
>  static int get_cmd_cb(ESPState *s)
>  {
>      int target;
> @@ -910,7 +924,6 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>      SysBusESPState *sysbus = opaque;
>      ESPState *s = ESP(&sysbus->esp);
>      uint32_t dmalen = esp_get_tc(s);
> -    uint8_t *buf = get_pdma_buf(s);
>  
>      trace_esp_pdma_write(size);
>  
> @@ -919,13 +932,13 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>      }
>      switch (size) {
>      case 1:
> -        buf[s->pdma_cur++] = val;
> +        esp_pdma_write(s, val);
>          s->pdma_len--;
>          dmalen--;
>          break;
>      case 2:
> -        buf[s->pdma_cur++] = val >> 8;
> -        buf[s->pdma_cur++] = val;
> +        esp_pdma_write(s, val >> 8);
> +        esp_pdma_write(s, val);
>          s->pdma_len -= 2;
>          dmalen -= 2;
>          break;
> @@ -944,7 +957,6 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>      SysBusESPState *sysbus = opaque;
>      ESPState *s = ESP(&sysbus->esp);
>      uint32_t dmalen = esp_get_tc(s);
> -    uint8_t *buf = get_pdma_buf(s);
>      uint64_t val = 0;
>  
>      trace_esp_pdma_read(size);
> @@ -954,13 +966,13 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>      }
>      switch (size) {
>      case 1:
> -        val = buf[s->pdma_cur++];
> +        val = esp_pdma_read(s);
>          s->pdma_len--;
>          dmalen--;
>          break;
>      case 2:
> -        val = buf[s->pdma_cur++];
> -        val = (val << 8) | buf[s->pdma_cur++];
> +        val = esp_pdma_read(s);
> +        val = (val << 8) | esp_pdma_read(s);
>          s->pdma_len -= 2;
>          dmalen -= 2;
>          break;
> 

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


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

* Re: [PATCH v2 16/42] esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write()
  2021-02-09 19:29 ` [PATCH v2 16/42] esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
  2021-02-23 18:25   ` Philippe Mathieu-Daudé
@ 2021-03-01 22:07   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 22:07 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> This is the first step in removing get_pdma_buf() from esp.c.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 34 ++++++++++++++++++++++++++++------
>  1 file changed, 28 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index b0cba889a9..cfeba2feb0 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -153,16 +153,38 @@ static uint8_t *get_pdma_buf(ESPState *s)
>  
>  static uint8_t esp_pdma_read(ESPState *s)
>  {
> -    uint8_t *buf = get_pdma_buf(s);
> -
> -    return buf[s->pdma_cur++];
> +    switch (s->pdma_origin) {
> +    case PDMA:
> +        return s->pdma_buf[s->pdma_cur++];
> +    case TI:
> +        return s->ti_buf[s->pdma_cur++];
> +    case CMD:
> +        return s->cmdbuf[s->pdma_cur++];
> +    case ASYNC:
> +        return s->async_buf[s->pdma_cur++];
> +    default:
> +        g_assert_not_reached();
> +    }
>  }
>  
>  static void esp_pdma_write(ESPState *s, uint8_t val)
>  {
> -    uint8_t *buf = get_pdma_buf(s);
> -
> -    buf[s->pdma_cur++] = val;
> +    switch (s->pdma_origin) {
> +    case PDMA:
> +        s->pdma_buf[s->pdma_cur++] = val;
> +        break;
> +    case TI:
> +        s->ti_buf[s->pdma_cur++] = val;
> +        break;
> +    case CMD:
> +        s->cmdbuf[s->pdma_cur++] = val;
> +        break;
> +    case ASYNC:
> +        s->async_buf[s->pdma_cur++] = val;
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
>  }
>  
>  static int get_cmd_cb(ESPState *s)
> 

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


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

* Re: [PATCH v2 17/42] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write()
  2021-02-09 19:29 ` [PATCH v2 17/42] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
  2021-02-23 21:23   ` Philippe Mathieu-Daudé
@ 2021-03-01 22:09   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-01 22:09 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 50 ++++++++++++++++++++++++++++++++------------------
>  1 file changed, 32 insertions(+), 18 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index cfeba2feb0..7134c0aff4 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -153,22 +153,45 @@ static uint8_t *get_pdma_buf(ESPState *s)
>  
>  static uint8_t esp_pdma_read(ESPState *s)
>  {
> +    uint32_t dmalen = esp_get_tc(s);
> +    uint8_t val;
> +
> +    if (dmalen == 0 || s->pdma_len == 0) {
> +        return 0;
> +    }
> +
>      switch (s->pdma_origin) {
>      case PDMA:
> -        return s->pdma_buf[s->pdma_cur++];
> +        val = s->pdma_buf[s->pdma_cur++];
> +        break;
>      case TI:
> -        return s->ti_buf[s->pdma_cur++];
> +        val = s->ti_buf[s->pdma_cur++];
> +        break;
>      case CMD:
> -        return s->cmdbuf[s->pdma_cur++];
> +        val = s->cmdbuf[s->pdma_cur++];
> +        break;
>      case ASYNC:
> -        return s->async_buf[s->pdma_cur++];
> +        val = s->async_buf[s->pdma_cur++];
> +        break;
>      default:
>          g_assert_not_reached();
>      }
> +
> +    s->pdma_len--;
> +    dmalen--;
> +    esp_set_tc(s, dmalen);
> +
> +    return val;
>  }
>  
>  static void esp_pdma_write(ESPState *s, uint8_t val)
>  {
> +    uint32_t dmalen = esp_get_tc(s);
> +
> +    if (dmalen == 0 || s->pdma_len == 0) {
> +        return;
> +    }
> +
>      switch (s->pdma_origin) {
>      case PDMA:
>          s->pdma_buf[s->pdma_cur++] = val;
> @@ -185,6 +208,10 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>      default:
>          g_assert_not_reached();
>      }
> +
> +    s->pdma_len--;
> +    dmalen--;
> +    esp_set_tc(s, dmalen);
>  }
>  
>  static int get_cmd_cb(ESPState *s)
> @@ -945,27 +972,18 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>  {
>      SysBusESPState *sysbus = opaque;
>      ESPState *s = ESP(&sysbus->esp);
> -    uint32_t dmalen = esp_get_tc(s);
>  
>      trace_esp_pdma_write(size);
>  
> -    if (dmalen == 0 || s->pdma_len == 0) {
> -        return;
> -    }
>      switch (size) {
>      case 1:
>          esp_pdma_write(s, val);
> -        s->pdma_len--;
> -        dmalen--;
>          break;
>      case 2:
>          esp_pdma_write(s, val >> 8);
>          esp_pdma_write(s, val);
> -        s->pdma_len -= 2;
> -        dmalen -= 2;
>          break;
>      }
> -    esp_set_tc(s, dmalen);
>      if (s->pdma_len == 0 && s->pdma_cb) {
>          esp_lower_drq(s);
>          s->pdma_cb(s);
> @@ -989,17 +1007,13 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>      switch (size) {
>      case 1:
>          val = esp_pdma_read(s);
> -        s->pdma_len--;
> -        dmalen--;
>          break;
>      case 2:
>          val = esp_pdma_read(s);
>          val = (val << 8) | esp_pdma_read(s);
> -        s->pdma_len -= 2;
> -        dmalen -= 2;
>          break;
>      }
> -    esp_set_tc(s, dmalen);
> +    dmalen = esp_get_tc(s);
>      if (dmalen == 0 || (s->pdma_len == 0 && s->pdma_cb)) {
>          esp_lower_drq(s);
>          s->pdma_cb(s);
> 

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


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

* Re: [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf
  2021-02-09 19:29 ` [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf Mark Cave-Ayland
  2021-02-23 21:25   ` Philippe Mathieu-Daudé
@ 2021-03-02 17:02   ` Laurent Vivier
  2021-03-02 17:34     ` Mark Cave-Ayland
  2021-03-02 21:22   ` Laurent Vivier
  2 siblings, 1 reply; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 17:02 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> ESP SCSI commands are already accumulated in cmdbuf and so there is no need to
> keep a separate pdma_buf buffer. Accumulate SCSI commands for PDMA transfers in
> cmdbuf instead of pdma_buf so update cmdlen accordingly and change pdma_origin
> for PDMA transfers to CMD which allows the PDMA origin to be removed.
> 
> This commit also removes a stray memcpy() from get_cmd() which is a no-op because
> cmdlen is always zero at the start of a command.
> 
> Notionally the removal of pdma_buf from vmstate_esp_pdma also breaks migration
> compatibility for the PDMA subsection until its complete removal by the end of
> the series.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 56 +++++++++++++++++++------------------------
>  include/hw/scsi/esp.h |  2 --
>  2 files changed, 25 insertions(+), 33 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 7134c0aff4..b846f022fb 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -139,8 +139,6 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>  static uint8_t *get_pdma_buf(ESPState *s)
>  {
>      switch (s->pdma_origin) {
> -    case PDMA:
> -        return s->pdma_buf;
>      case TI:
>          return s->ti_buf;
>      case CMD:
> @@ -161,14 +159,12 @@ static uint8_t esp_pdma_read(ESPState *s)
>      }
>  
>      switch (s->pdma_origin) {
> -    case PDMA:
> -        val = s->pdma_buf[s->pdma_cur++];
> -        break;
>      case TI:
>          val = s->ti_buf[s->pdma_cur++];
>          break;
>      case CMD:
> -        val = s->cmdbuf[s->pdma_cur++];
> +        val = s->cmdbuf[s->cmdlen++];
> +        s->pdma_cur++;
>          break;
>      case ASYNC:
>          val = s->async_buf[s->pdma_cur++];
> @@ -193,14 +189,12 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>      }
>  
>      switch (s->pdma_origin) {
> -    case PDMA:
> -        s->pdma_buf[s->pdma_cur++] = val;
> -        break;
>      case TI:
>          s->ti_buf[s->pdma_cur++] = val;
>          break;
>      case CMD:
> -        s->cmdbuf[s->pdma_cur++] = val;
> +        s->cmdbuf[s->cmdlen++] = val;
> +        s->pdma_cur++;
>          break;
>      case ASYNC:
>          s->async_buf[s->pdma_cur++] = val;
> @@ -256,8 +250,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, buf, dmalen);
>          } else {
> -            memcpy(s->pdma_buf, buf, dmalen);
> -            set_pdma(s, PDMA, 0, dmalen);
> +            set_pdma(s, CMD, 0, dmalen);
>              esp_raise_drq(s);
>              return 0;
>          }
> @@ -316,24 +309,24 @@ static void satn_pdma_cb(ESPState *s)
>      if (get_cmd_cb(s) < 0) {
>          return;
>      }
> -    if (s->pdma_cur != s->pdma_start) {
> -        do_cmd(s, get_pdma_buf(s) + s->pdma_start);
> +    s->do_cmd = 0;
> +    if (s->cmdlen) {
> +        do_cmd(s, s->cmdbuf);

I don't understant how you can remove the pdma_start: normally it is here to keep track of the
position in the pDMA if the migration is occuraing while a pDMA transfer.

Thanks,
Laurent


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

* Re: [PATCH v2 19/42] esp: remove buf parameter from do_cmd()
  2021-02-09 19:29 ` [PATCH v2 19/42] esp: remove buf parameter from do_cmd() Mark Cave-Ayland
  2021-02-23 18:27   ` Philippe Mathieu-Daudé
@ 2021-03-02 17:03   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 17:03 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> Now that all SCSI commands are accumulated in cmdbuf, remove the buf parameter
> from do_cmd() since this always points to cmdbuf.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 13 +++++++------
>  1 file changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index b846f022fb..bb467fbcdf 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -297,8 +297,9 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
>      esp_raise_irq(s);
>  }
>  
> -static void do_cmd(ESPState *s, uint8_t *buf)
> +static void do_cmd(ESPState *s)
>  {
> +    uint8_t *buf = s->cmdbuf;
>      uint8_t busid = buf[0];
>  
>      do_busid_cmd(s, &buf[1], busid);
> @@ -311,7 +312,7 @@ static void satn_pdma_cb(ESPState *s)
>      }
>      s->do_cmd = 0;
>      if (s->cmdlen) {
> -        do_cmd(s, s->cmdbuf);
> +        do_cmd(s);
>      }
>  }
>  
> @@ -324,7 +325,7 @@ static void handle_satn(ESPState *s)
>      s->pdma_cb = satn_pdma_cb;
>      s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
>      if (s->cmdlen) {
> -        do_cmd(s, s->cmdbuf);
> +        do_cmd(s);
>      } else {
>          s->do_cmd = 1;
>      }
> @@ -445,7 +446,7 @@ static void do_dma_pdma_cb(ESPState *s)
>          s->ti_size = 0;
>          s->cmdlen = 0;
>          s->do_cmd = 0;
> -        do_cmd(s, s->cmdbuf);
> +        do_cmd(s);
>          return;
>      }
>      s->async_buf += len;
> @@ -497,7 +498,7 @@ static void esp_do_dma(ESPState *s)
>          s->ti_size = 0;
>          s->cmdlen = 0;
>          s->do_cmd = 0;
> -        do_cmd(s, s->cmdbuf);
> +        do_cmd(s);
>          return;
>      }
>      if (s->async_len == 0) {
> @@ -628,7 +629,7 @@ static void handle_ti(ESPState *s)
>          s->ti_size = 0;
>          s->cmdlen = 0;
>          s->do_cmd = 0;
> -        do_cmd(s, s->cmdbuf);
> +        do_cmd(s);
>      }
>  }
>  
> 

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


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

* Re: [PATCH v2 20/42] esp: remove the buf and buflen parameters from get_cmd()
  2021-02-09 19:29 ` [PATCH v2 20/42] esp: remove the buf and buflen parameters from get_cmd() Mark Cave-Ayland
  2021-02-16  7:31   ` Philippe Mathieu-Daudé
@ 2021-03-02 17:03   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 17:03 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> Now that all SCSI commands are accumulated in cmdbuf, remove the buf and buflen
> parameters from get_cmd() since these always reference cmdbuf and ESP_CMDBUF_SZ
> respectively.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index bb467fbcdf..7055520a26 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -236,15 +236,16 @@ static int get_cmd_cb(ESPState *s)
>      return 0;
>  }
>  
> -static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
> +static uint32_t get_cmd(ESPState *s)
>  {
> +    uint8_t *buf = s->cmdbuf;
>      uint32_t dmalen;
>      int target;
>  
>      target = s->wregs[ESP_WBUSID] & BUSID_DID;
>      if (s->dma) {
>          dmalen = esp_get_tc(s);
> -        if (dmalen > buflen) {
> +        if (dmalen > ESP_CMDBUF_SZ) {
>              return 0;
>          }
>          if (s->dma_memory_read) {
> @@ -323,7 +324,7 @@ static void handle_satn(ESPState *s)
>          return;
>      }
>      s->pdma_cb = satn_pdma_cb;
> -    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
> +    s->cmdlen = get_cmd(s);
>      if (s->cmdlen) {
>          do_cmd(s);
>      } else {
> @@ -349,7 +350,7 @@ static void handle_s_without_atn(ESPState *s)
>          return;
>      }
>      s->pdma_cb = s_without_satn_pdma_cb;
> -    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
> +    s->cmdlen = get_cmd(s);
>      if (s->cmdlen) {
>          do_busid_cmd(s, s->cmdbuf, 0);
>      } else {
> @@ -380,7 +381,7 @@ static void handle_satn_stop(ESPState *s)
>          return;
>      }
>      s->pdma_cb = satn_stop_pdma_cb;
> -    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
> +    s->cmdlen = get_cmd(s);
>      if (s->cmdlen) {
>          trace_esp_handle_satn_stop(s->cmdlen);
>          s->do_cmd = 1;
> 

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


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

* Re: [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf
  2021-03-02 17:02   ` Laurent Vivier
@ 2021-03-02 17:34     ` Mark Cave-Ayland
  2021-03-02 17:59       ` Laurent Vivier
  0 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-03-02 17:34 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel, pbonzini, fam

On 02/03/2021 17:02, Laurent Vivier wrote:

> Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
>> ESP SCSI commands are already accumulated in cmdbuf and so there is no need to
>> keep a separate pdma_buf buffer. Accumulate SCSI commands for PDMA transfers in
>> cmdbuf instead of pdma_buf so update cmdlen accordingly and change pdma_origin
>> for PDMA transfers to CMD which allows the PDMA origin to be removed.
>>
>> This commit also removes a stray memcpy() from get_cmd() which is a no-op because
>> cmdlen is always zero at the start of a command.
>>
>> Notionally the removal of pdma_buf from vmstate_esp_pdma also breaks migration
>> compatibility for the PDMA subsection until its complete removal by the end of
>> the series.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp.c         | 56 +++++++++++++++++++------------------------
>>   include/hw/scsi/esp.h |  2 --
>>   2 files changed, 25 insertions(+), 33 deletions(-)
>>
>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>> index 7134c0aff4..b846f022fb 100644
>> --- a/hw/scsi/esp.c
>> +++ b/hw/scsi/esp.c
>> @@ -139,8 +139,6 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>>   static uint8_t *get_pdma_buf(ESPState *s)
>>   {
>>       switch (s->pdma_origin) {
>> -    case PDMA:
>> -        return s->pdma_buf;
>>       case TI:
>>           return s->ti_buf;
>>       case CMD:
>> @@ -161,14 +159,12 @@ static uint8_t esp_pdma_read(ESPState *s)
>>       }
>>   
>>       switch (s->pdma_origin) {
>> -    case PDMA:
>> -        val = s->pdma_buf[s->pdma_cur++];
>> -        break;
>>       case TI:
>>           val = s->ti_buf[s->pdma_cur++];
>>           break;
>>       case CMD:
>> -        val = s->cmdbuf[s->pdma_cur++];
>> +        val = s->cmdbuf[s->cmdlen++];
>> +        s->pdma_cur++;
>>           break;
>>       case ASYNC:
>>           val = s->async_buf[s->pdma_cur++];
>> @@ -193,14 +189,12 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>>       }
>>   
>>       switch (s->pdma_origin) {
>> -    case PDMA:
>> -        s->pdma_buf[s->pdma_cur++] = val;
>> -        break;
>>       case TI:
>>           s->ti_buf[s->pdma_cur++] = val;
>>           break;
>>       case CMD:
>> -        s->cmdbuf[s->pdma_cur++] = val;
>> +        s->cmdbuf[s->cmdlen++] = val;
>> +        s->pdma_cur++;
>>           break;
>>       case ASYNC:
>>           s->async_buf[s->pdma_cur++] = val;
>> @@ -256,8 +250,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
>>           if (s->dma_memory_read) {
>>               s->dma_memory_read(s->dma_opaque, buf, dmalen);
>>           } else {
>> -            memcpy(s->pdma_buf, buf, dmalen);
>> -            set_pdma(s, PDMA, 0, dmalen);
>> +            set_pdma(s, CMD, 0, dmalen);
>>               esp_raise_drq(s);
>>               return 0;
>>           }
>> @@ -316,24 +309,24 @@ static void satn_pdma_cb(ESPState *s)
>>       if (get_cmd_cb(s) < 0) {
>>           return;
>>       }
>> -    if (s->pdma_cur != s->pdma_start) {
>> -        do_cmd(s, get_pdma_buf(s) + s->pdma_start);
>> +    s->do_cmd = 0;
>> +    if (s->cmdlen) {
>> +        do_cmd(s, s->cmdbuf);
> 
> I don't understant how you can remove the pdma_start: normally it is here to keep track of the
> position in the pDMA if the migration is occuraing while a pDMA transfer.

Hi Laurent,

I was going to follow up on your reviews later this evening, however this one caught 
my eye: as per the cover letter, this patchset is a migration break for the q800 
machine. As there are likely more incompatible changes for the q800 machine coming up 
soon, it didn't seem worth the effort (and indeed I don't think it's possible to 
recreate the new internal state with 100% accuracy from the old state).

Migration for ESP devices that don't use PDMA is still supported, and I've tested 
this during development with qemu-system-sparc.


ATB,

Mark.


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

* Re: [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf
  2021-03-02 17:34     ` Mark Cave-Ayland
@ 2021-03-02 17:59       ` Laurent Vivier
  2021-03-02 19:29         ` Mark Cave-Ayland
  0 siblings, 1 reply; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 17:59 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 02/03/2021 à 18:34, Mark Cave-Ayland a écrit :
> On 02/03/2021 17:02, Laurent Vivier wrote:
> 
>> Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
>>> ESP SCSI commands are already accumulated in cmdbuf and so there is no need to
>>> keep a separate pdma_buf buffer. Accumulate SCSI commands for PDMA transfers in
>>> cmdbuf instead of pdma_buf so update cmdlen accordingly and change pdma_origin
>>> for PDMA transfers to CMD which allows the PDMA origin to be removed.
>>>
>>> This commit also removes a stray memcpy() from get_cmd() which is a no-op because
>>> cmdlen is always zero at the start of a command.
>>>
>>> Notionally the removal of pdma_buf from vmstate_esp_pdma also breaks migration
>>> compatibility for the PDMA subsection until its complete removal by the end of
>>> the series.
>>>
>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>> ---
>>>   hw/scsi/esp.c         | 56 +++++++++++++++++++------------------------
>>>   include/hw/scsi/esp.h |  2 --
>>>   2 files changed, 25 insertions(+), 33 deletions(-)
>>>
>>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>>> index 7134c0aff4..b846f022fb 100644
>>> --- a/hw/scsi/esp.c
>>> +++ b/hw/scsi/esp.c
>>> @@ -139,8 +139,6 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>>>   static uint8_t *get_pdma_buf(ESPState *s)
>>>   {
>>>       switch (s->pdma_origin) {
>>> -    case PDMA:
>>> -        return s->pdma_buf;
>>>       case TI:
>>>           return s->ti_buf;
>>>       case CMD:
>>> @@ -161,14 +159,12 @@ static uint8_t esp_pdma_read(ESPState *s)
>>>       }
>>>         switch (s->pdma_origin) {
>>> -    case PDMA:
>>> -        val = s->pdma_buf[s->pdma_cur++];
>>> -        break;
>>>       case TI:
>>>           val = s->ti_buf[s->pdma_cur++];
>>>           break;
>>>       case CMD:
>>> -        val = s->cmdbuf[s->pdma_cur++];
>>> +        val = s->cmdbuf[s->cmdlen++];
>>> +        s->pdma_cur++;
>>>           break;
>>>       case ASYNC:
>>>           val = s->async_buf[s->pdma_cur++];
>>> @@ -193,14 +189,12 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>>>       }
>>>         switch (s->pdma_origin) {
>>> -    case PDMA:
>>> -        s->pdma_buf[s->pdma_cur++] = val;
>>> -        break;
>>>       case TI:
>>>           s->ti_buf[s->pdma_cur++] = val;
>>>           break;
>>>       case CMD:
>>> -        s->cmdbuf[s->pdma_cur++] = val;
>>> +        s->cmdbuf[s->cmdlen++] = val;
>>> +        s->pdma_cur++;
>>>           break;
>>>       case ASYNC:
>>>           s->async_buf[s->pdma_cur++] = val;
>>> @@ -256,8 +250,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
>>>           if (s->dma_memory_read) {
>>>               s->dma_memory_read(s->dma_opaque, buf, dmalen);
>>>           } else {
>>> -            memcpy(s->pdma_buf, buf, dmalen);
>>> -            set_pdma(s, PDMA, 0, dmalen);
>>> +            set_pdma(s, CMD, 0, dmalen);
>>>               esp_raise_drq(s);
>>>               return 0;
>>>           }
>>> @@ -316,24 +309,24 @@ static void satn_pdma_cb(ESPState *s)
>>>       if (get_cmd_cb(s) < 0) {
>>>           return;
>>>       }
>>> -    if (s->pdma_cur != s->pdma_start) {
>>> -        do_cmd(s, get_pdma_buf(s) + s->pdma_start);
>>> +    s->do_cmd = 0;
>>> +    if (s->cmdlen) {
>>> +        do_cmd(s, s->cmdbuf);
>>
>> I don't understant how you can remove the pdma_start: normally it is here to keep track of the
>> position in the pDMA if the migration is occuraing while a pDMA transfer.
> 
> Hi Laurent,
> 
> I was going to follow up on your reviews later this evening, however this one caught my eye: as per
> the cover letter, this patchset is a migration break for the q800 machine. As there are likely more
> incompatible changes for the q800 machine coming up soon, it didn't seem worth the effort (and
> indeed I don't think it's possible to recreate the new internal state with 100% accuracy from the
> old state).
> 
> Migration for ESP devices that don't use PDMA is still supported, and I've tested this during
> development with qemu-system-sparc.
> 

I don't mean we can't migrate from a previous version to the new one, I mean the migration between
two machines of the current version is not possible anymore as we don't keep track of the position
of the pDMA index inside the buffer.

With a DMA, the migration cannot happen in the middle of the DMA, while with pDMA it can (as it's a
processor loop).

The whole purpose of get_pdma() and set_pdma() was for the migration.

https://patchew.org/QEMU/20190910113323.17324-1-laurent@vivier.eu/diff/20190910193347.16000-1-laurent@vivier.eu/

Previously the Q800 was not migratable also because the CPU was not migratable, but I added recently
the VMSTATE for the CPU.

Thanks,
Laurent


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

* Re: [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf
  2021-03-02 17:59       ` Laurent Vivier
@ 2021-03-02 19:29         ` Mark Cave-Ayland
  2021-03-02 21:21           ` Laurent Vivier
  0 siblings, 1 reply; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-03-02 19:29 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel, pbonzini, fam

On 02/03/2021 17:59, Laurent Vivier wrote:

> Le 02/03/2021 à 18:34, Mark Cave-Ayland a écrit :
>> On 02/03/2021 17:02, Laurent Vivier wrote:
>>
>>> Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
>>>> ESP SCSI commands are already accumulated in cmdbuf and so there is no need to
>>>> keep a separate pdma_buf buffer. Accumulate SCSI commands for PDMA transfers in
>>>> cmdbuf instead of pdma_buf so update cmdlen accordingly and change pdma_origin
>>>> for PDMA transfers to CMD which allows the PDMA origin to be removed.
>>>>
>>>> This commit also removes a stray memcpy() from get_cmd() which is a no-op because
>>>> cmdlen is always zero at the start of a command.
>>>>
>>>> Notionally the removal of pdma_buf from vmstate_esp_pdma also breaks migration
>>>> compatibility for the PDMA subsection until its complete removal by the end of
>>>> the series.
>>>>
>>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>>> ---
>>>>    hw/scsi/esp.c         | 56 +++++++++++++++++++------------------------
>>>>    include/hw/scsi/esp.h |  2 --
>>>>    2 files changed, 25 insertions(+), 33 deletions(-)
>>>>
>>>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>>>> index 7134c0aff4..b846f022fb 100644
>>>> --- a/hw/scsi/esp.c
>>>> +++ b/hw/scsi/esp.c
>>>> @@ -139,8 +139,6 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>>>>    static uint8_t *get_pdma_buf(ESPState *s)
>>>>    {
>>>>        switch (s->pdma_origin) {
>>>> -    case PDMA:
>>>> -        return s->pdma_buf;
>>>>        case TI:
>>>>            return s->ti_buf;
>>>>        case CMD:
>>>> @@ -161,14 +159,12 @@ static uint8_t esp_pdma_read(ESPState *s)
>>>>        }
>>>>          switch (s->pdma_origin) {
>>>> -    case PDMA:
>>>> -        val = s->pdma_buf[s->pdma_cur++];
>>>> -        break;
>>>>        case TI:
>>>>            val = s->ti_buf[s->pdma_cur++];
>>>>            break;
>>>>        case CMD:
>>>> -        val = s->cmdbuf[s->pdma_cur++];
>>>> +        val = s->cmdbuf[s->cmdlen++];
>>>> +        s->pdma_cur++;
>>>>            break;
>>>>        case ASYNC:
>>>>            val = s->async_buf[s->pdma_cur++];
>>>> @@ -193,14 +189,12 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>>>>        }
>>>>          switch (s->pdma_origin) {
>>>> -    case PDMA:
>>>> -        s->pdma_buf[s->pdma_cur++] = val;
>>>> -        break;
>>>>        case TI:
>>>>            s->ti_buf[s->pdma_cur++] = val;
>>>>            break;
>>>>        case CMD:
>>>> -        s->cmdbuf[s->pdma_cur++] = val;
>>>> +        s->cmdbuf[s->cmdlen++] = val;
>>>> +        s->pdma_cur++;
>>>>            break;
>>>>        case ASYNC:
>>>>            s->async_buf[s->pdma_cur++] = val;
>>>> @@ -256,8 +250,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
>>>>            if (s->dma_memory_read) {
>>>>                s->dma_memory_read(s->dma_opaque, buf, dmalen);
>>>>            } else {
>>>> -            memcpy(s->pdma_buf, buf, dmalen);
>>>> -            set_pdma(s, PDMA, 0, dmalen);
>>>> +            set_pdma(s, CMD, 0, dmalen);
>>>>                esp_raise_drq(s);
>>>>                return 0;
>>>>            }
>>>> @@ -316,24 +309,24 @@ static void satn_pdma_cb(ESPState *s)
>>>>        if (get_cmd_cb(s) < 0) {
>>>>            return;
>>>>        }
>>>> -    if (s->pdma_cur != s->pdma_start) {
>>>> -        do_cmd(s, get_pdma_buf(s) + s->pdma_start);
>>>> +    s->do_cmd = 0;
>>>> +    if (s->cmdlen) {
>>>> +        do_cmd(s, s->cmdbuf);
>>>
>>> I don't understant how you can remove the pdma_start: normally it is here to keep track of the
>>> position in the pDMA if the migration is occuraing while a pDMA transfer.
>>
>> Hi Laurent,
>>
>> I was going to follow up on your reviews later this evening, however this one caught my eye: as per
>> the cover letter, this patchset is a migration break for the q800 machine. As there are likely more
>> incompatible changes for the q800 machine coming up soon, it didn't seem worth the effort (and
>> indeed I don't think it's possible to recreate the new internal state with 100% accuracy from the
>> old state).
>>
>> Migration for ESP devices that don't use PDMA is still supported, and I've tested this during
>> development with qemu-system-sparc.
>>
> 
> I don't mean we can't migrate from a previous version to the new one, I mean the migration between
> two machines of the current version is not possible anymore as we don't keep track of the position
> of the pDMA index inside the buffer.
> 
> With a DMA, the migration cannot happen in the middle of the DMA, while with pDMA it can (as it's a
> processor loop).
> 
> The whole purpose of get_pdma() and set_pdma() was for the migration.
> 
> https://patchew.org/QEMU/20190910113323.17324-1-laurent@vivier.eu/diff/20190910193347.16000-1-laurent@vivier.eu/
> 
> Previously the Q800 was not migratable also because the CPU was not migratable, but I added recently
> the VMSTATE for the CPU.

What should happen here is that the PDMA bytes for the message out and command phases 
are accumulated in cmdbuf and cmdlen as per normal ESP DMA - these are already 
included in the migration stream so there should be no problem there.

The PDMA callbacks are invoked when pdma_len == 0 where pdma_len is initially set to 
len in esp_do_dma: this is effectively the TC which is set to the length of the CDB 
for a DMA transfer. This means that the PDMA callback and hence do_cmd() are only 
called at the end of the transfer once the entire CDB has been accumulated where 
pdma_start is 0 (cmdbuf always includes the preceding IDENTIFY byte).


ATB,

Mark.


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

* Re: [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf
  2021-03-02 19:29         ` Mark Cave-Ayland
@ 2021-03-02 21:21           ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 21:21 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 02/03/2021 à 20:29, Mark Cave-Ayland a écrit :
> On 02/03/2021 17:59, Laurent Vivier wrote:
> 
>> Le 02/03/2021 à 18:34, Mark Cave-Ayland a écrit :
>>> On 02/03/2021 17:02, Laurent Vivier wrote:
>>>
>>>> Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
>>>>> ESP SCSI commands are already accumulated in cmdbuf and so there is no need to
>>>>> keep a separate pdma_buf buffer. Accumulate SCSI commands for PDMA transfers in
>>>>> cmdbuf instead of pdma_buf so update cmdlen accordingly and change pdma_origin
>>>>> for PDMA transfers to CMD which allows the PDMA origin to be removed.
>>>>>
>>>>> This commit also removes a stray memcpy() from get_cmd() which is a no-op because
>>>>> cmdlen is always zero at the start of a command.
>>>>>
>>>>> Notionally the removal of pdma_buf from vmstate_esp_pdma also breaks migration
>>>>> compatibility for the PDMA subsection until its complete removal by the end of
>>>>> the series.
>>>>>
>>>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>>>> ---
>>>>>    hw/scsi/esp.c         | 56 +++++++++++++++++++------------------------
>>>>>    include/hw/scsi/esp.h |  2 --
>>>>>    2 files changed, 25 insertions(+), 33 deletions(-)
>>>>>
>>>>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>>>>> index 7134c0aff4..b846f022fb 100644
>>>>> --- a/hw/scsi/esp.c
>>>>> +++ b/hw/scsi/esp.c
>>>>> @@ -139,8 +139,6 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>>>>>    static uint8_t *get_pdma_buf(ESPState *s)
>>>>>    {
>>>>>        switch (s->pdma_origin) {
>>>>> -    case PDMA:
>>>>> -        return s->pdma_buf;
>>>>>        case TI:
>>>>>            return s->ti_buf;
>>>>>        case CMD:
>>>>> @@ -161,14 +159,12 @@ static uint8_t esp_pdma_read(ESPState *s)
>>>>>        }
>>>>>          switch (s->pdma_origin) {
>>>>> -    case PDMA:
>>>>> -        val = s->pdma_buf[s->pdma_cur++];
>>>>> -        break;
>>>>>        case TI:
>>>>>            val = s->ti_buf[s->pdma_cur++];
>>>>>            break;
>>>>>        case CMD:
>>>>> -        val = s->cmdbuf[s->pdma_cur++];
>>>>> +        val = s->cmdbuf[s->cmdlen++];
>>>>> +        s->pdma_cur++;
>>>>>            break;
>>>>>        case ASYNC:
>>>>>            val = s->async_buf[s->pdma_cur++];
>>>>> @@ -193,14 +189,12 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>>>>>        }
>>>>>          switch (s->pdma_origin) {
>>>>> -    case PDMA:
>>>>> -        s->pdma_buf[s->pdma_cur++] = val;
>>>>> -        break;
>>>>>        case TI:
>>>>>            s->ti_buf[s->pdma_cur++] = val;
>>>>>            break;
>>>>>        case CMD:
>>>>> -        s->cmdbuf[s->pdma_cur++] = val;
>>>>> +        s->cmdbuf[s->cmdlen++] = val;
>>>>> +        s->pdma_cur++;
>>>>>            break;
>>>>>        case ASYNC:
>>>>>            s->async_buf[s->pdma_cur++] = val;
>>>>> @@ -256,8 +250,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
>>>>>            if (s->dma_memory_read) {
>>>>>                s->dma_memory_read(s->dma_opaque, buf, dmalen);
>>>>>            } else {
>>>>> -            memcpy(s->pdma_buf, buf, dmalen);
>>>>> -            set_pdma(s, PDMA, 0, dmalen);
>>>>> +            set_pdma(s, CMD, 0, dmalen);
>>>>>                esp_raise_drq(s);
>>>>>                return 0;
>>>>>            }
>>>>> @@ -316,24 +309,24 @@ static void satn_pdma_cb(ESPState *s)
>>>>>        if (get_cmd_cb(s) < 0) {
>>>>>            return;
>>>>>        }
>>>>> -    if (s->pdma_cur != s->pdma_start) {
>>>>> -        do_cmd(s, get_pdma_buf(s) + s->pdma_start);
>>>>> +    s->do_cmd = 0;
>>>>> +    if (s->cmdlen) {
>>>>> +        do_cmd(s, s->cmdbuf);
>>>>
>>>> I don't understant how you can remove the pdma_start: normally it is here to keep track of the
>>>> position in the pDMA if the migration is occuraing while a pDMA transfer.
>>>
>>> Hi Laurent,
>>>
>>> I was going to follow up on your reviews later this evening, however this one caught my eye: as per
>>> the cover letter, this patchset is a migration break for the q800 machine. As there are likely more
>>> incompatible changes for the q800 machine coming up soon, it didn't seem worth the effort (and
>>> indeed I don't think it's possible to recreate the new internal state with 100% accuracy from the
>>> old state).
>>>
>>> Migration for ESP devices that don't use PDMA is still supported, and I've tested this during
>>> development with qemu-system-sparc.
>>>
>>
>> I don't mean we can't migrate from a previous version to the new one, I mean the migration between
>> two machines of the current version is not possible anymore as we don't keep track of the position
>> of the pDMA index inside the buffer.
>>
>> With a DMA, the migration cannot happen in the middle of the DMA, while with pDMA it can (as it's a
>> processor loop).
>>
>> The whole purpose of get_pdma() and set_pdma() was for the migration.
>>
>> https://patchew.org/QEMU/20190910113323.17324-1-laurent@vivier.eu/diff/20190910193347.16000-1-laurent@vivier.eu/
>>
>>
>> Previously the Q800 was not migratable also because the CPU was not migratable, but I added recently
>> the VMSTATE for the CPU.
> 
> What should happen here is that the PDMA bytes for the message out and command phases are
> accumulated in cmdbuf and cmdlen as per normal ESP DMA - these are already included in the migration
> stream so there should be no problem there.
> 
> The PDMA callbacks are invoked when pdma_len == 0 where pdma_len is initially set to len in
> esp_do_dma: this is effectively the TC which is set to the length of the CDB for a DMA transfer.
> This means that the PDMA callback and hence do_cmd() are only called at the end of the transfer once
> the entire CDB has been accumulated where pdma_start is 0 (cmdbuf always includes the preceding
> IDENTIFY byte).
>

OK, I think I was worried about the migration of the value of pdma_cur, used in
sysbus_esp_pdma_read()/sysbus_esp_pdma_write(), but it seems you take care of that later in the
series...

Thanks,
Laurent


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

* Re: [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf
  2021-02-09 19:29 ` [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf Mark Cave-Ayland
  2021-02-23 21:25   ` Philippe Mathieu-Daudé
  2021-03-02 17:02   ` Laurent Vivier
@ 2021-03-02 21:22   ` Laurent Vivier
  2 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 21:22 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> ESP SCSI commands are already accumulated in cmdbuf and so there is no need to
> keep a separate pdma_buf buffer. Accumulate SCSI commands for PDMA transfers in
> cmdbuf instead of pdma_buf so update cmdlen accordingly and change pdma_origin
> for PDMA transfers to CMD which allows the PDMA origin to be removed.
> 
> This commit also removes a stray memcpy() from get_cmd() which is a no-op because
> cmdlen is always zero at the start of a command.
> 
> Notionally the removal of pdma_buf from vmstate_esp_pdma also breaks migration
> compatibility for the PDMA subsection until its complete removal by the end of
> the series.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 56 +++++++++++++++++++------------------------
>  include/hw/scsi/esp.h |  2 --
>  2 files changed, 25 insertions(+), 33 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 7134c0aff4..b846f022fb 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -139,8 +139,6 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>  static uint8_t *get_pdma_buf(ESPState *s)
>  {
>      switch (s->pdma_origin) {
> -    case PDMA:
> -        return s->pdma_buf;
>      case TI:
>          return s->ti_buf;
>      case CMD:
> @@ -161,14 +159,12 @@ static uint8_t esp_pdma_read(ESPState *s)
>      }
>  
>      switch (s->pdma_origin) {
> -    case PDMA:
> -        val = s->pdma_buf[s->pdma_cur++];
> -        break;
>      case TI:
>          val = s->ti_buf[s->pdma_cur++];
>          break;
>      case CMD:
> -        val = s->cmdbuf[s->pdma_cur++];
> +        val = s->cmdbuf[s->cmdlen++];
> +        s->pdma_cur++;
>          break;
>      case ASYNC:
>          val = s->async_buf[s->pdma_cur++];
> @@ -193,14 +189,12 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>      }
>  
>      switch (s->pdma_origin) {
> -    case PDMA:
> -        s->pdma_buf[s->pdma_cur++] = val;
> -        break;
>      case TI:
>          s->ti_buf[s->pdma_cur++] = val;
>          break;
>      case CMD:
> -        s->cmdbuf[s->pdma_cur++] = val;
> +        s->cmdbuf[s->cmdlen++] = val;
> +        s->pdma_cur++;
>          break;
>      case ASYNC:
>          s->async_buf[s->pdma_cur++] = val;
> @@ -256,8 +250,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, buf, dmalen);
>          } else {
> -            memcpy(s->pdma_buf, buf, dmalen);
> -            set_pdma(s, PDMA, 0, dmalen);
> +            set_pdma(s, CMD, 0, dmalen);
>              esp_raise_drq(s);
>              return 0;
>          }
> @@ -316,24 +309,24 @@ static void satn_pdma_cb(ESPState *s)
>      if (get_cmd_cb(s) < 0) {
>          return;
>      }
> -    if (s->pdma_cur != s->pdma_start) {
> -        do_cmd(s, get_pdma_buf(s) + s->pdma_start);
> +    s->do_cmd = 0;
> +    if (s->cmdlen) {
> +        do_cmd(s, s->cmdbuf);
>      }
>  }
>  
>  static void handle_satn(ESPState *s)
>  {
> -    uint8_t buf[32];
> -    int len;
> -
>      if (s->dma && !s->dma_enabled) {
>          s->dma_cb = handle_satn;
>          return;
>      }
>      s->pdma_cb = satn_pdma_cb;
> -    len = get_cmd(s, buf, sizeof(buf));
> -    if (len) {
> -        do_cmd(s, buf);
> +    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
> +    if (s->cmdlen) {
> +        do_cmd(s, s->cmdbuf);
> +    } else {
> +        s->do_cmd = 1;
>      }
>  }
>  
> @@ -342,24 +335,24 @@ static void s_without_satn_pdma_cb(ESPState *s)
>      if (get_cmd_cb(s) < 0) {
>          return;
>      }
> -    if (s->pdma_cur != s->pdma_start) {
> +    s->do_cmd = 0;
> +    if (s->cmdlen) {
>          do_busid_cmd(s, get_pdma_buf(s) + s->pdma_start, 0);
>      }
>  }
>  
>  static void handle_s_without_atn(ESPState *s)
>  {
> -    uint8_t buf[32];
> -    int len;
> -
>      if (s->dma && !s->dma_enabled) {
>          s->dma_cb = handle_s_without_atn;
>          return;
>      }
>      s->pdma_cb = s_without_satn_pdma_cb;
> -    len = get_cmd(s, buf, sizeof(buf));
> -    if (len) {
> -        do_busid_cmd(s, buf, 0);
> +    s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
> +    if (s->cmdlen) {
> +        do_busid_cmd(s, s->cmdbuf, 0);
> +    } else {
> +        s->do_cmd = 1;
>      }
>  }
>  
> @@ -368,7 +361,7 @@ static void satn_stop_pdma_cb(ESPState *s)
>      if (get_cmd_cb(s) < 0) {
>          return;
>      }
> -    s->cmdlen = s->pdma_cur - s->pdma_start;
> +    s->do_cmd = 0;
>      if (s->cmdlen) {
>          trace_esp_handle_satn_stop(s->cmdlen);
>          s->do_cmd = 1;
> @@ -394,6 +387,8 @@ static void handle_satn_stop(ESPState *s)
>          s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
>          s->rregs[ESP_RSEQ] = SEQ_CD;
>          esp_raise_irq(s);
> +    } else {
> +        s->do_cmd = 1;
>      }
>  }
>  
> @@ -865,11 +860,10 @@ static bool esp_pdma_needed(void *opaque)
>  
>  static const VMStateDescription vmstate_esp_pdma = {
>      .name = "esp/pdma",
> -    .version_id = 1,
> -    .minimum_version_id = 1,
> +    .version_id = 2,
> +    .minimum_version_id = 2,
>      .needed = esp_pdma_needed,
>      .fields = (VMStateField[]) {
> -        VMSTATE_BUFFER(pdma_buf, ESPState),
>          VMSTATE_INT32(pdma_origin, ESPState),
>          VMSTATE_UINT32(pdma_len, ESPState),
>          VMSTATE_UINT32(pdma_start, ESPState),
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 9fad320513..c323d43f70 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -16,7 +16,6 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
>  typedef struct ESPState ESPState;
>  
>  enum pdma_origin_id {
> -    PDMA,
>      TI,
>      CMD,
>      ASYNC,
> @@ -57,7 +56,6 @@ struct ESPState {
>      ESPDMAMemoryReadWriteFunc dma_memory_write;
>      void *dma_opaque;
>      void (*dma_cb)(ESPState *s);
> -    uint8_t pdma_buf[32];
>      int pdma_origin;
>      uint32_t pdma_len;
>      uint32_t pdma_start;
> 

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


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

* Re: [PATCH v2 21/42] esp: remove redundant pdma_start from ESPState
  2021-02-09 19:29 ` [PATCH v2 21/42] esp: remove redundant pdma_start from ESPState Mark Cave-Ayland
@ 2021-03-02 21:22   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 21:22 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> Now that PDMA SCSI commands are accumulated in cmdbuf in the same way as normal
> commands, the existing logic for locating the start of the SCSI command in
> cmdbuf via cmdlen can be used. This enables the PDMA-specific pdma_start and
> also get_pdma_buf() to be removed.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 19 ++-----------------
>  include/hw/scsi/esp.h |  1 -
>  2 files changed, 2 insertions(+), 18 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 7055520a26..91f65a5d9b 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -131,24 +131,10 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>                       uint32_t index, uint32_t len)
>  {
>      s->pdma_origin = origin;
> -    s->pdma_start = index;
>      s->pdma_cur = index;
>      s->pdma_len = len;
>  }
>  
> -static uint8_t *get_pdma_buf(ESPState *s)
> -{
> -    switch (s->pdma_origin) {
> -    case TI:
> -        return s->ti_buf;
> -    case CMD:
> -        return s->cmdbuf;
> -    case ASYNC:
> -        return s->async_buf;
> -    }
> -    return NULL;
> -}
> -
>  static uint8_t esp_pdma_read(ESPState *s)
>  {
>      uint32_t dmalen = esp_get_tc(s);
> @@ -339,7 +325,7 @@ static void s_without_satn_pdma_cb(ESPState *s)
>      }
>      s->do_cmd = 0;
>      if (s->cmdlen) {
> -        do_busid_cmd(s, get_pdma_buf(s) + s->pdma_start, 0);
> +        do_busid_cmd(s, s->cmdbuf, 0);
>      }
>  }
>  
> @@ -441,7 +427,7 @@ static void esp_dma_done(ESPState *s)
>  static void do_dma_pdma_cb(ESPState *s)
>  {
>      int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
> -    int len = s->pdma_cur - s->pdma_start;
> +    int len = s->pdma_cur;
>  
>      if (s->do_cmd) {
>          s->ti_size = 0;
> @@ -868,7 +854,6 @@ static const VMStateDescription vmstate_esp_pdma = {
>      .fields = (VMStateField[]) {
>          VMSTATE_INT32(pdma_origin, ESPState),
>          VMSTATE_UINT32(pdma_len, ESPState),
> -        VMSTATE_UINT32(pdma_start, ESPState),
>          VMSTATE_UINT32(pdma_cur, ESPState),
>          VMSTATE_END_OF_LIST()
>      }
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index c323d43f70..578d936214 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -58,7 +58,6 @@ struct ESPState {
>      void (*dma_cb)(ESPState *s);
>      int pdma_origin;
>      uint32_t pdma_len;
> -    uint32_t pdma_start;
>      uint32_t pdma_cur;
>      void (*pdma_cb)(ESPState *s);
>  
> 

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


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

* Re: [PATCH v2 22/42] esp: move PDMA length adjustments into esp_pdma_read()/esp_pdma_write()
  2021-02-09 19:29 ` [PATCH v2 22/42] esp: move PDMA length adjustments into esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
@ 2021-03-02 21:44   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 21:44 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> Here the updates to async_len and ti_size are moved into the corresponding
> esp_pdma_read()/esp_pdma_write() function to eliminate the reference to
> pdma_cur in do_dma_pdma_cb().
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 24 ++++++++++++++----------
>  1 file changed, 14 insertions(+), 10 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 91f65a5d9b..691a2f4bdc 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -153,12 +153,18 @@ static uint8_t esp_pdma_read(ESPState *s)
>          s->pdma_cur++;
>          break;
>      case ASYNC:
> -        val = s->async_buf[s->pdma_cur++];
> +        val = s->async_buf[0];
> +        if (s->async_len > 0) {
> +            s->async_len--;
> +            s->async_buf++;
> +        }
> +        s->pdma_cur++;
>          break;
>      default:
>          g_assert_not_reached();
>      }
>  
> +    s->ti_size--;
>      s->pdma_len--;
>      dmalen--;
>      esp_set_tc(s, dmalen);
> @@ -183,12 +189,18 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>          s->pdma_cur++;
>          break;
>      case ASYNC:
> -        s->async_buf[s->pdma_cur++] = val;
> +        s->async_buf[0] = val;
> +        if (s->async_len > 0) {
> +            s->async_len--;
> +            s->async_buf++;
> +        }
> +        s->pdma_cur++;
>          break;
>      default:
>          g_assert_not_reached();
>      }
>  
> +    s->ti_size++;
>      s->pdma_len--;
>      dmalen--;
>      esp_set_tc(s, dmalen);
> @@ -427,7 +439,6 @@ static void esp_dma_done(ESPState *s)
>  static void do_dma_pdma_cb(ESPState *s)
>  {
>      int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
> -    int len = s->pdma_cur;
>  
>      if (s->do_cmd) {
>          s->ti_size = 0;
> @@ -436,13 +447,6 @@ static void do_dma_pdma_cb(ESPState *s)
>          do_cmd(s);
>          return;
>      }
> -    s->async_buf += len;
> -    s->async_len -= len;
> -    if (to_device) {
> -        s->ti_size += len;
> -    } else {
> -        s->ti_size -= len;
> -    }
>      if (s->async_len == 0) {
>          scsi_req_continue(s->current_req);
>          /*
> 

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


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

* Re: [PATCH v2 23/42] esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA
  2021-02-09 19:29 ` [PATCH v2 23/42] esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA Mark Cave-Ayland
  2021-02-23 21:29   ` Philippe Mathieu-Daudé
@ 2021-03-02 21:47   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 21:47 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
> This eliminates the last user of the PDMA-specific pdma_cur variable which can
> now be removed.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 23 ++++++++---------------
>  include/hw/scsi/esp.h |  1 -
>  2 files changed, 8 insertions(+), 16 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 691a2f4bdc..50503a6f53 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -127,11 +127,9 @@ static uint32_t esp_get_stc(ESPState *s)
>      return dmalen;
>  }
>  
> -static void set_pdma(ESPState *s, enum pdma_origin_id origin,
> -                     uint32_t index, uint32_t len)
> +static void set_pdma(ESPState *s, enum pdma_origin_id origin, uint32_t len)
>  {
>      s->pdma_origin = origin;
> -    s->pdma_cur = index;
>      s->pdma_len = len;
>  }
>  
> @@ -146,11 +144,10 @@ static uint8_t esp_pdma_read(ESPState *s)
>  
>      switch (s->pdma_origin) {
>      case TI:
> -        val = s->ti_buf[s->pdma_cur++];
> +        val = s->ti_buf[s->ti_rptr++];
>          break;
>      case CMD:
>          val = s->cmdbuf[s->cmdlen++];
> -        s->pdma_cur++;
>          break;
>      case ASYNC:
>          val = s->async_buf[0];
> @@ -158,7 +155,6 @@ static uint8_t esp_pdma_read(ESPState *s)
>              s->async_len--;
>              s->async_buf++;
>          }
> -        s->pdma_cur++;
>          break;
>      default:
>          g_assert_not_reached();
> @@ -182,11 +178,10 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>  
>      switch (s->pdma_origin) {
>      case TI:
> -        s->ti_buf[s->pdma_cur++] = val;
> +        s->ti_buf[s->ti_wptr++] = val;
>          break;
>      case CMD:
>          s->cmdbuf[s->cmdlen++] = val;
> -        s->pdma_cur++;
>          break;
>      case ASYNC:
>          s->async_buf[0] = val;
> @@ -194,7 +189,6 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>              s->async_len--;
>              s->async_buf++;
>          }
> -        s->pdma_cur++;
>          break;
>      default:
>          g_assert_not_reached();
> @@ -249,7 +243,7 @@ static uint32_t get_cmd(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, buf, dmalen);
>          } else {
> -            set_pdma(s, CMD, 0, dmalen);
> +            set_pdma(s, CMD, dmalen);
>              esp_raise_drq(s);
>              return 0;
>          }
> @@ -412,7 +406,7 @@ static void write_response(ESPState *s)
>              s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
>              s->rregs[ESP_RSEQ] = SEQ_CD;
>          } else {
> -            set_pdma(s, TI, 0, 2);
> +            set_pdma(s, TI, 2);
>              s->pdma_cb = write_response_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -480,7 +474,7 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
>          } else {
> -            set_pdma(s, CMD, s->cmdlen, len);
> +            set_pdma(s, CMD, len);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -503,7 +497,7 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, s->async_buf, len);
>          } else {
> -            set_pdma(s, ASYNC, 0, len);
> +            set_pdma(s, ASYNC, len);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -512,7 +506,7 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_write) {
>              s->dma_memory_write(s->dma_opaque, s->async_buf, len);
>          } else {
> -            set_pdma(s, ASYNC, 0, len);
> +            set_pdma(s, ASYNC, len);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -858,7 +852,6 @@ static const VMStateDescription vmstate_esp_pdma = {
>      .fields = (VMStateField[]) {
>          VMSTATE_INT32(pdma_origin, ESPState),
>          VMSTATE_UINT32(pdma_len, ESPState),
> -        VMSTATE_UINT32(pdma_cur, ESPState),
>          VMSTATE_END_OF_LIST()
>      }
>  };
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 578d936214..5908d59a0a 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -58,7 +58,6 @@ struct ESPState {
>      void (*dma_cb)(ESPState *s);
>      int pdma_origin;
>      uint32_t pdma_len;
> -    uint32_t pdma_cur;
>      void (*pdma_cb)(ESPState *s);
>  
>      uint8_t mig_version_id;
> 

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


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

* Re: [PATCH v2 24/42] esp: use in-built TC to determine PDMA transfer length
  2021-02-09 19:30 ` [PATCH v2 24/42] esp: use in-built TC to determine PDMA transfer length Mark Cave-Ayland
  2021-02-23 18:32   ` Philippe Mathieu-Daudé
@ 2021-03-02 21:48   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 21:48 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> Real hardware simply counts down using the in-built TC to determine when the
> the PDMA request is complete. Use the TC to determine the PDMA transfer length
> which then enables us to remove the redundant pdma_len variable.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 28 +++++++++++++---------------
>  include/hw/scsi/esp.h |  1 -
>  2 files changed, 13 insertions(+), 16 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 50503a6f53..bff330733f 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -127,10 +127,9 @@ static uint32_t esp_get_stc(ESPState *s)
>      return dmalen;
>  }
>  
> -static void set_pdma(ESPState *s, enum pdma_origin_id origin, uint32_t len)
> +static void set_pdma(ESPState *s, enum pdma_origin_id origin)
>  {
>      s->pdma_origin = origin;
> -    s->pdma_len = len;
>  }
>  
>  static uint8_t esp_pdma_read(ESPState *s)
> @@ -138,7 +137,7 @@ static uint8_t esp_pdma_read(ESPState *s)
>      uint32_t dmalen = esp_get_tc(s);
>      uint8_t val;
>  
> -    if (dmalen == 0 || s->pdma_len == 0) {
> +    if (dmalen == 0) {
>          return 0;
>      }
>  
> @@ -161,7 +160,6 @@ static uint8_t esp_pdma_read(ESPState *s)
>      }
>  
>      s->ti_size--;
> -    s->pdma_len--;
>      dmalen--;
>      esp_set_tc(s, dmalen);
>  
> @@ -172,7 +170,7 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>  {
>      uint32_t dmalen = esp_get_tc(s);
>  
> -    if (dmalen == 0 || s->pdma_len == 0) {
> +    if (dmalen == 0) {
>          return;
>      }
>  
> @@ -195,7 +193,6 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>      }
>  
>      s->ti_size++;
> -    s->pdma_len--;
>      dmalen--;
>      esp_set_tc(s, dmalen);
>  }
> @@ -243,7 +240,7 @@ static uint32_t get_cmd(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, buf, dmalen);
>          } else {
> -            set_pdma(s, CMD, dmalen);
> +            set_pdma(s, CMD);
>              esp_raise_drq(s);
>              return 0;
>          }
> @@ -406,7 +403,7 @@ static void write_response(ESPState *s)
>              s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
>              s->rregs[ESP_RSEQ] = SEQ_CD;
>          } else {
> -            set_pdma(s, TI, 2);
> +            set_pdma(s, TI);
>              s->pdma_cb = write_response_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -474,7 +471,7 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
>          } else {
> -            set_pdma(s, CMD, len);
> +            set_pdma(s, CMD);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -497,7 +494,7 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, s->async_buf, len);
>          } else {
> -            set_pdma(s, ASYNC, len);
> +            set_pdma(s, ASYNC);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -506,7 +503,7 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_write) {
>              s->dma_memory_write(s->dma_opaque, s->async_buf, len);
>          } else {
> -            set_pdma(s, ASYNC, len);
> +            set_pdma(s, ASYNC);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -851,7 +848,6 @@ static const VMStateDescription vmstate_esp_pdma = {
>      .needed = esp_pdma_needed,
>      .fields = (VMStateField[]) {
>          VMSTATE_INT32(pdma_origin, ESPState),
> -        VMSTATE_UINT32(pdma_len, ESPState),
>          VMSTATE_END_OF_LIST()
>      }
>  };
> @@ -950,6 +946,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>  {
>      SysBusESPState *sysbus = opaque;
>      ESPState *s = ESP(&sysbus->esp);
> +    uint32_t dmalen;
>  
>      trace_esp_pdma_write(size);
>  
> @@ -962,7 +959,8 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>          esp_pdma_write(s, val);
>          break;
>      }
> -    if (s->pdma_len == 0 && s->pdma_cb) {
> +    dmalen = esp_get_tc(s);
> +    if (dmalen == 0 && s->pdma_cb) {
>          esp_lower_drq(s);
>          s->pdma_cb(s);
>          s->pdma_cb = NULL;
> @@ -979,7 +977,7 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>  
>      trace_esp_pdma_read(size);
>  
> -    if (dmalen == 0 || s->pdma_len == 0) {
> +    if (dmalen == 0) {
>          return 0;
>      }
>      switch (size) {
> @@ -992,7 +990,7 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>          break;
>      }
>      dmalen = esp_get_tc(s);
> -    if (dmalen == 0 || (s->pdma_len == 0 && s->pdma_cb)) {
> +    if (dmalen == 0 && s->pdma_cb) {
>          esp_lower_drq(s);
>          s->pdma_cb(s);
>          s->pdma_cb = NULL;
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 5908d59a0a..1e84b7bfb0 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -57,7 +57,6 @@ struct ESPState {
>      void *dma_opaque;
>      void (*dma_cb)(ESPState *s);
>      int pdma_origin;
> -    uint32_t pdma_len;
>      void (*pdma_cb)(ESPState *s);
>  
>      uint8_t mig_version_id;
> 

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


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

* Re: [PATCH v2 25/42] esp: remove CMD pdma_origin
  2021-02-09 19:30 ` [PATCH v2 25/42] esp: remove CMD pdma_origin Mark Cave-Ayland
  2021-02-23 18:34   ` Philippe Mathieu-Daudé
@ 2021-03-02 21:49   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 21:49 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> The cmdbuf is really just a copy of FIFO data (including extra message phase
> bytes) so its pdma_origin is effectively TI. Fortunately we already know when
> we are receiving a SCSI command since do_cmd == 1 which enables us to
> distinguish between the two cases in esp_pdma_read()/esp_pdma_write().
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 22 ++++++++++++----------
>  include/hw/scsi/esp.h |  1 -
>  2 files changed, 12 insertions(+), 11 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index bff330733f..921f79ae89 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -143,10 +143,11 @@ static uint8_t esp_pdma_read(ESPState *s)
>  
>      switch (s->pdma_origin) {
>      case TI:
> -        val = s->ti_buf[s->ti_rptr++];
> -        break;
> -    case CMD:
> -        val = s->cmdbuf[s->cmdlen++];
> +        if (s->do_cmd) {
> +            val = s->cmdbuf[s->cmdlen++];
> +        } else {
> +            val = s->ti_buf[s->ti_rptr++];
> +        }
>          break;
>      case ASYNC:
>          val = s->async_buf[0];
> @@ -176,10 +177,11 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>  
>      switch (s->pdma_origin) {
>      case TI:
> -        s->ti_buf[s->ti_wptr++] = val;
> -        break;
> -    case CMD:
> -        s->cmdbuf[s->cmdlen++] = val;
> +        if (s->do_cmd) {
> +            s->cmdbuf[s->cmdlen++] = val;
> +        } else {
> +            s->ti_buf[s->ti_wptr++] = val;
> +        }
>          break;
>      case ASYNC:
>          s->async_buf[0] = val;
> @@ -240,7 +242,7 @@ static uint32_t get_cmd(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, buf, dmalen);
>          } else {
> -            set_pdma(s, CMD);
> +            set_pdma(s, TI);
>              esp_raise_drq(s);
>              return 0;
>          }
> @@ -471,7 +473,7 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
>          } else {
> -            set_pdma(s, CMD);
> +            set_pdma(s, TI);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 1e84b7bfb0..a8d5bf8a63 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -17,7 +17,6 @@ typedef struct ESPState ESPState;
>  
>  enum pdma_origin_id {
>      TI,
> -    CMD,
>      ASYNC,
>  };
>  
> 

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


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

* Re: [PATCH v2 26/42] esp: rename get_cmd_cb() to esp_select()
  2021-02-09 19:30 ` [PATCH v2 26/42] esp: rename get_cmd_cb() to esp_select() Mark Cave-Ayland
@ 2021-03-02 21:51   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 21:51 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> This better describes the purpose of the function.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
>  hw/scsi/esp.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 921f79ae89..6736e7142c 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -199,7 +199,7 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>      esp_set_tc(s, dmalen);
>  }
>  
> -static int get_cmd_cb(ESPState *s)
> +static int esp_select(ESPState *s)
>  {
>      int target;
>  
> @@ -256,7 +256,7 @@ static uint32_t get_cmd(ESPState *s)
>      }
>      trace_esp_get_cmd(dmalen, target);
>  
> -    if (get_cmd_cb(s) < 0) {
> +    if (esp_select(s) < 0) {
>          return 0;
>      }
>      return dmalen;
> @@ -299,7 +299,7 @@ static void do_cmd(ESPState *s)
>  
>  static void satn_pdma_cb(ESPState *s)
>  {
> -    if (get_cmd_cb(s) < 0) {
> +    if (esp_select(s) < 0) {
>          return;
>      }
>      s->do_cmd = 0;
> @@ -325,7 +325,7 @@ static void handle_satn(ESPState *s)
>  
>  static void s_without_satn_pdma_cb(ESPState *s)
>  {
> -    if (get_cmd_cb(s) < 0) {
> +    if (esp_select(s) < 0) {
>          return;
>      }
>      s->do_cmd = 0;
> @@ -351,7 +351,7 @@ static void handle_s_without_atn(ESPState *s)
>  
>  static void satn_stop_pdma_cb(ESPState *s)
>  {
> -    if (get_cmd_cb(s) < 0) {
> +    if (esp_select(s) < 0) {
>          return;
>      }
>      s->do_cmd = 0;
> 

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


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

* Re: [PATCH v2 27/42] esp: fix PDMA target selection
  2021-02-09 19:30 ` [PATCH v2 27/42] esp: fix PDMA target selection Mark Cave-Ayland
@ 2021-03-02 21:57   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 21:57 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

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>


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

* Re: [PATCH v2 28/42] esp: use FIFO for PDMA transfers between initiator and device
  2021-02-09 19:30 ` [PATCH v2 28/42] esp: use FIFO for PDMA transfers between initiator and device Mark Cave-Ayland
@ 2021-03-02 22:02   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 22:02 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> PDMA as implemented on the Quadra 800 uses DREQ to load data into the FIFO
> up to a maximum of 16 bytes at a time. The MacOS toolbox ROM requires this
> because it mixes FIFO and PDMA transfers whilst checking the FIFO status
> and counter registers to ensure success.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 109 ++++++++++++++++++++++++++++++++++----------------
>  1 file changed, 75 insertions(+), 34 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index b7ab5a5592..5dcd4cd651 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -134,13 +134,8 @@ static void set_pdma(ESPState *s, enum pdma_origin_id origin)
>  
>  static uint8_t esp_pdma_read(ESPState *s)
>  {
> -    uint32_t dmalen = esp_get_tc(s);
>      uint8_t val;
>  
> -    if (dmalen == 0) {
> -        return 0;
> -    }
> -
>      switch (s->pdma_origin) {
>      case TI:
>          if (s->do_cmd) {
> @@ -160,10 +155,6 @@ static uint8_t esp_pdma_read(ESPState *s)
>          g_assert_not_reached();
>      }
>  
> -    s->ti_size--;
> -    dmalen--;
> -    esp_set_tc(s, dmalen);
> -
>      return val;
>  }
>  
> @@ -194,7 +185,6 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>          g_assert_not_reached();
>      }
>  
> -    s->ti_size++;
>      dmalen--;
>      esp_set_tc(s, dmalen);
>  }
> @@ -290,6 +280,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
>      s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
>      s->rregs[ESP_RSEQ] = SEQ_CD;
>      esp_raise_irq(s);
> +    esp_lower_drq(s);
>  }
>  
>  static void do_cmd(ESPState *s)
> @@ -447,28 +438,71 @@ static void esp_dma_done(ESPState *s)
>  static void do_dma_pdma_cb(ESPState *s)
>  {
>      int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
> +    int len;
>  
>      if (s->do_cmd) {
>          s->ti_size = 0;
>          s->cmdlen = 0;
>          s->do_cmd = 0;
>          do_cmd(s);
> +        esp_lower_drq(s);
>          return;
>      }
> -    if (s->async_len == 0) {
> -        scsi_req_continue(s->current_req);
> -        /*
> -         * If there is still data to be read from the device then
> -         * complete the DMA operation immediately.  Otherwise defer
> -         * until the scsi layer has completed.
> -         */
> -        if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) {
> +
> +    if (to_device) {
> +        /* Copy FIFO data to device */
> +        len = MIN(s->ti_wptr, TI_BUFSZ);
> +        memcpy(s->async_buf, s->ti_buf, len);
> +        s->ti_wptr = 0;
> +        s->ti_rptr = 0;
> +        s->async_buf += len;
> +        s->async_len -= len;
> +        s->ti_size += len;
> +        if (s->async_len == 0) {
> +            scsi_req_continue(s->current_req);
>              return;
>          }
> -    }
>  
> -    /* Partially filled a scsi buffer. Complete immediately.  */
> -    esp_dma_done(s);
> +        if (esp_get_tc(s) == 0) {
> +            esp_lower_drq(s);
> +            esp_dma_done(s);
> +        }
> +
> +        return;
> +    } else {
> +        if (s->async_len == 0) {
> +            if (s->current_req) {
> +                scsi_req_continue(s->current_req);
> +            }
> +
> +            /*
> +             * If there is still data to be read from the device then
> +             * complete the DMA operation immediately.  Otherwise defer
> +             * until the scsi layer has completed.
> +             */
> +            if (esp_get_tc(s) != 0 || s->ti_size == 0) {
> +                return;
> +            }
> +        }
> +
> +        if (esp_get_tc(s) != 0) {
> +            /* Copy device data to FIFO */
> +            s->ti_wptr = 0;
> +            s->ti_rptr = 0;
> +            len = MIN(s->async_len, TI_BUFSZ);
> +            memcpy(s->ti_buf, s->async_buf, len);
> +            s->ti_wptr += len;
> +            s->async_buf += len;
> +            s->async_len -= len;
> +            s->ti_size -= len;
> +            esp_set_tc(s, esp_get_tc(s) - len);
> +            return;
> +        }
> +
> +        /* Partially filled a scsi buffer. Complete immediately.  */
> +        esp_lower_drq(s);
> +        esp_dma_done(s);
> +    }
>  }
>  
>  static void esp_do_dma(ESPState *s)
> @@ -511,7 +545,7 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, s->async_buf, len);
>          } else {
> -            set_pdma(s, ASYNC);
> +            set_pdma(s, TI);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -520,9 +554,20 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_write) {
>              s->dma_memory_write(s->dma_opaque, s->async_buf, len);
>          } else {
> -            set_pdma(s, ASYNC);
> +            /* Copy device data to FIFO */
> +            len = MIN(len, TI_BUFSZ - s->ti_wptr);
> +            memcpy(&s->ti_buf[s->ti_wptr], s->async_buf, len);
> +            s->ti_wptr += len;
> +            s->async_buf += len;
> +            s->async_len -= len;
> +            s->ti_size -= len;
> +            esp_set_tc(s, esp_get_tc(s) - len);
> +            set_pdma(s, TI);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
> +
> +            /* Indicate transfer to FIFO is complete */
> +            s->rregs[ESP_RSTAT] |= STAT_TC;
>              return;
>          }
>      }
> @@ -548,6 +593,7 @@ static void esp_do_dma(ESPState *s)
>  
>      /* Partially filled a scsi buffer. Complete immediately.  */
>      esp_dma_done(s);
> +    esp_lower_drq(s);
>  }
>  
>  static void esp_report_command_complete(ESPState *s, uint32_t status)
> @@ -564,6 +610,7 @@ static void esp_report_command_complete(ESPState *s, uint32_t status)
>      s->status = status;
>      s->rregs[ESP_RSTAT] = STAT_ST;
>      esp_dma_done(s);
> +    esp_lower_drq(s);
>      if (s->current_req) {
>          scsi_req_unref(s->current_req);
>          s->current_req = NULL;
> @@ -606,6 +653,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
>           * completion interrupt is deferred to here.
>           */
>          esp_dma_done(s);
> +        esp_lower_drq(s);
>      }
>  }
>  
> @@ -977,10 +1025,8 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>          break;
>      }
>      dmalen = esp_get_tc(s);
> -    if (dmalen == 0 && s->pdma_cb) {
> -        esp_lower_drq(s);
> +    if (dmalen == 0 || (s->ti_wptr == TI_BUFSZ)) {
>          s->pdma_cb(s);
> -        s->pdma_cb = NULL;
>      }
>  }
>  
> @@ -989,14 +1035,10 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>  {
>      SysBusESPState *sysbus = opaque;
>      ESPState *s = ESP(&sysbus->esp);
> -    uint32_t dmalen = esp_get_tc(s);
>      uint64_t val = 0;
>  
>      trace_esp_pdma_read(size);
>  
> -    if (dmalen == 0) {
> -        return 0;
> -    }
>      switch (size) {
>      case 1:
>          val = esp_pdma_read(s);
> @@ -1006,11 +1048,10 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>          val = (val << 8) | esp_pdma_read(s);
>          break;
>      }
> -    dmalen = esp_get_tc(s);
> -    if (dmalen == 0 && s->pdma_cb) {
> -        esp_lower_drq(s);
> +    if (s->ti_rptr == s->ti_wptr) {
> +        s->ti_wptr = 0;
> +        s->ti_rptr = 0;
>          s->pdma_cb(s);
> -        s->pdma_cb = NULL;
>      }
>      return val;
>  }
> 

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


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

* Re: [PATCH v2 29/42] esp: remove pdma_origin from ESPState
  2021-02-09 19:30 ` [PATCH v2 29/42] esp: remove pdma_origin from ESPState Mark Cave-Ayland
@ 2021-03-02 22:03   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 22:03 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> Now that all data is transferred via the FIFO (ti_buf) there is no need to track
> the source buffer being used for the data transfer. This also eliminates the
> need for a separate subsection for PDMA state migration.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 74 +++++--------------------------------------
>  include/hw/scsi/esp.h |  6 ----
>  2 files changed, 8 insertions(+), 72 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 5dcd4cd651..7671cc398d 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -127,32 +127,14 @@ static uint32_t esp_get_stc(ESPState *s)
>      return dmalen;
>  }
>  
> -static void set_pdma(ESPState *s, enum pdma_origin_id origin)
> -{
> -    s->pdma_origin = origin;
> -}
> -
>  static uint8_t esp_pdma_read(ESPState *s)
>  {
>      uint8_t val;
>  
> -    switch (s->pdma_origin) {
> -    case TI:
> -        if (s->do_cmd) {
> -            val = s->cmdbuf[s->cmdlen++];
> -        } else {
> -            val = s->ti_buf[s->ti_rptr++];
> -        }
> -        break;
> -    case ASYNC:
> -        val = s->async_buf[0];
> -        if (s->async_len > 0) {
> -            s->async_len--;
> -            s->async_buf++;
> -        }
> -        break;
> -    default:
> -        g_assert_not_reached();
> +    if (s->do_cmd) {
> +        val = s->cmdbuf[s->cmdlen++];
> +    } else {
> +        val = s->ti_buf[s->ti_rptr++];
>      }
>  
>      return val;
> @@ -166,23 +148,10 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>          return;
>      }
>  
> -    switch (s->pdma_origin) {
> -    case TI:
> -        if (s->do_cmd) {
> -            s->cmdbuf[s->cmdlen++] = val;
> -        } else {
> -            s->ti_buf[s->ti_wptr++] = val;
> -        }
> -        break;
> -    case ASYNC:
> -        s->async_buf[0] = val;
> -        if (s->async_len > 0) {
> -            s->async_len--;
> -            s->async_buf++;
> -        }
> -        break;
> -    default:
> -        g_assert_not_reached();
> +    if (s->do_cmd) {
> +        s->cmdbuf[s->cmdlen++] = val;
> +    } else {
> +        s->ti_buf[s->ti_wptr++] = val;
>      }
>  
>      dmalen--;
> @@ -232,7 +201,6 @@ static uint32_t get_cmd(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, buf, dmalen);
>          } else {
> -            set_pdma(s, TI);
>              if (esp_select(s) < 0) {
>                  return -1;
>              }
> @@ -411,7 +379,6 @@ static void write_response(ESPState *s)
>              s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
>              s->rregs[ESP_RSEQ] = SEQ_CD;
>          } else {
> -            set_pdma(s, TI);
>              s->pdma_cb = write_response_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -522,7 +489,6 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
>          } else {
> -            set_pdma(s, TI);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -545,7 +511,6 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, s->async_buf, len);
>          } else {
> -            set_pdma(s, TI);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
> @@ -562,7 +527,6 @@ static void esp_do_dma(ESPState *s)
>              s->async_len -= len;
>              s->ti_size -= len;
>              esp_set_tc(s, esp_get_tc(s) - len);
> -            set_pdma(s, TI);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>  
> @@ -899,24 +863,6 @@ static bool esp_mem_accepts(void *opaque, hwaddr addr,
>      return (size == 1) || (is_write && size == 4);
>  }
>  
> -static bool esp_pdma_needed(void *opaque)
> -{
> -    ESPState *s = opaque;
> -    return s->dma_memory_read == NULL && s->dma_memory_write == NULL &&
> -           s->dma_enabled;
> -}
> -
> -static const VMStateDescription vmstate_esp_pdma = {
> -    .name = "esp/pdma",
> -    .version_id = 2,
> -    .minimum_version_id = 2,
> -    .needed = esp_pdma_needed,
> -    .fields = (VMStateField[]) {
> -        VMSTATE_INT32(pdma_origin, ESPState),
> -        VMSTATE_END_OF_LIST()
> -    }
> -};
> -
>  static bool esp_is_before_version_5(void *opaque, int version_id)
>  {
>      ESPState *s = ESP(opaque);
> @@ -971,10 +917,6 @@ const VMStateDescription vmstate_esp = {
>          VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
>          VMSTATE_END_OF_LIST()
>      },
> -    .subsections = (const VMStateDescription * []) {
> -        &vmstate_esp_pdma,
> -        NULL
> -    }
>  };
>  
>  static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index a8d5bf8a63..6618f4e091 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -15,11 +15,6 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
>  
>  typedef struct ESPState ESPState;
>  
> -enum pdma_origin_id {
> -    TI,
> -    ASYNC,
> -};
> -
>  #define TYPE_ESP "esp"
>  OBJECT_DECLARE_SIMPLE_TYPE(ESPState, ESP)
>  
> @@ -55,7 +50,6 @@ struct ESPState {
>      ESPDMAMemoryReadWriteFunc dma_memory_write;
>      void *dma_opaque;
>      void (*dma_cb)(ESPState *s);
> -    int pdma_origin;
>      void (*pdma_cb)(ESPState *s);
>  
>      uint8_t mig_version_id;
> 

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


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

* Re: [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers
  2021-02-09 19:30 ` [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers Mark Cave-Ayland
  2021-02-12 18:56   ` Philippe Mathieu-Daudé
@ 2021-03-02 22:05   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-02 22:05 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> The MacOS toolbox ROM performs 4 byte reads/writes when transferring data to
> and from the target. Since the SCSI bus is 16-bits wide, use the memory API
> to split a 4 byte access into 2 x 2 byte accesses.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 7671cc398d..1d56c99527 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -1003,7 +1003,9 @@ static const MemoryRegionOps sysbus_esp_pdma_ops = {
>      .write = sysbus_esp_pdma_write,
>      .endianness = DEVICE_NATIVE_ENDIAN,
>      .valid.min_access_size = 1,
> -    .valid.max_access_size = 2,
> +    .valid.max_access_size = 4,
> +    .impl.min_access_size = 1,
> +    .impl.max_access_size = 2,
>  };
>  
>  static const struct SCSIBusInfo esp_scsi_info = {
> @@ -1048,7 +1050,7 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
>                            sysbus, "esp-regs", ESP_REGS << sysbus->it_shift);
>      sysbus_init_mmio(sbd, &sysbus->iomem);
>      memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops,
> -                          sysbus, "esp-pdma", 2);
> +                          sysbus, "esp-pdma", 4);
>      sysbus_init_mmio(sbd, &sysbus->pdma);
>  
>      qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2);
> 

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


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

* Re: [PATCH v2 01/42] esp: checkpatch fixes
  2021-03-01 19:43   ` Laurent Vivier
@ 2021-03-03  8:33     ` Mark Cave-Ayland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-03-03  8:33 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel, pbonzini, fam

On 01/03/2021 19:43, Laurent Vivier wrote:

> Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>> ---
>>   hw/scsi/esp.c | 52 ++++++++++++++++++++++++++++++---------------------
>>   1 file changed, 31 insertions(+), 21 deletions(-)
>>
>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>> index b84e0fe33e..7073166ad1 100644
>> --- a/hw/scsi/esp.c
>> +++ b/hw/scsi/esp.c
>> @@ -241,8 +241,9 @@ static void handle_satn(ESPState *s)
>>       }
>>       s->pdma_cb = satn_pdma_cb;
>>       len = get_cmd(s, buf, sizeof(buf));
>> -    if (len)
>> +    if (len) {
>>           do_cmd(s, buf);
>> +    }
>>   }
>>   
>>   static void s_without_satn_pdma_cb(ESPState *s)
>> @@ -398,8 +399,8 @@ static void esp_do_dma(ESPState *s)
>>            * handle_ti_cmd() with do_cmd != NULL (see the assert())
>>            */
>>           trace_esp_do_dma(s->cmdlen, len);
>> -        assert (s->cmdlen <= sizeof(s->cmdbuf) &&
>> -                len <= sizeof(s->cmdbuf) - s->cmdlen);
>> +        assert(s->cmdlen <= sizeof(s->cmdbuf) &&
>> +               len <= sizeof(s->cmdbuf) - s->cmdlen);
>>           if (s->dma_memory_read) {
>>               s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
>>           } else {
>> @@ -445,15 +446,18 @@ static void esp_do_dma(ESPState *s)
>>       s->dma_left -= len;
>>       s->async_buf += len;
>>       s->async_len -= len;
>> -    if (to_device)
>> +    if (to_device) {
>>           s->ti_size += len;
>> -    else
>> +    } else {
>>           s->ti_size -= len;
>> +    }
>>       if (s->async_len == 0) {
>>           scsi_req_continue(s->current_req);
>> -        /* If there is still data to be read from the device then
>> -           complete the DMA operation immediately.  Otherwise defer
>> -           until the scsi layer has completed.  */
>> +        /*
>> +         * If there is still data to be read from the device then
>> +         * complete the DMA operation immediately.  Otherwise defer
>> +         * until the scsi layer has completed.
>> +         */
>>           if (to_device || s->dma_left != 0 || s->ti_size == 0) {
>>               return;
>>           }
>> @@ -491,7 +495,8 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
>>       ESPState *s = req->hba_private;
>>   
>>       if (s->rregs[ESP_RSTAT] & STAT_INT) {
>> -        /* Defer handling command complete until the previous
>> +        /*
>> +         * Defer handling command complete until the previous
>>            * interrupt has been handled.
>>            */
>>           trace_esp_command_complete_deferred();
>> @@ -513,8 +518,10 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
>>       if (s->dma_left) {
>>           esp_do_dma(s);
>>       } else if (s->dma_counter != 0 && s->ti_size <= 0) {
>> -        /* If this was the last part of a DMA transfer then the
>> -           completion interrupt is deferred to here.  */
>> +        /*
>> +         * If this was the last part of a DMA transfer then the
>> +         * completion interrupt is deferred to here.
>> +         */
>>           esp_dma_done(s);
>>       }
>>   }
>> @@ -531,17 +538,18 @@ static void handle_ti(ESPState *s)
>>       dmalen = s->rregs[ESP_TCLO];
>>       dmalen |= s->rregs[ESP_TCMID] << 8;
>>       dmalen |= s->rregs[ESP_TCHI] << 16;
>> -    if (dmalen==0) {
>> -      dmalen=0x10000;
>> +    if (dmalen == 0) {
>> +        dmalen = 0x10000;
>>       }
>>       s->dma_counter = dmalen;
>>   
>> -    if (s->do_cmd)
>> +    if (s->do_cmd) {
>>           minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
>> -    else if (s->ti_size < 0)
>> +    } else if (s->ti_size < 0) {
>>           minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
>> -    else
>> +    } else {
>>           minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
>> +    }
>>       trace_esp_handle_ti(minlen);
>>       if (s->dma) {
>>           s->dma_left = minlen;
>> @@ -606,8 +614,10 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>>           }
>>           break;
>>       case ESP_RINTR:
>> -        /* Clear sequence step, interrupt register and all status bits
>> -           except TC */
>> +        /*
>> +         * Clear sequence step, interrupt register and all status bits
>> +         * except TC
>> +         */
>>           old_val = s->rregs[ESP_RINTR];
>>           s->rregs[ESP_RINTR] = 0;
>>           s->rregs[ESP_RSTAT] &= ~STAT_TC;
>> @@ -665,13 +675,13 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>>           } else {
>>               s->dma = 0;
>>           }
>> -        switch(val & CMD_CMD) {
>> +        switch (val & CMD_CMD) {
>>           case CMD_NOP:
>>               trace_esp_mem_writeb_cmd_nop(val);
>>               break;
>>           case CMD_FLUSH:
>>               trace_esp_mem_writeb_cmd_flush(val);
>> -            //s->ti_size = 0;
>> +            /*s->ti_size = 0;*/
> 
> Perhaps the line can simply be removed?

Phil pointed this out in one of his reviews, so I've removed it in my latest branch 
but in a later patch (I think after flush is implemented at which point we know it 
really isn't needed?).

>>               s->rregs[ESP_RINTR] = INTR_FC;
>>               s->rregs[ESP_RSEQ] = 0;
>>               s->rregs[ESP_RFLAGS] = 0;
>> @@ -787,7 +797,7 @@ static const VMStateDescription vmstate_esp_pdma = {
>>   };
>>   
>>   const VMStateDescription vmstate_esp = {
>> -    .name ="esp",
>> +    .name = "esp",
>>       .version_id = 4,
>>       .minimum_version_id = 3,
>>       .fields = (VMStateField[]) {
>>
> 
> Anyway:
> 
> Reviewed-by: Laurent Vivier <laurent@vivier.eu>


ATB,

Mark.


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

* Re: [PATCH v2 09/42] esp: introduce esp_get_tc() and esp_set_tc()
  2021-03-01 21:24   ` Laurent Vivier
@ 2021-03-03  8:35     ` Mark Cave-Ayland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-03-03  8:35 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel, pbonzini, fam

On 01/03/2021 21:24, Laurent Vivier wrote:

> Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
>> This simplifies reading and writing the TC register value without having to
>> manually shift each individual 8-bit value.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>> ---
>>   hw/scsi/esp.c | 38 +++++++++++++++++++++++---------------
>>   1 file changed, 23 insertions(+), 15 deletions(-)
>>
>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>> index e82e75d490..3a39450930 100644
>> --- a/hw/scsi/esp.c
>> +++ b/hw/scsi/esp.c
>> @@ -98,6 +98,24 @@ void esp_request_cancelled(SCSIRequest *req)
>>       }
>>   }
>>   
>> +static uint32_t esp_get_tc(ESPState *s)
>> +{
>> +    uint32_t dmalen;
>> +
>> +    dmalen = s->rregs[ESP_TCLO];
>> +    dmalen |= s->rregs[ESP_TCMID] << 8;
>> +    dmalen |= s->rregs[ESP_TCHI] << 16;
>> +
>> +    return dmalen;
>> +}
>> +
>> +static void esp_set_tc(ESPState *s, uint32_t dmalen)
>> +{
>> +    s->rregs[ESP_TCLO] = dmalen & 0xff;
> 
> The "& 0xff" is not needed as rregs is uint8_t.

That's true - I think it's just done that way since that was how it was originally 
written in the section below where I copied it from. I'll remove it in the next version.

>> +    s->rregs[ESP_TCMID] = dmalen >> 8;
>> +    s->rregs[ESP_TCHI] = dmalen >> 16;
>> +}
>> +
>>   static void set_pdma(ESPState *s, enum pdma_origin_id origin,
>>                        uint32_t index, uint32_t len)
>>   {
>> @@ -157,9 +175,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
>>   
>>       target = s->wregs[ESP_WBUSID] & BUSID_DID;
>>       if (s->dma) {
>> -        dmalen = s->rregs[ESP_TCLO];
>> -        dmalen |= s->rregs[ESP_TCMID] << 8;
>> -        dmalen |= s->rregs[ESP_TCHI] << 16;
>> +        dmalen = esp_get_tc(s);
>>           if (dmalen > buflen) {
>>               return 0;
>>           }
>> @@ -348,9 +364,7 @@ static void esp_dma_done(ESPState *s)
>>       s->rregs[ESP_RINTR] = INTR_BS;
>>       s->rregs[ESP_RSEQ] = 0;
>>       s->rregs[ESP_RFLAGS] = 0;
>> -    s->rregs[ESP_TCLO] = 0;
>> -    s->rregs[ESP_TCMID] = 0;
>> -    s->rregs[ESP_TCHI] = 0;
>> +    esp_set_tc(s, 0);
>>       esp_raise_irq(s);
>>   }
>>   
>> @@ -536,9 +550,7 @@ static void handle_ti(ESPState *s)
>>           return;
>>       }
>>   
>> -    dmalen = s->rregs[ESP_TCLO];
>> -    dmalen |= s->rregs[ESP_TCMID] << 8;
>> -    dmalen |= s->rregs[ESP_TCHI] << 16;
>> +    dmalen = esp_get_tc(s);
>>       if (dmalen == 0) {
>>           dmalen = 0x10000;
>>       }
>> @@ -889,9 +901,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>>   
>>       trace_esp_pdma_write(size);
>>   
>> -    dmalen = s->rregs[ESP_TCLO];
>> -    dmalen |= s->rregs[ESP_TCMID] << 8;
>> -    dmalen |= s->rregs[ESP_TCHI] << 16;
>> +    dmalen = esp_get_tc(s);
>>       if (dmalen == 0 || s->pdma_len == 0) {
>>           return;
>>       }
>> @@ -908,9 +918,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>>           dmalen -= 2;
>>           break;
>>       }
>> -    s->rregs[ESP_TCLO] = dmalen & 0xff;
>> -    s->rregs[ESP_TCMID] = dmalen >> 8;
>> -    s->rregs[ESP_TCHI] = dmalen >> 16;
>> +    esp_set_tc(s, dmalen);
>>       if (s->pdma_len == 0 && s->pdma_cb) {
>>           esp_lower_drq(s);
>>           s->pdma_cb(s);
>>
> 
> Reviewed-by: Laurent Vivier <laurent@vivier.eu>


ATB,

Mark.


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

* Re: [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time
  2021-03-01 21:35   ` Laurent Vivier
@ 2021-03-03  8:44     ` Mark Cave-Ayland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-03-03  8:44 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel, pbonzini, fam

On 01/03/2021 21:35, Laurent Vivier wrote:

> Le 09/02/2021 à 20:29, Mark Cave-Ayland a écrit :
>> Perform the length adjustment whereby a value of 0 in the STC represents
>> a transfer length of 0x10000 at the point where the TC is loaded at the
>> start of a DMA command rather than just when a TI (Transfer Information)
>> command is executed. This better matches the description as given in the
>> datasheet.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp.c | 9 +++++----
>>   1 file changed, 5 insertions(+), 4 deletions(-)
>>
>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>> index a1acc2c9bd..02b7876394 100644
>> --- a/hw/scsi/esp.c
>> +++ b/hw/scsi/esp.c
>> @@ -562,9 +562,6 @@ static void handle_ti(ESPState *s)
>>       }
>>   
>>       dmalen = esp_get_tc(s);
>> -    if (dmalen == 0) {
>> -        dmalen = 0x10000;
>> -    }
>>       s->dma_counter = dmalen;
>>   
>>       if (s->do_cmd) {
>> @@ -699,7 +696,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>>           if (val & CMD_DMA) {
>>               s->dma = 1;
>>               /* Reload DMA counter.  */
>> -            esp_set_tc(s, esp_get_stc(s));
>> +            if (esp_get_stc(s) == 0) {
>> +                esp_set_tc(s, 0x10000);
>> +            } else {
>> +                esp_set_tc(s, esp_get_stc(s));
>> +            }
> 
> More fun?
> 
>      esp_set_tc(s, esp_get_stc(s) ?: 0x10000);

I've just tried this, and it feels less intuitive to read when skimming over the 
code. I'd prefer to keep this in its current form and just accept that my coding 
style is more functional than artistic :/

>>           } else {
>>               s->dma = 0;
>>           }
>>
> 
> Reviewed-by: Laurent Vivier <laurent@vivier.eu>


ATB,

Mark.


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

* Re: [PATCH v2 31/42] esp: implement FIFO flush command
  2021-02-09 19:30 ` [PATCH v2 31/42] esp: implement FIFO flush command Mark Cave-Ayland
@ 2021-03-03 19:32   ` Laurent Vivier
  2021-03-04 18:26     ` Mark Cave-Ayland
  0 siblings, 1 reply; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 19:32 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> At this point it is now possible to properly implement the FIFO flush command
> without causing guest errors.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 1d56c99527..0994673ff8 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -770,6 +770,8 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          case CMD_FLUSH:
>              trace_esp_mem_writeb_cmd_flush(val);
>              /*s->ti_size = 0;*/
> +            s->ti_wptr = 0;
> +            s->ti_rptr = 0;
>              s->rregs[ESP_RINTR] = INTR_FC;
>              s->rregs[ESP_RSEQ] = 0;
>              s->rregs[ESP_RFLAGS] = 0;
> 

Why don't  you set aso ti_size to 0?

Anyway:

Reviwed-by: Laurent Vivier <laurent@vivier.eu>

Thanks,
Laurent


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

* Re: [PATCH v2 32/42] esp: latch individual bits in ESP_RINTR register
  2021-02-09 19:30 ` [PATCH v2 32/42] esp: latch individual bits in ESP_RINTR register Mark Cave-Ayland
@ 2021-03-03 19:48   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 19:48 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> Currently the ESP_RINTR register is set to a specific value as required within
> the ESP state machine. In order to implement the upcoming deferred interrupt
> functionality it is necessary to set individual bits within ESP_RINTR so that
> a deferred interrupt will not overwrite the value of any other interrupt bits.
> 
> This also requires fixing up a few locations where the ESP_RINTR and ESP_RSEQ
> registers are set/reset unexpectedly.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 29 +++++++++++++----------------
>  1 file changed, 13 insertions(+), 16 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 0994673ff8..728d4ddf99 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -178,7 +178,7 @@ static int esp_select(ESPState *s)
>      if (!s->current_dev) {
>          /* No such drive */
>          s->rregs[ESP_RSTAT] = 0;
> -        s->rregs[ESP_RINTR] = INTR_DC;
> +        s->rregs[ESP_RINTR] |= INTR_DC;
>          s->rregs[ESP_RSEQ] = SEQ_0;
>          esp_raise_irq(s);
>          return -1;
> @@ -245,7 +245,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
>          }
>          scsi_req_continue(s->current_req);
>      }
> -    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
> +    s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>      s->rregs[ESP_RSEQ] = SEQ_CD;
>      esp_raise_irq(s);
>      esp_lower_drq(s);
> @@ -326,7 +326,7 @@ static void satn_stop_pdma_cb(ESPState *s)
>          trace_esp_handle_satn_stop(s->cmdlen);
>          s->do_cmd = 1;
>          s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
> -        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
> +        s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>          s->rregs[ESP_RSEQ] = SEQ_CD;
>          esp_raise_irq(s);
>      }
> @@ -346,8 +346,8 @@ static void handle_satn_stop(ESPState *s)
>          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_RSTAT] = STAT_CD;
> +        s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>          s->rregs[ESP_RSEQ] = SEQ_CD;
>          esp_raise_irq(s);
>      } else if (cmdlen == 0) {
> @@ -362,7 +362,7 @@ static void handle_satn_stop(ESPState *s)
>  static void write_response_pdma_cb(ESPState *s)
>  {
>      s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
> -    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
> +    s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>      s->rregs[ESP_RSEQ] = SEQ_CD;
>      esp_raise_irq(s);
>  }
> @@ -376,7 +376,7 @@ static void write_response(ESPState *s)
>          if (s->dma_memory_write) {
>              s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
>              s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
> -            s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
> +            s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>              s->rregs[ESP_RSEQ] = SEQ_CD;
>          } else {
>              s->pdma_cb = write_response_pdma_cb;
> @@ -395,7 +395,7 @@ static void write_response(ESPState *s)
>  static void esp_dma_done(ESPState *s)
>  {
>      s->rregs[ESP_RSTAT] |= STAT_TC;
> -    s->rregs[ESP_RINTR] = INTR_BS;
> +    s->rregs[ESP_RINTR] |= INTR_BS;
>      s->rregs[ESP_RSEQ] = 0;
>      s->rregs[ESP_RFLAGS] = 0;
>      esp_set_tc(s, 0);
> @@ -701,7 +701,7 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>          val = s->rregs[ESP_RINTR];
>          s->rregs[ESP_RINTR] = 0;
>          s->rregs[ESP_RSTAT] &= ~STAT_TC;
> -        s->rregs[ESP_RSEQ] = SEQ_CD;
> +        s->rregs[ESP_RSEQ] = SEQ_0;
>          esp_lower_irq(s);
>          if (s->deferred_complete) {
>              esp_report_command_complete(s, s->deferred_status);
> @@ -772,9 +772,6 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>              /*s->ti_size = 0;*/
>              s->ti_wptr = 0;
>              s->ti_rptr = 0;
> -            s->rregs[ESP_RINTR] = INTR_FC;
> -            s->rregs[ESP_RSEQ] = 0;
> -            s->rregs[ESP_RFLAGS] = 0;
>              break;
>          case CMD_RESET:
>              trace_esp_mem_writeb_cmd_reset(val);
> @@ -782,8 +779,8 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>              break;
>          case CMD_BUSRESET:
>              trace_esp_mem_writeb_cmd_bus_reset(val);
> -            s->rregs[ESP_RINTR] = INTR_RST;
>              if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
> +                s->rregs[ESP_RINTR] |= INTR_RST;
>                  esp_raise_irq(s);
>              }
>              break;
> @@ -794,12 +791,12 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          case CMD_ICCS:
>              trace_esp_mem_writeb_cmd_iccs(val);
>              write_response(s);
> -            s->rregs[ESP_RINTR] = INTR_FC;
> +            s->rregs[ESP_RINTR] |= INTR_FC;
>              s->rregs[ESP_RSTAT] |= STAT_MI;
>              break;
>          case CMD_MSGACC:
>              trace_esp_mem_writeb_cmd_msgacc(val);
> -            s->rregs[ESP_RINTR] = INTR_DC;
> +            s->rregs[ESP_RINTR] |= INTR_DC;
>              s->rregs[ESP_RSEQ] = 0;
>              s->rregs[ESP_RFLAGS] = 0;
>              esp_raise_irq(s);
> @@ -807,7 +804,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          case CMD_PAD:
>              trace_esp_mem_writeb_cmd_pad(val);
>              s->rregs[ESP_RSTAT] = STAT_TC;
> -            s->rregs[ESP_RINTR] = INTR_FC;
> +            s->rregs[ESP_RINTR] |= INTR_FC;
>              s->rregs[ESP_RSEQ] = 0;
>              break;
>          case CMD_SATN:
> 

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


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

* Re: [PATCH v2 33/42] esp: defer command completion interrupt on incoming data transfers
  2021-02-18 17:25   ` Mark Cave-Ayland
@ 2021-03-03 19:52     ` Laurent Vivier
  2021-03-04 18:33       ` Mark Cave-Ayland
  0 siblings, 1 reply; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 19:52 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 18/02/2021 à 18:25, Mark Cave-Ayland a écrit :
> On 09/02/2021 19:30, Mark Cave-Ayland wrote:
> 
>> The MacOS toolbox ROM issues a command to the ESP controller as part of its
>> "FAST" SCSI routines and then proceeds to read the incoming data soon after
>> receiving the command completion interrupt.
>>
>> Unfortunately due to SCSI block transfers being asynchronous the incoming data
>> may not yet be present causing an underflow error. Resolve this by waiting for
>> the SCSI subsystem transfer_data callback before raising the command completion
>> interrupt.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp.c         | 54 +++++++++++++++++++++++++++++++++++++++----
>>   include/hw/scsi/esp.h |  1 +
>>   2 files changed, 51 insertions(+), 4 deletions(-)
>>
>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>> index 728d4ddf99..ce6a7a1ed0 100644
>> --- a/hw/scsi/esp.c
>> +++ b/hw/scsi/esp.c
>> @@ -183,6 +183,14 @@ static int esp_select(ESPState *s)
>>           esp_raise_irq(s);
>>           return -1;
>>       }
>> +
>> +    /*
>> +     * Note that we deliberately don't raise the IRQ here: this will be done
>> +     * either in do_busid_cmd() for DATA OUT transfers or by the deferred
>> +     * IRQ mechanism in esp_transfer_data() for DATA IN transfers
>> +     */
>> +    s->rregs[ESP_RINTR] |= INTR_FC;
>> +    s->rregs[ESP_RSEQ] = SEQ_CD;
>>       return 0;
>>   }
>>   @@ -237,18 +245,24 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
>>       s->ti_size = datalen;
>>       if (datalen != 0) {
>>           s->rregs[ESP_RSTAT] = STAT_TC;
>> +        s->rregs[ESP_RSEQ] = SEQ_CD;
>>           esp_set_tc(s, 0);
>>           if (datalen > 0) {
>> +            /*
>> +             * Switch to DATA IN phase but wait until initial data xfer is
>> +             * complete before raising the command completion interrupt
>> +             */
>> +            s->data_in_ready = false;
>>               s->rregs[ESP_RSTAT] |= STAT_DI;
>>           } else {
>>               s->rregs[ESP_RSTAT] |= STAT_DO;
>> +            s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>> +            esp_raise_irq(s);
>> +            esp_lower_drq(s);
>>           }
>>           scsi_req_continue(s->current_req);
>> +        return;
>>       }
>> -    s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>> -    s->rregs[ESP_RSEQ] = SEQ_CD;
>> -    esp_raise_irq(s);
>> -    esp_lower_drq(s);
>>   }
>>     static void do_cmd(ESPState *s)
>> @@ -603,12 +617,35 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
>>   void esp_transfer_data(SCSIRequest *req, uint32_t len)
>>   {
>>       ESPState *s = req->hba_private;
>> +    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
>>       uint32_t dmalen = esp_get_tc(s);
>>         assert(!s->do_cmd);
>>       trace_esp_transfer_data(dmalen, s->ti_size);
>>       s->async_len = len;
>>       s->async_buf = scsi_req_get_buf(req);
>> +
>> +    if (!to_device && !s->data_in_ready) {
>> +        /*
>> +         * Initial incoming data xfer is complete so raise command
>> +         * completion interrupt
>> +         */
>> +        s->data_in_ready = true;
>> +        s->rregs[ESP_RSTAT] |= STAT_TC;
>> +        s->rregs[ESP_RINTR] |= INTR_BS;
>> +        esp_raise_irq(s);
>> +
>> +        /*
>> +         * If data is ready to transfer and the TI command has already
>> +         * been executed, start DMA immediately. Otherwise DMA will start
>> +         * when host sends the TI command
>> +         */
>> +        if (s->ti_size && (s->rregs[ESP_CMD] == (CMD_TI | CMD_DMA))) {
>> +            esp_do_dma(s);
>> +        }
>> +        return;
>> +    }
>> +
>>       if (dmalen) {
>>           esp_do_dma(s);
>>       } else if (s->ti_size <= 0) {
>> @@ -870,6 +907,14 @@ static bool esp_is_before_version_5(void *opaque, int version_id)
>>       return version_id < 5;
>>   }
>>   +static bool esp_is_version_5(void *opaque, int version_id)
>> +{
>> +    ESPState *s = ESP(opaque);
>> +
>> +    version_id = MIN(version_id, s->mig_version_id);
>> +    return version_id == 5;
>> +}
>> +
>>   static int esp_pre_save(void *opaque)
>>   {
>>       ESPState *s = ESP(opaque);
>> @@ -914,6 +959,7 @@ const VMStateDescription vmstate_esp = {
>>           VMSTATE_UINT32(cmdlen, ESPState),
>>           VMSTATE_UINT32(do_cmd, ESPState),
>>           VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
>> +        VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
>>           VMSTATE_END_OF_LIST()
>>       },
>>   };
>> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
>> index 6618f4e091..3b69aedebe 100644
>> --- a/include/hw/scsi/esp.h
>> +++ b/include/hw/scsi/esp.h
>> @@ -41,6 +41,7 @@ struct ESPState {
>>       uint32_t cmdlen;
>>       uint32_t do_cmd;
>>   +    bool data_in_ready;
>>       int dma_enabled;
>>         uint32_t async_len;
> 
> Whilst doing some testing earlier, I discovered that the same change is required in
> do_dma_pdma_cb(): it seems during boot the ROM attempts several 128k DMA requests in a row, and with
> heavy debugging enabled it's enough to trigger the same underflow problem.
> 
> Fortunately the fix is easy, and I'll squash this into the v3 series:
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index a175191718..248c1ce27a 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -453,17 +453,13 @@ static void do_dma_pdma_cb(ESPState *s)
>      } else {
>          if (s->async_len == 0) {
>              if (s->current_req) {
> +               /*
> +                * Defer until the scsi layer has completed.
> +                */
>                  scsi_req_continue(s->current_req);
> +                s->data_in_ready = false;
>              }
> -
> -            /*
> -             * If there is still data to be read from the device then
> -             * complete the DMA operation immediately.  Otherwise defer
> -             * until the scsi layer has completed.
> -             */
> -            if (esp_get_tc(s) != 0 || s->ti_size == 0) {
> -                return;
> -            }
> +            return;
>          }
> 
>          if (esp_get_tc(s) != 0) {
> 
> 
> ATB,
> 
> Mark.


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


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

* Re: [PATCH v2 34/42] esp: remove old deferred command completion mechanism
  2021-02-09 19:30 ` [PATCH v2 34/42] esp: remove old deferred command completion mechanism Mark Cave-Ayland
@ 2021-03-03 19:55   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 19:55 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> Commit ea84a44250 "scsi: esp: Defer command completion until previous interrupts
> have been handled" provided a mechanism to delay the command completion interrupt
> until ESP_RINTR is read after the command has completed.
> 
> With the previous fixes for latching the ESP_RINTR bits and deferring the setting
> of the command completion interrupt for incoming data to the SCSI callback, this
> workaround is no longer required and can be removed.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 33 ++++++++-------------------------
>  include/hw/scsi/esp.h |  4 ++--
>  2 files changed, 10 insertions(+), 27 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index ce6a7a1ed0..8b856155d1 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -574,8 +574,11 @@ static void esp_do_dma(ESPState *s)
>      esp_lower_drq(s);
>  }
>  
> -static void esp_report_command_complete(ESPState *s, uint32_t status)
> +void esp_command_complete(SCSIRequest *req, uint32_t status,
> +                          size_t resid)
>  {
> +    ESPState *s = req->hba_private;
> +
>      trace_esp_command_complete();
>      if (s->ti_size != 0) {
>          trace_esp_command_complete_unexpected();
> @@ -596,24 +599,6 @@ static void esp_report_command_complete(ESPState *s, uint32_t status)
>      }
>  }
>  
> -void esp_command_complete(SCSIRequest *req, uint32_t status,
> -                          size_t resid)
> -{
> -    ESPState *s = req->hba_private;
> -
> -    if (s->rregs[ESP_RSTAT] & STAT_INT) {
> -        /*
> -         * Defer handling command complete until the previous
> -         * interrupt has been handled.
> -         */
> -        trace_esp_command_complete_deferred();
> -        s->deferred_status = status;
> -        s->deferred_complete = true;
> -        return;
> -    }
> -    esp_report_command_complete(s, status);
> -}
> -
>  void esp_transfer_data(SCSIRequest *req, uint32_t len)
>  {
>      ESPState *s = req->hba_private;
> @@ -740,10 +725,6 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>          s->rregs[ESP_RSTAT] &= ~STAT_TC;
>          s->rregs[ESP_RSEQ] = SEQ_0;
>          esp_lower_irq(s);
> -        if (s->deferred_complete) {
> -            esp_report_command_complete(s, s->deferred_status);
> -            s->deferred_complete = false;
> -        }
>          break;
>      case ESP_TCHI:
>          /* Return the unique id if the value has never been written */
> @@ -951,8 +932,10 @@ const VMStateDescription vmstate_esp = {
>          VMSTATE_UINT32(ti_wptr, ESPState),
>          VMSTATE_BUFFER(ti_buf, ESPState),
>          VMSTATE_UINT32(status, ESPState),
> -        VMSTATE_UINT32(deferred_status, ESPState),
> -        VMSTATE_BOOL(deferred_complete, ESPState),
> +        VMSTATE_UINT32_TEST(mig_deferred_status, ESPState,
> +                            esp_is_before_version_5),
> +        VMSTATE_BOOL_TEST(mig_deferred_complete, ESPState,
> +                          esp_is_before_version_5),
>          VMSTATE_UINT32(dma, ESPState),
>          VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16),
>          VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 3b69aedebe..5e68908fcb 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -30,8 +30,6 @@ struct ESPState {
>      int32_t ti_size;
>      uint32_t ti_rptr, ti_wptr;
>      uint32_t status;
> -    uint32_t deferred_status;
> -    bool deferred_complete;
>      uint32_t dma;
>      uint8_t ti_buf[TI_BUFSZ];
>      SCSIBus bus;
> @@ -57,6 +55,8 @@ struct ESPState {
>  
>      /* Legacy fields for vmstate_esp version < 5 */
>      uint32_t mig_dma_left;
> +    uint32_t mig_deferred_status;
> +    bool mig_deferred_complete;
>  };
>  
>  #define TYPE_SYSBUS_ESP "sysbus-esp"
> 

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


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

* Re: [PATCH v2 35/42] esp: raise interrupt after every non-DMA byte transferred to the FIFO
  2021-02-09 19:30 ` [PATCH v2 35/42] esp: raise interrupt after every non-DMA byte transferred to the FIFO Mark Cave-Ayland
@ 2021-03-03 19:59   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 19:59 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> This matches the description in the datasheet and is required as support for
> non-DMA transfers is added.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 8b856155d1..617fdcb3ed 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -767,6 +767,12 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>              s->ti_size++;
>              s->ti_buf[s->ti_wptr++] = val & 0xff;
>          }
> +
> +        /* Non-DMA transfers raise an interrupt after every byte */
> +        if (s->rregs[ESP_CMD] == CMD_TI) {
> +            s->rregs[ESP_RINTR] |= INTR_FC | INTR_BS;
> +            esp_raise_irq(s);
> +        }
>          break;
>      case ESP_CMD:
>          s->rregs[saddr] = val;
> 

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


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

* Re: [PATCH v2 36/42] esp: add maxlen parameter to get_cmd()
  2021-02-09 19:30 ` [PATCH v2 36/42] esp: add maxlen parameter to get_cmd() Mark Cave-Ayland
  2021-02-23 18:43   ` Philippe Mathieu-Daudé
@ 2021-03-03 20:04   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 20:04 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> Some guests use a mixture of DMA and non-DMA transfers in combination with the
> SATN and stop command to transfer message out phase and command phase bytes to
> the target. Prepare for the next commit by adding a maxlen parameter to
> get_cmd() to allow partial transfers.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 20 +++++++++++---------
>  1 file changed, 11 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 617fdcb3ed..058b482fda 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -194,7 +194,7 @@ static int esp_select(ESPState *s)
>      return 0;
>  }
>  
> -static uint32_t get_cmd(ESPState *s)
> +static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
>  {
>      uint8_t *buf = s->cmdbuf;
>      uint32_t dmalen;
> @@ -202,8 +202,8 @@ static uint32_t get_cmd(ESPState *s)
>  
>      target = s->wregs[ESP_WBUSID] & BUSID_DID;
>      if (s->dma) {
> -        dmalen = esp_get_tc(s);
> -        if (dmalen > ESP_CMDBUF_SZ) {
> +        dmalen = MIN(esp_get_tc(s), maxlen);
> +        if (dmalen == 0) {
>              return 0;
>          }
>          if (s->dma_memory_read) {
> @@ -216,12 +216,14 @@ static uint32_t get_cmd(ESPState *s)
>              return 0;
>          }
>      } else {
> -        dmalen = s->ti_size;
> -        if (dmalen > TI_BUFSZ) {
> +        dmalen = MIN(s->ti_size, maxlen);
> +        if (dmalen == 0) {
>              return 0;
>          }
>          memcpy(buf, s->ti_buf, dmalen);
> -        buf[0] = buf[2] >> 5;
> +        if (dmalen >= 3) {
> +            buf[0] = buf[2] >> 5;
> +        }
>      }
>      trace_esp_get_cmd(dmalen, target);
>  
> @@ -290,7 +292,7 @@ static void handle_satn(ESPState *s)
>          return;
>      }
>      s->pdma_cb = satn_pdma_cb;
> -    cmdlen = get_cmd(s);
> +    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
>      if (cmdlen > 0) {
>          s->cmdlen = cmdlen;
>          do_cmd(s);
> @@ -320,7 +322,7 @@ static void handle_s_without_atn(ESPState *s)
>          return;
>      }
>      s->pdma_cb = s_without_satn_pdma_cb;
> -    cmdlen = get_cmd(s);
> +    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
>      if (cmdlen > 0) {
>          s->cmdlen = cmdlen;
>          do_busid_cmd(s, s->cmdbuf, 0);
> @@ -355,7 +357,7 @@ static void handle_satn_stop(ESPState *s)
>          return;
>      }
>      s->pdma_cb = satn_stop_pdma_cb;
> -    cmdlen = get_cmd(s);
> +    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
>      if (cmdlen > 0) {
>          trace_esp_handle_satn_stop(s->cmdlen);
>          s->cmdlen = cmdlen;
> 

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


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

* Re: [PATCH v2 37/42] esp: transition to message out phase after SATN and stop command
  2021-02-09 19:30 ` [PATCH v2 37/42] esp: transition to message out phase after SATN and stop command Mark Cave-Ayland
@ 2021-03-03 20:06   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 20:06 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> The SCSI bus should remain in the message out phase after the SATN and stop
> command rather than transitioning to the command phase. A new ESPState variable
> cmdbuf_cdb_offset is added which stores the offset of the CDB from the start
> of cmdbuf when accumulating extended message out phase data.
> 
> Currently any extended message out data is discarded in do_cmd() before the CDB
> is processed in do_busid_cmd().
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 72 ++++++++++++++++++++++++++++++++++---------
>  include/hw/scsi/esp.h |  2 ++
>  2 files changed, 60 insertions(+), 14 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 058b482fda..5a66b7d710 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -272,13 +272,15 @@ static void do_cmd(ESPState *s)
>      uint8_t *buf = s->cmdbuf;
>      uint8_t busid = buf[0];
>  
> -    do_busid_cmd(s, &buf[1], busid);
> +    /* Ignore extended messages for now */
> +    do_busid_cmd(s, &buf[s->cmdbuf_cdb_offset], busid);
>  }
>  
>  static void satn_pdma_cb(ESPState *s)
>  {
>      s->do_cmd = 0;
>      if (s->cmdlen) {
> +        s->cmdbuf_cdb_offset = 1;
>          do_cmd(s);
>      }
>  }
> @@ -295,6 +297,7 @@ static void handle_satn(ESPState *s)
>      cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
>      if (cmdlen > 0) {
>          s->cmdlen = cmdlen;
> +        s->cmdbuf_cdb_offset = 1;
>          do_cmd(s);
>      } else if (cmdlen == 0) {
>          s->cmdlen = 0;
> @@ -309,6 +312,7 @@ static void s_without_satn_pdma_cb(ESPState *s)
>  {
>      s->do_cmd = 0;
>      if (s->cmdlen) {
> +        s->cmdbuf_cdb_offset = 0;
>          do_busid_cmd(s, s->cmdbuf, 0);
>      }
>  }
> @@ -325,6 +329,7 @@ static void handle_s_without_atn(ESPState *s)
>      cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
>      if (cmdlen > 0) {
>          s->cmdlen = cmdlen;
> +        s->cmdbuf_cdb_offset = 0;
>          do_busid_cmd(s, s->cmdbuf, 0);
>      } else if (cmdlen == 0) {
>          s->cmdlen = 0;
> @@ -341,6 +346,7 @@ static void satn_stop_pdma_cb(ESPState *s)
>      if (s->cmdlen) {
>          trace_esp_handle_satn_stop(s->cmdlen);
>          s->do_cmd = 1;
> +        s->cmdbuf_cdb_offset = 1;
>          s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
>          s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>          s->rregs[ESP_RSEQ] = SEQ_CD;
> @@ -357,21 +363,22 @@ static void handle_satn_stop(ESPState *s)
>          return;
>      }
>      s->pdma_cb = satn_stop_pdma_cb;
> -    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
> +    cmdlen = get_cmd(s, 1);
>      if (cmdlen > 0) {
> -        trace_esp_handle_satn_stop(s->cmdlen);
> +        trace_esp_handle_satn_stop(cmdlen);
>          s->cmdlen = cmdlen;
>          s->do_cmd = 1;
> -        s->rregs[ESP_RSTAT] = STAT_CD;
> +        s->cmdbuf_cdb_offset = 1;
> +        s->rregs[ESP_RSTAT] = STAT_MO;
>          s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
> -        s->rregs[ESP_RSEQ] = SEQ_CD;
> +        s->rregs[ESP_RSEQ] = SEQ_MO;
>          esp_raise_irq(s);
>      } 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;
> +        /* Target present, switch to message out phase */
> +        s->rregs[ESP_RSEQ] = SEQ_MO;
> +        s->rregs[ESP_RSTAT] = STAT_MO;
>      }
>  }
>  
> @@ -511,9 +518,27 @@ static void esp_do_dma(ESPState *s)
>          }
>          trace_esp_handle_ti_cmd(s->cmdlen);
>          s->ti_size = 0;
> -        s->cmdlen = 0;
> -        s->do_cmd = 0;
> -        do_cmd(s);
> +        if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
> +            /* No command received */
> +            if (s->cmdbuf_cdb_offset == s->cmdlen) {
> +                return;
> +            }
> +
> +            /* Command has been received */
> +            s->cmdlen = 0;
> +            s->do_cmd = 0;
> +            do_cmd(s);
> +        } else {
> +            /*
> +             * Extra message out bytes received: update cmdbuf_cdb_offset
> +             * and then switch to commmand phase
> +             */
> +            s->cmdbuf_cdb_offset = s->cmdlen;
> +            s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
> +            s->rregs[ESP_RSEQ] = SEQ_CD;
> +            s->rregs[ESP_RINTR] |= INTR_BS;
> +            esp_raise_irq(s);
> +        }
>          return;
>      }
>      if (s->async_len == 0) {
> @@ -662,9 +687,27 @@ static void handle_ti(ESPState *s)
>      } else if (s->do_cmd) {
>          trace_esp_handle_ti_cmd(s->cmdlen);
>          s->ti_size = 0;
> -        s->cmdlen = 0;
> -        s->do_cmd = 0;
> -        do_cmd(s);
> +        if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
> +            /* No command received */
> +            if (s->cmdbuf_cdb_offset == s->cmdlen) {
> +                return;
> +            }
> +
> +            /* Command has been received */
> +            s->cmdlen = 0;
> +            s->do_cmd = 0;
> +            do_cmd(s);
> +        } else {
> +            /*
> +             * Extra message out bytes received: update cmdbuf_cdb_offset
> +             * and then switch to commmand phase
> +             */
> +            s->cmdbuf_cdb_offset = s->cmdlen;
> +            s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
> +            s->rregs[ESP_RSEQ] = SEQ_CD;
> +            s->rregs[ESP_RINTR] |= INTR_BS;
> +            esp_raise_irq(s);
> +        }
>      }
>  }
>  
> @@ -951,6 +994,7 @@ const VMStateDescription vmstate_esp = {
>          VMSTATE_UINT32(do_cmd, ESPState),
>          VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
>          VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
> +        VMSTATE_UINT8_TEST(cmdbuf_cdb_offset, ESPState, esp_is_version_5),
>          VMSTATE_END_OF_LIST()
>      },
>  };
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 5e68908fcb..6f3bf4a0ce 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -37,6 +37,7 @@ struct ESPState {
>      SCSIRequest *current_req;
>      uint8_t cmdbuf[ESP_CMDBUF_SZ];
>      uint32_t cmdlen;
> +    uint8_t cmdbuf_cdb_offset;
>      uint32_t do_cmd;
>  
>      bool data_in_ready;
> @@ -136,6 +137,7 @@ struct SysBusESPState {
>  #define INTR_RST 0x80
>  
>  #define SEQ_0 0x0
> +#define SEQ_MO 0x1
>  #define SEQ_CD 0x4
>  
>  #define CFG1_RESREPT 0x40
> 

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


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

* Re: [PATCH v2 38/42] esp: convert ti_buf from array to Fifo8
  2021-02-09 19:30 ` [PATCH v2 38/42] esp: convert ti_buf from array to Fifo8 Mark Cave-Ayland
  2021-02-23 18:49   ` Philippe Mathieu-Daudé
@ 2021-03-03 20:11   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 20:11 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> Rename TI_BUFSZ to ESP_FIFO_SZ since this constant is really describing the size
> of the FIFO and is not directly related to the TI size.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 117 ++++++++++++++++++++++++++----------------
>  include/hw/scsi/esp.h |   8 +--
>  2 files changed, 79 insertions(+), 46 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 5a66b7d710..98df357276 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -98,6 +98,25 @@ void esp_request_cancelled(SCSIRequest *req)
>      }
>  }
>  
> +static void esp_fifo_push(ESPState *s, uint8_t val)
> +{
> +    if (fifo8_num_used(&s->fifo) == ESP_FIFO_SZ) {
> +        trace_esp_error_fifo_overrun();
> +        return;
> +    }
> +
> +    fifo8_push(&s->fifo, val);
> +}
> +
> +static uint8_t esp_fifo_pop(ESPState *s)
> +{
> +    if (fifo8_is_empty(&s->fifo)) {
> +        return 0;
> +    }
> +
> +    return fifo8_pop(&s->fifo);
> +}
> +
>  static uint32_t esp_get_tc(ESPState *s)
>  {
>      uint32_t dmalen;
> @@ -134,7 +153,7 @@ static uint8_t esp_pdma_read(ESPState *s)
>      if (s->do_cmd) {
>          val = s->cmdbuf[s->cmdlen++];
>      } else {
> -        val = s->ti_buf[s->ti_rptr++];
> +        val = esp_fifo_pop(s);
>      }
>  
>      return val;
> @@ -151,7 +170,7 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>      if (s->do_cmd) {
>          s->cmdbuf[s->cmdlen++] = val;
>      } else {
> -        s->ti_buf[s->ti_wptr++] = val;
> +        esp_fifo_push(s, val);
>      }
>  
>      dmalen--;
> @@ -165,8 +184,7 @@ static int esp_select(ESPState *s)
>      target = s->wregs[ESP_WBUSID] & BUSID_DID;
>  
>      s->ti_size = 0;
> -    s->ti_rptr = 0;
> -    s->ti_wptr = 0;
> +    fifo8_reset(&s->fifo);
>  
>      if (s->current_req) {
>          /* Started a new command before the old one finished.  Cancel it.  */
> @@ -197,7 +215,7 @@ static int esp_select(ESPState *s)
>  static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
>  {
>      uint8_t *buf = s->cmdbuf;
> -    uint32_t dmalen;
> +    uint32_t dmalen, n;
>      int target;
>  
>      target = s->wregs[ESP_WBUSID] & BUSID_DID;
> @@ -220,7 +238,7 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
>          if (dmalen == 0) {
>              return 0;
>          }
> -        memcpy(buf, s->ti_buf, dmalen);
> +        memcpy(buf, fifo8_pop_buf(&s->fifo, dmalen, &n), dmalen);
>          if (dmalen >= 3) {
>              buf[0] = buf[2] >> 5;
>          }
> @@ -392,12 +410,18 @@ static void write_response_pdma_cb(ESPState *s)
>  
>  static void write_response(ESPState *s)
>  {
> +    uint32_t n;
> +
>      trace_esp_write_response(s->status);
> -    s->ti_buf[0] = s->status;
> -    s->ti_buf[1] = 0;
> +
> +    fifo8_reset(&s->fifo);
> +    esp_fifo_push(s, s->status);
> +    esp_fifo_push(s, 0);
> +
>      if (s->dma) {
>          if (s->dma_memory_write) {
> -            s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
> +            s->dma_memory_write(s->dma_opaque,
> +                                (uint8_t *)fifo8_pop_buf(&s->fifo, 2, &n), 2);
>              s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
>              s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>              s->rregs[ESP_RSEQ] = SEQ_CD;
> @@ -408,8 +432,6 @@ static void write_response(ESPState *s)
>          }
>      } else {
>          s->ti_size = 2;
> -        s->ti_rptr = 0;
> -        s->ti_wptr = 2;
>          s->rregs[ESP_RFLAGS] = 2;
>      }
>      esp_raise_irq(s);
> @@ -429,6 +451,7 @@ static void do_dma_pdma_cb(ESPState *s)
>  {
>      int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
>      int len;
> +    uint32_t n;
>  
>      if (s->do_cmd) {
>          s->ti_size = 0;
> @@ -441,10 +464,8 @@ static void do_dma_pdma_cb(ESPState *s)
>  
>      if (to_device) {
>          /* Copy FIFO data to device */
> -        len = MIN(s->ti_wptr, TI_BUFSZ);
> -        memcpy(s->async_buf, s->ti_buf, len);
> -        s->ti_wptr = 0;
> -        s->ti_rptr = 0;
> +        len = MIN(fifo8_num_used(&s->fifo), ESP_FIFO_SZ);
> +        memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
>          s->async_buf += len;
>          s->async_len -= len;
>          s->ti_size += len;
> @@ -477,11 +498,8 @@ static void do_dma_pdma_cb(ESPState *s)
>  
>          if (esp_get_tc(s) != 0) {
>              /* Copy device data to FIFO */
> -            s->ti_wptr = 0;
> -            s->ti_rptr = 0;
> -            len = MIN(s->async_len, TI_BUFSZ);
> -            memcpy(s->ti_buf, s->async_buf, len);
> -            s->ti_wptr += len;
> +            len = MIN(s->async_len, fifo8_num_free(&s->fifo));
> +            fifo8_push_all(&s->fifo, s->async_buf, len);
>              s->async_buf += len;
>              s->async_len -= len;
>              s->ti_size -= len;
> @@ -561,9 +579,8 @@ static void esp_do_dma(ESPState *s)
>              s->dma_memory_write(s->dma_opaque, s->async_buf, len);
>          } else {
>              /* Copy device data to FIFO */
> -            len = MIN(len, TI_BUFSZ - s->ti_wptr);
> -            memcpy(&s->ti_buf[s->ti_wptr], s->async_buf, len);
> -            s->ti_wptr += len;
> +            len = MIN(len, fifo8_num_free(&s->fifo));
> +            fifo8_push_all(&s->fifo, s->async_buf, len);
>              s->async_buf += len;
>              s->async_len -= len;
>              s->ti_size -= len;
> @@ -717,8 +734,7 @@ void esp_hard_reset(ESPState *s)
>      memset(s->wregs, 0, ESP_REGS);
>      s->tchi_written = 0;
>      s->ti_size = 0;
> -    s->ti_rptr = 0;
> -    s->ti_wptr = 0;
> +    fifo8_reset(&s->fifo);
>      s->dma = 0;
>      s->do_cmd = 0;
>      s->dma_cb = NULL;
> @@ -750,13 +766,9 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>              /* Data out.  */
>              qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
>              s->rregs[ESP_FIFO] = 0;
> -        } else if (s->ti_rptr < s->ti_wptr) {
> +        } else {
>              s->ti_size--;
> -            s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
> -        }
> -        if (s->ti_rptr == s->ti_wptr) {
> -            s->ti_rptr = 0;
> -            s->ti_wptr = 0;
> +            s->rregs[ESP_FIFO] = esp_fifo_pop(s);
>          }
>          val = s->rregs[ESP_FIFO];
>          break;
> @@ -806,11 +818,9 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>              } else {
>                  trace_esp_error_fifo_overrun();
>              }
> -        } else if (s->ti_wptr == TI_BUFSZ - 1) {
> -            trace_esp_error_fifo_overrun();
>          } else {
>              s->ti_size++;
> -            s->ti_buf[s->ti_wptr++] = val & 0xff;
> +            esp_fifo_push(s, val & 0xff);
>          }
>  
>          /* Non-DMA transfers raise an interrupt after every byte */
> @@ -839,8 +849,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          case CMD_FLUSH:
>              trace_esp_mem_writeb_cmd_flush(val);
>              /*s->ti_size = 0;*/
> -            s->ti_wptr = 0;
> -            s->ti_rptr = 0;
> +            fifo8_reset(&s->fifo);
>              break;
>          case CMD_RESET:
>              trace_esp_mem_writeb_cmd_reset(val);
> @@ -958,11 +967,18 @@ static int esp_pre_save(void *opaque)
>  static int esp_post_load(void *opaque, int version_id)
>  {
>      ESPState *s = ESP(opaque);
> +    int len, i;
>  
>      version_id = MIN(version_id, s->mig_version_id);
>  
>      if (version_id < 5) {
>          esp_set_tc(s, s->mig_dma_left);
> +
> +        /* Migrate ti_buf to fifo */
> +        len = s->mig_ti_wptr - s->mig_ti_rptr;
> +        for (i = 0; i < len; i++) {
> +            fifo8_push(&s->fifo, s->mig_ti_buf[i]);
> +        }
>      }
>  
>      s->mig_version_id = vmstate_esp.version_id;
> @@ -979,9 +995,9 @@ const VMStateDescription vmstate_esp = {
>          VMSTATE_BUFFER(rregs, ESPState),
>          VMSTATE_BUFFER(wregs, ESPState),
>          VMSTATE_INT32(ti_size, ESPState),
> -        VMSTATE_UINT32(ti_rptr, ESPState),
> -        VMSTATE_UINT32(ti_wptr, ESPState),
> -        VMSTATE_BUFFER(ti_buf, ESPState),
> +        VMSTATE_UINT32_TEST(mig_ti_rptr, ESPState, esp_is_before_version_5),
> +        VMSTATE_UINT32_TEST(mig_ti_wptr, ESPState, esp_is_before_version_5),
> +        VMSTATE_BUFFER_TEST(mig_ti_buf, ESPState, esp_is_before_version_5),
>          VMSTATE_UINT32(status, ESPState),
>          VMSTATE_UINT32_TEST(mig_deferred_status, ESPState,
>                              esp_is_before_version_5),
> @@ -995,6 +1011,7 @@ const VMStateDescription vmstate_esp = {
>          VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
>          VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
>          VMSTATE_UINT8_TEST(cmdbuf_cdb_offset, ESPState, esp_is_version_5),
> +        VMSTATE_FIFO8_TEST(fifo, ESPState, esp_is_version_5),
>          VMSTATE_END_OF_LIST()
>      },
>  };
> @@ -1047,7 +1064,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>          break;
>      }
>      dmalen = esp_get_tc(s);
> -    if (dmalen == 0 || (s->ti_wptr == TI_BUFSZ)) {
> +    if (dmalen == 0 || fifo8_is_full(&s->fifo)) {
>          s->pdma_cb(s);
>      }
>  }
> @@ -1070,9 +1087,7 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>          val = (val << 8) | esp_pdma_read(s);
>          break;
>      }
> -    if (s->ti_rptr == s->ti_wptr) {
> -        s->ti_wptr = 0;
> -        s->ti_rptr = 0;
> +    if (fifo8_is_empty(&s->fifo)) {
>          s->pdma_cb(s);
>      }
>      return val;
> @@ -1182,6 +1197,20 @@ static const TypeInfo sysbus_esp_info = {
>      .class_init    = sysbus_esp_class_init,
>  };
>  
> +static void esp_finalize(Object *obj)
> +{
> +    ESPState *s = ESP(obj);
> +
> +    fifo8_destroy(&s->fifo);
> +}
> +
> +static void esp_init(Object *obj)
> +{
> +    ESPState *s = ESP(obj);
> +
> +    fifo8_create(&s->fifo, ESP_FIFO_SZ);
> +}
> +
>  static void esp_class_init(ObjectClass *klass, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(klass);
> @@ -1194,6 +1223,8 @@ static void esp_class_init(ObjectClass *klass, void *data)
>  static const TypeInfo esp_info = {
>      .name = TYPE_ESP,
>      .parent = TYPE_DEVICE,
> +    .instance_init = esp_init,
> +    .instance_finalize = esp_finalize,
>      .instance_size = sizeof(ESPState),
>      .class_init = esp_class_init,
>  };
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 6f3bf4a0ce..063d9b1caa 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -3,6 +3,7 @@
>  
>  #include "hw/scsi/scsi.h"
>  #include "hw/sysbus.h"
> +#include "qemu/fifo8.h"
>  #include "qom/object.h"
>  
>  /* esp.c */
> @@ -10,7 +11,7 @@
>  typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
>  
>  #define ESP_REGS 16
> -#define TI_BUFSZ 16
> +#define ESP_FIFO_SZ 16
>  #define ESP_CMDBUF_SZ 32
>  
>  typedef struct ESPState ESPState;
> @@ -28,10 +29,9 @@ struct ESPState {
>      uint8_t chip_id;
>      bool tchi_written;
>      int32_t ti_size;
> -    uint32_t ti_rptr, ti_wptr;
>      uint32_t status;
>      uint32_t dma;
> -    uint8_t ti_buf[TI_BUFSZ];
> +    Fifo8 fifo;
>      SCSIBus bus;
>      SCSIDevice *current_dev;
>      SCSIRequest *current_req;
> @@ -58,6 +58,8 @@ struct ESPState {
>      uint32_t mig_dma_left;
>      uint32_t mig_deferred_status;
>      bool mig_deferred_complete;
> +    uint32_t mig_ti_rptr, mig_ti_wptr;
> +    uint8_t mig_ti_buf[ESP_FIFO_SZ];
>  };
>  
>  #define TYPE_SYSBUS_ESP "sysbus-esp"
> 

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


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

* Re: [PATCH v2 39/42] esp: convert cmdbuf from array to Fifo8
  2021-02-09 19:30 ` [PATCH v2 39/42] esp: convert cmdbuf " Mark Cave-Ayland
@ 2021-03-03 20:16   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 20:16 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> Rename ESP_CMDBUF_SZ to ESP_CMDFIFO_SZ and cmdbuf_cdb_offset to cmdfifo_cdb_offset
> to indicate that the command buffer type has changed from an array to a Fifo8.
> 
> This also enables us to remove the ESPState field cmdlen since the command length
> is now simply the number of elements used in cmdfifo.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 151 +++++++++++++++++++++++++++---------------
>  include/hw/scsi/esp.h |   9 +--
>  2 files changed, 101 insertions(+), 59 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 98df357276..9dd9947307 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -117,6 +117,25 @@ static uint8_t esp_fifo_pop(ESPState *s)
>      return fifo8_pop(&s->fifo);
>  }
>  
> +static void esp_cmdfifo_push(ESPState *s, uint8_t val)
> +{
> +    if (fifo8_num_used(&s->cmdfifo) == ESP_CMDFIFO_SZ) {
> +        trace_esp_error_fifo_overrun();
> +        return;
> +    }
> +
> +    fifo8_push(&s->cmdfifo, val);
> +}
> +
> +static uint8_t esp_cmdfifo_pop(ESPState *s)
> +{
> +    if (fifo8_is_empty(&s->cmdfifo)) {
> +        return 0;
> +    }
> +
> +    return fifo8_pop(&s->cmdfifo);
> +}
> +
>  static uint32_t esp_get_tc(ESPState *s)
>  {
>      uint32_t dmalen;
> @@ -151,7 +170,7 @@ static uint8_t esp_pdma_read(ESPState *s)
>      uint8_t val;
>  
>      if (s->do_cmd) {
> -        val = s->cmdbuf[s->cmdlen++];
> +        val = esp_cmdfifo_pop(s);
>      } else {
>          val = esp_fifo_pop(s);
>      }
> @@ -168,7 +187,7 @@ static void esp_pdma_write(ESPState *s, uint8_t val)
>      }
>  
>      if (s->do_cmd) {
> -        s->cmdbuf[s->cmdlen++] = val;
> +        esp_cmdfifo_push(s, val);
>      } else {
>          esp_fifo_push(s, val);
>      }
> @@ -214,7 +233,7 @@ static int esp_select(ESPState *s)
>  
>  static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
>  {
> -    uint8_t *buf = s->cmdbuf;
> +    uint8_t buf[ESP_CMDFIFO_SZ];
>      uint32_t dmalen, n;
>      int target;
>  
> @@ -226,15 +245,18 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
>          }
>          if (s->dma_memory_read) {
>              s->dma_memory_read(s->dma_opaque, buf, dmalen);
> +            fifo8_push_all(&s->cmdfifo, buf, dmalen);
>          } else {
>              if (esp_select(s) < 0) {
> +                fifo8_reset(&s->cmdfifo);
>                  return -1;
>              }
>              esp_raise_drq(s);
> +            fifo8_reset(&s->cmdfifo);
>              return 0;
>          }
>      } else {
> -        dmalen = MIN(s->ti_size, maxlen);
> +        dmalen = MIN(fifo8_num_used(&s->fifo), maxlen);
>          if (dmalen == 0) {
>              return 0;
>          }
> @@ -242,27 +264,35 @@ static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
>          if (dmalen >= 3) {
>              buf[0] = buf[2] >> 5;
>          }
> +        fifo8_push_all(&s->cmdfifo, buf, dmalen);
>      }
>      trace_esp_get_cmd(dmalen, target);
>  
>      if (esp_select(s) < 0) {
> +        fifo8_reset(&s->cmdfifo);
>          return -1;
>      }
>      return dmalen;
>  }
>  
> -static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
> +static void do_busid_cmd(ESPState *s, uint8_t busid)
>  {
> +    uint32_t n, cmdlen;
>      int32_t datalen;
>      int lun;
>      SCSIDevice *current_lun;
> +    uint8_t *buf;
>  
>      trace_esp_do_busid_cmd(busid);
>      lun = busid & 7;
> +    cmdlen = fifo8_num_used(&s->cmdfifo);
> +    buf = (uint8_t *)fifo8_pop_buf(&s->cmdfifo, cmdlen, &n);
> +
>      current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
>      s->current_req = scsi_req_new(current_lun, 0, lun, buf, s);
>      datalen = scsi_req_enqueue(s->current_req);
>      s->ti_size = datalen;
> +    fifo8_reset(&s->cmdfifo);
>      if (datalen != 0) {
>          s->rregs[ESP_RSTAT] = STAT_TC;
>          s->rregs[ESP_RSEQ] = SEQ_CD;
> @@ -287,18 +317,25 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
>  
>  static void do_cmd(ESPState *s)
>  {
> -    uint8_t *buf = s->cmdbuf;
> -    uint8_t busid = buf[0];
> +    uint8_t busid = fifo8_pop(&s->cmdfifo);
> +    uint32_t n;
> +
> +    s->cmdfifo_cdb_offset--;
>  
>      /* Ignore extended messages for now */
> -    do_busid_cmd(s, &buf[s->cmdbuf_cdb_offset], busid);
> +    if (s->cmdfifo_cdb_offset) {
> +        fifo8_pop_buf(&s->cmdfifo, s->cmdfifo_cdb_offset, &n);
> +        s->cmdfifo_cdb_offset = 0;
> +    }
> +
> +    do_busid_cmd(s, busid);
>  }
>  
>  static void satn_pdma_cb(ESPState *s)
>  {
>      s->do_cmd = 0;
> -    if (s->cmdlen) {
> -        s->cmdbuf_cdb_offset = 1;
> +    if (!fifo8_is_empty(&s->cmdfifo)) {
> +        s->cmdfifo_cdb_offset = 1;
>          do_cmd(s);
>      }
>  }
> @@ -312,13 +349,11 @@ static void handle_satn(ESPState *s)
>          return;
>      }
>      s->pdma_cb = satn_pdma_cb;
> -    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
> +    cmdlen = get_cmd(s, ESP_CMDFIFO_SZ);
>      if (cmdlen > 0) {
> -        s->cmdlen = cmdlen;
> -        s->cmdbuf_cdb_offset = 1;
> +        s->cmdfifo_cdb_offset = 1;
>          do_cmd(s);
>      } 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;
> @@ -328,10 +363,13 @@ static void handle_satn(ESPState *s)
>  
>  static void s_without_satn_pdma_cb(ESPState *s)
>  {
> +    uint32_t len;
> +
>      s->do_cmd = 0;
> -    if (s->cmdlen) {
> -        s->cmdbuf_cdb_offset = 0;
> -        do_busid_cmd(s, s->cmdbuf, 0);
> +    len = fifo8_num_used(&s->cmdfifo);
> +    if (len) {
> +        s->cmdfifo_cdb_offset = 0;
> +        do_busid_cmd(s, 0);
>      }
>  }
>  
> @@ -344,13 +382,11 @@ static void handle_s_without_atn(ESPState *s)
>          return;
>      }
>      s->pdma_cb = s_without_satn_pdma_cb;
> -    cmdlen = get_cmd(s, ESP_CMDBUF_SZ);
> +    cmdlen = get_cmd(s, ESP_CMDFIFO_SZ);
>      if (cmdlen > 0) {
> -        s->cmdlen = cmdlen;
> -        s->cmdbuf_cdb_offset = 0;
> -        do_busid_cmd(s, s->cmdbuf, 0);
> +        s->cmdfifo_cdb_offset = 0;
> +        do_busid_cmd(s, 0);
>      } 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;
> @@ -361,10 +397,10 @@ static void handle_s_without_atn(ESPState *s)
>  static void satn_stop_pdma_cb(ESPState *s)
>  {
>      s->do_cmd = 0;
> -    if (s->cmdlen) {
> -        trace_esp_handle_satn_stop(s->cmdlen);
> +    if (!fifo8_is_empty(&s->cmdfifo)) {
> +        trace_esp_handle_satn_stop(fifo8_num_used(&s->cmdfifo));
>          s->do_cmd = 1;
> -        s->cmdbuf_cdb_offset = 1;
> +        s->cmdfifo_cdb_offset = 1;
>          s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
>          s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>          s->rregs[ESP_RSEQ] = SEQ_CD;
> @@ -383,16 +419,14 @@ static void handle_satn_stop(ESPState *s)
>      s->pdma_cb = satn_stop_pdma_cb;
>      cmdlen = get_cmd(s, 1);
>      if (cmdlen > 0) {
> -        trace_esp_handle_satn_stop(cmdlen);
> -        s->cmdlen = cmdlen;
> +        trace_esp_handle_satn_stop(fifo8_num_used(&s->cmdfifo));
>          s->do_cmd = 1;
> -        s->cmdbuf_cdb_offset = 1;
> +        s->cmdfifo_cdb_offset = 1;
>          s->rregs[ESP_RSTAT] = STAT_MO;
>          s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>          s->rregs[ESP_RSEQ] = SEQ_MO;
>          esp_raise_irq(s);
>      } else if (cmdlen == 0) {
> -        s->cmdlen = 0;
>          s->do_cmd = 1;
>          /* Target present, switch to message out phase */
>          s->rregs[ESP_RSEQ] = SEQ_MO;
> @@ -455,7 +489,6 @@ static void do_dma_pdma_cb(ESPState *s)
>  
>      if (s->do_cmd) {
>          s->ti_size = 0;
> -        s->cmdlen = 0;
>          s->do_cmd = 0;
>          do_cmd(s);
>          esp_lower_drq(s);
> @@ -515,8 +548,9 @@ static void do_dma_pdma_cb(ESPState *s)
>  
>  static void esp_do_dma(ESPState *s)
>  {
> -    uint32_t len;
> +    uint32_t len, cmdlen;
>      int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
> +    uint8_t buf[ESP_CMDFIFO_SZ];
>  
>      len = esp_get_tc(s);
>      if (s->do_cmd) {
> @@ -524,34 +558,33 @@ static void esp_do_dma(ESPState *s)
>           * handle_ti_cmd() case: esp_do_dma() is called only from
>           * handle_ti_cmd() with do_cmd != NULL (see the assert())
>           */
> -        trace_esp_do_dma(s->cmdlen, len);
> -        assert(s->cmdlen <= sizeof(s->cmdbuf) &&
> -               len <= sizeof(s->cmdbuf) - s->cmdlen);
> +        cmdlen = fifo8_num_used(&s->cmdfifo);
> +        trace_esp_do_dma(cmdlen, len);
>          if (s->dma_memory_read) {
> -            s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
> +            s->dma_memory_read(s->dma_opaque, buf, len);
> +            fifo8_push_all(&s->cmdfifo, buf, len);
>          } else {
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
>              return;
>          }
> -        trace_esp_handle_ti_cmd(s->cmdlen);
> +        trace_esp_handle_ti_cmd(cmdlen);
>          s->ti_size = 0;
>          if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
>              /* No command received */
> -            if (s->cmdbuf_cdb_offset == s->cmdlen) {
> +            if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
>                  return;
>              }
>  
>              /* Command has been received */
> -            s->cmdlen = 0;
>              s->do_cmd = 0;
>              do_cmd(s);
>          } else {
>              /*
> -             * Extra message out bytes received: update cmdbuf_cdb_offset
> +             * Extra message out bytes received: update cmdfifo_cdb_offset
>               * and then switch to commmand phase
>               */
> -            s->cmdbuf_cdb_offset = s->cmdlen;
> +            s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
>              s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
>              s->rregs[ESP_RSEQ] = SEQ_CD;
>              s->rregs[ESP_RINTR] |= INTR_BS;
> @@ -689,7 +722,7 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
>  
>  static void handle_ti(ESPState *s)
>  {
> -    uint32_t dmalen;
> +    uint32_t dmalen, cmdlen;
>  
>      if (s->dma && !s->dma_enabled) {
>          s->dma_cb = handle_ti;
> @@ -702,24 +735,24 @@ static void handle_ti(ESPState *s)
>          s->rregs[ESP_RSTAT] &= ~STAT_TC;
>          esp_do_dma(s);
>      } else if (s->do_cmd) {
> -        trace_esp_handle_ti_cmd(s->cmdlen);
> +        cmdlen = fifo8_num_used(&s->cmdfifo);
> +        trace_esp_handle_ti_cmd(cmdlen);
>          s->ti_size = 0;
>          if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
>              /* No command received */
> -            if (s->cmdbuf_cdb_offset == s->cmdlen) {
> +            if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
>                  return;
>              }
>  
>              /* Command has been received */
> -            s->cmdlen = 0;
>              s->do_cmd = 0;
>              do_cmd(s);
>          } else {
>              /*
> -             * Extra message out bytes received: update cmdbuf_cdb_offset
> +             * Extra message out bytes received: update cmdfifo_cdb_offset
>               * and then switch to commmand phase
>               */
> -            s->cmdbuf_cdb_offset = s->cmdlen;
> +            s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
>              s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
>              s->rregs[ESP_RSEQ] = SEQ_CD;
>              s->rregs[ESP_RINTR] |= INTR_BS;
> @@ -735,6 +768,7 @@ void esp_hard_reset(ESPState *s)
>      s->tchi_written = 0;
>      s->ti_size = 0;
>      fifo8_reset(&s->fifo);
> +    fifo8_reset(&s->cmdfifo);
>      s->dma = 0;
>      s->do_cmd = 0;
>      s->dma_cb = NULL;
> @@ -813,11 +847,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          break;
>      case ESP_FIFO:
>          if (s->do_cmd) {
> -            if (s->cmdlen < ESP_CMDBUF_SZ) {
> -                s->cmdbuf[s->cmdlen++] = val & 0xff;
> -            } else {
> -                trace_esp_error_fifo_overrun();
> -            }
> +            esp_cmdfifo_push(s, val & 0xff);
>          } else {
>              s->ti_size++;
>              esp_fifo_push(s, val & 0xff);
> @@ -979,6 +1009,11 @@ static int esp_post_load(void *opaque, int version_id)
>          for (i = 0; i < len; i++) {
>              fifo8_push(&s->fifo, s->mig_ti_buf[i]);
>          }
> +
> +        /* Migrate cmdbuf to cmdfifo */
> +        for (i = 0; i < s->mig_cmdlen; i++) {
> +            fifo8_push(&s->cmdfifo, s->mig_cmdbuf[i]);
> +        }
>      }
>  
>      s->mig_version_id = vmstate_esp.version_id;
> @@ -1004,14 +1039,18 @@ const VMStateDescription vmstate_esp = {
>          VMSTATE_BOOL_TEST(mig_deferred_complete, ESPState,
>                            esp_is_before_version_5),
>          VMSTATE_UINT32(dma, ESPState),
> -        VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16),
> -        VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
> -        VMSTATE_UINT32(cmdlen, ESPState),
> +        VMSTATE_STATIC_BUFFER(mig_cmdbuf, ESPState, 0,
> +                              esp_is_before_version_5, 0, 16),
> +        VMSTATE_STATIC_BUFFER(mig_cmdbuf, ESPState, 4,
> +                              esp_is_before_version_5, 16,
> +                              sizeof(typeof_field(ESPState, mig_cmdbuf))),
> +        VMSTATE_UINT32_TEST(mig_cmdlen, ESPState, esp_is_before_version_5),
>          VMSTATE_UINT32(do_cmd, ESPState),
>          VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
>          VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
> -        VMSTATE_UINT8_TEST(cmdbuf_cdb_offset, ESPState, esp_is_version_5),
> +        VMSTATE_UINT8_TEST(cmdfifo_cdb_offset, ESPState, esp_is_version_5),
>          VMSTATE_FIFO8_TEST(fifo, ESPState, esp_is_version_5),
> +        VMSTATE_FIFO8_TEST(cmdfifo, ESPState, esp_is_version_5),
>          VMSTATE_END_OF_LIST()
>      },
>  };
> @@ -1202,6 +1241,7 @@ static void esp_finalize(Object *obj)
>      ESPState *s = ESP(obj);
>  
>      fifo8_destroy(&s->fifo);
> +    fifo8_destroy(&s->cmdfifo);
>  }
>  
>  static void esp_init(Object *obj)
> @@ -1209,6 +1249,7 @@ static void esp_init(Object *obj)
>      ESPState *s = ESP(obj);
>  
>      fifo8_create(&s->fifo, ESP_FIFO_SZ);
> +    fifo8_create(&s->cmdfifo, ESP_CMDFIFO_SZ);
>  }
>  
>  static void esp_class_init(ObjectClass *klass, void *data)
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 063d9b1caa..9da2905f14 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -12,7 +12,7 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
>  
>  #define ESP_REGS 16
>  #define ESP_FIFO_SZ 16
> -#define ESP_CMDBUF_SZ 32
> +#define ESP_CMDFIFO_SZ 32
>  
>  typedef struct ESPState ESPState;
>  
> @@ -35,9 +35,8 @@ struct ESPState {
>      SCSIBus bus;
>      SCSIDevice *current_dev;
>      SCSIRequest *current_req;
> -    uint8_t cmdbuf[ESP_CMDBUF_SZ];
> -    uint32_t cmdlen;
> -    uint8_t cmdbuf_cdb_offset;
> +    Fifo8 cmdfifo;
> +    uint8_t cmdfifo_cdb_offset;
>      uint32_t do_cmd;
>  
>      bool data_in_ready;
> @@ -60,6 +59,8 @@ struct ESPState {
>      bool mig_deferred_complete;
>      uint32_t mig_ti_rptr, mig_ti_wptr;
>      uint8_t mig_ti_buf[ESP_FIFO_SZ];
> +    uint8_t mig_cmdbuf[ESP_CMDFIFO_SZ];
> +    uint32_t mig_cmdlen;
>  };
>  
>  #define TYPE_SYSBUS_ESP "sysbus-esp"
> 

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


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

* Re: [PATCH v2 40/42] esp: add trivial implementation of the ESP_RFLAGS register
  2021-02-09 19:30 ` [PATCH v2 40/42] esp: add trivial implementation of the ESP_RFLAGS register Mark Cave-Ayland
  2021-02-23 18:51   ` Philippe Mathieu-Daudé
@ 2021-03-03 20:19   ` Laurent Vivier
  1 sibling, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 20:19 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> The bottom 5 bits contain the number of bytes remaining in the FIFO which is
> trivial to implement with Fifo8 (the remaining bits are unimplemented and left
> as 0 for now).
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 9dd9947307..1f01f2314b 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -825,6 +825,10 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>              val = s->rregs[saddr];
>          }
>          break;
> +     case ESP_RFLAGS:
> +        /* Bottom 5 bits indicate number of bytes in FIFO */
> +        val = fifo8_num_used(&s->fifo);
> +        break;
>      default:
>          val = s->rregs[saddr];
>          break;
> 

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


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

* Re: [PATCH v2 41/42] esp: implement non-DMA transfers in PDMA mode
  2021-02-09 19:30 ` [PATCH v2 41/42] esp: implement non-DMA transfers in PDMA mode Mark Cave-Ayland
@ 2021-03-03 20:22   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 20:22 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> The MacOS toolbox ROM uses non-DMA TI commands to handle the first/last byte
> of an unaligned 16-bit transfer to memory.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c         | 133 ++++++++++++++++++++++++++++++------------
>  include/hw/scsi/esp.h |   1 +
>  2 files changed, 98 insertions(+), 36 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index 1f01f2314b..ae9e265a5d 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -296,6 +296,7 @@ static void do_busid_cmd(ESPState *s, uint8_t busid)
>      if (datalen != 0) {
>          s->rregs[ESP_RSTAT] = STAT_TC;
>          s->rregs[ESP_RSEQ] = SEQ_CD;
> +        s->ti_cmd = 0;
>          esp_set_tc(s, 0);
>          if (datalen > 0) {
>              /*
> @@ -651,6 +652,71 @@ static void esp_do_dma(ESPState *s)
>      esp_lower_drq(s);
>  }
>  
> +static void esp_do_nodma(ESPState *s)
> +{
> +    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
> +    uint32_t cmdlen, n;
> +    int len;
> +
> +    if (s->do_cmd) {
> +        cmdlen = fifo8_num_used(&s->cmdfifo);
> +        trace_esp_handle_ti_cmd(cmdlen);
> +        s->ti_size = 0;
> +        if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
> +            /* No command received */
> +            if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
> +                return;
> +            }
> +
> +            /* Command has been received */
> +            s->do_cmd = 0;
> +            do_cmd(s);
> +        } else {
> +            /*
> +             * Extra message out bytes received: update cmdfifo_cdb_offset
> +             * and then switch to commmand phase
> +             */
> +            s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
> +            s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
> +            s->rregs[ESP_RSEQ] = SEQ_CD;
> +            s->rregs[ESP_RINTR] |= INTR_BS;
> +            esp_raise_irq(s);
> +        }
> +        return;
> +    }
> +
> +    if (s->async_len == 0) {
> +        /* Defer until data is available.  */
> +        return;
> +    }
> +
> +    if (to_device) {
> +        len = MIN(fifo8_num_used(&s->fifo), ESP_FIFO_SZ);
> +        memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
> +        s->async_buf += len;
> +        s->async_len -= len;
> +        s->ti_size += len;
> +    } else {
> +        len = MIN(s->ti_size, s->async_len);
> +        len = MIN(len, fifo8_num_free(&s->fifo));
> +        fifo8_push_all(&s->fifo, s->async_buf, len);
> +        s->async_buf += len;
> +        s->async_len -= len;
> +        s->ti_size -= len;
> +    }
> +
> +    if (s->async_len == 0) {
> +        scsi_req_continue(s->current_req);
> +
> +        if (to_device || s->ti_size == 0) {
> +            return;
> +        }
> +    }
> +
> +    s->rregs[ESP_RINTR] |= INTR_BS;
> +    esp_raise_irq(s);
> +}
> +
>  void esp_command_complete(SCSIRequest *req, uint32_t status,
>                            size_t resid)
>  {
> @@ -708,56 +774,51 @@ void esp_transfer_data(SCSIRequest *req, uint32_t len)
>          return;
>      }
>  
> -    if (dmalen) {
> -        esp_do_dma(s);
> -    } else if (s->ti_size <= 0) {
> +    if (s->ti_cmd == 0) {
>          /*
> -         * If this was the last part of a DMA transfer then the
> -         * completion interrupt is deferred to here.
> +         * Always perform the initial transfer upon reception of the next TI
> +         * command to ensure the DMA/non-DMA status of the command is correct.
> +         * It is not possible to use s->dma directly in the section below as
> +         * some OSs send non-DMA NOP commands after a DMA transfer. Hence if the
> +         * async data transfer is delayed then s->dma is set incorrectly.
>           */
> -        esp_dma_done(s);
> -        esp_lower_drq(s);
> +        return;
> +    }
> +
> +    if (s->ti_cmd & CMD_DMA) {
> +        if (dmalen) {
> +            esp_do_dma(s);
> +        } else if (s->ti_size <= 0) {
> +            /*
> +             * If this was the last part of a DMA transfer then the
> +             * completion interrupt is deferred to here.
> +             */
> +            esp_dma_done(s);
> +            esp_lower_drq(s);
> +        }
> +    } else {
> +        esp_do_nodma(s);
>      }
>  }
>  
>  static void handle_ti(ESPState *s)
>  {
> -    uint32_t dmalen, cmdlen;
> +    uint32_t dmalen;
>  
>      if (s->dma && !s->dma_enabled) {
>          s->dma_cb = handle_ti;
>          return;
>      }
>  
> -    dmalen = esp_get_tc(s);
> +    s->ti_cmd = s->rregs[ESP_CMD];
>      if (s->dma) {
> +        dmalen = esp_get_tc(s);
>          trace_esp_handle_ti(dmalen);
>          s->rregs[ESP_RSTAT] &= ~STAT_TC;
>          esp_do_dma(s);
> -    } else if (s->do_cmd) {
> -        cmdlen = fifo8_num_used(&s->cmdfifo);
> -        trace_esp_handle_ti_cmd(cmdlen);
> -        s->ti_size = 0;
> -        if ((s->rregs[ESP_RSTAT] & 7) == STAT_CD) {
> -            /* No command received */
> -            if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
> -                return;
> -            }
> -
> -            /* Command has been received */
> -            s->do_cmd = 0;
> -            do_cmd(s);
> -        } else {
> -            /*
> -             * Extra message out bytes received: update cmdfifo_cdb_offset
> -             * and then switch to commmand phase
> -             */
> -            s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
> -            s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
> -            s->rregs[ESP_RSEQ] = SEQ_CD;
> -            s->rregs[ESP_RINTR] |= INTR_BS;
> -            esp_raise_irq(s);
> -        }
> +    } else {
> +        trace_esp_handle_ti(s->ti_size);
> +        esp_do_nodma(s);
>      }
>  }
>  
> @@ -796,12 +857,12 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
>  
>      switch (saddr) {
>      case ESP_FIFO:
> -        if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
> +        if (s->dma_memory_read && s->dma_memory_write &&
> +                (s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
>              /* Data out.  */
>              qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
>              s->rregs[ESP_FIFO] = 0;
>          } else {
> -            s->ti_size--;
>              s->rregs[ESP_FIFO] = esp_fifo_pop(s);
>          }
>          val = s->rregs[ESP_FIFO];
> @@ -853,7 +914,6 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>          if (s->do_cmd) {
>              esp_cmdfifo_push(s, val & 0xff);
>          } else {
> -            s->ti_size++;
>              esp_fifo_push(s, val & 0xff);
>          }
>  
> @@ -1055,6 +1115,7 @@ const VMStateDescription vmstate_esp = {
>          VMSTATE_UINT8_TEST(cmdfifo_cdb_offset, ESPState, esp_is_version_5),
>          VMSTATE_FIFO8_TEST(fifo, ESPState, esp_is_version_5),
>          VMSTATE_FIFO8_TEST(cmdfifo, ESPState, esp_is_version_5),
> +        VMSTATE_UINT8_TEST(ti_cmd, ESPState, esp_is_version_5),
>          VMSTATE_END_OF_LIST()
>      },
>  };
> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
> index 9da2905f14..a387eb5292 100644
> --- a/include/hw/scsi/esp.h
> +++ b/include/hw/scsi/esp.h
> @@ -40,6 +40,7 @@ struct ESPState {
>      uint32_t do_cmd;
>  
>      bool data_in_ready;
> +    uint8_t ti_cmd;
>      int dma_enabled;
>  
>      uint32_t async_len;
> 

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


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

* Re: [PATCH v2 42/42] esp: add support for unaligned accesses
  2021-02-09 19:30 ` [PATCH v2 42/42] esp: add support for unaligned accesses Mark Cave-Ayland
@ 2021-03-03 20:22   ` Laurent Vivier
  0 siblings, 0 replies; 135+ messages in thread
From: Laurent Vivier @ 2021-03-03 20:22 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel, pbonzini, fam

Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
> When the MacOS toolbox ROM transfers data from a target device to an unaligned
> memory address, the first/last byte of a 16-bit transfer needs to be handled
> separately. This means that the first byte is preloaded into the FIFO before
> the transfer, or the last byte remains in the FIFO after the transfer.
> 
> The result of this is that the PDMA routines must be updated so that the FIFO
> is loaded/unloaded if the last 16-bit word is used (rather than the last byte)
> and any remaining byte from a FIFO wraparound is handled correctly.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>  hw/scsi/esp.c | 48 +++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 41 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
> index ae9e265a5d..d2d6366525 100644
> --- a/hw/scsi/esp.c
> +++ b/hw/scsi/esp.c
> @@ -498,11 +498,22 @@ static void do_dma_pdma_cb(ESPState *s)
>  
>      if (to_device) {
>          /* Copy FIFO data to device */
> -        len = MIN(fifo8_num_used(&s->fifo), ESP_FIFO_SZ);
> +        len = MIN(s->async_len, ESP_FIFO_SZ);
> +        len = MIN(len, fifo8_num_used(&s->fifo));
>          memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
> -        s->async_buf += len;
> -        s->async_len -= len;
> -        s->ti_size += len;
> +        s->async_buf += n;
> +        s->async_len -= n;
> +        s->ti_size += n;
> +
> +        if (n < len) {
> +            /* Unaligned accesses can cause FIFO wraparound */
> +            len = len - n;
> +            memcpy(s->async_buf, fifo8_pop_buf(&s->fifo, len, &n), len);
> +            s->async_buf += n;
> +            s->async_len -= n;
> +            s->ti_size += n;
> +        }
> +
>          if (s->async_len == 0) {
>              scsi_req_continue(s->current_req);
>              return;
> @@ -532,12 +543,18 @@ static void do_dma_pdma_cb(ESPState *s)
>  
>          if (esp_get_tc(s) != 0) {
>              /* Copy device data to FIFO */
> -            len = MIN(s->async_len, fifo8_num_free(&s->fifo));
> +            len = MIN(s->async_len, esp_get_tc(s));
> +            len = MIN(len, fifo8_num_free(&s->fifo));
>              fifo8_push_all(&s->fifo, s->async_buf, len);
>              s->async_buf += len;
>              s->async_len -= len;
>              s->ti_size -= len;
>              esp_set_tc(s, esp_get_tc(s) - len);
> +
> +            if (esp_get_tc(s) == 0) {
> +                /* Indicate transfer to FIFO is complete */
> +                 s->rregs[ESP_RSTAT] |= STAT_TC;
> +            }
>              return;
>          }
>  
> @@ -612,12 +629,29 @@ static void esp_do_dma(ESPState *s)
>          if (s->dma_memory_write) {
>              s->dma_memory_write(s->dma_opaque, s->async_buf, len);
>          } else {
> +            /* Adjust TC for any leftover data in the FIFO */
> +            if (!fifo8_is_empty(&s->fifo)) {
> +                esp_set_tc(s, esp_get_tc(s) - fifo8_num_used(&s->fifo));
> +            }
> +
>              /* Copy device data to FIFO */
>              len = MIN(len, fifo8_num_free(&s->fifo));
>              fifo8_push_all(&s->fifo, s->async_buf, len);
>              s->async_buf += len;
>              s->async_len -= len;
>              s->ti_size -= len;
> +
> +            /*
> +             * MacOS toolbox uses a TI length of 16 bytes for all commands, so
> +             * commands shorter than this must be padded accordingly
> +             */
> +            if (len < esp_get_tc(s) && esp_get_tc(s) <= ESP_FIFO_SZ) {
> +                while (fifo8_num_used(&s->fifo) < ESP_FIFO_SZ) {
> +                    esp_fifo_push(s, 0);
> +                    len++;
> +                }
> +            }
> +
>              esp_set_tc(s, esp_get_tc(s) - len);
>              s->pdma_cb = do_dma_pdma_cb;
>              esp_raise_drq(s);
> @@ -1168,7 +1202,7 @@ static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
>          break;
>      }
>      dmalen = esp_get_tc(s);
> -    if (dmalen == 0 || fifo8_is_full(&s->fifo)) {
> +    if (dmalen == 0 || fifo8_num_free(&s->fifo) < 2) {
>          s->pdma_cb(s);
>      }
>  }
> @@ -1191,7 +1225,7 @@ static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
>          val = (val << 8) | esp_pdma_read(s);
>          break;
>      }
> -    if (fifo8_is_empty(&s->fifo)) {
> +    if (fifo8_num_used(&s->fifo) < 2) {
>          s->pdma_cb(s);
>      }
>      return val;
> 

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


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

* Re: [PATCH v2 31/42] esp: implement FIFO flush command
  2021-03-03 19:32   ` Laurent Vivier
@ 2021-03-04 18:26     ` Mark Cave-Ayland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-03-04 18:26 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel, pbonzini, fam

On 03/03/2021 19:32, Laurent Vivier wrote:

> Le 09/02/2021 à 20:30, Mark Cave-Ayland a écrit :
>> At this point it is now possible to properly implement the FIFO flush command
>> without causing guest errors.
>>
>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>> ---
>>   hw/scsi/esp.c | 2 ++
>>   1 file changed, 2 insertions(+)
>>
>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>> index 1d56c99527..0994673ff8 100644
>> --- a/hw/scsi/esp.c
>> +++ b/hw/scsi/esp.c
>> @@ -770,6 +770,8 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
>>           case CMD_FLUSH:
>>               trace_esp_mem_writeb_cmd_flush(val);
>>               /*s->ti_size = 0;*/
>> +            s->ti_wptr = 0;
>> +            s->ti_rptr = 0;
>>               s->rregs[ESP_RINTR] = INTR_FC;
>>               s->rregs[ESP_RSEQ] = 0;
>>               s->rregs[ESP_RFLAGS] = 0;
>>
> 
> Why don't  you set aso ti_size to 0?

I remember trying this and there was a sequence in one of my test images whereby the 
OS submitted a SCSI CDB followed by a flush (presumably to clear the CDB from the 
FIFO): this caused ti_size to be zeroed, losing the response reply size.

As Phil's original comment was against patch 38 "esp: convert ti_buf from array to 
Fifo8" that's where the comment is finally removed - it doesn't make sense to keep it 
after the conversion.

> Anyway:
> 
> Reviwed-by: Laurent Vivier <laurent@vivier.eu>
> 
> Thanks,
> Laurent


ATB,

Mark.


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

* Re: [PATCH v2 33/42] esp: defer command completion interrupt on incoming data transfers
  2021-03-03 19:52     ` Laurent Vivier
@ 2021-03-04 18:33       ` Mark Cave-Ayland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Cave-Ayland @ 2021-03-04 18:33 UTC (permalink / raw)
  To: Laurent Vivier, qemu-devel, pbonzini, fam

On 03/03/2021 19:52, Laurent Vivier wrote:

> Le 18/02/2021 à 18:25, Mark Cave-Ayland a écrit :
>> On 09/02/2021 19:30, Mark Cave-Ayland wrote:
>>
>>> The MacOS toolbox ROM issues a command to the ESP controller as part of its
>>> "FAST" SCSI routines and then proceeds to read the incoming data soon after
>>> receiving the command completion interrupt.
>>>
>>> Unfortunately due to SCSI block transfers being asynchronous the incoming data
>>> may not yet be present causing an underflow error. Resolve this by waiting for
>>> the SCSI subsystem transfer_data callback before raising the command completion
>>> interrupt.
>>>
>>> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
>>> ---
>>>    hw/scsi/esp.c         | 54 +++++++++++++++++++++++++++++++++++++++----
>>>    include/hw/scsi/esp.h |  1 +
>>>    2 files changed, 51 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>>> index 728d4ddf99..ce6a7a1ed0 100644
>>> --- a/hw/scsi/esp.c
>>> +++ b/hw/scsi/esp.c
>>> @@ -183,6 +183,14 @@ static int esp_select(ESPState *s)
>>>            esp_raise_irq(s);
>>>            return -1;
>>>        }
>>> +
>>> +    /*
>>> +     * Note that we deliberately don't raise the IRQ here: this will be done
>>> +     * either in do_busid_cmd() for DATA OUT transfers or by the deferred
>>> +     * IRQ mechanism in esp_transfer_data() for DATA IN transfers
>>> +     */
>>> +    s->rregs[ESP_RINTR] |= INTR_FC;
>>> +    s->rregs[ESP_RSEQ] = SEQ_CD;
>>>        return 0;
>>>    }
>>>    @@ -237,18 +245,24 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
>>>        s->ti_size = datalen;
>>>        if (datalen != 0) {
>>>            s->rregs[ESP_RSTAT] = STAT_TC;
>>> +        s->rregs[ESP_RSEQ] = SEQ_CD;
>>>            esp_set_tc(s, 0);
>>>            if (datalen > 0) {
>>> +            /*
>>> +             * Switch to DATA IN phase but wait until initial data xfer is
>>> +             * complete before raising the command completion interrupt
>>> +             */
>>> +            s->data_in_ready = false;
>>>                s->rregs[ESP_RSTAT] |= STAT_DI;
>>>            } else {
>>>                s->rregs[ESP_RSTAT] |= STAT_DO;
>>> +            s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>>> +            esp_raise_irq(s);
>>> +            esp_lower_drq(s);
>>>            }
>>>            scsi_req_continue(s->current_req);
>>> +        return;
>>>        }
>>> -    s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
>>> -    s->rregs[ESP_RSEQ] = SEQ_CD;
>>> -    esp_raise_irq(s);
>>> -    esp_lower_drq(s);
>>>    }
>>>      static void do_cmd(ESPState *s)
>>> @@ -603,12 +617,35 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
>>>    void esp_transfer_data(SCSIRequest *req, uint32_t len)
>>>    {
>>>        ESPState *s = req->hba_private;
>>> +    int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO);
>>>        uint32_t dmalen = esp_get_tc(s);
>>>          assert(!s->do_cmd);
>>>        trace_esp_transfer_data(dmalen, s->ti_size);
>>>        s->async_len = len;
>>>        s->async_buf = scsi_req_get_buf(req);
>>> +
>>> +    if (!to_device && !s->data_in_ready) {
>>> +        /*
>>> +         * Initial incoming data xfer is complete so raise command
>>> +         * completion interrupt
>>> +         */
>>> +        s->data_in_ready = true;
>>> +        s->rregs[ESP_RSTAT] |= STAT_TC;
>>> +        s->rregs[ESP_RINTR] |= INTR_BS;
>>> +        esp_raise_irq(s);
>>> +
>>> +        /*
>>> +         * If data is ready to transfer and the TI command has already
>>> +         * been executed, start DMA immediately. Otherwise DMA will start
>>> +         * when host sends the TI command
>>> +         */
>>> +        if (s->ti_size && (s->rregs[ESP_CMD] == (CMD_TI | CMD_DMA))) {
>>> +            esp_do_dma(s);
>>> +        }
>>> +        return;
>>> +    }
>>> +
>>>        if (dmalen) {
>>>            esp_do_dma(s);
>>>        } else if (s->ti_size <= 0) {
>>> @@ -870,6 +907,14 @@ static bool esp_is_before_version_5(void *opaque, int version_id)
>>>        return version_id < 5;
>>>    }
>>>    +static bool esp_is_version_5(void *opaque, int version_id)
>>> +{
>>> +    ESPState *s = ESP(opaque);
>>> +
>>> +    version_id = MIN(version_id, s->mig_version_id);
>>> +    return version_id == 5;
>>> +}
>>> +
>>>    static int esp_pre_save(void *opaque)
>>>    {
>>>        ESPState *s = ESP(opaque);
>>> @@ -914,6 +959,7 @@ const VMStateDescription vmstate_esp = {
>>>            VMSTATE_UINT32(cmdlen, ESPState),
>>>            VMSTATE_UINT32(do_cmd, ESPState),
>>>            VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
>>> +        VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5),
>>>            VMSTATE_END_OF_LIST()
>>>        },
>>>    };
>>> diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
>>> index 6618f4e091..3b69aedebe 100644
>>> --- a/include/hw/scsi/esp.h
>>> +++ b/include/hw/scsi/esp.h
>>> @@ -41,6 +41,7 @@ struct ESPState {
>>>        uint32_t cmdlen;
>>>        uint32_t do_cmd;
>>>    +    bool data_in_ready;
>>>        int dma_enabled;
>>>          uint32_t async_len;
>>
>> Whilst doing some testing earlier, I discovered that the same change is required in
>> do_dma_pdma_cb(): it seems during boot the ROM attempts several 128k DMA requests in a row, and with
>> heavy debugging enabled it's enough to trigger the same underflow problem.
>>
>> Fortunately the fix is easy, and I'll squash this into the v3 series:
>>
>> diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
>> index a175191718..248c1ce27a 100644
>> --- a/hw/scsi/esp.c
>> +++ b/hw/scsi/esp.c
>> @@ -453,17 +453,13 @@ static void do_dma_pdma_cb(ESPState *s)
>>       } else {
>>           if (s->async_len == 0) {
>>               if (s->current_req) {
>> +               /*
>> +                * Defer until the scsi layer has completed.
>> +                */

FWIW I've also squashed this comment down to a single line.

>>                   scsi_req_continue(s->current_req);
>> +                s->data_in_ready = false;
>>               }
>> -
>> -            /*
>> -             * If there is still data to be read from the device then
>> -             * complete the DMA operation immediately.  Otherwise defer
>> -             * until the scsi layer has completed.
>> -             */
>> -            if (esp_get_tc(s) != 0 || s->ti_size == 0) {
>> -                return;
>> -            }
>> +            return;
>>           }
>>
>>           if (esp_get_tc(s) != 0) {
>>
>>
>> ATB,
>>
>> Mark.
> 
> 
> Reviewed-by: Laurent Vivier <laurent@vivier.eu>


ATB,

Mark.


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

end of thread, other threads:[~2021-03-04 18:34 UTC | newest]

Thread overview: 135+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-09 19:29 [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Mark Cave-Ayland
2021-02-09 19:29 ` [PATCH v2 01/42] esp: checkpatch fixes Mark Cave-Ayland
2021-03-01 19:43   ` Laurent Vivier
2021-03-03  8:33     ` Mark Cave-Ayland
2021-02-09 19:29 ` [PATCH v2 02/42] esp: rename existing ESP QOM type to SYSBUS_ESP Mark Cave-Ayland
2021-02-10 22:29   ` Philippe Mathieu-Daudé
2021-03-01 19:52   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 03/42] esp: QOMify the internal ESP device state Mark Cave-Ayland
2021-02-12 18:51   ` Philippe Mathieu-Daudé
2021-02-15 22:29     ` Mark Cave-Ayland
2021-03-01 20:11       ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 04/42] esp: add vmstate_esp version to embedded ESPState Mark Cave-Ayland
2021-02-16  7:35   ` Philippe Mathieu-Daudé
2021-03-01 20:21   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 05/42] esp: add trace event when receiving a TI command Mark Cave-Ayland
2021-03-01 20:24   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 06/42] esp: fix esp_reg_read() trace event Mark Cave-Ayland
2021-03-01 20:29   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 07/42] esp: add PDMA trace events Mark Cave-Ayland
2021-03-01 20:32   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 08/42] esp: determine transfer direction directly from SCSI phase Mark Cave-Ayland
2021-02-16  7:36   ` Philippe Mathieu-Daudé
2021-03-01 21:18   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 09/42] esp: introduce esp_get_tc() and esp_set_tc() Mark Cave-Ayland
2021-03-01 21:24   ` Laurent Vivier
2021-03-03  8:35     ` Mark Cave-Ayland
2021-02-09 19:29 ` [PATCH v2 10/42] esp: introduce esp_get_stc() Mark Cave-Ayland
2021-02-10 22:33   ` Philippe Mathieu-Daudé
2021-02-11  7:53     ` Mark Cave-Ayland
2021-02-11 10:07       ` Philippe Mathieu-Daudé
2021-02-15 22:27         ` Mark Cave-Ayland
2021-03-01 21:28   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 11/42] esp: apply transfer length adjustment when STC is zero at TC load time Mark Cave-Ayland
2021-02-16  7:33   ` Philippe Mathieu-Daudé
2021-02-16 21:52     ` Mark Cave-Ayland
2021-03-01 21:35   ` Laurent Vivier
2021-03-03  8:44     ` Mark Cave-Ayland
2021-02-09 19:29 ` [PATCH v2 12/42] esp: remove dma_counter from ESPState Mark Cave-Ayland
2021-02-10 22:37   ` Philippe Mathieu-Daudé
2021-03-01 21:44   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 13/42] esp: remove dma_left " Mark Cave-Ayland
2021-02-23 21:22   ` Philippe Mathieu-Daudé
2021-03-01 21:50   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 14/42] esp: remove minlen restriction in handle_ti Mark Cave-Ayland
2021-02-23 18:24   ` Philippe Mathieu-Daudé
2021-03-01 22:04   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 15/42] esp: introduce esp_pdma_read() and esp_pdma_write() functions Mark Cave-Ayland
2021-02-10 22:51   ` Philippe Mathieu-Daudé
2021-02-11  8:01     ` Mark Cave-Ayland
2021-02-11 10:09       ` Philippe Mathieu-Daudé
2021-03-01 22:06   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 16/42] esp: use pdma_origin directly in esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
2021-02-23 18:25   ` Philippe Mathieu-Daudé
2021-03-01 22:07   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 17/42] esp: move pdma_len and TC logic into esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
2021-02-23 21:23   ` Philippe Mathieu-Daudé
2021-03-01 22:09   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 18/42] esp: accumulate SCSI commands for PDMA transfers in cmdbuf instead of pdma_buf Mark Cave-Ayland
2021-02-23 21:25   ` Philippe Mathieu-Daudé
2021-03-02 17:02   ` Laurent Vivier
2021-03-02 17:34     ` Mark Cave-Ayland
2021-03-02 17:59       ` Laurent Vivier
2021-03-02 19:29         ` Mark Cave-Ayland
2021-03-02 21:21           ` Laurent Vivier
2021-03-02 21:22   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 19/42] esp: remove buf parameter from do_cmd() Mark Cave-Ayland
2021-02-23 18:27   ` Philippe Mathieu-Daudé
2021-03-02 17:03   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 20/42] esp: remove the buf and buflen parameters from get_cmd() Mark Cave-Ayland
2021-02-16  7:31   ` Philippe Mathieu-Daudé
2021-03-02 17:03   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 21/42] esp: remove redundant pdma_start from ESPState Mark Cave-Ayland
2021-03-02 21:22   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 22/42] esp: move PDMA length adjustments into esp_pdma_read()/esp_pdma_write() Mark Cave-Ayland
2021-03-02 21:44   ` Laurent Vivier
2021-02-09 19:29 ` [PATCH v2 23/42] esp: use ti_wptr/ti_rptr to manage the current FIFO position for PDMA Mark Cave-Ayland
2021-02-23 21:29   ` Philippe Mathieu-Daudé
2021-03-02 21:47   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 24/42] esp: use in-built TC to determine PDMA transfer length Mark Cave-Ayland
2021-02-23 18:32   ` Philippe Mathieu-Daudé
2021-03-02 21:48   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 25/42] esp: remove CMD pdma_origin Mark Cave-Ayland
2021-02-23 18:34   ` Philippe Mathieu-Daudé
2021-03-02 21:49   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 26/42] esp: rename get_cmd_cb() to esp_select() Mark Cave-Ayland
2021-03-02 21:51   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 27/42] esp: fix PDMA target selection Mark Cave-Ayland
2021-03-02 21:57   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 28/42] esp: use FIFO for PDMA transfers between initiator and device Mark Cave-Ayland
2021-03-02 22:02   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 29/42] esp: remove pdma_origin from ESPState Mark Cave-Ayland
2021-03-02 22:03   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 30/42] esp: add 4 byte PDMA read and write transfers Mark Cave-Ayland
2021-02-12 18:56   ` Philippe Mathieu-Daudé
2021-02-15 22:35     ` Mark Cave-Ayland
2021-02-16  7:30       ` Philippe Mathieu-Daudé
2021-02-16 21:36         ` Mark Cave-Ayland
2021-02-23  8:24         ` Mark Cave-Ayland
2021-02-23 18:55           ` Philippe Mathieu-Daudé
2021-03-02 22:05   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 31/42] esp: implement FIFO flush command Mark Cave-Ayland
2021-03-03 19:32   ` Laurent Vivier
2021-03-04 18:26     ` Mark Cave-Ayland
2021-02-09 19:30 ` [PATCH v2 32/42] esp: latch individual bits in ESP_RINTR register Mark Cave-Ayland
2021-03-03 19:48   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 33/42] esp: defer command completion interrupt on incoming data transfers Mark Cave-Ayland
2021-02-18 17:25   ` Mark Cave-Ayland
2021-03-03 19:52     ` Laurent Vivier
2021-03-04 18:33       ` Mark Cave-Ayland
2021-02-09 19:30 ` [PATCH v2 34/42] esp: remove old deferred command completion mechanism Mark Cave-Ayland
2021-03-03 19:55   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 35/42] esp: raise interrupt after every non-DMA byte transferred to the FIFO Mark Cave-Ayland
2021-03-03 19:59   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 36/42] esp: add maxlen parameter to get_cmd() Mark Cave-Ayland
2021-02-23 18:43   ` Philippe Mathieu-Daudé
2021-03-03 20:04   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 37/42] esp: transition to message out phase after SATN and stop command Mark Cave-Ayland
2021-03-03 20:06   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 38/42] esp: convert ti_buf from array to Fifo8 Mark Cave-Ayland
2021-02-23 18:49   ` Philippe Mathieu-Daudé
2021-02-25  9:15     ` Mark Cave-Ayland
2021-03-03 20:11   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 39/42] esp: convert cmdbuf " Mark Cave-Ayland
2021-03-03 20:16   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 40/42] esp: add trivial implementation of the ESP_RFLAGS register Mark Cave-Ayland
2021-02-23 18:51   ` Philippe Mathieu-Daudé
2021-03-03 20:19   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 41/42] esp: implement non-DMA transfers in PDMA mode Mark Cave-Ayland
2021-03-03 20:22   ` Laurent Vivier
2021-02-09 19:30 ` [PATCH v2 42/42] esp: add support for unaligned accesses Mark Cave-Ayland
2021-03-03 20:22   ` Laurent Vivier
2021-02-23 21:32 ` [PATCH v2 00/42] esp: consolidate PDMA transfer buffers and other fixes Philippe Mathieu-Daudé
2021-02-25  9:54   ` Mark Cave-Ayland
2021-02-25 10:50     ` Philippe Mathieu-Daudé
2021-02-25 19:17       ` Mark Cave-Ayland

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.