From ed64fe7379a259a822aca69e70426a2b07aad25d Mon Sep 17 00:00:00 2001 From: Kuiying Wang Date: Tue, 7 Aug 2018 16:43:00 +0800 Subject: [PATCH] Capture host restart cause Capture host restart cause on power/reset button pressed, ipmi command/webui, host OS reboot(Ctrl-Alt-Del), and power restore policy settings. Save the restart cause into file system, and restore it when BMC boot up. Signed-off-by: Kuiying Wang Signed-off-by: Yong Li --- configure.ac | 4 +- discover_system_state.cpp | 14 +++++ host_state_manager.cpp | 17 ++++++ host_state_manager.hpp | 148 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 178 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 7919ec5..051a0c0 100644 --- a/configure.ac +++ b/configure.ac @@ -52,9 +52,9 @@ AC_ARG_VAR(HOST_RUNNING_FILE, [File to create if host is running]) AS_IF([test "x$HOST_RUNNING_FILE" == "x"], [HOST_RUNNING_FILE="/run/openbmc/host@%u-on"]) AC_DEFINE_UNQUOTED([HOST_RUNNING_FILE], ["$HOST_RUNNING_FILE"], [File to create if host is running]) -AC_ARG_VAR(HOST_STATE_PERSIST_PATH, [Path of file for storing requested host state.]) +AC_ARG_VAR(HOST_STATE_PERSIST_PATH, [Path of file for storing host state.]) AS_IF([test "x$HOST_STATE_PERSIST_PATH" == "x"], \ - [HOST_STATE_PERSIST_PATH="/var/lib/phosphor-state-manager/requestedHostTransition"]) + [HOST_STATE_PERSIST_PATH="/var/lib/phosphor-state-manager/hostState"]) AC_DEFINE_UNQUOTED([HOST_STATE_PERSIST_PATH], ["$HOST_STATE_PERSIST_PATH"], \ [Path of file for storing requested host state.]) diff --git a/discover_system_state.cpp b/discover_system_state.cpp index 3a38152..0b5798a 100644 --- a/discover_system_state.cpp +++ b/discover_system_state.cpp @@ -12,6 +12,7 @@ #include "settings.hpp" #include "xyz/openbmc_project/Common/error.hpp" #include "xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp" +#include namespace phosphor { @@ -181,6 +182,10 @@ int main(int argc, char** argv) log("power_policy=ALWAYS_POWER_ON, powering host on"); setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition", convertForMessage(server::Host::Transition::On)); + + setProperty( + bus, hostPath, HOST_BUSNAME, "HostRestartCause", + convertForMessage(server::Host::RestartCause::PowerPolicyAlwaysOn)); } else if (RestorePolicy::Policy::Restore == RestorePolicy::convertPolicyFromString(powerPolicy)) @@ -192,6 +197,15 @@ int main(int argc, char** argv) getProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition"); setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition", hostReqState); + + if (server::Host::convertTransitionFromString(hostReqState) == + server::Host::Transition::On) + { + setProperty( + bus, hostPath, HOST_BUSNAME, "HostRestartCause", + convertForMessage( + server::Host::RestartCause::PowerPolicyPreviousState)); + } } return 0; diff --git a/host_state_manager.cpp b/host_state_manager.cpp index 7d661dd..0e00e78 100644 --- a/host_state_manager.cpp +++ b/host_state_manager.cpp @@ -308,6 +308,15 @@ bool Host::deserialize(const fs::path& path) } } +void Host::restoreHostRestartCause() +{ + if (!deserialize(HOST_STATE_PERSIST_PATH)) + { + // set to default value + server::Host::hostRestartCause(server::Host::RestartCause::Unknown); + } +} + Host::Transition Host::requestedHostTransition(Transition value) { log("Host State transaction request", @@ -321,6 +330,7 @@ Host::Transition Host::requestedHostTransition(Transition value) // check of this count will occur if (value != server::Host::Transition::Off) { + hostRestartCause(RestartCause::IpmiCommand); decrementRebootCount(); } @@ -353,6 +363,13 @@ Host::HostState Host::currentHostState(HostState value) return server::Host::currentHostState(value); } +Host::RestartCause Host::hostRestartCause(RestartCause value) +{ + auto retVal = server::Host::hostRestartCause(value); + serialize(); + return retVal; +} + } // namespace manager } // namespace state } // namespace phosphor diff --git a/host_state_manager.hpp b/host_state_manager.hpp index 2b00777..afd8aa3 100644 --- a/host_state_manager.hpp +++ b/host_state_manager.hpp @@ -32,6 +32,22 @@ using namespace phosphor::logging; namespace sdbusRule = sdbusplus::bus::match::rules; namespace fs = std::experimental::filesystem; +const static constexpr char* powerButtonPath = + "/xyz/openbmc_project/Chassis/Buttons/Power0"; +const static constexpr char* powerButtonIntf = + "xyz.openbmc_project.Chassis.Buttons.Power"; +const static constexpr char* resetButtonPath = + "/xyz/openbmc_project/Chassis/Buttons/Reset0"; +const static constexpr char* resetButtonIntf = + "xyz.openbmc_project.Chassis.Buttons.Reset"; + +const static constexpr char* powerControlService = + "xyz.openbmc_project.Chassis.Control.Power"; +const static constexpr char* powerControlPath = + "/xyz/openbmc_project/Chassis/Control/Power0"; +const static constexpr char* powerControlInterface = + "xyz.openbmc_project.Chassis.Control.Power"; + /** @class Host * @brief OpenBMC host state management implementation. * @details A concrete implementation for xyz.openbmc_project.State.Host @@ -59,8 +75,93 @@ class Host : public HostInherit sdbusRule::interface("org.freedesktop.systemd1.Manager"), std::bind(std::mem_fn(&Host::sysStateChange), this, std::placeholders::_1)), - settings(bus) + settings(bus), + powerButtonPressedSignal( + bus, + sdbusRule::type::signal() + sdbusRule::member("Pressed") + + sdbusRule::path(powerButtonPath) + + sdbusRule::interface(powerButtonIntf), + [this](sdbusplus::message::message& msg) { + phosphor::logging::log( + "powerButtonPressedSignal callback function is called..."); + this->hostRestartCause(this->RestartCause::PowerButton); + this->powerButtonPressed = true; + return; + }), + resetButtonPressedSignal( + bus, + sdbusRule::type::signal() + sdbusRule::member("Pressed") + + sdbusRule::path(resetButtonPath) + + sdbusRule::interface(resetButtonIntf), + [this](sdbusplus::message::message& msg) { + phosphor::logging::log( + "resetButtonPressedSignal callback function is called..."); + this->hostRestartCause(this->RestartCause::ResetButton); + this->resetButtonPressed = true; + return; + }), + postCompletePropSignal( + bus, + sdbusplus::bus::match::rules::propertiesChanged( + powerControlPath, powerControlInterface), + [this](sdbusplus::message::message& msg) { + phosphor::logging::log( + "postCompletePropSignal callback function is called..."); + + using DbusVariant = sdbusplus::message::variant< + std::string, bool, uint8_t, uint16_t, int16_t, uint32_t, + int32_t, uint64_t, int64_t, double>; + + std::map props; + std::vector inval; + std::string iface; + msg.read(iface, props, inval); + + for (const auto& t : props) + { + auto key = t.first; + auto value = t.second; + + if (key == "state") + { + this->powerStateChanged = true; + } + + else if (key == "pgood") + { + this->pgood = + sdbusplus::message::variant_ns::get(value); + } + + else if (key == "post_complete") + { + bool postState = + sdbusplus::message::variant_ns::get(value); + + if (!postState && this->pgood) + { + if (!this->resetButtonPressed && + !this->powerButtonPressed && + !this->powerStateChanged) + { + phosphor::logging::log< + phosphor::logging::level::INFO>( + "OEM Reset"); + this->hostRestartCause(this->RestartCause::OEM); + } + this->powerButtonPressed = false; + this->powerStateChanged = false; + this->resetButtonPressed = false; + } + } + } + }) { + powerButtonPressed = false; + powerStateChanged = false; + resetButtonPressed = false; + pgood = 0; + // Enable systemd signals subscribeToSystemdSignals(); @@ -69,8 +170,29 @@ class Host : public HostInherit attemptsLeft(BOOT_COUNT_MAX_ALLOWED); + restoreHostRestartCause(); // restore host restart cause from persisted + // file + // We deferred this until we could get our property correct this->emit_object_added(); + sdbusplus::message::variant pgoodProp = -1; + auto method = + this->bus.new_method_call(powerControlService, powerControlPath, + "org.freedesktop.DBus.Properties", "Get"); + + method.append(powerControlInterface, "pgood"); + try + { + auto reply = this->bus.call(method); + reply.read(pgoodProp); + pgood = sdbusplus::message::variant_ns::get(pgoodProp); + } + catch (const sdbusplus::exception::SdBusError& e) + { + log("Error performing call to get pgood", + entry("NAME=%s", e.name()), + entry("ERROR=%s", e.what())); + } } /** @brief Set value of HostTransition */ @@ -85,6 +207,9 @@ class Host : public HostInherit /** @brief Set value of CurrentHostState */ HostState currentHostState(HostState value) override; + /** @brief Set value of HostRestartCause */ + RestartCause hostRestartCause(RestartCause value) override; + /** * @brief Set host reboot count to default * @@ -192,7 +317,9 @@ class Host : public HostInherit server::Progress::bootProgress()), convertForMessage( sdbusplus::xyz::openbmc_project::State::OperatingSystem:: - server::Status::operatingSystemState())); + server::Status::operatingSystemState()), + convertForMessage(sdbusplus::xyz::openbmc_project::State:: + server::Host::hostRestartCause())); } /** @brief Function required by Cereal to perform deserialization. @@ -208,7 +335,8 @@ class Host : public HostInherit std::string reqTranState; std::string bootProgress; std::string osState; - archive(reqTranState, bootProgress, osState); + std::string restartCause; + archive(reqTranState, bootProgress, osState, restartCause); auto reqTran = Host::convertTransitionFromString(reqTranState); // When restoring, set the requested state with persistent value // but don't call the override which would execute it @@ -219,6 +347,8 @@ class Host : public HostInherit sdbusplus::xyz::openbmc_project::State::OperatingSystem::server:: Status::operatingSystemState( Host::convertOSStatusFromString(osState)); + sdbusplus::xyz::openbmc_project::State::server::Host::hostRestartCause( + Host::convertRestartCauseFromString(restartCause)); } /** @brief Serialize and persist requested host state @@ -239,6 +369,9 @@ class Host : public HostInherit */ bool deserialize(const fs::path& path); + /** @brief Used to restore HostRestartCause value from persisted file */ + void restoreHostRestartCause(); + /** @brief Persistent sdbusplus DBus bus connection. */ sdbusplus::bus::bus& bus; @@ -247,6 +380,15 @@ class Host : public HostInherit // Settings objects of interest settings::Objects settings; + + bool resetButtonPressed; + bool powerButtonPressed; + bool powerStateChanged; + int32_t pgood; + + sdbusplus::bus::match_t powerButtonPressedSignal; + sdbusplus::bus::match_t resetButtonPressedSignal; + sdbusplus::bus::match_t postCompletePropSignal; }; } // namespace manager -- 2.7.4