瀏覽代碼

RP2040: Recover gracefully when DMA is busy at phase change.

Not sure yet why this happens, but no need to crash completely.
Petteri Aimonen 2 年之前
父節點
當前提交
79d581f2e1

+ 10 - 2
lib/BlueSCSI_platform_RP2040/scsiPhy.cpp

@@ -191,13 +191,21 @@ extern "C" uint32_t scsiEnterPhaseImmediate(int phase)
         scsiLogPhaseChange(phase);
         scsiLogPhaseChange(phase);
 
 
         // Select between synchronous vs. asynchronous SCSI writes
         // Select between synchronous vs. asynchronous SCSI writes
+        bool syncstatus = false;
         if (scsiDev.target->syncOffset > 0 && (g_scsi_phase == DATA_IN || g_scsi_phase == DATA_OUT))
         if (scsiDev.target->syncOffset > 0 && (g_scsi_phase == DATA_IN || g_scsi_phase == DATA_OUT))
         {
         {
-            scsi_accel_rp2040_setSyncMode(scsiDev.target->syncOffset, scsiDev.target->syncPeriod);
+            syncstatus = scsi_accel_rp2040_setSyncMode(scsiDev.target->syncOffset, scsiDev.target->syncPeriod);
         }
         }
         else
         else
         {
         {
-            scsi_accel_rp2040_setSyncMode(0, 0);
+            syncstatus = scsi_accel_rp2040_setSyncMode(0, 0);
+        }
+
+        if (!syncstatus)
+        {
+            // SCSI DMA was not idle, we are in some kind of error state, force bus reset
+            scsiDev.resetFlag = 1;
+            return 0;
         }
         }
 
 
         if (phase < 0)
         if (phase < 0)

+ 7 - 2
lib/BlueSCSI_platform_RP2040/scsi_accel_rp2040.cpp

@@ -936,9 +936,13 @@ void scsi_accel_rp2040_init()
     irq_set_enabled(DMA_IRQ_0, true);
     irq_set_enabled(DMA_IRQ_0, true);
 }
 }
 
 
-void scsi_accel_rp2040_setSyncMode(int syncOffset, int syncPeriod)
+bool scsi_accel_rp2040_setSyncMode(int syncOffset, int syncPeriod)
 {
 {
-    assert(g_scsi_dma_state == SCSIDMA_IDLE);
+    if (g_scsi_dma_state != SCSIDMA_IDLE)
+    {
+        log("ERROR: SCSI DMA was in state ", (int)g_scsi_dma_state, " when changing sync mode, forcing bus reset");
+        return false;
+    }
 
 
     if (syncOffset != g_scsi_dma.syncOffset || syncPeriod != g_scsi_dma.syncPeriod)
     if (syncOffset != g_scsi_dma.syncOffset || syncPeriod != g_scsi_dma.syncPeriod)
     {
     {
@@ -1031,4 +1035,5 @@ void scsi_accel_rp2040_setSyncMode(int syncOffset, int syncPeriod)
         }
         }
     }
     }
 
 
+    return true;
 }
 }

+ 2 - 1
lib/BlueSCSI_platform_RP2040/scsi_accel_rp2040.h

@@ -9,7 +9,8 @@ void scsi_accel_rp2040_init();
 // Set SCSI access mode for synchronous transfers
 // Set SCSI access mode for synchronous transfers
 // Setting syncOffset = 0 enables asynchronous SCSI.
 // Setting syncOffset = 0 enables asynchronous SCSI.
 // Setting syncOffset > 0 enables synchronous SCSI.
 // Setting syncOffset > 0 enables synchronous SCSI.
-void scsi_accel_rp2040_setSyncMode(int syncOffset, int syncPeriod);
+// Returns false if busy, caller should issue bus reset to recover.
+bool scsi_accel_rp2040_setSyncMode(int syncOffset, int syncPeriod);
 
 
 // Queue a request to write data from the buffer to SCSI bus.
 // Queue a request to write data from the buffer to SCSI bus.
 // This function typically returns immediately and the request will complete in background.
 // This function typically returns immediately and the request will complete in background.