Browse Source

SD hotswap, SD fixes, SCSI interface fixes, performance improvements.

Michael McMaster 9 years ago
parent
commit
74ca5dc83a

+ 6 - 0
lib/SCSI2SD/CHANGELOG

@@ -1,2 +1,8 @@
+20160616		6.01
+	- Improved SD card compatibility
+	- Fixed SCSI interfaces on slower SCSI controllers
+	- Significant performance improvements
+	- Added SD card hotswap support.
+
 20160528		6.0
 	- First BETA firmware for the 6.0 hardware version of the SCSI2SD.

+ 0 - 1
lib/SCSI2SD/STM32CubeMX/SCSI2SD-V6/Drivers/STM32F2xx_HAL_Driver/Src/stm32f2xx_hal_sd.c

@@ -178,7 +178,6 @@
 
 /* Includes ------------------------------------------------------------------*/
 #include "stm32f2xx_hal.h"
-
 #ifdef HAL_SD_MODULE_ENABLED
 
 /** @addtogroup STM32F2xx_HAL_Driver

+ 4 - 2
lib/SCSI2SD/STM32CubeMX/SCSI2SD-V6/Src/sdio.c

@@ -84,14 +84,16 @@ void HAL_SD_MspInit(SD_HandleTypeDef* hsd)
     GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 
                           |GPIO_PIN_12;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
-    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    //GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Pull = GPIO_PULLUP; // MM
     GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
     GPIO_InitStruct.Pin = GPIO_PIN_2;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
-    GPIO_InitStruct.Pull = GPIO_NOPULL;
+    //GPIO_InitStruct.Pull = GPIO_NOPULL;
+    GPIO_InitStruct.Pull = GPIO_PULLUP; // MM
     GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

BIN
lib/SCSI2SD/doc/SCSI2SD_QuickStartGuide.odt


+ 6 - 1
lib/SCSI2SD/include/scsi2sd.h

@@ -192,7 +192,12 @@ typedef enum
 	// uint32_t Sector Number (MSB)
 	// Response:
 	// 512 bytes of data
-	S2S_CMD_SD_READ
+	S2S_CMD_SD_READ,
+
+	// Command content:
+	// uint8_t S2S_CFG_DEBUG
+	// Response:
+	S2S_CMD_DEBUG,
 } S2S_COMMAND;
 
 typedef enum

BIN
lib/SCSI2SD/rtl/fpga_bitmap.o


+ 59 - 18
lib/SCSI2SD/src/firmware/config.c

@@ -38,7 +38,7 @@
 
 #include <string.h>
 
-static const uint16_t FIRMWARE_VERSION = 0x0600;
+static const uint16_t FIRMWARE_VERSION = 0x0601;
 
 // 1 flash row
 static const uint8_t DEFAULT_CONFIG[128] =
@@ -68,19 +68,6 @@ static int usbDebugEpState;
 #endif
 static int usbReady; // TODO MM REMOVE. Unused ?
 
-static void initS2S_BoardCfg(S2S_BoardCfg* config) {
-	if (memcmp(config->magic, "BCFG", 4)) {
-		config->selectionDelay = 255; // auto
-		config->flags6 = S2S_CFG_ENABLE_TERMINATOR;
-
-		memcpy(
-			s2s_cfg + sizeof(S2S_BoardCfg),
-			DEFAULT_CONFIG,
-			sizeof(S2S_TargetCfg));
-	}
-}
-
-
 void s2s_configInit(S2S_BoardCfg* config)
 {
 
@@ -88,7 +75,7 @@ void s2s_configInit(S2S_BoardCfg* config)
 	usbReady = 0; // We don't know if host is connected yet.
 
 
-	if (blockDev.state & DISK_PRESENT && sdDev.capacity)
+	if ((blockDev.state & DISK_PRESENT) && sdDev.capacity)
 	{
 		int cfgSectors = (S2S_CFG_SIZE + 511) / 512;
 		BSP_SD_ReadBlocks_DMA(
@@ -98,11 +85,35 @@ void s2s_configInit(S2S_BoardCfg* config)
 			cfgSectors);
 
 		memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));
-	}
 
-	initS2S_BoardCfg(config);
+		if (memcmp(config->magic, "BCFG", 4))
+		{
+			// Invalid SD card config, use default.
+			memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);
+			memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));
+			memcpy(config->magic, "BCFG", 4);
+			config->selectionDelay = 255; // auto
+			config->flags6 = S2S_CFG_ENABLE_TERMINATOR;
+
+			memcpy(
+				&s2s_cfg[0] + sizeof(S2S_BoardCfg),
+				DEFAULT_CONFIG,
+				sizeof(S2S_TargetCfg));
+		}
+	}
+	else
+	{
+		// No SD card, use existing config if valid
+		if (memcmp(config->magic, "BCFG", 4))
+		{
+			// Not valid, use empty config with no disks.
+			memset(&s2s_cfg[0], 0, S2S_CFG_SIZE);
+			memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));
+			config->selectionDelay = 255; // auto
+			config->flags6 = S2S_CFG_ENABLE_TERMINATOR;
+		}
+	}
 
-	scsiPhyConfig();
 }
 
 
@@ -154,6 +165,32 @@ scsiDevInfoCommand()
 	hidPacket_send(response, sizeof(response));
 }
 
+static void
+debugCommand()
+{
+	uint8_t response[32];
+	memcpy(&response, &scsiDev.cdb, 12);
+	response[12] = scsiDev.msgIn;
+	response[13] = scsiDev.msgOut;
+	response[14] = scsiDev.lastStatus;
+	response[15] = scsiDev.lastSense;
+	response[16] = scsiDev.phase;
+	response[17] = scsiStatusBSY();
+	response[18] = *SCSI_STS_SELECTED;
+	response[19] = scsiStatusATN();
+	response[20] = scsiStatusRST();
+	response[21] = scsiDev.rstCount;
+	response[22] = scsiDev.selCount;
+	response[23] = scsiDev.msgCount;
+	response[24] = scsiDev.cmdCount;
+	response[25] = scsiDev.watchdogTick;
+	response[26] = blockDev.state;
+	response[27] = scsiDev.lastSenseASC >> 8;
+	response[28] = scsiDev.lastSenseASC;
+	response[29] = *SCSI_STS_DBX;
+	response[30] = LastTrace;
+	hidPacket_send(response, sizeof(response));
+}
 
 static void
 sdWriteCommand(const uint8_t* cmd, size_t cmdSize)
@@ -230,6 +267,10 @@ processCommand(const uint8_t* cmd, size_t cmdSize)
 		sdReadCommand(cmd, cmdSize);
 		break;
 
+	case S2S_CMD_DEBUG:
+		debugCommand();
+		break;
+
 	case S2S_CMD_NONE: // invalid
 	default:
 		break;

+ 7 - 16
lib/SCSI2SD/src/firmware/disk.c

@@ -35,12 +35,7 @@ static int doSdInit()
 	int result = 0;
 	if (blockDev.state & DISK_PRESENT)
 	{
-		result = sdInit();
-
-		if (result)
-		{
-			blockDev.state = blockDev.state | DISK_INITIALISED;
-		}
+		blockDev.state = blockDev.state | DISK_INITIALISED;
 	}
 	return result;
 }
@@ -628,7 +623,6 @@ void scsiDiskPoll()
 				scsiWriteDMA(&scsiDev.data[SD_SECTOR_SIZE * (i % buffers)], dmaBytes);
 				scsiActive = 1;
 			}
-
 		}
 
 		// We've finished transferring the data to the FPGA, now wait until it's
@@ -656,6 +650,11 @@ void scsiDiskPoll()
 
 		const int sdPerScsi = SDSectorsPerSCSISector(bytesPerSector);
 		int totalSDSectors = transfer.blocks * sdPerScsi;
+		uint32_t sdLBA =
+			SCSISector2SD(
+				scsiDev.target->cfg->sdSectorStart,
+				bytesPerSector,
+				transfer.lba);
 		// int buffers = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
 		// int prep = 0;
 		int i = 0;
@@ -677,7 +676,7 @@ void scsiDiskPoll()
 			uint32_t sectors =
 				totalSDSectors < maxSectors ? totalSDSectors : maxSectors;
 			scsiRead(&scsiDev.data[0], sectors * SD_SECTOR_SIZE);
-			sdTmpWrite(&scsiDev.data[0], i + transfer.lba, sectors);
+			sdTmpWrite(&scsiDev.data[0], i + sdLBA, sectors);
 			i += sectors;
 #if 0
 			// Wait for the next DMA interrupt. It's beneficial to halt the
@@ -863,13 +862,5 @@ void scsiDiskInit()
 
 	// Don't require the host to send us a START STOP UNIT command
 	blockDev.state = DISK_STARTED;
-	// WP pin not available for micro-sd
-	// TODO read card WP register
-	#if 0
-	if (SD_WP_Read())
-	{
-		blockDev.state = blockDev.state | DISK_WP;
-	}
-	#endif
 }
 

+ 21 - 10
lib/SCSI2SD/src/firmware/main.c

@@ -32,6 +32,7 @@
 
 
 const char* Notice = "Copyright (C) 2016 Michael McMaster <michael@codesrc.com>";
+uint32_t lastSDPoll;
 
 void mainEarlyInit()
 {
@@ -51,10 +52,11 @@ void mainInit()
 	scsiDiskInit();
 	sdInit();
 	s2s_configInit(&scsiDev.boardCfg);
+	scsiPhyConfig();
+	scsiInit();
 
 	s2s_debugInit();
 
-	scsiInit();
 
 	MX_USB_DEVICE_Init(); // USB lun config now available.
 
@@ -72,10 +74,7 @@ void mainInit()
 		++delaySeconds;
 	}
 
-#if 0
-	uint32_t lastSDPoll = getTime_ms();
-	sdCheckPresent();
-#endif
+	lastSDPoll = s2s_getTime_ms();
 }
 
 void mainLoop()
@@ -89,16 +88,28 @@ void mainLoop()
 
 #if 0
 	sdPoll();
+#endif
 
 	if (unlikely(scsiDev.phase == BUS_FREE))
 	{
-		if (unlikely(elapsedTime_ms(lastSDPoll) > 200))
+		if (unlikely(s2s_elapsedTime_ms(lastSDPoll) > 200))
 		{
-			lastSDPoll = getTime_ms();
-			sdCheckPresent();
+			lastSDPoll = s2s_getTime_ms();
+			if (sdInit())
+			{
+				s2s_configInit(&scsiDev.boardCfg);
+				scsiPhyConfig();
+				scsiInit();
+
+
+				USBD_Stop(&hUsbDeviceFS);
+				s2s_delay_ms(128);
+				USBD_Start(&hUsbDeviceFS);
+			}
 		}
 		else
 		{
+#if 0
 			// Wait for our 1ms timer to save some power.
 			// There's an interrupt on the SEL signal to ensure we respond
 			// quickly to any SCSI commands. The selection abort time is
@@ -110,13 +121,13 @@ void mainLoop()
 				__WFI(); // Will wake on interrupt, regardless of mask
 			}
 			CyExitCriticalSection(interruptState);
+#endif
 		}
 	}
 	else if (scsiDev.phase >= 0)
 	{
 		// don't waste time scanning SD cards while we're doing disk IO
-		lastSDPoll = getTime_ms();
+		lastSDPoll = s2s_getTime_ms();
 	}
-#endif
 }
 

+ 12 - 2
lib/SCSI2SD/src/firmware/scsi.c

@@ -70,6 +70,7 @@ static void enter_BusFree()
 	// Bus settle delay + bus clear delay = 1200ns
 	s2s_delay_us(2);
 
+
 	s2s_ledOff();
 	scsiDev.phase = BUS_FREE;
 }
@@ -459,7 +460,6 @@ static void scsiReset()
 	s2s_ledOff();
 
 	scsiPhyReset();
-	// TODO SCSI_Out_Ctl_Write(0);
 
 	scsiDev.parityError = 0;
 	scsiDev.phase = BUS_FREE;
@@ -896,6 +896,8 @@ void scsiPoll(void)
 
 void scsiInit()
 {
+	static int firstInit = 1;
+
 	scsiDev.atnFlag = 0;
 	scsiDev.resetFlag = 1;
 	scsiDev.phase = BUS_FREE;
@@ -920,10 +922,18 @@ void scsiInit()
 		}
 		scsiDev.targets[i].reservedId = -1;
 		scsiDev.targets[i].reserverId = -1;
-		scsiDev.targets[i].unitAttention = POWER_ON_RESET;
+		if (firstInit)
+		{
+			scsiDev.targets[i].unitAttention = POWER_ON_RESET;
+		}
+		else
+		{
+			scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;
+		}
 		scsiDev.targets[i].sense.code = NO_SENSE;
 		scsiDev.targets[i].sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
 	}
+	firstInit = 0;
 }
 
 /* TODO REENABLE

+ 58 - 1
lib/SCSI2SD/src/firmware/scsiPhy.c

@@ -26,6 +26,8 @@
 #include "fpga.h"
 #include "led.h"
 
+#include <string.h>
+
 // Private DMA variables.
 static int dmaInProgress = 0;
 
@@ -133,7 +135,7 @@ scsiReadDMA(uint8_t* data, uint32_t count)
 	scsiTxDMAComplete = 1; // TODO not used much
 	scsiRxDMAComplete = 0; // TODO not used much
 
-	HAL_DMA_Start(&fsmcToMem, (uint32_t) SCSI_FIFO_DATA, (uint32_t) data, count); // TODO MM count/4 for tx
+	HAL_DMA_Start(&fsmcToMem, (uint32_t) SCSI_FIFO_DATA, (uint32_t) data, count);
 }
 
 int
@@ -424,6 +426,61 @@ void scsiPhyReset()
 	}
 	#endif
 
+	// FPGA comms test code
+	#ifdef FPGA_TEST
+
+	while(1)
+	{
+		for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
+		{
+			scsiDev.data[j] = j;
+		}
+
+		*SCSI_CTRL_PHASE = DATA_IN;
+		HAL_DMA_Start(
+			&memToFSMC,
+			(uint32_t) &scsiDev.data[0],
+			(uint32_t) SCSI_FIFO_DATA,
+			SCSI_FIFO_DEPTH / 4);
+
+		HAL_DMA_PollForTransfer(
+			&memToFSMC,
+			HAL_DMA_FULL_TRANSFER,
+			0xffffffff);
+
+		memset(&scsiDev.data[0], 0, SCSI_FIFO_DEPTH);
+
+		*SCSI_CTRL_PHASE = DATA_OUT;
+		HAL_DMA_Start(
+			&fsmcToMem,
+			(uint32_t) SCSI_FIFO_DATA,
+			(uint32_t) &scsiDev.data[0],
+			SCSI_FIFO_DEPTH);
+
+		HAL_DMA_PollForTransfer(
+			&fsmcToMem,
+			HAL_DMA_FULL_TRANSFER,
+			0xffffffff);
+
+		for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
+		{
+			if (scsiDev.data[j] != (uint8_t) j)
+			{
+				while (1)
+				{
+					s2s_ledOn();
+					s2s_delay_ms(100);
+					s2s_ledOff();
+					s2s_delay_ms(100);
+				}
+			}
+		}
+
+		s2s_fpgaReset();
+
+	}
+	#endif
+
 }
 
 static void scsiPhyInitDMA()

+ 3 - 5
lib/SCSI2SD/src/firmware/scsiPhy.h

@@ -30,13 +30,14 @@
 #define SCSI_STS_FIFO_COMPLETE ((volatile uint8_t*)0x60000012)
 #define SCSI_STS_SELECTED ((volatile uint8_t*)0x60000013)
 #define SCSI_STS_SCSI ((volatile uint8_t*)0x60000014)
+#define SCSI_STS_DBX ((volatile uint8_t*)0x60000015)
 
 #define SCSI_FIFO_DATA ((volatile uint8_t*)0x60000020)
 #define SCSI_FIFO_DEPTH 512
 
 
-#define scsiPhyFifoFull() ((*SCSI_STS_FIFO & 0x02) == 0x02)
-#define scsiPhyFifoEmpty() ((*SCSI_STS_FIFO & 0x01) == 0x01)
+#define scsiPhyFifoFull() ((*SCSI_STS_FIFO & 0x01) == 0x01)
+#define scsiPhyFifoEmpty() ((*SCSI_STS_FIFO & 0x02) == 0x02)
 
 #define scsiPhyFifoFlip() \
 {\
@@ -44,9 +45,6 @@
 	*SCSI_FIFO_SEL = scsiPhyFifoSel; \
 }
 
-// Clear 4 byte fifo
-#define scsiPhyFifoClear() (void) scsiPhyRx(); (void) scsiPhyRx(); (void) scsiPhyRx(); (void) scsiPhyRx();
-
 #define scsiPhyTx(val) *SCSI_FIFO_DATA = (val)
 #define scsiPhyRx() *SCSI_FIFO_DATA
 #define scsiPhyComplete() ((*SCSI_STS_FIFO_COMPLETE & 0x01) == 0x01)

+ 66 - 135
lib/SCSI2SD/src/firmware/sd.c

@@ -787,35 +787,12 @@ static void sdInitDMA()
 	{
 		init = 1;
 
- //TODO MM SEE STUPID SD_DMA_RxCplt that require the SD IRQs to preempt
-// Configured with 4 bits preemption, NO sub priority.
-  HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 8, 0);
-  HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
-  HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 8, 0);
-  HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
-#if 0
-		sdDMATxChan =
-			SD_TX_DMA_DmaInitialize(
-				2, // Bytes per burst
-				1, // request per burst
-				HI16(CYDEV_SRAM_BASE),
-				HI16(CYDEV_PERIPH_BASE)
-				);
-
-		sdDMARxChan =
-			SD_RX_DMA_DmaInitialize(
-				1, // Bytes per burst
-				1, // request per burst
-				HI16(CYDEV_PERIPH_BASE),
-				HI16(CYDEV_SRAM_BASE)
-				);
-
-		CyDmaChDisable(sdDMATxChan);
-		CyDmaChDisable(sdDMARxChan);
-
-		SD_RX_DMA_COMPLETE_StartEx(sdRxISR);
-		SD_TX_DMA_COMPLETE_StartEx(sdTxISR);
-#endif
+		//TODO MM SEE STUPID SD_DMA_RxCplt that require the SD IRQs to preempt
+		// Configured with 4 bits preemption, NO sub priority.
+		HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 8, 0);
+		HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
+		HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 8, 0);
+		HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
 	}
 }
 
@@ -829,97 +806,24 @@ void sdTmpWrite(uint8_t* data, uint32_t lba, int sectors)
 	BSP_SD_WriteBlocks_DMA((uint32_t*) data, lba * 512ll, 512, sectors);
 }
 
-int sdInit()
+static void sdClear()
 {
-	int result = 0;
-	//int i;
-
-	// TODO sdCmdState = CMD_STATE_IDLE;
 	sdDev.version = 0;
 	sdDev.ccs = 0;
 	sdDev.capacity = 0;
 	memset(sdDev.csd, 0, sizeof(sdDev.csd));
 	memset(sdDev.cid, 0, sizeof(sdDev.cid));
+}
 
-// TODO should be in POLL method!
-
-	sdInitDMA();
-#if 0
-
-	SD_CS_SetDriveMode(SD_CS_DM_STRONG);
-	SD_CS_Write(1); // Set CS inactive (active low)
-
-	// Set the SPI clock for 400kHz transfers
-	// 25MHz / 400kHz approx factor of 63.
-	// The register contains (divider - 1)
-	uint16_t clkDiv25MHz =  SD_Data_Clk_GetDividerRegister();
-	SD_Data_Clk_SetDivider(((clkDiv25MHz + 1) * 63) - 1);
-	// Wait for the clock to settle.
-	CyDelayUs(1);
-
-	SDCard_Start(); // Enable SPI hardware
-
-	// Power on sequence. 74 clock cycles of a "1" while CS unasserted.
-	for (i = 0; i < 10; ++i)
-	{
-		sdSpiByte(0xFF);
-	}
-
-	SD_CS_Write(0); // Set CS active (active low)
-	CyDelayUs(1);
-
-	sdSpiByte(0xFF);
-	v = sdDoCommand(SD_GO_IDLE_STATE, 0, 1, 0);
-	if(v != 1){goto bad;}
-
-	ledOn();
-	if (!sendIfCond()) goto bad; // Sets V1 or V2 flag  CMD8
-	if (!sdOpCond()) goto bad; // ACMD41. Wait for init completes.
-	if (!sdReadOCR()) goto bad; // CMD58. Get CCS flag. Only valid after init.
-
-	// This command will be ignored if sdDev.ccs is set.
-	// SDHC and SDXC are always 512bytes.
-	v = sdCRCCommandAndResponse(SD_SET_BLOCKLEN, SD_SECTOR_SIZE); //Force sector size
-	if(v){goto bad;}
-	v = sdCRCCommandAndResponse(SD_CRC_ON_OFF, 0); //crc off
-	if(v){goto bad;}
-
-	// now set the sd card back to full speed.
-	// The SD Card spec says we can run SPI @ 25MHz
-	SDCard_Stop();
-
-	// We can't run at full-speed with the pullup resistors enabled.
-	SD_MISO_SetDriveMode(SD_MISO_DM_DIG_HIZ);
-	SD_MOSI_SetDriveMode(SD_MOSI_DM_STRONG);
-	SD_SCK_SetDriveMode(SD_SCK_DM_STRONG);
-
-	SD_Data_Clk_SetDivider(clkDiv25MHz);
-	CyDelayUs(1);
-	SDCard_Start();
-
-	// Clear out rubbish data through clock change
-	CyDelayUs(1);
-	SDCard_ReadRxStatus();
-	SDCard_ReadTxStatus();
-	SDCard_ClearFIFO();
-
-	if (!sdReadCSD()) goto bad;
-	sdReadCID();
-
-	result = 1;
-	goto out;
+static int sdDoInit()
+{
+	int result = 0;
 
-bad:
-	SD_Data_Clk_SetDivider(clkDiv25MHz); // Restore the clock for our next retry
-	sdDev.capacity = 0;
+	// TODO sdCmdState = CMD_STATE_IDLE;
+	sdClear();
 
-out:
-	sdClearStatus();
-	ledOff();
-	return result;
 
-#endif
-	uint8_t error = BSP_SD_Init();
+	int8_t error = BSP_SD_Init();
 	if (error == MSD_OK)
 	{
 		memcpy(sdDev.csd, &SDCardInfo.SD_csd, sizeof(sdDev.csd));
@@ -1019,37 +923,54 @@ void sdPoll()
 	}
 }
 
-void sdCheckPresent()
+#endif
+int sdInit()
 {
 	// Check if there's an SD card present.
+	int result = 0;
+
+#if 0
 	if ((scsiDev.phase == BUS_FREE) &&
 		(sdIOState == SD_IDLE) &&
 		(sdCmdState == CMD_STATE_IDLE))
+#endif
+	static int firstInit = 1;
+
+	if (firstInit)
 	{
-		// The CS line is pulled high by the SD card.
-		// De-assert the line, and check if it's high.
-		// This isn't foolproof as it'll be left floating without
-		// an SD card. We can't use the built-in pull-down resistor as it will
-		// overpower the SD pullup resistor.
-		SD_CS_Write(0);
-		SD_CS_SetDriveMode(SD_CS_DM_DIG_HIZ);
-
-		// Delay extended to work with 60cm cables running cards at 2.85V
-		CyDelayCycles(128);
-		uint8_t cs = SD_CS_Read();
-		SD_CS_SetDriveMode(SD_CS_DM_STRONG)	;
+		blockDev.state &= ~(DISK_PRESENT | DISK_INITIALISED);
+		sdClear();
+		sdInitDMA();
+	}
+
+	if (scsiDev.phase == BUS_FREE)
+	{
+		uint8_t cs = HAL_GPIO_ReadPin(nSD_CD_GPIO_Port, nSD_CD_Pin) ? 0 : 1;
+		uint8_t wp = HAL_GPIO_ReadPin(nSD_WP_GPIO_Port, nSD_WP_Pin) ? 0 : 1;
 
 		if (cs && !(blockDev.state & DISK_PRESENT))
 		{
-			static int firstInit = 1;
+			s2s_ledOn();
 
 			// Debounce
-			CyDelay(250);
+			if (!firstInit)
+			{
+				s2s_delay_ms(250);
+			}
 
-			if (sdInit())
+			if (sdDoInit())
 			{
 				blockDev.state |= DISK_PRESENT | DISK_INITIALISED;
 
+				if (wp)
+				{
+					blockDev.state |= DISK_WP;
+				}
+				else
+				{
+					blockDev.state &= ~DISK_WP;
+				}
+
 				// Always "start" the device. Many systems (eg. Apple System 7)
 				// won't respond properly to
 				// LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED sense
@@ -1057,15 +978,21 @@ void sdCheckPresent()
 				// START STOP UNIT command.
 				blockDev.state |= DISK_STARTED;
 
-				if (!firstInit)
+				result = 1;
+
+				s2s_ledOff();
+			}
+			else
+			{
+				for (int i = 0; i < 10; ++i)
 				{
-					int i;
-					for (i = 0; i < MAX_SCSI_TARGETS; ++i)
-					{
-						scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;
-					}
+					// visual indicator of SD error
+					s2s_ledOff();
+					s2s_delay_ms(50);
+					s2s_ledOn();
+					s2s_delay_ms(50);
 				}
-				firstInit = 0;
+				s2s_ledOff();
 			}
 		}
 		else if (!cs && (blockDev.state & DISK_PRESENT))
@@ -1074,12 +1001,16 @@ void sdCheckPresent()
 			blockDev.state &= ~DISK_PRESENT;
 			blockDev.state &= ~DISK_INITIALISED;
 			int i;
-			for (i = 0; i < MAX_SCSI_TARGETS; ++i)
+			for (i = 0; i < S2S_MAX_TARGETS; ++i)
 			{
 				scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;
 			}
+
+			HAL_SD_DeInit(&hsd);
 		}
 	}
+	firstInit = 0;
+
+	return result;
 }
 
-#endif

+ 0 - 1
lib/SCSI2SD/src/firmware/sd.h

@@ -82,7 +82,6 @@ void sdReadSingleSectorDMA(uint32_t lba, uint8_t* outputBuffer);
 int sdReadSectorDMAPoll();
 
 void sdCompleteTransfer(void);
-void sdCheckPresent();
 void sdPoll();
 
 #endif

+ 9 - 3
lib/SCSI2SD/src/firmware/usb_device/usbd_msc_storage_sd.c

@@ -20,6 +20,7 @@
 #include "stm32f2xx.h"
 #include "bsp_driver_sd.h"
 #include "../bsp.h"
+#include "../disk.h"
 #include "../led.h"
 #include "../sd.h"
 #include "../config.h"
@@ -114,15 +115,20 @@ uint32_t s2s_usbd_storage_Inquiry (uint8_t lun, uint8_t* buf, uint8_t maxlen)
 	return s2s_getStandardInquiry(cfg, buf, maxlen);
 }
 
-int8_t  s2s_usbd_storage_IsReady (uint8_t lun)
+int8_t s2s_usbd_storage_IsReady (uint8_t lun)
 {
-	return (0);
+	const S2S_TargetCfg* cfg = getUsbConfig(lun);
+	return (
+			cfg &&
+			(blockDev.state & DISK_PRESENT) &&
+			(blockDev.state & DISK_INITIALISED)
+			) ? 0 : 1; // inverse logic
 }
 
 
 int8_t s2s_usbd_storage_IsWriteProtected (uint8_t lun)
 {
-	return  0;
+	return blockDev.state & DISK_WP;
 }
 
 int8_t s2s_usbd_storage_Read (uint8_t lun,