\r
#include "stm32f2xx.h"\r
\r
+// For SD write direct routines\r
+#include "sdio.h"\r
+#include "bsp_driver_sd.h"\r
+\r
+\r
#include "scsi.h"\r
#include "scsiPhy.h"\r
#include "config.h"\r
#include "disk.h"\r
#include "sd.h"\r
#include "time.h"\r
+#include "bsp.h"\r
\r
#include <string.h>\r
\r
if (scsiDev.phase == DATA_IN &&\r
transfer.currentBlock != transfer.blocks)\r
{\r
- scsiEnterPhase(DATA_IN);\r
\r
int totalSDSectors =\r
transfer.blocks * SDSectorsPerSCSISector(bytesPerSector);\r
int i = 0;\r
int scsiActive __attribute__((unused)) = 0; // unused if DMA disabled\r
int sdActive = 0;\r
+\r
+ uint32_t partialScsiChunk = 0;\r
+\r
+ // Start reading from the SD card FIRST, because we change state and\r
+ // wai for SCSI signals\r
+ int dataInStarted = 0;\r
+\r
while ((i < totalSDSectors) &&\r
- likely(scsiDev.phase == DATA_IN) &&\r
+ (!dataInStarted || likely(scsiDev.phase == DATA_IN)) &&\r
likely(!scsiDev.resetFlag))\r
{\r
int completedDmaSectors;\r
sdReadDMA(sdLBA + prep, sectors, &scsiDev.data[SD_SECTOR_SIZE * startBuffer]);\r
\r
sdActive = sectors;\r
+\r
+ if (!dataInStarted)\r
+ {\r
+ dataInStarted = 1;\r
+ scsiEnterPhase(DATA_IN); // Will wait a few microseconds.\r
+ }\r
}\r
\r
#ifdef SCSI_FSMC_DMA\r
+ #error this code not updated for 256 max bytes in scsi fifo\r
if (scsiActive && scsiPhyComplete() && scsiWriteDMAPoll())\r
{\r
scsiActive = 0;\r
if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;\r
}\r
\r
- uint16_t* scsiDmaData = (uint16_t*) &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);\r
// Manually unrolled loop for performance.\r
// -Os won't unroll this for us automatically,\r
// especially since scsiPhyTx does volatile stuff.\r
// Reduces bus utilisation by making the fsmc split\r
// 32bits into 2 16 bit writes.\r
+\r
+ uint16_t* scsiDmaData = (uint16_t*) &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers) + partialScsiChunk]);\r
+\r
+ uint32_t chunk = ((dmaBytes - partialScsiChunk) > SCSI_FIFO_DEPTH)\r
+ ? SCSI_FIFO_DEPTH : (dmaBytes - partialScsiChunk);\r
+\r
int k = 0;\r
- for (; k + 4 < (dmaBytes + 1) / 2; k += 4)\r
+ for (; k + 4 < (chunk + 1) / 2; k += 4)\r
{\r
scsiPhyTx32(scsiDmaData[k], scsiDmaData[k+1]);\r
scsiPhyTx32(scsiDmaData[k+2], scsiDmaData[k+3]);\r
}\r
- for (; k < (dmaBytes + 1) / 2; ++k)\r
+ for (; k < (chunk + 1) / 2; ++k)\r
{\r
scsiPhyTx(scsiDmaData[k]);\r
}\r
- i++;\r
while (!scsiPhyComplete() && !scsiDev.resetFlag)\r
{\r
__WFE(); // Wait for event\r
}\r
scsiPhyFifoFlip();\r
- scsiSetDataCount(dmaBytes);\r
+ scsiSetDataCount(chunk);\r
+\r
+ partialScsiChunk += chunk;\r
+ if (partialScsiChunk == dmaBytes)\r
+ {\r
+ partialScsiChunk = 0;\r
+ ++i;\r
+ }\r
}\r
#endif\r
}\r
\r
+ if (!dataInStarted && !scsiDev.resetFlag) // zero bytes ?\r
+ {\r
+ scsiEnterPhase(DATA_IN); // Will wait a few microseconds.\r
+ }\r
+\r
// We've finished transferring the data to the FPGA, now wait until it's\r
// written to he SCSI bus.\r
while (!scsiPhyComplete() &&\r
scsiDev.target->cfg->sdSectorStart,\r
bytesPerSector,\r
transfer.lba);\r
- // int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;\r
- // int prep = 0;\r
int i = 0;\r
- // int scsiDisconnected = 0;\r
- int scsiComplete = 0;\r
- //uint32_t lastActivityTime = s2s_getTime_ms();\r
- // int scsiActive = 0;\r
- // int sdActive = 0;\r
int clearBSY = 0;\r
\r
int parityError = 0;\r
+ int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;\r
+\r
while ((i < totalSDSectors) &&\r
- (likely(scsiDev.phase == DATA_OUT) || // scsiDisconnect keeps our phase.\r
- scsiComplete) &&\r
+ likely(scsiDev.phase == DATA_OUT) &&\r
likely(!scsiDev.resetFlag) &&\r
- likely(!parityError))\r
+ likely(!parityError || !enableParity))\r
{\r
// Well, until we have some proper non-blocking SD code, we must\r
// do this in a half-duplex fashion. We need to write as much as\r
uint32_t rem = totalSDSectors - i;\r
uint32_t sectors =\r
rem < maxSectors ? rem : maxSectors;\r
- scsiRead(&scsiDev.data[0], sectors * SD_SECTOR_SIZE, &parityError);\r
\r
- if (i + sectors >= totalSDSectors)\r
+ if (bytesPerSector == SD_SECTOR_SIZE)\r
{\r
- // We're transferring over the SCSI bus faster than the SD card\r
- // can write. All data is buffered, and we're just waiting for\r
- // the SD card to complete. The host won't let us disconnect.\r
- // Some drivers set a 250ms timeout on transfers to complete.\r
- // SD card writes are supposed to complete\r
- // within 200ms, but sometimes they don'to.\r
- // Just pretend we're finished.\r
- process_Status();\r
- process_MessageIn(); // Will go to BUS_FREE state\r
-\r
- // Try and prevent anyone else using the SCSI bus while we're not ready.\r
- if (*SCSI_CTRL_BSY == 0) // Could be busy for a linked command\r
+ // We assume the SD card is faster than the SCSI interface, but has\r
+ // no flow control. This can be handled if a) the scsi interface\r
+ // doesn't block and b) we read enough SCSI sectors first so that\r
+ // the SD interface cannot catch up.\r
+ uint32_t totalBytes = sectors * SD_SECTOR_SIZE;\r
+ uint32_t readAheadBytes = sectors * SD_SECTOR_SIZE;\r
+ uint32_t sdSpeed = s2s_getSdRateMBs() + (scsiDev.sdUnderrunCount / 2);\r
+ uint32_t scsiSpeed = s2s_getScsiRateMBs();\r
+ // if (have blind writes)\r
+ if (scsiSpeed > 0 && scsiDev.sdUnderrunCount < 16)\r
{\r
- *SCSI_CTRL_BSY = 1;\r
- clearBSY = 1;\r
+ // readAhead = sectors * (sd / scsi - 1 + 0.1);\r
+ readAheadBytes = totalBytes * sdSpeed / scsiSpeed - totalBytes + SCSI_FIFO_DEPTH;\r
+ if (readAheadBytes < SCSI_FIFO_DEPTH)\r
+ {\r
+ readAheadBytes = SCSI_FIFO_DEPTH;\r
+ }\r
+\r
+ if (readAheadBytes > totalBytes)\r
+ {\r
+ readAheadBytes = totalBytes;\r
+ }\r
}\r
- }\r
\r
+ uint32_t chunk = (readAheadBytes > SCSI_FIFO_DEPTH) ? SCSI_FIFO_DEPTH : readAheadBytes;\r
+ scsiSetDataCount(chunk);\r
\r
- if (!parityError)\r
- {\r
- sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors);\r
- }\r
- i += sectors;\r
+ uint32_t scsiBytesRead = 0;\r
+ while (scsiBytesRead < readAheadBytes)\r
+ {\r
+ while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
+ {\r
+ __WFE(); // Wait for event\r
+ }\r
+ parityError |= scsiParityError();\r
+ scsiPhyFifoFlip();\r
+ uint32_t nextChunk = ((totalBytes - scsiBytesRead - chunk) > SCSI_FIFO_DEPTH)\r
+ ? SCSI_FIFO_DEPTH : (totalBytes - scsiBytesRead - chunk);\r
+\r
+ if (nextChunk > 0) scsiSetDataCount(nextChunk);\r
+ scsiReadPIO(&scsiDev.data[scsiBytesRead], chunk);\r
+ scsiBytesRead += chunk;\r
+ chunk = nextChunk;\r
+ }\r
\r
-#if 0\r
- // Wait for the next DMA interrupt. It's beneficial to halt the\r
- // processor to give the DMA controller more memory bandwidth to\r
- // work with.\r
- int scsiBusy = 1;\r
- int sdBusy = 1;\r
- while (scsiBusy && sdBusy)\r
- {\r
- uint8_t intr = CyEnterCriticalSection();\r
- scsiBusy = scsiDMABusy();\r
- sdBusy = sdDMABusy();\r
- if (scsiBusy && sdBusy)\r
+ HAL_SD_WriteBlocks_DMA(&hsd, (uint32_t*) (&scsiDev.data[0]), (i + sdLBA) * 512ll, SD_SECTOR_SIZE, sectors);\r
+\r
+ while (scsiBytesRead < totalBytes)\r
{\r
- __WFI();\r
+ while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
+ {\r
+ __WFE(); // Wait for event\r
+ }\r
+ parityError |= scsiParityError();\r
+ scsiPhyFifoFlip();\r
+ uint32_t nextChunk = ((totalBytes - scsiBytesRead - chunk) > SCSI_FIFO_DEPTH)\r
+ ? SCSI_FIFO_DEPTH : (totalBytes - scsiBytesRead - chunk);\r
+\r
+ if (nextChunk > 0) scsiSetDataCount(nextChunk);\r
+ scsiReadPIO(&scsiDev.data[scsiBytesRead], chunk);\r
+ scsiBytesRead += chunk;\r
+ chunk = nextChunk;\r
}\r
- CyExitCriticalSection(intr);\r
- }\r
\r
- if (sdActive && !sdBusy && sdWriteSectorDMAPoll())\r
- {\r
- sdActive = 0;\r
- i++;\r
- }\r
- if (!sdActive && ((prep - i) > 0))\r
- {\r
- // Start an SD transfer if we have space.\r
- sdWriteMultiSectorDMA(&scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);\r
- sdActive = 1;\r
- }\r
+ // Oh dear, SD finished first.\r
+ int underrun = totalBytes > readAheadBytes && hsd.DmaTransferCplt;\r
\r
- uint32_t now = getTime_ms();\r
+ uint32_t dmaFinishTime = s2s_getTime_ms();\r
+ while (!hsd.SdTransferCplt &&\r
+ s2s_elapsedTime_ms(dmaFinishTime) < 180)\r
+ {\r
+ // Wait while keeping BSY.\r
+ }\r
+ while((__HAL_SD_SDIO_GET_FLAG(&hsd, SDIO_FLAG_TXACT)) &&\r
+ s2s_elapsedTime_ms(dmaFinishTime) < 180)\r
+ {\r
+ // Wait for SD card while keeping BSY.\r
+ }\r
\r
- if (scsiActive && !scsiBusy && scsiReadDMAPoll())\r
- {\r
- scsiActive = 0;\r
- ++prep;\r
- lastActivityTime = now;\r
- }\r
- if (!scsiActive &&\r
- ((prep - i) < buffers) &&\r
- (prep < totalSDSectors) &&\r
- likely(!scsiDisconnected))\r
- {\r
- int dmaBytes = SD_SECTOR_SIZE;\r
- if ((prep % sdPerScsi) == (sdPerScsi - 1))\r
+ if (i + sectors >= totalSDSectors &&\r
+ !underrun &&\r
+ (!parityError || !enableParity))\r
{\r
- dmaBytes = bytesPerSector % SD_SECTOR_SIZE;\r
- if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;\r
+ // We're transferring over the SCSI bus faster than the SD card\r
+ // can write. All data is buffered, and we're just waiting for\r
+ // the SD card to complete. The host won't let us disconnect.\r
+ // Some drivers set a 250ms timeout on transfers to complete.\r
+ // SD card writes are supposed to complete\r
+ // within 200ms, but sometimes they don't.\r
+ // Just pretend we're finished.\r
+ process_Status();\r
+ clearBSY = process_MessageIn(0); // Will go to BUS_FREE state but keep BSY asserted.\r
}\r
- scsiReadDMA(&scsiDev.data[SD_SECTOR_SIZE * (prep % buffers)], dmaBytes);\r
- scsiActive = 1;\r
- }\r
- else if (\r
- (scsiDev.boardCfg.flags & CONFIG_ENABLE_DISCONNECT) &&\r
- (scsiActive == 0) &&\r
- likely(!scsiDisconnected) &&\r
- unlikely(scsiDev.discPriv) &&\r
- unlikely(diffTime_ms(lastActivityTime, now) >= 20) &&\r
- likely(scsiDev.phase == DATA_OUT))\r
- {\r
- // We're transferring over the SCSI bus faster than the SD card\r
- // can write. There is no more buffer space once we've finished\r
- // this SCSI transfer.\r
- // The NCR 53C700 interface chips have a 250ms "byte-to-byte"\r
- // timeout buffer. SD card writes are supposed to complete\r
- // within 200ms, but sometimes they don't.\r
- // The NCR 53C700 series is used on HP 9000 workstations.\r
- scsiDisconnect();\r
- scsiDisconnected = 1;\r
- lastActivityTime = getTime_ms();\r
+\r
+ HAL_SD_CheckWriteOperation(&hsd, (uint32_t)SD_DATATIMEOUT);\r
+\r
+ if (underrun)\r
+ {\r
+ // Try again. Data is still in memory.\r
+ sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors);\r
+ scsiDev.sdUnderrunCount++;\r
+ }\r
+ i += sectors;\r
+\r
}\r
- else if (unlikely(scsiDisconnected) &&\r
- (\r
- (prep == i) || // Buffers empty.\r
- // Send some messages every 100ms so we don't timeout.\r
- // At a minimum, a reselection involves an IDENTIFY message.\r
- unlikely(diffTime_ms(lastActivityTime, now) >= 100)\r
- ))\r
+ else\r
{\r
- int reconnected = scsiReconnect();\r
- if (reconnected)\r
+ // Well, until we have some proper non-blocking SD code, we must\r
+ // do this in a half-duplex fashion. We need to write as much as\r
+ // possible in each SD card transaction.\r
+ // use sg_dd from sg_utils3 tools to test.\r
+ uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;\r
+ uint32_t rem = totalSDSectors - i;\r
+ uint32_t sectors = rem < maxSectors ? rem : maxSectors;\r
+ int scsiSector;\r
+ for (scsiSector = i; scsiSector < i + sectors; ++scsiSector)\r
{\r
- scsiDisconnected = 0;\r
- lastActivityTime = getTime_ms(); // Don't disconnect immediately.\r
+ int dmaBytes = SD_SECTOR_SIZE;\r
+ if ((scsiSector % sdPerScsi) == (sdPerScsi - 1))\r
+ {\r
+ dmaBytes = bytesPerSector % SD_SECTOR_SIZE;\r
+ if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;\r
+ }\r
+ scsiRead(&scsiDev.data[SD_SECTOR_SIZE * (scsiSector - i)], dmaBytes, &parityError);\r
}\r
- else if (diffTime_ms(lastActivityTime, getTime_ms()) >= 10000)\r
+ if (!parityError)\r
{\r
- // Give up after 10 seconds of trying to reconnect.\r
- scsiDev.resetFlag = 1;\r
+ sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors);\r
}\r
+ i += sectors;\r
}\r
- else if (\r
- likely(!scsiComplete) &&\r
- (sdActive == 1) &&\r
- (prep == totalSDSectors) && // All scsi data read and buffered\r
- likely(!scsiDev.discPriv) && // Prefer disconnect where possible.\r
- unlikely(diffTime_ms(lastActivityTime, now) >= 150) &&\r
-\r
- likely(scsiDev.phase == DATA_OUT) &&\r
- !(scsiDev.cdb[scsiDev.cdbLen - 1] & 0x01) // Not linked command\r
- )\r
- {\r
- // We're transferring over the SCSI bus faster than the SD card\r
- // can write. All data is buffered, and we're just waiting for\r
- // the SD card to complete. The host won't let us disconnect.\r
- // Some drivers set a 250ms timeout on transfers to complete.\r
- // SD card writes are supposed to complete\r
- // within 200ms, but sometimes they don'to.\r
- // Just pretend we're finished.\r
- scsiComplete = 1;\r
-\r
- process_Status();\r
- process_MessageIn(); // Will go to BUS_FREE state\r
-\r
- // Try and prevent anyone else using the SCSI bus while we're not ready.\r
- SCSI_SetPin(SCSI_Out_BSY); \r
- }\r
-#endif\r
}\r
\r
if (clearBSY)\r
{\r
- *SCSI_CTRL_BSY = 0;\r
- }\r
-\r
-#if 0\r
- if (scsiComplete)\r
- {\r
- SCSI_ClearPin(SCSI_Out_BSY);\r
- }\r
- while (\r
- !scsiDev.resetFlag &&\r
- unlikely(scsiDisconnected) &&\r
- (s2s_elapsedTime_ms(lastActivityTime) <= 10000))\r
- {\r
- scsiDisconnected = !scsiReconnect();\r
- }\r
- if (scsiDisconnected)\r
- {\r
- // Failed to reconnect\r
- scsiDev.resetFlag = 1;\r
+ enter_BusFree();\r
}\r
-#endif\r
\r
if (scsiDev.phase == DATA_OUT)\r
{\r