diff --git a/src/raspberrypi/controllers/sasidev_ctrl.cpp b/src/raspberrypi/controllers/sasidev_ctrl.cpp index e3d9551c..cfcc6a12 100644 --- a/src/raspberrypi/controllers/sasidev_ctrl.cpp +++ b/src/raspberrypi/controllers/sasidev_ctrl.cpp @@ -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 diff --git a/src/raspberrypi/controllers/sasidev_ctrl.h b/src/raspberrypi/controllers/sasidev_ctrl.h index 5a203fb2..f3d294c3 100644 --- a/src/raspberrypi/controllers/sasidev_ctrl.h +++ b/src/raspberrypi/controllers/sasidev_ctrl.h @@ -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 diff --git a/src/raspberrypi/controllers/scsidev_ctrl.cpp b/src/raspberrypi/controllers/scsidev_ctrl.cpp index d31dcbd0..3a7e7a2c 100644 --- a/src/raspberrypi/controllers/scsidev_ctrl.cpp +++ b/src/raspberrypi/controllers/scsidev_ctrl.cpp @@ -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; diff --git a/src/raspberrypi/controllers/scsidev_ctrl.h b/src/raspberrypi/controllers/scsidev_ctrl.h index cddf7c99..cf7fd0ba 100644 --- a/src/raspberrypi/controllers/scsidev_ctrl.h +++ b/src/raspberrypi/controllers/scsidev_ctrl.h @@ -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 diff --git a/src/raspberrypi/devices/disk.cpp b/src/raspberrypi/devices/disk.cpp index 33aecee7..d9d34102 100644 --- a/src/raspberrypi/devices/disk.cpp +++ b/src/raspberrypi/devices/disk.cpp @@ -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); diff --git a/src/raspberrypi/exceptions.h b/src/raspberrypi/exceptions.h index d6d4e874..7d2c6d28 100644 --- a/src/raspberrypi/exceptions.h +++ b/src/raspberrypi/exceptions.h @@ -23,7 +23,7 @@ public: ~lunexception() { } - DWORD getlun() { + DWORD getlun() const { return lun; } }; diff --git a/src/raspberrypi/scsi.h b/src/raspberrypi/scsi.h index 8a71c0ec..c0dfde14 100644 --- a/src/raspberrypi/scsi.h +++ b/src/raspberrypi/scsi.h @@ -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