Kaynağa Gözat

Merge branch 'main' into pico

Morio 2 yıl önce
ebeveyn
işleme
e603683e74

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

@@ -88,7 +88,8 @@ typedef enum
 	S2S_CFG_QUIRKS_APPLE = 1,
 	S2S_CFG_QUIRKS_OMTI = 2,
 	S2S_CFG_QUIRKS_XEBEC = 4,
-	S2S_CFG_QUIRKS_VMS = 8
+	S2S_CFG_QUIRKS_VMS = 8,
+	S2S_CFG_QUIRKS_EMU = 9
 } S2S_CFG_QUIRKS;
 
 typedef enum

+ 1 - 11
lib/SCSI2SD/src/firmware/diagnostic.c

@@ -196,7 +196,7 @@ void scsiReadBuffer()
 }
 
 // Callback after the DATA OUT phase is complete.
-static void doWriteBuffer(void)
+void doWriteBuffer(void)
 {
 	if (scsiDev.status == GOOD) // skip if we've already encountered an error
 	{
@@ -234,14 +234,4 @@ void scsiWriteBuffer()
 	}
 }
 
-// XEBEC specific command. See
-// http://www.bitsavers.org/pdf/westernDigital/WD100x/79-000004_WD1002-SHD_OEM_Manual_Aug1984.pdf
-// Section 4.3.14
-void scsiWriteSectorBuffer()
-{
-	scsiDev.dataLen = scsiDev.target->liveCfg.bytesPerSector;
-	scsiDev.phase = DATA_OUT;
-	scsiDev.postDataOutHook = doWriteBuffer;
-}
-
 

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

@@ -19,8 +19,8 @@
 
 void scsiSendDiagnostic(void);
 void scsiReceiveDiagnostic(void);
+void doWriteBuffer(void);
 void scsiWriteBuffer(void);
-void scsiWriteSectorBuffer(void);
 void scsiReadBuffer(void);
 
 #endif

+ 4 - 6
lib/SCSI2SD/src/firmware/mode.c

@@ -242,8 +242,8 @@ static const uint8_t SequentialDeviceConfigPage[] =
 static const uint8_t AppleVendorPage[] =
 {
 0x30, // Page code
-23, // Page length
-'A','P','P','L','E',' ','C','O','M','P','U','T','E','R',',',' ','I','N','C',' ',' ',' ',0x00
+0x16, // Page length
+'A','P','P','L','E',' ','C','O','M','P','U','T','E','R',',',' ','I','N','C',' ',' ',' '
 };
 
 static void pageIn(int pc, int dataIdx, const uint8_t* pageData, int pageLen)
@@ -516,10 +516,8 @@ static void doModeSense(
 
 	idx += modeSenseCDCapabilitiesPage(pc, idx, pageCode, &pageFound);
 
-	if ((
-			(scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_APPLE) ||
-			(idx + sizeof(AppleVendorPage) <= allocLength)
-		) &&
+	if ((scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_APPLE) &&
+	    (idx + sizeof(AppleVendorPage) <= allocLength) &&
 		(pageCode == 0x30 || pageCode == 0x3F))
 	{
 		pageFound = 1;

+ 51 - 13
lib/SCSI2SD/src/firmware/scsi.c

@@ -388,14 +388,57 @@ static void process_Command()
 		{
 			// Completely non-standard
 			allocLength = 4;
-			if (scsiDev.target->sense.code == NO_SENSE)
-				scsiDev.data[0] = 0;
-			else if (scsiDev.target->sense.code == ILLEGAL_REQUEST)
-				scsiDev.data[0] = 0x20; // Illegal command
-			else if (scsiDev.target->sense.code == NOT_READY)
-				scsiDev.data[0] = 0x04; // Drive not ready
-			else
-				scsiDev.data[0] = 0x11;  // Uncorrectable data error
+
+			switch (scsiDev.target->sense.code)
+			{
+				case NO_SENSE:
+					scsiDev.data[0] = 0;
+					break;
+				case MEDIUM_ERROR:
+					switch (scsiDev.target->sense.asc)
+					{
+						case NO_SEEK_COMPLETE:
+							scsiDev.data[0] = 0x15; // Seek Error
+							break;
+						case WRITE_ERROR_AUTO_REALLOCATION_FAILED:
+							scsiDev.data[0] = 0x03; // Write fault
+							break;
+						default:
+						case UNRECOVERED_READ_ERROR:
+							scsiDev.data[0] = 0x11; // Uncorrectable read error
+							break;
+					}
+					break;
+				case ILLEGAL_REQUEST:
+					switch (scsiDev.target->sense.asc)
+					{
+						case LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE:
+							scsiDev.data[0] = 0x14; // Target sector not found
+							break;
+						case WRITE_PROTECTED:
+							scsiDev.data[0] = 0x03; // Write fault
+							break;
+						default:
+							scsiDev.data[0] = 0x20; // Invalid command
+							break;
+					}
+					break;
+				case NOT_READY:
+					switch (scsiDev.target->sense.asc)
+					{
+						default:
+						case MEDIUM_NOT_PRESENT:
+							scsiDev.data[0] = 0x04; // Drive not ready
+							break;
+						case LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED:
+							scsiDev.data[0] = 0x1A; // Format Error
+							break;
+					}
+					break;
+				default:
+					scsiDev.data[0] = 0x11;  // Uncorrectable data error
+					break;
+			}
 
 			scsiDev.data[1] = (scsiDev.cdb[1] & 0x20) | ((transfer.lba >> 16) & 0x1F);
 			scsiDev.data[2] = transfer.lba >> 8;
@@ -549,11 +592,6 @@ static void process_Command()
 	{
 		scsiWriteBuffer();
 	}
-	else if (command == 0x0f &&
-		scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
-	{
-		scsiWriteSectorBuffer();
-	}
 	else if (command == 0x3C)
 	{
 		scsiReadBuffer();

+ 34 - 2
lib/SCSI2SD/src/firmware/vendor.c

@@ -17,12 +17,27 @@
 
 #include "scsi.h"
 #include "vendor.h"
-
+#include "diagnostic.h"
 
 // Callback after the DATA OUT phase is complete.
 static void doAssignDiskParameters(void)
 {
-	scsiDev.phase = STATUS;
+	if (scsiDev.status == GOOD)
+	{
+		scsiDev.phase = STATUS;
+	}
+}
+
+// XEBEC specific commands
+// http://www.bitsavers.org/pdf/xebec/104524C_S1410Man_Aug83.pdf
+// WD100x seems to be identical to the Xebec but calls this command "Set Parameters"
+// http://www.bitsavers.org/pdf/westernDigital/WD100x/79-000004_WD1002-SHD_OEM_Manual_Aug1984.pdf
+static void doXebecInitializeDriveCharacteristics()
+{
+	if (scsiDev.status == GOOD)
+	{
+		scsiDev.phase = STATUS;
+	}
 }
 
 int scsiVendorCommand()
@@ -48,6 +63,23 @@ int scsiVendorCommand()
 		scsiDev.phase = DATA_OUT;
 		scsiDev.postDataOutHook = doAssignDiskParameters;
 	}
+	else if (command == 0x0C &&
+		scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
+	{
+		// XEBEC S1410: "Initialize Drive Characteristics"
+		// WD100x: "Set Parameters"
+		scsiDev.dataLen = 8;
+		scsiDev.phase = DATA_OUT;
+		scsiDev.postDataOutHook = doXebecInitializeDriveCharacteristics;
+	}
+	else if (command == 0x0F &&
+		scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
+	{
+		// XEBEC S1410, WD100x: "Write Sector Buffer"
+		scsiDev.dataLen = scsiDev.target->liveCfg.bytesPerSector;
+		scsiDev.phase = DATA_OUT;
+		scsiDev.postDataOutHook = doWriteBuffer;
+	}
 	else
 	{
 		commandHandled = 0;

+ 2 - 1
lib/ZuluSCSI_platform_RP2040/ZuluSCSI_platform.cpp

@@ -402,7 +402,7 @@ void platform_emergency_log_save()
     crashfile.close();
 }
 
-#ifdef __MBED___
+#ifdef __MBED__
 void mbed_error_hook(const mbed_error_ctx * error_context)
 {
     logmsg("--------------");
@@ -967,6 +967,7 @@ const uint16_t g_scsi_parity_check_lookup[512] __attribute__((aligned(1024), sec
 
 } /* extern "C" */
 
+
 #ifdef __MBED__
 /* Logging from mbed */
 

+ 6 - 3
lib/ZuluSCSI_platform_RP2040/run_pioasm.sh

@@ -6,6 +6,9 @@ pioasm sdio_RP2040.pio sdio_RP2040.pio.h
 pioasm sdio_Pico.pio sdio_Pico.pio.h
 pioasm sdio_BS2.pio sdio_BS2.pio.h
 
-pioasm scsi_accel_RP2040.pio scsi_accel.pio_RP2040.h
-pioasm scsi_accel_Pico.pio scsi_accel_Pico.pio.h
-pioasm scsi_accel_BS2.pio scsi_accel_BS2.pio.h
+pioasm scsi_accel_target_RP2040.pio scsi_accel_target_RP2040.pio.h
+pioasm scsi_accel_target_BS2.pio scsi_accel_target_BS2.pio.h
+pioasm scsi_accel_target_Pico.pio scsi_accel_target_Pico.pio.h
+
+pioasm scsi_accel_host_RP2040.pio scsi_accel_host_RP2040.pio.h
+pioasm scsi_accel_host_Pico.pio scsi_accel_host_Pico.pio.h

+ 1 - 1
platformio.ini

@@ -1,7 +1,7 @@
 ; PlatformIO Project Configuration File https://docs.platformio.org/page/projectconf.html
 
 [platformio]
-default_envs = ZuluSCSIv1_0, ZuluSCSIv1_0_mini, ZuluSCSIv1_1, ZuluSCSI_RP2040, ZuluSCSI_RP2040_Audio, ZuluSCSI_Pico, ZuluSCSI_Pico_Net_DaynaPORT, ZuluSCSI_BS2
+default_envs = ZuluSCSIv1_0, ZuluSCSIv1_0_mini, ZuluSCSIv1_1, ZuluSCSI_RP2040, ZuluSCSI_RP2040_Audio, ZuluSCSI_Pico, ZuluSCSI_BS2
 
 ; Example platform to serve as a base for porting efforts
 [env:template]

+ 2 - 2
src/ZuluSCSI_config.h

@@ -28,8 +28,8 @@
 #include <ZuluSCSI_platform.h>
 
 // Use variables for version number
-#define FW_VER_NUM      "23.08.21"
-#define FW_VER_SUFFIX   "pico"
+#define FW_VER_NUM      "23.09.07"
+#define FW_VER_SUFFIX   "devel"
 #define ZULU_FW_VERSION FW_VER_NUM "-" FW_VER_SUFFIX
 
 // Configuration and log file paths

+ 39 - 1
src/ZuluSCSI_disk.cpp

@@ -230,6 +230,37 @@ static void formatDriveInfoField(char *field, int fieldsize, bool align_right)
     }
 }
 
+// remove path and extension from filename 
+void extractFileName(const char* path, char* output) {
+
+    const char *lastSlash, *lastDot;
+    int fileNameLength;
+
+    lastSlash = strrchr(path, '/');
+    if (!lastSlash) lastSlash = path;
+        else lastSlash++;
+
+    lastDot = strrchr(lastSlash, '.');
+    if (lastDot && (lastDot > lastSlash)) {
+        fileNameLength = lastDot - lastSlash;
+        strncpy(output, lastSlash, fileNameLength);
+        output[fileNameLength] = '\0';
+    } else {
+        strcpy(output, lastSlash);
+    }
+}
+
+void setNameFromImage(image_config_t &img, const char *filename) {
+
+    char image_name[MAX_FILE_PATH];
+
+    extractFileName(filename, image_name);
+    memset(img.vendor, 0, 8);
+    strncpy(img.vendor, image_name, 8);  
+    memset(img.prodId, 0, 8);
+    strncpy(img.prodId, image_name+8, 8);
+}
+
 // Set default drive vendor / product info after the image file
 // is loaded and the device type is known.
 static void setDefaultDriveInfo(int target_idx)
@@ -411,6 +442,12 @@ bool scsiDiskOpenHDDImage(int target_idx, const char *filename, int scsi_id, int
         PLATFORM_CONFIG_HOOK(&img);
 #endif
 
+        if (img.name_from_image) 
+        { 
+            setNameFromImage(img, filename); 
+            logmsg("Vendor / product id set from image file name");
+        }
+
         setDefaultDriveInfo(target_idx);
 
         if (img.prefetchbytes > 0)
@@ -541,8 +578,9 @@ static void scsiDiskLoadConfig(int target_idx, const char *section)
     img.deviceTypeModifier = ini_getl(section, "TypeModifier", img.deviceTypeModifier, CONFIGFILE);
     img.sectorsPerTrack = ini_getl(section, "SectorsPerTrack", img.sectorsPerTrack, CONFIGFILE);
     img.headsPerCylinder = ini_getl(section, "HeadsPerCylinder", img.headsPerCylinder, CONFIGFILE);
-    img.quirks = ini_getl(section, "Quirks", img.quirks, CONFIGFILE);
+    img.quirks = ini_getl(section, "Quirks", img.quirks, CONFIGFILE);  
     img.rightAlignStrings = ini_getbool(section, "RightAlignStrings", 0, CONFIGFILE);
+    img.name_from_image = ini_getbool(section, "NameFromImage", 0, CONFIGFILE);    
     img.prefetchbytes = ini_getl(section, "PrefetchBytes", img.prefetchbytes, CONFIGFILE);
     img.reinsert_on_inquiry = ini_getbool(section, "ReinsertCDOnInquiry", img.reinsert_on_inquiry, CONFIGFILE);
     img.reinsert_after_eject = ini_getbool(section, "ReinsertAfterEject", img.reinsert_after_eject, CONFIGFILE);

+ 3 - 0
src/ZuluSCSI_disk.h

@@ -79,6 +79,9 @@ struct image_config_t: public S2S_TargetCfg
     // This field uses -1 for default when field is not set in .ini
     int rightAlignStrings;
 
+    // Set Vendor / Product Id from image file name
+    bool name_from_image;
+
     // Maximum amount of bytes to prefetch
     int prefetchbytes;
 

+ 16 - 1
src/ZuluSCSI_log_trace.cpp

@@ -49,7 +49,8 @@ static const char *getCommandName(uint8_t cmd)
         case 0x08: return "Read6";
         case 0x0A: return "Write6";
         case 0x0B: return "Seek6";
-        case 0x0F: return "WriteSectorBuffer";
+        case 0x0C: return "Xebec InitializeDriveCharacteristics";
+        case 0x0F: return "Xebec WriteSectorBuffer";
         case 0x10: return "WriteFilemarks";
         case 0x11: return "Space";
         case 0x12: return "Inquiry";
@@ -174,6 +175,9 @@ static void printNewPhase(int phase, bool initiator = false)
             if (!initiator && scsiDev.target->syncOffset > 0)
                 dbgmsg("---- DATA_OUT, syncOffset ", (int)scsiDev.target->syncOffset,
                                     " syncPeriod ", (int)scsiDev.target->syncPeriod);
+	    // log Xebec vendor commands data
+	    else if (scsiDev.cdb[0] == 0x0C || scsiDev.cdb[0] == 0x0F)
+		    g_LogData = true;
             else
                 dbgmsg("---- DATA_OUT");
             break;
@@ -206,6 +210,17 @@ void scsiLogPhaseChange(int new_phase)
         {
             dbgmsg("---- Total IN: ", g_InByteCount, " OUT: ", g_OutByteCount, " CHECKSUM: ", (int)g_DataChecksum);
         }
+	// log Xebec vendor command
+        if (old_phase == DATA_OUT && scsiDev.cdb[0] == 0x0C && g_OutByteCount == 8)
+	{
+		int cylinders = ((uint16_t)scsiDev.data[0] << 8) + scsiDev.data[1];
+		int heads = scsiDev.data[2];
+		int reducedWrite = ((uint16_t)scsiDev.data[3] << 8) + scsiDev.data[4];
+		int writePrecomp = ((uint16_t)scsiDev.data[5] << 8) + scsiDev.data[6];
+		int eccBurst = scsiDev.data[7];
+		dbgmsg("---- Xebec Initialize Drive Characteristics: cylinders=", cylinders, " heads=", heads,
+				" reducedWrite=", reducedWrite, " writePrecomp=", writePrecomp, " eccBurst=", eccBurst);
+	}
         g_InByteCount = g_OutByteCount = 0;
         g_DataChecksum = 0;