|
|
@@ -38,6 +38,8 @@
|
|
|
#include "time.h"
|
|
|
#include "bsp.h"
|
|
|
|
|
|
+#include "led.h"
|
|
|
+
|
|
|
#include <string.h>
|
|
|
|
|
|
// Global
|
|
|
@@ -216,15 +218,6 @@ static void doWrite(uint32_t lba, uint32_t blocks)
|
|
|
// No need for single-block writes atm. Overhead of the
|
|
|
// multi-block write is minimal.
|
|
|
transfer.multiBlock = 1;
|
|
|
-
|
|
|
-
|
|
|
- // TODO uint32_t sdLBA =
|
|
|
-// TODO SCSISector2SD(
|
|
|
- // TODO scsiDev.target->cfg->sdSectorStart,
|
|
|
- // TODO bytesPerSector,
|
|
|
- // TODO lba);
|
|
|
- // TODO uint32_t sdBlocks = blocks * SDSectorsPerSCSISector(bytesPerSector);
|
|
|
- // TODO sdWriteMultiSectorPrep(sdLBA, sdBlocks);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -303,7 +296,15 @@ static void doSeek(uint32_t lba)
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- s2s_delay_ms(10);
|
|
|
+ if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB) ||
|
|
|
+ scsiDev.compatMode < COMPAT_SCSI2)
|
|
|
+ {
|
|
|
+ s2s_delay_ms(10);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ s2s_delay_ms(1);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -558,411 +559,626 @@ int scsiDiskCommand()
|
|
|
return commandHandled;
|
|
|
}
|
|
|
|
|
|
-void scsiDiskPoll()
|
|
|
+static void diskDataInBuffered(int totalSDSectors, uint32_t sdLBA, int useSlowDataCount, uint32_t* phaseChangeDelayNs)
|
|
|
{
|
|
|
uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
|
|
|
|
|
|
- if (scsiDev.phase == DATA_IN &&
|
|
|
- transfer.currentBlock != transfer.blocks)
|
|
|
- {
|
|
|
- // Take responsibility for waiting for the phase delays
|
|
|
- uint32_t phaseChangeDelayUs = scsiEnterPhaseImmediate(DATA_IN);
|
|
|
-
|
|
|
- int totalSDSectors =
|
|
|
- transfer.blocks * SDSectorsPerSCSISector(bytesPerSector);
|
|
|
- uint32_t sdLBA =
|
|
|
- SCSISector2SD(
|
|
|
- scsiDev.target->cfg->sdSectorStart,
|
|
|
- bytesPerSector,
|
|
|
- transfer.lba);
|
|
|
+ const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
|
|
|
+ const int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
|
|
|
+ int prep = 0;
|
|
|
+ int i = 0;
|
|
|
+ int scsiActive __attribute__((unused)) = 0; // unused if DMA disabled
|
|
|
+ int sdActive = 0;
|
|
|
|
|
|
- const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
|
|
|
- const int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
|
|
|
- int prep = 0;
|
|
|
- int i = 0;
|
|
|
- int scsiActive __attribute__((unused)) = 0; // unused if DMA disabled
|
|
|
- int sdActive = 0;
|
|
|
+ int gotHalf = 0;
|
|
|
+ int sentHalf = 0;
|
|
|
|
|
|
- // It's highly unlikely that someone is going to use huge transfers
|
|
|
- // per scsi command, but if they do it'll be slower than usual.
|
|
|
- uint32_t totalScsiBytes = transfer.blocks * bytesPerSector;
|
|
|
- int useSlowDataCount = totalScsiBytes >= SCSI_XFER_MAX;
|
|
|
- if (!useSlowDataCount)
|
|
|
+ while ((i < totalSDSectors) &&
|
|
|
+ likely(scsiDev.phase == DATA_IN) &&
|
|
|
+ likely(!scsiDev.resetFlag))
|
|
|
+ {
|
|
|
+ int completedDmaSectors;
|
|
|
+ if (sdActive && (completedDmaSectors = sdReadDMAPoll(sdActive)))
|
|
|
{
|
|
|
- scsiSetDataCount(totalScsiBytes);
|
|
|
+ prep += completedDmaSectors;
|
|
|
+ sdActive -= completedDmaSectors;
|
|
|
+ gotHalf = 0;
|
|
|
}
|
|
|
-
|
|
|
- while ((i < totalSDSectors) &&
|
|
|
- likely(scsiDev.phase == DATA_IN) &&
|
|
|
- likely(!scsiDev.resetFlag))
|
|
|
+ else if (sdActive > 1)
|
|
|
{
|
|
|
- int completedDmaSectors;
|
|
|
- if (sdActive && (completedDmaSectors = sdReadDMAPoll(sdActive)))
|
|
|
+ if ((scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 510] != 0xAA) ||
|
|
|
+ (scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 511] != 0x33))
|
|
|
{
|
|
|
- prep += completedDmaSectors;
|
|
|
- sdActive -= completedDmaSectors;
|
|
|
- } else if (sdActive > 1)
|
|
|
+ prep += 1;
|
|
|
+ sdActive -= 1;
|
|
|
+ gotHalf = 0;
|
|
|
+ }
|
|
|
+ else if (scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 127] != 0xAA)
|
|
|
{
|
|
|
- if ((scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 510] != 0xAA) ||
|
|
|
- (scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 511] != 0x33))
|
|
|
- {
|
|
|
- prep += 1;
|
|
|
- sdActive -= 1;
|
|
|
- }
|
|
|
+ // Half-block
|
|
|
+ gotHalf = 1;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if (!sdActive &&
|
|
|
- (prep - i < buffers) &&
|
|
|
- (prep < totalSDSectors) &&
|
|
|
- ((totalSDSectors - prep) >= sdPerScsi) &&
|
|
|
- (likely(!useSlowDataCount) || scsiPhyComplete()) &&
|
|
|
- (HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY)) // rx complete but IRQ not fired yet.
|
|
|
- {
|
|
|
- // Start an SD transfer if we have space.
|
|
|
- uint32_t startBuffer = prep % buffers;
|
|
|
- uint32_t sectors = totalSDSectors - prep;
|
|
|
- uint32_t freeBuffers = buffers - (prep - i);
|
|
|
+ if (!sdActive &&
|
|
|
+ (prep - i < buffers) &&
|
|
|
+ (prep < totalSDSectors) &&
|
|
|
+ ((totalSDSectors - prep) >= sdPerScsi) &&
|
|
|
+ (likely(!useSlowDataCount) || scsiPhyComplete()) &&
|
|
|
+ (HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY)) // rx complete but IRQ not fired yet.
|
|
|
+ {
|
|
|
+ // Start an SD transfer if we have space.
|
|
|
+ uint32_t startBuffer = prep % buffers;
|
|
|
+ uint32_t sectors = totalSDSectors - prep;
|
|
|
+ uint32_t freeBuffers = buffers - (prep - i);
|
|
|
|
|
|
- uint32_t contiguousBuffers = buffers - startBuffer;
|
|
|
- freeBuffers = freeBuffers < contiguousBuffers
|
|
|
- ? freeBuffers : contiguousBuffers;
|
|
|
- sectors = sectors < freeBuffers ? sectors : freeBuffers;
|
|
|
+ uint32_t contiguousBuffers = buffers - startBuffer;
|
|
|
+ freeBuffers = freeBuffers < contiguousBuffers
|
|
|
+ ? freeBuffers : contiguousBuffers;
|
|
|
+ sectors = sectors < freeBuffers ? sectors : freeBuffers;
|
|
|
|
|
|
- if (sectors > 128) sectors = 128; // 65536 DMA limit !!
|
|
|
+ if (sectors > 128) sectors = 128; // 65536 DMA limit !!
|
|
|
|
|
|
- // Round-down when we have odd sector sizes.
|
|
|
- if (sdPerScsi != 1)
|
|
|
- {
|
|
|
- sectors = (sectors / sdPerScsi) * sdPerScsi;
|
|
|
- }
|
|
|
+ // Round-down when we have odd sector sizes.
|
|
|
+ if (sdPerScsi != 1)
|
|
|
+ {
|
|
|
+ sectors = (sectors / sdPerScsi) * sdPerScsi;
|
|
|
+ }
|
|
|
|
|
|
- for (int dodgy = 0; dodgy < sectors; dodgy++)
|
|
|
- {
|
|
|
- scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 510] = 0xAA;
|
|
|
- scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 511] = 0x33;
|
|
|
- }
|
|
|
+ for (int dodgy = 0; dodgy < sectors; dodgy++)
|
|
|
+ {
|
|
|
+ scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 127] = 0xAA;
|
|
|
|
|
|
- sdReadDMA(sdLBA + prep, sectors, &scsiDev.data[SD_SECTOR_SIZE * startBuffer]);
|
|
|
+ scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 510] = 0xAA;
|
|
|
+ scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 511] = 0x33;
|
|
|
+ }
|
|
|
|
|
|
- sdActive = sectors;
|
|
|
+ sdReadDMA(sdLBA + prep, sectors, &scsiDev.data[SD_SECTOR_SIZE * startBuffer]);
|
|
|
|
|
|
- if (useSlowDataCount)
|
|
|
- {
|
|
|
- scsiSetDataCount((sectors / sdPerScsi) * bytesPerSector);
|
|
|
- }
|
|
|
+ sdActive = sectors;
|
|
|
|
|
|
- // Wait now that the SD card is busy
|
|
|
- // Chances are we've probably already waited sufficient time,
|
|
|
- // but it's hard to measure microseconds cheaply. So just wait
|
|
|
- // extra just-in-case. Hopefully it's in parallel with dma.
|
|
|
- if (phaseChangeDelayUs > 0)
|
|
|
- {
|
|
|
- s2s_delay_us(phaseChangeDelayUs);
|
|
|
- phaseChangeDelayUs = 0;
|
|
|
- }
|
|
|
+ if (useSlowDataCount)
|
|
|
+ {
|
|
|
+ scsiSetDataCount((sectors / sdPerScsi) * bytesPerSector);
|
|
|
}
|
|
|
|
|
|
- if (((prep - i) > 0) &&
|
|
|
- scsiFifoReady())
|
|
|
+ // Wait now that the SD card is busy
|
|
|
+ // Chances are we've probably already waited sufficient time,
|
|
|
+ // but it's hard to measure microseconds cheaply. So just wait
|
|
|
+ // extra just-in-case. Hopefully it's in parallel with dma.
|
|
|
+ if (*phaseChangeDelayNs > 0)
|
|
|
{
|
|
|
- int dmaBytes = SD_SECTOR_SIZE;
|
|
|
- if ((i % sdPerScsi) == (sdPerScsi - 1))
|
|
|
- {
|
|
|
- dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
|
|
|
- if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
|
|
|
- }
|
|
|
+ s2s_delay_ns(*phaseChangeDelayNs);
|
|
|
+ *phaseChangeDelayNs = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int fifoReady = scsiFifoReady();
|
|
|
+ if (((prep - i) > 0) && fifoReady)
|
|
|
+ {
|
|
|
+ int dmaBytes = SD_SECTOR_SIZE;
|
|
|
+ if ((i % sdPerScsi) == (sdPerScsi - 1))
|
|
|
+ {
|
|
|
+ dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
|
|
|
+ if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
|
|
|
+ }
|
|
|
|
|
|
- uint8_t* scsiDmaData = &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);
|
|
|
- scsiWritePIO(scsiDmaData, dmaBytes);
|
|
|
+ uint8_t* scsiDmaData = &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);
|
|
|
|
|
|
- ++i;
|
|
|
+ if (sentHalf)
|
|
|
+ {
|
|
|
+ scsiDmaData += SD_SECTOR_SIZE / 2;
|
|
|
+ dmaBytes -= (SD_SECTOR_SIZE / 2);
|
|
|
}
|
|
|
- }
|
|
|
+ scsiWritePIO(scsiDmaData, dmaBytes);
|
|
|
|
|
|
- if (phaseChangeDelayUs > 0 && !scsiDev.resetFlag) // zero bytes ?
|
|
|
+ ++i;
|
|
|
+ sentHalf = 0;
|
|
|
+ gotHalf = 0;
|
|
|
+ }
|
|
|
+ else if (gotHalf && !sentHalf && fifoReady && bytesPerSector == SD_SECTOR_SIZE)
|
|
|
{
|
|
|
- s2s_delay_us(phaseChangeDelayUs);
|
|
|
- phaseChangeDelayUs = 0;
|
|
|
+ uint8_t* scsiDmaData = &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);
|
|
|
+ scsiWritePIO(scsiDmaData, SD_SECTOR_SIZE / 2);
|
|
|
+ sentHalf = 1;
|
|
|
}
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- if (scsiDev.resetFlag)
|
|
|
+// Transfer from the SD card straight to the SCSI Fifo without storing in memory first for lower latency
|
|
|
+// This requires hardware flow control on the SD device (broken on stm32f205)
|
|
|
+// Only functional for 512 byte sectors.
|
|
|
+static void diskDataInDirect(uint32_t totalSDSectors, uint32_t sdLBA, int useSlowDataCount, uint32_t* phaseChangeDelayNs)
|
|
|
+{
|
|
|
+ sdReadPIO(sdLBA, totalSDSectors);
|
|
|
+
|
|
|
+ // Wait while the SD card starts buffering data
|
|
|
+ if (*phaseChangeDelayNs > 0)
|
|
|
+ {
|
|
|
+ s2s_delay_ns(*phaseChangeDelayNs);
|
|
|
+ *phaseChangeDelayNs = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < totalSDSectors && !scsiDev.resetFlag; ++i)
|
|
|
+ {
|
|
|
+ // TODO if i %128 == 0, and not in an error state, then do another read.
|
|
|
+
|
|
|
+ if (useSlowDataCount)
|
|
|
{
|
|
|
- HAL_SD_Abort(&hsd);
|
|
|
+ scsiSetDataCount(SD_SECTOR_SIZE);
|
|
|
}
|
|
|
- else
|
|
|
+
|
|
|
+ // The SCSI fifo is a full sector so we only need to check once.
|
|
|
+ while (!scsiFifoReady() && !scsiDev.resetFlag)
|
|
|
+ {}
|
|
|
+
|
|
|
+ int byteCount = 0;
|
|
|
+ while(byteCount < SD_SECTOR_SIZE &&
|
|
|
+ likely(!scsiDev.resetFlag) &&
|
|
|
+ likely(scsiDev.phase == DATA_IN) &&
|
|
|
+ !__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT))
|
|
|
{
|
|
|
- // Wait for the SD transfer to complete before we disable IRQs.
|
|
|
- // (Otherwise some cards will cause an error if we don't sent the
|
|
|
- // stop transfer command via the DMA complete handler in time)
|
|
|
- while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY)
|
|
|
+ if(__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_RXFIFOHF))
|
|
|
{
|
|
|
- // Wait while keeping BSY.
|
|
|
+ // The SDIO fifo is 32 x 32bits. As we're using the "half full" flag we must
|
|
|
+ // always read half the FIFO.
|
|
|
+
|
|
|
+ for (int j = 0; j < 4; ++j)
|
|
|
+ {
|
|
|
+ uint32_t data[4];
|
|
|
+ data[0] = SDIO_ReadFIFO(hsd.Instance);
|
|
|
+ data[1] = SDIO_ReadFIFO(hsd.Instance);
|
|
|
+ data[2] = SDIO_ReadFIFO(hsd.Instance);
|
|
|
+ data[3] = SDIO_ReadFIFO(hsd.Instance);
|
|
|
+
|
|
|
+ *((volatile uint32_t*)SCSI_FIFO_DATA) = data[0];
|
|
|
+ *((volatile uint32_t*)SCSI_FIFO_DATA) = data[1];
|
|
|
+ *((volatile uint32_t*)SCSI_FIFO_DATA) = data[2];
|
|
|
+ *((volatile uint32_t*)SCSI_FIFO_DATA) = data[3];
|
|
|
+
|
|
|
+ /*
|
|
|
+ scsiPhyTx32(data[0] & 0xFFFF, data[0] >> 16);
|
|
|
+ scsiPhyTx32(data[1] & 0xFFFF, data[1] >> 16);
|
|
|
+ scsiPhyTx32(data[2] & 0xFFFF, data[2] >> 16);
|
|
|
+ scsiPhyTx32(data[3] & 0xFFFF, data[3] >> 16);
|
|
|
+ */
|
|
|
+ }
|
|
|
+
|
|
|
+ byteCount += 64;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd);
|
|
|
- while (cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_SENDING)
|
|
|
+ int error = 0;
|
|
|
+ if (__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_DTIMEOUT))
|
|
|
{
|
|
|
- cardState = HAL_SD_GetCardState(&hsd);
|
|
|
- }
|
|
|
+ __HAL_SD_CLEAR_FLAG(&hsd, SDIO_FLAG_DTIMEOUT);
|
|
|
+ error = 1;
|
|
|
+ }
|
|
|
+ else if (__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_DCRCFAIL))
|
|
|
+ {
|
|
|
+ __HAL_SD_CLEAR_FLAG(&hsd, SDIO_FLAG_DCRCFAIL);
|
|
|
+ error = 1;
|
|
|
+ }
|
|
|
+ else if (__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_RXOVERR))
|
|
|
+ {
|
|
|
+ __HAL_SD_CLEAR_FLAG(&hsd, SDIO_FLAG_RXOVERR);
|
|
|
+ error = 1;
|
|
|
+ }
|
|
|
|
|
|
- // We've finished transferring the data to the FPGA, now wait until it's
|
|
|
- // written to he SCSI bus.
|
|
|
- while (!scsiPhyComplete() &&
|
|
|
- likely(scsiDev.phase == DATA_IN) &&
|
|
|
+ if (error && scsiDev.phase == DATA_IN)
|
|
|
+ {
|
|
|
+ __HAL_SD_CLEAR_FLAG(&hsd, SDIO_STATIC_FLAGS);
|
|
|
+
|
|
|
+ scsiDiskReset();
|
|
|
+
|
|
|
+ scsiDev.status = CHECK_CONDITION;
|
|
|
+ scsiDev.target->sense.code = HARDWARE_ERROR;
|
|
|
+ scsiDev.target->sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;
|
|
|
+ scsiDev.phase = STATUS;
|
|
|
+ }
|
|
|
+
|
|
|
+ // We need the SCSI FIFO count to complete even after the SD read has failed
|
|
|
+ while (byteCount < SD_SECTOR_SIZE &&
|
|
|
likely(!scsiDev.resetFlag))
|
|
|
{
|
|
|
- __disable_irq();
|
|
|
- if (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
|
|
|
- {
|
|
|
- __WFI();
|
|
|
- }
|
|
|
- __enable_irq();
|
|
|
+ scsiPhyTx32(0, 0);
|
|
|
+ byteCount += 4;
|
|
|
}
|
|
|
|
|
|
- if (scsiDev.phase == DATA_IN)
|
|
|
+ while (useSlowDataCount && !scsiDev.resetFlag && !scsiPhyComplete())
|
|
|
{
|
|
|
- scsiDev.phase = STATUS;
|
|
|
}
|
|
|
- scsiDiskReset();
|
|
|
}
|
|
|
- else if (scsiDev.phase == DATA_OUT &&
|
|
|
- transfer.currentBlock != transfer.blocks)
|
|
|
+
|
|
|
+//while(1) { s2s_ledOn(); s2s_delay_ms(1000); s2s_ledOff(); s2s_delay_ms(1000); }
|
|
|
+
|
|
|
+ /* Send stop transmission command in case of multiblock read */
|
|
|
+ if(totalSDSectors > 1U)
|
|
|
{
|
|
|
- scsiEnterPhase(DATA_OUT);
|
|
|
+ SDMMC_CmdStopTransfer(hsd.Instance);
|
|
|
+ }
|
|
|
|
|
|
- const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
|
|
|
- int totalSDSectors = transfer.blocks * sdPerScsi;
|
|
|
- uint32_t sdLBA =
|
|
|
- SCSISector2SD(
|
|
|
- scsiDev.target->cfg->sdSectorStart,
|
|
|
- bytesPerSector,
|
|
|
- transfer.lba);
|
|
|
- int i = 0;
|
|
|
- int clearBSY = 0;
|
|
|
- int disconnected = 0;
|
|
|
+ // Read remaining data
|
|
|
+ uint32_t extraCount = SD_DATATIMEOUT;
|
|
|
+ while ((__HAL_SD_GET_FLAG(&hsd, SDIO_FLAG_RXDAVL)) && (extraCount > 0))
|
|
|
+ {
|
|
|
+ SDIO_ReadFIFO(hsd.Instance);
|
|
|
+ extraCount--;
|
|
|
+ }
|
|
|
|
|
|
- int parityError = 0;
|
|
|
- int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;
|
|
|
+ __HAL_SD_CLEAR_FLAG(&hsd, SDIO_STATIC_DATA_FLAGS);
|
|
|
+ hsd.State = HAL_SD_STATE_READY;
|
|
|
+
|
|
|
+ sdCompleteTransfer(); // Probably overkill
|
|
|
+}
|
|
|
|
|
|
- uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
|
|
|
+static void diskDataIn()
|
|
|
+{
|
|
|
+ uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
|
|
|
+
|
|
|
+ // Take responsibility for waiting for the phase delays
|
|
|
+ uint32_t phaseChangeDelayNs = scsiEnterPhaseImmediate(DATA_IN);
|
|
|
+
|
|
|
+ int totalSDSectors =
|
|
|
+ transfer.blocks * SDSectorsPerSCSISector(bytesPerSector);
|
|
|
+ uint32_t sdLBA =
|
|
|
+ SCSISector2SD(
|
|
|
+ scsiDev.target->cfg->sdSectorStart,
|
|
|
+ bytesPerSector,
|
|
|
+ transfer.lba);
|
|
|
+
|
|
|
+ // It's highly unlikely that someone is going to use huge transfers
|
|
|
+ // per scsi command, but if they do it'll be slower than usual.
|
|
|
+ uint32_t totalScsiBytes = transfer.blocks * bytesPerSector;
|
|
|
+ int useSlowDataCount = totalScsiBytes >= SCSI_XFER_MAX;
|
|
|
+ if (!useSlowDataCount)
|
|
|
+ {
|
|
|
+ scsiSetDataCount(totalScsiBytes);
|
|
|
+ }
|
|
|
|
|
|
- static_assert(SCSI_XFER_MAX >= sizeof(scsiDev.data), "Assumes SCSI_XFER_MAX >= sizeof(scsiDev.data)");
|
|
|
+#ifdef STM32F4xx
|
|
|
+ // Direct mode requires hardware flow control to be working on the SD peripheral
|
|
|
+ if (bytesPerSector == SD_SECTOR_SIZE && totalSDSectors < 128)
|
|
|
+ {
|
|
|
+ diskDataInDirect(totalSDSectors, sdLBA, useSlowDataCount, &phaseChangeDelayNs);
|
|
|
+ }
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ diskDataInBuffered(totalSDSectors, sdLBA, useSlowDataCount, &phaseChangeDelayNs);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (phaseChangeDelayNs > 0 && !scsiDev.resetFlag) // zero bytes ?
|
|
|
+ {
|
|
|
+ s2s_delay_ns(phaseChangeDelayNs);
|
|
|
+ phaseChangeDelayNs = 0;
|
|
|
+ }
|
|
|
|
|
|
- // Start reading and filling fifos as soon as possible.
|
|
|
- // It's highly unlikely that someone is going to use huge transfers
|
|
|
- // per scsi command, but if they do it'll be slower than usual.
|
|
|
- // Note: Happens in Macintosh FWB HDD Toolkit benchmarks which default
|
|
|
- // to 768kb
|
|
|
- uint32_t totalTransferBytes = transfer.blocks * bytesPerSector;
|
|
|
- int useSlowDataCount = totalTransferBytes >= SCSI_XFER_MAX;
|
|
|
- if (!useSlowDataCount)
|
|
|
+ if (scsiDev.resetFlag)
|
|
|
+ {
|
|
|
+ HAL_SD_Abort(&hsd);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Wait for the SD transfer to complete before we disable IRQs.
|
|
|
+ // (Otherwise some cards will cause an error if we don't sent the
|
|
|
+ // stop transfer command via the DMA complete handler in time)
|
|
|
+ while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY)
|
|
|
{
|
|
|
- DWT->CYCCNT = 0; // Start counting cycles
|
|
|
- scsiSetDataCount(totalTransferBytes);
|
|
|
+ // Wait while keeping BSY.
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- int lastWriteSize = 0;
|
|
|
+ HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd);
|
|
|
+ while (cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_SENDING)
|
|
|
+ {
|
|
|
+ cardState = HAL_SD_GetCardState(&hsd);
|
|
|
+ }
|
|
|
|
|
|
- while ((i < totalSDSectors) &&
|
|
|
- likely(scsiDev.phase == DATA_OUT) &&
|
|
|
- likely(!scsiDev.resetFlag))
|
|
|
- // KEEP GOING to ensure FIFOs are in a good state.
|
|
|
- // likely(!parityError || !enableParity))
|
|
|
+ // We've finished transferring the data to the FPGA, now wait until it's
|
|
|
+ // written to he SCSI bus.
|
|
|
+ while (!scsiPhyComplete() &&
|
|
|
+ likely(scsiDev.phase == DATA_IN) &&
|
|
|
+ likely(!scsiDev.resetFlag))
|
|
|
+ {
|
|
|
+ __disable_irq();
|
|
|
+ if (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
|
|
|
{
|
|
|
- if (bytesPerSector == SD_SECTOR_SIZE)
|
|
|
- {
|
|
|
- uint32_t maxXferSectors = SCSI_XFER_MAX / SD_SECTOR_SIZE;
|
|
|
- uint32_t rem = totalSDSectors - i;
|
|
|
- uint32_t sectors = rem < maxXferSectors ? rem : maxXferSectors;
|
|
|
+ __WFI();
|
|
|
+ }
|
|
|
+ __enable_irq();
|
|
|
+ }
|
|
|
|
|
|
- uint32_t totalBytes = sectors * SD_SECTOR_SIZE;
|
|
|
+ if (scsiDev.phase == DATA_IN)
|
|
|
+ {
|
|
|
+ scsiDev.phase = STATUS;
|
|
|
+ }
|
|
|
+ scsiDiskReset();
|
|
|
+}
|
|
|
|
|
|
- if (useSlowDataCount)
|
|
|
- {
|
|
|
- scsiSetDataCount(totalBytes);
|
|
|
- }
|
|
|
+void diskDataOut_512(int totalSDSectors, uint32_t sdLBA, int useSlowDataCount, int* clearBSY, int* parityError)
|
|
|
+{
|
|
|
+ int i = 0;
|
|
|
+ int disconnected = 0;
|
|
|
|
|
|
- lastWriteSize = sectors;
|
|
|
- HAL_SD_WriteBlocks_DMA(&hsd, i + sdLBA, sectors);
|
|
|
- int j = 0;
|
|
|
- int prep = 0;
|
|
|
- int sdActive = 0;
|
|
|
- uint32_t dmaFinishTime = 0;
|
|
|
- while (j < sectors && !scsiDev.resetFlag)
|
|
|
- {
|
|
|
- if (sdActive &&
|
|
|
- HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY &&
|
|
|
- !sdIsBusy())
|
|
|
- {
|
|
|
- j += sdActive;
|
|
|
- sdActive = 0;
|
|
|
- }
|
|
|
- if (!sdActive && ((prep - j) > 0))
|
|
|
- {
|
|
|
- // Start an SD transfer if we have space.
|
|
|
- HAL_SD_WriteBlocks_Data(&hsd, &scsiDev.data[SD_SECTOR_SIZE * (j % maxSectors)]);
|
|
|
-
|
|
|
- sdActive = 1;
|
|
|
- }
|
|
|
-
|
|
|
- if (((prep - j) < maxSectors) &&
|
|
|
- (prep < sectors) &&
|
|
|
- scsiFifoReady())
|
|
|
- {
|
|
|
- scsiReadPIO(
|
|
|
- &scsiDev.data[(prep % maxSectors) * SD_SECTOR_SIZE],
|
|
|
- SD_SECTOR_SIZE,
|
|
|
- &parityError);
|
|
|
- prep++;
|
|
|
- if (prep == sectors)
|
|
|
- {
|
|
|
- dmaFinishTime = s2s_getTime_ms();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (i + prep >= totalSDSectors &&
|
|
|
- !disconnected &&
|
|
|
- (!parityError || !enableParity) &&
|
|
|
- s2s_elapsedTime_ms(dmaFinishTime) >= 180)
|
|
|
- {
|
|
|
- // We're transferring over the SCSI bus faster than the SD card
|
|
|
- // can write. All data is buffered, and we're just waiting for
|
|
|
- // the SD card to complete. The host won't let us disconnect.
|
|
|
- // Some drivers set a 250ms timeout on transfers to complete.
|
|
|
- // SD card writes are supposed to complete
|
|
|
- // within 200ms, but sometimes they don't.
|
|
|
- // Just pretend we're finished.
|
|
|
- process_Status();
|
|
|
- clearBSY = process_MessageIn(0); // Will go to BUS_FREE state but keep BSY asserted.
|
|
|
- disconnected = 1;
|
|
|
- }
|
|
|
- }
|
|
|
+ int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;
|
|
|
|
|
|
- if (scsiDev.resetFlag)
|
|
|
- {
|
|
|
- HAL_SD_Abort(&hsd);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY) {} // Waits for DMA to complete
|
|
|
- if (lastWriteSize > 1)
|
|
|
- {
|
|
|
- SDMMC_CmdStopTransfer(hsd.Instance);
|
|
|
- }
|
|
|
- }
|
|
|
+ uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
|
|
|
|
|
|
- while (sdIsBusy() &&
|
|
|
- s2s_elapsedTime_ms(dmaFinishTime) < 180)
|
|
|
- {
|
|
|
- // Wait while the SD card is writing buffer to flash
|
|
|
- // The card may remain in the RECEIVING state (even though it's programming) if
|
|
|
- // it has buffer space to receive more data available.
|
|
|
- }
|
|
|
+ int lastWriteSize = 0;
|
|
|
|
|
|
- if (!disconnected &&
|
|
|
- i + sectors >= totalSDSectors &&
|
|
|
- (!parityError || !enableParity))
|
|
|
- {
|
|
|
- // We're transferring over the SCSI bus faster than the SD card
|
|
|
- // can write. All data is buffered, and we're just waiting for
|
|
|
- // the SD card to complete. The host won't let us disconnect.
|
|
|
- // Some drivers set a 250ms timeout on transfers to complete.
|
|
|
- // SD card writes are supposed to complete
|
|
|
- // within 200ms, but sometimes they don't.
|
|
|
- // Just pretend we're finished.
|
|
|
- process_Status();
|
|
|
- clearBSY = process_MessageIn(0); // Will go to BUS_FREE state but keep BSY asserted.
|
|
|
- }
|
|
|
+ while ((i < totalSDSectors) &&
|
|
|
+ likely(scsiDev.phase == DATA_OUT) &&
|
|
|
+ likely(!scsiDev.resetFlag))
|
|
|
+ // KEEP GOING to ensure FIFOs are in a good state.
|
|
|
+ // likely(!parityError || !enableParity))
|
|
|
+ {
|
|
|
|
|
|
- // Wait while the SD card is writing buffer to flash
|
|
|
- // The card may remain in the RECEIVING state (even though it's programming) if
|
|
|
- // it has buffer space to receive more data available.
|
|
|
- while (sdIsBusy()) {}
|
|
|
- HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd);
|
|
|
- while (cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_RECEIVING)
|
|
|
- {
|
|
|
- // Wait while the SD card is writing buffer to flash
|
|
|
- // The card may remain in the RECEIVING state (even though it's programming) if
|
|
|
- // it has buffer space to receive more data available.
|
|
|
- cardState = HAL_SD_GetCardState(&hsd);
|
|
|
- }
|
|
|
+ uint32_t maxXferSectors = SCSI_XFER_MAX / SD_SECTOR_SIZE;
|
|
|
+ uint32_t rem = totalSDSectors - i;
|
|
|
+ uint32_t sectors = rem < maxXferSectors ? rem : maxXferSectors;
|
|
|
+
|
|
|
+ uint32_t totalBytes = sectors * SD_SECTOR_SIZE;
|
|
|
+
|
|
|
+ if (useSlowDataCount)
|
|
|
+ {
|
|
|
+ scsiSetDataCount(totalBytes);
|
|
|
+ }
|
|
|
|
|
|
- i += sectors;
|
|
|
+ lastWriteSize = sectors;
|
|
|
+ HAL_SD_WriteBlocks_DMA(&hsd, i + sdLBA, sectors);
|
|
|
+ int j = 0;
|
|
|
+ int prep = 0;
|
|
|
+ int sdActive = 0;
|
|
|
+ uint32_t dmaFinishTime = 0;
|
|
|
+ while (j < sectors && !scsiDev.resetFlag)
|
|
|
+ {
|
|
|
+ if (sdActive &&
|
|
|
+ HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY &&
|
|
|
+ !sdIsBusy())
|
|
|
+ {
|
|
|
+ j += sdActive;
|
|
|
+ sdActive = 0;
|
|
|
}
|
|
|
- else
|
|
|
+ if (!sdActive && ((prep - j) > 0))
|
|
|
{
|
|
|
- // Well, until we have some proper non-blocking SD code, we must
|
|
|
- // do this in a half-duplex fashion. We need to write as much as
|
|
|
- // possible in each SD card transaction.
|
|
|
- // use sg_dd from sg_utils3 tools to test.
|
|
|
-
|
|
|
- uint32_t rem = totalSDSectors - i;
|
|
|
- uint32_t sectors;
|
|
|
- if (rem <= maxSectors)
|
|
|
- {
|
|
|
- sectors = rem;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- sectors = maxSectors;
|
|
|
- while (sectors % sdPerScsi) sectors--;
|
|
|
- }
|
|
|
-
|
|
|
+ // Start an SD transfer if we have space.
|
|
|
+ HAL_SD_WriteBlocks_Data(&hsd, &scsiDev.data[SD_SECTOR_SIZE * (j % maxSectors)]);
|
|
|
|
|
|
- if (useSlowDataCount)
|
|
|
- {
|
|
|
- scsiSetDataCount((sectors / sdPerScsi) * bytesPerSector);
|
|
|
- }
|
|
|
+ sdActive = 1;
|
|
|
+ }
|
|
|
|
|
|
- for (int scsiSector = i; scsiSector < i + sectors; ++scsiSector)
|
|
|
- {
|
|
|
- int dmaBytes = SD_SECTOR_SIZE;
|
|
|
- if ((scsiSector % sdPerScsi) == (sdPerScsi - 1))
|
|
|
- {
|
|
|
- dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
|
|
|
- if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
|
|
|
- }
|
|
|
-
|
|
|
- scsiReadPIO(&scsiDev.data[SD_SECTOR_SIZE * (scsiSector - i)], dmaBytes, &parityError);
|
|
|
- }
|
|
|
- if (!parityError || !enableParity)
|
|
|
+ if (((prep - j) < maxSectors) &&
|
|
|
+ (prep < sectors) &&
|
|
|
+ scsiFifoReady())
|
|
|
+ {
|
|
|
+ scsiReadPIO(
|
|
|
+ &scsiDev.data[(prep % maxSectors) * SD_SECTOR_SIZE],
|
|
|
+ SD_SECTOR_SIZE,
|
|
|
+ parityError);
|
|
|
+ prep++;
|
|
|
+ if (prep == sectors)
|
|
|
{
|
|
|
- BSP_SD_WriteBlocks_DMA(&scsiDev.data[0], i + sdLBA, sectors);
|
|
|
+ dmaFinishTime = s2s_getTime_ms();
|
|
|
}
|
|
|
- i += sectors;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i + prep >= totalSDSectors &&
|
|
|
+ !disconnected &&
|
|
|
+ (!(*parityError) || !enableParity) &&
|
|
|
+ s2s_elapsedTime_ms(dmaFinishTime) >= 180)
|
|
|
+ {
|
|
|
+ // We're transferring over the SCSI bus faster than the SD card
|
|
|
+ // can write. All data is buffered, and we're just waiting for
|
|
|
+ // the SD card to complete. The host won't let us disconnect.
|
|
|
+ // Some drivers set a 250ms timeout on transfers to complete.
|
|
|
+ // SD card writes are supposed to complete
|
|
|
+ // within 200ms, but sometimes they don't.
|
|
|
+ // Just pretend we're finished.
|
|
|
+ process_Status();
|
|
|
+ *clearBSY = process_MessageIn(0); // Will go to BUS_FREE state but keep BSY asserted.
|
|
|
+ disconnected = 1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Should already be complete here as we've ready the FIFOs
|
|
|
- // by now. Check anyway.
|
|
|
- __disable_irq();
|
|
|
- while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
|
|
|
+ if (scsiDev.resetFlag)
|
|
|
{
|
|
|
- __WFI();
|
|
|
+ HAL_SD_Abort(&hsd);
|
|
|
}
|
|
|
- __enable_irq();
|
|
|
+ else
|
|
|
+ {
|
|
|
+ while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY) {} // Waits for DMA to complete
|
|
|
+ if (lastWriteSize > 1)
|
|
|
+ {
|
|
|
+ SDMMC_CmdStopTransfer(hsd.Instance);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ while (sdIsBusy() &&
|
|
|
+ s2s_elapsedTime_ms(dmaFinishTime) < 180)
|
|
|
+ {
|
|
|
+ // Wait while the SD card is writing buffer to flash
|
|
|
+ // The card may remain in the RECEIVING state (even though it's programming) if
|
|
|
+ // it has buffer space to receive more data available.
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!disconnected &&
|
|
|
+ i + sectors >= totalSDSectors &&
|
|
|
+ (!parityError || !enableParity))
|
|
|
+ {
|
|
|
+ // We're transferring over the SCSI bus faster than the SD card
|
|
|
+ // can write. All data is buffered, and we're just waiting for
|
|
|
+ // the SD card to complete. The host won't let us disconnect.
|
|
|
+ // Some drivers set a 250ms timeout on transfers to complete.
|
|
|
+ // SD card writes are supposed to complete
|
|
|
+ // within 200ms, but sometimes they don't.
|
|
|
+ // Just pretend we're finished.
|
|
|
+ process_Status();
|
|
|
+ *clearBSY = process_MessageIn(0); // Will go to BUS_FREE state but keep BSY asserted.
|
|
|
+ }
|
|
|
+
|
|
|
+ // Wait while the SD card is writing buffer to flash
|
|
|
+ // The card may remain in the RECEIVING state (even though it's programming) if
|
|
|
+ // it has buffer space to receive more data available.
|
|
|
+ while (sdIsBusy()) {}
|
|
|
+ HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd);
|
|
|
+ while (cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_RECEIVING)
|
|
|
+ {
|
|
|
+ // Wait while the SD card is writing buffer to flash
|
|
|
+ // The card may remain in the RECEIVING state (even though it's programming) if
|
|
|
+ // it has buffer space to receive more data available.
|
|
|
+ cardState = HAL_SD_GetCardState(&hsd);
|
|
|
+ }
|
|
|
+
|
|
|
+ i += sectors;
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void diskDataOut_variableSectorSize(int sdPerScsi, int totalSDSectors, uint32_t sdLBA, int useSlowDataCount, int* parityError)
|
|
|
+{
|
|
|
+ uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
|
|
|
|
|
|
- if (clearBSY)
|
|
|
+ int i = 0;
|
|
|
+
|
|
|
+ int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;
|
|
|
+
|
|
|
+ uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
|
|
|
+
|
|
|
+ while ((i < totalSDSectors) &&
|
|
|
+ likely(scsiDev.phase == DATA_OUT) &&
|
|
|
+ likely(!scsiDev.resetFlag))
|
|
|
+ // KEEP GOING to ensure FIFOs are in a good state.
|
|
|
+ // likely(!parityError || !enableParity))
|
|
|
+ {
|
|
|
+ // Well, until we have some proper non-blocking SD code, we must
|
|
|
+ // do this in a half-duplex fashion. We need to write as much as
|
|
|
+ // possible in each SD card transaction.
|
|
|
+ // use sg_dd from sg_utils3 tools to test.
|
|
|
+
|
|
|
+ uint32_t rem = totalSDSectors - i;
|
|
|
+ uint32_t sectors;
|
|
|
+ if (rem <= maxSectors)
|
|
|
{
|
|
|
- enter_BusFree();
|
|
|
+ sectors = rem;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ sectors = maxSectors;
|
|
|
+ while (sectors % sdPerScsi) sectors--;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (useSlowDataCount)
|
|
|
+ {
|
|
|
+ scsiSetDataCount((sectors / sdPerScsi) * bytesPerSector);
|
|
|
}
|
|
|
|
|
|
- if (scsiDev.phase == DATA_OUT)
|
|
|
+ for (int scsiSector = i; scsiSector < i + sectors; ++scsiSector)
|
|
|
{
|
|
|
- if (parityError &&
|
|
|
- (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
|
|
|
+ int dmaBytes = SD_SECTOR_SIZE;
|
|
|
+ if ((scsiSector % sdPerScsi) == (sdPerScsi - 1))
|
|
|
{
|
|
|
- scsiDev.target->sense.code = ABORTED_COMMAND;
|
|
|
- scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
|
|
|
- scsiDev.status = CHECK_CONDITION;;
|
|
|
+ dmaBytes = bytesPerSector % SD_SECTOR_SIZE;
|
|
|
+ if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;
|
|
|
}
|
|
|
- scsiDev.phase = STATUS;
|
|
|
+
|
|
|
+ scsiReadPIO(&scsiDev.data[SD_SECTOR_SIZE * (scsiSector - i)], dmaBytes, parityError);
|
|
|
}
|
|
|
- scsiDiskReset();
|
|
|
+ if (!(*parityError) || !enableParity)
|
|
|
+ {
|
|
|
+ BSP_SD_WriteBlocks_DMA(&scsiDev.data[0], i + sdLBA, sectors);
|
|
|
+ }
|
|
|
+ i += sectors;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void diskDataOut()
|
|
|
+{
|
|
|
+ uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
|
|
|
+
|
|
|
+ scsiEnterPhase(DATA_OUT);
|
|
|
+
|
|
|
+ const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
|
|
|
+ int totalSDSectors = transfer.blocks * sdPerScsi;
|
|
|
+ uint32_t sdLBA =
|
|
|
+ SCSISector2SD(
|
|
|
+ scsiDev.target->cfg->sdSectorStart,
|
|
|
+ bytesPerSector,
|
|
|
+ transfer.lba);
|
|
|
+ int clearBSY = 0;
|
|
|
+
|
|
|
+ int parityError = 0;
|
|
|
+
|
|
|
+ static_assert(SCSI_XFER_MAX >= sizeof(scsiDev.data), "Assumes SCSI_XFER_MAX >= sizeof(scsiDev.data)");
|
|
|
+
|
|
|
+ // Start reading and filling fifos as soon as possible.
|
|
|
+ // It's highly unlikely that someone is going to use huge transfers
|
|
|
+ // per scsi command, but if they do it'll be slower than usual.
|
|
|
+ // Note: Happens in Macintosh FWB HDD Toolkit benchmarks which default
|
|
|
+ // to 768kb
|
|
|
+ uint32_t totalTransferBytes = transfer.blocks * bytesPerSector;
|
|
|
+ int useSlowDataCount = totalTransferBytes >= SCSI_XFER_MAX;
|
|
|
+ if (!useSlowDataCount)
|
|
|
+ {
|
|
|
+ DWT->CYCCNT = 0; // Start counting cycles
|
|
|
+ scsiSetDataCount(totalTransferBytes);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bytesPerSector == SD_SECTOR_SIZE)
|
|
|
+ {
|
|
|
+ diskDataOut_512(totalSDSectors, sdLBA, useSlowDataCount, &clearBSY, &parityError);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ diskDataOut_variableSectorSize(sdPerScsi, totalSDSectors, sdLBA, useSlowDataCount, &parityError);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // Should already be complete here as we've ready the FIFOs
|
|
|
+ // by now. Check anyway.
|
|
|
+ __disable_irq();
|
|
|
+ while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
|
|
|
+ {
|
|
|
+ __WFI();
|
|
|
+ }
|
|
|
+ __enable_irq();
|
|
|
+
|
|
|
+ if (clearBSY)
|
|
|
+ {
|
|
|
+ enter_BusFree();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (scsiDev.phase == DATA_OUT)
|
|
|
+ {
|
|
|
+ if (parityError &&
|
|
|
+ (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
|
|
|
+ {
|
|
|
+ scsiDev.target->sense.code = ABORTED_COMMAND;
|
|
|
+ scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
|
|
|
+ scsiDev.status = CHECK_CONDITION;;
|
|
|
+ }
|
|
|
+ scsiDev.phase = STATUS;
|
|
|
+ }
|
|
|
+ scsiDiskReset();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void scsiDiskPoll()
|
|
|
+{
|
|
|
+ if (scsiDev.phase == DATA_IN &&
|
|
|
+ transfer.currentBlock != transfer.blocks)
|
|
|
+ {
|
|
|
+ diskDataIn();
|
|
|
+ }
|
|
|
+ else if (scsiDev.phase == DATA_OUT &&
|
|
|
+ transfer.currentBlock != transfer.blocks)
|
|
|
+ {
|
|
|
+ diskDataOut();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
void scsiDiskReset()
|
|
|
{
|
|
|
scsiDev.dataPtr = 0;
|