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,9 +144,22 @@ static void doRead(uint32 lba, uint32 blocks)
transfer.currentBlock = 0;
scsiDev.phase = DATA_IN;
scsiDev.dataLen = 0; // No data yet
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();
}
}
}
static void doSeek(uint32 lba)
{
@@ -352,7 +369,14 @@ void scsiDiskPoll()
{
if (scsiDev.dataLen == 0)
{
sdReadSector();
if (transfer.multiBlock)
{
sdReadSectorMulti();
}
else
{
sdReadSectorSingle();
}
}
else if (scsiDev.dataPtr == scsiDev.dataLen)
{
@@ -361,12 +385,16 @@ void scsiDiskPoll()
transfer.currentBlock++;
if (transfer.currentBlock >= transfer.blocks)
{
int needComplete = transfer.multiBlock;
scsiDev.phase = STATUS;
scsiDiskReset();
if (needComplete)
{
sdCompleteRead();
}
}
}
}
else if (scsiDev.phase == DATA_OUT &&
transfer.currentBlock != transfer.blocks)
{
@@ -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;
@@ -162,8 +162,11 @@ void sdReadSector()
token = sdSpiByte(0xFF);
}
if (token != 0xFE)
{
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