From c07d24d25c071e03076800e201e077e37c940330 Mon Sep 17 00:00:00 2001 From: Alay Shah Date: Thu, 23 Nov 2023 02:13:15 +0000 Subject: [PATCH 1/2] Introduce Stack Reset Stack reset helps reset situation where user may press Ctrl-C in the middle of command and current established session does not close properly. When operating in single session mode, drive shall not let establish another session until sessionTimeout is reached or drive is power cycled (whichever occurs first). Stack Reset helps reset any on going session and able to re-establish session without reaching timeout or physically removing drive (or power cycling the drive). Use of timeout was interesting idea - but a few drives that tested showed min and max SessionTimeout, when configured value in between, session could not be established due to invalid parameters. SessionTimeout is optional implementation, while Stack Reset is required as per spec. --- Common/DtaDev.cpp | 43 ++++++++++++++++++ Common/DtaDev.h | 6 +++ Common/DtaDevEnterprise.cpp | 18 ++++++-- Common/DtaDevOpal.cpp | 18 ++++++-- Common/DtaLexicon.h | 5 ++ Common/DtaSession.cpp | 21 +++++++-- Common/DtaStructures.h | 91 +++++++++++++++++++++++++++++++++++++ 7 files changed, 191 insertions(+), 11 deletions(-) diff --git a/Common/DtaDev.cpp b/Common/DtaDev.cpp index 0346acf4..b496ae88 100644 --- a/Common/DtaDev.cpp +++ b/Common/DtaDev.cpp @@ -300,3 +300,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..fdfbbd88 100644 --- a/Common/DtaDev.h +++ b/Common/DtaDev.h @@ -283,6 +283,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..423befd0 100644 --- a/Common/DtaDevEnterprise.cpp +++ b/Common/DtaDevEnterprise.cpp @@ -1492,9 +1492,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..c7a9f6e4 100644 --- a/Common/DtaDevOpal.cpp +++ b/Common/DtaDevOpal.cpp @@ -1638,9 +1638,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..9ecccf0e 100644 --- a/Common/DtaLexicon.h +++ b/Common/DtaLexicon.h @@ -264,3 +264,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..58fb6362 100644 --- a/Common/DtaSession.cpp +++ b/Common/DtaSession.cpp @@ -140,11 +140,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..baf67839 100644 --- a/Common/DtaStructures.h +++ b/Common/DtaStructures.h @@ -264,6 +264,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, From a6ac07c1e6ccfdae2b8b729335d4471f3dbc4ec0 Mon Sep 17 00:00:00 2001 From: Alay Shah Date: Thu, 28 Dec 2023 22:33:46 +0000 Subject: [PATCH 2/2] Add copyright information Note: No functionality change expected. --- Common/DtaDev.cpp | 1 + Common/DtaDev.h | 1 + Common/DtaDevEnterprise.cpp | 1 + Common/DtaDevOpal.cpp | 1 + Common/DtaLexicon.h | 1 + Common/DtaSession.cpp | 1 + Common/DtaStructures.h | 3 ++- 7 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Common/DtaDev.cpp b/Common/DtaDev.cpp index b496ae88..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. diff --git a/Common/DtaDev.h b/Common/DtaDev.h index fdfbbd88..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. diff --git a/Common/DtaDevEnterprise.cpp b/Common/DtaDevEnterprise.cpp index 423befd0..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. diff --git a/Common/DtaDevOpal.cpp b/Common/DtaDevOpal.cpp index c7a9f6e4..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. diff --git a/Common/DtaLexicon.h b/Common/DtaLexicon.h index 9ecccf0e..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. diff --git a/Common/DtaSession.cpp b/Common/DtaSession.cpp index 58fb6362..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. diff --git a/Common/DtaStructures.h b/Common/DtaStructures.h index baf67839..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. @@ -557,4 +558,4 @@ class CScsiCmdSecurityProtocolOut uint8_t m_Control; // 11 }; // 12 -#pragma pack(pop) \ No newline at end of file +#pragma pack(pop)