Don't send SD Complete Transfer command for single block writes v6.4.6
authorMichael McMaster <michael@codesrc.com>
Thu, 13 May 2021 11:53:09 +0000 (21:53 +1000)
committerMichael McMaster <michael@codesrc.com>
Thu, 13 May 2021 11:53:09 +0000 (21:53 +1000)
src/firmware/bsp_driver_sd.c
src/firmware/config.c
src/firmware/disk.c
src/firmware/main.c

index dda58d9d7a2ba5e38cda919f88817e4564f339c4..e972c98ff818aa38b724cd201774f82fac5ec4c4 100755 (executable)
@@ -248,6 +248,12 @@ uint8_t BSP_SD_ReadBlocks_DMA(uint8_t *pData, uint64_t BlockAddr, uint32_t NumOf
     {
       SD_state = MSD_OK;
     }
+
+    HAL_SD_CardStateTypeDef cardState = HAL_SD_GetCardState(&hsd);
+    while (cardState == HAL_SD_CARD_PROGRAMMING || cardState == HAL_SD_CARD_SENDING) 
+    {
+        cardState = HAL_SD_GetCardState(&hsd);
+    }
   }
   
   return SD_state; 
@@ -291,7 +297,11 @@ uint8_t BSP_SD_WriteBlocks_DMA(uint8_t *pData, uint64_t BlockAddr, uint32_t NumO
     }
 
     while (HAL_SD_GetState(&hsd) == HAL_SD_STATE_BUSY) {} // Wait for DMA to complete
-    SDMMC_CmdStopTransfer(hsd.Instance);
+
+    if (NumOfBlocks > 1)
+    {
+        SDMMC_CmdStopTransfer(hsd.Instance);
+    }
 
     if(HAL_SD_GetState(&hsd) == HAL_SD_STATE_ERROR)
     {
index a016f6fc97ad106cdb62028c5f429f176feff6ca..109b856f0670df171a68a0e37734629cea85c2a1 100755 (executable)
@@ -36,7 +36,7 @@
 \r
 #include <string.h>\r
 \r
-static const uint16_t FIRMWARE_VERSION = 0x0645;\r
+static const uint16_t FIRMWARE_VERSION = 0x0646;\r
 \r
 // Optional static config\r
 extern uint8_t* __fixed_config;\r
index 26962d939536a2f7aefdc101c6c17dfc4ce44a2c..c9c7ae4596c5c3e7f0b336b453618477ff05d919 100755 (executable)
@@ -1,20 +1,20 @@
-//     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
@@ -46,728 +46,744 @@ Transfer transfer;
 \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
@@ -780,45 +796,45 @@ void scsiDiskPoll()
                             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
@@ -828,12 +844,15 @@ void scsiDiskPoll()
                 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
@@ -841,20 +860,20 @@ void scsiDiskPoll()
                     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
@@ -865,99 +884,99 @@ void scsiDiskPoll()
                     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
index caea8e20a5d911ccc8de2b68e9384a2cf5562aa9..c7dd55425474ae561fa20e0ff96f83fccd07cc7d 100755 (executable)
@@ -1,19 +1,19 @@
-//     Copyright (C) 2014 Michael McMaster <michael@codesrc.com>\r
+//    Copyright (C) 2014 Michael McMaster <michael@codesrc.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
@@ -38,6 +38,8 @@
 #include "usb_device/usbd_composite.h"\r
 #include "usb_device/usbd_msc_storage_sd.h"\r
 \r
+#include "bsp_driver_sd.h"\r
+\r
 const char* Notice = "Copyright (C) 2020 Michael McMaster <michael@codesrc.com>";\r
 uint32_t lastSDPoll;\r
 \r
@@ -47,107 +49,132 @@ static int isUsbStarted;
 void mainEarlyInit()\r
 {\r
 #ifdef nULPI_RESET_GPIO_Port\r
-       // Disable the ULPI chip\r
-       HAL_GPIO_WritePin(nULPI_RESET_GPIO_Port, nULPI_RESET_Pin, GPIO_PIN_RESET);\r
+    // Disable the ULPI chip\r
+    HAL_GPIO_WritePin(nULPI_RESET_GPIO_Port, nULPI_RESET_Pin, GPIO_PIN_RESET);\r
 #endif\r
 \r
-       // Sets up function pointers only\r
-       s2s_initUsbDeviceStorage();\r
+    // Sets up function pointers only\r
+    s2s_initUsbDeviceStorage();\r
 }\r
 \r
 void mainInit()\r
 {\r
-       s2s_timeInit();\r
-       s2s_checkHwVersion();\r
-\r
-       s2s_ledInit();\r
-       s2s_fpgaInit();\r
-\r
-       scsiPhyInit();\r
-\r
-       scsiDiskInit();\r
-       sdInit();\r
-       s2s_configInit(&scsiDev.boardCfg);\r
-       scsiPhyConfig();\r
-       scsiInit();\r
-\r
-       #ifdef S2S_USB_HS\r
-               // Enable the ULPI chip\r
-               HAL_GPIO_WritePin(nULPI_RESET_GPIO_Port, nULPI_RESET_Pin, GPIO_PIN_SET);\r
-               s2s_delay_ms(5);\r
-       #endif\r
-\r
-       MX_USB_DEVICE_Init(); // USB lun config now available.\r
-       isUsbStarted = 1;\r
-\r
-       // Optional bootup delay\r
-       int delaySeconds = 0;\r
-       while (delaySeconds < scsiDev.boardCfg.startupDelay) {\r
-               // Keep the USB connection working, otherwise it's very hard to revert\r
-               // silly extra-long startup delay settings.\r
-               int i;\r
-               for (i = 0; i < 200; i++) {\r
-                       s2s_delay_ms(5);\r
-                       scsiDev.watchdogTick++;\r
-                       s2s_configPoll();\r
-               }\r
-               ++delaySeconds;\r
-       }\r
-\r
-       lastSDPoll = s2s_getTime_ms();\r
+    s2s_timeInit();\r
+    s2s_checkHwVersion();\r
+\r
+    s2s_ledInit();\r
+    s2s_fpgaInit();\r
+\r
+    scsiPhyInit();\r
+\r
+    scsiDiskInit();\r
+    sdInit();\r
+    s2s_configInit(&scsiDev.boardCfg);\r
+    scsiPhyConfig();\r
+    scsiInit();\r
+\r
+    #ifdef S2S_USB_HS\r
+        // Enable the ULPI chip\r
+        HAL_GPIO_WritePin(nULPI_RESET_GPIO_Port, nULPI_RESET_Pin, GPIO_PIN_SET);\r
+        s2s_delay_ms(5);\r
+    #endif\r
+\r
+    MX_USB_DEVICE_Init(); // USB lun config now available.\r
+    isUsbStarted = 1;\r
+\r
+    // Optional bootup delay\r
+    int delaySeconds = 0;\r
+    while (delaySeconds < scsiDev.boardCfg.startupDelay) {\r
+        // Keep the USB connection working, otherwise it's very hard to revert\r
+        // silly extra-long startup delay settings.\r
+        int i;\r
+        for (i = 0; i < 200; i++) {\r
+            s2s_delay_ms(5);\r
+            scsiDev.watchdogTick++;\r
+            s2s_configPoll();\r
+        }\r
+        ++delaySeconds;\r
+    }\r
+\r
+#ifdef TEST_SD_CARDS\r
+    s2s_ledOn();\r
+    for (int h = 0; h < 1000; ++h)\r
+    {\r
+        uint8_t g = BSP_SD_ReadBlocks_DMA(scsiDev.data, (1000 - h) * 1000, 64);\r
+        if (g != MSD_OK)\r
+        {\r
+            while (1) {}\r
+        }\r
+        if (h & 1)\r
+        {\r
+            uint8_t r = BSP_SD_ReadBlocks_DMA(scsiDev.data, h * 1000, 1);\r
+            if (r != MSD_OK)\r
+            {\r
+                while (1) {}\r
+            }\r
+        }\r
+        else\r
+        {\r
+            BSP_SD_WriteBlocks_DMA(scsiDev.data, h * 2000, 1);\r
+        }\r
+    }\r
+    s2s_ledOff();\r
+#endif\r
+\r
+    lastSDPoll = s2s_getTime_ms();\r
 }\r
 \r
 void mainLoop()\r
 {\r
-       scsiDev.watchdogTick++;\r
+    scsiDev.watchdogTick++;\r
 \r
-       scsiPoll();\r
-       scsiDiskPoll();\r
-       s2s_configPoll();\r
+    scsiPoll();\r
+    scsiDiskPoll();\r
+    s2s_configPoll();\r
 \r
 #ifdef S2S_USB_FS\r
-       int usbBusy = s2s_usbDevicePoll(&hUsbDeviceFS);\r
+    int usbBusy = s2s_usbDevicePoll(&hUsbDeviceFS);\r
 #endif\r
 #ifdef S2S_USB_HS\r
-       int usbBusy = s2s_usbDevicePoll(&hUsbDeviceHS);\r
+    int usbBusy = s2s_usbDevicePoll(&hUsbDeviceHS);\r
 #endif\r
 \r
 #if 0\r
-       sdPoll();\r
+    sdPoll();\r
 #endif\r
 \r
     // TODO test if USB transfer is in progress\r
-       if (unlikely(scsiDev.phase == BUS_FREE) && !usbBusy)\r
-       {\r
-               if (unlikely(s2s_elapsedTime_ms(lastSDPoll) > 200))\r
-               {\r
-                       lastSDPoll = s2s_getTime_ms();\r
-                       if (sdInit())\r
-                       {\r
-                               s2s_configInit(&scsiDev.boardCfg);\r
-                               scsiPhyConfig();\r
-                               scsiInit();\r
-\r
-                               if (isUsbStarted)\r
-                               {\r
+    if (unlikely(scsiDev.phase == BUS_FREE) && !usbBusy)\r
+    {\r
+        if (unlikely(s2s_elapsedTime_ms(lastSDPoll) > 200))\r
+        {\r
+            lastSDPoll = s2s_getTime_ms();\r
+            if (sdInit())\r
+            {\r
+                s2s_configInit(&scsiDev.boardCfg);\r
+                scsiPhyConfig();\r
+                scsiInit();\r
+\r
+                if (isUsbStarted)\r
+                {\r
 #ifdef S2S_USB_FS\r
-                                       USBD_Stop(&hUsbDeviceFS);\r
-                                       s2s_delay_ms(128);\r
-                                       USBD_Start(&hUsbDeviceFS);\r
+                    USBD_Stop(&hUsbDeviceFS);\r
+                    s2s_delay_ms(128);\r
+                    USBD_Start(&hUsbDeviceFS);\r
 #endif\r
 #ifdef S2S_USB_HS\r
-                                       USBD_Stop(&hUsbDeviceHS);\r
-                                       s2s_delay_ms(128);\r
-                                       USBD_Start(&hUsbDeviceHS);\r
+                    USBD_Stop(&hUsbDeviceHS);\r
+                    s2s_delay_ms(128);\r
+                    USBD_Start(&hUsbDeviceHS);\r
 #endif\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       else if (usbBusy || ((scsiDev.phase >= 0) && (blockDev.state & DISK_PRESENT)))\r
-       {\r
-               // don't waste time scanning SD cards while we're doing disk IO\r
-               lastSDPoll = s2s_getTime_ms();\r
-       }\r
+                }\r
+            }\r
+        }\r
+    }\r
+    else if (usbBusy || ((scsiDev.phase >= 0) && (blockDev.state & DISK_PRESENT)))\r
+    {\r
+        // don't waste time scanning SD cards while we're doing disk IO\r
+        lastSDPoll = s2s_getTime_ms();\r
+    }\r
 }\r
 \r