Explorar o código

Initiator: Handle target premature exit from DATA_IN/DATA_OUT mode

Petteri Aimonen %!s(int64=3) %!d(string=hai) anos
pai
achega
ed855c5ac9

+ 38 - 10
lib/ZuluSCSI_platform_RP2040/scsiHostPhy.cpp

@@ -186,47 +186,75 @@ static inline uint8_t scsiHostReadOneByte(int* parityError)
     return (uint8_t)r;
 }
 
-bool scsiHostWrite(const uint8_t *data, uint32_t count)
+uint32_t scsiHostWrite(const uint8_t *data, uint32_t count)
 {
     scsiLogDataOut(data, count);
 
+    int cd_start = SCSI_IN(CD);
+    int msg_start = SCSI_IN(MSG);
+
     for (uint32_t i = 0; i < count; i++)
     {
-        if (g_scsiHostPhyReset) return false;
+        while (!SCSI_IN(REQ))
+        {
+            if (g_scsiHostPhyReset || SCSI_IN(IO) || SCSI_IN(CD) != cd_start || SCSI_IN(MSG) != msg_start)
+            {
+                // Target switched out of DATA_OUT mode
+                azlog("scsiHostWrite: sent ", (int)i, " bytes, expected ", (int)count);
+                return i;
+            }
+        }
 
         scsiHostWriteOneByte(data[i]);
     }
 
-    return true;
+    return count;
 }
 
-bool scsiHostRead(uint8_t *data, uint32_t count)
+uint32_t scsiHostRead(uint8_t *data, uint32_t count)
 {
     int parityError = 0;
+    uint32_t fullcount = count;
+
+    int cd_start = SCSI_IN(CD);
+    int msg_start = SCSI_IN(MSG);
 
     if ((count & 1) == 0)
     {
         // Even number of bytes, use accelerated routine
-        scsi_accel_host_read(data, count, &parityError, &g_scsiHostPhyReset);
+        count = scsi_accel_host_read(data, count, &parityError, &g_scsiHostPhyReset);
     }
     else
     {
         for (uint32_t i = 0; i < count; i++)
         {
-            if (g_scsiHostPhyReset) return false;
+            while (!SCSI_IN(REQ))
+            {
+                if (g_scsiHostPhyReset || !SCSI_IN(IO) || SCSI_IN(CD) != cd_start || SCSI_IN(MSG) != msg_start)
+                {
+                    // Target switched out of DATA_IN mode
+                    count = i;
+                }
+            }
 
             data[i] = scsiHostReadOneByte(&parityError);
         }
     }
 
-    if (parityError || g_scsiHostPhyReset)
+    scsiLogDataIn(data, count);
+
+    if (g_scsiHostPhyReset || parityError)
     {
-        return false;
+        return 0;
     }
     else
     {
-        scsiLogDataIn(data, count);
-        return true;
+        if (count < fullcount)
+        {
+            azlog("scsiHostRead: received ", (int)count, " bytes, expected ", (int)fullcount);
+        }
+
+        return count;
     }
 }
 

+ 3 - 2
lib/ZuluSCSI_platform_RP2040/scsiHostPhy.h

@@ -24,8 +24,9 @@ int scsiHostPhyGetPhase();
 bool scsiHostRequestWaiting();
 
 // Blocking data transfer
-bool scsiHostWrite(const uint8_t *data, uint32_t count);
-bool scsiHostRead(uint8_t *data, uint32_t count);
+// These return the actual number of bytes transferred.
+uint32_t scsiHostWrite(const uint8_t *data, uint32_t count);
+uint32_t scsiHostRead(uint8_t *data, uint32_t count);
 
 // Release all bus signals
 void scsiHostPhyRelease();

+ 15 - 5
lib/ZuluSCSI_platform_RP2040/scsi_accel_host.cpp

@@ -58,12 +58,15 @@ static void scsi_accel_host_config_gpio()
     }
 }
 
-void scsi_accel_host_read(uint8_t *buf, uint32_t count, int *parityError, volatile int *resetFlag)
+uint32_t scsi_accel_host_read(uint8_t *buf, uint32_t count, int *parityError, volatile int *resetFlag)
 {
     // Currently this method just reads from the PIO RX fifo directly in software loop.
     // The SD card access is parallelized using DMA, so there is limited benefit from using DMA here.
     g_scsi_host_state = SCSIHOST_READ;
 
+    int cd_start = SCSI_IN(CD);
+    int msg_start = SCSI_IN(MSG);
+
     pio_sm_init(SCSI_PIO, SCSI_SM, g_scsi_host.pio_offset_async_read, &g_scsi_host.pio_cfg_async_read);
     scsi_accel_host_config_gpio();
     pio_sm_set_enabled(SCSI_PIO, SCSI_SM, true);
@@ -78,13 +81,18 @@ void scsi_accel_host_read(uint8_t *buf, uint32_t count, int *parityError, volati
     uint32_t paritycheck = 0;
     while (dst < end)
     {
-        if (*resetFlag)
+        uint32_t available = pio_sm_get_rx_fifo_level(SCSI_PIO, SCSI_SM);
+
+        if (available == 0)
         {
-            break;
+            if (*resetFlag || !SCSI_IN(IO) || SCSI_IN(CD) != cd_start || SCSI_IN(MSG) != msg_start)
+            {
+                // Target switched out of DATA_IN mode
+                count = dst - buf;
+                break;
+            }
         }
 
-        uint32_t available = pio_sm_get_rx_fifo_level(SCSI_PIO, SCSI_SM);
-
         while (available > 0)
         {
             available--;
@@ -110,6 +118,8 @@ void scsi_accel_host_read(uint8_t *buf, uint32_t count, int *parityError, volati
     SCSI_RELEASE_DATA_REQ();
     scsi_accel_host_config_gpio();
     pio_sm_set_enabled(SCSI_PIO, SCSI_SM, false);
+
+    return count;
 }
 
 

+ 1 - 1
lib/ZuluSCSI_platform_RP2040/scsi_accel_host.h

@@ -8,4 +8,4 @@ void scsi_accel_host_init();
 
 // Read data from SCSI bus.
 // Number of bytes to read must be divisible by two.
-void scsi_accel_host_read(uint8_t *buf, uint32_t count, int *parityError, volatile int *resetFlag);
+uint32_t scsi_accel_host_read(uint8_t *buf, uint32_t count, int *parityError, volatile int *resetFlag);

+ 5 - 5
src/ZuluSCSI_initiator.cpp

@@ -293,7 +293,7 @@ int scsiInitiatorRunCommand(int target_id,
                 break;
             }
 
-            if (!scsiHostRead(bufIn, bufInLen))
+            if (scsiHostRead(bufIn, bufInLen) == 0)
             {
                 azlog("scsiHostRead failed, tried to read ", (int)bufInLen, " bytes");
                 status = -2;
@@ -310,7 +310,7 @@ int scsiInitiatorRunCommand(int target_id,
                 break;
             }
 
-            if (!scsiHostWrite(bufOut, bufOutLen))
+            if (scsiHostWrite(bufOut, bufOutLen) < bufOutLen)
             {
                 azlog("scsiHostWrite failed, was writing ", bytearray(bufOut, bufOutLen));
                 status = -2;
@@ -319,7 +319,7 @@ int scsiInitiatorRunCommand(int target_id,
         }
         else if (phase == STATUS)
         {
-            uint8_t tmp = 0;
+            uint8_t tmp = -1;
             scsiHostRead(&tmp, 1);
             status = tmp;
             azdbg("------ STATUS: ", tmp);
@@ -373,7 +373,7 @@ bool scsiInitiatorReadCapacity(int target_id, uint32_t *sectorcount, uint32_t *s
 // Execute REQUEST SENSE command to get more information about error status
 bool scsiRequestSense(int target_id, uint8_t *sense_key)
 {
-    uint8_t command[6] = {0x03, 0, 0, 0, 4, 0};
+    uint8_t command[6] = {0x03, 0, 0, 0, 18, 0};
     uint8_t response[18] = {0};
 
     int status = scsiInitiatorRunCommand(target_id,
@@ -531,7 +531,7 @@ static void initiatorReadSDCallback(uint32_t bytes_complete)
             return;
 
         // azdbg("SCSI read ", (int)start, " + ", (int)len, ", sd ready cnt ", (int)sd_ready_cnt, " ", (int)bytes_complete, ", scsi done ", (int)g_initiator_transfer.bytes_scsi_done);
-        if (!scsiHostRead(&scsiDev.data[start], len))
+        if (scsiHostRead(&scsiDev.data[start], len) != len)
         {
             azlog("Read failed at byte ", (int)g_initiator_transfer.bytes_scsi_done);
             g_initiator_transfer.all_ok = false;