Support for providing sense data for REQUEST SENSE (#120)

* Error() supports passing Sense Key and ASC, REQUEST SENSE returns these data

* Synchronized error handlign with sasidev_ctrl

* Added warning for missing sense key

* Logging and comment update

* Updated invalid LUN handling

* Updated REQUEST SENSE

* Revert "Updated REQUEST SENSE"

This reverts commit 61a1ecbca7.

* Report MEDIUM NOT PRESENT if capacity cannot be determined

* Updated handling of non-existing LUNs. This change results issue #124.

* Log a warning if drive capacity cannot be determined

* Added enums for sense keys and ASCs

* Updated Error() signature to use enums

* Fixed compiler warnings

* Merge with develop branch
This commit is contained in:
uweseimet 2021-07-16 02:49:54 +02:00 committed by GitHub
parent 0f5baa8839
commit fef21a6cf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 127 additions and 30 deletions

View File

@ -466,11 +466,12 @@ void FASTCALL SASIDEV::Command()
// Execution Phase
try {
Execute();
Execute();
}
catch (lunexception& e) {
LOGINFO("%s unsupported LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
Error();
LOGINFO("%s Invalid LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
}
#else
// Request the command
@ -513,6 +514,12 @@ void FASTCALL SASIDEV::Execute()
ctrl.execstart = SysTimer::GetTimerLow();
#endif // RASCSI
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if ((SASIDEV::scsi_command)ctrl.cmd[0] != eCmdRequestSense) {
ctrl.sense_key = 0;
ctrl.asc = 0;
}
// Process by command
switch ((SASIDEV::scsi_command)ctrl.cmd[0]) {
// TEST UNIT READY
@ -830,7 +837,7 @@ void FASTCALL SASIDEV::DataOut()
// Error
//
//---------------------------------------------------------------------------
void FASTCALL SASIDEV::Error()
void FASTCALL SASIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc)
{
// Get bus information
((GPIOBUS*)ctrl.bus)->Aquire();
@ -851,9 +858,11 @@ void FASTCALL SASIDEV::Error()
return;
}
#if defined(DISK_LOG)
LOGWARN("Error occured (going to status phase)");
#endif // DISK_LOG
LOGTRACE("%s Sense Key and ASC for subsequent REQUEST SENSE: $%02X, $%02X", __PRETTY_FUNCTION__, sense_key, asc);
// Set Sense Key and ASC for a subsequent REQUEST SENSE
ctrl.sense_key = sense_key;
ctrl.asc = asc;
// Logical Unit
DWORD lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -861,6 +870,10 @@ void FASTCALL SASIDEV::Error()
// Set status and message(CHECK CONDITION)
ctrl.status = (lun << 5) | 0x02;
#if defined(DISK_LOG)
LOGWARN("Error occured (going to status phase)");
#endif // DISK_LOG
// status phase
Status();
}
@ -920,13 +933,36 @@ void FASTCALL SASIDEV::CmdRequestSense()
{
LOGTRACE( "%s REQUEST SENSE Command ", __PRETTY_FUNCTION__);
DWORD lun = GetLun();
DWORD lun;
try {
lun = GetLun();
}
catch(const lunexception& e) {
LOGINFO("%s Non-existing LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
// Note: According to the SCSI specs the LUN handling for REQUEST SENSE is special.
// Non-existing LUNs do *not* result in CHECK CONDITION.
// Only the Sense Key and ASC are set in order to signal the non-existing LUN.
// LUN 0 can be assumed to be present (required to call RequestSense() below)
lun = 0;
ctrl.sense_key = ERROR_CODES::sense_key::ILLEGAL_REQUEST;
ctrl.asc = ERROR_CODES::asc::INVALID_LUN;
}
ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer);
ASSERT(ctrl.length > 0);
LOGTRACE("%s Sense Key $%02X, ASC $%02X",__PRETTY_FUNCTION__, ctrl.sense_key, ctrl.asc);
LOGTRACE("%s Sense key $%02X, ASC $%02X",__PRETTY_FUNCTION__, (WORD)ctrl.buffer[2], (WORD)ctrl.buffer[12]);
// REQUEST SENSE returns the sense data set by the previous (failed) command
ctrl.buffer[2] = ctrl.sense_key;
ctrl.buffer[12] = ctrl.asc;
// The sense data are only valid once
ctrl.sense_key = 0;
ctrl.asc = 0;
// Read phase
DataIn();
@ -1240,8 +1276,7 @@ void FASTCALL SASIDEV::CmdInvalid()
{
LOGWARN("%s Command not supported", __PRETTY_FUNCTION__);
// Failure (Error)
Error();
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
}
//===========================================================================
@ -1519,7 +1554,14 @@ void FASTCALL SASIDEV::ReceiveNext()
// Command phase
case BUS::command:
// Execution Phase
Execute();
try {
Execute();
}
catch (const lunexception& e) {
LOGINFO("%s unsupported LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
// LOGICAL UNIT NOT SUPPORTED
Error(SENSE_KEY_ILLEGAL_REQUEST, ASC_INVALID_LUN);
}
break;
#endif // RASCSI

View File

@ -135,12 +135,16 @@ public:
BYTE *buffer; // Transfer data buffer
int bufsize; // Transfer data buffer size
DWORD blocks; // Number of transfer block
DWORD next; // Next record
DWORD next; // Next record
DWORD offset; // Transfer offset
DWORD length; // Transfer remaining length
// Logical unit
Disk *unit[UnitMax]; // Logical Unit
Disk *unit[UnitMax];
// Sense Key and Additional Sense Code (ASC) of the previous command
int sense_key;
int asc;
} ctrl_t;
public:
@ -194,7 +198,8 @@ protected:
void FASTCALL MsgIn(); // Message in phase
void FASTCALL DataIn(); // Data in phase
void FASTCALL DataOut(); // Data out phase
virtual void FASTCALL Error(); // Common error handling
virtual void FASTCALL 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
// commands
void FASTCALL CmdTestUnitReady(); // TEST UNIT READY command

View File

@ -307,6 +307,12 @@ void FASTCALL SCSIDEV::Execute()
LOGDEBUG("++++ CMD ++++ %s Received %s ($%02X)", __PRETTY_FUNCTION__, command->name, (unsigned int)ctrl.cmd[0]);
// Discard pending sense data from the previous command if the current command is not REQUEST SENSE
if ((unsigned int)ctrl.cmd[0] != 0x03) {
ctrl.sense_key = 0;
ctrl.asc = 0;
}
// Process by command
(this->*command->execute)();
}
@ -361,7 +367,7 @@ void FASTCALL SCSIDEV::MsgOut()
// Common Error Handling
//
//---------------------------------------------------------------------------
void FASTCALL SCSIDEV::Error()
void FASTCALL SCSIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc)
{
// Get bus information
((GPIOBUS*)ctrl.bus)->Aquire();
@ -382,12 +388,18 @@ void FASTCALL SCSIDEV::Error()
return;
}
LOGTRACE( "%s Error (to status phase)", __PRETTY_FUNCTION__);
LOGTRACE("%s Sense Key and ASC for subsequent REQUEST SENSE: $%02X, $%02X", __PRETTY_FUNCTION__, sense_key, asc);
// Set Sense Key and ASC for a subsequent REQUEST SENSE
ctrl.sense_key = sense_key;
ctrl.asc = asc;
// Set status and message(CHECK CONDITION)
ctrl.status = 0x02;
ctrl.message = 0x00;
LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__);
// status phase
Status();
}
@ -411,10 +423,10 @@ void FASTCALL SCSIDEV::CmdInquiry()
// TODO The code below is most likely wrong. It results in the same INQUIRY data being
// used for all LUNs, even though each LUN has its individual set of INQUIRY data.
Disk *disk = NULL;
int lun;
for (lun = 0; lun < UnitMax; lun++) {
if (ctrl.unit[lun]) {
disk = ctrl.unit[lun];
int valid_lun;
for (valid_lun = 0; valid_lun < UnitMax; valid_lun++) {
if (ctrl.unit[valid_lun]) {
disk = ctrl.unit[valid_lun];
break;
}
}
@ -425,7 +437,7 @@ void FASTCALL SCSIDEV::CmdInquiry()
DWORD minor = (DWORD)(RASCSI & 0xff);
LOGTRACE("%s Buffer size is %d",__PRETTY_FUNCTION__, ctrl.bufsize);
ctrl.length =
ctrl.unit[lun]->Inquiry(ctrl.cmd, ctrl.buffer, major, minor);
ctrl.unit[valid_lun]->Inquiry(ctrl.cmd, ctrl.buffer, major, minor);
} else {
ctrl.length = 0;
}
@ -441,6 +453,12 @@ void FASTCALL SCSIDEV::CmdInquiry()
ctrl.buffer[7] |= (1 << 4);
}
// Report if the device does not support the requested LUN
DWORD lun = (ctrl.cmd[1] >> 5) & 0x07;
if (!ctrl.unit[lun]) {
ctrl.buffer[0] |= 0x7f;
}
// Data-in Phase
DataIn();
}
@ -650,7 +668,7 @@ void FASTCALL SCSIDEV::CmdReadCapacity()
int length = ctrl.unit[lun]->ReadCapacity(ctrl.cmd, ctrl.buffer);
ASSERT(length >= 0);
if (length <= 0) {
Error();
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
return;
}
@ -1510,11 +1528,12 @@ void FASTCALL SCSIDEV::Receive()
// Execution Phase
try {
Execute();
Execute();
}
catch (lunexception& e) {
LOGINFO("%s unsupported LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
Error();
catch (const lunexception& e) {
LOGINFO("%s Invalid LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
}
break;

View File

@ -74,7 +74,8 @@ private:
void FASTCALL Selection(); // Selection phase
void FASTCALL Execute(); // Execution phase
void FASTCALL MsgOut(); // Message out phase
void FASTCALL Error(); // Common erorr handling
void FASTCALL Error(ERROR_CODES::sense_key sense_key = ERROR_CODES::sense_key::NO_SENSE,
ERROR_CODES::asc asc = ERROR_CODES::asc::NO_ADDITIONAL_SENSE_INFORMATION); // Common erorr handling
// commands
void FASTCALL CmdInquiry(); // INQUIRY command

View File

@ -1216,7 +1216,10 @@ int FASTCALL Disk::RequestSense(const DWORD *cdb, BYTE *buf)
memset(buf, 0, size);
// Set 18 bytes including extended sense data
// Current error
buf[0] = 0x70;
buf[2] = (BYTE)(disk.code >> 16);
buf[7] = 10;
buf[12] = (BYTE)(disk.code >> 8);
@ -2152,8 +2155,13 @@ int FASTCALL Disk::ReadCapacity(const DWORD* /*cdb*/, BYTE *buf)
return 0;
}
if (disk.blocks <= 0) {
LOGWARN("%s Capacity not available, medium may not be present", __PRETTY_FUNCTION__);
return -1;
}
// Create end of logical block address (disk.blocks-1)
ASSERT(disk.blocks > 0);
blocks = disk.blocks - 1;
buf[0] = (BYTE)(blocks >> 24);
buf[1] = (BYTE)(blocks >> 16);

View File

@ -23,7 +23,7 @@ public:
~lunexception() { }
DWORD getlun() {
DWORD getlun() const {
return lun;
}
};

View File

@ -12,6 +12,28 @@
#if !defined(scsi_h)
#define scsi_h
//===========================================================================
//
// Sense Keys and Additional Sense Codes
// (See https://www.t10.org/lists/1spc-lst.htm)
//
//===========================================================================
class ERROR_CODES
{
public:
enum sense_key : int {
NO_SENSE = 0x00,
ILLEGAL_REQUEST = 0x05
};
enum asc : int {
NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
INVALID_COMMAND_OPERATION_CODE = 0x20,
INVALID_LUN = 0x25,
MEDIUM_NOT_PRESENT = 0x3a
};
};
//===========================================================================
//
// SASI/SCSI Bus