xref: /openbmc/phosphor-state-manager/chassis_state_manager.cpp (revision 9f38152abf80aba2f0177cb55729ff107f54947d)
1e426b589SAndrew Geissler #include "config.h"
2e426b589SAndrew Geissler 
3e426b589SAndrew Geissler #include "chassis_state_manager.hpp"
4e426b589SAndrew Geissler 
5f8ae6a02SAndrew Geissler #include "utils.hpp"
6e426b589SAndrew Geissler #include "xyz/openbmc_project/Common/error.hpp"
7e426b589SAndrew Geissler #include "xyz/openbmc_project/State/Shutdown/Power/error.hpp"
8e426b589SAndrew Geissler 
9e426b589SAndrew Geissler #include <cereal/archives/json.hpp>
109a286db2SPatrick Williams #include <org/freedesktop/UPower/Device/client.hpp>
11e426b589SAndrew Geissler #include <phosphor-logging/elog-errors.hpp>
128ffdb269SAndrew Geissler #include <phosphor-logging/lg2.hpp>
130029a5d2SAndrew Geissler #include <sdbusplus/bus.hpp>
1409568ff7SWilliam A. Kennington III #include <sdbusplus/exception.hpp>
15d998f82bSWilliam A. Kennington III #include <sdeventplus/event.hpp>
16d998f82bSWilliam A. Kennington III #include <sdeventplus/exception.hpp>
179a286db2SPatrick Williams #include <xyz/openbmc_project/ObjectMapper/client.hpp>
18765446aeSAndrew Geissler #include <xyz/openbmc_project/State/Chassis/error.hpp>
19396ed8a5SAdriana Kobylak #include <xyz/openbmc_project/State/Decorator/PowerSystemInputs/server.hpp>
20e426b589SAndrew Geissler 
21f2b22e8eSAndrew Geissler #include <filesystem>
2278c066f6SPatrick Williams #include <format>
23e426b589SAndrew Geissler #include <fstream>
24cb781fe1SNagaraju Goruganti 
25a90a31a9SAndrew Geissler namespace phosphor
26a90a31a9SAndrew Geissler {
27a90a31a9SAndrew Geissler namespace state
28a90a31a9SAndrew Geissler {
29a90a31a9SAndrew Geissler namespace manager
30a90a31a9SAndrew Geissler {
31a90a31a9SAndrew Geissler 
328ffdb269SAndrew Geissler PHOSPHOR_LOG2_USING;
338ffdb269SAndrew Geissler 
34a90a31a9SAndrew Geissler // When you see server:: you know we're referencing our base class
357e969cb9SPatrick Williams namespace server = sdbusplus::server::xyz::openbmc_project::state;
36396ed8a5SAdriana Kobylak namespace decoratorServer =
377e969cb9SPatrick Williams     sdbusplus::server::xyz::openbmc_project::state::decorator;
38a90a31a9SAndrew Geissler 
399a286db2SPatrick Williams using ObjectMapper = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>;
409a286db2SPatrick Williams using UPowerDevice = sdbusplus::client::org::freedesktop::u_power::Device<>;
419a286db2SPatrick Williams 
42a90a31a9SAndrew Geissler using namespace phosphor::logging;
43d998f82bSWilliam A. Kennington III using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
4427115aecSAatir Manzur using sdbusplus::xyz::openbmc_project::State::Shutdown::Power::Error::Blackout;
452c36e5adSBen Tyner using sdbusplus::xyz::openbmc_project::State::Shutdown::Power::Error::Regulator;
4670f36d8eSPotin Lai constexpr auto CHASSIS_STATE_POWEROFF_TGT_FMT =
4770f36d8eSPotin Lai     "obmc-chassis-poweroff@{}.target";
4870f36d8eSPotin Lai constexpr auto CHASSIS_STATE_HARD_POWEROFF_TGT_FMT =
4970f36d8eSPotin Lai     "obmc-chassis-hard-poweroff@{}.target";
5070f36d8eSPotin Lai constexpr auto CHASSIS_STATE_POWERON_TGT_FMT = "obmc-chassis-poweron@{}.target";
517e0e4e92SCorey_Hardesty constexpr auto CHASSIS_BLACKOUT_TGT_FMT = "obmc-chassis-blackout@{}.target";
520688132aSDelphineCCChiu constexpr auto CHASSIS_STATE_POWERCYCLE_TGT_FMT =
530688132aSDelphineCCChiu     "obmc-chassis-powercycle@{}.target";
5477a91831SAndrew Geissler constexpr auto AUTO_POWER_RESTORE_SVC_FMT =
5577a91831SAndrew Geissler     "phosphor-discover-system-state@{}.service";
56697474c5SJosh D. King constexpr auto ACTIVE_STATE = "active";
57697474c5SJosh D. King constexpr auto ACTIVATING_STATE = "activating";
58697474c5SJosh D. King 
592cf2a268SAndrew Geissler // Details at https://upower.freedesktop.org/docs/Device.html
602cf2a268SAndrew Geissler constexpr uint TYPE_UPS = 3;
612cf2a268SAndrew Geissler constexpr uint STATE_FULLY_CHARGED = 4;
622cf2a268SAndrew Geissler constexpr uint BATTERY_LVL_FULL = 8;
632cf2a268SAndrew Geissler 
64ce80f24cSAndrew Geissler constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
65ce80f24cSAndrew Geissler constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
66ce80f24cSAndrew Geissler constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
67ce80f24cSAndrew Geissler 
68697474c5SJosh D. King constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
69697474c5SJosh D. King constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
70697474c5SJosh D. King 
718b1f8620SAndrew Geissler constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
728b1f8620SAndrew Geissler 
createSystemdTargetTable()7370f36d8eSPotin Lai void Chassis::createSystemdTargetTable()
7470f36d8eSPotin Lai {
7570f36d8eSPotin Lai     systemdTargetTable = {
7670f36d8eSPotin Lai         // Use the hard off target to ensure we shutdown immediately
7778c066f6SPatrick Williams         {Transition::Off, std::format(CHASSIS_STATE_HARD_POWEROFF_TGT_FMT, id)},
7878c066f6SPatrick Williams         {Transition::On, std::format(CHASSIS_STATE_POWERON_TGT_FMT, id)},
790688132aSDelphineCCChiu         {Transition::PowerCycle,
8078c066f6SPatrick Williams          std::format(CHASSIS_STATE_POWERCYCLE_TGT_FMT, id)}};
8170f36d8eSPotin Lai }
8270f36d8eSPotin Lai 
83dff50ed6SAndrew Geissler // TODO - Will be rewritten once sdbusplus client bindings are in place
84dff50ed6SAndrew Geissler //        and persistent storage design is in place and sdbusplus
85dff50ed6SAndrew Geissler //        has read property function
determineInitialState()86dff50ed6SAndrew Geissler void Chassis::determineInitialState()
87dff50ed6SAndrew Geissler {
882cf2a268SAndrew Geissler     // Monitor for any properties changed signals on UPower device path
892cf2a268SAndrew Geissler     uPowerPropChangeSignal = std::make_unique<sdbusplus::bus::match_t>(
902cf2a268SAndrew Geissler         bus,
912cf2a268SAndrew Geissler         sdbusplus::bus::match::rules::propertiesChangedNamespace(
929a286db2SPatrick Williams             "/org/freedesktop/UPower", UPowerDevice::interface),
932cf2a268SAndrew Geissler         [this](auto& msg) { this->uPowerChangeEvent(msg); });
942cf2a268SAndrew Geissler 
95396ed8a5SAdriana Kobylak     // Monitor for any properties changed signals on PowerSystemInputs
96396ed8a5SAdriana Kobylak     powerSysInputsPropChangeSignal = std::make_unique<sdbusplus::bus::match_t>(
97396ed8a5SAdriana Kobylak         bus,
98396ed8a5SAdriana Kobylak         sdbusplus::bus::match::rules::propertiesChangedNamespace(
9978c066f6SPatrick Williams             std::format(
100396ed8a5SAdriana Kobylak                 "/xyz/openbmc_project/power/power_supplies/chassis{}/psus", id),
1019a286db2SPatrick Williams             decoratorServer::PowerSystemInputs::interface),
102396ed8a5SAdriana Kobylak         [this](auto& msg) { this->powerSysInputsChangeEvent(msg); });
103396ed8a5SAdriana Kobylak 
1048b1f8620SAndrew Geissler     determineStatusOfPower();
1058b1f8620SAndrew Geissler 
1062975e26fSPatrick Williams     std::variant<int> pgood = -1;
10758a18013SAndrew Geissler     auto method = this->bus.new_method_call(
10858a18013SAndrew Geissler         "org.openbmc.control.Power", "/org/openbmc/control/power0",
10958a18013SAndrew Geissler         "org.freedesktop.DBus.Properties", "Get");
110dff50ed6SAndrew Geissler 
111dff50ed6SAndrew Geissler     method.append("org.openbmc.control.Power", "pgood");
1129a2f37cfSWilliam A. Kennington III     try
1139a2f37cfSWilliam A. Kennington III     {
114dff50ed6SAndrew Geissler         auto reply = this->bus.call(method);
115dff50ed6SAndrew Geissler         reply.read(pgood);
116dff50ed6SAndrew Geissler 
11737413dcbSPatrick Williams         if (std::get<int>(pgood) == 1)
118dff50ed6SAndrew Geissler         {
1198ffdb269SAndrew Geissler             info("Initial Chassis State will be On");
120dff50ed6SAndrew Geissler             server::Chassis::currentPowerState(PowerState::On);
121dff50ed6SAndrew Geissler             server::Chassis::requestedPowerTransition(Transition::On);
12209568ff7SWilliam A. Kennington III             return;
123dff50ed6SAndrew Geissler         }
1249eab9861SMatt Spinler         else
1259eab9861SMatt Spinler         {
1269eab9861SMatt Spinler             // The system is off.  If we think it should be on then
1279eab9861SMatt Spinler             // we probably lost AC while up, so set a new state
1289eab9861SMatt Spinler             // change time.
1299eab9861SMatt Spinler             uint64_t lastTime;
1309eab9861SMatt Spinler             PowerState lastState;
1319eab9861SMatt Spinler 
1329eab9861SMatt Spinler             if (deserializeStateChangeTime(lastTime, lastState))
1339eab9861SMatt Spinler             {
1347ed36236SAndrew Geissler                 // If power was on before the BMC reboot and the reboot reason
1357ed36236SAndrew Geissler                 // was not a pinhole reset, log an error
1369eab9861SMatt Spinler                 if (lastState == PowerState::On)
1379eab9861SMatt Spinler                 {
1387ed36236SAndrew Geissler                     info(
1397ed36236SAndrew Geissler                         "Chassis power was on before the BMC reboot and it is off now");
140be6efabcSMatthew Barth 
141be6efabcSMatthew Barth                     // Reset host sensors since system is off now
1427e0e4e92SCorey_Hardesty                     // Ensure Power Leds are off.
14378c066f6SPatrick Williams                     startUnit(std::format(CHASSIS_BLACKOUT_TGT_FMT, id));
144be6efabcSMatthew Barth 
1457ed36236SAndrew Geissler                     setStateChangeTime();
146bcbee4a2SNodeMan97                     // Generate file indicating AC loss occurred
147bcbee4a2SNodeMan97                     std::string chassisLostPowerFileFmt =
14878c066f6SPatrick Williams                         std::format(CHASSIS_LOST_POWER_FILE, id);
149bcbee4a2SNodeMan97                     fs::create_directories(BASE_FILE_DIR);
150bcbee4a2SNodeMan97                     fs::path chassisPowerLossFile{chassisLostPowerFileFmt};
151bcbee4a2SNodeMan97                     std::ofstream outfile(chassisPowerLossFile);
152bcbee4a2SNodeMan97                     outfile.close();
1537ed36236SAndrew Geissler 
1544fe860f5SBrandon Wyman                     // 0 indicates pinhole reset. 1 is NOT pinhole reset
1557ed36236SAndrew Geissler                     if (phosphor::state::manager::utils::getGpioValue(
1564fe860f5SBrandon Wyman                             "reset-cause-pinhole") != 0)
1577ed36236SAndrew Geissler                     {
1582c36e5adSBen Tyner                         if (standbyVoltageRegulatorFault())
1592c36e5adSBen Tyner                         {
1602c36e5adSBen Tyner                             report<Regulator>();
1612c36e5adSBen Tyner                         }
1622c36e5adSBen Tyner                         else
1632c36e5adSBen Tyner                         {
164073fa2b3SMike Capps                             report<Blackout>(Entry::Level::Critical);
1652c36e5adSBen Tyner                         }
1667ed36236SAndrew Geissler                     }
1674fe860f5SBrandon Wyman                     else
1684fe860f5SBrandon Wyman                     {
1694fe860f5SBrandon Wyman                         info("Pinhole reset");
1704fe860f5SBrandon Wyman                     }
1719eab9861SMatt Spinler                 }
1729eab9861SMatt Spinler             }
1739eab9861SMatt Spinler         }
1749a2f37cfSWilliam A. Kennington III     }
175f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
1769a2f37cfSWilliam A. Kennington III     {
1779a2f37cfSWilliam A. Kennington III         // It's acceptable for the pgood state service to not be available
1789a2f37cfSWilliam A. Kennington III         // since it will notify us of the pgood state when it comes up.
1799a2f37cfSWilliam A. Kennington III         if (e.name() != nullptr &&
1809a2f37cfSWilliam A. Kennington III             strcmp("org.freedesktop.DBus.Error.ServiceUnknown", e.name()) == 0)
1819a2f37cfSWilliam A. Kennington III         {
1829a2f37cfSWilliam A. Kennington III             goto fail;
1839a2f37cfSWilliam A. Kennington III         }
1849a2f37cfSWilliam A. Kennington III 
1859a2f37cfSWilliam A. Kennington III         // Only log for unexpected error types.
1868ffdb269SAndrew Geissler         error("Error performing call to get pgood: {ERROR}", "ERROR", e);
1879a2f37cfSWilliam A. Kennington III         goto fail;
1889a2f37cfSWilliam A. Kennington III     }
18909568ff7SWilliam A. Kennington III 
19009568ff7SWilliam A. Kennington III fail:
1918ffdb269SAndrew Geissler     info("Initial Chassis State will be Off");
192dff50ed6SAndrew Geissler     server::Chassis::currentPowerState(PowerState::Off);
193dff50ed6SAndrew Geissler     server::Chassis::requestedPowerTransition(Transition::Off);
194dff50ed6SAndrew Geissler 
195dff50ed6SAndrew Geissler     return;
196dff50ed6SAndrew Geissler }
197dff50ed6SAndrew Geissler 
determineStatusOfPower()1988b1f8620SAndrew Geissler void Chassis::determineStatusOfPower()
1998b1f8620SAndrew Geissler {
20077a91831SAndrew Geissler     auto initialPowerStatus = server::Chassis::currentPowerStatus();
20177a91831SAndrew Geissler 
20266aacdc4SAndrew Geissler     bool powerGood = determineStatusOfUPSPower();
20366aacdc4SAndrew Geissler     if (!powerGood)
204396ed8a5SAdriana Kobylak     {
205396ed8a5SAdriana Kobylak         return;
206396ed8a5SAdriana Kobylak     }
207396ed8a5SAdriana Kobylak 
20866aacdc4SAndrew Geissler     powerGood = determineStatusOfPSUPower();
20966aacdc4SAndrew Geissler     if (powerGood)
21066aacdc4SAndrew Geissler     {
21166aacdc4SAndrew Geissler         // All checks passed, set power status to good
21266aacdc4SAndrew Geissler         server::Chassis::currentPowerStatus(PowerStatus::Good);
21377a91831SAndrew Geissler 
21477a91831SAndrew Geissler         // If power status transitioned from bad to good and chassis power is
21577a91831SAndrew Geissler         // off then call Auto Power Restart to see if the system should auto
21677a91831SAndrew Geissler         // power on now that power status is good
21777a91831SAndrew Geissler         if ((initialPowerStatus != PowerStatus::Good) &&
21877a91831SAndrew Geissler             (server::Chassis::currentPowerState() == PowerState::Off))
21977a91831SAndrew Geissler         {
22077a91831SAndrew Geissler             info("power status transitioned from {START_PWR_STATE} to Good and "
22177a91831SAndrew Geissler                  "chassis power is off, calling APR",
22277a91831SAndrew Geissler                  "START_PWR_STATE", initialPowerStatus);
22378c066f6SPatrick Williams             restartUnit(std::format(AUTO_POWER_RESTORE_SVC_FMT, this->id));
22477a91831SAndrew Geissler         }
22566aacdc4SAndrew Geissler     }
226396ed8a5SAdriana Kobylak }
227396ed8a5SAdriana Kobylak 
determineStatusOfUPSPower()22866aacdc4SAndrew Geissler bool Chassis::determineStatusOfUPSPower()
229396ed8a5SAdriana Kobylak {
2308b1f8620SAndrew Geissler     // Find all implementations of the UPower interface
2319a286db2SPatrick Williams     auto mapper = bus.new_method_call(ObjectMapper::default_service,
2329a286db2SPatrick Williams                                       ObjectMapper::instance_path,
2339a286db2SPatrick Williams                                       ObjectMapper::interface, "GetSubTree");
2348b1f8620SAndrew Geissler 
2359a286db2SPatrick Williams     mapper.append("/", 0, std::vector<std::string>({UPowerDevice::interface}));
2368b1f8620SAndrew Geissler 
2378b1f8620SAndrew Geissler     std::map<std::string, std::map<std::string, std::vector<std::string>>>
2388b1f8620SAndrew Geissler         mapperResponse;
2398b1f8620SAndrew Geissler 
2408b1f8620SAndrew Geissler     try
2418b1f8620SAndrew Geissler     {
2428b1f8620SAndrew Geissler         auto mapperResponseMsg = bus.call(mapper);
2438b1f8620SAndrew Geissler         mapperResponseMsg.read(mapperResponse);
2448b1f8620SAndrew Geissler     }
245f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
2468b1f8620SAndrew Geissler     {
2478b1f8620SAndrew Geissler         error("Error in mapper GetSubTree call for UPS: {ERROR}", "ERROR", e);
2488b1f8620SAndrew Geissler         throw;
2498b1f8620SAndrew Geissler     }
2508b1f8620SAndrew Geissler 
2518b1f8620SAndrew Geissler     if (mapperResponse.empty())
2528b1f8620SAndrew Geissler     {
2538b1f8620SAndrew Geissler         debug("No UPower devices found in system");
2548b1f8620SAndrew Geissler     }
2558b1f8620SAndrew Geissler 
2568b1f8620SAndrew Geissler     // Iterate through all returned Upower interfaces and look for UPS's
2578b1f8620SAndrew Geissler     for (const auto& [path, services] : mapperResponse)
2588b1f8620SAndrew Geissler     {
2598b1f8620SAndrew Geissler         for (const auto& serviceIter : services)
2608b1f8620SAndrew Geissler         {
2618b1f8620SAndrew Geissler             const std::string& service = serviceIter.first;
2628b1f8620SAndrew Geissler 
2638b1f8620SAndrew Geissler             try
2648b1f8620SAndrew Geissler             {
2658b1f8620SAndrew Geissler                 auto method = bus.new_method_call(service.c_str(), path.c_str(),
2668b1f8620SAndrew Geissler                                                   PROPERTY_INTERFACE, "GetAll");
2679a286db2SPatrick Williams                 method.append(UPowerDevice::interface);
2688b1f8620SAndrew Geissler 
2698b1f8620SAndrew Geissler                 auto response = bus.call(method);
2708b1f8620SAndrew Geissler                 using Property = std::string;
2718b1f8620SAndrew Geissler                 using Value = std::variant<bool, uint>;
2728b1f8620SAndrew Geissler                 using PropertyMap = std::map<Property, Value>;
2738b1f8620SAndrew Geissler                 PropertyMap properties;
2748b1f8620SAndrew Geissler                 response.read(properties);
2758b1f8620SAndrew Geissler 
2768b1f8620SAndrew Geissler                 if (std::get<uint>(properties["Type"]) != TYPE_UPS)
2778b1f8620SAndrew Geissler                 {
2788b1f8620SAndrew Geissler                     info("UPower device {OBJ_PATH} is not a UPS device",
2798b1f8620SAndrew Geissler                          "OBJ_PATH", path);
2808b1f8620SAndrew Geissler                     continue;
2818b1f8620SAndrew Geissler                 }
2828b1f8620SAndrew Geissler 
28344bbf11dSPavithra Barithaya                 if (!std::get<bool>(properties["IsPresent"]))
2842cf2a268SAndrew Geissler                 {
2852cf2a268SAndrew Geissler                     // There is a UPS detected but it is not officially
2862cf2a268SAndrew Geissler                     // "present" yet. Monitor it for state change.
2872cf2a268SAndrew Geissler                     info("UPower device {OBJ_PATH} is not present", "OBJ_PATH",
2882cf2a268SAndrew Geissler                          path);
2892cf2a268SAndrew Geissler                     continue;
2902cf2a268SAndrew Geissler                 }
2912cf2a268SAndrew Geissler 
2928b1f8620SAndrew Geissler                 if (std::get<uint>(properties["State"]) == STATE_FULLY_CHARGED)
2938b1f8620SAndrew Geissler                 {
2948b1f8620SAndrew Geissler                     info("UPS is fully charged");
2958b1f8620SAndrew Geissler                 }
2968b1f8620SAndrew Geissler                 else
2978b1f8620SAndrew Geissler                 {
2988b1f8620SAndrew Geissler                     info("UPS is not fully charged: {UPS_STATE}", "UPS_STATE",
2998b1f8620SAndrew Geissler                          std::get<uint>(properties["State"]));
3008b1f8620SAndrew Geissler                     server::Chassis::currentPowerStatus(
3018b1f8620SAndrew Geissler                         PowerStatus::UninterruptiblePowerSupply);
30266aacdc4SAndrew Geissler                     return false;
3038b1f8620SAndrew Geissler                 }
3048b1f8620SAndrew Geissler 
3058b1f8620SAndrew Geissler                 if (std::get<uint>(properties["BatteryLevel"]) ==
3068b1f8620SAndrew Geissler                     BATTERY_LVL_FULL)
3078b1f8620SAndrew Geissler                 {
3088b1f8620SAndrew Geissler                     info("UPS Battery Level is Full");
3092cf2a268SAndrew Geissler                     // Only one UPS per system, we've found it and it's all
3102cf2a268SAndrew Geissler                     // good so exit function
31166aacdc4SAndrew Geissler                     return true;
3128b1f8620SAndrew Geissler                 }
3138b1f8620SAndrew Geissler                 else
3148b1f8620SAndrew Geissler                 {
3158b1f8620SAndrew Geissler                     info("UPS Battery Level is Low: {UPS_BAT_LEVEL}",
3168b1f8620SAndrew Geissler                          "UPS_BAT_LEVEL",
3178b1f8620SAndrew Geissler                          std::get<uint>(properties["BatteryLevel"]));
3188b1f8620SAndrew Geissler                     server::Chassis::currentPowerStatus(
3198b1f8620SAndrew Geissler                         PowerStatus::UninterruptiblePowerSupply);
32066aacdc4SAndrew Geissler                     return false;
3218b1f8620SAndrew Geissler                 }
3228b1f8620SAndrew Geissler             }
323f053e6feSPatrick Williams             catch (const sdbusplus::exception_t& e)
3248b1f8620SAndrew Geissler             {
3258b1f8620SAndrew Geissler                 error("Error reading UPS property, error: {ERROR}, "
3268b1f8620SAndrew Geissler                       "service: {SERVICE} path: {PATH}",
3278b1f8620SAndrew Geissler                       "ERROR", e, "SERVICE", service, "PATH", path);
3288b1f8620SAndrew Geissler                 throw;
3298b1f8620SAndrew Geissler             }
3308b1f8620SAndrew Geissler         }
3318b1f8620SAndrew Geissler     }
33266aacdc4SAndrew Geissler     return true;
3338b1f8620SAndrew Geissler }
3348b1f8620SAndrew Geissler 
determineStatusOfPSUPower()33566aacdc4SAndrew Geissler bool Chassis::determineStatusOfPSUPower()
336396ed8a5SAdriana Kobylak {
337396ed8a5SAdriana Kobylak     // Find all implementations of the PowerSystemInputs interface
3389a286db2SPatrick Williams     auto mapper = bus.new_method_call(ObjectMapper::default_service,
3399a286db2SPatrick Williams                                       ObjectMapper::instance_path,
3409a286db2SPatrick Williams                                       ObjectMapper::interface, "GetSubTree");
341396ed8a5SAdriana Kobylak 
3429a286db2SPatrick Williams     mapper.append("/", 0,
3439a286db2SPatrick Williams                   std::vector<std::string>(
3449a286db2SPatrick Williams                       {decoratorServer::PowerSystemInputs::interface}));
345396ed8a5SAdriana Kobylak 
346396ed8a5SAdriana Kobylak     std::map<std::string, std::map<std::string, std::vector<std::string>>>
347396ed8a5SAdriana Kobylak         mapperResponse;
348396ed8a5SAdriana Kobylak 
349396ed8a5SAdriana Kobylak     try
350396ed8a5SAdriana Kobylak     {
351396ed8a5SAdriana Kobylak         auto mapperResponseMsg = bus.call(mapper);
352396ed8a5SAdriana Kobylak         mapperResponseMsg.read(mapperResponse);
353396ed8a5SAdriana Kobylak     }
354f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
355396ed8a5SAdriana Kobylak     {
356396ed8a5SAdriana Kobylak         error("Error in mapper GetSubTree call for PowerSystemInputs: {ERROR}",
357396ed8a5SAdriana Kobylak               "ERROR", e);
358396ed8a5SAdriana Kobylak         throw;
359396ed8a5SAdriana Kobylak     }
360396ed8a5SAdriana Kobylak 
361396ed8a5SAdriana Kobylak     for (const auto& [path, services] : mapperResponse)
362396ed8a5SAdriana Kobylak     {
363396ed8a5SAdriana Kobylak         for (const auto& serviceIter : services)
364396ed8a5SAdriana Kobylak         {
365396ed8a5SAdriana Kobylak             const std::string& service = serviceIter.first;
366396ed8a5SAdriana Kobylak 
367396ed8a5SAdriana Kobylak             try
368396ed8a5SAdriana Kobylak             {
369396ed8a5SAdriana Kobylak                 auto method = bus.new_method_call(service.c_str(), path.c_str(),
370396ed8a5SAdriana Kobylak                                                   PROPERTY_INTERFACE, "GetAll");
3719a286db2SPatrick Williams                 method.append(decoratorServer::PowerSystemInputs::interface);
372396ed8a5SAdriana Kobylak 
373396ed8a5SAdriana Kobylak                 auto response = bus.call(method);
374396ed8a5SAdriana Kobylak                 using Property = std::string;
375396ed8a5SAdriana Kobylak                 using Value = std::variant<std::string>;
376396ed8a5SAdriana Kobylak                 using PropertyMap = std::map<Property, Value>;
377396ed8a5SAdriana Kobylak                 PropertyMap properties;
378396ed8a5SAdriana Kobylak                 response.read(properties);
379396ed8a5SAdriana Kobylak 
380396ed8a5SAdriana Kobylak                 auto statusStr = std::get<std::string>(properties["Status"]);
381396ed8a5SAdriana Kobylak                 auto status =
382396ed8a5SAdriana Kobylak                     decoratorServer::PowerSystemInputs::convertStatusFromString(
383396ed8a5SAdriana Kobylak                         statusStr);
384396ed8a5SAdriana Kobylak 
385396ed8a5SAdriana Kobylak                 if (status == decoratorServer::PowerSystemInputs::Status::Fault)
386396ed8a5SAdriana Kobylak                 {
387396ed8a5SAdriana Kobylak                     info("Power System Inputs status is in Fault state");
388396ed8a5SAdriana Kobylak                     server::Chassis::currentPowerStatus(PowerStatus::BrownOut);
38966aacdc4SAndrew Geissler                     return false;
390396ed8a5SAdriana Kobylak                 }
391396ed8a5SAdriana Kobylak             }
392f053e6feSPatrick Williams             catch (const sdbusplus::exception_t& e)
393396ed8a5SAdriana Kobylak             {
394396ed8a5SAdriana Kobylak                 error(
395396ed8a5SAdriana Kobylak                     "Error reading Power System Inputs property, error: {ERROR}, "
396396ed8a5SAdriana Kobylak                     "service: {SERVICE} path: {PATH}",
397396ed8a5SAdriana Kobylak                     "ERROR", e, "SERVICE", service, "PATH", path);
398396ed8a5SAdriana Kobylak                 throw;
399396ed8a5SAdriana Kobylak             }
400396ed8a5SAdriana Kobylak         }
401396ed8a5SAdriana Kobylak     }
40266aacdc4SAndrew Geissler     return true;
403396ed8a5SAdriana Kobylak }
404396ed8a5SAdriana Kobylak 
uPowerChangeEvent(sdbusplus::message_t & msg)405f053e6feSPatrick Williams void Chassis::uPowerChangeEvent(sdbusplus::message_t& msg)
4062cf2a268SAndrew Geissler {
4072cf2a268SAndrew Geissler     debug("UPS Property Change Event Triggered");
4082cf2a268SAndrew Geissler     std::string statusInterface;
4092cf2a268SAndrew Geissler     std::map<std::string, std::variant<uint, bool>> msgData;
4102cf2a268SAndrew Geissler     msg.read(statusInterface, msgData);
4112cf2a268SAndrew Geissler 
412396ed8a5SAdriana Kobylak     // If the change is to any of the properties we are interested in, then call
413396ed8a5SAdriana Kobylak     // determineStatusOfPower(), which looks at all the power-related
414396ed8a5SAdriana Kobylak     // interfaces, to see if a power status change is needed
4152cf2a268SAndrew Geissler     auto propertyMap = msgData.find("IsPresent");
4162cf2a268SAndrew Geissler     if (propertyMap != msgData.end())
4172cf2a268SAndrew Geissler     {
4182cf2a268SAndrew Geissler         info("UPS presence changed to {UPS_PRES_INFO}", "UPS_PRES_INFO",
4192cf2a268SAndrew Geissler              std::get<bool>(propertyMap->second));
4202cf2a268SAndrew Geissler         determineStatusOfPower();
4212cf2a268SAndrew Geissler         return;
4222cf2a268SAndrew Geissler     }
4232cf2a268SAndrew Geissler 
4242cf2a268SAndrew Geissler     propertyMap = msgData.find("State");
4252cf2a268SAndrew Geissler     if (propertyMap != msgData.end())
4262cf2a268SAndrew Geissler     {
4272cf2a268SAndrew Geissler         info("UPS State changed to {UPS_STATE}", "UPS_STATE",
4282cf2a268SAndrew Geissler              std::get<uint>(propertyMap->second));
4292cf2a268SAndrew Geissler         determineStatusOfPower();
4302cf2a268SAndrew Geissler         return;
4312cf2a268SAndrew Geissler     }
4322cf2a268SAndrew Geissler 
4332cf2a268SAndrew Geissler     propertyMap = msgData.find("BatteryLevel");
4342cf2a268SAndrew Geissler     if (propertyMap != msgData.end())
4352cf2a268SAndrew Geissler     {
4362cf2a268SAndrew Geissler         info("UPS BatteryLevel changed to {UPS_BAT_LEVEL}", "UPS_BAT_LEVEL",
4372cf2a268SAndrew Geissler              std::get<uint>(propertyMap->second));
4382cf2a268SAndrew Geissler         determineStatusOfPower();
4392cf2a268SAndrew Geissler         return;
4402cf2a268SAndrew Geissler     }
4412cf2a268SAndrew Geissler     return;
4422cf2a268SAndrew Geissler }
4432cf2a268SAndrew Geissler 
powerSysInputsChangeEvent(sdbusplus::message_t & msg)444f053e6feSPatrick Williams void Chassis::powerSysInputsChangeEvent(sdbusplus::message_t& msg)
445396ed8a5SAdriana Kobylak {
446396ed8a5SAdriana Kobylak     debug("Power System Inputs Property Change Event Triggered");
447396ed8a5SAdriana Kobylak     std::string statusInterface;
448396ed8a5SAdriana Kobylak     std::map<std::string, std::variant<std::string>> msgData;
449396ed8a5SAdriana Kobylak     msg.read(statusInterface, msgData);
450396ed8a5SAdriana Kobylak 
451396ed8a5SAdriana Kobylak     // If the change is to any of the properties we are interested in, then call
452396ed8a5SAdriana Kobylak     // determineStatusOfPower(), which looks at all the power-related
453396ed8a5SAdriana Kobylak     // interfaces, to see if a power status change is needed
454396ed8a5SAdriana Kobylak     auto propertyMap = msgData.find("Status");
455396ed8a5SAdriana Kobylak     if (propertyMap != msgData.end())
456396ed8a5SAdriana Kobylak     {
457396ed8a5SAdriana Kobylak         info("Power System Inputs status changed to {POWER_SYS_INPUT_STATUS}",
458396ed8a5SAdriana Kobylak              "POWER_SYS_INPUT_STATUS",
459396ed8a5SAdriana Kobylak              std::get<std::string>(propertyMap->second));
460396ed8a5SAdriana Kobylak         determineStatusOfPower();
461396ed8a5SAdriana Kobylak         return;
462396ed8a5SAdriana Kobylak     }
463396ed8a5SAdriana Kobylak     return;
464396ed8a5SAdriana Kobylak }
465396ed8a5SAdriana Kobylak 
startUnit(const std::string & sysdUnit)466be6efabcSMatthew Barth void Chassis::startUnit(const std::string& sysdUnit)
467ce80f24cSAndrew Geissler {
46858a18013SAndrew Geissler     auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
46958a18013SAndrew Geissler                                             SYSTEMD_INTERFACE, "StartUnit");
470ce80f24cSAndrew Geissler 
471be6efabcSMatthew Barth     method.append(sysdUnit);
472ce80f24cSAndrew Geissler     method.append("replace");
473ce80f24cSAndrew Geissler 
474ce80f24cSAndrew Geissler     this->bus.call_noreply(method);
475ce80f24cSAndrew Geissler 
476ce80f24cSAndrew Geissler     return;
477ce80f24cSAndrew Geissler }
478ce80f24cSAndrew Geissler 
restartUnit(const std::string & sysdUnit)47977a91831SAndrew Geissler void Chassis::restartUnit(const std::string& sysdUnit)
48077a91831SAndrew Geissler {
48177a91831SAndrew Geissler     auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
48277a91831SAndrew Geissler                                             SYSTEMD_INTERFACE, "RestartUnit");
48377a91831SAndrew Geissler 
48477a91831SAndrew Geissler     method.append(sysdUnit);
48577a91831SAndrew Geissler     method.append("replace");
48677a91831SAndrew Geissler 
48777a91831SAndrew Geissler     this->bus.call_noreply(method);
48877a91831SAndrew Geissler 
48977a91831SAndrew Geissler     return;
49077a91831SAndrew Geissler }
49177a91831SAndrew Geissler 
stateActive(const std::string & target)492697474c5SJosh D. King bool Chassis::stateActive(const std::string& target)
493697474c5SJosh D. King {
4942975e26fSPatrick Williams     std::variant<std::string> currentState;
495697474c5SJosh D. King     sdbusplus::message::object_path unitTargetPath;
496697474c5SJosh D. King 
49758a18013SAndrew Geissler     auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
49858a18013SAndrew Geissler                                             SYSTEMD_INTERFACE, "GetUnit");
499697474c5SJosh D. King 
500697474c5SJosh D. King     method.append(target);
501697474c5SJosh D. King 
50209568ff7SWilliam A. Kennington III     try
50309568ff7SWilliam A. Kennington III     {
50432c532eaSAnthony Wilson         auto result = this->bus.call(method);
505697474c5SJosh D. King         result.read(unitTargetPath);
50609568ff7SWilliam A. Kennington III     }
507f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
50809568ff7SWilliam A. Kennington III     {
5098ffdb269SAndrew Geissler         error("Error in GetUnit call: {ERROR}", "ERROR", e);
51009568ff7SWilliam A. Kennington III         return false;
51109568ff7SWilliam A. Kennington III     }
512697474c5SJosh D. King 
51358a18013SAndrew Geissler     method = this->bus.new_method_call(
51458a18013SAndrew Geissler         SYSTEMD_SERVICE,
51558a18013SAndrew Geissler         static_cast<const std::string&>(unitTargetPath).c_str(),
51658a18013SAndrew Geissler         SYSTEMD_PROPERTY_IFACE, "Get");
517697474c5SJosh D. King 
518697474c5SJosh D. King     method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
519697474c5SJosh D. King 
52032c532eaSAnthony Wilson     try
521697474c5SJosh D. King     {
52232c532eaSAnthony Wilson         auto result = this->bus.call(method);
52332c532eaSAnthony Wilson         result.read(currentState);
52432c532eaSAnthony Wilson     }
525f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
52632c532eaSAnthony Wilson     {
5278ffdb269SAndrew Geissler         error("Error in ActiveState Get: {ERROR}", "ERROR", e);
528697474c5SJosh D. King         return false;
529697474c5SJosh D. King     }
530697474c5SJosh D. King 
53137413dcbSPatrick Williams     const auto& currentStateStr = std::get<std::string>(currentState);
5327a0689a9SWilliam A. Kennington III     return currentStateStr == ACTIVE_STATE ||
5337a0689a9SWilliam A. Kennington III            currentStateStr == ACTIVATING_STATE;
534697474c5SJosh D. King }
535697474c5SJosh D. King 
sysStateChange(sdbusplus::message_t & msg)536f053e6feSPatrick Williams int Chassis::sysStateChange(sdbusplus::message_t& msg)
5370029a5d2SAndrew Geissler {
5380029a5d2SAndrew Geissler     sdbusplus::message::object_path newStateObjPath;
5390029a5d2SAndrew Geissler     std::string newStateUnit{};
5400029a5d2SAndrew Geissler     std::string newStateResult{};
5410029a5d2SAndrew Geissler 
5420029a5d2SAndrew Geissler     // Read the msg and populate each variable
54309568ff7SWilliam A. Kennington III     try
54409568ff7SWilliam A. Kennington III     {
5459b8af4f2SAndrew Geissler         // newStateID is a throwaway that is needed in order to read the
5469b8af4f2SAndrew Geissler         // parameters that are useful out of the dbus message
5479b8af4f2SAndrew Geissler         uint32_t newStateID{};
5488f8ba39fSPatrick Williams         msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
54909568ff7SWilliam A. Kennington III     }
550f053e6feSPatrick Williams     catch (const sdbusplus::exception_t& e)
55109568ff7SWilliam A. Kennington III     {
5528ffdb269SAndrew Geissler         error("Error in state change - bad encoding: {ERROR} {REPLY_SIG}",
5538ffdb269SAndrew Geissler               "ERROR", e, "REPLY_SIG", msg.get_signature());
55409568ff7SWilliam A. Kennington III         return 0;
55509568ff7SWilliam A. Kennington III     }
5560029a5d2SAndrew Geissler 
55778c066f6SPatrick Williams     if ((newStateUnit == std::format(CHASSIS_STATE_POWEROFF_TGT_FMT, id)) &&
55870f36d8eSPotin Lai         (newStateResult == "done") &&
55970f36d8eSPotin Lai         (!stateActive(systemdTargetTable[Transition::On])))
5600029a5d2SAndrew Geissler     {
5618ffdb269SAndrew Geissler         info("Received signal that power OFF is complete");
5620029a5d2SAndrew Geissler         this->currentPowerState(server::Chassis::PowerState::Off);
5639eab9861SMatt Spinler         this->setStateChangeTime();
5640029a5d2SAndrew Geissler     }
56570f36d8eSPotin Lai     else if ((newStateUnit == systemdTargetTable[Transition::On]) &&
566697474c5SJosh D. King              (newStateResult == "done") &&
56770f36d8eSPotin Lai              (stateActive(systemdTargetTable[Transition::On])))
5680029a5d2SAndrew Geissler     {
5698ffdb269SAndrew Geissler         info("Received signal that power ON is complete");
5700029a5d2SAndrew Geissler         this->currentPowerState(server::Chassis::PowerState::On);
5719eab9861SMatt Spinler         this->setStateChangeTime();
572f2b22e8eSAndrew Geissler 
573f2b22e8eSAndrew Geissler         // Remove temporary file which is utilized for scenarios where the
574f2b22e8eSAndrew Geissler         // BMC is rebooted while the chassis power is still on.
575f2b22e8eSAndrew Geissler         // This file is used to indicate to chassis related systemd services
576f2b22e8eSAndrew Geissler         // that the chassis is already on and they should skip running.
577f2b22e8eSAndrew Geissler         // Once the chassis state is back to on we can clear this file.
57878c066f6SPatrick Williams         auto chassisFile = std::format(CHASSIS_ON_FILE, 0);
57978c066f6SPatrick Williams         if (std::filesystem::exists(chassisFile))
580f2b22e8eSAndrew Geissler         {
58178c066f6SPatrick Williams             std::filesystem::remove(chassisFile);
582f2b22e8eSAndrew Geissler         }
5830029a5d2SAndrew Geissler     }
5840029a5d2SAndrew Geissler 
5850029a5d2SAndrew Geissler     return 0;
5860029a5d2SAndrew Geissler }
5870029a5d2SAndrew Geissler 
requestedPowerTransition(Transition value)588a90a31a9SAndrew Geissler Chassis::Transition Chassis::requestedPowerTransition(Transition value)
589a90a31a9SAndrew Geissler {
5908ffdb269SAndrew Geissler     info("Change to Chassis Requested Power State: {REQ_POWER_TRAN}",
5918ffdb269SAndrew Geissler          "REQ_POWER_TRAN", value);
592765446aeSAndrew Geissler #if ONLY_ALLOW_BOOT_WHEN_BMC_READY
593765446aeSAndrew Geissler     if ((value != Transition::Off) && (!utils::isBmcReady(this->bus)))
594765446aeSAndrew Geissler     {
595765446aeSAndrew Geissler         info("BMC State is not Ready so no chassis on operations allowed");
596765446aeSAndrew Geissler         throw sdbusplus::xyz::openbmc_project::State::Chassis::Error::
597765446aeSAndrew Geissler             BMCNotReady();
598765446aeSAndrew Geissler     }
599765446aeSAndrew Geissler #endif
600*9f38152aSThang Tran 
601*9f38152aSThang Tran #ifdef CHECK_FWUPDATE_BEFORE_DO_TRANSITION
602*9f38152aSThang Tran     /*
603*9f38152aSThang Tran      * Do not do transition when the any firmware being updated
604*9f38152aSThang Tran      */
605*9f38152aSThang Tran     if ((value != Transition::Off) &&
606*9f38152aSThang Tran         (phosphor::state::manager::utils::isFirmwareUpdating(this->bus)))
607*9f38152aSThang Tran     {
608*9f38152aSThang Tran         info("Firmware being updated, reject the transition request");
609*9f38152aSThang Tran         throw sdbusplus::xyz::openbmc_project::Common::Error::Unavailable();
610*9f38152aSThang Tran     }
611*9f38152aSThang Tran #endif // CHECK_FWUPDATE_BEFORE_DO_TRANSITION
612*9f38152aSThang Tran 
61370f36d8eSPotin Lai     startUnit(systemdTargetTable.find(value)->second);
614a90a31a9SAndrew Geissler     return server::Chassis::requestedPowerTransition(value);
615a90a31a9SAndrew Geissler }
616a90a31a9SAndrew Geissler 
currentPowerState(PowerState value)617a90a31a9SAndrew Geissler Chassis::PowerState Chassis::currentPowerState(PowerState value)
618a90a31a9SAndrew Geissler {
619cb781fe1SNagaraju Goruganti     PowerState chassisPowerState;
6208ffdb269SAndrew Geissler     info("Change to Chassis Power State: {CUR_POWER_STATE}", "CUR_POWER_STATE",
6218ffdb269SAndrew Geissler          value);
622cb781fe1SNagaraju Goruganti 
623cb781fe1SNagaraju Goruganti     chassisPowerState = server::Chassis::currentPowerState(value);
6246d582a88Sshamim ali     if (chassisPowerState == PowerState::On)
6256d582a88Sshamim ali     {
6266d582a88Sshamim ali         pohTimer.resetRemaining();
6276d582a88Sshamim ali     }
628cb781fe1SNagaraju Goruganti     return chassisPowerState;
629cb781fe1SNagaraju Goruganti }
630cb781fe1SNagaraju Goruganti 
pohCounter(uint32_t value)63145a1ed71SPatrick Williams uint32_t Chassis::pohCounter(uint32_t value)
632cb781fe1SNagaraju Goruganti {
63345a1ed71SPatrick Williams     if (value != pohCounter())
634cb781fe1SNagaraju Goruganti     {
63545a1ed71SPatrick Williams         ChassisInherit::pohCounter(value);
63681957841SMatt Spinler         serializePOH();
637cb781fe1SNagaraju Goruganti     }
63845a1ed71SPatrick Williams     return pohCounter();
639cb781fe1SNagaraju Goruganti }
640cb781fe1SNagaraju Goruganti 
pohCallback()64145a1ed71SPatrick Williams void Chassis::pohCallback()
642d998f82bSWilliam A. Kennington III {
643d998f82bSWilliam A. Kennington III     if (ChassisInherit::currentPowerState() == PowerState::On)
644d998f82bSWilliam A. Kennington III     {
64545a1ed71SPatrick Williams         pohCounter(pohCounter() + 1);
646d998f82bSWilliam A. Kennington III     }
647d998f82bSWilliam A. Kennington III }
648d998f82bSWilliam A. Kennington III 
restorePOHCounter()649cb781fe1SNagaraju Goruganti void Chassis::restorePOHCounter()
650cb781fe1SNagaraju Goruganti {
651cb781fe1SNagaraju Goruganti     uint32_t counter;
652ba182f0cSAllen.Wang     if (!deserializePOH(counter))
653cb781fe1SNagaraju Goruganti     {
654cb781fe1SNagaraju Goruganti         // set to default value
65545a1ed71SPatrick Williams         pohCounter(0);
656cb781fe1SNagaraju Goruganti     }
657cb781fe1SNagaraju Goruganti     else
658cb781fe1SNagaraju Goruganti     {
65945a1ed71SPatrick Williams         pohCounter(counter);
660cb781fe1SNagaraju Goruganti     }
661cb781fe1SNagaraju Goruganti }
662cb781fe1SNagaraju Goruganti 
serializePOH()663ba182f0cSAllen.Wang fs::path Chassis::serializePOH()
664cb781fe1SNagaraju Goruganti {
66578c066f6SPatrick Williams     fs::path path{std::format(POH_COUNTER_PERSIST_PATH, id)};
666cb781fe1SNagaraju Goruganti     std::ofstream os(path.c_str(), std::ios::binary);
667cb781fe1SNagaraju Goruganti     cereal::JSONOutputArchive oarchive(os);
66845a1ed71SPatrick Williams     oarchive(pohCounter());
669cb781fe1SNagaraju Goruganti     return path;
670cb781fe1SNagaraju Goruganti }
671cb781fe1SNagaraju Goruganti 
deserializePOH(uint32_t & pohCounter)672ba182f0cSAllen.Wang bool Chassis::deserializePOH(uint32_t& pohCounter)
673cb781fe1SNagaraju Goruganti {
67478c066f6SPatrick Williams     fs::path path{std::format(POH_COUNTER_PERSIST_PATH, id)};
675cb781fe1SNagaraju Goruganti     try
676cb781fe1SNagaraju Goruganti     {
677cb781fe1SNagaraju Goruganti         if (fs::exists(path))
678cb781fe1SNagaraju Goruganti         {
679cb781fe1SNagaraju Goruganti             std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
680cb781fe1SNagaraju Goruganti             cereal::JSONInputArchive iarchive(is);
68145a1ed71SPatrick Williams             iarchive(pohCounter);
682cb781fe1SNagaraju Goruganti             return true;
683cb781fe1SNagaraju Goruganti         }
684cb781fe1SNagaraju Goruganti         return false;
685cb781fe1SNagaraju Goruganti     }
6868583b3b9SPatrick Williams     catch (const cereal::Exception& e)
687cb781fe1SNagaraju Goruganti     {
6888ffdb269SAndrew Geissler         error("deserialize exception: {ERROR}", "ERROR", e);
689cb781fe1SNagaraju Goruganti         fs::remove(path);
690cb781fe1SNagaraju Goruganti         return false;
691cb781fe1SNagaraju Goruganti     }
692cb781fe1SNagaraju Goruganti     catch (const fs::filesystem_error& e)
693cb781fe1SNagaraju Goruganti     {
694cb781fe1SNagaraju Goruganti         return false;
695cb781fe1SNagaraju Goruganti     }
696cb781fe1SNagaraju Goruganti 
697cb781fe1SNagaraju Goruganti     return false;
698cb781fe1SNagaraju Goruganti }
699cb781fe1SNagaraju Goruganti 
startPOHCounter()700cb781fe1SNagaraju Goruganti void Chassis::startPOHCounter()
701cb781fe1SNagaraju Goruganti {
702cb781fe1SNagaraju Goruganti     auto dir = fs::path(POH_COUNTER_PERSIST_PATH).parent_path();
703cb781fe1SNagaraju Goruganti     fs::create_directories(dir);
704cb781fe1SNagaraju Goruganti 
705cb781fe1SNagaraju Goruganti     try
706cb781fe1SNagaraju Goruganti     {
707d998f82bSWilliam A. Kennington III         auto event = sdeventplus::Event::get_default();
708d998f82bSWilliam A. Kennington III         bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
709d998f82bSWilliam A. Kennington III         event.loop();
710cb781fe1SNagaraju Goruganti     }
711d998f82bSWilliam A. Kennington III     catch (const sdeventplus::SdEventError& e)
712cb781fe1SNagaraju Goruganti     {
7138ffdb269SAndrew Geissler         error("Error occurred during the sdeventplus loop: {ERROR}", "ERROR",
7148ffdb269SAndrew Geissler               e);
715cb781fe1SNagaraju Goruganti         phosphor::logging::commit<InternalFailure>();
716cb781fe1SNagaraju Goruganti     }
717a90a31a9SAndrew Geissler }
718a90a31a9SAndrew Geissler 
serializeStateChangeTime()7199eab9861SMatt Spinler void Chassis::serializeStateChangeTime()
7209eab9861SMatt Spinler {
72178c066f6SPatrick Williams     fs::path path{std::format(CHASSIS_STATE_CHANGE_PERSIST_PATH, id)};
7229eab9861SMatt Spinler     std::ofstream os(path.c_str(), std::ios::binary);
7239eab9861SMatt Spinler     cereal::JSONOutputArchive oarchive(os);
7249eab9861SMatt Spinler 
7259eab9861SMatt Spinler     oarchive(ChassisInherit::lastStateChangeTime(),
7269eab9861SMatt Spinler              ChassisInherit::currentPowerState());
7279eab9861SMatt Spinler }
7289eab9861SMatt Spinler 
deserializeStateChangeTime(uint64_t & time,PowerState & state)7299eab9861SMatt Spinler bool Chassis::deserializeStateChangeTime(uint64_t& time, PowerState& state)
7309eab9861SMatt Spinler {
73178c066f6SPatrick Williams     fs::path path{std::format(CHASSIS_STATE_CHANGE_PERSIST_PATH, id)};
7329eab9861SMatt Spinler 
7339eab9861SMatt Spinler     try
7349eab9861SMatt Spinler     {
7359eab9861SMatt Spinler         if (fs::exists(path))
7369eab9861SMatt Spinler         {
7379eab9861SMatt Spinler             std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
7389eab9861SMatt Spinler             cereal::JSONInputArchive iarchive(is);
7399eab9861SMatt Spinler             iarchive(time, state);
7409eab9861SMatt Spinler             return true;
7419eab9861SMatt Spinler         }
7429eab9861SMatt Spinler     }
7438583b3b9SPatrick Williams     catch (const std::exception& e)
7449eab9861SMatt Spinler     {
7458ffdb269SAndrew Geissler         error("deserialize exception: {ERROR}", "ERROR", e);
7469eab9861SMatt Spinler         fs::remove(path);
7479eab9861SMatt Spinler     }
7489eab9861SMatt Spinler 
7499eab9861SMatt Spinler     return false;
7509eab9861SMatt Spinler }
7519eab9861SMatt Spinler 
restoreChassisStateChangeTime()7529eab9861SMatt Spinler void Chassis::restoreChassisStateChangeTime()
7539eab9861SMatt Spinler {
7549eab9861SMatt Spinler     uint64_t time;
7559eab9861SMatt Spinler     PowerState state;
7569eab9861SMatt Spinler 
7579eab9861SMatt Spinler     if (!deserializeStateChangeTime(time, state))
7589eab9861SMatt Spinler     {
7599eab9861SMatt Spinler         ChassisInherit::lastStateChangeTime(0);
7609eab9861SMatt Spinler     }
7619eab9861SMatt Spinler     else
7629eab9861SMatt Spinler     {
7639eab9861SMatt Spinler         ChassisInherit::lastStateChangeTime(time);
7649eab9861SMatt Spinler     }
7659eab9861SMatt Spinler }
7669eab9861SMatt Spinler 
setStateChangeTime()7679eab9861SMatt Spinler void Chassis::setStateChangeTime()
7689eab9861SMatt Spinler {
7699eab9861SMatt Spinler     using namespace std::chrono;
7709eab9861SMatt Spinler     uint64_t lastTime;
7719eab9861SMatt Spinler     PowerState lastState;
7729eab9861SMatt Spinler 
7739eab9861SMatt Spinler     auto now =
7749eab9861SMatt Spinler         duration_cast<milliseconds>(system_clock::now().time_since_epoch())
7759eab9861SMatt Spinler             .count();
7769eab9861SMatt Spinler 
7779eab9861SMatt Spinler     // If power is on when the BMC is rebooted, this function will get called
7789eab9861SMatt Spinler     // because sysStateChange() runs.  Since the power state didn't change
7799eab9861SMatt Spinler     // in this case, neither should the state change time, so check that
7809eab9861SMatt Spinler     // the power state actually did change here.
7819eab9861SMatt Spinler     if (deserializeStateChangeTime(lastTime, lastState))
7829eab9861SMatt Spinler     {
7839eab9861SMatt Spinler         if (lastState == ChassisInherit::currentPowerState())
7849eab9861SMatt Spinler         {
7859eab9861SMatt Spinler             return;
7869eab9861SMatt Spinler         }
7879eab9861SMatt Spinler     }
7889eab9861SMatt Spinler 
7899eab9861SMatt Spinler     ChassisInherit::lastStateChangeTime(now);
7909eab9861SMatt Spinler     serializeStateChangeTime();
7919eab9861SMatt Spinler }
7929eab9861SMatt Spinler 
standbyVoltageRegulatorFault()7932c36e5adSBen Tyner bool Chassis::standbyVoltageRegulatorFault()
7942c36e5adSBen Tyner {
7952c36e5adSBen Tyner     bool regulatorFault = false;
7962c36e5adSBen Tyner 
797f8ae6a02SAndrew Geissler     // find standby voltage regulator fault via gpiog
7982c36e5adSBen Tyner 
799f8ae6a02SAndrew Geissler     auto gpioval = utils::getGpioValue("regulator-standby-faulted");
8002c36e5adSBen Tyner 
8012c36e5adSBen Tyner     if (-1 == gpioval)
8022c36e5adSBen Tyner     {
8032c36e5adSBen Tyner         error("Failed reading regulator-standby-faulted GPIO");
8042c36e5adSBen Tyner     }
8052c36e5adSBen Tyner 
8062c36e5adSBen Tyner     if (1 == gpioval)
8072c36e5adSBen Tyner     {
8082c36e5adSBen Tyner         info("Detected standby voltage regulator fault");
8092c36e5adSBen Tyner         regulatorFault = true;
8102c36e5adSBen Tyner     }
811f8ae6a02SAndrew Geissler 
8122c36e5adSBen Tyner     return regulatorFault;
8132c36e5adSBen Tyner }
8142c36e5adSBen Tyner 
815a90a31a9SAndrew Geissler } // namespace manager
816a90a31a9SAndrew Geissler } // namespace state
817a965cf06SAndrew Geissler } // namespace phosphor
818