Synchronous support 5MB/s and 10MB/s working.
authorMichael McMaster <michael@codesrc.com>
Fri, 26 Aug 2016 13:28:58 +0000 (23:28 +1000)
committerMichael McMaster <michael@codesrc.com>
Fri, 26 Aug 2016 13:28:58 +0000 (23:28 +1000)
Also fixes bug in FPGA interface that caused issues writing large files.

CHANGELOG
Makefile
rtl/fpga_bitmap.o
src/firmware/bsp.h
src/firmware/config.c
src/firmware/diagnostic.c
src/firmware/inquiry.c
src/firmware/scsi.c
src/firmware/scsi.h
src/firmware/scsiPhy.c
src/firmware/scsiPhy.h

index 3bbc3af..f16e064 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,5 @@
 2016XXXX               6.0.7
+       - Synchronous transfers supported ! 5MB/s and 10MB/s supported.
        - Fix for accessing data via USB with more than 2 devices configured.
 
 20160815               6.0.6
index 61c8226..0839fcd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,8 +6,9 @@ CPPFLAGS=-DSTM32F205xx -DUSE_HAL_DRIVER -Wall -Werror
 CFLAGS=-mcpu=cortex-m3 -mthumb -mslow-flash-data \
        -std=gnu11 \
        -specs=nosys.specs \
-       -Os -g \
+       -g \
 
+#      -Os -g \
 
 LDFLAGS= \
        "-Tsrc/firmware/link.ld" \
index 5334888..56551b3 100644 (file)
Binary files a/rtl/fpga_bitmap.o and b/rtl/fpga_bitmap.o differ
index 5b9c8d1..fd1a710 100644 (file)
@@ -20,7 +20,7 @@
 
 // For the STM32F205, DMA bursts may not cross 1KB address boundaries.
 // The maximum burst is 16 bytes.
-#define S2S_DMA_ALIGN __attribute__((aligned(16)))
+#define S2S_DMA_ALIGN __attribute__((aligned(1024)))
 
 
 #endif
index eb6b369..8977263 100755 (executable)
@@ -37,7 +37,7 @@
 \r
 #include <string.h>\r
 \r
-static const uint16_t FIRMWARE_VERSION = 0x0606;\r
+static const uint16_t FIRMWARE_VERSION = 0x0607;\r
 \r
 // 1 flash row\r
 static const uint8_t DEFAULT_CONFIG[128] =\r
index 0f92406..faddace 100755 (executable)
@@ -165,6 +165,26 @@ void scsiReadBuffer()
                        (allocLength > MAX_SECTOR_SIZE) ? MAX_SECTOR_SIZE : allocLength;\r
                scsiDev.phase = DATA_IN;\r
        }\r
+       else if (mode == 0x2 && (scsiDev.cdb[2] == 0))\r
+       {\r
+               // TODO support BUFFER OFFSET fields in CDB\r
+               scsiDev.dataLen =\r
+                       (allocLength > MAX_SECTOR_SIZE) ? MAX_SECTOR_SIZE : allocLength;\r
+               scsiDev.phase = DATA_IN;\r
+       }\r
+       else if (mode == 0x3)\r
+       {\r
+               uint32_t maxSize = MAX_SECTOR_SIZE - 4;\r
+               // 4 byte header\r
+               scsiDev.data[0] = 0;\r
+               scsiDev.data[1] = (maxSize >> 16) & 0xff;\r
+               scsiDev.data[2] = (maxSize >> 8) & 0xff;\r
+               scsiDev.data[3] = maxSize & 0xff;\r
+\r
+               scsiDev.dataLen =\r
+                       (allocLength > 4) ? 4: allocLength;\r
+               scsiDev.phase = DATA_IN;\r
+       }\r
        else\r
        {\r
                // error.\r
@@ -198,7 +218,7 @@ void scsiWriteBuffer()
                (((uint32_t) scsiDev.cdb[7]) << 8) +\r
                scsiDev.cdb[8];\r
 \r
-       if (mode == 0 && allocLength <= sizeof(scsiDev.data))\r
+       if ((mode == 0 || mode == 2) && allocLength <= sizeof(scsiDev.data))\r
        {\r
                scsiDev.dataLen = allocLength;\r
                scsiDev.phase = DATA_OUT;\r
index 549ee4f..d51b3c0 100755 (executable)
@@ -29,7 +29,7 @@ static uint8_t StandardResponse[] =
 0x01, // Response format is compatible with the old CCS format.\r
 0x1f, // standard length.\r
 0, 0, // Reserved\r
-0x08 // Enable linked commands\r
+0x18 // Enable sync and linked commands\r
 };\r
 // Vendor set by config 'c','o','d','e','s','r','c',' ',\r
 // prodId set by config'S','C','S','I','2','S','D',' ',' ',' ',' ',' ',' ',' ',' ',' ',\r
index bbb3e48..e43afd2 100755 (executable)
@@ -480,6 +480,13 @@ static void scsiReset()
                scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;\r
        }\r
        scsiDev.target = NULL;\r
+\r
+       for (int i = 0; i < S2S_MAX_TARGETS; ++i)\r
+       {\r
+               scsiDev.target[i].syncOffset = 0;\r
+               scsiDev.target[i].syncPeriod = 0;\r
+       }\r
+\r
        scsiDiskReset();\r
 \r
        scsiDev.postDataOutHook = NULL;\r
@@ -516,6 +523,8 @@ static void enter_SelectionPhase()
        transfer.currentBlock = 0;\r
 \r
        scsiDev.postDataOutHook = NULL;\r
+\r
+       scsiDev.needSyncNegotiationAck = 0;\r
 }\r
 \r
 static void process_SelectionPhase()\r
@@ -655,6 +664,11 @@ static void process_MessageOut()
                // ANY initiator can reset the reservation state via this message.\r
                scsiDev.target->reservedId = -1;\r
                scsiDev.target->reserverId = -1;\r
+\r
+               // Cancel any sync negotiation\r
+               scsiDev.target->syncOffset = 0;\r
+               scsiDev.target->syncPeriod = 0;\r
+\r
                enter_BusFree();\r
        }\r
        else if (scsiDev.msgOut == 0x05)\r
@@ -677,7 +691,13 @@ static void process_MessageOut()
        {\r
                // Message Reject\r
                // Oh well.\r
-               scsiDev.resetFlag = 1;\r
+\r
+               if (scsiDev.needSyncNegotiationAck)\r
+               {\r
+                       scsiDev.target->syncOffset = 0;\r
+                       scsiDev.target->syncPeriod = 0;\r
+                       scsiDev.needSyncNegotiationAck = 0;\r
+               }\r
        }\r
        else if (scsiDev.msgOut == 0x08)\r
        {\r
@@ -737,10 +757,27 @@ static void process_MessageOut()
                }\r
                else if (extmsg[0] == 1 && msgLen == 3) // Synchronous data request\r
                {\r
-                       // Negotiate back to async\r
+                       int transferPeriod = extmsg[3];\r
+                       int offset = extmsg[4];\r
+\r
+                       if (transferPeriod > 50) // 200ns, 5MB/s\r
+                       {\r
+                               scsiDev.target->syncOffset = 0;\r
+                               scsiDev.target->syncPeriod = 0;\r
+                       } else {\r
+                               scsiDev.target->syncOffset = offset < 15 ? offset : 15;\r
+                               if (transferPeriod <= 25)\r
+                               {\r
+                                       scsiDev.target->syncPeriod = 25; // 10MB/s\r
+                               } else {\r
+                                       scsiDev.target->syncPeriod = 50; // 5MB/s\r
+                               }\r
+                       }\r
+\r
                        scsiEnterPhase(MESSAGE_IN);\r
-                       static const uint8_t SDTR[] = {0x01, 0x03, 0x01, 0x00, 0x00};\r
+                       uint8_t SDTR[] = {0x01, 0x03, 0x01, scsiDev.target->syncPeriod, scsiDev.target->syncOffset};\r
                        scsiWrite(SDTR, sizeof(SDTR));\r
+                       scsiDev.needSyncNegotiationAck = 1; // Check if this message is rejected.\r
                }\r
                else\r
                {\r
@@ -755,6 +792,12 @@ static void process_MessageOut()
 \r
        // Re-check the ATN flag in case it stays asserted.\r
        scsiDev.atnFlag |= scsiStatusATN();\r
+\r
+       if (!scsiDev.atnFlag)\r
+       {\r
+               // Message wasn't rejected!\r
+               scsiDev.needSyncNegotiationAck = 0;\r
+       }\r
 }\r
 \r
 void scsiPoll(void)\r
@@ -918,6 +961,9 @@ void scsiInit()
                }\r
                scsiDev.targets[i].sense.code = NO_SENSE;\r
                scsiDev.targets[i].sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;\r
+\r
+               scsiDev.targets[i].syncOffset = 0;\r
+               scsiDev.targets[i].syncPeriod = 0;\r
        }\r
        firstInit = 0;\r
 }\r
index 2e3a5fa..2ef223e 100755 (executable)
@@ -93,6 +93,9 @@ typedef struct
        // A 3rd party may be sending the RESERVE/RELEASE commands
        int reservedId; // 0 -> 7 if reserved. -1 if not reserved.
        int reserverId; // 0 -> 7 if reserved. -1 if not reserved.
+
+       uint8_t syncOffset;
+       uint8_t syncPeriod;
 } TargetState;
 
 typedef struct
@@ -148,6 +151,8 @@ typedef struct
        uint8_t lastStatus;
        uint8_t lastSense;
        uint16_t lastSenseASC;
+
+       int needSyncNegotiationAck;
 } ScsiDevice;
 
 extern ScsiDevice scsiDev;
index 2231089..71640f4 100755 (executable)
 \r
 #include <string.h>\r
 \r
+// Assumes a 60MHz fpga clock.\r
+// 7:6 Hold count, 45ns\r
+// 5:3 Assertion count, 90ns\r
+// 2:0 Deskew count, 55ns\r
+#define SCSI_DEFAULT_TIMING ((0x3 << 6) | (0x6 << 3) | 0x4)\r
+\r
+// 7:6 Hold count, 10ns\r
+// 5:3 Assertion count, 30ns\r
+// 2:0 Deskew count, 25ns\r
+#define SCSI_FAST_TIMING ((0x1 << 6) | (0x2 << 3) | 0x2)\r
+\r
 // Private DMA variables.\r
 static int dmaInProgress = 0;\r
 \r
@@ -218,17 +229,21 @@ scsiRead(uint8_t* data, uint32_t count)
                        };\r
                }\r
 \r
-#if FIFODEBUG\r
-               if (!scsiPhyFifoEmpty()) {\r
+\r
+               i += chunk;\r
+               chunk = nextChunk;\r
+       }\r
+#if 1\r
+               if (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty()) {\r
                        int j = 0;\r
                        while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++j; }\r
+                       scsiPhyFifoFlip();\r
+                       int k = 0;\r
+                       while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++k; }\r
                        // Force a lock-up.\r
                        assertFail();\r
                }\r
 #endif\r
-               i += chunk;\r
-               chunk = nextChunk;\r
-       }\r
 }\r
 \r
 void\r
@@ -382,12 +397,29 @@ void scsiEnterPhase(int phase)
        int newPhase = phase > 0 ? phase : 0;\r
        int oldPhase = *SCSI_CTRL_PHASE;\r
 \r
-       if (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty()) {\r
+       if (!scsiDev.resetFlag && (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty())) {\r
                // Force a lock-up.\r
                assertFail();\r
        }\r
        if (newPhase != oldPhase)\r
        {\r
+               if ((newPhase == DATA_IN || newPhase == DATA_OUT) &&\r
+                       scsiDev.target->syncOffset)\r
+               {\r
+                       if (scsiDev.target->syncPeriod == 25)\r
+                       {\r
+                               // SCSI2 FAST Timing. 10MB/s.\r
+                               *SCSI_CTRL_TIMING = SCSI_FAST_TIMING;\r
+                       } else {\r
+                               // 5MB/s Timing\r
+                               *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;\r
+                       }\r
+                       *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;\r
+               } else {\r
+                       *SCSI_CTRL_SYNC_OFFSET = 0;\r
+                       *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;\r
+               }\r
+\r
                *SCSI_CTRL_PHASE = newPhase;\r
                busSettleDelay();\r
 \r
@@ -446,6 +478,9 @@ void scsiPhyReset()
        *SCSI_FIFO_SEL = 0;\r
        *SCSI_CTRL_DBX = 0;\r
 \r
+       *SCSI_CTRL_SYNC_OFFSET = 0;\r
+       *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;\r
+\r
        // DMA Benchmark code\r
        // Currently 10MB/s. Assume 20MB/s is achievable with 16 bits.\r
        #ifdef DMA_BENCHMARK\r
@@ -609,6 +644,9 @@ void scsiPhyInit()
        *SCSI_FIFO_SEL = 0;\r
        *SCSI_CTRL_DBX = 0;\r
 \r
+       *SCSI_CTRL_SYNC_OFFSET = 0;\r
+       *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;\r
+\r
 }\r
 \r
 void scsiPhyConfig()\r
index fcdf3e4..b70ff7b 100755 (executable)
@@ -25,6 +25,8 @@
 #define SCSI_DATA_CNT_LO ((volatile uint8_t*)0x60000005)
 #define SCSI_DATA_CNT_SET ((volatile uint8_t*)0x60000006)
 #define SCSI_CTRL_DBX ((volatile uint8_t*)0x60000007)
+#define SCSI_CTRL_SYNC_OFFSET ((volatile uint8_t*)0x60000008)
+#define SCSI_CTRL_TIMING ((volatile uint8_t*)0x60000009)
 
 #define SCSI_STS_FIFO ((volatile uint8_t*)0x60000010)
 #define SCSI_STS_ALTFIFO ((volatile uint8_t*)0x60000011)