Quellcode durchsuchen

Synchronous support 5MB/s and 10MB/s working.
Also fixes bug in FPGA interface that caused issues writing large files.

Michael McMaster vor 9 Jahren
Ursprung
Commit
c820106a2c

+ 1 - 0
lib/SCSI2SD/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

+ 2 - 1
lib/SCSI2SD/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" \

BIN
lib/SCSI2SD/rtl/fpga_bitmap.o


+ 1 - 1
lib/SCSI2SD/src/firmware/bsp.h

@@ -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

+ 1 - 1
lib/SCSI2SD/src/firmware/config.c

@@ -37,7 +37,7 @@
 
 #include <string.h>
 
-static const uint16_t FIRMWARE_VERSION = 0x0606;
+static const uint16_t FIRMWARE_VERSION = 0x0607;
 
 // 1 flash row
 static const uint8_t DEFAULT_CONFIG[128] =

+ 21 - 1
lib/SCSI2SD/src/firmware/diagnostic.c

@@ -165,6 +165,26 @@ void scsiReadBuffer()
 			(allocLength > MAX_SECTOR_SIZE) ? MAX_SECTOR_SIZE : allocLength;
 		scsiDev.phase = DATA_IN;
 	}
+	else if (mode == 0x2 && (scsiDev.cdb[2] == 0))
+	{
+		// TODO support BUFFER OFFSET fields in CDB
+		scsiDev.dataLen =
+			(allocLength > MAX_SECTOR_SIZE) ? MAX_SECTOR_SIZE : allocLength;
+		scsiDev.phase = DATA_IN;
+	}
+	else if (mode == 0x3)
+	{
+		uint32_t maxSize = MAX_SECTOR_SIZE - 4;
+		// 4 byte header
+		scsiDev.data[0] = 0;
+		scsiDev.data[1] = (maxSize >> 16) & 0xff;
+		scsiDev.data[2] = (maxSize >> 8) & 0xff;
+		scsiDev.data[3] = maxSize & 0xff;
+
+		scsiDev.dataLen =
+			(allocLength > 4) ? 4: allocLength;
+		scsiDev.phase = DATA_IN;
+	}
 	else
 	{
 		// error.
@@ -198,7 +218,7 @@ void scsiWriteBuffer()
 		(((uint32_t) scsiDev.cdb[7]) << 8) +
 		scsiDev.cdb[8];
 
-	if (mode == 0 && allocLength <= sizeof(scsiDev.data))
+	if ((mode == 0 || mode == 2) && allocLength <= sizeof(scsiDev.data))
 	{
 		scsiDev.dataLen = allocLength;
 		scsiDev.phase = DATA_OUT;

+ 1 - 1
lib/SCSI2SD/src/firmware/inquiry.c

@@ -29,7 +29,7 @@ static uint8_t StandardResponse[] =
 0x01, // Response format is compatible with the old CCS format.
 0x1f, // standard length.
 0, 0, // Reserved
-0x08 // Enable linked commands
+0x18 // Enable sync and linked commands
 };
 // Vendor set by config 'c','o','d','e','s','r','c',' ',
 // prodId set by config'S','C','S','I','2','S','D',' ',' ',' ',' ',' ',' ',' ',' ',' ',

+ 49 - 3
lib/SCSI2SD/src/firmware/scsi.c

@@ -480,6 +480,13 @@ static void scsiReset()
 		scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
 	}
 	scsiDev.target = NULL;
+
+	for (int i = 0; i < S2S_MAX_TARGETS; ++i)
+	{
+		scsiDev.target[i].syncOffset = 0;
+		scsiDev.target[i].syncPeriod = 0;
+	}
+
 	scsiDiskReset();
 
 	scsiDev.postDataOutHook = NULL;
@@ -516,6 +523,8 @@ static void enter_SelectionPhase()
 	transfer.currentBlock = 0;
 
 	scsiDev.postDataOutHook = NULL;
+
+	scsiDev.needSyncNegotiationAck = 0;
 }
 
 static void process_SelectionPhase()
@@ -655,6 +664,11 @@ static void process_MessageOut()
 		// ANY initiator can reset the reservation state via this message.
 		scsiDev.target->reservedId = -1;
 		scsiDev.target->reserverId = -1;
+
+		// Cancel any sync negotiation
+		scsiDev.target->syncOffset = 0;
+		scsiDev.target->syncPeriod = 0;
+
 		enter_BusFree();
 	}
 	else if (scsiDev.msgOut == 0x05)
@@ -677,7 +691,13 @@ static void process_MessageOut()
 	{
 		// Message Reject
 		// Oh well.
-		scsiDev.resetFlag = 1;
+
+		if (scsiDev.needSyncNegotiationAck)
+		{
+			scsiDev.target->syncOffset = 0;
+			scsiDev.target->syncPeriod = 0;
+			scsiDev.needSyncNegotiationAck = 0;
+		}
 	}
 	else if (scsiDev.msgOut == 0x08)
 	{
@@ -737,10 +757,27 @@ static void process_MessageOut()
 		}
 		else if (extmsg[0] == 1 && msgLen == 3) // Synchronous data request
 		{
-			// Negotiate back to async
+			int transferPeriod = extmsg[3];
+			int offset = extmsg[4];
+
+			if (transferPeriod > 50) // 200ns, 5MB/s
+			{
+				scsiDev.target->syncOffset = 0;
+				scsiDev.target->syncPeriod = 0;
+			} else {
+				scsiDev.target->syncOffset = offset < 15 ? offset : 15;
+				if (transferPeriod <= 25)
+				{
+					scsiDev.target->syncPeriod = 25; // 10MB/s
+				} else {
+					scsiDev.target->syncPeriod = 50; // 5MB/s
+				}
+			}
+
 			scsiEnterPhase(MESSAGE_IN);
-			static const uint8_t SDTR[] = {0x01, 0x03, 0x01, 0x00, 0x00};
+			uint8_t SDTR[] = {0x01, 0x03, 0x01, scsiDev.target->syncPeriod, scsiDev.target->syncOffset};
 			scsiWrite(SDTR, sizeof(SDTR));
+			scsiDev.needSyncNegotiationAck = 1; // Check if this message is rejected.
 		}
 		else
 		{
@@ -755,6 +792,12 @@ static void process_MessageOut()
 
 	// Re-check the ATN flag in case it stays asserted.
 	scsiDev.atnFlag |= scsiStatusATN();
+
+	if (!scsiDev.atnFlag)
+	{
+		// Message wasn't rejected!
+		scsiDev.needSyncNegotiationAck = 0;
+	}
 }
 
 void scsiPoll(void)
@@ -918,6 +961,9 @@ void scsiInit()
 		}
 		scsiDev.targets[i].sense.code = NO_SENSE;
 		scsiDev.targets[i].sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+
+		scsiDev.targets[i].syncOffset = 0;
+		scsiDev.targets[i].syncPeriod = 0;
 	}
 	firstInit = 0;
 }

+ 5 - 0
lib/SCSI2SD/src/firmware/scsi.h

@@ -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;

+ 44 - 6
lib/SCSI2SD/src/firmware/scsiPhy.c

@@ -28,6 +28,17 @@
 
 #include <string.h>
 
+// Assumes a 60MHz fpga clock.
+// 7:6 Hold count, 45ns
+// 5:3 Assertion count, 90ns
+// 2:0 Deskew count, 55ns
+#define SCSI_DEFAULT_TIMING ((0x3 << 6) | (0x6 << 3) | 0x4)
+
+// 7:6 Hold count, 10ns
+// 5:3 Assertion count, 30ns
+// 2:0 Deskew count, 25ns
+#define SCSI_FAST_TIMING ((0x1 << 6) | (0x2 << 3) | 0x2)
+
 // Private DMA variables.
 static int dmaInProgress = 0;
 
@@ -218,17 +229,21 @@ scsiRead(uint8_t* data, uint32_t count)
 			};
 		}
 
-#if FIFODEBUG
-		if (!scsiPhyFifoEmpty()) {
+
+		i += chunk;
+		chunk = nextChunk;
+	}
+#if 1
+		if (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty()) {
 			int j = 0;
 			while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++j; }
+			scsiPhyFifoFlip();
+			int k = 0;
+			while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++k; }
 			// Force a lock-up.
 			assertFail();
 		}
 #endif
-		i += chunk;
-		chunk = nextChunk;
-	}
 }
 
 void
@@ -382,12 +397,29 @@ void scsiEnterPhase(int phase)
 	int newPhase = phase > 0 ? phase : 0;
 	int oldPhase = *SCSI_CTRL_PHASE;
 
-	if (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty()) {
+	if (!scsiDev.resetFlag && (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty())) {
 		// Force a lock-up.
 		assertFail();
 	}
 	if (newPhase != oldPhase)
 	{
+		if ((newPhase == DATA_IN || newPhase == DATA_OUT) &&
+			scsiDev.target->syncOffset)
+		{
+			if (scsiDev.target->syncPeriod == 25)
+			{
+				// SCSI2 FAST Timing. 10MB/s.
+				*SCSI_CTRL_TIMING = SCSI_FAST_TIMING;
+			} else {
+				// 5MB/s Timing
+				*SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
+			}
+			*SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;
+		} else {
+			*SCSI_CTRL_SYNC_OFFSET = 0;
+			*SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
+		}
+
 		*SCSI_CTRL_PHASE = newPhase;
 		busSettleDelay();
 
@@ -446,6 +478,9 @@ void scsiPhyReset()
 	*SCSI_FIFO_SEL = 0;
 	*SCSI_CTRL_DBX = 0;
 
+	*SCSI_CTRL_SYNC_OFFSET = 0;
+	*SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
+
 	// DMA Benchmark code
 	// Currently 10MB/s. Assume 20MB/s is achievable with 16 bits.
 	#ifdef DMA_BENCHMARK
@@ -609,6 +644,9 @@ void scsiPhyInit()
 	*SCSI_FIFO_SEL = 0;
 	*SCSI_CTRL_DBX = 0;
 
+	*SCSI_CTRL_SYNC_OFFSET = 0;
+	*SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
+
 }
 
 void scsiPhyConfig()

+ 2 - 0
lib/SCSI2SD/src/firmware/scsiPhy.h

@@ -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)