Fix errors reading the last sector of SD card.
authorMichael McMaster <michael@codesrc.com>
Mon, 23 Dec 2013 12:59:31 +0000 (22:59 +1000)
committerMichael McMaster <michael@codesrc.com>
Mon, 23 Dec 2013 12:59:31 +0000 (22:59 +1000)
software/SCSI2SD/SCSI2SD.cydsn/disk.c
software/SCSI2SD/SCSI2SD.cydsn/disk.h
software/SCSI2SD/SCSI2SD.cydsn/sd.c
software/SCSI2SD/SCSI2SD.cydsn/sd.h

index 20de53b..c94aaa8 100755 (executable)
@@ -118,6 +118,10 @@ static void doWrite(uint32 lba, uint32 blocks)
                scsiDev.phase = DATA_OUT;\r
                scsiDev.dataLen = SCSI_BLOCK_SIZE;\r
                scsiDev.dataPtr = SCSI_BLOCK_SIZE; // TODO FIX scsiDiskPoll()\r
+               \r
+               // No need for single-block reads atm.  Overhead of the\r
+               // multi-block read is minimal.\r
+               transfer.multiBlock = 1;\r
                sdPrepareWrite();\r
        }\r
 }\r
@@ -140,7 +144,20 @@ static void doRead(uint32 lba, uint32 blocks)
                transfer.currentBlock = 0;\r
                scsiDev.phase = DATA_IN;\r
                scsiDev.dataLen = 0; // No data yet\r
-               sdPrepareRead();\r
+               \r
+               if ((blocks == 1) ||\r
+                       (((uint64) lba) + blocks == blockDev.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
+                       sdPrepareRead();\r
+               }               \r
        }\r
 }\r
 \r
@@ -352,7 +369,14 @@ void scsiDiskPoll()
        {\r
                if (scsiDev.dataLen == 0)\r
                {\r
-                       sdReadSector();\r
+                       if (transfer.multiBlock)\r
+                       {\r
+                               sdReadSectorMulti();\r
+                       }\r
+                       else\r
+                       {\r
+                               sdReadSectorSingle();\r
+                       }\r
                }\r
                else if (scsiDev.dataPtr == scsiDev.dataLen)\r
                {\r
@@ -361,9 +385,13 @@ void scsiDiskPoll()
                        transfer.currentBlock++;\r
                        if (transfer.currentBlock >= transfer.blocks)\r
                        {\r
+                               int needComplete = transfer.multiBlock;\r
                                scsiDev.phase = STATUS;\r
                                scsiDiskReset();\r
-                               sdCompleteRead();\r
+                               if (needComplete)\r
+                               {\r
+                                       sdCompleteRead();\r
+                               }\r
                        }\r
                }\r
        }\r
@@ -378,6 +406,7 @@ void scsiDiskPoll()
                        scsiDev.dataLen = 0;\r
                        scsiDev.dataPtr = 0;\r
                        scsiDev.phase = STATUS;\r
+                       \r
                        scsiDiskReset();\r
 \r
                        if (writeOk)\r
@@ -397,6 +426,7 @@ void scsiDiskReset()
        transfer.lba = 0;\r
        transfer.blocks = 0;\r
        transfer.currentBlock = 0;\r
+       transfer.multiBlock = 0;\r
 }\r
 \r
 void scsiDiskInit()\r
index 2133279..a58425f 100755 (executable)
@@ -42,6 +42,7 @@ typedef struct
 typedef struct
 {
        int dir;
+       int multiBlock; // True if we're using a multi-block SPI transfer.
        uint32 lba;
        uint32 blocks;
 
index a35ea6e..bf2d12c 100755 (executable)
@@ -147,7 +147,7 @@ void sdPrepareRead()
        }\r
 }\r
 \r
-void sdReadSector()\r
+static void doReadSector()\r
 {\r
        int prep, i, guard;\r
        \r
@@ -163,7 +163,10 @@ void sdReadSector()
        }\r
        if (token != 0xFE)\r
        {\r
-               sdCompleteRead();\r
+               if (transfer.multiBlock)\r
+               {\r
+                       sdCompleteRead();\r
+               }\r
                if (scsiDev.status != CHECK_CONDITION)\r
                {\r
                        scsiDev.status = CHECK_CONDITION;\r
@@ -235,6 +238,39 @@ void sdReadSector()
        scsiDev.dataPtr = SCSI_BLOCK_SIZE;\r
 }\r
 \r
+void sdReadSectorSingle()\r
+{\r
+       uint8 v;\r
+       uint32 len = (transfer.lba + transfer.currentBlock);\r
+       if (!sdDev.ccs)\r
+       {\r
+               len = len * SCSI_BLOCK_SIZE;\r
+       }       \r
+       v = sdCommandAndResponse(SD_READ_SINGLE_BLOCK, len);\r
+       if (v)\r
+       {\r
+               scsiDiskReset();\r
+               sdClearStatus();\r
+\r
+               scsiDev.status = CHECK_CONDITION;\r
+               scsiDev.sense.code = HARDWARE_ERROR;\r
+               scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;\r
+               scsiDev.phase = STATUS;\r
+       }\r
+       else\r
+       {\r
+               doReadSector();\r
+       }\r
+}\r
+\r
+void sdReadSectorMulti()\r
+{\r
+       // Pre: sdPrepareRead called.\r
+       \r
+       doReadSector();\r
+}\r
+\r
+\r
 void sdCompleteRead()\r
 {\r
        // We cannot send even a single "padding" byte, as we normally would when\r
@@ -294,8 +330,6 @@ int sdWriteSector()
                scsiEnterPhase(DATA_OUT);\r
        }\r
        \r
-       // Wait for a previously-written sector to complete.\r
-       sdWaitWriteBusy();\r
        sdSpiByte(0xFC); // MULTIPLE byte start token\r
        \r
        prep = 0;\r
@@ -382,8 +416,7 @@ int sdWriteSector()
        }\r
        else\r
        {\r
-               // The card is probably in the busy state.\r
-               // Don't wait, as we could read the SCSI interface instead.\r
+               sdWaitWriteBusy();\r
                result = 1;\r
        }\r
 \r
@@ -394,9 +427,6 @@ void sdCompleteWrite()
 {\r
        uint8 r1, r2;\r
        \r
-       // Wait for a previously-written sector to complete.\r
-       sdWaitWriteBusy();\r
-\r
        sdSpiByte(0xFD); // STOP TOKEN\r
        // Wait for the card to come out of busy.\r
        sdWaitWriteBusy();\r
index 7cdca9a..7eb8fcf 100755 (executable)
@@ -26,6 +26,7 @@ typedef enum
        SD_STOP_TRANSMISSION = 12,
        SD_SEND_STATUS = 13,
        SD_SET_BLOCKLEN = 16,
+       SD_READ_SINGLE_BLOCK = 17,
        SD_READ_MULTIPLE_BLOCK = 18,
        SD_APP_SET_WR_BLK_ERASE_COUNT = 23,
        SD_APP_SEND_OP_COND = 41,
@@ -60,7 +61,8 @@ int sdWriteSector(void);
 void sdCompleteWrite(void);
 
 void sdPrepareRead(void);
-void sdReadSector(void);
+void sdReadSectorMulti(void);
+void sdReadSectorSingle(void);
 void sdCompleteRead(void);
 
 #endif