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 // Execution Phase
try { try {
Execute(); Execute();
} }
catch (lunexception& e) { catch (lunexception& e) {
LOGINFO("%s unsupported LUN %d", __PRETTY_FUNCTION__, (int)e.getlun()); LOGINFO("%s Invalid LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
Error();
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
} }
#else #else
// Request the command // Request the command
@ -513,6 +514,12 @@ void FASTCALL SASIDEV::Execute()
ctrl.execstart = SysTimer::GetTimerLow(); ctrl.execstart = SysTimer::GetTimerLow();
#endif // RASCSI #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 // Process by command
switch ((SASIDEV::scsi_command)ctrl.cmd[0]) { switch ((SASIDEV::scsi_command)ctrl.cmd[0]) {
// TEST UNIT READY // TEST UNIT READY
@ -830,7 +837,7 @@ void FASTCALL SASIDEV::DataOut()
// Error // Error
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void FASTCALL SASIDEV::Error() void FASTCALL SASIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc)
{ {
// Get bus information // Get bus information
((GPIOBUS*)ctrl.bus)->Aquire(); ((GPIOBUS*)ctrl.bus)->Aquire();
@ -851,9 +858,11 @@ void FASTCALL SASIDEV::Error()
return; return;
} }
#if defined(DISK_LOG) LOGTRACE("%s Sense Key and ASC for subsequent REQUEST SENSE: $%02X, $%02X", __PRETTY_FUNCTION__, sense_key, asc);
LOGWARN("Error occured (going to status phase)");
#endif // DISK_LOG // Set Sense Key and ASC for a subsequent REQUEST SENSE
ctrl.sense_key = sense_key;
ctrl.asc = asc;
// Logical Unit // Logical Unit
DWORD lun = (ctrl.cmd[1] >> 5) & 0x07; DWORD lun = (ctrl.cmd[1] >> 5) & 0x07;
@ -861,6 +870,10 @@ void FASTCALL SASIDEV::Error()
// Set status and message(CHECK CONDITION) // Set status and message(CHECK CONDITION)
ctrl.status = (lun << 5) | 0x02; ctrl.status = (lun << 5) | 0x02;
#if defined(DISK_LOG)
LOGWARN("Error occured (going to status phase)");
#endif // DISK_LOG
// status phase // status phase
Status(); Status();
} }
@ -920,13 +933,36 @@ void FASTCALL SASIDEV::CmdRequestSense()
{ {
LOGTRACE( "%s REQUEST SENSE Command ", __PRETTY_FUNCTION__); 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); ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer);
ASSERT(ctrl.length > 0); 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 // Read phase
DataIn(); DataIn();
@ -1240,8 +1276,7 @@ void FASTCALL SASIDEV::CmdInvalid()
{ {
LOGWARN("%s Command not supported", __PRETTY_FUNCTION__); LOGWARN("%s Command not supported", __PRETTY_FUNCTION__);
// Failure (Error) Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_COMMAND_OPERATION_CODE);
Error();
} }
//=========================================================================== //===========================================================================
@ -1519,7 +1554,14 @@ void FASTCALL SASIDEV::ReceiveNext()
// Command phase // Command phase
case BUS::command: case BUS::command:
// Execution Phase // 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; break;
#endif // RASCSI #endif // RASCSI

View File

@ -135,12 +135,16 @@ public:
BYTE *buffer; // Transfer data buffer BYTE *buffer; // Transfer data buffer
int bufsize; // Transfer data buffer size int bufsize; // Transfer data buffer size
DWORD blocks; // Number of transfer block DWORD blocks; // Number of transfer block
DWORD next; // Next record DWORD next; // Next record
DWORD offset; // Transfer offset DWORD offset; // Transfer offset
DWORD length; // Transfer remaining length DWORD length; // Transfer remaining length
// Logical unit // 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; } ctrl_t;
public: public:
@ -194,7 +198,8 @@ protected:
void FASTCALL MsgIn(); // Message in phase void FASTCALL MsgIn(); // Message in phase
void FASTCALL DataIn(); // Data in phase void FASTCALL DataIn(); // Data in phase
void FASTCALL DataOut(); // Data out 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 // commands
void FASTCALL CmdTestUnitReady(); // TEST UNIT READY command 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]); 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 // Process by command
(this->*command->execute)(); (this->*command->execute)();
} }
@ -361,7 +367,7 @@ void FASTCALL SCSIDEV::MsgOut()
// Common Error Handling // Common Error Handling
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void FASTCALL SCSIDEV::Error() void FASTCALL SCSIDEV::Error(ERROR_CODES::sense_key sense_key, ERROR_CODES::asc asc)
{ {
// Get bus information // Get bus information
((GPIOBUS*)ctrl.bus)->Aquire(); ((GPIOBUS*)ctrl.bus)->Aquire();
@ -382,12 +388,18 @@ void FASTCALL SCSIDEV::Error()
return; 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) // Set status and message(CHECK CONDITION)
ctrl.status = 0x02; ctrl.status = 0x02;
ctrl.message = 0x00; ctrl.message = 0x00;
LOGTRACE("%s Error (to status phase)", __PRETTY_FUNCTION__);
// status phase // status phase
Status(); 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 // 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. // used for all LUNs, even though each LUN has its individual set of INQUIRY data.
Disk *disk = NULL; Disk *disk = NULL;
int lun; int valid_lun;
for (lun = 0; lun < UnitMax; lun++) { for (valid_lun = 0; valid_lun < UnitMax; valid_lun++) {
if (ctrl.unit[lun]) { if (ctrl.unit[valid_lun]) {
disk = ctrl.unit[lun]; disk = ctrl.unit[valid_lun];
break; break;
} }
} }
@ -425,7 +437,7 @@ void FASTCALL SCSIDEV::CmdInquiry()
DWORD minor = (DWORD)(RASCSI & 0xff); DWORD minor = (DWORD)(RASCSI & 0xff);
LOGTRACE("%s Buffer size is %d",__PRETTY_FUNCTION__, ctrl.bufsize); LOGTRACE("%s Buffer size is %d",__PRETTY_FUNCTION__, ctrl.bufsize);
ctrl.length = ctrl.length =
ctrl.unit[lun]->Inquiry(ctrl.cmd, ctrl.buffer, major, minor); ctrl.unit[valid_lun]->Inquiry(ctrl.cmd, ctrl.buffer, major, minor);
} else { } else {
ctrl.length = 0; ctrl.length = 0;
} }
@ -441,6 +453,12 @@ void FASTCALL SCSIDEV::CmdInquiry()
ctrl.buffer[7] |= (1 << 4); 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 // Data-in Phase
DataIn(); DataIn();
} }
@ -650,7 +668,7 @@ void FASTCALL SCSIDEV::CmdReadCapacity()
int length = ctrl.unit[lun]->ReadCapacity(ctrl.cmd, ctrl.buffer); int length = ctrl.unit[lun]->ReadCapacity(ctrl.cmd, ctrl.buffer);
ASSERT(length >= 0); ASSERT(length >= 0);
if (length <= 0) { if (length <= 0) {
Error(); Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::MEDIUM_NOT_PRESENT);
return; return;
} }
@ -1510,11 +1528,12 @@ void FASTCALL SCSIDEV::Receive()
// Execution Phase // Execution Phase
try { try {
Execute(); Execute();
} }
catch (lunexception& e) { catch (const lunexception& e) {
LOGINFO("%s unsupported LUN %d", __PRETTY_FUNCTION__, (int)e.getlun()); LOGINFO("%s Invalid LUN %d", __PRETTY_FUNCTION__, (int)e.getlun());
Error();
Error(ERROR_CODES::sense_key::ILLEGAL_REQUEST, ERROR_CODES::asc::INVALID_LUN);
} }
break; break;

View File

@ -74,7 +74,8 @@ private:
void FASTCALL Selection(); // Selection phase void FASTCALL Selection(); // Selection phase
void FASTCALL Execute(); // Execution phase void FASTCALL Execute(); // Execution phase
void FASTCALL MsgOut(); // Message out 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 // commands
void FASTCALL CmdInquiry(); // INQUIRY command void FASTCALL CmdInquiry(); // INQUIRY command

View File

@ -1216,7 +1216,10 @@ int FASTCALL Disk::RequestSense(const DWORD *cdb, BYTE *buf)
memset(buf, 0, size); memset(buf, 0, size);
// Set 18 bytes including extended sense data // Set 18 bytes including extended sense data
// Current error
buf[0] = 0x70; buf[0] = 0x70;
buf[2] = (BYTE)(disk.code >> 16); buf[2] = (BYTE)(disk.code >> 16);
buf[7] = 10; buf[7] = 10;
buf[12] = (BYTE)(disk.code >> 8); buf[12] = (BYTE)(disk.code >> 8);
@ -2152,8 +2155,13 @@ int FASTCALL Disk::ReadCapacity(const DWORD* /*cdb*/, BYTE *buf)
return 0; 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) // Create end of logical block address (disk.blocks-1)
ASSERT(disk.blocks > 0);
blocks = disk.blocks - 1; blocks = disk.blocks - 1;
buf[0] = (BYTE)(blocks >> 24); buf[0] = (BYTE)(blocks >> 24);
buf[1] = (BYTE)(blocks >> 16); buf[1] = (BYTE)(blocks >> 16);

View File

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

View File

@ -12,6 +12,28 @@
#if !defined(scsi_h) #if !defined(scsi_h)
#define 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 // SASI/SCSI Bus