chassis: Monitor the PowerSystemInputs for power status
In addition to the uPower interface, monitor the PowerSystemInputs
interface to detect a Brownout condition. Reference:
https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/48015
Tested: In simulation, trigger a power supply brownout and clear it,
verify that phosphor-chassis-check-power-status detects the condition:
Mar 29 19:02:21 p10bmc phosphor-chassis-state-manager[1101]: Power
System Inputs status changed to
xyz.openbmc_project.State.Decorator.PowerSystemInputs.Status.Fault
Mar 29 19:02:21 p10bmc phosphor-chassis-state-manager[1101]: Power
System Inputs status is in Fault state
root@p10bmc:~# /usr/bin/phosphor-chassis-check-power-status --chassis 0
<3> Chassis power status is not good:
xyz.openbmc_project.State.Chassis.PowerStatus.BrownOut
Mar 29 19:08:20 p10bmc phosphor-chassis-check-power-status[1133]:
Chassis power status is not good:
xyz.openbmc_project.State.Chassis.PowerStatus.BrownOut
Mar 29 19:08:20 p10bmc phosphor-log-manager[319]: Created PEL 0x50000004
(BMC ID 4) with SRC BDA13402
Mar 29 19:08:20 p10bmc phosphor-ledmanager[447]: SAI: FRU path:
/xyz/openbmc_project/inventory/system
Mar 29 19:02:21 p10bmc phosphor-chassis-state-manager[1101]: Power
System Inputs status changed to
xyz.openbmc_project.State.Decorator.PowerSystemInputs.Status.Good
Mar 29 19:02:21 p10bmc phosphor-chassis-state-manager[1101]:
determineStatusOfPSUPower(): Good
root@p10bmc:~# /usr/bin/phosphor-chassis-check-power-status --chassis 0
<6> Chassis power status good, start power on
Change-Id: I6adbb6474155e50219b6a48dd9b2cf872934f4a6
Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
diff --git a/chassis_state_manager.cpp b/chassis_state_manager.cpp
index fc1abac..f3e8389 100644
--- a/chassis_state_manager.cpp
+++ b/chassis_state_manager.cpp
@@ -15,6 +15,7 @@
#include <sdbusplus/exception.hpp>
#include <sdeventplus/event.hpp>
#include <sdeventplus/exception.hpp>
+#include <xyz/openbmc_project/State/Decorator/PowerSystemInputs/server.hpp>
#include <filesystem>
#include <fstream>
@@ -30,6 +31,8 @@
// When you see server:: you know we're referencing our base class
namespace server = sdbusplus::xyz::openbmc_project::State::server;
+namespace decoratorServer =
+ sdbusplus::xyz::openbmc_project::State::Decorator::server;
using namespace phosphor::logging;
using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
@@ -61,6 +64,8 @@
constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
constexpr auto UPOWER_INTERFACE = "org.freedesktop.UPower.Device";
+constexpr auto POWERSYSINPUTS_INTERFACE =
+ "xyz.openbmc_project.State.Decorator.PowerSystemInputs";
constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
void Chassis::subscribeToSystemdSignals()
@@ -101,6 +106,15 @@
"/org/freedesktop/UPower", UPOWER_INTERFACE),
[this](auto& msg) { this->uPowerChangeEvent(msg); });
+ // Monitor for any properties changed signals on PowerSystemInputs
+ powerSysInputsPropChangeSignal = std::make_unique<sdbusplus::bus::match_t>(
+ bus,
+ sdbusplus::bus::match::rules::propertiesChangedNamespace(
+ fmt::format(
+ "/xyz/openbmc_project/power/power_supplies/chassis{}/psus", id),
+ POWERSYSINPUTS_INTERFACE),
+ [this](auto& msg) { this->powerSysInputsChangeEvent(msg); });
+
determineStatusOfPower();
std::variant<int> pgood = -1;
@@ -192,6 +206,17 @@
// Default PowerStatus to good
server::Chassis::currentPowerStatus(PowerStatus::Good);
+ determineStatusOfUPSPower();
+ if (server::Chassis::currentPowerStatus() != PowerStatus::Good)
+ {
+ return;
+ }
+
+ determineStatusOfPSUPower();
+}
+
+void Chassis::determineStatusOfUPSPower()
+{
// Find all implementations of the UPower interface
auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
MAPPER_INTERFACE, "GetSubTree");
@@ -296,6 +321,73 @@
return;
}
+void Chassis::determineStatusOfPSUPower()
+{
+ // Find all implementations of the PowerSystemInputs interface
+ auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
+ MAPPER_INTERFACE, "GetSubTree");
+
+ mapper.append("/", 0, std::vector<std::string>({POWERSYSINPUTS_INTERFACE}));
+
+ std::map<std::string, std::map<std::string, std::vector<std::string>>>
+ mapperResponse;
+
+ try
+ {
+ auto mapperResponseMsg = bus.call(mapper);
+ mapperResponseMsg.read(mapperResponse);
+ }
+ catch (const sdbusplus::exception::exception& e)
+ {
+ error("Error in mapper GetSubTree call for PowerSystemInputs: {ERROR}",
+ "ERROR", e);
+ throw;
+ }
+
+ for (const auto& [path, services] : mapperResponse)
+ {
+ for (const auto& serviceIter : services)
+ {
+ const std::string& service = serviceIter.first;
+
+ try
+ {
+ auto method = bus.new_method_call(service.c_str(), path.c_str(),
+ PROPERTY_INTERFACE, "GetAll");
+ method.append(POWERSYSINPUTS_INTERFACE);
+
+ auto response = bus.call(method);
+ using Property = std::string;
+ using Value = std::variant<std::string>;
+ using PropertyMap = std::map<Property, Value>;
+ PropertyMap properties;
+ response.read(properties);
+
+ auto statusStr = std::get<std::string>(properties["Status"]);
+ auto status =
+ decoratorServer::PowerSystemInputs::convertStatusFromString(
+ statusStr);
+
+ if (status == decoratorServer::PowerSystemInputs::Status::Fault)
+ {
+ info("Power System Inputs status is in Fault state");
+ server::Chassis::currentPowerStatus(PowerStatus::BrownOut);
+ return;
+ }
+ }
+ catch (const sdbusplus::exception::exception& e)
+ {
+ error(
+ "Error reading Power System Inputs property, error: {ERROR}, "
+ "service: {SERVICE} path: {PATH}",
+ "ERROR", e, "SERVICE", service, "PATH", path);
+ throw;
+ }
+ }
+ }
+ return;
+}
+
void Chassis::uPowerChangeEvent(sdbusplus::message::message& msg)
{
debug("UPS Property Change Event Triggered");
@@ -303,9 +395,9 @@
std::map<std::string, std::variant<uint, bool>> msgData;
msg.read(statusInterface, msgData);
- // If the change is to any of the three properties we are interested in
- // then call determineStatusOfPower() to see if a power status change
- // is needed
+ // If the change is to any of the properties we are interested in, then call
+ // determineStatusOfPower(), which looks at all the power-related
+ // interfaces, to see if a power status change is needed
auto propertyMap = msgData.find("IsPresent");
if (propertyMap != msgData.end())
{
@@ -335,6 +427,28 @@
return;
}
+void Chassis::powerSysInputsChangeEvent(sdbusplus::message::message& msg)
+{
+ debug("Power System Inputs Property Change Event Triggered");
+ std::string statusInterface;
+ std::map<std::string, std::variant<std::string>> msgData;
+ msg.read(statusInterface, msgData);
+
+ // If the change is to any of the properties we are interested in, then call
+ // determineStatusOfPower(), which looks at all the power-related
+ // interfaces, to see if a power status change is needed
+ auto propertyMap = msgData.find("Status");
+ if (propertyMap != msgData.end())
+ {
+ info("Power System Inputs status changed to {POWER_SYS_INPUT_STATUS}",
+ "POWER_SYS_INPUT_STATUS",
+ std::get<std::string>(propertyMap->second));
+ determineStatusOfPower();
+ return;
+ }
+ return;
+}
+
void Chassis::startUnit(const std::string& sysdUnit)
{
auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,