diff options
author | Nagaraju Goruganti <ngorugan@in.ibm.com> | 2018-04-06 13:41:01 -0500 |
---|---|---|
committer | Nagaraju Goruganti <ngorugan@in.ibm.com> | 2018-05-12 04:57:37 +0000 |
commit | cb781fe1b8750712b9f8c6e534e794d27204c5ef (patch) | |
tree | 48428765acf75b0a66eedbcdbd4ff2f40046ca1c | |
parent | 41a774efacb3f3a9593aeaa971468e770d205e13 (diff) | |
download | phosphor-state-manager-cb781fe1b8750712b9f8c6e534e794d27204c5ef.tar.gz phosphor-state-manager-cb781fe1b8750712b9f8c6e534e794d27204c5ef.zip |
Add Chassis POH Counter
Added 32-bit counter, which shows how many hours the system has been
running. The value is a cumulative one and includes all working hours
since production. If the chassis state is Powered-on, This will be
incremented by one for every hour. It won't get updated when the
chassis state is powered-off.
Resolves openbmc/openbmc#2979
Change-Id: I18e9bb571d1a6e401b25450168249f70891be665
Signed-off-by: Nagaraju Goruganti <ngorugan@in.ibm.com>
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | chassis_state_manager.cpp | 128 | ||||
-rw-r--r-- | chassis_state_manager.hpp | 81 | ||||
-rw-r--r-- | chassis_state_manager_main.cpp | 7 | ||||
-rw-r--r-- | configure.ac | 6 |
5 files changed, 216 insertions, 10 deletions
diff --git a/Makefile.am b/Makefile.am index dbd84f9..5aff810 100644 --- a/Makefile.am +++ b/Makefile.am @@ -37,14 +37,14 @@ generic_cxxflags = \ generic_ldflags = \ $(SYSTEMD_LIBS) \ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ - $(SDBUSPLUS_LIBS) + $(SDBUSPLUS_LIBS) \ $(PHOSPHOR_LOGGING_LIBS) phosphor_host_state_manager_CXXFLAGS = $(generic_cxxflags) phosphor_host_state_manager_LDFLAGS = $(generic_ldflags) -lstdc++fs phosphor_chassis_state_manager_CXXFLAGS = $(generic_cxxflags) -phosphor_chassis_state_manager_LDFLAGS = $(generic_ldflags) +phosphor_chassis_state_manager_LDFLAGS = $(generic_ldflags) -lstdc++fs phosphor_bmc_state_manager_CXXFLAGS = $(generic_cxxflags) phosphor_bmc_state_manager_LDFLAGS = $(generic_ldflags) diff --git a/chassis_state_manager.cpp b/chassis_state_manager.cpp index ece0b1c..d78a6f7 100644 --- a/chassis_state_manager.cpp +++ b/chassis_state_manager.cpp @@ -1,6 +1,15 @@ #include <sdbusplus/bus.hpp> #include <phosphor-logging/log.hpp> +#include <phosphor-logging/elog-errors.hpp> +#include "xyz/openbmc_project/Common/error.hpp" #include "chassis_state_manager.hpp" +#include <cereal/archives/json.hpp> +#include <fstream> +#include "config.h" +#include <experimental/filesystem> + +// Register class version with Cereal +CEREAL_CLASS_VERSION(phosphor::state::manager::Chassis, CLASS_VERSION); namespace phosphor { @@ -181,10 +190,127 @@ Chassis::Transition Chassis::requestedPowerTransition(Transition value) Chassis::PowerState Chassis::currentPowerState(PowerState value) { + PowerState chassisPowerState; log<level::INFO>("Change to Chassis Power State", entry("CHASSIS_CURRENT_POWER_STATE=%s", convertForMessage(value).c_str())); - return server::Chassis::currentPowerState(value); + + chassisPowerState = server::Chassis::currentPowerState(value); + if (chassisPowerState == PowerState::On) + { + timer->state(timer::ON); + } + else + { + timer->state(timer::OFF); + } + return chassisPowerState; +} + +uint32_t Chassis::pOHCounter(uint32_t value) +{ + if (value != pOHCounter()) + { + ChassisInherit::pOHCounter(value); + serialize(); + } + return pOHCounter(); +} + +void Chassis::restorePOHCounter() +{ + uint32_t counter; + if (!deserialize(POH_COUNTER_PERSIST_PATH, counter)) + { + // set to default value + pOHCounter(0); + } + else + { + pOHCounter(counter); + } +} + +fs::path Chassis::serialize(const fs::path& path) +{ + std::ofstream os(path.c_str(), std::ios::binary); + cereal::JSONOutputArchive oarchive(os); + oarchive(pOHCounter()); + return path; +} + +bool Chassis::deserialize(const fs::path& path, uint32_t& pOHCounter) +{ + try + { + if (fs::exists(path)) + { + std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); + cereal::JSONInputArchive iarchive(is); + iarchive(pOHCounter); + return true; + } + return false; + } + catch (cereal::Exception& e) + { + log<level::ERR>(e.what()); + fs::remove(path); + return false; + } + catch (const fs::filesystem_error& e) + { + return false; + } + + return false; +} + +void Chassis::startPOHCounter() +{ + using namespace std::chrono_literals; + using namespace phosphor::logging; + using namespace sdbusplus::xyz::openbmc_project::Common::Error; + + auto dir = fs::path(POH_COUNTER_PERSIST_PATH).parent_path(); + fs::create_directories(dir); + + sd_event* event = nullptr; + auto r = sd_event_default(&event); + if (r < 0) + { + log<level::ERR>("Error creating a default sd_event handler"); + throw; + } + + phosphor::state::manager::EventPtr eventP{event}; + event = nullptr; + + auto callback = [&]() { + if (ChassisInherit::currentPowerState() == PowerState::On) + { + pOHCounter(pOHCounter() + 1); + } + }; + + try + { + timer = std::make_unique<phosphor::state::manager::Timer>( + eventP, callback, std::chrono::seconds(POH::hour), + phosphor::state::manager::timer::ON); + bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL); + r = sd_event_loop(eventP.get()); + if (r < 0) + { + log<level::ERR>("Error occurred during the sd_event_loop", + entry("RC=%d", r)); + elog<InternalFailure>(); + } + } + catch (InternalFailure& e) + { + phosphor::logging::commit<InternalFailure>(); + } } } // namespace manager diff --git a/chassis_state_manager.hpp b/chassis_state_manager.hpp index 54f0afd..a1fcb04 100644 --- a/chassis_state_manager.hpp +++ b/chassis_state_manager.hpp @@ -1,8 +1,13 @@ #pragma once #include <functional> +#include <experimental/filesystem> +#include <cereal/cereal.hpp> #include <sdbusplus/bus.hpp> #include "xyz/openbmc_project/State/Chassis/server.hpp" +#include "xyz/openbmc_project/State/PowerOnHours/server.hpp" +#include "config.h" +#include "timer.hpp" namespace phosphor { @@ -10,10 +15,19 @@ namespace state { namespace manager { +namespace POH +{ + +using namespace std::chrono_literals; +constexpr auto hour = 3600s; // seconds Per Hour + +} // namespace POH using ChassisInherit = sdbusplus::server::object::object< - sdbusplus::xyz::openbmc_project::State::server::Chassis>; + sdbusplus::xyz::openbmc_project::State::server::Chassis, + sdbusplus::xyz::openbmc_project::State::server::PowerOnHours>; namespace sdbusRule = sdbusplus::bus::match::rules; +namespace fs = std::experimental::filesystem; /** @class Chassis * @brief OpenBMC chassis state management implementation. @@ -49,6 +63,8 @@ class Chassis : public ChassisInherit determineInitialState(); + restorePOHCounter(); // restore POHCounter from persisted file + // We deferred this until we could get our property correct this->emit_object_added(); } @@ -59,6 +75,12 @@ class Chassis : public ChassisInherit /** @brief Set value of CurrentPowerState */ PowerState currentPowerState(PowerState value) override; + /** @brief Get value of POHCounter */ + using ChassisInherit::pOHCounter; + + /** @brief Increment POHCounter if Chassis Power state is ON */ + void startPOHCounter(); + private: /** @brief Determine initial chassis state and set internally */ void determineInitialState(); @@ -108,6 +130,63 @@ class Chassis : public ChassisInherit /** @brief Used to subscribe to dbus systemd signals **/ sdbusplus::bus::match_t systemdSignals; + + /** @brief Used to Set value of POHCounter */ + uint32_t pOHCounter(uint32_t value) override; + + /** @brief Used to restore POHCounter value from persisted file */ + void restorePOHCounter(); + + /** @brief Function required by Cereal to perform serialization. + * + * @tparam Archive - Cereal archive type (json in our case). + * @param[in] archive - reference to Cereal archive. + * @param[in] version - Class version that enables handling + * a serialized data across code levels + */ + template <class Archive> + inline void save(Archive& archive, const std::uint32_t version) const + { + archive(pOHCounter()); + } + + /** @brief Function required by Cereal to perform deserialization. + * + * @tparam Archive - Cereal archive type (json in our case). + * @param[in] archive - reference to Cereal archive. + * @param[in] version - Class version that enables handling + * a serialized data across code levels + */ + template <class Archive> + inline void load(Archive& archive, const std::uint32_t version) + { + uint32_t value; + archive(value); + pOHCounter(value); + } + + /** @brief Serialize and persist requested POH counter. + * + * @param[in] dir - pathname of file where the serialized POH counter will + * be placed. + * + * @return fs::path - pathname of persisted requested POH counter. + */ + fs::path + serialize(const fs::path& dir = fs::path(POH_COUNTER_PERSIST_PATH)); + + /** @brief Deserialze a persisted requested POH counter. + * + * @param[in] path - pathname of persisted POH counter file + * @param[in] retCounter - deserialized POH counter value + * + * @return bool - true if the deserialization was successful, false + * otherwise. + */ + bool deserialize(const fs::path& path, uint32_t& retCounter); + + /** @brief Timer */ + std::unique_ptr<phosphor::state::manager::Timer> timer; }; } // namespace manager diff --git a/chassis_state_manager_main.cpp b/chassis_state_manager_main.cpp index ce3a0d8..1870890 100644 --- a/chassis_state_manager_main.cpp +++ b/chassis_state_manager_main.cpp @@ -19,12 +19,7 @@ int main(int argc, char *argv[]) objPathInst.c_str()); bus.request_name(CHASSIS_BUSNAME); - - while (true) - { - bus.process_discard(); - bus.wait(); - } + manager.startPOHCounter(); return 0; } diff --git a/configure.ac b/configure.ac index 8c02dc8..838aaf2 100644 --- a/configure.ac +++ b/configure.ac @@ -60,6 +60,12 @@ AS_IF([test "x$HOST_STATE_PERSIST_PATH" == "x"], \ AC_DEFINE_UNQUOTED([HOST_STATE_PERSIST_PATH], ["$HOST_STATE_PERSIST_PATH"], \ [Path of file for storing requested host state.]) +AC_ARG_VAR(POH_COUNTER_PERSIST_PATH, [Path of file for storing POH counter.]) +AS_IF([test "x$POH_COUNTER_PERSIST_PATH" == "x"], \ + [POH_COUNTER_PERSIST_PATH="/var/lib/phosphor-state-manager/POHCounter"]) +AC_DEFINE_UNQUOTED([POH_COUNTER_PERSIST_PATH], ["$POH_COUNTER_PERSIST_PATH"], \ + [Path of file for storing POH counter.]) + 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]) |