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
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
{\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
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
scsiDev.dataLen = 0;\r
scsiDev.dataPtr = 0;\r
scsiDev.phase = STATUS;\r
+ \r
scsiDiskReset();\r
\r
if (writeOk)\r
transfer.lba = 0;\r
transfer.blocks = 0;\r
transfer.currentBlock = 0;\r
+ transfer.multiBlock = 0;\r
}\r
\r
void scsiDiskInit()\r
typedef struct
{
int dir;
+ int multiBlock; // True if we're using a multi-block SPI transfer.
uint32 lba;
uint32 blocks;
}\r
}\r
\r
-void sdReadSector()\r
+static void doReadSector()\r
{\r
int prep, i, guard;\r
\r
}\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
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
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
}\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
{\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
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,
void sdCompleteWrite(void);
void sdPrepareRead(void);
-void sdReadSector(void);
+void sdReadSectorMulti(void);
+void sdReadSectorSingle(void);
void sdCompleteRead(void);
#endif