فهرست منبع

Add zuluscsi.ini setting VendorExtensions

Currently the only setting is specific to CD-ROM drives.
Setting `VendorExtensions = 1` under a device heading e.g. `[SCSI3]`
in the `zuluscsi.ini` file will add Plextor's 0xD8 SCSI vendor command.

This enables CD-ROM drives to act as certain models of Plextor's SCSI
CD-ROM drives. This command reads raw CD sectors that are 2352 bytes in
length. It start two sectors before the end of the TOC and since
ZuluSCSI doesn't support images with raw TOC data the sector offset
must start at 2 otherwise it will emit an error message.
Morio 1 سال پیش
والد
کامیت
0ff9d41047

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

@@ -132,7 +132,10 @@ typedef struct __attribute__((packed))
 
 	uint16_t quirks; // S2S_CFG_QUIRKS
 
-	uint8_t reserved[64]; // Pad out to 128 bytes for main section.
+	// bit flags vendor extention for specific device types
+	uint32_t vendorExtensions;
+
+	uint8_t reserved[60]; // Pad out to 128 bytes for main section.
 } S2S_TargetCfg;
 
 typedef struct __attribute__((packed))

+ 9 - 4
lib/SCSI2SD/src/firmware/scsi.c

@@ -301,11 +301,16 @@ static void process_Command()
 
 	group = scsiDev.cdb[0] >> 5;
 	scsiDev.cdbLen = CmdGroupBytes[group];
-	// vendor specific SCSI command lengths
-	if (scsiDev.cdb[0] == 0xD8)
+
+	if (scsiDev.target->cfg->deviceType == S2S_CFG_OPTICAL)
 	{
-		// Plextor CD-ROM drive - Vendor Read Command
-		scsiDev.cdbLen =  12;
+		// Plextor CD-ROM vendor extensions 0xD8
+		if (unlikely(scsiDev.target->cfg->vendorExtensions & VENDOR_EXTENSION_OPTICAL_PLEXTOR))
+
+			if (scsiDev.cdb[0] == 0xD8)
+			{
+				scsiDev.cdbLen =  12;
+			}
 	}
 	if (parityError &&
 		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))

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

@@ -182,6 +182,12 @@ typedef struct
 	int hostSpeedMeasured;
 } ScsiDevice;
 
+typedef enum
+{
+	VENDOR_EXTENSION_OPTICAL_PLEXTOR = 1 << 0,
+} VENDOR_EXTENSION_OPTICAL;
+
+
 extern ScsiDevice scsiDev;
 
 void process_Status(void);

+ 36 - 29
src/ZuluSCSI_cdrom.cpp

@@ -1839,19 +1839,29 @@ static bool doReadCapacity(uint32_t lba, uint8_t pmi)
     return true;
 }
 
-static void doReadD8(uint32_t lba, uint32_t length, int sector_length, int read_size)
+static void doReadD8(uint32_t lba, uint32_t length)
 {
+    const uint32_t CD_SECTOR_SIZE = 2352;
+    const uint32_t SD_BLOCKSIZE =  512;
+    const uint32_t bytes_per_sector = CD_SECTOR_SIZE;
+    const uint32_t bytes_per_block = SD_BLOCKSIZE;
+
     image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
     uint8_t *buf0 = scsiDev.data;
-    uint8_t *buf1;// = scsiDev.data + read_length;
+    uint8_t *buf1 = buf0 + (sizeof(scsiDev.data)/2);
     // Adjust for plextor d8 offset
-    if (lba - 2 < 0)
+    if ((int)lba - 2 < 0)
     {
-        logmsg("Error - lba is negative after plextor d8 2 sector adjustment");
+        logmsg("ERROR: Plextor vendor 0xD8 command LBA must be greater than 2, given: ", (int)lba);
+        scsiDev.status = CHECK_CONDITION;
+        scsiDev.target->sense.code = ILLEGAL_REQUEST;
+        scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
+        scsiDev.phase = STATUS;
+        return;
     }
     lba = lba -2;
 
-    uint64_t offset = lba * sector_length;
+    uint64_t offset = lba * bytes_per_sector;
 
 
     scsiDev.phase = DATA_IN;
@@ -1865,24 +1875,24 @@ static void doReadD8(uint32_t lba, uint32_t length, int sector_length, int read_
         diskEjectButtonUpdate(false);
 
         // Where in bytes the sector starts in the image file
-        uint64_t sector_start = offset + idx * sector_length;
+        uint64_t sector_start = offset + idx * bytes_per_sector;
         // Where to start reading the image file in bytes, aligned at or before sector start
-        uint64_t aligned_start = (sector_start / read_size) * read_size; 
+        uint64_t aligned_start = (sector_start / bytes_per_block) * bytes_per_block;
         // The difference between the sector start and aligned start
         uint32_t sector_start_offset = (uint32_t)(sector_start - aligned_start);
         // Where the sector on the CD ends in bytes
-        uint64_t sector_end = sector_start + sector_length - 1;
+        uint64_t sector_end = sector_start + bytes_per_sector - 1;
         // The number of aligned blocks on the image file to read rounded up
-        uint32_t number_of_read_sectors = (sector_end - aligned_start + read_size - 1) / read_size;
+        uint32_t number_of_read_sectors = (sector_end - aligned_start + bytes_per_block - 1) / bytes_per_block;
         // How many bytes to read from the image file
-        uint32_t aligned_read_length = number_of_read_sectors * read_size;
+        uint32_t aligned_read_length = number_of_read_sectors * bytes_per_block;
         img.file.seek(aligned_start);
 
         // Verify that previous write using this buffer has finished
         uint8_t *buf = ((idx & 1) ? buf1 : buf0);
         uint8_t *bufstart = buf + sector_start_offset;
         uint32_t start = millis();
-        while (!scsiIsWriteFinished(bufstart + sector_length - 1) && !scsiDev.resetFlag)
+        while (!scsiIsWriteFinished(bufstart + bytes_per_sector - 1) && !scsiDev.resetFlag)
         {
             if ((uint32_t)(millis() - start) > 5000)
             {
@@ -1894,14 +1904,12 @@ static void doReadD8(uint32_t lba, uint32_t length, int sector_length, int read_
         }
         if (scsiDev.resetFlag) break;
 
-        // User data
         img.file.read(buf, aligned_read_length);
 
-        scsiStartWrite(bufstart, sector_length);
+        scsiStartWrite(bufstart, bytes_per_sector);
     }
 
     scsiFinishWrite();
-
     scsiDev.status = 0;
     scsiDev.phase = STATUS;
 }
@@ -2208,27 +2216,26 @@ extern "C" int scsiCDRomCommand()
 
         doReadCD(lba, blocks, 0, 0x10, 0, true);
     }
-    else if (command == 0xD8)
+    else if (unlikely(scsiDev.target->cfg->vendorExtensions & VENDOR_EXTENSION_OPTICAL_PLEXTOR) && 
+            command == 0xD8)
     {
-        const uint32_t CD_DATA_SIZE = 2352;
-        const uint32_t CD_C2_SIZE = 294;
-        const uint32_t CD_SUBCODE_SIZE = 96;
-        const uint32_t CD_RAW_DATA_SIZE = CD_DATA_SIZE + CD_C2_SIZE + CD_SUBCODE_SIZE;
-        uint32_t bytes_per_sector = 0;
-        bytes_per_sector = ini_getl("SCSI","PlextorBytesPerSector", 0, CONFIGFILE);
-        uint32_t bytes_per_block = ini_getl("SCSI", "PlextorBytesPerBlock", 512 , CONFIGFILE);
-        if (bytes_per_sector == 0) bytes_per_sector = CD_DATA_SIZE;
         uint8_t lun = scsiDev.cdb[1] & 0x7;
         uint8_t subcode = scsiDev.cdb[10];
         if (lun != 0)
         {
-            logmsg("Error - only LUN 0 supported for plextor vender 0xD8 command CDDA Read. Given ", (int)lun);
-            commandHandled = 0;
+            logmsg("ERROR: Plextor vendor 0xD8 command only supports LUN 0. Given ", (int)lun);
+            scsiDev.status = CHECK_CONDITION;
+            scsiDev.target->sense.code = ILLEGAL_REQUEST;
+            scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
+            scsiDev.phase = STATUS;
         }
         else if (subcode != 0)
         {
-            logmsg("Error - Subcodes not supported yet. Given ", subcode);
-            commandHandled = 0;
+            logmsg("ERROR: Plextor vendor 0xD8 command subcodes not supported. Given ", subcode);
+            scsiDev.status = CHECK_CONDITION;
+            scsiDev.target->sense.code = ILLEGAL_REQUEST;
+            scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
+            scsiDev.phase = STATUS;
         }
         else
         {
@@ -2242,8 +2249,8 @@ extern "C" int scsiCDRomCommand()
                 (((uint32_t) scsiDev.cdb[7]) << 16) +
                 (((uint32_t) scsiDev.cdb[8]) << 8) +
                 scsiDev.cdb[9];
-            dbgmsg("Doing a Plextor 0xD8 CDDA Read, starting: ", (int)lba, " length: ",(int)blocks, " byte-per-sector: ", (int) bytes_per_sector, " byte=per=block: ", (int) bytes_per_block );
-            doReadD8(lba, blocks, bytes_per_sector, bytes_per_block);
+            dbgmsg("Plextor vendor 0xD8 command CDDA Read, starting: ", (int)lba, " length: ",(int)blocks);
+            doReadD8(lba, blocks);
         }
     }
     else if (command == 0x4E)

+ 2 - 0
src/ZuluSCSI_disk.cpp

@@ -250,6 +250,8 @@ static void scsiDiskSetImageConfig(uint8_t target_idx)
     img.reinsert_on_inquiry = devCfg->reinsertOnInquiry;
     img.reinsert_after_eject = devCfg->reinsertAfterEject;
     img.ejectButton = devCfg->ejectButton;
+    img.vendorExtensions = devCfg->vendorExtensions;
+
 #ifdef ENABLE_AUDIO_OUTPUT
     uint16_t vol = devCfg->vol;
     // Set volume on both channels

+ 4 - 0
src/ZuluSCSI_settings.cpp

@@ -225,6 +225,8 @@ static void readIniSCSIDeviceSetting(scsi_device_settings_t &cfg, const char *se
     cfg.sectorSDBegin = ini_getl(section, "SectorSDBegin", cfg.sectorSDBegin, CONFIGFILE);
     cfg.sectorSDEnd = ini_getl(section, "SectorSDEnd", cfg.sectorSDEnd, CONFIGFILE);
 
+    cfg.vendorExtensions = ini_getl(section, "VendorExtensions", cfg.vendorExtensions, CONFIGFILE);
+
     char tmp[32];
     ini_gets(section, "Vendor", "", tmp, sizeof(tmp), CONFIGFILE);
     if (tmp[0])
@@ -305,6 +307,8 @@ scsi_system_settings_t *ZuluSCSISettings::initSystem(const char *presetName)
     cfgDev.sectorSDBegin = 0;
     cfgDev.sectorSDEnd = 0;
 
+    cfgDev.vendorExtensions = 0;
+
     // System-specific defaults
 
     if (strequals(systemPresetName[SYS_PRESET_NONE], presetName))

+ 2 - 0
src/ZuluSCSI_settings.h

@@ -93,6 +93,8 @@ typedef struct __attribute__((__packed__)) scsi_device_settings_t
 
     uint32_t sectorSDBegin;
     uint32_t sectorSDEnd;
+
+    uint32_t vendorExtensions;
 } scsi_device_settings_t;
 
 

+ 2 - 0
zuluscsi.ini

@@ -47,6 +47,8 @@
 #Version = "1.0"
 #Serial = "0123456789ABCDEF"
 #Type = 0     # 0: Fixed, 1: Removable, 2: Optical, 3: Floppy, 4: Mag-optical, 5: Tape, 6: Network
+#VendorExtensions = 0 # Bit flags for specific extensions per device type
+#  CDROM - 1: Plextor's d8h vendor command
 #TypeModifier = 0  # Affects only INQUIRY response
 #SectorsPerTrack = 63
 #HeadsPerCylinder = 255