summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Spinler <spinler@us.ibm.com>2018-07-11 14:13:52 -0500
committerMatt Spinler <spinler@us.ibm.com>2018-08-06 15:10:17 -0500
commit9eab98618fb0e30b24be34e25817f849f5b5ac7b (patch)
tree6fc4f0b909b15e31abd97919212f17303791c3c7
parent81957841962362be620339dd30573030d54475df (diff)
downloadphosphor-state-manager-9eab98618fb0e30b24be34e25817f849f5b5ac7b.tar.gz
phosphor-state-manager-9eab98618fb0e30b24be34e25817f849f5b5ac7b.zip
Add LastStateChangeTime to chassis manager
This property is set to the timestamp of the last time the chassis power state changed. It is persisted so it survives reboots. Resolves openbmc/openbmc#3300 Tested: Various incantations of power cycling, reboots, and AC pulls. Change-Id: I19f244e0490bc9b921454e393989a9cbd283e2dd Signed-off-by: Matt Spinler <spinler@us.ibm.com>
-rw-r--r--chassis_state_manager.cpp92
-rw-r--r--chassis_state_manager.hpp31
-rw-r--r--configure.ac6
3 files changed, 129 insertions, 0 deletions
diff --git a/chassis_state_manager.cpp b/chassis_state_manager.cpp
index a723d8f..a99aec9 100644
--- a/chassis_state_manager.cpp
+++ b/chassis_state_manager.cpp
@@ -95,6 +95,22 @@ void Chassis::determineInitialState()
server::Chassis::requestedPowerTransition(Transition::On);
return;
}
+ else
+ {
+ // The system is off. If we think it should be on then
+ // we probably lost AC while up, so set a new state
+ // change time.
+ uint64_t lastTime;
+ PowerState lastState;
+
+ if (deserializeStateChangeTime(lastTime, lastState))
+ {
+ if (lastState == PowerState::On)
+ {
+ setStateChangeTime();
+ }
+ }
+ }
}
catch (const SdBusError& e)
{
@@ -220,6 +236,7 @@ int Chassis::sysStateChange(sdbusplus::message::message& msg)
{
log<level::INFO>("Received signal that power OFF is complete");
this->currentPowerState(server::Chassis::PowerState::Off);
+ this->setStateChangeTime();
}
else if ((newStateUnit == CHASSIS_STATE_POWERON_TGT) &&
(newStateResult == "done") &&
@@ -227,6 +244,7 @@ int Chassis::sysStateChange(sdbusplus::message::message& msg)
{
log<level::INFO>("Received signal that power ON is complete");
this->currentPowerState(server::Chassis::PowerState::On);
+ this->setStateChangeTime();
}
return 0;
@@ -367,6 +385,80 @@ void Chassis::startPOHCounter()
}
}
+void Chassis::serializeStateChangeTime()
+{
+ fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
+ std::ofstream os(path.c_str(), std::ios::binary);
+ cereal::JSONOutputArchive oarchive(os);
+
+ oarchive(ChassisInherit::lastStateChangeTime(),
+ ChassisInherit::currentPowerState());
+}
+
+bool Chassis::deserializeStateChangeTime(uint64_t& time, PowerState& state)
+{
+ fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
+
+ try
+ {
+ if (fs::exists(path))
+ {
+ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
+ cereal::JSONInputArchive iarchive(is);
+ iarchive(time, state);
+ return true;
+ }
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>(e.what());
+ fs::remove(path);
+ }
+
+ return false;
+}
+
+void Chassis::restoreChassisStateChangeTime()
+{
+ uint64_t time;
+ PowerState state;
+
+ if (!deserializeStateChangeTime(time, state))
+ {
+ ChassisInherit::lastStateChangeTime(0);
+ }
+ else
+ {
+ ChassisInherit::lastStateChangeTime(time);
+ }
+}
+
+void Chassis::setStateChangeTime()
+{
+ using namespace std::chrono;
+ uint64_t lastTime;
+ PowerState lastState;
+
+ auto now =
+ duration_cast<milliseconds>(system_clock::now().time_since_epoch())
+ .count();
+
+ // If power is on when the BMC is rebooted, this function will get called
+ // because sysStateChange() runs. Since the power state didn't change
+ // in this case, neither should the state change time, so check that
+ // the power state actually did change here.
+ if (deserializeStateChangeTime(lastTime, lastState))
+ {
+ if (lastState == ChassisInherit::currentPowerState())
+ {
+ return;
+ }
+ }
+
+ ChassisInherit::lastStateChangeTime(now);
+ serializeStateChangeTime();
+}
+
} // namespace manager
} // namespace state
} // namepsace phosphor
diff --git a/chassis_state_manager.hpp b/chassis_state_manager.hpp
index 5532949..9a6b647 100644
--- a/chassis_state_manager.hpp
+++ b/chassis_state_manager.hpp
@@ -61,6 +61,8 @@ class Chassis : public ChassisInherit
{
subscribeToSystemdSignals();
+ restoreChassisStateChangeTime();
+
determineInitialState();
restorePOHCounter(); // restore POHCounter from persisted file
@@ -157,6 +159,35 @@ class Chassis : public ChassisInherit
*/
bool deserializePOH(const fs::path& path, uint32_t& retCounter);
+ /** @brief Sets the LastStateChangeTime property and persists it. */
+ void setStateChangeTime();
+
+ /** @brief Serialize the last power state change time.
+ *
+ * Save the time the state changed and the state itself.
+ * The state needs to be saved as well so that during rediscovery
+ * on reboots there's a way to know not to update the time again.
+ */
+ void serializeStateChangeTime();
+
+ /** @brief Deserialize the last power state change time.
+ *
+ * @param[out] time - Deserialized time
+ * @param[out] state - Deserialized power state
+ *
+ * @return bool - true if successful, false otherwise.
+ */
+ bool deserializeStateChangeTime(uint64_t& time, PowerState& state);
+
+ /** @brief Restores the power state change time.
+ *
+ * The time is loaded into the LastStateChangeTime D-Bus property.
+ * On the very first start after this code has been applied but
+ * before the state has changed, the LastStateChangeTime value
+ * will be zero.
+ */
+ void restoreChassisStateChangeTime();
+
/** @brief Timer */
std::unique_ptr<phosphor::state::manager::Timer> timer;
};
diff --git a/configure.ac b/configure.ac
index 838aaf2..f1d3a2f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -66,6 +66,12 @@ AS_IF([test "x$POH_COUNTER_PERSIST_PATH" == "x"], \
AC_DEFINE_UNQUOTED([POH_COUNTER_PERSIST_PATH], ["$POH_COUNTER_PERSIST_PATH"], \
[Path of file for storing POH counter.])
+AC_ARG_VAR(CHASSIS_STATE_CHANGE_PERSIST_PATH, [Path of file for storing the state change time.])
+AS_IF([test "x$CHASSIS_STATE_CHANGE_PERSIST_PATH" == "x"], \
+ [CHASSIS_STATE_CHANGE_PERSIST_PATH="/var/lib/phosphor-state-manager/chassisStateChangeTime"])
+AC_DEFINE_UNQUOTED([CHASSIS_STATE_CHANGE_PERSIST_PATH], ["$CHASSIS_STATE_CHANGE_PERSIST_PATH"], \
+ [Path of file for storing the state change time.])
+
AC_ARG_VAR(BOOT_COUNT_MAX_ALLOWED, [The maximum allowed reboot count])
AS_IF([test "x$BOOT_COUNT_MAX_ALLOWED" == "x"], [BOOT_COUNT_MAX_ALLOWED=3])
AC_DEFINE_UNQUOTED([BOOT_COUNT_MAX_ALLOWED], [$BOOT_COUNT_MAX_ALLOWED], [The maximum allowed reboot count])
OpenPOWER on IntegriCloud