Browse Source

Fix errors reading the last sector of SD card.

Michael McMaster 12 years ago
parent
commit
50b54691aa

+ 33 - 3
lib/SCSI2SD/software/SCSI2SD/SCSI2SD.cydsn/disk.c

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

+ 1 - 0
lib/SCSI2SD/software/SCSI2SD/SCSI2SD.cydsn/disk.h

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

+ 39 - 9
lib/SCSI2SD/software/SCSI2SD/SCSI2SD.cydsn/sd.c

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

+ 3 - 1
lib/SCSI2SD/software/SCSI2SD/SCSI2SD.cydsn/sd.h

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