oem-ibm: Support system reboot after inband code update
This commit adds a bmc effecter that causes a system reboot(
phyp, chassis and bmc)
After bmc sends an end update successful event, Host will
set this new effecter. Upon getting the setStateEffecterStates
call bmc-pldm does the following:
1. Set the power restore to reboot the host once the BMC
is rebooted
2. power off Host and Chassis
3. reboot the bmc
Tested with pldmtool
Steps after patching changes:
1. Boot host to STANDBY
2. Fetch the effecter to note the effecterId
Ex: ./pldmtool platform GetPDR -d 28
3. Trigger the system reboot by toggling the effecter
./pldmtool platform SetStateEffecterStates -i 10 -c 1
-d 1 1
Signed-off-by: Sagar Srinivas <sagar.srinivas@ibm.com>
Change-Id: Id2d4201a7d61ae335adc64f2583571a37dc7879d
diff --git a/oem/ibm/libpldmresponder/file_io_type_lid.hpp b/oem/ibm/libpldmresponder/file_io_type_lid.hpp
index e5e5b5f..841099c 100644
--- a/oem/ibm/libpldmresponder/file_io_type_lid.hpp
+++ b/oem/ibm/libpldmresponder/file_io_type_lid.hpp
@@ -125,7 +125,7 @@
{
flags = O_WRONLY | O_CREAT | O_TRUNC | O_SYNC;
}
- auto fd = open(lidPath.c_str(), flags);
+ auto fd = open(lidPath.c_str(), flags, S_IRUSR);
if (fd == -1)
{
std::cerr << "Could not open file for writing " << lidPath.c_str()
@@ -219,7 +219,7 @@
return PLDM_DATA_OUT_OF_RANGE;
}
}
- auto fd = open(lidPath.c_str(), flags);
+ auto fd = open(lidPath.c_str(), flags, S_IRUSR);
if (fd == -1)
{
std::cerr << "could not open file " << lidPath.c_str() << "\n";
diff --git a/oem/ibm/libpldmresponder/inband_code_update.cpp b/oem/ibm/libpldmresponder/inband_code_update.cpp
index 723caad..27ce945 100644
--- a/oem/ibm/libpldmresponder/inband_code_update.cpp
+++ b/oem/ibm/libpldmresponder/inband_code_update.cpp
@@ -138,7 +138,6 @@
<< "ERROR=" << e.what() << std::endl;
rc = PLDM_ERROR;
}
- newImageId.clear();
return rc;
}
@@ -198,7 +197,7 @@
msg.read(iface, props);
processPriorityChangeNotification(props);
}));
- fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
+ fwUpdateMatcher.push_back(std::make_unique<sdbusplus::bus::match::match>(
pldm::utils::DBusHandler::getBus(),
"interface='org.freedesktop.DBus.ObjectManager',type='signal',"
"member='InterfacesAdded',path='/xyz/openbmc_project/software'",
@@ -206,6 +205,7 @@
DBusInterfaceAdded interfaces;
sdbusplus::message::object_path path;
msg.read(path, interfaces);
+
for (auto& interface : interfaces)
{
if (interface.first ==
@@ -214,6 +214,7 @@
auto imageInterface =
"xyz.openbmc_project.Software.Activation";
auto imageObjPath = path.str.c_str();
+
try
{
auto propVal = dBusIntf->getDbusPropertyVariant(
@@ -224,20 +225,82 @@
isCodeUpdateInProgress())
{
newImageId = path.str;
+ if (!imageActivationMatch)
+ {
+ imageActivationMatch = std::make_unique<
+ sdbusplus::bus::match::match>(
+ pldm::utils::DBusHandler::getBus(),
+ propertiesChanged(newImageId,
+ "xyz.openbmc_project."
+ "Software.Activation"),
+ [this](sdbusplus::message::message& msg) {
+ DbusChangedProps props;
+ std::string iface;
+ msg.read(iface, props);
+ const auto itr =
+ props.find("Activation");
+ if (itr != props.end())
+ {
+ PropertyValue value = itr->second;
+ auto propVal =
+ std::get<std::string>(value);
+ if (propVal ==
+ "xyz.openbmc_project.Software."
+ "Activation.Activations.Active")
+ {
+ CodeUpdateState state =
+ CodeUpdateState::END;
+ setCodeUpdateProgress(false);
+ auto sensorId =
+ getFirmwareUpdateSensor();
+ sendStateSensorEvent(
+ sensorId,
+ PLDM_STATE_SENSOR_STATE, 0,
+ uint8_t(state),
+ uint8_t(CodeUpdateState::
+ START));
+ newImageId.clear();
+ }
+ else if (propVal ==
+ "xyz.openbmc_project."
+ "Software.Activation."
+ "Activations.Failed" ||
+ propVal ==
+ "xyz.openbmc_"
+ "project.Software."
+ "Activation."
+ "Activations."
+ "Invalid")
+ {
+ CodeUpdateState state =
+ CodeUpdateState::FAIL;
+ setCodeUpdateProgress(false);
+ auto sensorId =
+ getFirmwareUpdateSensor();
+ sendStateSensorEvent(
+ sensorId,
+ PLDM_STATE_SENSOR_STATE, 0,
+ uint8_t(state),
+ uint8_t(CodeUpdateState::
+ START));
+ newImageId.clear();
+ }
+ }
+ });
+ }
auto rc = setRequestedActivation();
- CodeUpdateState state = CodeUpdateState::END;
if (rc != PLDM_SUCCESS)
{
- state = CodeUpdateState::FAIL;
+ CodeUpdateState state = CodeUpdateState::FAIL;
+ setCodeUpdateProgress(false);
+ auto sensorId = getFirmwareUpdateSensor();
+ sendStateSensorEvent(
+ sensorId, PLDM_STATE_SENSOR_STATE, 0,
+ uint8_t(state),
+ uint8_t(CodeUpdateState::START));
std::cerr
<< "could not set RequestedActivation \n";
}
- setCodeUpdateProgress(false);
- auto sensorId = getFirmwareUpdateSensor();
- sendStateSensorEvent(
- sensorId, PLDM_STATE_SENSOR_STATE, 0,
- uint8_t(state),
- uint8_t(CodeUpdateState::START));
break;
}
}
@@ -247,7 +310,7 @@
}
}
}
- });
+ }));
}
void CodeUpdate::processPriorityChangeNotification(
diff --git a/oem/ibm/libpldmresponder/inband_code_update.hpp b/oem/ibm/libpldmresponder/inband_code_update.hpp
index 77f55f1..2bd02f4 100644
--- a/oem/ibm/libpldmresponder/inband_code_update.hpp
+++ b/oem/ibm/libpldmresponder/inband_code_update.hpp
@@ -39,6 +39,7 @@
nextBootSide = Tside;
markerLidSensorId = PLDM_INVALID_EFFECTER_ID;
firmwareUpdateSensorId = PLDM_INVALID_EFFECTER_ID;
+ imageActivationMatch = nullptr;
}
/* @brief Method to return the current boot side
@@ -183,7 +184,7 @@
std::vector<std::unique_ptr<sdbusplus::bus::match::match>>
captureNextBootSideChange; //!< vector to catch the D-Bus property
//!< change for next boot side
- std::unique_ptr<sdbusplus::bus::match::match>
+ std::vector<std::unique_ptr<sdbusplus::bus::match::match>>
fwUpdateMatcher; //!< pointer to capture the interface added signal for
//!< new image
pldm::responder::oem_platform::Handler*
@@ -191,6 +192,9 @@
uint16_t markerLidSensorId;
uint16_t firmwareUpdateSensorId;
+ /** @brief D-Bus property changed signal match for image activation */
+ std::unique_ptr<sdbusplus::bus::match::match> imageActivationMatch;
+
/* @brief Method to take action when the subscribed D-Bus property is
* changed
* @param[in] chProperties - list of properties which have changed
diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
index 2f06bc5..43e0de4 100644
--- a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
@@ -120,6 +120,19 @@
// sendCodeUpdateEvent(effecterId, REJECT, END);
}
}
+ else if (entityType == PLDM_ENTITY_SYSTEM_CHASSIS &&
+ stateSetId == PLDM_OEM_IBM_SYSTEM_POWER_STATE)
+ {
+ if (stateField[currState].effecter_state == POWER_CYCLE_HARD)
+ {
+ systemRebootEvent =
+ std::make_unique<sdeventplus::source::Defer>(
+ event,
+ std::bind(std::mem_fn(&oem_ibm_platform::Handler::
+ _processSystemReboot),
+ this, std::placeholders::_1));
+ }
+ }
else
{
rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
@@ -134,8 +147,8 @@
}
void buildAllCodeUpdateEffecterPDR(platform::Handler* platformHandler,
- uint16_t entityInstance, uint16_t stateSetID,
- pdr_utils::Repo& repo)
+ uint16_t entityType, uint16_t entityInstance,
+ uint16_t stateSetID, pdr_utils::Repo& repo)
{
size_t pdrSize = 0;
pdrSize = sizeof(pldm_state_effecter_pdr) +
@@ -156,7 +169,7 @@
pdr->hdr.length = sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr);
pdr->terminus_handle = pdr::BmcPldmTerminusHandle;
pdr->effecter_id = platformHandler->getNextEffecterId();
- pdr->entity_type = PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE;
+ pdr->entity_type = entityType;
pdr->entity_instance = entityInstance;
pdr->container_id = 0;
pdr->effecter_semantic_id = 0;
@@ -175,6 +188,8 @@
state->states[0].byte = 6;
else if (stateSetID == PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE)
state->states[0].byte = 126;
+ else if (stateSetID == PLDM_OEM_IBM_SYSTEM_POWER_STATE)
+ state->states[0].byte = 2;
pldm::responder::pdr_utils::PdrEntry pdrEntry{};
pdrEntry.data = entry.data();
pdrEntry.size = pdrSize;
@@ -232,12 +247,18 @@
void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR(
pdr_utils::Repo& repo)
{
- buildAllCodeUpdateEffecterPDR(platformHandler, ENTITY_INSTANCE_0,
- PLDM_OEM_IBM_BOOT_STATE, repo);
- buildAllCodeUpdateEffecterPDR(platformHandler, ENTITY_INSTANCE_1,
- PLDM_OEM_IBM_BOOT_STATE, repo);
- buildAllCodeUpdateEffecterPDR(platformHandler, ENTITY_INSTANCE_0,
- PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
+ buildAllCodeUpdateEffecterPDR(
+ platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
+ PLDM_OEM_IBM_BOOT_STATE, repo);
+ buildAllCodeUpdateEffecterPDR(
+ platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_1,
+ PLDM_OEM_IBM_BOOT_STATE, repo);
+ buildAllCodeUpdateEffecterPDR(
+ platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
+ PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE, repo);
+ buildAllCodeUpdateEffecterPDR(platformHandler, PLDM_ENTITY_SYSTEM_CHASSIS,
+ ENTITY_INSTANCE_0,
+ PLDM_OEM_IBM_SYSTEM_POWER_STATE, repo);
buildAllCodeUpdateSensorPDR(
platformHandler, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE, ENTITY_INSTANCE_0,
@@ -329,7 +350,6 @@
uint16_t sensorId, enum sensor_event_class_states sensorEventClass,
uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState)
{
-
std::vector<uint8_t> sensorEventDataVec{};
size_t sensorEventSize = PLDM_SENSOR_EVENT_DATA_MIN_LENGTH + 1;
sensorEventDataVec.resize(sensorEventSize);
@@ -397,6 +417,80 @@
uint8_t(CodeUpdateState::END));
}
+void pldm::responder::oem_ibm_platform::Handler::_processSystemReboot(
+ sdeventplus::source::EventBase& /*source */)
+{
+ 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)
+ {
+
+ std::cerr << "Chassis State transition to Off failed,"
+ << "unable to set property RequestedPowerTransition"
+ << "ERROR=" << e.what() << "\n";
+ }
+
+ using namespace sdbusplus::bus::match::rules;
+ chassisOffMatch = std::make_unique<sdbusplus::bus::match::match>(
+ pldm::utils::DBusHandler::getBus(),
+ propertiesChanged("/xyz/openbmc_project/state/chassis0",
+ "xyz.openbmc_project.State.Chassis"),
+ [this](sdbusplus::message::message& msg) {
+ DbusChangedProps props{};
+ std::string intf;
+ msg.read(intf, props);
+ const auto itr = props.find("CurrentPowerState");
+ if (itr != props.end())
+ {
+ PropertyValue value = itr->second;
+ auto propVal = std::get<std::string>(value);
+ if (propVal ==
+ "xyz.openbmc_project.State.Chassis.PowerState.Off")
+ {
+ pldm::utils::DBusMapping dbusMapping{
+ "/xyz/openbmc_project/control/host0/"
+ "power_restore_policy/one_time",
+ "xyz.openbmc_project.Control.Power.RestorePolicy",
+ "PowerRestorePolicy", "string"};
+ value = "xyz.openbmc_project.Control.Power.RestorePolicy."
+ "Policy.AlwaysOn";
+ try
+ {
+ dBusIntf->setDbusProperty(dbusMapping, value);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "Setting one-time restore policy failed,"
+ << "unable to set property PowerRestorePolicy"
+ << "ERROR=" << e.what() << "\n";
+ }
+ dbusMapping = pldm::utils::DBusMapping{
+ "/xyz/openbmc_project/state/bmc0",
+ "xyz.openbmc_project.State.BMC",
+ "RequestedBMCTransition", "string"};
+ value = "xyz.openbmc_project.State.BMC.Transition.Reboot";
+ try
+ {
+ dBusIntf->setDbusProperty(dbusMapping, value);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "BMC state transition to reboot failed,"
+ << "unable to set property "
+ "RequestedBMCTransition"
+ << "ERROR=" << e.what() << "\n";
+ }
+ }
+ }
+ });
+}
} // 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 854c96b..b574262 100644
--- a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
@@ -1,4 +1,5 @@
#pragma once
+#include "libpldm/entity.h"
#include "libpldm/platform.h"
#include "inband_code_update.hpp"
@@ -15,6 +16,7 @@
#define PLDM_OEM_IBM_FIRMWARE_UPDATE_STATE 32768
#define PLDM_OEM_IBM_BOOT_STATE 32769
+#define PLDM_OEM_IBM_SYSTEM_POWER_STATE 32771
static constexpr auto PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE = 24577;
static constexpr auto PLDM_OEM_IBM_VERIFICATION_STATE = 32770;
@@ -39,6 +41,11 @@
MIN_MIF_FAIL = 0x4,
};
+enum SystemPowerStates
+{
+ POWER_CYCLE_HARD = 0x1,
+};
+
class Handler : public oem_platform::Handler
{
public:
@@ -127,6 +134,13 @@
*/
void _processStartUpdate(sdeventplus::source::EventBase& source);
+ /** @brief _processSystemReboot processes the actual work that needs to be
+ * carried out after the System Power State effecter is set to reboot
+ * the system
+ * @param[in] source - sdeventplus event source
+ */
+ void _processSystemReboot(sdeventplus::source::EventBase& source);
+
~Handler() = default;
pldm::responder::CodeUpdate* codeUpdate; //!< pointer to CodeUpdate object
@@ -146,11 +160,16 @@
/** @brief sdeventplus event source */
std::unique_ptr<sdeventplus::source::Defer> assembleImageEvent;
std::unique_ptr<sdeventplus::source::Defer> startUpdateEvent;
+ std::unique_ptr<sdeventplus::source::Defer> systemRebootEvent;
/** @brief reference of main event loop of pldmd, primarily used to schedule
* work
*/
sdeventplus::Event& event;
+
+ private:
+ /** @brief D-Bus property changed signal match for CurrentPowerState*/
+ std::unique_ptr<sdbusplus::bus::match::match> chassisOffMatch;
};
/** @brief Method to encode code update event msg