From ac90091df28004b3e196042a4fde4699840f4939 Mon Sep 17 00:00:00 2001 From: Varsha Kaverappa Date: Thu, 11 Jul 2024 01:15:47 -0500 Subject: [PATCH] oem-ibm: PLDM Power down effecter and APR support This commit adds a single OEM state effecter with a OEM entity type and with states [7, 9, 10] to perform 3 custom actions ReIPL, PowerDown and ArmAPR. The defined states are PLDM_POWER_CYCLE_OFF_SOFT_GRACEFUL= 7, PLDM_POWER_OFF_SOFT_GRACEFUL= 9 and PLDM_POWER_OFF_HARD_GRACEFUL= 10 When PHYP toggles the PLDM_POWER_CYCLE_OFF_SOFT_GRACEFUL we set the state manager property RequestedHostTransition to ForceWarmReboot instead of Reboot, this will directly reboot the host firmware without notification and chassis power will remain on throughout the reboot, instead of doing a graceful reboot. Signed-off-by: Varsha Kaverappa --- libpldmresponder/oem_handler.hpp | 1 + libpldmresponder/pdr_numeric_effecter.hpp | 3 +- libpldmresponder/pdr_state_effecter.hpp | 3 +- libpldmresponder/pdr_state_sensor.hpp | 66 +++++- libpldmresponder/platform.cpp | 32 +-- libpldmresponder/platform.hpp | 21 +- .../libpldmresponder_pdr_effecter_test.cpp | 8 +- .../test/libpldmresponder_pdr_sensor_test.cpp | 4 +- .../test/libpldmresponder_platform_test.cpp | 28 +-- oem/ibm/libpldmresponder/oem_ibm_handler.cpp | 202 ++++++++++++++++++ oem/ibm/libpldmresponder/oem_ibm_handler.hpp | 31 ++- .../libpldmresponder_oem_platform_test.cpp | 2 +- pldmd/pldmd.cpp | 6 +- pldmtool/oem/ibm/oem_ibm_state_set.hpp | 4 +- pldmtool/pldm_platform_cmd.cpp | 7 +- 15 files changed, 365 insertions(+), 53 deletions(-) diff --git a/libpldmresponder/oem_handler.hpp b/libpldmresponder/oem_handler.hpp index 3b14ea835..93a7da048 100644 --- a/libpldmresponder/oem_handler.hpp +++ b/libpldmresponder/oem_handler.hpp @@ -22,6 +22,7 @@ class Handler : public CmdHandler * * @param[in] entityType - entity type corresponding to the sensor * @param[in] entityInstance - entity instance number + * @param[in] entityContainerID - container id * @param[in] stateSetId - state set id * @param[in] compSensorCnt - composite sensor count * @param[out] stateField - The state field data for each of the states, diff --git a/libpldmresponder/pdr_numeric_effecter.hpp b/libpldmresponder/pdr_numeric_effecter.hpp index a425da38b..c987016b3 100644 --- a/libpldmresponder/pdr_numeric_effecter.hpp +++ b/libpldmresponder/pdr_numeric_effecter.hpp @@ -28,7 +28,8 @@ static const Json empty{}; template void generateNumericEffecterPDR(const DBusInterface& dBusIntf, const Json& json, Handler& handler, - pdr_utils::RepoInterface& repo) + pdr_utils::RepoInterface& repo, + pldm_entity_association_tree* /*bmcEntityTree*/) { static const std::vector emptyList{}; auto entries = json.value("entries", emptyList); diff --git a/libpldmresponder/pdr_state_effecter.hpp b/libpldmresponder/pdr_state_effecter.hpp index 4e3031a7c..2a8f41588 100644 --- a/libpldmresponder/pdr_state_effecter.hpp +++ b/libpldmresponder/pdr_state_effecter.hpp @@ -28,7 +28,8 @@ static const Json empty{}; */ template void generateStateEffecterPDR(const DBusInterface& dBusIntf, const Json& json, - Handler& handler, pdr_utils::RepoInterface& repo) + Handler& handler, pdr_utils::RepoInterface& repo, + pldm_entity_association_tree* /*bmcEntityTree*/) { static const std::vector emptyList{}; auto entries = json.value("entries", emptyList); diff --git a/libpldmresponder/pdr_state_sensor.hpp b/libpldmresponder/pdr_state_sensor.hpp index dd9a99280..a1fe011f1 100644 --- a/libpldmresponder/pdr_state_sensor.hpp +++ b/libpldmresponder/pdr_state_sensor.hpp @@ -18,6 +18,9 @@ using Json = nlohmann::json; static const Json empty{}; +constexpr uint32_t BMC_PDR_START_RANGE = 0x00000000; +constexpr uint32_t BMC_PDR_END_RANGE = 0x00FFFFFF; + /** @brief Parse PDR JSON file and generate state sensor PDR structure * * @param[in] json - the JSON Object with the state sensor PDR @@ -27,7 +30,8 @@ static const Json empty{}; */ template void generateStateSensorPDR(const DBusInterface& dBusIntf, const Json& json, - Handler& handler, pdr_utils::RepoInterface& repo) + Handler& handler, pdr_utils::RepoInterface& repo, + pldm_entity_association_tree* bmcEntityTree) { static const std::vector emptyList{}; auto entries = json.value("entries", emptyList); @@ -99,6 +103,66 @@ void generateStateSensorPDR(const DBusInterface& dBusIntf, const Json& json, { continue; } + // now attach this entity to the container that was + // mentioned in the json, and add this entity to the + // parents entity assocation PDR + + std::string parent_entity_path = e.value("parent_entity_path", + ""); + if (parent_entity_path != "" && + associatedEntityMap.contains(parent_entity_path)) + { + // find the parent node in the tree + pldm_entity parent_entity = + associatedEntityMap.at(parent_entity_path); + pldm_entity child_entity = {pdr->entity_type, + pdr->entity_instance, + pdr->container_id}; + auto parent_node = + pldm_entity_association_tree_find_with_locality( + bmcEntityTree, &parent_entity, false); + if (!parent_node) + { + // parent node not found in the entity association tree, + // this should not be possible + error( + "Parent Entity of type {P_ENTITY_TYP} not found in the BMC Entity Association tree", + "P_ENTITY_TYP", + static_cast(parent_entity.entity_type)); + return; + } + pldm_entity_association_tree_add_entity( + bmcEntityTree, &child_entity, pdr->entity_instance, + parent_node, PLDM_ENTITY_ASSOCIAION_PHYSICAL, false, + false, 0xFFFF); + uint32_t bmc_record_handle = 0; +#ifdef OEM_IBM + auto lastLocalRecord = pldm_pdr_find_last_in_range( + repo.getPdr(), BMC_PDR_START_RANGE, BMC_PDR_END_RANGE); + bmc_record_handle = pldm_pdr_get_record_handle( + repo.getPdr(), lastLocalRecord); +#endif + + [[maybe_unused]] uint8_t bmcEventDataOps; + uint32_t updatedRecordHdlBmc = 0; + bool found = false; + pldm_entity_association_find_parent_entity( + repo.getPdr(), &parent_entity, false, + &updatedRecordHdlBmc, &found); + if (found) + { + pldm_entity_association_pdr_add_contained_entity_to_remote_pdr( + repo.getPdr(), &child_entity, updatedRecordHdlBmc); + bmcEventDataOps = PLDM_RECORDS_MODIFIED; + } + else + { + pldm_entity_association_pdr_create_new( + repo.getPdr(), bmc_record_handle, &parent_entity, + &child_entity, &updatedRecordHdlBmc); + bmcEventDataOps = PLDM_RECORDS_ADDED; + } + } } } catch (const std::exception&) diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp index c81ff89e5..706f18261 100644 --- a/libpldmresponder/platform.cpp +++ b/libpldmresponder/platform.cpp @@ -66,7 +66,8 @@ const std::tuple& } void Handler::generate(const pldm::utils::DBusHandler& dBusIntf, - const std::vector& dir, Repo& repo) + const std::vector& dir, Repo& repo, + pldm_entity_association_tree* bmcEntityTree) { for (const auto& directory : dir) { @@ -86,22 +87,27 @@ void Handler::generate(const pldm::utils::DBusHandler& dBusIntf, const std::map generateHandlers = { {PLDM_STATE_EFFECTER_PDR, [this](const DBusHandler& dBusIntf, const auto& json, - RepoInterface& repo) { + RepoInterface& repo, + pldm_entity_association_tree* bmcEntityTree) { pdr_state_effecter::generateStateEffecterPDR(dBusIntf, json, - *this, repo); + Handler>( + dBusIntf, json, *this, repo, bmcEntityTree); }}, {PLDM_NUMERIC_EFFECTER_PDR, [this](const DBusHandler& dBusIntf, const auto& json, - RepoInterface& repo) { + RepoInterface& repo, + pldm_entity_association_tree* bmcEntityTree) { pdr_numeric_effecter::generateNumericEffecterPDR< - pldm::utils::DBusHandler, Handler>(dBusIntf, json, *this, repo); + pldm::utils::DBusHandler, Handler>(dBusIntf, json, *this, repo, + bmcEntityTree); }}, - {PLDM_STATE_SENSOR_PDR, [this](const DBusHandler& dBusIntf, - const auto& json, RepoInterface& repo) { + {PLDM_STATE_SENSOR_PDR, + [this](const DBusHandler& dBusIntf, const auto& json, + RepoInterface& repo, + pldm_entity_association_tree* bmcEntityTree) { pdr_state_sensor::generateStateSensorPDR(dBusIntf, json, *this, - repo); + repo, bmcEntityTree); }}}; Type pdrType{}; @@ -121,15 +127,15 @@ void Handler::generate(const pldm::utils::DBusHandler& dBusIntf, { pdrType = effecter.value("pdrType", 0); generateHandlers.at(pdrType)(dBusIntf, effecter, - repo); + repo, bmcEntityTree); } auto sensorPDRs = json.value("sensorPDRs", empty); for (const auto& sensor : sensorPDRs) { pdrType = sensor.value("pdrType", 0); - generateHandlers.at(pdrType)(dBusIntf, sensor, - repo); + generateHandlers.at(pdrType)(dBusIntf, sensor, repo, + bmcEntityTree); } } } @@ -199,7 +205,7 @@ Response Handler::getPDR(const pldm_msg* request, size_t payloadLength) { oemPlatformHandler->buildOEMPDR(pdrRepo); } - generate(*dBusIntf, pdrJsonsDir, pdrRepo); + generate(*dBusIntf, pdrJsonsDir, pdrRepo, bmcEntityTree); pdrCreated = true; diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp index ac0776757..b5da9abd5 100644 --- a/libpldmresponder/platform.hpp +++ b/libpldmresponder/platform.hpp @@ -28,9 +28,10 @@ namespace responder { namespace platform { -using generatePDR = std::function; +using generatePDR = std::function; using EffecterId = uint16_t; using DbusObjMaps = @@ -54,6 +55,7 @@ class Handler : public CmdHandler pldm_pdr* repo, HostPDRHandler* hostPDRHandler, pldm::state_sensor::DbusToPLDMEvent* dbusToPLDMEventHandler, fru::Handler* fruHandler, + pldm_entity_association_tree* bmcEntityTree, pldm::responder::oem_platform::Handler* oemPlatformHandler, pldm::responder::platform_config::Handler* platformConfigHandler, pldm::requester::Handler* handler, @@ -63,7 +65,8 @@ class Handler : public CmdHandler instanceIdDb(instanceIdDb), pdrRepo(repo), hostPDRHandler(hostPDRHandler), dbusToPLDMEventHandler(dbusToPLDMEventHandler), fruHandler(fruHandler), - dBusIntf(dBusIntf), oemPlatformHandler(oemPlatformHandler), + bmcEntityTree(bmcEntityTree), dBusIntf(dBusIntf), + oemPlatformHandler(oemPlatformHandler), platformConfigHandler(platformConfigHandler), handler(handler), event(event), pdrJsonDir(pdrJsonDir), pdrCreated(false), pdrJsonsDir({pdrJsonDir}) @@ -71,7 +74,7 @@ class Handler : public CmdHandler if (!buildPDRLazily) { generateTerminusLocatorPDR(pdrRepo); - generate(*dBusIntf, pdrJsonsDir, pdrRepo); + generate(*dBusIntf, pdrJsonsDir, pdrRepo, bmcEntityTree); pdrCreated = true; } @@ -196,7 +199,8 @@ class Handler : public CmdHandler */ void generate(const pldm::utils::DBusHandler& dBusIntf, const std::vector& dir, - pldm::responder::pdr_utils::Repo& repo); + pldm::responder::pdr_utils::Repo& repo, + pldm_entity_association_tree* bmcEntityTree); /** @brief Parse PDR JSONs and build state effecter PDR repository * @@ -204,7 +208,8 @@ class Handler : public CmdHandler * @param[in] repo - instance of state effecter implementation of Repo */ void generateStateEffecterRepo(const pldm::utils::Json& json, - pldm::responder::pdr_utils::Repo& repo); + pldm::responder::pdr_utils::Repo& repo, + pldm_entity_association_tree* bmcEntityTree); /** @brief map of PLDM event type to EventHandlers * @@ -499,6 +504,7 @@ class Handler : public CmdHandler HostPDRHandler* hostPDRHandler; pldm::state_sensor::DbusToPLDMEvent* dbusToPLDMEventHandler; fru::Handler* fruHandler; + pldm_entity_association_tree* bmcEntityTree; const pldm::utils::DBusHandler* dBusIntf; pldm::responder::oem_platform::Handler* oemPlatformHandler; pldm::responder::platform_config::Handler* platformConfigHandler; @@ -521,6 +527,7 @@ class Handler : public CmdHandler * @param[out] entityType - entity type * @param[out] entityInstance - entity instance number * @param[out] stateSetId - state set id + * @param[out] containerId - container id * * @return true if the sensor is OEM. All out parameters are invalid * for a non OEM sensor diff --git a/libpldmresponder/test/libpldmresponder_pdr_effecter_test.cpp b/libpldmresponder/test/libpldmresponder_pdr_effecter_test.cpp index ce344349d..e4b58107a 100644 --- a/libpldmresponder/test/libpldmresponder_pdr_effecter_test.cpp +++ b/libpldmresponder/test/libpldmresponder_pdr_effecter_test.cpp @@ -32,7 +32,7 @@ TEST(GeneratePDRByStateEffecter, testGoodJson) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR); @@ -133,7 +133,7 @@ TEST(GeneratePDRByNumericEffecter, testGoodJson) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_NUMERIC_EFFECTER_PDR); @@ -181,7 +181,7 @@ TEST(GeneratePDR, testMalformedJson) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR); @@ -204,7 +204,7 @@ TEST(findStateEffecterId, goodJson) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); uint16_t entityType = 33; uint16_t entityInstance = 0; uint16_t containerId = 0; diff --git a/libpldmresponder/test/libpldmresponder_pdr_sensor_test.cpp b/libpldmresponder/test/libpldmresponder_pdr_sensor_test.cpp index 92da0662c..6eede60cc 100644 --- a/libpldmresponder/test/libpldmresponder_pdr_sensor_test.cpp +++ b/libpldmresponder/test/libpldmresponder_pdr_sensor_test.cpp @@ -36,7 +36,7 @@ TEST(GeneratePDRByStateSensor, testGoodJson) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_sensor/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); handler.getPDR(req, requestPayloadLength); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR); @@ -88,7 +88,7 @@ TEST(GeneratePDR, testMalformedJson) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_sensor/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); handler.getPDR(req, requestPayloadLength); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR); diff --git a/libpldmresponder/test/libpldmresponder_platform_test.cpp b/libpldmresponder/test/libpldmresponder_platform_test.cpp index 35da05a08..67867de3c 100644 --- a/libpldmresponder/test/libpldmresponder_platform_test.cpp +++ b/libpldmresponder/test/libpldmresponder_platform_test.cpp @@ -43,7 +43,7 @@ TEST(getPDR, testGoodPath) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo repo(pdrRepo); ASSERT_EQ(repo.empty(), false); auto response = handler.getPDR(req, requestPayloadLength); @@ -82,7 +82,7 @@ TEST(getPDR, testShortRead) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo repo(pdrRepo); ASSERT_EQ(repo.empty(), false); auto response = handler.getPDR(req, requestPayloadLength); @@ -115,7 +115,7 @@ TEST(getPDR, testBadRecordHandle) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo repo(pdrRepo); ASSERT_EQ(repo.empty(), false); auto response = handler.getPDR(req, requestPayloadLength); @@ -146,7 +146,7 @@ TEST(getPDR, testNoNextRecord) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo repo(pdrRepo); ASSERT_EQ(repo.empty(), false); auto response = handler.getPDR(req, requestPayloadLength); @@ -179,7 +179,7 @@ TEST(getPDR, testFindPDR) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", pdrRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo repo(pdrRepo); ASSERT_EQ(repo.empty(), false); auto response = handler.getPDR(req, requestPayloadLength); @@ -240,7 +240,7 @@ TEST(setStateEffecterStatesHandler, testGoodRequest) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); handler.getPDR(req, requestPayloadLength); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR); @@ -288,7 +288,7 @@ TEST(setStateEffecterStatesHandler, testBadRequest) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); handler.getPDR(req, requestPayloadLength); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR); @@ -335,7 +335,7 @@ TEST(setNumericEffecterValueHandler, testGoodRequest) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR); @@ -379,7 +379,7 @@ TEST(setNumericEffecterValueHandler, testBadRequest) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR); @@ -416,7 +416,7 @@ TEST(getNumericEffecterValueHandler, testGoodRequest) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR); @@ -493,7 +493,7 @@ TEST(getNumericEffecterValueHandler, testBadRequest) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR); @@ -750,7 +750,7 @@ TEST(TerminusLocatorPDR, BMCTerminusLocatorPDR) MockdBusHandler mockedUtils; auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "", inPDRRepo, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, event); + nullptr, nullptr, nullptr, nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_TERMINUS_LOCATOR_PDR); @@ -796,7 +796,7 @@ TEST(getStateSensorReadingsHandler, testGoodRequest) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_sensor/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR); pdr_utils::PdrEntry e; @@ -846,7 +846,7 @@ TEST(getStateSensorReadingsHandler, testBadRequest) auto event = sdeventplus::Event::get_default(); Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_sensor/good", inPDRRepo, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, event); + nullptr, nullptr, event); Repo inRepo(inPDRRepo); getRepoByType(inRepo, outRepo, PLDM_STATE_SENSOR_PDR); pdr_utils::PdrEntry e; diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp index 906e96429..a604ef878 100644 --- a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp +++ b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp @@ -1,5 +1,7 @@ #include "oem_ibm_handler.hpp" +#include "libpldm/state_set.h" + #include "file_io_type_lid.hpp" #include "libpldmresponder/file_io.hpp" #include "libpldmresponder/pdr_utils.hpp" @@ -141,6 +143,25 @@ int pldm::responder::oem_ibm_platform::Handler:: this, std::placeholders::_1)); } } + else if (entityType == PLDM_OEM_IBM_CHASSIS_POWER_CONTROLLER && + stateSetId == PLDM_STATE_SET_SYSTEM_POWER_STATE) + { + if (stateField[currState].effecter_state == + PLDM_STATE_SET_SYS_POWER_CYCLE_OFF_SOFT_GRACEFUL) + { + processPowerCycleOffSoftGraceful(); + } + else if (stateField[currState].effecter_state == + PLDM_STATE_SET_SYS_POWER_STATE_OFF_SOFT_GRACEFUL) + { + processPowerOffSoftGraceful(); + } + else if (stateField[currState].effecter_state == + PLDM_STATE_SET_SYS_POWER_STATE_OFF_HARD_GRACEFUL) + { + processPowerOffHardGraceful(); + } + } else { rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE; @@ -154,6 +175,105 @@ int pldm::responder::oem_ibm_platform::Handler:: return rc; } +void buildAllSystemPowerStateEffecterPDR( + oem_ibm_platform::Handler* platformHandler, uint16_t entityType, + uint16_t entityInstance, uint16_t stateSetID, pdr_utils::Repo& repo) +{ + size_t pdrSize = 0; + pdrSize = sizeof(pldm_state_effecter_pdr) + + sizeof(state_effecter_possible_states); + std::vector entry{}; + entry.resize(pdrSize); + pldm_state_effecter_pdr* pdr = + reinterpret_cast(entry.data()); + if (!pdr) + { + error("Failed to get record by PDR type, ERROR:{ERR}", "ERR", lg2::hex, + static_cast(PLDM_PLATFORM_INVALID_EFFECTER_ID)); + return; + } + pdr->hdr.record_handle = 0; + pdr->hdr.version = 1; + pdr->hdr.type = PLDM_STATE_EFFECTER_PDR; + pdr->hdr.record_change_num = 0; + pdr->hdr.length = sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr); + pdr->terminus_handle = TERMINUS_HANDLE; + pdr->effecter_id = platformHandler->getNextEffecterId(); + pdr->entity_type = entityType; + pdr->entity_instance = entityInstance; + pdr->container_id = 1; + pdr->effecter_semantic_id = 0; + pdr->effecter_init = PLDM_NO_INIT; + pdr->has_description_pdr = false; + pdr->composite_effecter_count = 1; + + auto* possibleStatesPtr = pdr->possible_states; + auto possibleStates = + reinterpret_cast(possibleStatesPtr); + possibleStates->state_set_id = stateSetID; + possibleStates->possible_states_size = 2; + auto state = + reinterpret_cast(possibleStates); + state->states[0].byte = 128; + state->states[1].byte = 6; + pldm::responder::pdr_utils::PdrEntry pdrEntry{}; + pdrEntry.data = entry.data(); + pdrEntry.size = pdrSize; + repo.addRecord(pdrEntry); +} + +void attachOemEntityToEntityAssociationPDR( + oem_ibm_platform::Handler* platformHandler, + pldm_entity_association_tree* bmcEntityTree, + const std::string& parentEntityPath, pdr_utils::Repo& repo, + pldm_entity childEntity) +{ + auto& associatedEntityMap = platformHandler->getAssociateEntityMap(); + if (associatedEntityMap.contains(parentEntityPath)) + { + // Parent is present in the entity association PDR + pldm_entity parent_entity = associatedEntityMap.at(parentEntityPath); + auto parent_node = pldm_entity_association_tree_find_with_locality( + bmcEntityTree, &parent_entity, false); + if (!parent_node) + { + // parent node not found in the entity association tree, + // this should not be possible + error( + "Parent Entity of type {ENTITY_TYP} not found in the BMC Entity Association tree ", + "ENTITY_TYP", static_cast(parent_entity.entity_type)); + return; + } + uint32_t bmc_record_handle = 0; + +#ifdef OEM_IBM + auto lastLocalRecord = pldm_pdr_find_last_in_range( + repo.getPdr(), BMC_PDR_START_RANGE, BMC_PDR_END_RANGE); + bmc_record_handle = pldm_pdr_get_record_handle(repo.getPdr(), + lastLocalRecord); +#endif + + [[maybe_unused]] uint8_t bmcEventDataOps; + uint32_t updatedRecordHdlBmc = 0; + bool found = false; + pldm_entity_association_find_parent_entity( + repo.getPdr(), &parent_entity, false, &updatedRecordHdlBmc, &found); + if (found) + { + pldm_entity_association_pdr_add_contained_entity_to_remote_pdr( + repo.getPdr(), &childEntity, updatedRecordHdlBmc); + bmcEventDataOps = PLDM_RECORDS_MODIFIED; + } + else + { + pldm_entity_association_pdr_create_new( + repo.getPdr(), bmc_record_handle, &parent_entity, &childEntity, + &updatedRecordHdlBmc); + bmcEventDataOps = PLDM_RECORDS_ADDED; + } + } +} + void buildAllCodeUpdateEffecterPDR(oem_ibm_platform::Handler* platformHandler, uint16_t entityType, uint16_t entityInstance, uint16_t stateSetID, pdr_utils::Repo& repo) @@ -283,6 +403,16 @@ void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR( buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0, PLDM_OEM_IBM_VERIFICATION_STATE, repo); + + buildAllSystemPowerStateEffecterPDR( + this, PLDM_OEM_IBM_CHASSIS_POWER_CONTROLLER, ENTITY_INSTANCE_0, + PLDM_STATE_SET_SYSTEM_POWER_STATE, repo); + + pldm_entity fwUpEntity = {PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, 0, 1}; + attachOemEntityToEntityAssociationPDR( + this, bmcEntityTree, "/xyz/openbmc_project/inventory/system", repo, + fwUpEntity); + auto sensorId = findStateSensorId( repo.getPdr(), 0, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0, 1, PLDM_OEM_IBM_VERIFICATION_STATE); @@ -689,6 +819,78 @@ void pldm::responder::oem_ibm_platform::Handler::setSurvTimer(uint8_t tid, } } +void pldm::responder::oem_ibm_platform::Handler:: + processPowerCycleOffSoftGraceful() +{ + error("Received soft graceful power cycle request"); + pldm::utils::PropertyValue value = + "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; + pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/host0", + "xyz.openbmc_project.State.Host", + "RequestedHostTransition", "string"}; + try + { + dBusIntf->setDbusProperty(dbusMapping, value); + } + catch (const std::exception& e) + { + error( + "Error to do a ForceWarmReboot, chassis power remains on, and boot the host back up. Unable to set property RequestedHostTransition. ERROR={ERR_EXCEP}", + "ERR_EXCEP", e.what()); + } +} + +void pldm::responder::oem_ibm_platform::Handler::processPowerOffSoftGraceful() +{ + error("Received soft power off graceful request"); + pldm::utils::PropertyValue value = + "xyz.openbmc_project.State.Chassis.Transition.Off"; + pldm::utils::DBusMapping dbusMapping{"/xyz/openbmc_project/state/chassis0", + "xyz.openbmc_project.State.Chassis", + "RequestedPowerTransition", "string"}; + try + { + dBusIntf->setDbusProperty(dbusMapping, value); + } + catch (const std::exception& e) + { + error( + "Error in powering down the host. Unable to set property RequestedPowerTransition. ERROR={ERR_EXCEP}", + "ERR_EXCEP", e.what()); + } +} + +void pldm::responder::oem_ibm_platform::Handler::processPowerOffHardGraceful() +{ + error("Received hard power off graceful request"); + pldm::utils::PropertyValue value = + "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"; + pldm::utils::DBusMapping dbusMapping{ + "/xyz/openbmc_project/control/host0/power_restore_policy/one_time", + "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", + "string"}; + try + { + auto customerPolicy = + pldm::utils::DBusHandler().getDbusProperty( + "/xyz/openbmc_project/control/host0/power_restore_policy", + "PowerRestorePolicy", + "xyz.openbmc_project.Control.Power.RestorePolicy"); + if (customerPolicy != + "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff") + { + dBusIntf->setDbusProperty(dbusMapping, value); + } + } + catch (const std::exception& e) + { + error( + "Setting one-time restore policy failed, Unable to set property PowerRestorePolicy. ERROR={ERR_EXCEP}", + "ERR_EXCEP", e.what()); + } + processPowerOffSoftGraceful(); +} + } // namespace oem_ibm_platform } // namespace responder } // namespace pldm diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp index 202f8a128..a35e6afec 100644 --- a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp +++ b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp @@ -1,5 +1,8 @@ #pragma once +#include "libpldm/oem/ibm/entity.h" + +#include "common/utils.hpp" #include "inband_code_update.hpp" #include "libpldmresponder/oem_handler.hpp" #include "libpldmresponder/pdr_utils.hpp" @@ -21,6 +24,8 @@ namespace pldm { namespace responder { +using ObjectPath = std::string; +using AssociatedEntityMap = std::map; namespace oem_ibm_platform { constexpr uint16_t ENTITY_INSTANCE_0 = 0; @@ -47,11 +52,12 @@ class Handler : public oem_platform::Handler pldm::responder::CodeUpdate* codeUpdate, int mctp_fd, uint8_t mctp_eid, pldm::InstanceIdDb& instanceIdDb, sdeventplus::Event& event, - pldm::requester::Handler* handler) : + pldm::requester::Handler* handler, + pldm_entity_association_tree* bmcEntityTree) : oem_platform::Handler(dBusIntf), codeUpdate(codeUpdate), platformHandler(nullptr), mctp_fd(mctp_fd), mctp_eid(mctp_eid), instanceIdDb(instanceIdDb), event(event), - handler(handler), + handler(handler), bmcEntityTree(bmcEntityTree), timer(event, std::bind(std::mem_fn(&Handler::setSurvTimer), this, HYPERVISOR_TID, false)), hostTransitioningToOff(true) @@ -147,7 +153,8 @@ class Handler : public oem_platform::Handler } int getOemStateSensorReadingsHandler( - EntityType entityType, pldm::pdr::EntityInstance entityInstance, + pldm::pdr::EntityType entityType, + pldm::pdr::EntityInstance entityInstance, pldm::pdr::StateSetId stateSetId, pldm::pdr::CompositeCount compSensorCnt, std::vector& stateField); @@ -183,6 +190,11 @@ class Handler : public oem_platform::Handler return platformHandler->getNextSensorId(); } + virtual const AssociatedEntityMap& getAssociateEntityMap() + { + return platformHandler->getAssociateEntityMap(); + } + /** @brief Method to Generate the OEM PDRs * * @param[in] repo - instance of concrete implementation of Repo @@ -287,6 +299,16 @@ class Handler : public oem_platform::Handler platformHandler->setEventReceiver(); } + /** @brief To process the graceful shutdown, cycle chassis power, and boot + * the host back up*/ + void processPowerCycleOffSoftGraceful(); + + /** @brief To process powering down the host*/ + void processPowerOffSoftGraceful(); + + /** @brief To process auto power restore policy*/ + void processPowerOffHardGraceful(); + /** @brief Method to Enable/Disable timer to see if remote terminus sends * the surveillance ping and logs informational error if remote terminus * fails to send the surveillance pings @@ -336,6 +358,9 @@ class Handler : public oem_platform::Handler /** @brief PLDM request handler */ pldm::requester::Handler* handler; + /** @brief Pointer to BMC's entity association tree */ + pldm_entity_association_tree* bmcEntityTree; + /** @brief D-Bus property changed signal match */ std::unique_ptr hostOffMatch; diff --git a/oem/ibm/test/libpldmresponder_oem_platform_test.cpp b/oem/ibm/test/libpldmresponder_oem_platform_test.cpp index ea9b97ab1..20aa140ef 100644 --- a/oem/ibm/test/libpldmresponder_oem_platform_test.cpp +++ b/oem/ibm/test/libpldmresponder_oem_platform_test.cpp @@ -37,7 +37,7 @@ class MockOemPlatformHandler : public oem_ibm_platform::Handler uint8_t mctp_eid, pldm::InstanceIdDb& instanceIdDb, sdeventplus::Event& event) : oem_ibm_platform::Handler(dBusIntf, codeUpdate, mctp_fd, mctp_eid, - instanceIdDb, event, nullptr) + instanceIdDb, event, nullptr, nullptr) {} MOCK_METHOD(uint16_t, getNextEffecterId, ()); MOCK_METHOD(uint16_t, getNextSensorId, ()); diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp index b512b93ae..f2ad275f0 100644 --- a/pldmd/pldmd.cpp +++ b/pldmd/pldmd.cpp @@ -250,7 +250,7 @@ int main(int argc, char** argv) codeUpdate->clearDirPath(LID_STAGING_DIR); oemPlatformHandler = std::make_unique( &dbusHandler, codeUpdate.get(), pldmTransport.getEventSource(), hostEID, - instanceIdDb, event, &reqHandler); + instanceIdDb, event, &reqHandler, bmcEntityTree.get()); codeUpdate->setOemPlatformHandler(oemPlatformHandler.get()); oemFruHandler = std::make_unique(pdrRepo.get()); invoker.registerHandler(PLDM_OEM, std::make_unique( @@ -290,8 +290,8 @@ int main(int argc, char** argv) auto platformHandler = std::make_unique( &dbusHandler, hostEID, &instanceIdDb, PDR_JSONS_DIR, pdrRepo.get(), hostPDRHandler.get(), dbusToPLDMEventHandler.get(), fruHandler.get(), - oemPlatformHandler.get(), platformConfigHandler.get(), &reqHandler, - event, true); + bmcEntityTree.get(), oemPlatformHandler.get(), + platformConfigHandler.get(), &reqHandler, event, true); #ifdef OEM_IBM pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = dynamic_cast( diff --git a/pldmtool/oem/ibm/oem_ibm_state_set.hpp b/pldmtool/oem/ibm/oem_ibm_state_set.hpp index 361ae3c4f..329714ff4 100644 --- a/pldmtool/oem/ibm/oem_ibm_state_set.hpp +++ b/pldmtool/oem/ibm/oem_ibm_state_set.hpp @@ -43,7 +43,9 @@ enum pldm_oem_ibm_boot_state_set_values */ extern const std::map OemIBMEntityType{ {PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, "OEM IBM Firmware Update"}, - {PLDM_OEM_IBM_ENTITY_TPM, "OEM IBM Trusted Platform Module"}}; + {PLDM_OEM_IBM_ENTITY_TPM, "OEM IBM Trusted Platform Module"}, + {PLDM_OEM_IBM_CHASSIS_POWER_CONTROLLER, + "OEM IBM Chassis Power Controller"}}; /** @brief Map for PLDM OEM IBM State Sets */ diff --git a/pldmtool/pldm_platform_cmd.cpp b/pldmtool/pldm_platform_cmd.cpp index 34b73b862..06dac64a4 100644 --- a/pldmtool/pldm_platform_cmd.cpp +++ b/pldmtool/pldm_platform_cmd.cpp @@ -541,8 +541,11 @@ class GetPDR : public CommandInterface "Non Recoverable Error"}}; static inline const std::map setSysPowerState{ - {PLDM_STATE_SET_SYS_POWER_STATE_OFF_SOFT_GRACEFUL, - "Off-Soft Graceful"}}; + {PLDM_STATE_SET_SYS_POWER_STATE_OFF_SOFT_GRACEFUL, "Off-Soft Graceful"}, + {PLDM_STATE_SET_SYS_POWER_CYCLE_OFF_SOFT_GRACEFUL, + "Power Cycle Off-Soft Graceful"}, + {PLDM_STATE_SET_SYS_POWER_STATE_OFF_HARD_GRACEFUL, + "Off-Hard Graceful"}}; static inline const std::map setSWTerminationStatus{ {PLDM_SW_TERM_GRACEFUL_RESTART_REQUESTED,