mirror of
https://github.com/akuker/RASCSI.git
synced 2024-12-22 15:30:09 +00:00
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:
parent
0f5baa8839
commit
fef21a6cf5
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
|
||||
~lunexception() { }
|
||||
|
||||
DWORD getlun() {
|
||||
DWORD getlun() const {
|
||||
return lun;
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user