mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-26 13:49:21 +00:00
SASI FORMAT opcode fix, SASI segfault fix, added SASI INQUIRY/READ CAPACITY, 512 bytes per sector SASI drives (#724)
* Fixed opcode
* Fixed segfault
* Re-added 0x06 as additional SASI FORMAT opcode
* Added support of SASI drives with 512 bytes
* SASI LUN must always be taken from CDB and must be 0 or 1
* Fixed typo
* Fixed one more SASI segfault
* Removed duplicate code
* Updated error handling
* Updated error handling
* Logging update
* Added enum value for SPC-6
* Comment update
* Added support for SASI Inquiry
* Updated SASI LUN check
* Updated SASI LUN handling
* Comment update
* Revert "Comment update"
This reverts commit c6adbde25c
.
* Updated logging
* Implemented SASI READ CAPACITY
* Validate SASI block count
* Do not support ICD semantics for SASI drives
* SASI READ CAPACITY is a group 1 command with 10 bytes
* Comment update
This commit is contained in:
parent
536e77cd9d
commit
9099d7249c
@ -309,7 +309,7 @@ void SASIDEV::Command()
|
|||||||
ctrl.blocks = 1;
|
ctrl.blocks = 1;
|
||||||
|
|
||||||
// If no byte can be received move to the status phase
|
// If no byte can be received move to the status phase
|
||||||
int count = ctrl.bus->CommandHandShake(ctrl.buffer);
|
int count = ctrl.bus->CommandHandShake(ctrl.buffer, IsSASI());
|
||||||
if (!count) {
|
if (!count) {
|
||||||
Error();
|
Error();
|
||||||
return;
|
return;
|
||||||
@ -355,74 +355,95 @@ void SASIDEV::Execute()
|
|||||||
ctrl.blocks = 1;
|
ctrl.blocks = 1;
|
||||||
ctrl.execstart = SysTimer::GetTimerLow();
|
ctrl.execstart = SysTimer::GetTimerLow();
|
||||||
|
|
||||||
|
int lun = GetEffectiveLun();
|
||||||
|
if (!ctrl.unit[lun]) {
|
||||||
|
ctrl.device->SetStatusCode(STATUS_INVALIDLUN);
|
||||||
|
Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_LUN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl.device = ctrl.unit[lun];
|
||||||
|
ctrl.device->SetCtrl(&ctrl);
|
||||||
|
|
||||||
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
|
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
|
||||||
if ((SASIDEV::sasi_command)ctrl.cmd[0] != SASIDEV::eCmdRequestSense) {
|
if ((SASIDEV::sasi_command)ctrl.cmd[0] != SASIDEV::eCmdRequestSense) {
|
||||||
ctrl.status = 0;
|
ctrl.status = 0;
|
||||||
ctrl.device->SetStatusCode(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process by command
|
// Process by command
|
||||||
// TODO This code does not belong here. Each device type needs such a dispatcher, which the controller has to call.
|
|
||||||
switch ((SASIDEV::sasi_command)ctrl.cmd[0]) {
|
switch ((SASIDEV::sasi_command)ctrl.cmd[0]) {
|
||||||
// TEST UNIT READY
|
|
||||||
case SASIDEV::eCmdTestUnitReady:
|
case SASIDEV::eCmdTestUnitReady:
|
||||||
CmdTestUnitReady();
|
LOGTRACE( "%s TEST UNIT READY Command", __PRETTY_FUNCTION__);
|
||||||
|
ctrl.device->TestUnitReady(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// REZERO UNIT
|
|
||||||
case SASIDEV::eCmdRezero:
|
case SASIDEV::eCmdRezero:
|
||||||
CmdRezero();
|
LOGTRACE( "%s REZERO Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->Rezero(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// REQUEST SENSE
|
|
||||||
case SASIDEV::eCmdRequestSense:
|
case SASIDEV::eCmdRequestSense:
|
||||||
CmdRequestSense();
|
LOGTRACE( "%s REQUEST SENSE Command", __PRETTY_FUNCTION__);
|
||||||
|
ctrl.device->RequestSense(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// FORMAT
|
// FORMAT (the old RaSCSI code used 0x06 as opcode, which is not compliant with the SASI specification)
|
||||||
|
// The FORMAT command of RaSCSI does not do anything but just returns a GOOD status
|
||||||
case SASIDEV::eCmdFormat:
|
case SASIDEV::eCmdFormat:
|
||||||
CmdFormat();
|
case SASIDEV::eCmdFormatLegacy:
|
||||||
|
LOGTRACE( "%s FORMAT UNIT Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->FormatUnit(this);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SASIDEV::eCmdReadCapacity:
|
||||||
|
LOGTRACE( "%s READ CAPACITY Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->ReadCapacity10(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// REASSIGN BLOCKS
|
|
||||||
case SASIDEV::eCmdReassign:
|
case SASIDEV::eCmdReassign:
|
||||||
CmdReassignBlocks();
|
LOGTRACE( "%s REASSIGN BLOCKS Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->ReassignBlocks(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// READ(6)
|
|
||||||
case SASIDEV::eCmdRead6:
|
case SASIDEV::eCmdRead6:
|
||||||
CmdRead6();
|
LOGTRACE( "%s READ Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->Read6(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// WRITE(6)
|
|
||||||
case SASIDEV::eCmdWrite6:
|
case SASIDEV::eCmdWrite6:
|
||||||
CmdWrite6();
|
LOGTRACE( "%s WRITE Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->Write6(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// SEEK(6)
|
|
||||||
case SASIDEV::eCmdSeek6:
|
case SASIDEV::eCmdSeek6:
|
||||||
CmdSeek6();
|
LOGTRACE( "%s SEEK Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->Seek(this);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SASIDEV::eCmdInquiry:
|
||||||
|
LOGTRACE( "%s INQUIRY Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->Inquiry(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// ASSIGN (SASI only)
|
// ASSIGN (SASI only)
|
||||||
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
|
// This doesn't exist in the SASI Spec, but was in the original RaSCSI code.
|
||||||
// leaving it here for now....
|
// leaving it here for now....
|
||||||
case SASIDEV::eCmdSasiCmdAssign:
|
case SASIDEV::eCmdSasiCmdAssign:
|
||||||
CmdAssign();
|
CmdAssign();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// RESERVE UNIT(16)
|
|
||||||
case SASIDEV::eCmdReserve6:
|
case SASIDEV::eCmdReserve6:
|
||||||
CmdReserveUnit();
|
LOGTRACE( "%s RESERVE Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->Reserve(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// RELEASE UNIT(17)
|
|
||||||
case eCmdRelease6:
|
case eCmdRelease6:
|
||||||
CmdReleaseUnit();
|
LOGTRACE( "%s RELEASE Command", __PRETTY_FUNCTION__);
|
||||||
|
((Disk *)ctrl.device)->Release(this);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// SPECIFY (SASI only)
|
// SPECIFY (SASI only)
|
||||||
// This doesn't exist in the SCSI Spec, but was in the original RaSCSI code.
|
// This doesn't exist in the SASI Spec, but was in the original RaSCSI code.
|
||||||
// leaving it here for now....
|
// leaving it here for now....
|
||||||
case SASIDEV::eCmdInvalid:
|
case SASIDEV::eCmdInvalid:
|
||||||
CmdSpecify();
|
CmdSpecify();
|
||||||
@ -432,18 +453,11 @@ void SASIDEV::Execute()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsupported command
|
|
||||||
LOGTRACE("%s ID %d received unsupported command: $%02X", __PRETTY_FUNCTION__, GetSCSIID(), (BYTE)ctrl.cmd[0]);
|
LOGTRACE("%s ID %d received unsupported command: $%02X", __PRETTY_FUNCTION__, GetSCSIID(), (BYTE)ctrl.cmd[0]);
|
||||||
|
|
||||||
// Logical Unit
|
ctrl.device->SetStatusCode(STATUS_INVALIDCMD);
|
||||||
DWORD lun = GetEffectiveLun();
|
|
||||||
if (ctrl.unit[lun]) {
|
|
||||||
// Command processing on drive
|
|
||||||
ctrl.unit[lun]->SetStatusCode(STATUS_INVALIDCMD);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failure (Error)
|
Error(sense_key::ILLEGAL_REQUEST, asc::INVALID_COMMAND_OPERATION_CODE);
|
||||||
Error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@ -618,11 +632,6 @@ void SASIDEV::DataOut()
|
|||||||
Receive();
|
Receive();
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Error
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::Error(sense_key sense_key, asc asc, status status)
|
void SASIDEV::Error(sense_key sense_key, asc asc, status status)
|
||||||
{
|
{
|
||||||
// Get bus information
|
// Get bus information
|
||||||
@ -644,205 +653,13 @@ void SASIDEV::Error(sense_key sense_key, asc asc, status status)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logical Unit
|
|
||||||
DWORD lun = GetEffectiveLun();
|
|
||||||
|
|
||||||
// Set status and message
|
// Set status and message
|
||||||
ctrl.status = (lun << 5) | status;
|
ctrl.status = (GetEffectiveLun() << 5) | status;
|
||||||
|
|
||||||
// status phase
|
// status phase
|
||||||
Status();
|
Status();
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// TEST UNIT READY
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdTestUnitReady()
|
|
||||||
{
|
|
||||||
LOGTRACE("%s TEST UNIT READY Command ", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
// Command processing on drive
|
|
||||||
ctrl.device->TestUnitReady(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// REZERO UNIT
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdRezero()
|
|
||||||
{
|
|
||||||
LOGTRACE( "%s REZERO UNIT Command ", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
// Command processing on drive
|
|
||||||
((Disk *)ctrl.device)->Rezero(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// REQUEST SENSE
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdRequestSense()
|
|
||||||
{
|
|
||||||
LOGTRACE( "%s REQUEST SENSE Command ", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
// Command processing on drive
|
|
||||||
ctrl.device->RequestSense(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// FORMAT UNIT
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdFormat()
|
|
||||||
{
|
|
||||||
LOGTRACE( "%s FORMAT UNIT Command ", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
// Command processing on drive
|
|
||||||
((Disk *)ctrl.device)->FormatUnit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// REASSIGN BLOCKS
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdReassignBlocks()
|
|
||||||
{
|
|
||||||
LOGTRACE("%s REASSIGN BLOCKS Command ", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
// Command processing on drive
|
|
||||||
((Disk *)ctrl.device)->ReassignBlocks(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// RESERVE UNIT(16)
|
|
||||||
//
|
|
||||||
// The reserve/release commands are only used in multi-initiator
|
|
||||||
// environments. RaSCSI doesn't support this use case. However, some old
|
|
||||||
// versions of Solaris will issue the reserve/release commands. We will
|
|
||||||
// just respond with an OK status.
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdReserveUnit()
|
|
||||||
{
|
|
||||||
LOGTRACE( "%s Reserve(6) Command", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
// status phase
|
|
||||||
Status();
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// RELEASE UNIT(17)
|
|
||||||
//
|
|
||||||
// The reserve/release commands are only used in multi-initiator
|
|
||||||
// environments. RaSCSI doesn't support this use case. However, some old
|
|
||||||
// versions of Solaris will issue the reserve/release commands. We will
|
|
||||||
// just respond with an OK status.
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdReleaseUnit()
|
|
||||||
{
|
|
||||||
LOGTRACE( "%s Release(6) Command", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
// status phase
|
|
||||||
Status();
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// READ(6)
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdRead6()
|
|
||||||
{
|
|
||||||
// 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 = ctrl.cmd[4];
|
|
||||||
if (ctrl.blocks == 0) {
|
|
||||||
ctrl.blocks = 0x100;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGTRACE("%s READ(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (unsigned int)record, (int)ctrl.blocks);
|
|
||||||
|
|
||||||
// Command processing on drive
|
|
||||||
ctrl.length = ((Disk *)ctrl.device)->Read(ctrl.cmd, ctrl.buffer, record);
|
|
||||||
if (ctrl.length <= 0) {
|
|
||||||
// Failure (Error)
|
|
||||||
Error();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set next block
|
|
||||||
ctrl.next = record + 1;
|
|
||||||
|
|
||||||
// Read phase
|
|
||||||
DataIn();
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// WRITE(6)
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdWrite6()
|
|
||||||
{
|
|
||||||
// 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 = ctrl.cmd[4];
|
|
||||||
if (ctrl.blocks == 0) {
|
|
||||||
ctrl.blocks = 0x100;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGTRACE("%s WRITE(6) command record=%d blocks=%d", __PRETTY_FUNCTION__, (WORD)record, (WORD)ctrl.blocks);
|
|
||||||
|
|
||||||
// Command processing on drive
|
|
||||||
ctrl.length = ((Disk *)ctrl.device)->WriteCheck(record);
|
|
||||||
if (ctrl.length <= 0) {
|
|
||||||
// Failure (Error)
|
|
||||||
Error();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set next block
|
|
||||||
ctrl.next = record + 1;
|
|
||||||
|
|
||||||
// Write phase
|
|
||||||
DataOut();
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// SEEK(6)
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdSeek6()
|
|
||||||
{
|
|
||||||
LOGTRACE("%s SEEK(6) Command ", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
// Command processing on drive
|
|
||||||
((Disk *)ctrl.device)->Seek6(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// ASSIGN
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdAssign()
|
void SASIDEV::CmdAssign()
|
||||||
{
|
{
|
||||||
LOGTRACE("%s ASSIGN Command ", __PRETTY_FUNCTION__);
|
LOGTRACE("%s ASSIGN Command ", __PRETTY_FUNCTION__);
|
||||||
@ -862,11 +679,6 @@ void SASIDEV::CmdAssign()
|
|||||||
DataOut();
|
DataOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// SPECIFY
|
|
||||||
//
|
|
||||||
//---------------------------------------------------------------------------
|
|
||||||
void SASIDEV::CmdSpecify()
|
void SASIDEV::CmdSpecify()
|
||||||
{
|
{
|
||||||
LOGTRACE("%s SPECIFY Command ", __PRETTY_FUNCTION__);
|
LOGTRACE("%s SPECIFY Command ", __PRETTY_FUNCTION__);
|
||||||
@ -1276,6 +1088,6 @@ void SASIDEV::FlushUnit()
|
|||||||
|
|
||||||
int SASIDEV::GetEffectiveLun() const
|
int SASIDEV::GetEffectiveLun() const
|
||||||
{
|
{
|
||||||
return ctrl.lun != -1 ? ctrl.lun : (ctrl.cmd[1] >> 5) & 0x07;
|
return (ctrl.cmd[1] >> 5) & 0x07;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,12 +36,15 @@ private:
|
|||||||
eCmdTestUnitReady = 0x00,
|
eCmdTestUnitReady = 0x00,
|
||||||
eCmdRezero = 0x01,
|
eCmdRezero = 0x01,
|
||||||
eCmdRequestSense = 0x03,
|
eCmdRequestSense = 0x03,
|
||||||
eCmdFormat = 0x06,
|
eCmdFormat = 0x04,
|
||||||
|
eCmdReadCapacity = 0x05,
|
||||||
|
eCmdFormatLegacy = 0x06,
|
||||||
eCmdReassign = 0x07,
|
eCmdReassign = 0x07,
|
||||||
eCmdRead6 = 0x08,
|
eCmdRead6 = 0x08,
|
||||||
eCmdWrite6 = 0x0A,
|
eCmdWrite6 = 0x0A,
|
||||||
eCmdSeek6 = 0x0B,
|
eCmdSeek6 = 0x0B,
|
||||||
eCmdSetMcastAddr = 0x0D, // DaynaPort specific command
|
eCmdSetMcastAddr = 0x0D, // DaynaPort specific command
|
||||||
|
eCmdInquiry = 0x12,
|
||||||
eCmdModeSelect6 = 0x15,
|
eCmdModeSelect6 = 0x15,
|
||||||
eCmdReserve6 = 0x16,
|
eCmdReserve6 = 0x16,
|
||||||
eCmdRelease6 = 0x17,
|
eCmdRelease6 = 0x17,
|
||||||
@ -137,8 +140,7 @@ public:
|
|||||||
void MsgIn(); // Message in phase
|
void MsgIn(); // Message in phase
|
||||||
void DataOut(); // Data out phase
|
void DataOut(); // Data out phase
|
||||||
|
|
||||||
// Get LUN based on IDENTIFY message, with LUN from the CDB as fallback
|
virtual int GetEffectiveLun() const;
|
||||||
int GetEffectiveLun() const;
|
|
||||||
|
|
||||||
virtual void Error(scsi_defs::sense_key sense_key = scsi_defs::sense_key::NO_SENSE,
|
virtual void Error(scsi_defs::sense_key sense_key = scsi_defs::sense_key::NO_SENSE,
|
||||||
scsi_defs::asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
scsi_defs::asc = scsi_defs::asc::NO_ADDITIONAL_SENSE_INFORMATION,
|
||||||
@ -152,16 +154,6 @@ protected:
|
|||||||
virtual void Execute(); // Execution phase
|
virtual void Execute(); // Execution phase
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
void CmdTestUnitReady(); // TEST UNIT READY command
|
|
||||||
void CmdRezero(); // REZERO UNIT command
|
|
||||||
void CmdRequestSense(); // REQUEST SENSE command
|
|
||||||
void CmdFormat(); // FORMAT command
|
|
||||||
void CmdReassignBlocks(); // REASSIGN BLOCKS command
|
|
||||||
void CmdReserveUnit(); // RESERVE UNIT command
|
|
||||||
void CmdReleaseUnit(); // RELEASE UNIT command
|
|
||||||
void CmdRead6(); // READ(6) command
|
|
||||||
void CmdWrite6(); // WRITE(6) command
|
|
||||||
void CmdSeek6(); // SEEK(6) command
|
|
||||||
void CmdAssign(); // ASSIGN command
|
void CmdAssign(); // ASSIGN command
|
||||||
void CmdSpecify(); // SPECIFY command
|
void CmdSpecify(); // SPECIFY command
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ void SCSIDEV::Execute()
|
|||||||
|
|
||||||
int lun = GetEffectiveLun();
|
int lun = GetEffectiveLun();
|
||||||
if (!ctrl.unit[lun]) {
|
if (!ctrl.unit[lun]) {
|
||||||
if ((scsi_command)ctrl.cmd[0] != eCmdInquiry &&
|
if ((scsi_command)ctrl.cmd[0] != scsi_command::eCmdInquiry &&
|
||||||
(scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
|
(scsi_command)ctrl.cmd[0] != scsi_command::eCmdRequestSense) {
|
||||||
LOGDEBUG("Invalid LUN %d for ID %d", lun, GetSCSIID());
|
LOGDEBUG("Invalid LUN %d for ID %d", lun, GetSCSIID());
|
||||||
|
|
||||||
@ -911,3 +911,8 @@ bool SCSIDEV::XferOut(bool cont)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SCSIDEV::GetEffectiveLun() const
|
||||||
|
{
|
||||||
|
return ctrl.lun != -1 ? ctrl.lun : (ctrl.cmd[1] >> 5) & 0x07;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,9 @@ public:
|
|||||||
|
|
||||||
void Receive() override;
|
void Receive() override;
|
||||||
|
|
||||||
|
// Get LUN based on IDENTIFY message, with LUN from the CDB as fallback
|
||||||
|
int GetEffectiveLun() const;
|
||||||
|
|
||||||
bool IsSASI() const override { return false; }
|
bool IsSASI() const override { return false; }
|
||||||
bool IsSCSI() const override { return true; }
|
bool IsSCSI() const override { return true; }
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ using namespace rascsi_interface;
|
|||||||
|
|
||||||
DeviceFactory::DeviceFactory()
|
DeviceFactory::DeviceFactory()
|
||||||
{
|
{
|
||||||
sector_sizes[SAHD] = { 256, 1024 };
|
sector_sizes[SAHD] = { 256, 512, 1024 };
|
||||||
sector_sizes[SCHD] = { 512, 1024, 2048, 4096 };
|
sector_sizes[SCHD] = { 512, 1024, 2048, 4096 };
|
||||||
sector_sizes[SCRM] = { 512, 1024, 2048, 4096 };
|
sector_sizes[SCRM] = { 512, 1024, 2048, 4096 };
|
||||||
sector_sizes[SCMO] = { 512, 1024, 2048, 4096 };
|
sector_sizes[SCMO] = { 512, 1024, 2048, 4096 };
|
||||||
|
@ -71,6 +71,8 @@ public:
|
|||||||
bool Eject(bool) override;
|
bool Eject(bool) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class SASIDEV;
|
||||||
|
|
||||||
typedef ModePageDevice super;
|
typedef ModePageDevice super;
|
||||||
|
|
||||||
// Commands covered by the SCSI specification (see https://www.t10.org/drafts.htm)
|
// Commands covered by the SCSI specification (see https://www.t10.org/drafts.htm)
|
||||||
@ -94,7 +96,7 @@ private:
|
|||||||
void Verify16(SASIDEV *);
|
void Verify16(SASIDEV *);
|
||||||
void Seek(SASIDEV *);
|
void Seek(SASIDEV *);
|
||||||
void Seek10(SASIDEV *);
|
void Seek10(SASIDEV *);
|
||||||
void ReadCapacity10(SASIDEV *) override;
|
virtual void ReadCapacity10(SASIDEV *) override;
|
||||||
void ReadCapacity16(SASIDEV *) override;
|
void ReadCapacity16(SASIDEV *) override;
|
||||||
void Reserve(SASIDEV *);
|
void Reserve(SASIDEV *);
|
||||||
void Release(SASIDEV *);
|
void Release(SASIDEV *);
|
||||||
|
@ -128,8 +128,6 @@ void PrimaryDevice::RequestSense(SASIDEV *controller)
|
|||||||
memcpy(ctrl->buffer, buf.data(), allocation_length);
|
memcpy(ctrl->buffer, buf.data(), allocation_length);
|
||||||
ctrl->length = allocation_length;
|
ctrl->length = allocation_length;
|
||||||
|
|
||||||
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl->status, ctrl->buffer[2], ctrl->buffer[12]);
|
|
||||||
|
|
||||||
controller->DataIn();
|
controller->DataIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,6 +203,8 @@ vector<BYTE> PrimaryDevice::RequestSense(int)
|
|||||||
buf[12] = GetStatusCode() >> 8;
|
buf[12] = GetStatusCode() >> 8;
|
||||||
buf[13] = GetStatusCode();
|
buf[13] = GetStatusCode();
|
||||||
|
|
||||||
|
LOGTRACE("%s Status $%02X, Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl->status, ctrl->buffer[2], ctrl->buffer[12]);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ public:
|
|||||||
|
|
||||||
void TestUnitReady(SASIDEV *);
|
void TestUnitReady(SASIDEV *);
|
||||||
void RequestSense(SASIDEV *);
|
void RequestSense(SASIDEV *);
|
||||||
|
virtual void Inquiry(SASIDEV *);
|
||||||
|
|
||||||
void SetCtrl(SASIDEV::ctrl_t *ctrl) { this->ctrl = ctrl; }
|
void SetCtrl(SASIDEV::ctrl_t *ctrl) { this->ctrl = ctrl; }
|
||||||
|
|
||||||
@ -49,6 +50,5 @@ private:
|
|||||||
|
|
||||||
Dispatcher<PrimaryDevice, SASIDEV> dispatcher;
|
Dispatcher<PrimaryDevice, SASIDEV> dispatcher;
|
||||||
|
|
||||||
void Inquiry(SASIDEV *);
|
|
||||||
void ReportLuns(SASIDEV *);
|
void ReportLuns(SASIDEV *);
|
||||||
};
|
};
|
||||||
|
@ -53,6 +53,11 @@ void SASIHD::Open(const Filepath& path)
|
|||||||
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 256, true);
|
SetSectorSizeInBytes(GetConfiguredSectorSize() ? GetConfiguredSectorSize() : 256, true);
|
||||||
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
|
SetBlockCount((DWORD)(size >> GetSectorSizeShiftCount()));
|
||||||
|
|
||||||
|
// SASI only supports READ/WRITE(6), limiting the block count to 2^21
|
||||||
|
if (GetBlockCount() > 2097152) {
|
||||||
|
throw io_exception("SASI drives are limited to 2097152 blocks");
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(REMOVE_FIXED_SASIHD_SIZE)
|
#if defined(REMOVE_FIXED_SASIHD_SIZE)
|
||||||
// Effective size must be a multiple of the sector size
|
// Effective size must be a multiple of the sector size
|
||||||
size = (size / GetSectorSizeInBytes()) * GetSectorSizeInBytes();
|
size = (size / GetSectorSizeInBytes()) * GetSectorSizeInBytes();
|
||||||
@ -83,8 +88,9 @@ void SASIHD::Open(const Filepath& path)
|
|||||||
|
|
||||||
vector<BYTE> SASIHD::Inquiry() const
|
vector<BYTE> SASIHD::Inquiry() const
|
||||||
{
|
{
|
||||||
assert(false);
|
// Byte 0 = 0: Direct access device
|
||||||
return vector<BYTE>(0);
|
|
||||||
|
return vector<BYTE>(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<BYTE> SASIHD::RequestSense(int allocation_length)
|
vector<BYTE> SASIHD::RequestSense(int allocation_length)
|
||||||
@ -96,5 +102,29 @@ vector<BYTE> SASIHD::RequestSense(int allocation_length)
|
|||||||
buf[0] = (BYTE)(GetStatusCode() >> 16);
|
buf[0] = (BYTE)(GetStatusCode() >> 16);
|
||||||
buf[1] = (BYTE)(GetLun() << 5);
|
buf[1] = (BYTE)(GetLun() << 5);
|
||||||
|
|
||||||
|
LOGTRACE("%s Status $%02X",__PRETTY_FUNCTION__, buf[0]);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SASIHD::ReadCapacity10(SASIDEV *controller)
|
||||||
|
{
|
||||||
|
BYTE *buf = ctrl->buffer;
|
||||||
|
|
||||||
|
// Create end of logical block address (disk.blocks-1)
|
||||||
|
uint32_t blocks = disk.blocks - 1;
|
||||||
|
buf[0] = (BYTE)(blocks >> 24);
|
||||||
|
buf[1] = (BYTE)(blocks >> 16);
|
||||||
|
buf[2] = (BYTE)(blocks >> 8);
|
||||||
|
buf[3] = (BYTE)blocks;
|
||||||
|
|
||||||
|
// Create block length (1 << disk.size)
|
||||||
|
uint32_t length = 1 << disk.size;
|
||||||
|
buf[4] = (BYTE)(length >> 8);
|
||||||
|
buf[5] = (BYTE)length;
|
||||||
|
|
||||||
|
// the size
|
||||||
|
ctrl->length = 6;
|
||||||
|
|
||||||
|
controller->DataIn();
|
||||||
|
}
|
||||||
|
@ -35,4 +35,5 @@ public:
|
|||||||
|
|
||||||
vector<BYTE> RequestSense(int) override;
|
vector<BYTE> RequestSense(int) override;
|
||||||
vector<BYTE> Inquiry() const override;
|
vector<BYTE> Inquiry() const override;
|
||||||
|
virtual void ReadCapacity10(SASIDEV *) override;
|
||||||
};
|
};
|
||||||
|
@ -817,7 +817,7 @@ BOOL GPIOBUS::GetDP()
|
|||||||
// Receive command handshake
|
// Receive command handshake
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
int GPIOBUS::CommandHandShake(BYTE *buf)
|
int GPIOBUS::CommandHandShake(BYTE *buf, bool is_sasi)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
@ -869,7 +869,7 @@ int GPIOBUS::CommandHandShake(BYTE *buf)
|
|||||||
// semantics. I fact, these semantics have become a standard in the Atari world.
|
// semantics. I fact, these semantics have become a standard in the Atari world.
|
||||||
|
|
||||||
// RaSCSI becomes ICD compatible by ignoring the prepended $1F byte before processing the CDB.
|
// RaSCSI becomes ICD compatible by ignoring the prepended $1F byte before processing the CDB.
|
||||||
if (*buf == 0x1F) {
|
if (!is_sasi && *buf == 0x1F) {
|
||||||
SetSignal(PIN_REQ, ON);
|
SetSignal(PIN_REQ, ON);
|
||||||
|
|
||||||
ret = WaitSignal(PIN_ACK, TRUE);
|
ret = WaitSignal(PIN_ACK, TRUE);
|
||||||
@ -1592,7 +1592,7 @@ int GPIOBUS::GetCommandByteCount(BYTE opcode) {
|
|||||||
else if (opcode == 0xA0) {
|
else if (opcode == 0xA0) {
|
||||||
return 12;
|
return 12;
|
||||||
}
|
}
|
||||||
else if (opcode >= 0x20 && opcode <= 0x7D) {
|
else if (opcode == 0x05 || (opcode >= 0x20 && opcode <= 0x7D)) {
|
||||||
return 10;
|
return 10;
|
||||||
} else {
|
} else {
|
||||||
return 6;
|
return 6;
|
||||||
|
@ -565,7 +565,7 @@ public:
|
|||||||
// Set DAT signal
|
// Set DAT signal
|
||||||
BOOL GetDP() override;
|
BOOL GetDP() override;
|
||||||
// Get Data parity signal
|
// Get Data parity signal
|
||||||
int CommandHandShake(BYTE *buf) override;
|
int CommandHandShake(BYTE *buf, bool) override;
|
||||||
// Command receive handshake
|
// Command receive handshake
|
||||||
int ReceiveHandShake(BYTE *buf, int count) override;
|
int ReceiveHandShake(BYTE *buf, int count) override;
|
||||||
// Data receive handshake
|
// Data receive handshake
|
||||||
|
@ -98,7 +98,7 @@ public:
|
|||||||
virtual BOOL GetDP() = 0; // Get parity signal
|
virtual BOOL GetDP() = 0; // Get parity signal
|
||||||
|
|
||||||
virtual DWORD Aquire() = 0;
|
virtual DWORD Aquire() = 0;
|
||||||
virtual int CommandHandShake(BYTE *buf) = 0;
|
virtual int CommandHandShake(BYTE *buf, bool) = 0;
|
||||||
virtual int ReceiveHandShake(BYTE *buf, int count) = 0;
|
virtual int ReceiveHandShake(BYTE *buf, int count) = 0;
|
||||||
virtual int SendHandShake(BYTE *buf, int count, int delay_after_bytes) = 0;
|
virtual int SendHandShake(BYTE *buf, int count, int delay_after_bytes) = 0;
|
||||||
|
|
||||||
@ -131,7 +131,8 @@ namespace scsi_defs {
|
|||||||
SPC_2 = 4,
|
SPC_2 = 4,
|
||||||
SPC_3 = 5,
|
SPC_3 = 5,
|
||||||
SPC_4 = 6,
|
SPC_4 = 6,
|
||||||
SPC_5 = 7
|
SPC_5 = 7,
|
||||||
|
SPC_6 = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
enum device_type : int {
|
enum device_type : int {
|
||||||
|
Loading…
Reference in New Issue
Block a user