Browse Source

Merge master into 2020a

Michael McMaster 5 years ago
parent
commit
0b80c91687

+ 14 - 0
lib/SCSI2SD/CHANGELOG

@@ -1,3 +1,17 @@
+20200101		6.2.14
+	- Fix for invalid CDROM READ TOC responses (Thanks Simon Gander)
+	- Fix for data corruption for hosts that transfer more than 64k per
+	write.
+
+20191208		6.2.9
+	- Fix to prevent sending floppy geometry mode page when not configured as
+	a floppy (Thanks Landon Rodgers)
+	- Fix for VMS 5.5-2 Inquiry allocation lengths. Requires setting "vms" quirk
+	mode in the XML config (Thanks Landon Rodgers)
+
+20191030		6.2.8
+	- Fix incorrect results from the self-test function.
+
 20191009		6.2.7
 	- Slight improvements to data throughput, which may assist SCSI hosts with
 	short timeouts.

+ 3 - 0
lib/SCSI2SD/Makefile

@@ -141,6 +141,9 @@ build/firmware.elf: $(SRC) rtl/fpga_bitmap.o $(STM32OBJS)
 build/firmware.bin: build/firmware.elf
 	$(OBJCOPY) -O binary $< $@
 
+# Example to hard-code config within firmware
+#sudo arm-none-eabi-objcopy --update-section .fixed_config=config.dat firmware.elf -O binary firmware.bin
+
 build/stm32cubemx/%.o:
 	mkdir -p build/stm32cubemx
 	$(ARMCC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $(STM32CubeMX_INCUDE) $(INCLUDE) $^

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

@@ -81,7 +81,8 @@ typedef enum
 	S2S_CFG_QUIRKS_NONE = 0,
 	S2S_CFG_QUIRKS_APPLE = 1,
 	S2S_CFG_QUIRKS_OMTI = 2,
-	S2S_CFG_QUIRKS_XEBEC = 4
+	S2S_CFG_QUIRKS_XEBEC = 4,
+	S2S_CFG_QUIRKS_VMS = 8
 } S2S_CFG_QUIRKS;
 
 typedef enum

+ 3 - 3
lib/SCSI2SD/src/firmware/bsp.c

@@ -23,15 +23,15 @@ static int usingFastClock = 0;
 
 // TODO keep clock routines consistent with those in STM32Cubemx main.c
 
-uint32_t s2s_getSdRateMBs()
+uint32_t s2s_getSdRateKBs()
 {
 	if (usingFastClock)
 	{
-		return 18; // ((72MHz / 2) / 8bits) * 4bitparallel
+		return 18000; // ((72MHz / 2) / 8bits) * 4bitparallel
 	}
 	else
 	{
-		return 12; // ((48MHz / 2) / 8bits) * 4bitparallel
+		return 12000; // ((48MHz / 2) / 8bits) * 4bitparallel
 	}
 }
 

+ 1 - 1
lib/SCSI2SD/src/firmware/bsp.h

@@ -27,7 +27,7 @@
 void s2s_setNormalClock();
 void s2s_setFastClock();
 
-uint32_t s2s_getSdRateMBs();
+uint32_t s2s_getSdRateKBs();
 
 #endif
 

+ 5 - 5
lib/SCSI2SD/src/firmware/cdrom.c

@@ -170,14 +170,14 @@ static void doReadTOC(int MSF, uint8_t track, uint16_t allocationLength)
 		// Replace start of leadout track
 		if (MSF)
 		{
-			LBA2MSF(capacity, scsiDev.data + 0x0E);
+			LBA2MSF(capacity, scsiDev.data + 0x10);
 		}
 		else
 		{
-			scsiDev.data[0x0E] = capacity >> 24;
-			scsiDev.data[0x0F] = capacity >> 16;
-			scsiDev.data[0x10] = capacity >> 8;
-			scsiDev.data[0x11] = capacity;
+			scsiDev.data[0x10] = capacity >> 24;
+			scsiDev.data[0x11] = capacity >> 16;
+			scsiDev.data[0x12] = capacity >> 8;
+			scsiDev.data[0x13] = capacity;
 		}
 
 		if (len > allocationLength)

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

@@ -37,7 +37,10 @@
 
 #include <string.h>
 
-static const uint16_t FIRMWARE_VERSION = 0x0627;
+static const uint16_t FIRMWARE_VERSION = 0x062E;
+
+// Optional static config
+extern uint8_t* __fixed_config;
 
 // 1 flash row
 static const uint8_t DEFAULT_CONFIG[128] =
@@ -87,7 +90,14 @@ void s2s_configInit(S2S_BoardCfg* config)
 {
 	usbInEpState = USB_IDLE;
 
-	if ((blockDev.state & DISK_PRESENT) && sdDev.capacity)
+	if (memcmp(__fixed_config, "BCFG", 4) == 0)
+	{
+		// Use hardcoded config
+		memcpy(s2s_cfg, __fixed_config, S2S_CFG_SIZE);
+		memcpy(config, s2s_cfg, sizeof(S2S_BoardCfg));
+	}
+
+	else if ((blockDev.state & DISK_PRESENT) && sdDev.capacity)
 	{
 		int cfgSectors = (S2S_CFG_SIZE + 511) / 512;
 		BSP_SD_ReadBlocks_DMA(

+ 80 - 45
lib/SCSI2SD/src/firmware/disk.c

@@ -524,11 +524,21 @@ int scsiDiskCommand()
 	else if (unlikely(command == 0x37))
 	{
 		// READ DEFECT DATA
-		scsiDev.status = CHECK_CONDITION;
-		scsiDev.target->sense.code = NO_SENSE;
-		scsiDev.target->sense.asc = DEFECT_LIST_NOT_FOUND;
-		scsiDev.phase = STATUS;
+		uint32_t allocLength = (((uint16_t)scsiDev.cdb[7]) << 8) |
+			scsiDev.cdb[8];
+
+		scsiDev.data[0] = 0;
+		scsiDev.data[1] = scsiDev.cdb[1];
+		scsiDev.data[2] = 0;
+		scsiDev.data[3] = 0;
+		scsiDev.dataLen = 4;
+
+		if (scsiDev.dataLen > allocLength)
+		{
+			scsiDev.dataLen = allocLength;
+		}
 
+		scsiDev.phase = DATA_IN;
 	}
 	else
 	{
@@ -538,6 +548,29 @@ int scsiDiskCommand()
 	return commandHandled;
 }
 
+static uint32_t
+calcReadahead(uint32_t totalBytes, uint32_t sdSpeedKBs, uint32_t scsiSpeedKBs)
+{
+	if (scsiSpeedKBs == 0 || scsiDev.hostSpeedMeasured == 0)
+	{
+		return totalBytes;
+	}
+
+	// uint32_t readAheadBytes = totalBytes * (1 - scsiSpeedKBs / sdSpeedKBs);
+	// Won't overflow with 65536 max bytes, 20000 max scsi speed.
+	uint32_t readAheadBytes = totalBytes - totalBytes * scsiSpeedKBs / sdSpeedKBs;
+
+	// Round up to nearest FIFO size (* 4 for safety)
+	readAheadBytes = ((readAheadBytes / SCSI_FIFO_DEPTH) + 4) * SCSI_FIFO_DEPTH;
+
+	if (readAheadBytes > totalBytes)
+	{
+		readAheadBytes = totalBytes;
+	}
+
+	return readAheadBytes;
+}
+
 void scsiDiskPoll()
 {
 	uint32_t bytesPerSector = scsiDev.target->liveCfg.bytesPerSector;
@@ -694,18 +727,16 @@ void scsiDiskPoll()
 				transfer.lba);
 		int i = 0;
 		int clearBSY = 0;
-		int extraSectors = 0;
 
 		int parityError = 0;
 		int enableParity = scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY;
 
-		uint32_t scsiSpeed = s2s_getScsiRateMBs();
-
 		uint32_t maxSectors = sizeof(scsiDev.data) / SD_SECTOR_SIZE;
 
 		static_assert(SCSI_XFER_MAX >= sizeof(scsiDev.data), "Assumes SCSI_XFER_MAX >= sizeof(scsiDev.data)");
 
 		// Start reading and filling fifos as soon as possible.
+		DWT->CYCCNT = 0; // Start counting cycles
 		scsiSetDataCount(transfer.blocks * bytesPerSector);
 
 		while ((i < totalSDSectors) &&
@@ -723,31 +754,15 @@ void scsiDiskPoll()
 				// no flow control. This can be handled if a) the scsi interface
 				// doesn't block and b) we read enough SCSI sectors first so that
 				// the SD interface cannot catch up.
-				int prevExtraSectors = extraSectors;
 				uint32_t totalBytes = sectors * SD_SECTOR_SIZE;
-				extraSectors = 0;
-
-				int32_t readAheadBytes = totalBytes;
-				uint32_t sdSpeed = s2s_getSdRateMBs() + (scsiDev.sdUnderrunCount / 2);
-				// if (have blind writes)
-				if (scsiSpeed > 0 && scsiDev.sdUnderrunCount < 16)
-				{
-					// readAhead = sectors * (sd / scsi - 1 + 0.1);
-					readAheadBytes = totalBytes * sdSpeed / scsiSpeed - totalBytes;
 
-					// Round up to nearest FIFO size.
-					readAheadBytes = ((readAheadBytes / SCSI_FIFO_DEPTH) + 1) * SCSI_FIFO_DEPTH;
-
-					if (readAheadBytes > totalBytes)
-					{
-						readAheadBytes = totalBytes;
-					}
-				}
-
-				uint32_t prevExtraBytes = prevExtraSectors * SD_SECTOR_SIZE;
-				uint32_t scsiBytesRead = prevExtraBytes;
-				readAheadBytes -= prevExtraBytes; // Must be signed!
+				uint32_t sdSpeedKBs = s2s_getSdRateKBs() + (scsiDev.sdUnderrunCount * 256);
+				uint32_t readAheadBytes = calcReadahead(
+					totalBytes,
+					sdSpeedKBs,
+					scsiDev.hostSpeedKBs);
 
+				uint32_t scsiBytesRead = 0;
 				if (readAheadBytes > 0)
 				{
 					scsiReadPIO(
@@ -755,6 +770,42 @@ void scsiDiskPoll()
 						readAheadBytes,
 						&parityError);
 					scsiBytesRead += readAheadBytes;
+
+					if (i == 0)
+					{
+						uint32_t elapsedCycles = DWT->CYCCNT;
+
+						// uint32_t rateKBs = (readAheadBytes / 1000) / (elapsedCycles / HAL_RCC_GetHCLKFreq());
+						// Scaled by 4 to avoid overflow w/ max 65536 at 108MHz.
+						uint32_t rateKBs = ((readAheadBytes / 4) * (HAL_RCC_GetHCLKFreq() / 1000) / elapsedCycles) * 4;
+
+						scsiDev.hostSpeedKBs = (scsiDev.hostSpeedKBs + rateKBs) / 2;
+						scsiDev.hostSpeedMeasured = 1;
+
+						if (rateKBs < scsiDev.hostSpeedKBs)
+						{
+							// Our readahead was too slow; assume remaining bytes
+							// will be as well.
+							if (readAheadBytes < totalBytes)
+							{
+								uint32_t properReadahead = calcReadahead(
+									totalBytes,
+									sdSpeedKBs,
+									rateKBs);
+
+								if (properReadahead > readAheadBytes)
+								{
+									uint32_t diff = properReadahead - readAheadBytes;
+									readAheadBytes = properReadahead;
+									scsiReadPIO(
+										&scsiDev.data[scsiBytesRead],
+										diff,
+										&parityError);
+									scsiBytesRead += diff;
+								}
+							}
+						}
+					}
 				}
 
 				HAL_SD_WriteBlocks_DMA(&hsd, (uint32_t*) (&scsiDev.data[0]), (i + sdLBA) * 512ll, SD_SECTOR_SIZE, sectors);
@@ -773,22 +824,6 @@ void scsiDiskPoll()
 					scsiBytesRead += (totalBytes - readAheadBytes);
 				}
 
-				if (!underrun && rem > sectors)
-				{
-					// We probably have some time to waste reading more here.
-					// While noting this is going to drop us down into
-					// half-duplex operation (hence why we read max / 4 only)
-
-					extraSectors = rem - sectors > (maxSectors / 4)
-						? (maxSectors / 4)
-						: rem - sectors;
-
-					scsiReadPIO(
-						&scsiDev.data[0],
-						extraSectors * SD_SECTOR_SIZE,
-						&parityError);
-				}
-
 				uint32_t dmaFinishTime = s2s_getTime_ms();
 				while ((!hsd.SdTransferCplt ||
 						__HAL_SD_SDIO_GET_FLAG(&hsd, SDIO_FLAG_TXACT)) &&

+ 8 - 0
lib/SCSI2SD/src/firmware/inquiry.c

@@ -1,4 +1,5 @@
 //	Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
+//	Copyright (C) 2019 Landon Rodgers  <g.landon.rodgers@gmail.com>
 //
 //	This file is part of SCSI2SD.
 //
@@ -154,6 +155,13 @@ void s2s_scsiInquiry()
 
 	if (scsiDev.phase == DATA_IN)
 	{
+		// VAX workaround
+		if (allocationLength == 255 &&
+			(scsiDev.target->cfg->quirks & S2S_CFG_QUIRKS_VMS))
+		{
+			allocationLength = 254;
+		}
+
 		// "real" hard drives send back exactly allocationLenth bytes, padded
 		// with zeroes. This only seems to happen for Inquiry responses, and not
 		// other commands that also supply an allocation length such as Mode Sense or

+ 10 - 0
lib/SCSI2SD/src/firmware/link.ld

@@ -34,6 +34,16 @@ SECTIONS
     . = ALIGN(4);
   } >FLASH_ISR
 
+  /* Store config settings into FLASH */
+  .fixed_config :
+  {
+    . = ALIGN(4);
+    __fixed_config = .;        /* create a global symbol at config start */
+    . += 1024;
+    KEEP(*(.fixed_config))
+    . = ALIGN(4);
+  } >CONFIG
+
   /* The program code and other data goes into FLASH */
   .text :
   {

+ 3 - 1
lib/SCSI2SD/src/firmware/mode.c

@@ -1,5 +1,6 @@
 //	Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
 //  Copyright (C) 2014 Doug Brown <doug@downtowndougbrown.com>
+//  Copyright (C) 2019 Landon Rodgers <g.landon.rodgers@gmail.com>
 //
 //	This file is part of SCSI2SD.
 //
@@ -467,7 +468,8 @@ static void doModeSense(
 		}
 	}
 
-	if (pageCode == 0x05 || pageCode == 0x3F)
+	if ((pageCode == 0x05 || pageCode == 0x3F) &&
+		(scsiDev.target->cfg->deviceType == S2S_CFG_FLOPPY_14MB))
 	{
 		pageFound = 1;
 		pageIn(pc, idx, FlexibleDiskDriveGeometry, sizeof(FlexibleDiskDriveGeometry));

+ 7 - 0
lib/SCSI2SD/src/firmware/scsi.c

@@ -965,6 +965,11 @@ static void process_MessageOut()
 				scsiWrite(SDTR, sizeof(SDTR));
 				scsiDev.needSyncNegotiationAck = 1; // Check if this message is rejected.
 				scsiDev.sdUnderrunCount = 0;  // reset counter, may work now.
+
+				// Set to the theoretical speed, then adjust if we measure lower
+				// actual speeds.
+				scsiDev.hostSpeedKBs = s2s_getScsiRateKBs();
+				scsiDev.hostSpeedMeasured = 0;
 			}
 		}
 		else
@@ -1125,6 +1130,8 @@ void scsiInit()
 	scsiDev.phase = BUS_FREE;
 	scsiDev.target = NULL;
 	scsiDev.compatMode = COMPAT_UNKNOWN;
+	scsiDev.hostSpeedKBs = 0;
+	scsiDev.hostSpeedMeasured = 0;
 
 	int i;
 	for (i = 0; i < S2S_MAX_TARGETS; ++i)

+ 4 - 0
lib/SCSI2SD/src/firmware/scsi.h

@@ -165,6 +165,10 @@ typedef struct
 
 	int needSyncNegotiationAck;
 	int sdUnderrunCount;
+
+	// Estimate of the SCSI host actual speed
+	uint32_t hostSpeedKBs;
+	int hostSpeedMeasured;
 } ScsiDevice;
 
 extern ScsiDevice scsiDev;

+ 9 - 77
lib/SCSI2SD/src/firmware/scsiPhy.c

@@ -133,17 +133,6 @@ void EXTI4_IRQHandler()
 	}
 }
 
-static void assertFail()
-{
-	while (1)
-	{
-		s2s_ledOn();
-		s2s_delay_ms(100);
-		s2s_ledOff();
-		s2s_delay_ms(100);
-	}
-}
-
 void
 scsiSetDataCount(uint32_t count)
 {
@@ -688,21 +677,25 @@ uint32_t scsiEnterPhaseImmediate(int newPhase)
 	return 0; // No change
 }
 
-uint32_t s2s_getScsiRateMBs()
+// Returns a "safe" estimate of the host SCSI speed of
+// theoretical speed / 2
+uint32_t s2s_getScsiRateKBs()
 {
 	if (scsiDev.target->syncOffset)
 	{
 		if (scsiDev.target->syncPeriod < 23)
 		{
-			return 20;
+			return 20 / 2;
 		}
 		else if (scsiDev.target->syncPeriod <= 25)
 		{
-			return 10;
+			return 10 / 2;
 		}
 		else
 		{
-			return 1000 / (scsiDev.target->syncPeriod * 4);
+			// 1000000000 / (scsiDev.target->syncPeriod * 4) bytes per second
+			// (1000000000 / (scsiDev.target->syncPeriod * 4)) / 1000  kB/s
+			return (1000000 / (scsiDev.target->syncPeriod * 4)) / 2;
 		}
 	}
 	else
@@ -969,69 +962,8 @@ int scsiSelfTest()
 	// TODO Test DBP
 	*SCSI_CTRL_DBX = 0;
 
-	// FPGA comms test code
-	for(i = 0; i < 10000; ++i)
-	{
-		for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
-		{
-			scsiDev.data[j] = j;
-		}
-
-		if (!scsiPhyFifoEmpty())
-		{
-			assertFail();
-		}
-
-		*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);
-
-		if (!scsiPhyFifoFull())
-		{
-			assertFail();
-		}
-
-		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 / 2);
-
-		HAL_DMA_PollForTransfer(
-			&fsmcToMem,
-			HAL_DMA_FULL_TRANSFER,
-			0xffffffff);
-
-		if (!scsiPhyFifoEmpty())
-		{
-			assertFail();
-		}
-
-
-		for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
-		{
-			if (scsiDev.data[j] != (uint8_t) j)
-			{
-				result |= 64;
-			}
-		}
-
-		s2s_fpgaReset();
-
-	}
-
 	*SCSI_CTRL_BSY = 0;
+
 	return result;
 }
 

+ 1 - 1
lib/SCSI2SD/src/firmware/scsiPhy.h

@@ -117,6 +117,6 @@ int scsiWriteDMAPoll();
 
 int scsiSelfTest(void);
 
-uint32_t s2s_getScsiRateMBs();
+uint32_t s2s_getScsiRateKBs();
 
 #endif

+ 9 - 0
lib/SCSI2SD/src/scsi2sd-util6/ConfigUtil.cc

@@ -168,6 +168,7 @@ ConfigUtil::toBytes(const S2S_TargetCfg& _config)
 	config.headsPerCylinder = fromLE16(config.headsPerCylinder);
 
 	const uint8_t* begin = reinterpret_cast<const uint8_t*>(&config);
+
 	return std::vector<uint8_t>(begin, begin + sizeof(config));
 }
 
@@ -229,6 +230,10 @@ ConfigUtil::toXML(const S2S_TargetCfg& config)
 	{
 		s << "xebec";
 	}
+	else if (config.quirks == S2S_CFG_QUIRKS_VMS)
+	{
+		s << "vms";
+	}
 
 	s <<
 			"</quirks>\n" <<
@@ -465,6 +470,10 @@ parseTarget(wxXmlNode* node)
 				{
 					result.quirks |= S2S_CFG_QUIRKS_XEBEC;
 				}
+				else if (quirk == "vms")
+				{
+					result.quirks |= S2S_CFG_QUIRKS_VMS;
+				}
 			}
 		}
 		else if (child->GetName() == "deviceType")

+ 1 - 1
lib/SCSI2SD/src/scsi2sd-util6/Makefile

@@ -96,7 +96,7 @@ ifeq ($(TARGET),Linux)
 	BUILD := $(PWD)/build/linux
 	LIBUSB_CONFIG+=--disable-shared
 	LDFLAGS_LIBUSB+= -ludev -lpthread
-all: $(BUILD)/scsi2sd-test
+#all: $(BUILD)/scsi2sd-test
 
 endif
 ifeq ($(TARGET),Darwin)