diff --git a/Common/DtaDev.cpp b/Common/DtaDev.cpp index 0346acf4..de2ea879 100644 --- a/Common/DtaDev.cpp +++ b/Common/DtaDev.cpp @@ -1,5 +1,6 @@ /* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. +This software is Copyright 2023 Nutanix, Inc. This file is part of sedutil. @@ -300,3 +301,46 @@ void DtaDev::puke() if (disk_info.Unknown) cout << "**** " << (uint16_t)disk_info.Unknown << " **** Unknown function codes IGNORED " << std::endl; } + +uint8_t DtaDev::stack_reset(uint32_t ext_com_id) { + uint8_t reset_buffer[MIN_BUFFER_LENGTH + IO_BUFFER_ALIGNMENT]; + uint8_t response_buf[MIN_BUFFER_LENGTH + IO_BUFFER_ALIGNMENT]; + uint8_t lastRC; + LOG(D1) << "Entering DtaDev::stack_reset()"; + + memset(reset_buffer, 0, MIN_BUFFER_LENGTH); + reset_buffer[0] = (ext_com_id >> 24) & 0xFF; + reset_buffer[1] = (ext_com_id >> 16) & 0xFF; + reset_buffer[2] = (ext_com_id >> 8) & 0xFF; + reset_buffer[3] = (ext_com_id) & 0xFF; + reset_buffer[7] = 0x02; + if ((lastRC = sendCmd(IF_SEND, 0x02, comID(), reset_buffer, MIN_BUFFER_LENGTH)) != 0) { + LOG(E) << "Reset send with ComID " << HEXON(4) << comID() << " failed!" << HEXOFF << std::endl; + return lastRC; + } + for (uint8_t trials=1; trials<=2;trials++) { + memset(response_buf, 0, MIN_BUFFER_LENGTH); + if ((lastRC = sendCmd(IF_RECV, 0x02, comID(), response_buf, MIN_BUFFER_LENGTH)) != 0) { + LOG(D) << "Receive Reset Status Request to device failed " << (uint16_t)lastRC; + return -1; + } + SSCCommResp *resp = (SSCCommResp *)(response_buf); + resp->decode(); + if (resp->type == SSCCommResp::STACK_RESET_PEND_RESP) { + LOG(D) << " DtaDev::stack_reset() Reset is pending. Retry #" << trials; + osmsSleep(25); + } else if (resp->type == SSCCommResp::STACK_RESET_RESP) { + if (resp->structure.reset.status != SSCCommResp::Response::Reset::SUCCESS) { + LOG(E) << "Stack reset failed"; + return SWAP32(resp->structure.reset.status); + } + LOG(D) << "DtaDev::stack_reset() Stack Reset is successful"; + return 0; + } else { + LOG(E) << "DtaDev::stack_reset() Unrecognized response received"; + return -2; + } + } + LOG(E) << "DtaDev::stack_reset() Reset poll timed out"; + return -3; +} diff --git a/Common/DtaDev.h b/Common/DtaDev.h index 473f7bd0..8f2d9994 100644 --- a/Common/DtaDev.h +++ b/Common/DtaDev.h @@ -1,5 +1,6 @@ /* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. +This software is Copyright 2023 Nutanix, Inc. This file is part of sedutil. @@ -283,6 +284,12 @@ class DtaDev { virtual uint8_t exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol = 0x01) = 0; /** return the communications ID to be used for sessions to this device */ virtual uint16_t comID() = 0; + + /* Reset the stack, without powering cycle the drive. All ongoing or + * in middle sessions are closed. Non committed transactions are lost. + */ + virtual uint8_t stack_reset(uint32_t ext_com_id); + bool no_hash_passwords; /** disables hashing of passwords */ sedutiloutput output_format; /** standard, readable, JSON */ protected: diff --git a/Common/DtaDevEnterprise.cpp b/Common/DtaDevEnterprise.cpp index 76e6e39d..cecbb01d 100644 --- a/Common/DtaDevEnterprise.cpp +++ b/Common/DtaDevEnterprise.cpp @@ -1,6 +1,7 @@ /* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. This software is Copyright 2017 Spectra Logic Corporation +This software is Copyright 2023 Nutanix, Inc. This file is part of sedutil. @@ -1492,9 +1493,21 @@ uint8_t DtaDevEnterprise::properties() props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::ENDLIST); props->complete(); - if ((lastRC = session->sendCommand(props, propertiesResponse)) != 0) { - delete props; - return lastRC; + for (uint8_t trial=1; trial<=2; trial++) { + if ((lastRC = session->sendCommand(props, propertiesResponse)) != 0) { + LOG(E) << "Property Exchange Command Failed rc = " << (int)lastRC; + if (trial == 1) { + LOG(D) << "Try to apply stack reset"; + if (this->stack_reset(this->comID() << 16) == 0x0000) { + LOG(D) << "Stack Reset Successful"; + continue; + } + LOG(E) << "Stack Reset Failed"; + delete props; + return lastRC; + } + } + break; } disk_info.Properties = 1; delete props; diff --git a/Common/DtaDevOpal.cpp b/Common/DtaDevOpal.cpp index 3014ebb9..bf621633 100644 --- a/Common/DtaDevOpal.cpp +++ b/Common/DtaDevOpal.cpp @@ -1,5 +1,6 @@ /* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. +This software is Copyright 2023 Nutanix, Inc. This file is part of sedutil. @@ -1638,9 +1639,21 @@ uint8_t DtaDevOpal::properties() props->addToken(OPAL_TOKEN::ENDNAME); props->addToken(OPAL_TOKEN::ENDLIST); props->complete(); - if ((lastRC = session->sendCommand(props, propertiesResponse)) != 0) { - delete props; - return lastRC; + for (uint8_t trial=1; trial<=2; trial++) { + if ((lastRC = session->sendCommand(props, propertiesResponse)) != 0) { + LOG(E) << "Property Exchange Command Failed rc = " << (int)lastRC; + if (trial == 1) { + LOG(D) << "Try to apply stack reset"; + if (this->stack_reset(this->comID() << 16) == 0x0000) { + LOG(D) << "Stack Reset Successful"; + continue; + } + LOG(E) << "Stack Reset Failed"; + delete props; + return lastRC; + } + } + break; } disk_info.Properties = 1; delete props; diff --git a/Common/DtaLexicon.h b/Common/DtaLexicon.h index 7e490f4c..e1892378 100644 --- a/Common/DtaLexicon.h +++ b/Common/DtaLexicon.h @@ -1,5 +1,6 @@ /* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. +This software is Copyright 2023 Nutanix, Inc. This file is part of sedutil. @@ -264,3 +265,8 @@ typedef enum _OPALSTATUSCODE { AUTHORITY_LOCKED_OUT = 0x12, FAIL = 0x3f, } OPALSTATUSCODE; + +typedef enum _SA_CORE_COMM_LAYER_CMD { + VERIFY_COMID_VALID, + STACK_RESET +} SA_CORE_COMM_LAYER_CMD; diff --git a/Common/DtaSession.cpp b/Common/DtaSession.cpp index e7b51a14..37700938 100644 --- a/Common/DtaSession.cpp +++ b/Common/DtaSession.cpp @@ -1,5 +1,6 @@ /* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. +This software is Copyright 2023 Nutanix, Inc. This file is part of sedutil. @@ -140,11 +141,22 @@ DtaSession::start(OPAL_UID SP, char * HostChallenge, vector SignAuthori cmd->addToken(OPAL_TOKEN::ENDLIST); // ] (Close Bracket) cmd->complete(); - if ((lastRC = sendCommand(cmd, response)) != 0) { - LOG(E) << "Session start failed rc = " << (int)lastRC; - delete cmd; - return lastRC; - } + for (uint8_t trial=1; trial<=2; trial++) { + if ((lastRC = sendCommand(cmd, response)) != 0) { + LOG(E) << "Session start failed rc = " << (int)lastRC; + if (trial == 1) { + LOG(D) << "Try to apply stack reset"; + if (d->stack_reset(d->comID() << 16) == 0x0000) { + LOG(D) << "Stack Reset Successful"; + continue; + } + LOG(E) << "Stack Reset Failed"; + } + delete cmd; + return lastRC; + } + break; + } // call user method SL HSN TSN EL EOD SL 00 00 00 EL // 0 1 2 3 4 5 6 7 8 HSN = SWAP32(response.getUint32(4)); diff --git a/Common/DtaStructures.h b/Common/DtaStructures.h index 12a92b0e..37dc59a9 100644 --- a/Common/DtaStructures.h +++ b/Common/DtaStructures.h @@ -1,5 +1,6 @@ /* C:B************************************************************************** This software is Copyright 2014-2017 Bright Plaza Inc. +This software is Copyright 2023 Nutanix, Inc. This file is part of sedutil. @@ -264,6 +265,97 @@ typedef struct _OPALHeader { OPALPacket pkt; OPALDataSubPacket subpkt; } OPALHeader; + +/** Comm Layer Commands */ + +/** Comm Layer Response Header + * se Header */ +typedef struct _SSCCommRespHdr { + uint32_t extendedComID; + uint32_t requestCode; + uint16_t reserved0; + uint16_t length; +} SSCCommRespHdr; + +typedef struct _SSCDateVal { + uint8_t year[2]; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t fraction[2]; + uint8_t reserved; + + uint16_t get_year() { + return (year[1] | (year[0] << 8)); + } + uint16_t get_fraction() { + return (fraction[1] | (fraction[0] << 8)); + } +} SSCDateVal; + +typedef struct _SSCCommResp { + union Response { + struct { + SSCCommRespHdr hdr; + } no_resp; + struct VerifyComIDValid { + SSCCommRespHdr hdr; + enum uint32_t { + INVALID = 0x00000000, + INACTIVE = 0x01000000, + ISSUED = 0x02000000, + ASSOCIATED = 0x03000000 + } state; + SSCDateVal allocation_time; + SSCDateVal expiry_time; + SSCDateVal since_last_reset_time; + } verify_comid_valid; + struct Reset { + SSCCommRespHdr hdr; + enum uint32_t { + SUCCESS = 0x00000000, + FAILURE = 0x01000000 + } status; + } reset; + struct { + SSCCommRespHdr hdr; + } reset_pending; + struct { + uint8_t data[512]; + } raw; + } structure; + enum {NO_RESP, VERIFY_COMID_RESP, STACK_RESET_RESP, STACK_RESET_PEND_RESP, UNKNOWN } type; + uint16_t length; + + void decode() { + length = ((structure.no_resp.hdr.length & 0xFF) << 8) | ((structure.no_resp.hdr.length >> 8) & 0xFF); + switch (structure.no_resp.hdr.requestCode) { + case 0x01000000 : { + if (structure.no_resp.hdr.length == 0) + type = NO_RESP; + else if (length == 0x22) + type = VERIFY_COMID_RESP; + else type = UNKNOWN; + }; + break; + case 0x02000000 : { + if (structure.reset_pending.hdr.length == 0) + type = STACK_RESET_PEND_RESP; + else if (length == 0x4) + type = STACK_RESET_RESP; + else type = UNKNOWN; + }; + break; + default: { + type = UNKNOWN; + } + break; + } + } +} SSCCommResp; + /** ATA commands needed for TCG storage communication */ typedef enum _ATACOMMAND { IF_RECV = 0x5c, @@ -466,4 +558,4 @@ class CScsiCmdSecurityProtocolOut uint8_t m_Control; // 11 }; // 12 -#pragma pack(pop) \ No newline at end of file +#pragma pack(pop)