فهرست منبع

Merge pull request #316 from ZuluSCSI/initiator-mode-updates

Initiator mode improvements
Alex Perez 2 سال پیش
والد
کامیت
cd790cf33b

+ 1 - 1
lib/ZuluSCSI_platform_RP2040/rp2040.ld

@@ -22,7 +22,7 @@
 MEMORY
 {
     FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 352k
-    RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 240k  /* Leave space for pico-debug */
+    RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k  /* Leave space for pico-debug */
     SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
     SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k
 }

+ 2 - 5
lib/ZuluSCSI_platform_RP2040/scsiHostPhy.cpp

@@ -62,9 +62,9 @@ void scsiHostPhyReset(void)
     g_scsiHostPhyReset = false;
 }
 
-// Select a device, id 0-7.
+// Select a device and an initiator, ids 0-7.
 // Returns true if the target answers to selection request.
-bool scsiHostPhySelect(int target_id)
+bool scsiHostPhySelect(int target_id, uint8_t initiator_id)
 {
     SCSI_RELEASE_OUTPUTS();
 
@@ -86,9 +86,6 @@ bool scsiHostPhySelect(int target_id)
         }
     }
 
-    // Choose initiator ID different than target ID
-    uint8_t initiator_id = (target_id == 7) ? 0 : 7;
-
     // Selection phase
     scsiLogInitiatorPhaseChange(SELECTION);
     dbgmsg("------ SELECTING ", target_id, " with initiator ID ", (int)initiator_id);

+ 3 - 1
lib/ZuluSCSI_platform_RP2040/scsiHostPhy.h

@@ -34,8 +34,10 @@ extern volatile int g_scsiHostPhyReset;
 void scsiHostPhyReset(void);
 
 // Select a device, id 0-7.
+// target_id - target device id 0-7
+// initiator_id - host device id 0-7
 // Returns true if the target answers to selection request.
-bool scsiHostPhySelect(int target_id);
+bool scsiHostPhySelect(int target_id, uint8_t initiator_id);
 
 // Read the current communication phase as signaled by the target
 // Matches SCSI_PHASE enumeration from scsi.h.

+ 1 - 0
platformio.ini

@@ -98,6 +98,7 @@ lib_deps =
     ZuluSCSI_platform_RP2040
     SCSI2SD
     CUEParser
+debug_build_flags = -O2 -ggdb -g3
 build_flags =
     -O2 -Isrc -ggdb -g3
     -Wall -Wno-sign-compare -Wno-ignored-qualifiers

+ 112 - 16
src/ZuluSCSI_initiator.cpp

@@ -29,6 +29,7 @@
 #include "ZuluSCSI_log_trace.h"
 #include "ZuluSCSI_initiator.h"
 #include <ZuluSCSI_platform.h>
+#include <minIni.h>
 #include "SdFat.h"
 
 #include <scsi2sd.h>
@@ -68,6 +69,8 @@ static struct {
     // Bitmap of all drives that have been imaged
     uint32_t drives_imaged;
 
+    uint8_t initiator_id;
+
     // Is imaging a drive in progress, or are we scanning?
     bool imaging;
 
@@ -94,7 +97,15 @@ void scsiInitiatorInit()
 {
     scsiHostPhyReset();
 
-    g_initiator_state.drives_imaged = 0;
+    g_initiator_state.initiator_id = ini_getl("SCSI", "InitiatorID", 7, CONFIGFILE);
+    if (g_initiator_state.initiator_id > 7)
+    {
+        logmsg("InitiatorID set to illegal value in, ", CONFIGFILE, ", defaulting to 7");
+        g_initiator_state.initiator_id = 7;
+    }
+    // treat initiator id as already imaged drive so it gets skipped
+    g_initiator_state.drives_imaged = 1 << g_initiator_state.initiator_id;
+
     g_initiator_state.imaging = false;
     g_initiator_state.target_id = -1;
     g_initiator_state.sectorsize = 0;
@@ -103,6 +114,8 @@ void scsiInitiatorInit()
     g_initiator_state.retrycount = 0;
     g_initiator_state.failposition = 0;
     g_initiator_state.max_sector_per_transfer = 512;
+
+
 }
 
 // Update progress bar LED during transfers
@@ -174,24 +187,25 @@ void scsiInitiatorMainLoop()
                 scsiInquiry(g_initiator_state.target_id, inquiry_data);
             LED_OFF();
 
+            uint64_t total_bytes = 0;
             if (readcapok)
             {
-                logmsg("SCSI id ", g_initiator_state.target_id,
+                logmsg("SCSI ID ", g_initiator_state.target_id,
                     " capacity ", (int)g_initiator_state.sectorcount,
                     " sectors x ", (int)g_initiator_state.sectorsize, " bytes");
 
                 g_initiator_state.sectorcount_all = g_initiator_state.sectorcount;
 
-                uint64_t total_bytes = (uint64_t)g_initiator_state.sectorcount * g_initiator_state.sectorsize;
+                total_bytes = (uint64_t)g_initiator_state.sectorcount * g_initiator_state.sectorsize;
                 logmsg("Drive total size is ", (int)(total_bytes / (1024 * 1024)), " MiB");
                 if (total_bytes >= 0xFFFFFFFF && SD.fatType() != FAT_TYPE_EXFAT)
                 {
                     // Note: the FAT32 limit is 4 GiB - 1 byte
-                    logmsg("Image files equal or larger than 4 GiB are only possible on exFAT filesystem");
-                    logmsg("Please reformat the SD card with exFAT format to image this drive fully");
-
-                    g_initiator_state.sectorcount = (uint32_t)0xFFFFFFFF / g_initiator_state.sectorsize;
-                    logmsg("Will image first 4 GiB - 1 = ", (int)g_initiator_state.sectorcount, " sectors");
+                    logmsg("Target SCSI ID ", g_initiator_state.target_id, " image size is equal or larger than 4 GiB.");
+                    logmsg("This is larger than the max filesize supported by SD card's filesystem");
+                    logmsg("Please reformat the SD card with exFAT format to image this target");
+                    g_initiator_state.drives_imaged |= 1 << g_initiator_state.target_id;
+                    return;
                 }
             }
             else if (startstopok)
@@ -209,22 +223,99 @@ void scsiInitiatorMainLoop()
                 g_initiator_state.sectorcount = g_initiator_state.sectorcount_all = 0;
             }
 
-            const char *filename_format = "HD00_imaged.hda";
+            char filename_base[12];
+            strncpy(filename_base, "HD00_imaged", sizeof(filename_base));
+            const char *filename_extention = ".hda";
             if (inquiryok)
             {
                 if ((inquiry_data[0] & 0x1F) == 5)
                 {
-                    filename_format = "CD00_imaged.iso";
+                    strncpy(filename_base, "CD00_imaged", sizeof(filename_base));
+                    filename_extention = ".iso";
                 }
             }
 
             if (g_initiator_state.sectorcount > 0)
             {
                 char filename[32] = {0};
-                strncpy(filename, filename_format, sizeof(filename) - 1);
-                filename[2] += g_initiator_state.target_id;
+                filename_base[2] += g_initiator_state.target_id;
+                strncpy(filename, filename_base, sizeof(filename) - 1);
+                strncat(filename, filename_extention, sizeof(filename) - 1);
+                static int handling = -1;
+                if (handling == -1)
+                {
+                    handling = ini_getl("SCSI", "InitiatorImageHandling", 0, CONFIGFILE);
+                }
+                // Stop if a file already exists
+                if (handling == 0)
+                {
+                    if (SD.exists(filename))
+                    {
+                        logmsg("File, ", filename, ", already exists, InitiatorImageHandling set to stop if file exists.");
+                        g_initiator_state.drives_imaged |= (1 << g_initiator_state.target_id);
+                        return;
+                    }
+                }
+                // Create a new copy to the file 002-999
+                else if (handling == 1)
+                {
+                    for (uint32_t i = 1; i <= 1000; i++)
+                    {
+                        if (i == 1)
+                        {
+                            if (SD.exists(filename))
+                                continue;
+                            break;
+                        }
+                        else if(i >= 1000)
+                        {
+                            logmsg("Max images created from SCSI ID ", g_initiator_state.target_id, ", skipping image creation");
+                            g_initiator_state.drives_imaged |= (1 << g_initiator_state.target_id);
+                            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 (SD.exists(filename))
+                            continue;
+                        break;
+                    }
+
+                }
+                // overwrite file if it exists
+                else if (handling == 2)
+                {
+                    if (SD.exists(filename))
+                    {
+                        logmsg("File, ",filename, " already exists, InitiatorImageHandling set to overwrite file");
+                        SD.remove(filename);
+                    }
+                }
+                // InitiatorImageHandling invalid setting
+                else
+                {
+                    static bool invalid_logged_once = false;
+                    if (!invalid_logged_once)
+                    {
+                        logmsg("InitiatorImageHandling is set to, ", handling, ", which is invalid");
+                        invalid_logged_once = true;
+                    }
+                    return;
+                }
+
+                uint64_t sd_card_free_bytes = (uint64_t)SD.vol()->freeClusterCount() * SD.vol()->bytesPerCluster();
+                if (sd_card_free_bytes < total_bytes)
+                {
+                    logmsg("SD Card only has ", (int)(sd_card_free_bytes / (1024 * 1024)),
+                           " MiB - not enough free space to image SCSI ID ", g_initiator_state.target_id);
+                    g_initiator_state.drives_imaged |= 1 << g_initiator_state.target_id;
+                    return;
+                }
 
-                SD.remove(filename);
                 g_initiator_state.target_file = SD.open(filename, O_RDWR | O_CREAT | O_TRUNC);
                 if (!g_initiator_state.target_file.isOpen())
                 {
@@ -334,7 +425,8 @@ int scsiInitiatorRunCommand(int target_id,
                             const uint8_t *bufOut, size_t bufOutLen,
                             bool returnDataPhase)
 {
-    if (!scsiHostPhySelect(target_id))
+
+    if (!scsiHostPhySelect(target_id, g_initiator_state.initiator_id))
     {
         dbgmsg("------ Target ", target_id, " did not respond");
         scsiHostPhyRelease();
@@ -468,10 +560,14 @@ bool scsiRequestSense(int target_id, uint8_t *sense_key)
 // Execute UNIT START STOP command to load/unload media
 bool scsiStartStopUnit(int target_id, bool start)
 {
-    uint8_t command[6] = {0x1B, 0, 0, 0, 0, 0};
+    uint8_t command[6] = {0x1B, 0x1, 0, 0, 0, 0};
     uint8_t response[4] = {0};
 
-    if (start) command[4] |= 1;
+    if (start)
+    {
+        command[4] |= 1; // Start
+        command[1] = 0;  // Immediate
+    }
 
     int status = scsiInitiatorRunCommand(target_id,
                                          command, sizeof(command),

+ 4 - 0
zuluscsi.ini

@@ -31,6 +31,10 @@
 #DisableROMDrive = 1 # Disable the ROM drive if it has been loaded to flash
 #ROMDriveSCSIID = 7 # Override ROM drive's SCSI ID
 
+#Initiator settings
+#InitiatorID = 7 # SCSI ID, 0-7, when the device is in initiator mode, default is 7
+#InitiatorImageHandling = 0 # 0: skip exisitng images, 1: create new image with incrementing suffix, 2: overwrite exising image
+
 # Settings that can be specified either per-device or for all devices.
 #Vendor = "QUANTUM"
 #Product = "FIREBALL1"