Moved DaynPort specific code

This commit is contained in:
Uwe Seimet 2021-08-22 17:52:36 +02:00
parent 806e0e0f27
commit d3a9ae48af
10 changed files with 215 additions and 243 deletions

View File

@ -836,14 +836,6 @@ void SASIDEV::CmdRead6()
ctrl.blocks = 0x100;
}
// TODO Move Daynaport specific test
// TODO This class must not know about SCDP
if(ctrl.device->IsDaynaPort()){
// The DaynaPort only wants one block.
// ctrl.cmd[4] and ctrl.cmd[5] are used to specify the maximum buffer size for the DaynaPort
ctrl.blocks=1;
}
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks);
// Command processing on drive
@ -851,7 +843,7 @@ void SASIDEV::CmdRead6()
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, (int)ctrl.length);
// The DaynaPort will respond a status of 0x02 when a read of size 1 occurs.
if (ctrl.length <= 0 && !ctrl.device->IsDaynaPort()) {
if (ctrl.length <= 0) {
// Failure (Error)
Error();
return;
@ -864,56 +856,6 @@ void SASIDEV::CmdRead6()
DataIn();
}
//---------------------------------------------------------------------------
//
// This Send Message command is used by the DaynaPort SCSI/Link
// TODO This class must not know about SCDP
//
//---------------------------------------------------------------------------
void SASIDEV::DaynaPortWrite()
{
// Error if not a DaynaPort device
if (!ctrl.device->IsDaynaPort()) {
LOGERROR("Received DaynaPortWrite for a non-DaynaPort device");
Error();
return;
}
// Reallocate buffer (because it is not transfer for each block)
if (ctrl.bufsize < DAYNAPORT_BUFFER_SIZE) {
free(ctrl.buffer);
ctrl.bufsize = DAYNAPORT_BUFFER_SIZE;
ctrl.buffer = (BYTE *)malloc(ctrl.bufsize);
}
DWORD data_format = ctrl.cmd[5];
if(data_format == 0x00){
ctrl.length = (WORD)ctrl.cmd[4] + ((WORD)ctrl.cmd[3] << 8);
}
else if (data_format == 0x80){
ctrl.length = (WORD)ctrl.cmd[4] + ((WORD)ctrl.cmd[3] << 8) + 8;
}
else
{
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format);
}
LOGTRACE("%s length: %04X (%d) format: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl.length, (int)ctrl.length, (unsigned int)data_format);
if (ctrl.length <= 0) {
// Failure (Error)
Error();
return;
}
// Set next block
ctrl.blocks = 1;
ctrl.next = 1;
// Light phase
DataOut();
}
//---------------------------------------------------------------------------
//
// WRITE(6)
@ -921,12 +863,6 @@ void SASIDEV::DaynaPortWrite()
//---------------------------------------------------------------------------
void SASIDEV::CmdWrite6()
{
// Special receive function for the DaynaPort
if (ctrl.device->IsDaynaPort()){
DaynaPortWrite();
return;
}
// Get record number and block number
DWORD record = ctrl.cmd[1] & 0x1f;
record <<= 8;
@ -1308,7 +1244,7 @@ BOOL SASIDEV::XferOut(BOOL cont)
}
// Special case Write function for DaynaPort
// TODO This class must not know about SCSIDP
// TODO This class must not know about DaynaPort
if (device->IsDaynaPort()) {
LOGTRACE("%s Doing special case write for DaynaPort", __PRETTY_FUNCTION__);
if (!(SCSIDaynaPort*)device->Write(ctrl.cmd, ctrl.buffer, ctrl.length)) {

View File

@ -89,6 +89,7 @@ public:
const int UNKNOWN_SCSI_ID = -1;
const int DEFAULT_BUFFER_SIZE = 0x1000;
// TODO Remove this duplicate
const int DAYNAPORT_BUFFER_SIZE = 0x1000000;
// For timing adjustments
@ -162,8 +163,6 @@ public:
void MsgIn(); // Message in phase
void DataOut(); // Data out phase
void DaynaPortWrite(); // DaynaPort specific 'write' operation
virtual void Error(ERROR_CODES::sense_key sense_key = ERROR_CODES::sense_key::NO_SENSE,
ERROR_CODES::asc = ERROR_CODES::asc::NO_ADDITIONAL_SENSE_INFORMATION); // Common error handling

View File

@ -41,25 +41,10 @@ SCSIDEV::SCSIDEV() : SASIDEV()
scsi.atnmsg = FALSE;
scsi.msc = 0;
memset(scsi.msb, 0x00, sizeof(scsi.msb));
// MMC specific. TODO Move to separate class
SetUpControllerCommand(eCmdReadToc, "CmdReadToc", &SCSIDEV::CmdReadToc);
SetUpControllerCommand(eCmdPlayAudio10, "CmdPlayAudio10", &SCSIDEV::CmdPlayAudio10);
SetUpControllerCommand(eCmdPlayAudioMSF, "CmdPlayAudioMSF", &SCSIDEV::CmdPlayAudioMSF);
SetUpControllerCommand(eCmdPlayAudioTrack, "CmdPlayAudioTrack", &SCSIDEV::CmdPlayAudioTrack);
SetUpControllerCommand(eCmdGetEventStatusNotification, "CmdGetEventStatusNotification", &SCSIDEV::CmdGetEventStatusNotification);
}
SCSIDEV::~SCSIDEV()
{
for (auto const& command : controller_commands) {
free(command.second);
}
}
void SCSIDEV::SetUpControllerCommand(scsi_command opcode, const char* name, void (SCSIDEV::*execute)(void))
{
controller_commands[opcode] = new controller_command_t(name, execute);
}
//---------------------------------------------------------------------------
@ -257,23 +242,7 @@ void SCSIDEV::Execute()
ctrl.execstart = SysTimer::GetTimerLow();
ctrl.device = ctrl.unit[GetLun()];
if (ctrl.device->Dispatch(this)) {
return;
}
// If the command is valid it must be contained in the command map
if (!controller_commands.count(static_cast<scsi_command>(ctrl.cmd[0]))) {
CmdInvalid();
return;
}
controller_command_t* command = controller_commands[static_cast<scsi_command>(ctrl.cmd[0])];
LOGDEBUG("++++ CMD ++++ %s ID %d received %s ($%02X)", __PRETTY_FUNCTION__, GetSCSIID(), command->name, (unsigned int)ctrl.cmd[0]);
// Process by command
(this->*command->execute)();
ctrl.device->Dispatch(this);
}
//---------------------------------------------------------------------------
@ -366,99 +335,6 @@ void SCSIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc)
Status();
}
//---------------------------------------------------------------------------
//
// Command
//
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//
// READ TOC
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdReadToc()
{
// Command processing on drive
ctrl.length = ctrl.device->ReadToc(ctrl.cmd, ctrl.buffer);
if (ctrl.length <= 0) {
// Failure (Error)
Error();
return;
}
// Data-in Phase
DataIn();
}
//---------------------------------------------------------------------------
//
// PLAY AUDIO(10)
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdPlayAudio10()
{
// Command processing on drive
bool status = ctrl.device->PlayAudio(ctrl.cmd);
if (!status) {
// Failure (Error)
Error();
return;
}
// status phase
Status();
}
//---------------------------------------------------------------------------
//
// PLAY AUDIO MSF
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdPlayAudioMSF()
{
// Command processing on drive
bool status = ctrl.device->PlayAudioMSF(ctrl.cmd);
if (!status) {
// Failure (Error)
Error();
return;
}
// status phase
Status();
}
//---------------------------------------------------------------------------
//
// PLAY AUDIO TRACK
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdPlayAudioTrack()
{
// Command processing on drive
bool status = ctrl.device->PlayAudioTrack(ctrl.cmd);
if (!status) {
// Failure (Error)
Error();
return;
}
// status phase
Status();
}
//---------------------------------------------------------------------------
//
// GET EVENT STATUS NOTIFICATION
//
//---------------------------------------------------------------------------
void SCSIDEV::CmdGetEventStatusNotification()
{
// This naive (but legal) implementation avoids constant warnings in the logs
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
}
//---------------------------------------------------------------------------
//
// GET MESSAGE(10)

View File

@ -85,15 +85,6 @@ public:
BYTE msb[256];
} scsi_t;
// SCSI command name and pointer to implementation
typedef struct _controller_command_t {
const char* name;
void (SCSIDEV::*execute)(void);
_controller_command_t(const char* _name, void (SCSIDEV::*_execute)(void)) : name(_name), execute(_execute) { };
} controller_command_t;
std::map<scsi_command, controller_command_t*> controller_commands;
public:
// Basic Functions
SCSIDEV();
@ -115,7 +106,6 @@ public:
void CmdSendMessage10(); // SEND MESSAGE(10) command
private:
void SetUpControllerCommand(scsi_command, const char*, void (SCSIDEV::*)(void));
// Phase
void BusFree(); // Bus free phase
@ -124,10 +114,6 @@ private:
void MsgOut(); // Message out phase
// commands
void CmdReadToc(); // READ TOC command
void CmdPlayAudio10(); // PLAY AUDIO(10) command
void CmdPlayAudioMSF(); // PLAY AUDIO MSF command
void CmdPlayAudioTrack(); // PLAY AUDIO TRACK INDEX command
void CmdGetEventStatusNotification();
void CmdModeSelect10(); // MODE SELECT(10) command
void CmdModeSense10(); // MODE SENSE(10) command

View File

@ -469,24 +469,15 @@ void Disk::Read6(SASIDEV *controller)
ctrl->blocks = 0x100;
}
// TODO Move Daynaport specific test
// TODO This class must not know about SCDP
if(IsDaynaPort()){
// The DaynaPort only wants one block.
// ctrl.cmd[4] and ctrl.cmd[5] are used to specify the maximum buffer size for the DaynaPort
ctrl->blocks=1;
}
else {
// Check capacity
DWORD capacity = GetBlockCount();
if (record > capacity || record + ctrl->blocks > capacity) {
ostringstream s;
s << "Media capacity of " << capacity << " blocks exceeded: "
<< "Trying to read block " << record << ", block count " << ctrl->blocks;
LOGWARN("%s", s.str().c_str());
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
// Check capacity
DWORD capacity = GetBlockCount();
if (record > capacity || record + ctrl->blocks > capacity) {
ostringstream s;
s << "Media capacity of " << capacity << " blocks exceeded: "
<< "Trying to read block " << record << ", block count " << ctrl->blocks;
LOGWARN("%s", s.str().c_str());
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::LBA_OUT_OF_RANGE);
return;
}
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl->blocks);
@ -615,12 +606,6 @@ void Disk::Write6(SASIDEV *controller)
{
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();
// Special receive function for the DaynaPort
if (IsDaynaPort()){
controller->DaynaPortWrite();
return;
}
// Get record number and block number
DWORD record = ctrl->cmd[1] & 0x1f;
record <<= 8;
@ -1340,7 +1325,7 @@ void Disk::AddCommand(SCSIDEV::scsi_command opcode, const char* name, void (Disk
commands[opcode] = new command_t(name, execute);
}
bool Disk::Dispatch(SCSIDEV *controller)
bool Disk::Dispatch(SASIDEV *controller)
{
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();

View File

@ -231,7 +231,7 @@ public:
bool Format(const DWORD *cdb); // FORMAT UNIT command
bool Reassign(const DWORD *cdb); // REASSIGN UNIT command
virtual bool Dispatch(SCSIDEV *);
virtual bool Dispatch(SASIDEV *);
protected:
// Internal processing

View File

@ -89,12 +89,14 @@ SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
m_mac_addr[5]=0xE3;
#endif // linux
LOGTRACE("SCSIDaynaPort Constructor End");
AddCommand(SCSIDEV::eCmdRead6, "CmdRead6", &SCSIDaynaPort::CmdRead6);
AddCommand(SCSIDEV::eCmdWrite6, "CmdWrite6", &SCSIDaynaPort::CmdWrite6);
AddCommand(SCSIDEV::eCmdRetrieveStats, "CmdRetrieveStats", &SCSIDaynaPort::CmdRetrieveStats);
AddCommand(SCSIDEV::eCmdSetIfaceMode, "CmdSetIfaceMode", &SCSIDaynaPort::CmdSetIfaceMode);
AddCommand(SCSIDEV::eCmdSetMcastAddr, "CmdSetMcastAddr", &SCSIDaynaPort::CmdSetMcastAddr);
AddCommand(SCSIDEV::eCmdEnableInterface, "CmdEnableInterface", &SCSIDaynaPort::CmdEnableInterface);
AddCommand(SCSIDEV::eCmdGetEventStatusNotification, "CmdGetEventStatusNotification", &SCSIDaynaPort::CmdGetEventStatusNotification);
}
//---------------------------------------------------------------------------
@ -104,7 +106,6 @@ SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
//---------------------------------------------------------------------------
SCSIDaynaPort::~SCSIDaynaPort()
{
LOGTRACE("SCSIDaynaPort Destructor");
// TAP driver release
if (m_tap) {
m_tap->Cleanup();
@ -116,9 +117,10 @@ SCSIDaynaPort::~SCSIDaynaPort()
}
}
void SCSIDaynaPort::Open(const Filepath& path, BOOL attn)
void SCSIDaynaPort::Open(const Filepath& path, BOOL attn)
{
LOGTRACE("SCSIDaynaPort Open");
m_tap->OpenDump(path);
}
@ -127,7 +129,7 @@ SCSIDaynaPort::~SCSIDaynaPort()
commands[opcode] = new command_t(name, execute);
}
bool SCSIDaynaPort::Dispatch(SCSIDEV *controller)
bool SCSIDaynaPort::Dispatch(SASIDEV *controller)
{
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();
@ -510,11 +512,6 @@ bool SCSIDaynaPort::EnableInterface(const DWORD *cdb)
return result;
}
//---------------------------------------------------------------------------
//
// TEST UNIT READY
//
//---------------------------------------------------------------------------
bool SCSIDaynaPort::TestUnitReady(const DWORD* /*cdb*/)
{
LOGTRACE("%s", __PRETTY_FUNCTION__);
@ -523,6 +520,73 @@ bool SCSIDaynaPort::TestUnitReady(const DWORD* /*cdb*/)
return true;
}
void SCSIDaynaPort::CmdRead6(SASIDEV *controller)
{
LOGTRACE("%s",__PRETTY_FUNCTION__);
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();
// Get record number and block number
DWORD record = ctrl->cmd[1] & 0x1f;
record <<= 8;
record |= ctrl->cmd[2];
record <<= 8;
record |= ctrl->cmd[3];
ctrl->blocks=1;
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl->blocks);
ctrl->length = Read(ctrl->cmd, ctrl->buffer, record);
LOGTRACE("%s ctrl.length is %d", __PRETTY_FUNCTION__, (int)ctrl->length);
// Set next block
ctrl->next = record + 1;
// Read phase
controller->DataIn();
}
void SCSIDaynaPort::CmdWrite6(SASIDEV *controller)
{
LOGTRACE("%s",__PRETTY_FUNCTION__);
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();
// Reallocate buffer (because it is not transfer for each block)
if (ctrl->bufsize < DAYNAPORT_BUFFER_SIZE) {
free(ctrl->buffer);
ctrl->bufsize = DAYNAPORT_BUFFER_SIZE;
ctrl->buffer = (BYTE *)malloc(ctrl->bufsize);
}
DWORD data_format = ctrl->cmd[5];
if(data_format == 0x00){
ctrl->length = (WORD)ctrl->cmd[4] + ((WORD)ctrl->cmd[3] << 8);
}
else if (data_format == 0x80){
ctrl->length = (WORD)ctrl->cmd[4] + ((WORD)ctrl->cmd[3] << 8) + 8;
}
else
{
LOGWARN("%s Unknown data format %02X", __PRETTY_FUNCTION__, (unsigned int)data_format);
}
LOGTRACE("%s length: %04X (%d) format: %02X", __PRETTY_FUNCTION__, (unsigned int)ctrl->length, (int)ctrl->length, (unsigned int)data_format);
if (ctrl->length <= 0) {
// Failure (Error)
controller->Error();
return;
}
// Set next block
ctrl->blocks = 1;
ctrl->next = 1;
// Data out phase
controller->DataOut();
}
void SCSIDaynaPort::CmdRetrieveStats(SASIDEV *controller)
{
LOGTRACE("%s",__PRETTY_FUNCTION__);
@ -607,6 +671,14 @@ void SCSIDaynaPort::CmdEnableInterface(SASIDEV *controller)
controller->Status();
}
void SCSIDaynaPort::CmdGetEventStatusNotification(SASIDEV *controller)
{
LOGTRACE("%s",__PRETTY_FUNCTION__);
// This naive (but legal) implementation avoids constant warnings in the logs
controller->Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_FIELD_IN_CDB);
}
//---------------------------------------------------------------------------
//
// Set Mode - enable broadcast messages

View File

@ -82,12 +82,17 @@ public:
void SetMode(const DWORD *cdb, BYTE *buffer);
// Set the mode: whether broadcast traffic is enabled or not
void CmdRead6(SASIDEV *);
void CmdWrite6(SASIDEV *);
void CmdRetrieveStats(SASIDEV *);
void CmdSetIfaceMode(SASIDEV *);
void CmdSetMcastAddr(SASIDEV *);
void CmdEnableInterface(SASIDEV *);
void CmdGetEventStatusNotification(SASIDEV *);
bool Dispatch(SCSIDEV *);
bool Dispatch(SASIDEV *);
const int DAYNAPORT_BUFFER_SIZE = 0x1000000;
static const BYTE CMD_SCSILINK_STATS = 0x09;
static const BYTE CMD_SCSILINK_ENABLE = 0x0E;

View File

@ -244,6 +244,11 @@ SCSICD::SCSICD() : Disk("SCCD")
tracks = 0;
dataindex = -1;
audioindex = -1;
AddCommand(SCSIDEV::eCmdReadToc, "CmdReadToc", &SCSICD::CmdReadToc);
AddCommand(SCSIDEV::eCmdPlayAudio10, "CmdPlayAudio10", &SCSICD::CmdPlayAudio10);
AddCommand(SCSIDEV::eCmdPlayAudioMSF, "CmdPlayAudioMSF", &SCSICD::CmdPlayAudioMSF);
AddCommand(SCSIDEV::eCmdPlayAudioTrack, "CmdPlayAudioTrack", &SCSICD::CmdPlayAudioTrack);
}
//---------------------------------------------------------------------------
@ -255,6 +260,32 @@ SCSICD::~SCSICD()
{
// Clear track
ClearTrack();
for (auto const& command : commands) {
free(command.second);
}
}
void SCSICD::AddCommand(SCSIDEV::scsi_command opcode, const char* name, void (SCSICD::*execute)(SASIDEV *))
{
commands[opcode] = new command_t(name, execute);
}
bool SCSICD::Dispatch(SASIDEV *controller)
{
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();
if (commands.count(static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0]))) {
command_t *command = commands[static_cast<SCSIDEV::scsi_command>(ctrl->cmd[0])];
LOGDEBUG("++++ CMD ++++ %s received %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl->cmd[0]);
(this->*command->execute)(controller);
return true;
}
return Disk::Dispatch(controller);
}
//---------------------------------------------------------------------------
@ -470,6 +501,69 @@ void SCSICD::OpenPhysical(const Filepath& path)
dataindex = 0;
}
void SCSICD::CmdReadToc(SASIDEV *controller)
{
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();
ctrl->length = ReadToc(ctrl->cmd, ctrl->buffer);
if (ctrl->length <= 0) {
// Failure (Error)
controller->Error();
return;
}
// Data-in Phase
controller->DataIn();
}
void SCSICD::CmdPlayAudio10(SASIDEV *controller)
{
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();
// Command processing on drive
bool status = PlayAudio(ctrl->cmd);
if (!status) {
// Failure (Error)
controller->Error();
return;
}
// Status phase
controller->Status();
}
void SCSICD::CmdPlayAudioMSF(SASIDEV *controller)
{
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();
// Command processing on drive
bool status = PlayAudioMSF(ctrl->cmd);
if (!status) {
// Failure (Error)
controller->Error();
return;
}
// Status phase
controller->Status();
}
void SCSICD::CmdPlayAudioTrack(SASIDEV *controller)
{
SASIDEV::ctrl_t *ctrl = controller->GetWorkAddr();
// Command processing on drive
bool status = PlayAudioTrack(ctrl->cmd);
if (!status) {
// Failure (Error)
controller->Error();
return;
}
// Status phase
controller->Status();
}
//---------------------------------------------------------------------------
//
// INQUIRY

View File

@ -69,6 +69,15 @@ private:
//===========================================================================
class SCSICD : public Disk, public FileSupport
{
private:
typedef struct _command_t {
const char* name;
void (SCSICD::*execute)(SASIDEV *);
_command_t(const char* _name, void (SCSICD::*_execute)(SASIDEV *)) : name(_name), execute(_execute) { };
} command_t;
std::map<SCSIDEV::scsi_command, command_t*> commands;
public:
// Number of tracks
enum {
@ -96,11 +105,21 @@ public:
void LBAtoMSF(DWORD lba, BYTE *msf) const; // LBA→MSF conversion
DWORD MSFtoLBA(const BYTE *msf) const; // MSF→LBA conversion
bool Dispatch(SASIDEV *);
private:
// Open
void OpenCue(const Filepath& path); // Open(CUE)
void OpenIso(const Filepath& path); // Open(ISO)
void OpenPhysical(const Filepath& path); // Open(Physical)
void AddCommand(SCSIDEV::scsi_command, const char*, void (SCSICD::*)(SASIDEV *));
void CmdReadToc(SASIDEV *);
void CmdPlayAudio10(SASIDEV *);
void CmdPlayAudioMSF(SASIDEV *);
void CmdPlayAudioTrack(SASIDEV *);
BOOL rawfile; // RAW flag
// Track management