ソースを参照

Merge branch 'main' into plextor-d8h-vendor-cmd

Morio 1 年間 前
コミット
ee0b8d54d3

+ 1 - 1
.github/workflows/firmware_build.yml

@@ -34,7 +34,7 @@ jobs:
           utils/rename_binaries.sh
 
       - name: Upload binaries into build artifacts
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           path: ZuluSCSI/distrib/*
           name: ZuluSCSI binaries

+ 1 - 0
.gitignore

@@ -1,2 +1,3 @@
 .pio
 .vscode
+.DS_Store

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

@@ -89,7 +89,8 @@ typedef enum
 	S2S_CFG_QUIRKS_OMTI = 2,
 	S2S_CFG_QUIRKS_XEBEC = 4,
 	S2S_CFG_QUIRKS_VMS = 8,
-	S2S_CFG_QUIRKS_EMU = 9
+	S2S_CFG_QUIRKS_X68000 = 16,
+	S2S_CFG_QUIRKS_EWSD = 32
 } S2S_CFG_QUIRKS;
 
 typedef enum

+ 1 - 1
lib/SCSI2SD/src/firmware/inquiry.c

@@ -163,7 +163,7 @@ void s2s_scsiInquiry()
 	{
 		// VAX workaround
 		if (allocationLength == 255 &&
-			(scsiDev.target->cfg->quirks & S2S_CFG_QUIRKS_VMS))
+			(scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_VMS))
 		{
 			allocationLength = 254;
 		}

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

@@ -1,5 +1,6 @@
 //	Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
 //	Copyright (c) 2023 joshua stein <jcs@jcs.org>
+//	Copyright (c) 2023 Andrea Ottaviani <andrea.ottaviani.69@gmail.com>
 //
 //	This file is part of SCSI2SD.
 //
@@ -71,7 +72,7 @@ void enter_BusFree()
 
 	// Wait for the initiator to cease driving signals
 	// Bus settle delay + bus clear delay = 1200ns
-    // Just waiting the clear delay is sufficient.
+	// Just waiting the clear delay is sufficient.
 	s2s_delay_ns(800);
 
 	s2s_ledOff();
@@ -141,6 +142,11 @@ void process_Status()
 {
 	scsiEnterPhase(STATUS);
 
+	if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_EWSD)
+	{
+		s2s_delay_ms(1);
+	}
+
 	uint8_t message;
 
 	uint8_t control = scsiDev.cdb[scsiDev.cdbLen - 1];
@@ -366,6 +372,23 @@ static void process_Command()
 		memset(scsiDev.cdb, 0xff, sizeof(scsiDev.cdb));
 		return;
 	}
+	// X68000 and strange "0x00 0xXX .. .. .. .." command
+	else if ((command == 0x00) && likely(scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_X68000))
+	{
+		if (scsiDev.cdb[1] == 0x28)
+		{
+			scsiDev.target->sense.code = NO_SENSE;
+			scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+			enter_Status(CHECK_CONDITION);
+			return;
+		} 	else if (scsiDev.cdb[1] == 0x03)
+		{
+			scsiDev.target->sense.code = NO_SENSE;
+			scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+			enter_Status(GOOD);
+			return;
+		}
+	}
 	else if (parityError &&
 		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
 	{
@@ -455,18 +478,18 @@ static void process_Command()
 		{
 			// The response is completely non-standard.
 			if (likely(allocLength > 12))
-			    allocLength = 12;
+				allocLength = 12;
 			else if (unlikely(allocLength < 4))
 				allocLength = 4;
 			if (cfg->deviceType != S2S_CFG_SEQUENTIAL)
-			    allocLength = 4;
+				allocLength = 4;
 			memset(scsiDev.data, 0, allocLength);
 			if (scsiDev.target->sense.code == NO_SENSE)
 			{
 				// Nothing to report.
 			}
 			else if (scsiDev.target->sense.code == UNIT_ATTENTION &&
-			    cfg->deviceType == S2S_CFG_SEQUENTIAL)
+				cfg->deviceType == S2S_CFG_SEQUENTIAL)
 			{
 				scsiDev.data[0] = 0x10; // Tape exception
 			}
@@ -530,6 +553,12 @@ static void process_Command()
 			scsiDev.data[7] = 10; // additional length
 			scsiDev.data[12] = scsiDev.target->sense.asc >> 8;
 			scsiDev.data[13] = scsiDev.target->sense.asc;
+			if ((scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_EWSD))
+			{
+				/* EWSD seems not to want something behind additional length. (8 + 0x0e = 22) */
+				allocLength=22;
+				scsiDev.data[7] = 0x0e;
+			}
 		}
 
 		// Silently truncate results. SCSI-2 spec 8.2.14.
@@ -544,8 +573,15 @@ static void process_Command()
 	// on receiving the unit attention response on boot, thus
 	// triggering another unit attention condition.
 	else if (scsiDev.target->unitAttention &&
-		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_UNIT_ATTENTION))
+		scsiDev.target->unitAttentionStop == 0 &&
+		((scsiDev.boardCfg.flags & S2S_CFG_ENABLE_UNIT_ATTENTION) ||
+		(scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_EWSD)))
 	{
+		/* EWSD requires unitAttention to be sent only once. */
+		if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_EWSD)
+		{
+			scsiDev.target->unitAttentionStop = 1;
+		}
 		scsiDev.target->sense.code = UNIT_ATTENTION;
 		scsiDev.target->sense.asc = scsiDev.target->unitAttention;
 
@@ -1273,7 +1309,13 @@ void scsiInit()
 		scsiDev.targets[i].reserverId = -1;
 		if (firstInit)
 		{
-			scsiDev.targets[i].unitAttention = POWER_ON_RESET;
+			if ((cfg->deviceType == S2S_CFG_MO) && (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_EWSD))
+			{
+				scsiDev.targets[i].unitAttention = POWER_ON_RESET_OR_BUS_DEVICE_RESET_OCCURRED;
+			} else
+			{
+				scsiDev.targets[i].unitAttention = POWER_ON_RESET;
+			}
 		}
 		else
 		{
@@ -1400,4 +1442,3 @@ int scsiReconnect()
 	return reconnected;
 }
 */
-

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

@@ -102,6 +102,7 @@ typedef struct
 	ScsiSense sense;
 
 	uint16_t unitAttention; // Set to the sense qualifier key to be returned.
+	uint8_t unitAttentionStop; // Indicates if unit attention has to be stopped.
 
 	// Only let the reserved initiator talk to us.
 	// A 3rd party may be sending the RESERVE/RELEASE commands

+ 15 - 0
lib/SCSI2SD/src/firmware/vendor.c

@@ -80,6 +80,21 @@ int scsiVendorCommand()
 		scsiDev.phase = DATA_OUT;
 		scsiDev.postDataOutHook = doWriteBuffer;
 	}
+	else if (command == 0xE0 && 
+		scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
+	{
+	  // RAM Diagnostic
+	  // XEBEC S1410 controller
+	  // http://bitsavers.informatik.uni-stuttgart.de/pdf/xebec/104524C_S1410Man_Aug83.pdf
+	  // Stub, return success
+	}
+	else if (command == 0xE4 && 
+		scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
+	{
+	  // Drive Diagnostic
+	  // XEBEC S1410 controller
+	  // Stub, return success
+	}   	
 	else
 	{
 		commandHandled = 0;

+ 13 - 6
lib/ZuluSCSI_platform_RP2040/ZuluSCSI_platform.cpp

@@ -638,10 +638,14 @@ static void watchdog_callback(unsigned alarm_num)
             logmsg("scsiDev.phase: ", (int)scsiDev.phase);
             scsi_accel_log_state();
 
-            uint32_t *p = (uint32_t*)__get_PSP();
+#ifdef __MBED__
+            uint32_t *p =  (uint32_t*)__get_PSP();
+#else
+            uint32_t *p =  (uint32_t*)__get_MSP();
+#endif
             for (int i = 0; i < 8; i++)
             {
-                if (p == &__StackTop) break; // End of stack
+            if (p == &__StackTop) break; // End of stack
 
                 logmsg("STACK ", (uint32_t)p, ":    ", p[0], " ", p[1], " ", p[2], " ", p[3]);
                 p += 4;
@@ -654,14 +658,18 @@ static void watchdog_callback(unsigned alarm_num)
         if (g_watchdog_timeout <= 0)
         {
             logmsg("--------------");
-            logmsg("WATCHDOG TIMEOUT!");
+            logmsg("WATCHDOG TIMEOUT, already attempted bus reset, rebooting");
             logmsg("Platform: ", g_platform_name);
             logmsg("FW Version: ", g_log_firmwareversion);
             logmsg("GPIO states: out ", sio_hw->gpio_out, " oe ", sio_hw->gpio_oe, " in ", sio_hw->gpio_in);
             logmsg("scsiDev.cdb: ", bytearray(scsiDev.cdb, 12));
             logmsg("scsiDev.phase: ", (int)scsiDev.phase);
 
-            uint32_t *p = (uint32_t*)__get_PSP();
+#ifdef __MBED__
+            uint32_t *p =  (uint32_t*)__get_PSP();
+#else
+            uint32_t *p =  (uint32_t*)__get_MSP();
+#endif
             for (int i = 0; i < 8; i++)
             {
                 if (p == &__StackTop) break; // End of stack
@@ -678,7 +686,7 @@ static void watchdog_callback(unsigned alarm_num)
         }
     }
 
-    hardware_alarm_set_target(3, delayed_by_ms(get_absolute_time(), 1000));
+    hardware_alarm_set_target(alarm_num, delayed_by_ms(get_absolute_time(), 1000));
 }
 
 // This function can be used to periodically reset watchdog timer for crash handling.
@@ -687,7 +695,6 @@ void platform_reset_watchdog()
 {
     g_watchdog_timeout = WATCHDOG_CRASH_TIMEOUT;
 
-
     if (!g_watchdog_initialized)
     {
         int alarm_num = -1;

+ 3 - 3
platformio.ini

@@ -176,10 +176,10 @@ build_flags =
     -DZULUSCSI_DAYNAPORT
 ; These take a large portion of the SRAM and can be adjusted
     -DLOGBUFSIZE=8192
-    -DPREFETCH_BUFFER_SIZE=6144
+    -DPREFETCH_BUFFER_SIZE=5632
     -DSCSI2SD_BUFFER_SIZE=57344
-    ; This controls the depth of 2 x NETWORK_PACKET_MAX_SIZE (1520 bytes)
-    ; For example a queue size of 10 would be 10 x 2 x 1520 = 30400 bytes
+    ; This controls the depth of NETWORK_PACKET_MAX_SIZE (1520 bytes)
+    ; For example a queue size of 10 would be 10 x 1520 = 15200 bytes
     -DNETWORK_PACKET_QUEUE_SIZE=18
 ; build flags mirroring the framework-arduinopico#v3.6.0-DaynaPORT static library build
     -DPICO_CYW43_ARCH_POLL=1

+ 1 - 1
src/ZuluSCSI_config.h

@@ -28,7 +28,7 @@
 #include <ZuluSCSI_platform.h>
 
 // Use variables for version number
-#define FW_VER_NUM      "23.12.14"
+#define FW_VER_NUM      "24.02.22"
 #define FW_VER_SUFFIX   "dev"
 #define ZULU_FW_VERSION FW_VER_NUM "-" FW_VER_SUFFIX
 

+ 5 - 0
src/ZuluSCSI_disk.cpp

@@ -706,6 +706,7 @@ int scsiDiskGetNextImageName(image_config_t &img, char *buf, size_t buflen)
         int ret = ini_gets(section, key, "", buf, buflen, CONFIGFILE);
         if (buf[0] != '\0')
         {
+            img.deviceType = g_scsi_settings.getDevice(target_idx)->deviceType;
             return ret;
         }
         else if (img.image_index > 0)
@@ -1114,6 +1115,10 @@ static void doReadCapacity()
     {
         uint32_t highestBlock = capacity - 1;
 
+	if (pmi && scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_EWSD)
+	{
+		highestBlock = 0x00001053;
+	}
         scsiDev.data[0] = highestBlock >> 24;
         scsiDev.data[1] = highestBlock >> 16;
         scsiDev.data[2] = highestBlock >> 8;

+ 154 - 42
src/ZuluSCSI_initiator.cpp

@@ -81,11 +81,19 @@ static struct {
     uint32_t sectorcount_all;
     uint32_t sectors_done;
     uint32_t max_sector_per_transfer;
+    uint32_t bad_sector_count;
+    uint8_t ansi_version;
+    uint8_t max_retry_count;
+    uint8_t device_type;
 
     // Retry information for sector reads.
     // If a large read fails, retry is done sector-by-sector.
     int retrycount;
     uint32_t failposition;
+    bool eject_when_done;
+    bool removable;
+
+    uint32_t removable_count[8];
 
     FsFile target_file;
 } g_initiator_state;
@@ -103,6 +111,12 @@ void scsiInitiatorInit()
         logmsg("InitiatorID set to illegal value in, ", CONFIGFILE, ", defaulting to 7");
         g_initiator_state.initiator_id = 7;
     }
+    else
+    {
+        logmsg("InitiatorID set to ID ", g_initiator_state.initiator_id);
+    }
+    g_initiator_state.max_retry_count = ini_getl("SCSI", "InitiatorMaxRetry", 5, CONFIGFILE);
+
     // treat initiator id as already imaged drive so it gets skipped
     g_initiator_state.drives_imaged = 1 << g_initiator_state.initiator_id;
 
@@ -114,7 +128,12 @@ void scsiInitiatorInit()
     g_initiator_state.retrycount = 0;
     g_initiator_state.failposition = 0;
     g_initiator_state.max_sector_per_transfer = 512;
-
+    g_initiator_state.ansi_version = 0;
+    g_initiator_state.bad_sector_count = 0;
+    g_initiator_state.device_type = SCSI_DEVICE_TYPE_DIRECT_ACCESS;
+    g_initiator_state.removable = false;
+    g_initiator_state.eject_when_done = false;
+    memset(g_initiator_state.removable_count, 0, sizeof(g_initiator_state.removable_count));
 
 }
 
@@ -150,6 +169,30 @@ void delay_with_poll(uint32_t ms)
     }
 }
 
+static int scsiTypeToIniType(int scsi_type, bool removable)
+{
+    int ini_type = -1;
+    switch (scsi_type)
+    {
+        case SCSI_DEVICE_TYPE_DIRECT_ACCESS:
+            ini_type = removable ? S2S_CFG_REMOVABLE : S2S_CFG_FIXED;
+            break;
+        case 1:
+            ini_type = -1; // S2S_CFG_SEQUENTIAL
+            break;
+        case SCSI_DEVICE_TYPE_CD:
+            ini_type = S2S_CFG_OPTICAL;
+            break;
+        case SCSI_DEVICE_TYPE_MO:
+            ini_type = S2S_CFG_MO;
+            break;
+        default:
+            ini_type = -1;
+            break;
+    }
+    return ini_type;
+}
+
 // High level logic of the initiator mode
 void scsiInitiatorMainLoop()
 {
@@ -166,14 +209,14 @@ void scsiInitiatorMainLoop()
         g_initiator_state.sectors_done = 0;
         g_initiator_state.retrycount = 0;
         g_initiator_state.max_sector_per_transfer = 512;
+        g_initiator_state.bad_sector_count = 0;
+        g_initiator_state.eject_when_done = false;
 
         if (!(g_initiator_state.drives_imaged & (1 << g_initiator_state.target_id)))
         {
             delay_with_poll(1000);
 
-            uint8_t inquiry_data[36];
-	    char vendor[9], product[17], revision[5];
-	    int type;
+            uint8_t inquiry_data[36] = {0};
 
             LED_ON();
             bool startstopok =
@@ -188,14 +231,6 @@ void scsiInitiatorMainLoop()
             bool inquiryok = startstopok &&
                 scsiInquiry(g_initiator_state.target_id, inquiry_data);
 
-	    memcpy(vendor, &inquiry_data[8], 8);
-	    vendor[8]=0;
-	    memcpy(product, &inquiry_data[16], 16);
-	    product[16]=0;
-	    memcpy(revision, &inquiry_data[32], 4);
-	    revision[4]=0;
-	    type=inquiry_data[0]&0x1f;
-
             LED_OFF();
 
             uint64_t total_bytes = 0;
@@ -205,12 +240,6 @@ void scsiInitiatorMainLoop()
                     " capacity ", (int)g_initiator_state.sectorcount,
                     " sectors x ", (int)g_initiator_state.sectorsize, " bytes");
 
-		logmsg("[SCSI", g_initiator_state.target_id,"]");
-		logmsg("  Vendor = \"", vendor,"\"");
-		logmsg("  Product = \"", product,"\"");
-		logmsg("  Version = \"", revision,"\"");
-		logmsg("  Type = ", type);
-
                 g_initiator_state.sectorcount_all = g_initiator_state.sectorcount;
 
                 total_bytes = (uint64_t)g_initiator_state.sectorcount * g_initiator_state.sectorsize;
@@ -242,22 +271,79 @@ void scsiInitiatorMainLoop()
 
             char filename_base[12];
             strncpy(filename_base, "HD00_imaged", sizeof(filename_base));
-            const char *filename_extention = ".hda";
+            const char *filename_extension = ".hda";
+
             if (inquiryok)
             {
-                if ((inquiry_data[0] & 0x1F) == 5)
+                char vendor[9], product[17], revision[5];
+                g_initiator_state.device_type=inquiry_data[0] & 0x1f;
+                g_initiator_state.ansi_version = inquiry_data[2] & 0x7;
+                g_initiator_state.removable = !!(inquiry_data[1] & 0x80);
+                g_initiator_state.eject_when_done = g_initiator_state.removable;
+                memcpy(vendor, &inquiry_data[8], 8);
+                vendor[8]=0;
+                memcpy(product, &inquiry_data[16], 16);
+                product[16]=0;
+                memcpy(revision, &inquiry_data[32], 4);
+                revision[4]=0;
+
+                if(g_initiator_state.ansi_version != 0x02)
+                {
+                    // this is a SCSI-1 drive, use READ6 and 256 bytes to be safe.
+                    g_initiator_state.max_sector_per_transfer = 256;
+                }
+                int ini_type = scsiTypeToIniType(g_initiator_state.device_type, g_initiator_state.removable);
+                logmsg("SCSI Version ", (int) g_initiator_state.ansi_version);
+                logmsg("[SCSI", g_initiator_state.target_id,"]");
+                logmsg("  Vendor = \"", vendor,"\"");
+                logmsg("  Product = \"", product,"\"");
+                logmsg("  Version = \"", revision,"\"");
+                if (ini_type == -1)
+                    logmsg("Type = Not Supported, trying direct access");
+                else
+                    logmsg("  Type = ", ini_type);
+
+                if (g_initiator_state.device_type == SCSI_DEVICE_TYPE_CD)
                 {
                     strncpy(filename_base, "CD00_imaged", sizeof(filename_base));
-                    filename_extention = ".iso";
+                    filename_extension = ".iso";
+                }
+                else if (g_initiator_state.device_type == SCSI_DEVICE_TYPE_MO)
+                {
+                    strncpy(filename_base, "MO00_imaged", sizeof(filename_base));
+                    filename_extension = ".img";
+                }
+                else if (g_initiator_state.device_type != SCSI_DEVICE_TYPE_DIRECT_ACCESS)
+                {
+                    logmsg("Unhandled scsi device type: ", g_initiator_state.device_type, ". Handling it as Direct Access Device.");
+                    g_initiator_state.device_type = SCSI_DEVICE_TYPE_DIRECT_ACCESS;
+                }
+
+                if (g_initiator_state.device_type == SCSI_DEVICE_TYPE_DIRECT_ACCESS && g_initiator_state.removable)
+                {
+                    strncpy(filename_base, "RM00_imaged", sizeof(filename_base));
+                    filename_extension = ".img";
                 }
             }
 
+            if (g_initiator_state.eject_when_done && g_initiator_state.removable_count[g_initiator_state.target_id] == 0)
+            {
+                g_initiator_state.removable_count[g_initiator_state.target_id] = 1;
+            }
+
             if (g_initiator_state.sectorcount > 0)
             {
                 char filename[32] = {0};
                 filename_base[2] += g_initiator_state.target_id;
-                strncpy(filename, filename_base, sizeof(filename) - 1);
-                strncat(filename, filename_extention, sizeof(filename) - 1);
+                if (g_initiator_state.eject_when_done)
+                {
+                    auto removable_count = g_initiator_state.removable_count[g_initiator_state.target_id];
+                    snprintf(filename, sizeof(filename), "%s(%lu)%s",filename_base, removable_count, filename_extension);
+                }
+                else
+                {
+                    snprintf(filename, sizeof(filename), "%s%s", filename_base, filename_extension);
+                }
                 static int handling = -1;
                 if (handling == -1)
                 {
@@ -291,12 +377,16 @@ void scsiInitiatorMainLoop()
                             return;
                         }
                         char filename_copy[6] = {0};
-                        snprintf(filename_copy, sizeof(filename_copy), "_%03lu", i);
-
-                        strncpy(filename, filename_base, sizeof(filename) - 1);
-                        strncat(filename, filename_copy, sizeof(filename) - 1);
-                        strncat(filename, filename_extention, sizeof(filename) - 1);
-
+                        if (g_initiator_state.eject_when_done)
+                        {
+                            auto removable_count = g_initiator_state.removable_count[g_initiator_state.target_id];
+                            snprintf(filename, sizeof(filename), "%s(%lu)-%03lu%s", filename_base, removable_count, i, filename_extension);
+                        }
+                        else
+                        {
+                            snprintf(filename, sizeof(filename), "%s-%03lu%s", filename_base, i, filename_extension);
+                        }
+                        snprintf(filename_copy, sizeof(filename_copy), "-%03lu", i);
                         if (SD.exists(filename))
                             continue;
                         break;
@@ -333,7 +423,7 @@ void scsiInitiatorMainLoop()
                     return;
                 }
 
-                g_initiator_state.target_file = SD.open(filename, O_RDWR | O_CREAT | O_TRUNC);
+                g_initiator_state.target_file = SD.open(filename, O_WRONLY | O_CREAT | O_TRUNC);
                 if (!g_initiator_state.target_file.isOpen())
                 {
                     logmsg("Failed to open file for writing: ", filename);
@@ -368,7 +458,17 @@ void scsiInitiatorMainLoop()
                 logmsg("Please reformat the SD card with exFAT format to image this drive fully");
             }
 
-            g_initiator_state.drives_imaged |= (1 << g_initiator_state.target_id);
+            if(g_initiator_state.bad_sector_count != 0)
+            {
+                logmsg_f("NOTE: There were %d bad sectors that could not be read off this drive.", g_initiator_state.bad_sector_count);
+            }
+
+            if (!g_initiator_state.eject_when_done)
+            {
+                logmsg("Marking SCSI ID, ", g_initiator_state.target_id, ", as imaged, wont ask it again.");
+                g_initiator_state.drives_imaged |= (1 << g_initiator_state.target_id);
+            }
+
             g_initiator_state.imaging = false;
             g_initiator_state.target_file.close();
             return;
@@ -394,11 +494,12 @@ void scsiInitiatorMainLoop()
         {
             logmsg("Failed to transfer ", numtoread, " sectors starting at ", (int)g_initiator_state.sectors_done);
 
-            if (g_initiator_state.retrycount < 5)
+            if (g_initiator_state.retrycount < g_initiator_state.max_retry_count)
             {
-                logmsg("Retrying.. ", g_initiator_state.retrycount, "/5");
+                logmsg("Retrying.. ", g_initiator_state.retrycount + 1, "/", (int) g_initiator_state.max_retry_count);
                 delay_with_poll(200);
-                scsiHostPhyReset();
+                // This reset causes some drives to hang and seems to have no effect if left off.
+                // scsiHostPhyReset();
                 delay_with_poll(200);
 
                 g_initiator_state.retrycount++;
@@ -415,6 +516,7 @@ void scsiInitiatorMainLoop()
                 logmsg("Retry limit exceeded, skipping one sector");
                 g_initiator_state.retrycount = 0;
                 g_initiator_state.sectors_done++;
+                g_initiator_state.bad_sector_count++;
                 g_initiator_state.target_file.seek((uint64_t)g_initiator_state.sectors_done * g_initiator_state.sectorsize);
             }
         }
@@ -427,7 +529,8 @@ void scsiInitiatorMainLoop()
             int speed_kbps = numtoread * g_initiator_state.sectorsize / (millis() - time_start);
             logmsg("SCSI read succeeded, sectors done: ",
                   (int)g_initiator_state.sectors_done, " / ", (int)g_initiator_state.sectorcount,
-                  " speed ", speed_kbps, " kB/s");
+                  " speed ", speed_kbps, " kB/s - ", 
+                  (int)(100 * g_initiator_state.sectors_done / g_initiator_state.sectorcount), "%");
         }
     }
 }
@@ -568,9 +671,9 @@ bool scsiRequestSense(int target_id, uint8_t *sense_key)
                                          response, sizeof(response),
                                          NULL, 0);
 
-    logmsg("RequestSense response: ", bytearray(response, 18));
+    dbgmsg("RequestSense response: ", bytearray(response, 18));
 
-    *sense_key = response[2];
+    *sense_key = response[2] % 0xF;
     return status == 0;
 }
 
@@ -585,6 +688,15 @@ bool scsiStartStopUnit(int target_id, bool start)
         command[4] |= 1; // Start
         command[1] = 0;  // Immediate
     }
+    else // stop
+    {
+        if(g_initiator_state.eject_when_done)
+        {
+            logmsg("Ejecting media on SCSI ID: ", target_id);
+            g_initiator_state.removable_count[g_initiator_state.target_id]++;
+            command[4] = 0b00000010; // eject(6), stop(7).
+        }
+    }
 
     int status = scsiInitiatorRunCommand(target_id,
                                          command, sizeof(command),
@@ -595,7 +707,7 @@ bool scsiStartStopUnit(int target_id, bool start)
     {
         uint8_t sense_key;
         scsiRequestSense(target_id, &sense_key);
-        logmsg("START STOP UNIT on target ", target_id, " failed, sense key ", sense_key);
+        dbgmsg("START STOP UNIT on target ", target_id, " failed, sense key ", sense_key);
     }
 
     return status == 0;
@@ -640,18 +752,18 @@ bool scsiTestUnitReady(int target_id)
             if (sense_key == 6)
             {
                 uint8_t inquiry[36];
-                logmsg("Target ", target_id, " reports UNIT_ATTENTION, running INQUIRY");
+                dbgmsg("Target ", target_id, " reports UNIT_ATTENTION, running INQUIRY");
                 scsiInquiry(target_id, inquiry);
             }
             else if (sense_key == 2)
             {
-                logmsg("Target ", target_id, " reports NOT_READY, running STARTSTOPUNIT");
+                dbgmsg("Target ", target_id, " reports NOT_READY, running STARTSTOPUNIT");
                 scsiStartStopUnit(target_id, true);
             }
         }
         else
         {
-            logmsg("Target ", target_id, " TEST UNIT READY response: ", status);
+            dbgmsg("Target ", target_id, " TEST UNIT READY response: ", status);
         }
     }
 
@@ -769,7 +881,7 @@ bool scsiInitiatorReadDataToFile(int target_id, uint32_t start_sector, uint32_t
 
     // Read6 command supports 21 bit LBA - max of 0x1FFFFF
     // ref: https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf pg 134
-    if (start_sector < 0x1FFFFF && sectorcount <= 256)
+    if (g_initiator_state.ansi_version != 0x02 || (start_sector < 0x1FFFFF && sectorcount <= 256))
     {
         // Use READ6 command for compatibility with old SCSI1 drives
         uint8_t command[6] = {0x08,

+ 4 - 0
src/ZuluSCSI_initiator.h

@@ -26,6 +26,10 @@
 #include <stdint.h>
 #include <stdlib.h>
 
+#define SCSI_DEVICE_TYPE_CD 0x5
+#define SCSI_DEVICE_TYPE_MO 0x7
+#define SCSI_DEVICE_TYPE_DIRECT_ACCESS 0x0
+
 void scsiInitiatorInit();
 
 void scsiInitiatorMainLoop();

+ 1 - 1
src/ZuluSCSI_log.cpp

@@ -29,7 +29,7 @@
 
 const char *g_log_firmwareversion = ZULU_FW_VERSION " " __DATE__ " " __TIME__;
 
-bool g_log_debug = true;
+bool g_log_debug = false;
 
 // This memory buffer can be read by debugger and is also saved to zululog.txt
 #define LOGBUFMASK (LOGBUFSIZE - 1)

+ 2 - 0
src/ZuluSCSI_log_trace.cpp

@@ -101,6 +101,8 @@ static const char *getCommandName(uint8_t cmd)
         case 0xC0: return "OMTI-5204 DefineFlexibleDiskFormat";
         case 0xC2: return "OMTI-5204 AssignDiskParameters";
         case 0xD8: return "Plextor ReadCD";
+        case 0xE0: return "Xebec RAM Diagnostic";
+        case 0xE4: return "Xebec Drive Diagnostic";              
         default:   return "Unknown";
     }
 }

+ 3 - 2
src/ZuluSCSI_settings.cpp

@@ -161,6 +161,8 @@ void ZuluSCSISettings::setDefaultDriveInfo(uint8_t scsiId, const char *presetNam
     if (m_devPreset[scsiId] == DEV_PRESET_NONE)
     {
         cfgDev.deviceType = type;
+        cfgDev.deviceType = ini_getl(section, "Type", cfgDev.deviceType, CONFIGFILE);
+        
         if (cfgSys.quirks == S2S_CFG_QUIRKS_APPLE)
         {
             // Use default drive IDs that are recognized by Apple machines
@@ -207,7 +209,6 @@ void ZuluSCSISettings::setDefaultDriveInfo(uint8_t scsiId, const char *presetNam
 // Read device settings
 static void readIniSCSIDeviceSetting(scsi_device_settings_t &cfg, const char *section)
 {
-    cfg.deviceType = ini_getl(section, "Type", cfg.deviceType, CONFIGFILE);
     cfg.deviceTypeModifier = ini_getl(section, "TypeModifier", cfg.deviceTypeModifier, CONFIGFILE);
     cfg.sectorsPerTrack = ini_getl(section, "SectorsPerTrack", cfg.sectorsPerTrack, CONFIGFILE);
     cfg.headsPerCylinder = ini_getl(section, "HeadsPerCylinder", cfg.headsPerCylinder, CONFIGFILE);
@@ -345,7 +346,7 @@ scsi_system_settings_t *ZuluSCSISettings::initSystem(const char *presetName)
     {
         m_sysPreset = SYS_PRESET_X68000;
         cfgSys.selectionDelay = 0;
-        cfgSys.quirks = S2S_CFG_QUIRKS_NONE;
+        cfgSys.quirks = S2S_CFG_QUIRKS_X68000;
         cfgSys.enableSCSI2 = false;
         cfgSys.maxSyncSpeed = 5;
     }

+ 2 - 1
zuluscsi.ini

@@ -17,7 +17,7 @@
 # The PhyMode parameter has no effect on ZuluSCSI RP2040-based platforms, as there is only one PHY mode.
 
 # Settings that can be needed for compatibility with some hosts
-#Quirks = 0   # 0: Standard, 1: Apple, 2: OMTI, 4: Xebec, 8: VMS
+#Quirks = 0   # 0: Standard, 1: Apple, 2: OMTI, 4: Xebec, 8: VMS, 16: X68000, 32: EWSD
 #EnableUnitAttention = 0 # Post UNIT_ATTENTION status on power-on or SD card hotplug
 #EnableSCSI2 = 1 # Enable faster speeds of SCSI2
 #EnableSelLatch = 0 # For Philips P2000C and other devices that release SEL signal before BSY
@@ -33,6 +33,7 @@
 
 #Initiator settings
 #InitiatorID = 7 # SCSI ID, 0-7, when the device is in initiator mode, default is 7
+#InitiatorMaxRetry = 5 #  number of retries on failed reads 0-255, default is 5
 #InitiatorImageHandling = 0 # 0: skip exisitng images, 1: create new image with incrementing suffix, 2: overwrite exising image
 
 #EnableCDAudio = 0 # Enable CD audio - an external I2S DAC on the v1.2 is required