Skip to content

Commit

Permalink
Add zuluscsi.ini setting VendorExtensions
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
morio committed Feb 1, 2024
1 parent e3e864c commit 0ff9d41
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 34 deletions.
5 changes: 4 additions & 1 deletion lib/SCSI2SD/include/scsi2sd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
13 changes: 9 additions & 4 deletions lib/SCSI2SD/src/firmware/scsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
6 changes: 6 additions & 0 deletions lib/SCSI2SD/src/firmware/scsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
65 changes: 36 additions & 29 deletions src/ZuluSCSI_cdrom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
{
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
{
Expand All @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/ZuluSCSI_disk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/ZuluSCSI_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down Expand Up @@ -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))
Expand Down
2 changes: 2 additions & 0 deletions src/ZuluSCSI_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;


Expand Down
2 changes: 2 additions & 0 deletions zuluscsi.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0ff9d41

Please sign in to comment.