blob: 4d6b445da6b3d7e7fc71e254f66d10abd144130a [file] [log] [blame]
Andrew Geisslere426b582020-05-28 12:40:55 -05001#include "config.h"
2
3#include "chassis_state_manager.hpp"
4
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -06005#include "utils.hpp"
Andrew Geisslere426b582020-05-28 12:40:55 -05006#include "xyz/openbmc_project/Common/error.hpp"
7#include "xyz/openbmc_project/State/Shutdown/Power/error.hpp"
8
9#include <cereal/archives/json.hpp>
10#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler8ffdb262021-09-20 15:25:19 -050011#include <phosphor-logging/lg2.hpp>
Andrew Geissler0029a5d2017-01-24 14:48:35 -060012#include <sdbusplus/bus.hpp>
William A. Kennington III09568ff2018-05-11 00:03:12 -070013#include <sdbusplus/exception.hpp>
William A. Kennington IIId998f822018-10-17 23:17:57 -070014#include <sdeventplus/event.hpp>
15#include <sdeventplus/exception.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -050016
Andrew Geisslerf2b22e82021-03-12 14:47:03 -060017#include <filesystem>
Andrew Geisslere426b582020-05-28 12:40:55 -050018#include <fstream>
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -050019
Andrew Geisslera90a31a2016-12-13 16:16:28 -060020namespace phosphor
21{
22namespace state
23{
24namespace manager
25{
26
Andrew Geissler8ffdb262021-09-20 15:25:19 -050027PHOSPHOR_LOG2_USING;
28
Andrew Geisslera90a31a2016-12-13 16:16:28 -060029// When you see server:: you know we're referencing our base class
30namespace server = sdbusplus::xyz::openbmc_project::State::server;
31
32using namespace phosphor::logging;
William A. Kennington IIId998f822018-10-17 23:17:57 -070033using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Aatir Manzur27115ae2019-07-23 16:25:38 -050034using sdbusplus::xyz::openbmc_project::State::Shutdown::Power::Error::Blackout;
Ben Tyner2c36e5a2021-07-12 14:56:49 -050035using sdbusplus::xyz::openbmc_project::State::Shutdown::Power::Error::Regulator;
Josh D. King6838ea92017-04-11 13:39:18 -050036constexpr auto CHASSIS_STATE_POWEROFF_TGT = "obmc-chassis-poweroff@0.target";
Andrew Geissler58a18012018-01-19 19:36:05 -080037constexpr auto CHASSIS_STATE_HARD_POWEROFF_TGT =
38 "obmc-chassis-hard-poweroff@0.target";
Josh D. King6838ea92017-04-11 13:39:18 -050039constexpr auto CHASSIS_STATE_POWERON_TGT = "obmc-chassis-poweron@0.target";
Andrew Geissler0029a5d2017-01-24 14:48:35 -060040
Josh D. King697474c2017-03-02 11:15:55 -060041constexpr auto ACTIVE_STATE = "active";
42constexpr auto ACTIVATING_STATE = "activating";
43
Andrew Geisslerce80f242017-01-24 13:25:33 -060044/* Map a transition to it's systemd target */
Andrew Geissler58a18012018-01-19 19:36:05 -080045const std::map<server::Chassis::Transition, std::string> SYSTEMD_TARGET_TABLE =
46 {
Andrew Geissler8cf2f9a2017-07-21 11:58:04 -050047 // Use the hard off target to ensure we shutdown immediately
48 {server::Chassis::Transition::Off, CHASSIS_STATE_HARD_POWEROFF_TGT},
Andrew Geissler58a18012018-01-19 19:36:05 -080049 {server::Chassis::Transition::On, CHASSIS_STATE_POWERON_TGT}};
Andrew Geisslerce80f242017-01-24 13:25:33 -060050
Andrew Geissler58a18012018-01-19 19:36:05 -080051constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
52constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Andrew Geisslerce80f242017-01-24 13:25:33 -060053constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
54
Josh D. King697474c2017-03-02 11:15:55 -060055constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
56constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
57
Andrew Geissler0029a5d2017-01-24 14:48:35 -060058void Chassis::subscribeToSystemdSignals()
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060059{
Andrew Geissler3a30b052019-05-14 15:54:37 -050060 try
61 {
62 auto method = this->bus.new_method_call(
63 SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, SYSTEMD_INTERFACE, "Subscribe");
Andrew Geissler5b950272019-05-24 12:27:51 -050064 this->bus.call(method);
Andrew Geissler3a30b052019-05-14 15:54:37 -050065 }
Andrew Geissler8ffdb262021-09-20 15:25:19 -050066 catch (const sdbusplus::exception::exception& e)
Andrew Geissler3a30b052019-05-14 15:54:37 -050067 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050068 error("Failed to subscribe to systemd signals: {ERROR}", "ERROR", e);
Andrew Geissler3a30b052019-05-14 15:54:37 -050069 elog<InternalFailure>();
70 }
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060071
Andrew Geissler0029a5d2017-01-24 14:48:35 -060072 return;
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060073}
74
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060075// TODO - Will be rewritten once sdbusplus client bindings are in place
76// and persistent storage design is in place and sdbusplus
77// has read property function
78void Chassis::determineInitialState()
79{
Patrick Williams2975e262020-05-13 18:01:09 -050080 std::variant<int> pgood = -1;
Andrew Geissler58a18012018-01-19 19:36:05 -080081 auto method = this->bus.new_method_call(
82 "org.openbmc.control.Power", "/org/openbmc/control/power0",
83 "org.freedesktop.DBus.Properties", "Get");
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060084
85 method.append("org.openbmc.control.Power", "pgood");
William A. Kennington III09568ff2018-05-11 00:03:12 -070086 try
87 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -070088 auto reply = this->bus.call(method);
Anthony Wilson32c532e2018-10-25 21:56:07 -050089 reply.read(pgood);
William A. Kennington III9a2f37c2018-06-28 16:18:37 -070090
Patrick Williams37413dc2020-05-13 11:29:54 -050091 if (std::get<int>(pgood) == 1)
William A. Kennington III9a2f37c2018-06-28 16:18:37 -070092 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050093 info("Initial Chassis State will be On");
William A. Kennington III9a2f37c2018-06-28 16:18:37 -070094 server::Chassis::currentPowerState(PowerState::On);
95 server::Chassis::requestedPowerTransition(Transition::On);
96 return;
97 }
Matt Spinler9eab9862018-07-11 14:13:52 -050098 else
99 {
100 // The system is off. If we think it should be on then
101 // we probably lost AC while up, so set a new state
102 // change time.
103 uint64_t lastTime;
104 PowerState lastState;
105
106 if (deserializeStateChangeTime(lastTime, lastState))
107 {
Andrew Geissler7ed36232022-01-26 13:49:28 -0600108 // If power was on before the BMC reboot and the reboot reason
109 // was not a pinhole reset, log an error
Matt Spinler9eab9862018-07-11 14:13:52 -0500110 if (lastState == PowerState::On)
111 {
Andrew Geissler7ed36232022-01-26 13:49:28 -0600112 info(
113 "Chassis power was on before the BMC reboot and it is off now");
Matt Spinler9eab9862018-07-11 14:13:52 -0500114 setStateChangeTime();
Andrew Geissler7ed36232022-01-26 13:49:28 -0600115
116 if (phosphor::state::manager::utils::getGpioValue(
117 "reset-cause-pinhole") != 1)
118 {
119 if (standbyVoltageRegulatorFault())
120 {
121 report<Regulator>();
122 }
123 else
124 {
125 report<Blackout>();
126 }
127 }
Matt Spinler9eab9862018-07-11 14:13:52 -0500128 }
129 }
130 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700131 }
Patrick Williams0a675212021-09-02 09:49:43 -0500132 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700133 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700134 // It's acceptable for the pgood state service to not be available
135 // since it will notify us of the pgood state when it comes up.
136 if (e.name() != nullptr &&
137 strcmp("org.freedesktop.DBus.Error.ServiceUnknown", e.name()) == 0)
138 {
139 goto fail;
140 }
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600141
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700142 // Only log for unexpected error types.
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500143 error("Error performing call to get pgood: {ERROR}", "ERROR", e);
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700144 goto fail;
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600145 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700146
147fail:
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500148 info("Initial Chassis State will be Off");
William A. Kennington III09568ff2018-05-11 00:03:12 -0700149 server::Chassis::currentPowerState(PowerState::Off);
150 server::Chassis::requestedPowerTransition(Transition::Off);
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600151
152 return;
153}
154
Andrew Geisslerce80f242017-01-24 13:25:33 -0600155void Chassis::executeTransition(Transition tranReq)
156{
157 auto sysdTarget = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
158
Andrew Geissler58a18012018-01-19 19:36:05 -0800159 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
160 SYSTEMD_INTERFACE, "StartUnit");
Andrew Geisslerce80f242017-01-24 13:25:33 -0600161
162 method.append(sysdTarget);
163 method.append("replace");
164
165 this->bus.call_noreply(method);
166
167 return;
168}
169
Josh D. King697474c2017-03-02 11:15:55 -0600170bool Chassis::stateActive(const std::string& target)
171{
Patrick Williams2975e262020-05-13 18:01:09 -0500172 std::variant<std::string> currentState;
Josh D. King697474c2017-03-02 11:15:55 -0600173 sdbusplus::message::object_path unitTargetPath;
174
Andrew Geissler58a18012018-01-19 19:36:05 -0800175 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
176 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King697474c2017-03-02 11:15:55 -0600177
178 method.append(target);
Josh D. King697474c2017-03-02 11:15:55 -0600179
William A. Kennington III09568ff2018-05-11 00:03:12 -0700180 try
181 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500182 auto result = this->bus.call(method);
William A. Kennington III09568ff2018-05-11 00:03:12 -0700183 result.read(unitTargetPath);
184 }
Patrick Williams0a675212021-09-02 09:49:43 -0500185 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700186 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500187 error("Error in GetUnit call: {ERROR}", "ERROR", e);
William A. Kennington III09568ff2018-05-11 00:03:12 -0700188 return false;
189 }
Josh D. King697474c2017-03-02 11:15:55 -0600190
Andrew Geissler58a18012018-01-19 19:36:05 -0800191 method = this->bus.new_method_call(
192 SYSTEMD_SERVICE,
193 static_cast<const std::string&>(unitTargetPath).c_str(),
194 SYSTEMD_PROPERTY_IFACE, "Get");
Josh D. King697474c2017-03-02 11:15:55 -0600195
196 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
Josh D. King697474c2017-03-02 11:15:55 -0600197
Anthony Wilson32c532e2018-10-25 21:56:07 -0500198 try
Josh D. King697474c2017-03-02 11:15:55 -0600199 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500200 auto result = this->bus.call(method);
201 result.read(currentState);
202 }
Patrick Williams0a675212021-09-02 09:49:43 -0500203 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500204 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500205 error("Error in ActiveState Get: {ERROR}", "ERROR", e);
Josh D. King697474c2017-03-02 11:15:55 -0600206 return false;
207 }
208
Patrick Williams37413dc2020-05-13 11:29:54 -0500209 const auto& currentStateStr = std::get<std::string>(currentState);
William A. Kennington III7a0689a2018-11-12 17:19:33 -0800210 return currentStateStr == ACTIVE_STATE ||
211 currentStateStr == ACTIVATING_STATE;
Josh D. King697474c2017-03-02 11:15:55 -0600212}
213
Patrick Williams8f8ba392017-05-05 15:47:39 -0500214int Chassis::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600215{
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600216 sdbusplus::message::object_path newStateObjPath;
217 std::string newStateUnit{};
218 std::string newStateResult{};
219
Andrew Geissler58a18012018-01-19 19:36:05 -0800220 // Read the msg and populate each variable
William A. Kennington III09568ff2018-05-11 00:03:12 -0700221 try
222 {
Andrew Geissler9b8af4f2019-09-12 14:19:14 -0500223 // newStateID is a throwaway that is needed in order to read the
224 // parameters that are useful out of the dbus message
225 uint32_t newStateID{};
William A. Kennington III09568ff2018-05-11 00:03:12 -0700226 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
227 }
Patrick Williams0a675212021-09-02 09:49:43 -0500228 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700229 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500230 error("Error in state change - bad encoding: {ERROR} {REPLY_SIG}",
231 "ERROR", e, "REPLY_SIG", msg.get_signature());
William A. Kennington III09568ff2018-05-11 00:03:12 -0700232 return 0;
233 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600234
Andrew Geissler58a18012018-01-19 19:36:05 -0800235 if ((newStateUnit == CHASSIS_STATE_POWEROFF_TGT) &&
236 (newStateResult == "done") && (!stateActive(CHASSIS_STATE_POWERON_TGT)))
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600237 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500238 info("Received signal that power OFF is complete");
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600239 this->currentPowerState(server::Chassis::PowerState::Off);
Matt Spinler9eab9862018-07-11 14:13:52 -0500240 this->setStateChangeTime();
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600241 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800242 else if ((newStateUnit == CHASSIS_STATE_POWERON_TGT) &&
243 (newStateResult == "done") &&
244 (stateActive(CHASSIS_STATE_POWERON_TGT)))
245 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500246 info("Received signal that power ON is complete");
Andrew Geissler58a18012018-01-19 19:36:05 -0800247 this->currentPowerState(server::Chassis::PowerState::On);
Matt Spinler9eab9862018-07-11 14:13:52 -0500248 this->setStateChangeTime();
Andrew Geisslerf2b22e82021-03-12 14:47:03 -0600249
250 // Remove temporary file which is utilized for scenarios where the
251 // BMC is rebooted while the chassis power is still on.
252 // This file is used to indicate to chassis related systemd services
253 // that the chassis is already on and they should skip running.
254 // Once the chassis state is back to on we can clear this file.
255 auto size = std::snprintf(nullptr, 0, CHASSIS_ON_FILE, 0);
256 size++; // null
257 std::unique_ptr<char[]> chassisFile(new char[size]);
258 std::snprintf(chassisFile.get(), size, CHASSIS_ON_FILE, 0);
259 if (std::filesystem::exists(chassisFile.get()))
260 {
261 std::filesystem::remove(chassisFile.get());
262 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800263 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600264
265 return 0;
266}
267
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600268Chassis::Transition Chassis::requestedPowerTransition(Transition value)
269{
270
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500271 info("Change to Chassis Requested Power State: {REQ_POWER_TRAN}",
272 "REQ_POWER_TRAN", value);
Andrew Geisslerce80f242017-01-24 13:25:33 -0600273 executeTransition(value);
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600274 return server::Chassis::requestedPowerTransition(value);
275}
276
277Chassis::PowerState Chassis::currentPowerState(PowerState value)
278{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500279 PowerState chassisPowerState;
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500280 info("Change to Chassis Power State: {CUR_POWER_STATE}", "CUR_POWER_STATE",
281 value);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500282
283 chassisPowerState = server::Chassis::currentPowerState(value);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500284 pohTimer.setEnabled(chassisPowerState == PowerState::On);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500285 return chassisPowerState;
286}
287
Patrick Williams45a1ed72021-04-30 21:02:43 -0500288uint32_t Chassis::pohCounter(uint32_t value)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500289{
Patrick Williams45a1ed72021-04-30 21:02:43 -0500290 if (value != pohCounter())
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500291 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500292 ChassisInherit::pohCounter(value);
Matt Spinler81957842018-07-11 10:37:12 -0500293 serializePOH();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500294 }
Patrick Williams45a1ed72021-04-30 21:02:43 -0500295 return pohCounter();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500296}
297
Patrick Williams45a1ed72021-04-30 21:02:43 -0500298void Chassis::pohCallback()
William A. Kennington IIId998f822018-10-17 23:17:57 -0700299{
300 if (ChassisInherit::currentPowerState() == PowerState::On)
301 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500302 pohCounter(pohCounter() + 1);
William A. Kennington IIId998f822018-10-17 23:17:57 -0700303 }
304}
305
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500306void Chassis::restorePOHCounter()
307{
308 uint32_t counter;
Matt Spinler81957842018-07-11 10:37:12 -0500309 if (!deserializePOH(POH_COUNTER_PERSIST_PATH, counter))
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500310 {
311 // set to default value
Patrick Williams45a1ed72021-04-30 21:02:43 -0500312 pohCounter(0);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500313 }
314 else
315 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500316 pohCounter(counter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500317 }
318}
319
Matt Spinler81957842018-07-11 10:37:12 -0500320fs::path Chassis::serializePOH(const fs::path& path)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500321{
322 std::ofstream os(path.c_str(), std::ios::binary);
323 cereal::JSONOutputArchive oarchive(os);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500324 oarchive(pohCounter());
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500325 return path;
326}
327
Patrick Williams45a1ed72021-04-30 21:02:43 -0500328bool Chassis::deserializePOH(const fs::path& path, uint32_t& pohCounter)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500329{
330 try
331 {
332 if (fs::exists(path))
333 {
334 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
335 cereal::JSONInputArchive iarchive(is);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500336 iarchive(pohCounter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500337 return true;
338 }
339 return false;
340 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500341 catch (const cereal::Exception& e)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500342 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500343 error("deserialize exception: {ERROR}", "ERROR", e);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500344 fs::remove(path);
345 return false;
346 }
347 catch (const fs::filesystem_error& e)
348 {
349 return false;
350 }
351
352 return false;
353}
354
355void Chassis::startPOHCounter()
356{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500357 auto dir = fs::path(POH_COUNTER_PERSIST_PATH).parent_path();
358 fs::create_directories(dir);
359
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500360 try
361 {
William A. Kennington IIId998f822018-10-17 23:17:57 -0700362 auto event = sdeventplus::Event::get_default();
363 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
364 event.loop();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500365 }
William A. Kennington IIId998f822018-10-17 23:17:57 -0700366 catch (const sdeventplus::SdEventError& e)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500367 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500368 error("Error occurred during the sdeventplus loop: {ERROR}", "ERROR",
369 e);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500370 phosphor::logging::commit<InternalFailure>();
371 }
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600372}
373
Matt Spinler9eab9862018-07-11 14:13:52 -0500374void Chassis::serializeStateChangeTime()
375{
376 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
377 std::ofstream os(path.c_str(), std::ios::binary);
378 cereal::JSONOutputArchive oarchive(os);
379
380 oarchive(ChassisInherit::lastStateChangeTime(),
381 ChassisInherit::currentPowerState());
382}
383
384bool Chassis::deserializeStateChangeTime(uint64_t& time, PowerState& state)
385{
386 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
387
388 try
389 {
390 if (fs::exists(path))
391 {
392 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
393 cereal::JSONInputArchive iarchive(is);
394 iarchive(time, state);
395 return true;
396 }
397 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500398 catch (const std::exception& e)
Matt Spinler9eab9862018-07-11 14:13:52 -0500399 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500400 error("deserialize exception: {ERROR}", "ERROR", e);
Matt Spinler9eab9862018-07-11 14:13:52 -0500401 fs::remove(path);
402 }
403
404 return false;
405}
406
407void Chassis::restoreChassisStateChangeTime()
408{
409 uint64_t time;
410 PowerState state;
411
412 if (!deserializeStateChangeTime(time, state))
413 {
414 ChassisInherit::lastStateChangeTime(0);
415 }
416 else
417 {
418 ChassisInherit::lastStateChangeTime(time);
419 }
420}
421
422void Chassis::setStateChangeTime()
423{
424 using namespace std::chrono;
425 uint64_t lastTime;
426 PowerState lastState;
427
428 auto now =
429 duration_cast<milliseconds>(system_clock::now().time_since_epoch())
430 .count();
431
432 // If power is on when the BMC is rebooted, this function will get called
433 // because sysStateChange() runs. Since the power state didn't change
434 // in this case, neither should the state change time, so check that
435 // the power state actually did change here.
436 if (deserializeStateChangeTime(lastTime, lastState))
437 {
438 if (lastState == ChassisInherit::currentPowerState())
439 {
440 return;
441 }
442 }
443
444 ChassisInherit::lastStateChangeTime(now);
445 serializeStateChangeTime();
446}
447
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500448bool Chassis::standbyVoltageRegulatorFault()
449{
450 bool regulatorFault = false;
451
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600452 // find standby voltage regulator fault via gpiog
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500453
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600454 auto gpioval = utils::getGpioValue("regulator-standby-faulted");
455
456 if (-1 == gpioval)
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500457 {
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600458 error("Failed reading regulator-standby-faulted GPIO");
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500459 }
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600460
461 if (1 == gpioval)
462 {
463 info("Detected standby voltage regulator fault");
464 regulatorFault = true;
465 }
466
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500467 return regulatorFault;
468}
469
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600470} // namespace manager
471} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700472} // namespace phosphor