-// Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
-// Copyright (C) 2014 Doug Brown <doug@downtowndougbrown.com>\r
+// Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
+// Copyright (C) 2014 Doug Brown <doug@downtowndougbrown.com>\r
//\r
-// This file is part of SCSI2SD.\r
+// This file is part of SCSI2SD.\r
//\r
-// SCSI2SD is free software: you can redistribute it and/or modify\r
-// it under the terms of the GNU General Public License as published by\r
-// the Free Software Foundation, either version 3 of the License, or\r
-// (at your option) any later version.\r
+// SCSI2SD is free software: you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation, either version 3 of the License, or\r
+// (at your option) any later version.\r
//\r
-// SCSI2SD is distributed in the hope that it will be useful,\r
-// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-// GNU General Public License for more details.\r
+// SCSI2SD is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
//\r
-// You should have received a copy of the GNU General Public License\r
-// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.\r
+// You should have received a copy of the GNU General Public License\r
+// along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.\r
\r
#ifdef STM32F2xx\r
#include "stm32f2xx.h"\r
\r
static int doSdInit()\r
{\r
- int result = 0;\r
- if (blockDev.state & DISK_PRESENT)\r
- {\r
- blockDev.state = blockDev.state | DISK_INITIALISED;\r
- }\r
- return result;\r
+ int result = 0;\r
+ if (blockDev.state & DISK_PRESENT)\r
+ {\r
+ blockDev.state = blockDev.state | DISK_INITIALISED;\r
+ }\r
+ return result;\r
}\r
\r
// Callback once all data has been read in the data out phase.\r
static void doFormatUnitComplete(void)\r
{\r
- // TODO start writing the initialisation pattern to the SD\r
- // card\r
- scsiDev.phase = STATUS;\r
+ // TODO start writing the initialisation pattern to the SD\r
+ // card\r
+ scsiDev.phase = STATUS;\r
}\r
\r
static void doFormatUnitSkipData(int bytes)\r
{\r
- // We may not have enough memory to store the initialisation pattern and\r
- // defect list data. Since we're not making use of it yet anyway, just\r
- // discard the bytes.\r
- scsiEnterPhase(DATA_OUT);\r
- int i;\r
- for (i = 0; i < bytes; ++i)\r
- {\r
- scsiReadByte();\r
- }\r
+ // We may not have enough memory to store the initialisation pattern and\r
+ // defect list data. Since we're not making use of it yet anyway, just\r
+ // discard the bytes.\r
+ scsiEnterPhase(DATA_OUT);\r
+ int i;\r
+ for (i = 0; i < bytes; ++i)\r
+ {\r
+ scsiReadByte();\r
+ }\r
}\r
\r
// Callback from the data out phase.\r
static void doFormatUnitPatternHeader(void)\r
{\r
- int defectLength =\r
- ((((uint16_t)scsiDev.data[2])) << 8) +\r
- scsiDev.data[3];\r
+ int defectLength =\r
+ ((((uint16_t)scsiDev.data[2])) << 8) +\r
+ scsiDev.data[3];\r
\r
- int patternLength =\r
- ((((uint16_t)scsiDev.data[4 + 2])) << 8) +\r
- scsiDev.data[4 + 3];\r
+ int patternLength =\r
+ ((((uint16_t)scsiDev.data[4 + 2])) << 8) +\r
+ scsiDev.data[4 + 3];\r
\r
- doFormatUnitSkipData(defectLength + patternLength);\r
- doFormatUnitComplete();\r
+ doFormatUnitSkipData(defectLength + patternLength);\r
+ doFormatUnitComplete();\r
}\r
\r
// Callback from the data out phase.\r
static void doFormatUnitHeader(void)\r
{\r
- int IP = (scsiDev.data[1] & 0x08) ? 1 : 0;\r
- int DSP = (scsiDev.data[1] & 0x04) ? 1 : 0;\r
-\r
- if (! DSP) // disable save parameters\r
- {\r
- // Save the "MODE SELECT savable parameters"\r
- s2s_configSave(\r
- scsiDev.target->targetId,\r
- scsiDev.target->liveCfg.bytesPerSector);\r
- }\r
-\r
- if (IP)\r
- {\r
- // We need to read the initialisation pattern header first.\r
- scsiDev.dataLen += 4;\r
- scsiDev.phase = DATA_OUT;\r
- scsiDev.postDataOutHook = doFormatUnitPatternHeader;\r
- }\r
- else\r
- {\r
- // Read the defect list data\r
- int defectLength =\r
- ((((uint16_t)scsiDev.data[2])) << 8) +\r
- scsiDev.data[3];\r
- doFormatUnitSkipData(defectLength);\r
- doFormatUnitComplete();\r
- }\r
+ int IP = (scsiDev.data[1] & 0x08) ? 1 : 0;\r
+ int DSP = (scsiDev.data[1] & 0x04) ? 1 : 0;\r
+\r
+ if (! DSP) // disable save parameters\r
+ {\r
+ // Save the "MODE SELECT savable parameters"\r
+ s2s_configSave(\r
+ scsiDev.target->targetId,\r
+ scsiDev.target->liveCfg.bytesPerSector);\r
+ }\r
+\r
+ if (IP)\r
+ {\r
+ // We need to read the initialisation pattern header first.\r
+ scsiDev.dataLen += 4;\r
+ scsiDev.phase = DATA_OUT;\r
+ scsiDev.postDataOutHook = doFormatUnitPatternHeader;\r
+ }\r
+ else\r
+ {\r
+ // Read the defect list data\r
+ int defectLength =\r
+ ((((uint16_t)scsiDev.data[2])) << 8) +\r
+ scsiDev.data[3];\r
+ doFormatUnitSkipData(defectLength);\r
+ doFormatUnitComplete();\r
+ }\r
}\r
\r
static void doReadCapacity()\r
{\r
- uint32_t lba = (((uint32_t) scsiDev.cdb[2]) << 24) +\r
- (((uint32_t) scsiDev.cdb[3]) << 16) +\r
- (((uint32_t) scsiDev.cdb[4]) << 8) +\r
- scsiDev.cdb[5];\r
- int pmi = scsiDev.cdb[8] & 1;\r
-\r
- uint32_t capacity = getScsiCapacity(\r
- scsiDev.target->cfg->sdSectorStart,\r
- scsiDev.target->liveCfg.bytesPerSector,\r
- scsiDev.target->cfg->scsiSectors);\r
-\r
- if (!pmi && lba)\r
- {\r
- // error.\r
- // We don't do anything with the "partial medium indicator", and\r
- // assume that delays are constant across each block. But the spec\r
- // says we must return this error if pmi is specified incorrectly.\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
- scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
- scsiDev.phase = STATUS;\r
- }\r
- else if (capacity > 0)\r
- {\r
- uint32_t highestBlock = capacity - 1;\r
-\r
- scsiDev.data[0] = highestBlock >> 24;\r
- scsiDev.data[1] = highestBlock >> 16;\r
- scsiDev.data[2] = highestBlock >> 8;\r
- scsiDev.data[3] = highestBlock;\r
-\r
- uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
- scsiDev.data[4] = bytesPerSector >> 24;\r
- scsiDev.data[5] = bytesPerSector >> 16;\r
- scsiDev.data[6] = bytesPerSector >> 8;\r
- scsiDev.data[7] = bytesPerSector;\r
- scsiDev.dataLen = 8;\r
- scsiDev.phase = DATA_IN;\r
- }\r
- else\r
- {\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = NOT_READY;\r
- scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;\r
- scsiDev.phase = STATUS;\r
- }\r
+ uint32_t lba = (((uint32_t) scsiDev.cdb[2]) << 24) +\r
+ (((uint32_t) scsiDev.cdb[3]) << 16) +\r
+ (((uint32_t) scsiDev.cdb[4]) << 8) +\r
+ scsiDev.cdb[5];\r
+ int pmi = scsiDev.cdb[8] & 1;\r
+\r
+ uint32_t capacity = getScsiCapacity(\r
+ scsiDev.target->cfg->sdSectorStart,\r
+ scsiDev.target->liveCfg.bytesPerSector,\r
+ scsiDev.target->cfg->scsiSectors);\r
+\r
+ if (!pmi && lba)\r
+ {\r
+ // error.\r
+ // We don't do anything with the "partial medium indicator", and\r
+ // assume that delays are constant across each block. But the spec\r
+ // says we must return this error if pmi is specified incorrectly.\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
+ scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ else if (capacity > 0)\r
+ {\r
+ uint32_t highestBlock = capacity - 1;\r
+\r
+ scsiDev.data[0] = highestBlock >> 24;\r
+ scsiDev.data[1] = highestBlock >> 16;\r
+ scsiDev.data[2] = highestBlock >> 8;\r
+ scsiDev.data[3] = highestBlock;\r
+\r
+ uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
+ scsiDev.data[4] = bytesPerSector >> 24;\r
+ scsiDev.data[5] = bytesPerSector >> 16;\r
+ scsiDev.data[6] = bytesPerSector >> 8;\r
+ scsiDev.data[7] = bytesPerSector;\r
+ scsiDev.dataLen = 8;\r
+ scsiDev.phase = DATA_IN;\r
+ }\r
+ else\r
+ {\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = NOT_READY;\r
+ scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;\r
+ scsiDev.phase = STATUS;\r
+ }\r
}\r
\r
static void doWrite(uint32_t lba, uint32_t blocks)\r
{\r
- if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {\r
- // Floppies are supposed to be slow. Some systems can't handle a floppy\r
- // without an access time\r
- s2s_delay_ms(10);\r
- }\r
-\r
- uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
-\r
- if (unlikely(blockDev.state & DISK_WP) ||\r
- unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_OPTICAL))\r
-\r
- {\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
- scsiDev.target->sense.asc = WRITE_PROTECTED;\r
- scsiDev.phase = STATUS;\r
- }\r
- else if (unlikely(((uint64_t) lba) + blocks >\r
- getScsiCapacity(\r
- scsiDev.target->cfg->sdSectorStart,\r
- bytesPerSector,\r
- scsiDev.target->cfg->scsiSectors\r
- )\r
- ))\r
- {\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
- scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\r
- scsiDev.phase = STATUS;\r
- }\r
- else\r
- {\r
- transfer.lba = lba;\r
- transfer.blocks = blocks;\r
- transfer.currentBlock = 0;\r
- scsiDev.phase = DATA_OUT;\r
- scsiDev.dataLen = bytesPerSector;\r
- scsiDev.dataPtr = bytesPerSector;\r
-\r
- // No need for single-block writes atm. Overhead of the\r
- // multi-block write is minimal.\r
- transfer.multiBlock = 1;\r
-\r
-\r
- // TODO uint32_t sdLBA =\r
-// TODO SCSISector2SD(\r
- // TODO scsiDev.target->cfg->sdSectorStart,\r
- // TODO bytesPerSector,\r
- // TODO lba);\r
- // TODO uint32_t sdBlocks = blocks * SDSectorsPerSCSISector(bytesPerSector);\r
- // TODO sdWriteMultiSectorPrep(sdLBA, sdBlocks);\r
- }\r
+ if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {\r
+ // Floppies are supposed to be slow. Some systems can't handle a floppy\r
+ // without an access time\r
+ s2s_delay_ms(10);\r
+ }\r
+\r
+ uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
+\r
+ if (unlikely(blockDev.state & DISK_WP) ||\r
+ unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_OPTICAL))\r
+\r
+ {\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
+ scsiDev.target->sense.asc = WRITE_PROTECTED;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ else if (unlikely(((uint64_t) lba) + blocks >\r
+ getScsiCapacity(\r
+ scsiDev.target->cfg->sdSectorStart,\r
+ bytesPerSector,\r
+ scsiDev.target->cfg->scsiSectors\r
+ )\r
+ ))\r
+ {\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
+ scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ else\r
+ {\r
+ transfer.lba = lba;\r
+ transfer.blocks = blocks;\r
+ transfer.currentBlock = 0;\r
+ scsiDev.phase = DATA_OUT;\r
+ scsiDev.dataLen = bytesPerSector;\r
+ scsiDev.dataPtr = bytesPerSector;\r
+\r
+ // No need for single-block writes atm. Overhead of the\r
+ // multi-block write is minimal.\r
+ transfer.multiBlock = 1;\r
+\r
+\r
+ // TODO uint32_t sdLBA =\r
+// TODO SCSISector2SD(\r
+ // TODO scsiDev.target->cfg->sdSectorStart,\r
+ // TODO bytesPerSector,\r
+ // TODO lba);\r
+ // TODO uint32_t sdBlocks = blocks * SDSectorsPerSCSISector(bytesPerSector);\r
+ // TODO sdWriteMultiSectorPrep(sdLBA, sdBlocks);\r
+ }\r
}\r
\r
\r
static void doRead(uint32_t lba, uint32_t blocks)\r
{\r
- if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {\r
- // Floppies are supposed to be slow. Some systems can't handle a floppy\r
- // without an access time\r
- s2s_delay_ms(10);\r
- }\r
-\r
- uint32_t capacity = getScsiCapacity(\r
- scsiDev.target->cfg->sdSectorStart,\r
- scsiDev.target->liveCfg.bytesPerSector,\r
- scsiDev.target->cfg->scsiSectors);\r
- if (unlikely(((uint64_t) lba) + blocks > capacity))\r
- {\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
- scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\r
- scsiDev.phase = STATUS;\r
- }\r
- else\r
- {\r
- transfer.lba = lba;\r
- transfer.blocks = blocks;\r
- transfer.currentBlock = 0;\r
- scsiDev.phase = DATA_IN;\r
- scsiDev.dataLen = 0; // No data yet\r
-\r
- uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
- uint32_t sdSectorPerSCSISector = SDSectorsPerSCSISector(bytesPerSector);\r
- uint32_t sdSectors =\r
- blocks * sdSectorPerSCSISector;\r
-\r
- if ((\r
- (sdSectors == 1) &&\r
- !(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE)\r
- ) ||\r
- unlikely(((uint64_t) lba) + blocks == capacity)\r
- )\r
- {\r
- // We get errors on reading the last sector using a multi-sector\r
- // read :-(\r
- transfer.multiBlock = 0;\r
- }\r
- else\r
- {\r
- transfer.multiBlock = 1;\r
-\r
- // uint32_t sdLBA =\r
- // SCSISector2SD(\r
- // scsiDev.target->cfg->sdSectorStart,\r
- // bytesPerSector,\r
- // lba);\r
-\r
- // TODO sdReadMultiSectorPrep(sdLBA, sdSectors);\r
- }\r
- }\r
+ if (unlikely(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB)) {\r
+ // Floppies are supposed to be slow. Some systems can't handle a floppy\r
+ // without an access time\r
+ s2s_delay_ms(10);\r
+ }\r
+\r
+ uint32_t capacity = getScsiCapacity(\r
+ scsiDev.target->cfg->sdSectorStart,\r
+ scsiDev.target->liveCfg.bytesPerSector,\r
+ scsiDev.target->cfg->scsiSectors);\r
+ if (unlikely(((uint64_t) lba) + blocks > capacity))\r
+ {\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
+ scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ else\r
+ {\r
+ transfer.lba = lba;\r
+ transfer.blocks = blocks;\r
+ transfer.currentBlock = 0;\r
+ scsiDev.phase = DATA_IN;\r
+ scsiDev.dataLen = 0; // No data yet\r
+\r
+ uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
+ uint32_t sdSectorPerSCSISector = SDSectorsPerSCSISector(bytesPerSector);\r
+ uint32_t sdSectors =\r
+ blocks * sdSectorPerSCSISector;\r
+\r
+ if ((\r
+ (sdSectors == 1) &&\r
+ !(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE)\r
+ ) ||\r
+ unlikely(((uint64_t) lba) + blocks == capacity)\r
+ )\r
+ {\r
+ // We get errors on reading the last sector using a multi-sector\r
+ // read :-(\r
+ transfer.multiBlock = 0;\r
+ }\r
+ else\r
+ {\r
+ transfer.multiBlock = 1;\r
+\r
+ // uint32_t sdLBA =\r
+ // SCSISector2SD(\r
+ // scsiDev.target->cfg->sdSectorStart,\r
+ // bytesPerSector,\r
+ // lba);\r
+\r
+ // TODO sdReadMultiSectorPrep(sdLBA, sdSectors);\r
+ }\r
+ }\r
}\r
\r
static void doSeek(uint32_t lba)\r
{\r
- if (lba >=\r
- getScsiCapacity(\r
- scsiDev.target->cfg->sdSectorStart,\r
- scsiDev.target->liveCfg.bytesPerSector,\r
- scsiDev.target->cfg->scsiSectors)\r
- )\r
- {\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
- scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\r
- scsiDev.phase = STATUS;\r
- }\r
- else\r
- {\r
- s2s_delay_ms(10);\r
- }\r
+ if (lba >=\r
+ getScsiCapacity(\r
+ scsiDev.target->cfg->sdSectorStart,\r
+ scsiDev.target->liveCfg.bytesPerSector,\r
+ scsiDev.target->cfg->scsiSectors)\r
+ )\r
+ {\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
+ scsiDev.target->sense.asc = LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ else\r
+ {\r
+ s2s_delay_ms(10);\r
+ }\r
}\r
\r
static int doTestUnitReady()\r
{\r
- int ready = 1;\r
- if (likely(blockDev.state == (DISK_STARTED | DISK_PRESENT | DISK_INITIALISED)))\r
- {\r
- // nothing to do.\r
- }\r
- else if (unlikely(!(blockDev.state & DISK_STARTED)))\r
- {\r
- ready = 0;\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = NOT_READY;\r
- scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED;\r
- scsiDev.phase = STATUS;\r
- }\r
- else if (unlikely(!(blockDev.state & DISK_PRESENT)))\r
- {\r
- ready = 0;\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = NOT_READY;\r
- scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;\r
- scsiDev.phase = STATUS;\r
- }\r
- else if (unlikely(!(blockDev.state & DISK_INITIALISED)))\r
- {\r
- ready = 0;\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = NOT_READY;\r
- scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE;\r
- scsiDev.phase = STATUS;\r
- }\r
- return ready;\r
+ int ready = 1;\r
+ if (likely(blockDev.state == (DISK_STARTED | DISK_PRESENT | DISK_INITIALISED)))\r
+ {\r
+ // nothing to do.\r
+ }\r
+ else if (unlikely(!(blockDev.state & DISK_STARTED)))\r
+ {\r
+ ready = 0;\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = NOT_READY;\r
+ scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ else if (unlikely(!(blockDev.state & DISK_PRESENT)))\r
+ {\r
+ ready = 0;\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = NOT_READY;\r
+ scsiDev.target->sense.asc = MEDIUM_NOT_PRESENT;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ else if (unlikely(!(blockDev.state & DISK_INITIALISED)))\r
+ {\r
+ ready = 0;\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = NOT_READY;\r
+ scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_READY_CAUSE_NOT_REPORTABLE;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ return ready;\r
}\r
\r
// Handle direct-access scsi device commands\r
int scsiDiskCommand()\r
{\r
- int commandHandled = 1;\r
-\r
- uint8_t command = scsiDev.cdb[0];\r
- if (unlikely(command == 0x1B))\r
- {\r
- // START STOP UNIT\r
- // Enable or disable media access operations.\r
- // Ignore load/eject requests. We can't do that.\r
- //int immed = scsiDev.cdb[1] & 1;\r
- int start = scsiDev.cdb[4] & 1;\r
-\r
- if (start)\r
- {\r
- blockDev.state = blockDev.state | DISK_STARTED;\r
- if (!(blockDev.state & DISK_INITIALISED))\r
- {\r
- doSdInit();\r
- }\r
- }\r
- else\r
- {\r
- blockDev.state &= ~DISK_STARTED;\r
- }\r
- }\r
- else if (unlikely(command == 0x00))\r
- {\r
- // TEST UNIT READY\r
- doTestUnitReady();\r
- }\r
- else if (unlikely(!doTestUnitReady()))\r
- {\r
- // Status and sense codes already set by doTestUnitReady\r
- }\r
- else if (likely(command == 0x08))\r
- {\r
- // READ(6)\r
- uint32_t lba =\r
- (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +\r
- (((uint32_t) scsiDev.cdb[2]) << 8) +\r
- scsiDev.cdb[3];\r
- uint32_t blocks = scsiDev.cdb[4];\r
- if (unlikely(blocks == 0)) blocks = 256;\r
- doRead(lba, blocks);\r
- }\r
- else if (likely(command == 0x28))\r
- {\r
- // READ(10)\r
- // Ignore all cache control bits - we don't support a memory cache.\r
-\r
- uint32_t lba =\r
- (((uint32_t) scsiDev.cdb[2]) << 24) +\r
- (((uint32_t) scsiDev.cdb[3]) << 16) +\r
- (((uint32_t) scsiDev.cdb[4]) << 8) +\r
- scsiDev.cdb[5];\r
- uint32_t blocks =\r
- (((uint32_t) scsiDev.cdb[7]) << 8) +\r
- scsiDev.cdb[8];\r
-\r
- doRead(lba, blocks);\r
- }\r
- else if (likely(command == 0x0A))\r
- {\r
- // WRITE(6)\r
- uint32_t lba =\r
- (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +\r
- (((uint32_t) scsiDev.cdb[2]) << 8) +\r
- scsiDev.cdb[3];\r
- uint32_t blocks = scsiDev.cdb[4];\r
- if (unlikely(blocks == 0)) blocks = 256;\r
- doWrite(lba, blocks);\r
- }\r
- else if (likely(command == 0x2A) || // WRITE(10)\r
- unlikely(command == 0x2E)) // WRITE AND VERIFY\r
- {\r
- // Ignore all cache control bits - we don't support a memory cache.\r
- // Don't bother verifying either. The SD card likely stores ECC\r
- // along with each flash row.\r
-\r
- uint32_t lba =\r
- (((uint32_t) scsiDev.cdb[2]) << 24) +\r
- (((uint32_t) scsiDev.cdb[3]) << 16) +\r
- (((uint32_t) scsiDev.cdb[4]) << 8) +\r
- scsiDev.cdb[5];\r
- uint32_t blocks =\r
- (((uint32_t) scsiDev.cdb[7]) << 8) +\r
- scsiDev.cdb[8];\r
-\r
- doWrite(lba, blocks);\r
- }\r
- else if (unlikely(command == 0x04))\r
- {\r
- // FORMAT UNIT\r
- // We don't really do any formatting, but we need to read the correct\r
- // number of bytes in the DATA_OUT phase to make the SCSI host happy.\r
-\r
- int fmtData = (scsiDev.cdb[1] & 0x10) ? 1 : 0;\r
- if (fmtData)\r
- {\r
- // We need to read the parameter list, but we don't know how\r
- // big it is yet. Start with the header.\r
- scsiDev.dataLen = 4;\r
- scsiDev.phase = DATA_OUT;\r
- scsiDev.postDataOutHook = doFormatUnitHeader;\r
- }\r
- else\r
- {\r
- // No data to read, we're already finished!\r
- }\r
- }\r
- else if (unlikely(command == 0x25))\r
- {\r
- // READ CAPACITY\r
- doReadCapacity();\r
- }\r
- else if (unlikely(command == 0x0B))\r
- {\r
- // SEEK(6)\r
- uint32_t lba =\r
- (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +\r
- (((uint32_t) scsiDev.cdb[2]) << 8) +\r
- scsiDev.cdb[3];\r
-\r
- doSeek(lba);\r
- }\r
-\r
- else if (unlikely(command == 0x2B))\r
- {\r
- // SEEK(10)\r
- uint32_t lba =\r
- (((uint32_t) scsiDev.cdb[2]) << 24) +\r
- (((uint32_t) scsiDev.cdb[3]) << 16) +\r
- (((uint32_t) scsiDev.cdb[4]) << 8) +\r
- scsiDev.cdb[5];\r
-\r
- doSeek(lba);\r
- }\r
- else if (unlikely(command == 0x36))\r
- {\r
- // LOCK UNLOCK CACHE\r
- // We don't have a cache to lock data into. do nothing.\r
- }\r
- else if (unlikely(command == 0x34))\r
- {\r
- // PRE-FETCH.\r
- // We don't have a cache to pre-fetch into. do nothing.\r
- }\r
- else if (unlikely(command == 0x1E))\r
- {\r
- // PREVENT ALLOW MEDIUM REMOVAL\r
- // Not much we can do to prevent the user removing the SD card.\r
- // do nothing.\r
- }\r
- else if (unlikely(command == 0x01))\r
- {\r
- // REZERO UNIT\r
- // Set the lun to a vendor-specific state. Ignore.\r
- }\r
- else if (unlikely(command == 0x35))\r
- {\r
- // SYNCHRONIZE CACHE\r
- // We don't have a cache. do nothing.\r
- }\r
- else if (unlikely(command == 0x2F))\r
- {\r
- // VERIFY\r
- // TODO: When they supply data to verify, we should read the data and\r
- // verify it. If they don't supply any data, just say success.\r
- if ((scsiDev.cdb[1] & 0x02) == 0)\r
- {\r
- // They are asking us to do a medium verification with no data\r
- // comparison. Assume success, do nothing.\r
- }\r
- else\r
- {\r
- // TODO. This means they are supplying data to verify against.\r
- // Technically we should probably grab the data and compare it.\r
- scsiDev.status = CHECK_CONDITION;\r
- scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
- scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
- scsiDev.phase = STATUS;\r
- }\r
- }\r
- else if (unlikely(command == 0x37))\r
- {\r
- // READ DEFECT DATA\r
- uint32_t allocLength = (((uint16_t)scsiDev.cdb[7]) << 8) |\r
- scsiDev.cdb[8];\r
-\r
- scsiDev.data[0] = 0;\r
- scsiDev.data[1] = scsiDev.cdb[1];\r
- scsiDev.data[2] = 0;\r
- scsiDev.data[3] = 0;\r
- scsiDev.dataLen = 4;\r
-\r
- if (scsiDev.dataLen > allocLength)\r
- {\r
- scsiDev.dataLen = allocLength;\r
- }\r
-\r
- scsiDev.phase = DATA_IN;\r
- }\r
- else\r
- {\r
- commandHandled = 0;\r
- }\r
-\r
- return commandHandled;\r
+ int commandHandled = 1;\r
+\r
+ uint8_t command = scsiDev.cdb[0];\r
+ if (unlikely(command == 0x1B))\r
+ {\r
+ // START STOP UNIT\r
+ // Enable or disable media access operations.\r
+ // Ignore load/eject requests. We can't do that.\r
+ //int immed = scsiDev.cdb[1] & 1;\r
+ int start = scsiDev.cdb[4] & 1;\r
+\r
+ if (start)\r
+ {\r
+ blockDev.state = blockDev.state | DISK_STARTED;\r
+ if (!(blockDev.state & DISK_INITIALISED))\r
+ {\r
+ doSdInit();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ blockDev.state &= ~DISK_STARTED;\r
+ }\r
+ }\r
+ else if (unlikely(command == 0x00))\r
+ {\r
+ // TEST UNIT READY\r
+ doTestUnitReady();\r
+ }\r
+ else if (unlikely(!doTestUnitReady()))\r
+ {\r
+ // Status and sense codes already set by doTestUnitReady\r
+ }\r
+ else if (likely(command == 0x08))\r
+ {\r
+ // READ(6)\r
+ uint32_t lba =\r
+ (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +\r
+ (((uint32_t) scsiDev.cdb[2]) << 8) +\r
+ scsiDev.cdb[3];\r
+ uint32_t blocks = scsiDev.cdb[4];\r
+ if (unlikely(blocks == 0)) blocks = 256;\r
+ doRead(lba, blocks);\r
+ }\r
+ else if (likely(command == 0x28))\r
+ {\r
+ // READ(10)\r
+ // Ignore all cache control bits - we don't support a memory cache.\r
+\r
+ uint32_t lba =\r
+ (((uint32_t) scsiDev.cdb[2]) << 24) +\r
+ (((uint32_t) scsiDev.cdb[3]) << 16) +\r
+ (((uint32_t) scsiDev.cdb[4]) << 8) +\r
+ scsiDev.cdb[5];\r
+ uint32_t blocks =\r
+ (((uint32_t) scsiDev.cdb[7]) << 8) +\r
+ scsiDev.cdb[8];\r
+\r
+ doRead(lba, blocks);\r
+ }\r
+ else if (likely(command == 0x0A))\r
+ {\r
+ // WRITE(6)\r
+ uint32_t lba =\r
+ (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +\r
+ (((uint32_t) scsiDev.cdb[2]) << 8) +\r
+ scsiDev.cdb[3];\r
+ uint32_t blocks = scsiDev.cdb[4];\r
+ if (unlikely(blocks == 0)) blocks = 256;\r
+ doWrite(lba, blocks);\r
+ }\r
+ else if (likely(command == 0x2A) || // WRITE(10)\r
+ unlikely(command == 0x2E)) // WRITE AND VERIFY\r
+ {\r
+ // Ignore all cache control bits - we don't support a memory cache.\r
+ // Don't bother verifying either. The SD card likely stores ECC\r
+ // along with each flash row.\r
+\r
+ uint32_t lba =\r
+ (((uint32_t) scsiDev.cdb[2]) << 24) +\r
+ (((uint32_t) scsiDev.cdb[3]) << 16) +\r
+ (((uint32_t) scsiDev.cdb[4]) << 8) +\r
+ scsiDev.cdb[5];\r
+ uint32_t blocks =\r
+ (((uint32_t) scsiDev.cdb[7]) << 8) +\r
+ scsiDev.cdb[8];\r
+\r
+ doWrite(lba, blocks);\r
+ }\r
+ else if (unlikely(command == 0x04))\r
+ {\r
+ // FORMAT UNIT\r
+ // We don't really do any formatting, but we need to read the correct\r
+ // number of bytes in the DATA_OUT phase to make the SCSI host happy.\r
+\r
+ int fmtData = (scsiDev.cdb[1] & 0x10) ? 1 : 0;\r
+ if (fmtData)\r
+ {\r
+ // We need to read the parameter list, but we don't know how\r
+ // big it is yet. Start with the header.\r
+ scsiDev.dataLen = 4;\r
+ scsiDev.phase = DATA_OUT;\r
+ scsiDev.postDataOutHook = doFormatUnitHeader;\r
+ }\r
+ else\r
+ {\r
+ // No data to read, we're already finished!\r
+ }\r
+ }\r
+ else if (unlikely(command == 0x25))\r
+ {\r
+ // READ CAPACITY\r
+ doReadCapacity();\r
+ }\r
+ else if (unlikely(command == 0x0B))\r
+ {\r
+ // SEEK(6)\r
+ uint32_t lba =\r
+ (((uint32_t) scsiDev.cdb[1] & 0x1F) << 16) +\r
+ (((uint32_t) scsiDev.cdb[2]) << 8) +\r
+ scsiDev.cdb[3];\r
+\r
+ doSeek(lba);\r
+ }\r
+\r
+ else if (unlikely(command == 0x2B))\r
+ {\r
+ // SEEK(10)\r
+ uint32_t lba =\r
+ (((uint32_t) scsiDev.cdb[2]) << 24) +\r
+ (((uint32_t) scsiDev.cdb[3]) << 16) +\r
+ (((uint32_t) scsiDev.cdb[4]) << 8) +\r
+ scsiDev.cdb[5];\r
+\r
+ doSeek(lba);\r
+ }\r
+ else if (unlikely(command == 0x36))\r
+ {\r
+ // LOCK UNLOCK CACHE\r
+ // We don't have a cache to lock data into. do nothing.\r
+ }\r
+ else if (unlikely(command == 0x34))\r
+ {\r
+ // PRE-FETCH.\r
+ // We don't have a cache to pre-fetch into. do nothing.\r
+ }\r
+ else if (unlikely(command == 0x1E))\r
+ {\r
+ // PREVENT ALLOW MEDIUM REMOVAL\r
+ // Not much we can do to prevent the user removing the SD card.\r
+ // do nothing.\r
+ }\r
+ else if (unlikely(command == 0x01))\r
+ {\r
+ // REZERO UNIT\r
+ // Set the lun to a vendor-specific state. Ignore.\r
+ }\r
+ else if (unlikely(command == 0x35))\r
+ {\r
+ // SYNCHRONIZE CACHE\r
+ // We don't have a cache. do nothing.\r
+ }\r
+ else if (unlikely(command == 0x2F))\r
+ {\r
+ // VERIFY\r
+ // TODO: When they supply data to verify, we should read the data and\r
+ // verify it. If they don't supply any data, just say success.\r
+ if ((scsiDev.cdb[1] & 0x02) == 0)\r
+ {\r
+ // They are asking us to do a medium verification with no data\r
+ // comparison. Assume success, do nothing.\r
+ }\r
+ else\r
+ {\r
+ // TODO. This means they are supplying data to verify against.\r
+ // Technically we should probably grab the data and compare it.\r
+ scsiDev.status = CHECK_CONDITION;\r
+ scsiDev.target->sense.code = ILLEGAL_REQUEST;\r
+ scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ }\r
+ else if (unlikely(command == 0x37))\r
+ {\r
+ // READ DEFECT DATA\r
+ uint32_t allocLength = (((uint16_t)scsiDev.cdb[7]) << 8) |\r
+ scsiDev.cdb[8];\r
+\r
+ scsiDev.data[0] = 0;\r
+ scsiDev.data[1] = scsiDev.cdb[1];\r
+ scsiDev.data[2] = 0;\r
+ scsiDev.data[3] = 0;\r
+ scsiDev.dataLen = 4;\r
+\r
+ if (scsiDev.dataLen > allocLength)\r
+ {\r
+ scsiDev.dataLen = allocLength;\r
+ }\r
+\r
+ scsiDev.phase = DATA_IN;\r
+ }\r
+ else\r
+ {\r
+ commandHandled = 0;\r
+ }\r
+\r
+ return commandHandled;\r
}\r
\r
void scsiDiskPoll()\r
{\r
- uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
-\r
- if (scsiDev.phase == DATA_IN &&\r
- transfer.currentBlock != transfer.blocks)\r
- {\r
- // Take responsibility for waiting for the phase delays\r
- uint32_t phaseChangeDelayUs = scsiEnterPhaseImmediate(DATA_IN);\r
-\r
- int totalSDSectors =\r
- transfer.blocks * SDSectorsPerSCSISector(bytesPerSector);\r
- uint32_t sdLBA =\r
- SCSISector2SD(\r
- scsiDev.target->cfg->sdSectorStart,\r
- bytesPerSector,\r
- transfer.lba);\r
-\r
- const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);\r
- const int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;\r
- int prep = 0;\r
- int i = 0;\r
- int scsiActive __attribute__((unused)) = 0; // unused if DMA disabled\r
- int sdActive = 0;\r
-\r
- // It's highly unlikely that someone is going to use huge transfers\r
- // per scsi command, but if they do it'll be slower than usual.\r
- uint32_t totalScsiBytes = transfer.blocks * bytesPerSector;\r
- int useSlowDataCount = totalScsiBytes >= SCSI_XFER_MAX;\r
- if (!useSlowDataCount)\r
- {\r
- scsiSetDataCount(totalScsiBytes);\r
- }\r
-\r
- while ((i < totalSDSectors) &&\r
- likely(scsiDev.phase == DATA_IN) &&\r
- likely(!scsiDev.resetFlag))\r
- {\r
- int completedDmaSectors;\r
- if (sdActive && (completedDmaSectors = sdReadDMAPoll(sdActive)))\r
- {\r
- prep += completedDmaSectors;\r
- sdActive -= completedDmaSectors;\r
- } else if (sdActive > 1)\r
- {\r
- if ((scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 510] != 0xAA) ||\r
- (scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 511] != 0x33))\r
- {\r
- prep += 1;\r
- sdActive -= 1;\r
- }\r
- }\r
-\r
- if (!sdActive &&\r
- (prep - i < buffers) &&\r
- (prep < totalSDSectors) &&\r
- ((totalSDSectors - prep) >= sdPerScsi) &&\r
- (likely(!useSlowDataCount) || scsiPhyComplete()) &&\r
- (HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY)) // rx complete but IRQ not fired yet.\r
- {\r
- // Start an SD transfer if we have space.\r
- uint32_t startBuffer = prep % buffers;\r
- uint32_t sectors = totalSDSectors - prep;\r
- uint32_t freeBuffers = buffers - (prep - i);\r
-\r
- uint32_t contiguousBuffers = buffers - startBuffer;\r
- freeBuffers = freeBuffers < contiguousBuffers\r
- ? freeBuffers : contiguousBuffers;\r
- sectors = sectors < freeBuffers ? sectors : freeBuffers;\r
-\r
- if (sectors > 128) sectors = 128; // 65536 DMA limit !!\r
-\r
- // Round-down when we have odd sector sizes.\r
- if (sdPerScsi != 1)\r
- {\r
- sectors = (sectors / sdPerScsi) * sdPerScsi;\r
- }\r
-\r
- for (int dodgy = 0; dodgy < sectors; dodgy++)\r
- {\r
- scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 510] = 0xAA;\r
- scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 511] = 0x33;\r
- }\r
-\r
- sdReadDMA(sdLBA + prep, sectors, &scsiDev.data[SD_SECTOR_SIZE * startBuffer]);\r
-\r
- sdActive = sectors;\r
-\r
- if (useSlowDataCount)\r
- {\r
- scsiSetDataCount((sectors / sdPerScsi) * bytesPerSector);\r
- }\r
-\r
- // Wait now that the SD card is busy\r
- // Chances are we've probably already waited sufficient time,\r
- // but it's hard to measure microseconds cheaply. So just wait\r
- // extra just-in-case. Hopefully it's in parallel with dma.\r
- if (phaseChangeDelayUs > 0)\r
- {\r
- s2s_delay_us(phaseChangeDelayUs);\r
- phaseChangeDelayUs = 0;\r
- }\r
- }\r
-\r
- if (((prep - i) > 0) &&\r
+ uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;\r
+\r
+ if (scsiDev.phase == DATA_IN &&\r
+ transfer.currentBlock != transfer.blocks)\r
+ {\r
+ // Take responsibility for waiting for the phase delays\r
+ uint32_t phaseChangeDelayUs = scsiEnterPhaseImmediate(DATA_IN);\r
+\r
+ int totalSDSectors =\r
+ transfer.blocks * SDSectorsPerSCSISector(bytesPerSector);\r
+ uint32_t sdLBA =\r
+ SCSISector2SD(\r
+ scsiDev.target->cfg->sdSectorStart,\r
+ bytesPerSector,\r
+ transfer.lba);\r
+\r
+ const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);\r
+ const int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;\r
+ int prep = 0;\r
+ int i = 0;\r
+ int scsiActive __attribute__((unused)) = 0; // unused if DMA disabled\r
+ int sdActive = 0;\r
+\r
+ // It's highly unlikely that someone is going to use huge transfers\r
+ // per scsi command, but if they do it'll be slower than usual.\r
+ uint32_t totalScsiBytes = transfer.blocks * bytesPerSector;\r
+ int useSlowDataCount = totalScsiBytes >= SCSI_XFER_MAX;\r
+ if (!useSlowDataCount)\r
+ {\r
+ scsiSetDataCount(totalScsiBytes);\r
+ }\r
+\r
+ while ((i < totalSDSectors) &&\r
+ likely(scsiDev.phase == DATA_IN) &&\r
+ likely(!scsiDev.resetFlag))\r
+ {\r
+ int completedDmaSectors;\r
+ if (sdActive && (completedDmaSectors = sdReadDMAPoll(sdActive)))\r
+ {\r
+ prep += completedDmaSectors;\r
+ sdActive -= completedDmaSectors;\r
+ } else if (sdActive > 1)\r
+ {\r
+ if ((scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 510] != 0xAA) ||\r
+ (scsiDev.data[SD_SECTOR_SIZE * (prep % buffers) + 511] != 0x33))\r
+ {\r
+ prep += 1;\r
+ sdActive -= 1;\r
+ }\r
+ }\r
+\r
+ if (!sdActive &&\r
+ (prep - i < buffers) &&\r
+ (prep < totalSDSectors) &&\r
+ ((totalSDSectors - prep) >= sdPerScsi) &&\r
+ (likely(!useSlowDataCount) || scsiPhyComplete()) &&\r
+ (HAL_SD_GetState(&hsd) != HAL_SD_STATE_BUSY)) // rx complete but IRQ not fired yet.\r
+ {\r
+ // Start an SD transfer if we have space.\r
+ uint32_t startBuffer = prep % buffers;\r
+ uint32_t sectors = totalSDSectors - prep;\r
+ uint32_t freeBuffers = buffers - (prep - i);\r
+\r
+ uint32_t contiguousBuffers = buffers - startBuffer;\r
+ freeBuffers = freeBuffers < contiguousBuffers\r
+ ? freeBuffers : contiguousBuffers;\r
+ sectors = sectors < freeBuffers ? sectors : freeBuffers;\r
+\r
+ if (sectors > 128) sectors = 128; // 65536 DMA limit !!\r
+\r
+ // Round-down when we have odd sector sizes.\r
+ if (sdPerScsi != 1)\r
+ {\r
+ sectors = (sectors / sdPerScsi) * sdPerScsi;\r
+ }\r
+\r
+ for (int dodgy = 0; dodgy < sectors; dodgy++)\r
+ {\r
+ scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 510] = 0xAA;\r
+ scsiDev.data[SD_SECTOR_SIZE * (startBuffer + dodgy) + 511] = 0x33;\r
+ }\r
+\r
+ sdReadDMA(sdLBA + prep, sectors, &scsiDev.data[SD_SECTOR_SIZE * startBuffer]);\r
+\r
+ sdActive = sectors;\r
+\r
+ if (useSlowDataCount)\r
+ {\r
+ scsiSetDataCount((sectors / sdPerScsi) * bytesPerSector);\r
+ }\r
+\r
+ // Wait now that the SD card is busy\r
+ // Chances are we've probably already waited sufficient time,\r
+ // but it's hard to measure microseconds cheaply. So just wait\r
+ // extra just-in-case. Hopefully it's in parallel with dma.\r
+ if (phaseChangeDelayUs > 0)\r
+ {\r
+ s2s_delay_us(phaseChangeDelayUs);\r
+ phaseChangeDelayUs = 0;\r
+ }\r
+ }\r
+\r
+ if (((prep - i) > 0) &&\r
scsiFifoReady())\r
- {\r
- int dmaBytes = SD_SECTOR_SIZE;\r
- if ((i % sdPerScsi) == (sdPerScsi - 1))\r
- {\r
- dmaBytes = bytesPerSector % SD_SECTOR_SIZE;\r
- if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;\r
- }\r
-\r
- uint8_t* scsiDmaData = &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);\r
- scsiWritePIO(scsiDmaData, dmaBytes);\r
-\r
- ++i;\r
- }\r
- }\r
-\r
- if (phaseChangeDelayUs > 0 && !scsiDev.resetFlag) // zero bytes ?\r
- {\r
- s2s_delay_us(phaseChangeDelayUs);\r
- phaseChangeDelayUs = 0;\r
- }\r
-\r
- // Wait for the SD transfer to complete before we disable IRQs.\r
- // (Otherwise some cards will cause an error if we don't sent the\r
- // stop transfer command via the DMA complete handler in time)\r
- while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY)\r
- {\r
- // Wait while keeping BSY.\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
- likely(scsiDev.phase == DATA_IN) &&\r
- likely(!scsiDev.resetFlag))\r
- {\r
- __disable_irq();\r
- if (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
{\r
- __WFI();\r
+ int dmaBytes = SD_SECTOR_SIZE;\r
+ if ((i % sdPerScsi) == (sdPerScsi - 1))\r
+ {\r
+ dmaBytes = bytesPerSector % SD_SECTOR_SIZE;\r
+ if (dmaBytes == 0) dmaBytes = SD_SECTOR_SIZE;\r
+ }\r
+\r
+ uint8_t* scsiDmaData = &(scsiDev.data[SD_SECTOR_SIZE * (i % buffers)]);\r
+ scsiWritePIO(scsiDmaData, dmaBytes);\r
+\r
+ ++i;\r
+ }\r
+ }\r
+\r
+ if (phaseChangeDelayUs > 0 && !scsiDev.resetFlag) // zero bytes ?\r
+ {\r
+ s2s_delay_us(phaseChangeDelayUs);\r
+ phaseChangeDelayUs = 0;\r
+ }\r
+\r
+ if (scsiDev.resetFlag)\r
+ {\r
+ HAL_SD_Abort(&hsd);\r
+ }\r
+ else\r
+ {\r
+ // Wait for the SD transfer to complete before we disable IRQs.\r
+ // (Otherwise some cards will cause an error if we don't sent the\r
+ // stop transfer command via the DMA complete handler in time)\r
+ while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY)\r
+ {\r
+ // Wait while keeping BSY.\r
}\r
- __enable_irq();\r
- }\r
-\r
- if (scsiDev.phase == DATA_IN)\r
- {\r
- scsiDev.phase = STATUS;\r
- }\r
- scsiDiskReset();\r
}\r
- else if (scsiDev.phase == DATA_OUT &&\r
- transfer.currentBlock != transfer.blocks)\r
- {\r
- scsiEnterPhase(DATA_OUT);\r
-\r
- const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);\r
- int totalSDSectors = transfer.blocks * sdPerScsi;\r
- uint32_t sdLBA =\r
- SCSISector2SD(\r
- scsiDev.target->cfg->sdSectorStart,\r
- bytesPerSector,\r
- transfer.lba);\r
- int i = 0;\r
- int clearBSY = 0;\r
+\r
+ HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd);\r
+ while (cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_SENDING) \r
+ {\r
+ cardState = HAL_SD_GetCardState(&hsd);\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
+ likely(scsiDev.phase == DATA_IN) &&\r
+ likely(!scsiDev.resetFlag))\r
+ {\r
+ __disable_irq();\r
+ if (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
+ {\r
+ __WFI();\r
+ }\r
+ __enable_irq();\r
+ }\r
+\r
+ if (scsiDev.phase == DATA_IN)\r
+ {\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ scsiDiskReset();\r
+ }\r
+ else if (scsiDev.phase == DATA_OUT &&\r
+ transfer.currentBlock != transfer.blocks)\r
+ {\r
+ scsiEnterPhase(DATA_OUT);\r
+\r
+ const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);\r
+ int totalSDSectors = transfer.blocks * sdPerScsi;\r
+ uint32_t sdLBA =\r
+ SCSISector2SD(\r
+ scsiDev.target->cfg->sdSectorStart,\r
+ bytesPerSector,\r
+ transfer.lba);\r
+ int i = 0;\r
+ int clearBSY = 0;\r
int disconnected = 0;\r
\r
- int parityError = 0;\r
- int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;\r
-\r
- uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;\r
-\r
- static_assert(SCSI_XFER_MAX >= sizeof(scsiDev.data), "Assumes SCSI_XFER_MAX >= sizeof(scsiDev.data)");\r
-\r
- // Start reading and filling fifos as soon as possible.\r
- // It's highly unlikely that someone is going to use huge transfers\r
- // per scsi command, but if they do it'll be slower than usual.\r
- // Note: Happens in Macintosh FWB HDD Toolkit benchmarks which default\r
- // to 768kb\r
- uint32_t totalTransferBytes = transfer.blocks * bytesPerSector;\r
- int useSlowDataCount = totalTransferBytes >= SCSI_XFER_MAX;\r
- if (!useSlowDataCount)\r
- {\r
- DWT->CYCCNT = 0; // Start counting cycles\r
- scsiSetDataCount(totalTransferBytes);\r
- }\r
-\r
- while ((i < totalSDSectors) &&\r
- likely(scsiDev.phase == DATA_OUT) &&\r
- likely(!scsiDev.resetFlag))\r
- // KEEP GOING to ensure FIFOs are in a good state.\r
- // likely(!parityError || !enableParity))\r
- {\r
- if (bytesPerSector == SD_SECTOR_SIZE)\r
- {\r
+ int parityError = 0;\r
+ int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;\r
+\r
+ uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;\r
+\r
+ static_assert(SCSI_XFER_MAX >= sizeof(scsiDev.data), "Assumes SCSI_XFER_MAX >= sizeof(scsiDev.data)");\r
+\r
+ // Start reading and filling fifos as soon as possible.\r
+ // It's highly unlikely that someone is going to use huge transfers\r
+ // per scsi command, but if they do it'll be slower than usual.\r
+ // Note: Happens in Macintosh FWB HDD Toolkit benchmarks which default\r
+ // to 768kb\r
+ uint32_t totalTransferBytes = transfer.blocks * bytesPerSector;\r
+ int useSlowDataCount = totalTransferBytes >= SCSI_XFER_MAX;\r
+ if (!useSlowDataCount)\r
+ {\r
+ DWT->CYCCNT = 0; // Start counting cycles\r
+ scsiSetDataCount(totalTransferBytes);\r
+ }\r
+\r
+ int lastWriteSize = 0;\r
+\r
+ while ((i < totalSDSectors) &&\r
+ likely(scsiDev.phase == DATA_OUT) &&\r
+ likely(!scsiDev.resetFlag))\r
+ // KEEP GOING to ensure FIFOs are in a good state.\r
+ // likely(!parityError || !enableParity))\r
+ {\r
+ if (bytesPerSector == SD_SECTOR_SIZE)\r
+ {\r
uint32_t maxXferSectors = SCSI_XFER_MAX / SD_SECTOR_SIZE;\r
- uint32_t rem = totalSDSectors - i;\r
- uint32_t sectors = rem < maxXferSectors ? rem : maxXferSectors;\r
+ uint32_t rem = totalSDSectors - i;\r
+ uint32_t sectors = rem < maxXferSectors ? rem : maxXferSectors;\r
\r
- uint32_t totalBytes = sectors * SD_SECTOR_SIZE;\r
+ uint32_t totalBytes = sectors * SD_SECTOR_SIZE;\r
\r
- if (useSlowDataCount)\r
- {\r
- scsiSetDataCount(totalBytes);\r
- }\r
+ if (useSlowDataCount)\r
+ {\r
+ scsiSetDataCount(totalBytes);\r
+ }\r
\r
- HAL_SD_WriteBlocks_DMA(&hsd, i + sdLBA, sectors);\r
+ lastWriteSize = sectors;\r
+ HAL_SD_WriteBlocks_DMA(&hsd, i + sdLBA, sectors);\r
int j = 0;\r
int prep = 0;\r
int sdActive = 0;\r
- uint32_t dmaFinishTime = 0;\r
+ uint32_t dmaFinishTime = 0;\r
while (j < sectors && !scsiDev.resetFlag)\r
{\r
if (sdActive &&\r
sdActive = 0;\r
}\r
}\r
- if (!sdActive && ((prep - j) > 0))\r
- {\r
- // Start an SD transfer if we have space.\r
- HAL_SD_WriteBlocks_Data(&hsd, &scsiDev.data[SD_SECTOR_SIZE * (j % maxSectors)]);\r
+ if (!sdActive && ((prep - j) > 0))\r
+ {\r
+ // Start an SD transfer if we have space.\r
+ HAL_SD_WriteBlocks_Data(&hsd, &scsiDev.data[SD_SECTOR_SIZE * (j % maxSectors)]);\r
\r
- sdActive = 1;\r
- }\r
+ sdActive = 1;\r
+ }\r
\r
if (((prep - j) < maxSectors) &&\r
(prep < sectors) &&\r
scsiFifoReady())\r
{\r
- scsiReadPIO(\r
- &scsiDev.data[(prep % maxSectors) * SD_SECTOR_SIZE],\r
- SD_SECTOR_SIZE,\r
- &parityError);\r
+ scsiReadPIO(\r
+ &scsiDev.data[(prep % maxSectors) * SD_SECTOR_SIZE],\r
+ SD_SECTOR_SIZE,\r
+ &parityError);\r
prep++;\r
if (prep == sectors)\r
{\r
- dmaFinishTime = s2s_getTime_ms();\r
+ dmaFinishTime = s2s_getTime_ms();\r
}\r
}\r
- \r
+ \r
if (i + prep >= totalSDSectors &&\r
!disconnected &&\r
- (!parityError || !enableParity) &&\r
+ (!parityError || !enableParity) &&\r
s2s_elapsedTime_ms(dmaFinishTime) >= 180)\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'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
+ // 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
disconnected = 1;\r
- }\r
+ }\r
}\r
\r
if (scsiDev.resetFlag)\r
else\r
{\r
while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY) {} // Waits for DMA to complete\r
- SDMMC_CmdStopTransfer(hsd.Instance);\r
+ if (lastWriteSize > 1)\r
+ {\r
+ SDMMC_CmdStopTransfer(hsd.Instance);\r
+ }\r
}\r
\r
HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd);\r
while ((cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_RECEIVING) &&\r
- s2s_elapsedTime_ms(dmaFinishTime) < 180)\r
+ s2s_elapsedTime_ms(dmaFinishTime) < 180)\r
{\r
// Wait while the SD card is writing buffer to flash\r
// The card may remain in the RECEIVING state (even though it's programming) if\r
cardState = HAL_SD_GetCardState(&hsd);\r
}\r
\r
- if (!disconnected && \r
+ if (!disconnected && \r
i + sectors >= totalSDSectors &&\r
- (!parityError || !enableParity))\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'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
+ (!parityError || !enableParity))\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'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
\r
cardState = HAL_SD_GetCardState(&hsd);\r
while (cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_RECEIVING) \r
cardState = HAL_SD_GetCardState(&hsd);\r
}\r
\r
- i += sectors;\r
- }\r
- else\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
- // possible in each SD card transaction.\r
- // use sg_dd from sg_utils3 tools to test.\r
-\r
- uint32_t rem = totalSDSectors - i;\r
- uint32_t sectors = rem < maxSectors ? rem : maxSectors;\r
-\r
- if (useSlowDataCount)\r
- {\r
- scsiSetDataCount(sectors * bytesPerSector);\r
- }\r
-\r
- for (int scsiSector = i; scsiSector < i + sectors; ++scsiSector)\r
- {\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
-\r
- scsiReadPIO(&scsiDev.data[SD_SECTOR_SIZE * (scsiSector - i)], dmaBytes, &parityError);\r
- }\r
- if (!parityError || !enableParity)\r
- {\r
- BSP_SD_WriteBlocks_DMA(&scsiDev.data[0], i + sdLBA, sectors);\r
- }\r
- i += sectors;\r
- }\r
- }\r
-\r
- // Should already be complete here as we've ready the FIFOs\r
- // by now. Check anyway.\r
- __disable_irq();\r
- while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
- {\r
- __WFI();\r
- }\r
- __enable_irq();\r
-\r
- if (clearBSY)\r
- {\r
- enter_BusFree();\r
- }\r
-\r
- if (scsiDev.phase == DATA_OUT)\r
- {\r
- if (parityError &&\r
- (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))\r
- {\r
- scsiDev.target->sense.code = ABORTED_COMMAND;\r
- scsiDev.target->sense.asc = SCSI_PARITY_ERROR;\r
- scsiDev.status = CHECK_CONDITION;;\r
- }\r
- scsiDev.phase = STATUS;\r
- }\r
- scsiDiskReset();\r
- }\r
+ i += sectors;\r
+ }\r
+ else\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
+ // possible in each SD card transaction.\r
+ // use sg_dd from sg_utils3 tools to test.\r
+\r
+ uint32_t rem = totalSDSectors - i;\r
+ uint32_t sectors = rem < maxSectors ? rem : maxSectors;\r
+\r
+ if (useSlowDataCount)\r
+ {\r
+ scsiSetDataCount(sectors * bytesPerSector);\r
+ }\r
+\r
+ for (int scsiSector = i; scsiSector < i + sectors; ++scsiSector)\r
+ {\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
+\r
+ scsiReadPIO(&scsiDev.data[SD_SECTOR_SIZE * (scsiSector - i)], dmaBytes, &parityError);\r
+ }\r
+ if (!parityError || !enableParity)\r
+ {\r
+ BSP_SD_WriteBlocks_DMA(&scsiDev.data[0], i + sdLBA, sectors);\r
+ }\r
+ i += sectors;\r
+ }\r
+ }\r
+\r
+ // Should already be complete here as we've ready the FIFOs\r
+ // by now. Check anyway.\r
+ __disable_irq();\r
+ while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))\r
+ {\r
+ __WFI();\r
+ }\r
+ __enable_irq();\r
+\r
+ if (clearBSY)\r
+ {\r
+ enter_BusFree();\r
+ }\r
+\r
+ if (scsiDev.phase == DATA_OUT)\r
+ {\r
+ if (parityError &&\r
+ (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))\r
+ {\r
+ scsiDev.target->sense.code = ABORTED_COMMAND;\r
+ scsiDev.target->sense.asc = SCSI_PARITY_ERROR;\r
+ scsiDev.status = CHECK_CONDITION;;\r
+ }\r
+ scsiDev.phase = STATUS;\r
+ }\r
+ scsiDiskReset();\r
+ }\r
}\r
\r
void scsiDiskReset()\r
{\r
- scsiDev.dataPtr = 0;\r
- scsiDev.savedDataPtr = 0;\r
- scsiDev.dataLen = 0;\r
- // transfer.lba = 0; // Needed in Request Sense to determine failure\r
- transfer.blocks = 0;\r
- transfer.currentBlock = 0;\r
-\r
- // Cancel long running commands!\r
+ scsiDev.dataPtr = 0;\r
+ scsiDev.savedDataPtr = 0;\r
+ scsiDev.dataLen = 0;\r
+ // transfer.lba = 0; // Needed in Request Sense to determine failure\r
+ transfer.blocks = 0;\r
+ transfer.currentBlock = 0;\r
+\r
+ // Cancel long running commands!\r
#if 0\r
- if (\r
- ((scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE) == 0) ||\r
- (transfer.multiBlock == 0)\r
- )\r
+ if (\r
+ ((scsiDev.boardCfg.flags & S2S_CFG_ENABLE_CACHE) == 0) ||\r
+ (transfer.multiBlock == 0)\r
+ )\r
#endif\r
- {\r
- sdCompleteTransfer();\r
- }\r
+ {\r
+ sdCompleteTransfer();\r
+ }\r
\r
- transfer.multiBlock = 0;\r
+ transfer.multiBlock = 0;\r
}\r
\r
void scsiDiskInit()\r
{\r
- scsiDiskReset();\r
+ scsiDiskReset();\r
\r
- // Don't require the host to send us a START STOP UNIT command\r
- blockDev.state = DISK_STARTED;\r
+ // Don't require the host to send us a START STOP UNIT command\r
+ blockDev.state = DISK_STARTED;\r
}\r
\r