From: Michael McMaster Date: Fri, 26 Aug 2016 13:28:58 +0000 (+1000) Subject: Synchronous support 5MB/s and 10MB/s working. X-Git-Tag: v6.0.8~3 X-Git-Url: http://git.codesrc.com/gitweb.cgi?a=commitdiff_plain;h=918a04a159194bf4253b604fd9b223fed53616d9;p=SCSI2SD-V6.git Synchronous support 5MB/s and 10MB/s working. Also fixes bug in FPGA interface that caused issues writing large files. --- diff --git a/CHANGELOG b/CHANGELOG index 3bbc3afc..f16e0648 100644 --- 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 diff --git a/Makefile b/Makefile index 61c82263..0839fcdf 100644 --- 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" \ diff --git a/rtl/fpga_bitmap.o b/rtl/fpga_bitmap.o index 53348881..56551b36 100644 Binary files a/rtl/fpga_bitmap.o and b/rtl/fpga_bitmap.o differ diff --git a/src/firmware/bsp.h b/src/firmware/bsp.h index 5b9c8d14..fd1a7108 100644 --- a/src/firmware/bsp.h +++ b/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 diff --git a/src/firmware/config.c b/src/firmware/config.c index eb6b3694..89772632 100755 --- a/src/firmware/config.c +++ b/src/firmware/config.c @@ -37,7 +37,7 @@ #include -static const uint16_t FIRMWARE_VERSION = 0x0606; +static const uint16_t FIRMWARE_VERSION = 0x0607; // 1 flash row static const uint8_t DEFAULT_CONFIG[128] = diff --git a/src/firmware/diagnostic.c b/src/firmware/diagnostic.c index 0f924062..faddace1 100755 --- a/src/firmware/diagnostic.c +++ b/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; diff --git a/src/firmware/inquiry.c b/src/firmware/inquiry.c index 549ee4f4..d51b3c0d 100755 --- a/src/firmware/inquiry.c +++ b/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',' ',' ',' ',' ',' ',' ',' ',' ',' ', diff --git a/src/firmware/scsi.c b/src/firmware/scsi.c index bbb3e484..e43afd24 100755 --- a/src/firmware/scsi.c +++ b/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; } diff --git a/src/firmware/scsi.h b/src/firmware/scsi.h index 2e3a5fa8..2ef223ec 100755 --- a/src/firmware/scsi.h +++ b/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; diff --git a/src/firmware/scsiPhy.c b/src/firmware/scsiPhy.c index 2231089d..71640f4f 100755 --- a/src/firmware/scsiPhy.c +++ b/src/firmware/scsiPhy.c @@ -28,6 +28,17 @@ #include +// 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() diff --git a/src/firmware/scsiPhy.h b/src/firmware/scsiPhy.h index fcdf3e45..b70ff7bc 100755 --- a/src/firmware/scsiPhy.h +++ b/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)