Fix errors reading the last sector of SD card.

This commit is contained in:
Michael McMaster 2013-12-23 22:59:31 +10:00
parent 0629f76919
commit 09782fcdc5
4 changed files with 76 additions and 13 deletions

View File

@ -118,6 +118,10 @@ static void doWrite(uint32 lba, uint32 blocks)
scsiDev.phase = DATA_OUT;
scsiDev.dataLen = SCSI_BLOCK_SIZE;
scsiDev.dataPtr = SCSI_BLOCK_SIZE; // TODO FIX scsiDiskPoll()
// No need for single-block reads atm. Overhead of the
// multi-block read is minimal.
transfer.multiBlock = 1;
sdPrepareWrite();
}
}
@ -140,7 +144,20 @@ static void doRead(uint32 lba, uint32 blocks)
transfer.currentBlock = 0;
scsiDev.phase = DATA_IN;
scsiDev.dataLen = 0; // No data yet
sdPrepareRead();
if ((blocks == 1) ||
(((uint64) lba) + blocks == blockDev.capacity)
)
{
// We get errors on reading the last sector using a multi-sector
// read :-(
transfer.multiBlock = 0;
}
else
{
transfer.multiBlock = 1;
sdPrepareRead();
}
}
}
@ -352,7 +369,14 @@ void scsiDiskPoll()
{
if (scsiDev.dataLen == 0)
{
sdReadSector();
if (transfer.multiBlock)
{
sdReadSectorMulti();
}
else
{
sdReadSectorSingle();
}
}
else if (scsiDev.dataPtr == scsiDev.dataLen)
{
@ -361,9 +385,13 @@ void scsiDiskPoll()
transfer.currentBlock++;
if (transfer.currentBlock >= transfer.blocks)
{
int needComplete = transfer.multiBlock;
scsiDev.phase = STATUS;
scsiDiskReset();
sdCompleteRead();
if (needComplete)
{
sdCompleteRead();
}
}
}
}
@ -378,6 +406,7 @@ void scsiDiskPoll()
scsiDev.dataLen = 0;
scsiDev.dataPtr = 0;
scsiDev.phase = STATUS;
scsiDiskReset();
if (writeOk)
@ -397,6 +426,7 @@ void scsiDiskReset()
transfer.lba = 0;
transfer.blocks = 0;
transfer.currentBlock = 0;
transfer.multiBlock = 0;
}
void scsiDiskInit()

View File

@ -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;

View File

@ -147,7 +147,7 @@ void sdPrepareRead()
}
}
void sdReadSector()
static void doReadSector()
{
int prep, i, guard;
@ -163,7 +163,10 @@ void sdReadSector()
}
if (token != 0xFE)
{
sdCompleteRead();
if (transfer.multiBlock)
{
sdCompleteRead();
}
if (scsiDev.status != CHECK_CONDITION)
{
scsiDev.status = CHECK_CONDITION;
@ -235,6 +238,39 @@ void sdReadSector()
scsiDev.dataPtr = SCSI_BLOCK_SIZE;
}
void sdReadSectorSingle()
{
uint8 v;
uint32 len = (transfer.lba + transfer.currentBlock);
if (!sdDev.ccs)
{
len = len * SCSI_BLOCK_SIZE;
}
v = sdCommandAndResponse(SD_READ_SINGLE_BLOCK, len);
if (v)
{
scsiDiskReset();
sdClearStatus();
scsiDev.status = CHECK_CONDITION;
scsiDev.sense.code = HARDWARE_ERROR;
scsiDev.sense.asc = LOGICAL_UNIT_COMMUNICATION_FAILURE;
scsiDev.phase = STATUS;
}
else
{
doReadSector();
}
}
void sdReadSectorMulti()
{
// Pre: sdPrepareRead called.
doReadSector();
}
void sdCompleteRead()
{
// We cannot send even a single "padding" byte, as we normally would when
@ -294,8 +330,6 @@ int sdWriteSector()
scsiEnterPhase(DATA_OUT);
}
// Wait for a previously-written sector to complete.
sdWaitWriteBusy();
sdSpiByte(0xFC); // MULTIPLE byte start token
prep = 0;
@ -382,8 +416,7 @@ int sdWriteSector()
}
else
{
// The card is probably in the busy state.
// Don't wait, as we could read the SCSI interface instead.
sdWaitWriteBusy();
result = 1;
}
@ -394,9 +427,6 @@ void sdCompleteWrite()
{
uint8 r1, r2;
// Wait for a previously-written sector to complete.
sdWaitWriteBusy();
sdSpiByte(0xFD); // STOP TOKEN
// Wait for the card to come out of busy.
sdWaitWriteBusy();

View File

@ -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