blob: ae998ef0b36c4c8a09526df98a14ec169f247641 [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 Geissler8b1f8622022-01-28 16:37:07 -060058constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
59constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
60constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
61constexpr auto UPOWER_INTERFACE = "org.freedesktop.UPower.Device";
62constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
63
Andrew Geissler0029a5d2017-01-24 14:48:35 -060064void Chassis::subscribeToSystemdSignals()
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060065{
Andrew Geissler3a30b052019-05-14 15:54:37 -050066 try
67 {
68 auto method = this->bus.new_method_call(
69 SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, SYSTEMD_INTERFACE, "Subscribe");
Andrew Geissler5b950272019-05-24 12:27:51 -050070 this->bus.call(method);
Andrew Geissler3a30b052019-05-14 15:54:37 -050071 }
Andrew Geissler8ffdb262021-09-20 15:25:19 -050072 catch (const sdbusplus::exception::exception& e)
Andrew Geissler3a30b052019-05-14 15:54:37 -050073 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050074 error("Failed to subscribe to systemd signals: {ERROR}", "ERROR", e);
Andrew Geissler3a30b052019-05-14 15:54:37 -050075 elog<InternalFailure>();
76 }
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060077
Andrew Geissler0029a5d2017-01-24 14:48:35 -060078 return;
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060079}
80
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060081// TODO - Will be rewritten once sdbusplus client bindings are in place
82// and persistent storage design is in place and sdbusplus
83// has read property function
84void Chassis::determineInitialState()
85{
Andrew Geissler8b1f8622022-01-28 16:37:07 -060086 determineStatusOfPower();
87
Patrick Williams2975e262020-05-13 18:01:09 -050088 std::variant<int> pgood = -1;
Andrew Geissler58a18012018-01-19 19:36:05 -080089 auto method = this->bus.new_method_call(
90 "org.openbmc.control.Power", "/org/openbmc/control/power0",
91 "org.freedesktop.DBus.Properties", "Get");
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060092
93 method.append("org.openbmc.control.Power", "pgood");
William A. Kennington III09568ff2018-05-11 00:03:12 -070094 try
95 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -070096 auto reply = this->bus.call(method);
Anthony Wilson32c532e2018-10-25 21:56:07 -050097 reply.read(pgood);
William A. Kennington III9a2f37c2018-06-28 16:18:37 -070098
Patrick Williams37413dc2020-05-13 11:29:54 -050099 if (std::get<int>(pgood) == 1)
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700100 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500101 info("Initial Chassis State will be On");
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700102 server::Chassis::currentPowerState(PowerState::On);
103 server::Chassis::requestedPowerTransition(Transition::On);
104 return;
105 }
Matt Spinler9eab9862018-07-11 14:13:52 -0500106 else
107 {
108 // The system is off. If we think it should be on then
109 // we probably lost AC while up, so set a new state
110 // change time.
111 uint64_t lastTime;
112 PowerState lastState;
113
114 if (deserializeStateChangeTime(lastTime, lastState))
115 {
Andrew Geissler7ed36232022-01-26 13:49:28 -0600116 // If power was on before the BMC reboot and the reboot reason
117 // was not a pinhole reset, log an error
Matt Spinler9eab9862018-07-11 14:13:52 -0500118 if (lastState == PowerState::On)
119 {
Andrew Geissler7ed36232022-01-26 13:49:28 -0600120 info(
121 "Chassis power was on before the BMC reboot and it is off now");
Matt Spinler9eab9862018-07-11 14:13:52 -0500122 setStateChangeTime();
Andrew Geissler7ed36232022-01-26 13:49:28 -0600123
124 if (phosphor::state::manager::utils::getGpioValue(
125 "reset-cause-pinhole") != 1)
126 {
127 if (standbyVoltageRegulatorFault())
128 {
129 report<Regulator>();
130 }
131 else
132 {
133 report<Blackout>();
134 }
135 }
Matt Spinler9eab9862018-07-11 14:13:52 -0500136 }
137 }
138 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700139 }
Patrick Williams0a675212021-09-02 09:49:43 -0500140 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700141 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700142 // It's acceptable for the pgood state service to not be available
143 // since it will notify us of the pgood state when it comes up.
144 if (e.name() != nullptr &&
145 strcmp("org.freedesktop.DBus.Error.ServiceUnknown", e.name()) == 0)
146 {
147 goto fail;
148 }
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600149
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700150 // Only log for unexpected error types.
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500151 error("Error performing call to get pgood: {ERROR}", "ERROR", e);
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700152 goto fail;
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600153 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700154
155fail:
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500156 info("Initial Chassis State will be Off");
William A. Kennington III09568ff2018-05-11 00:03:12 -0700157 server::Chassis::currentPowerState(PowerState::Off);
158 server::Chassis::requestedPowerTransition(Transition::Off);
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600159
160 return;
161}
162
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600163void Chassis::determineStatusOfPower()
164{
165
166 // Details at https://upower.freedesktop.org/docs/Device.html
167 constexpr uint TYPE_UPS = 3;
168 constexpr uint STATE_FULLY_CHARGED = 4;
169 constexpr uint BATTERY_LVL_FULL = 8;
170
171 // Default PowerStatus to good
172 server::Chassis::currentPowerStatus(PowerStatus::Good);
173
174 // Find all implementations of the UPower interface
175 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
176 MAPPER_INTERFACE, "GetSubTree");
177
178 mapper.append("/", 0, std::vector<std::string>({UPOWER_INTERFACE}));
179
180 std::map<std::string, std::map<std::string, std::vector<std::string>>>
181 mapperResponse;
182
183 try
184 {
185 auto mapperResponseMsg = bus.call(mapper);
186 mapperResponseMsg.read(mapperResponse);
187 }
188 catch (const sdbusplus::exception::exception& e)
189 {
190 error("Error in mapper GetSubTree call for UPS: {ERROR}", "ERROR", e);
191 throw;
192 }
193
194 if (mapperResponse.empty())
195 {
196 debug("No UPower devices found in system");
197 return;
198 }
199
200 // Iterate through all returned Upower interfaces and look for UPS's
201 for (const auto& [path, services] : mapperResponse)
202 {
203 for (const auto& serviceIter : services)
204 {
205 const std::string& service = serviceIter.first;
206
207 try
208 {
209 auto method = bus.new_method_call(service.c_str(), path.c_str(),
210 PROPERTY_INTERFACE, "GetAll");
211 method.append(UPOWER_INTERFACE);
212
213 auto response = bus.call(method);
214 using Property = std::string;
215 using Value = std::variant<bool, uint>;
216 using PropertyMap = std::map<Property, Value>;
217 PropertyMap properties;
218 response.read(properties);
219
220 if (std::get<bool>(properties["IsPresent"]) != true)
221 {
222 info("UPower device {OBJ_PATH} is not present", "OBJ_PATH",
223 path);
224 continue;
225 }
226
227 if (std::get<uint>(properties["Type"]) != TYPE_UPS)
228 {
229 info("UPower device {OBJ_PATH} is not a UPS device",
230 "OBJ_PATH", path);
231 continue;
232 }
233
234 if (std::get<uint>(properties["State"]) == STATE_FULLY_CHARGED)
235 {
236 info("UPS is fully charged");
237 }
238 else
239 {
240 info("UPS is not fully charged: {UPS_STATE}", "UPS_STATE",
241 std::get<uint>(properties["State"]));
242 server::Chassis::currentPowerStatus(
243 PowerStatus::UninterruptiblePowerSupply);
244 return;
245 }
246
247 if (std::get<uint>(properties["BatteryLevel"]) ==
248 BATTERY_LVL_FULL)
249 {
250 info("UPS Battery Level is Full");
251 }
252 else
253 {
254 info("UPS Battery Level is Low: {UPS_BAT_LEVEL}",
255 "UPS_BAT_LEVEL",
256 std::get<uint>(properties["BatteryLevel"]));
257 server::Chassis::currentPowerStatus(
258 PowerStatus::UninterruptiblePowerSupply);
259 return;
260 }
261 }
262 catch (const sdbusplus::exception::exception& e)
263 {
264 error("Error reading UPS property, error: {ERROR}, "
265 "service: {SERVICE} path: {PATH}",
266 "ERROR", e, "SERVICE", service, "PATH", path);
267 throw;
268 }
269 }
270 }
271 return;
272}
273
Andrew Geisslerce80f242017-01-24 13:25:33 -0600274void Chassis::executeTransition(Transition tranReq)
275{
276 auto sysdTarget = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
277
Andrew Geissler58a18012018-01-19 19:36:05 -0800278 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
279 SYSTEMD_INTERFACE, "StartUnit");
Andrew Geisslerce80f242017-01-24 13:25:33 -0600280
281 method.append(sysdTarget);
282 method.append("replace");
283
284 this->bus.call_noreply(method);
285
286 return;
287}
288
Josh D. King697474c2017-03-02 11:15:55 -0600289bool Chassis::stateActive(const std::string& target)
290{
Patrick Williams2975e262020-05-13 18:01:09 -0500291 std::variant<std::string> currentState;
Josh D. King697474c2017-03-02 11:15:55 -0600292 sdbusplus::message::object_path unitTargetPath;
293
Andrew Geissler58a18012018-01-19 19:36:05 -0800294 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
295 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King697474c2017-03-02 11:15:55 -0600296
297 method.append(target);
Josh D. King697474c2017-03-02 11:15:55 -0600298
William A. Kennington III09568ff2018-05-11 00:03:12 -0700299 try
300 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500301 auto result = this->bus.call(method);
William A. Kennington III09568ff2018-05-11 00:03:12 -0700302 result.read(unitTargetPath);
303 }
Patrick Williams0a675212021-09-02 09:49:43 -0500304 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700305 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500306 error("Error in GetUnit call: {ERROR}", "ERROR", e);
William A. Kennington III09568ff2018-05-11 00:03:12 -0700307 return false;
308 }
Josh D. King697474c2017-03-02 11:15:55 -0600309
Andrew Geissler58a18012018-01-19 19:36:05 -0800310 method = this->bus.new_method_call(
311 SYSTEMD_SERVICE,
312 static_cast<const std::string&>(unitTargetPath).c_str(),
313 SYSTEMD_PROPERTY_IFACE, "Get");
Josh D. King697474c2017-03-02 11:15:55 -0600314
315 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
Josh D. King697474c2017-03-02 11:15:55 -0600316
Anthony Wilson32c532e2018-10-25 21:56:07 -0500317 try
Josh D. King697474c2017-03-02 11:15:55 -0600318 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500319 auto result = this->bus.call(method);
320 result.read(currentState);
321 }
Patrick Williams0a675212021-09-02 09:49:43 -0500322 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500323 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500324 error("Error in ActiveState Get: {ERROR}", "ERROR", e);
Josh D. King697474c2017-03-02 11:15:55 -0600325 return false;
326 }
327
Patrick Williams37413dc2020-05-13 11:29:54 -0500328 const auto& currentStateStr = std::get<std::string>(currentState);
William A. Kennington III7a0689a2018-11-12 17:19:33 -0800329 return currentStateStr == ACTIVE_STATE ||
330 currentStateStr == ACTIVATING_STATE;
Josh D. King697474c2017-03-02 11:15:55 -0600331}
332
Patrick Williams8f8ba392017-05-05 15:47:39 -0500333int Chassis::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600334{
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600335 sdbusplus::message::object_path newStateObjPath;
336 std::string newStateUnit{};
337 std::string newStateResult{};
338
Andrew Geissler58a18012018-01-19 19:36:05 -0800339 // Read the msg and populate each variable
William A. Kennington III09568ff2018-05-11 00:03:12 -0700340 try
341 {
Andrew Geissler9b8af4f2019-09-12 14:19:14 -0500342 // newStateID is a throwaway that is needed in order to read the
343 // parameters that are useful out of the dbus message
344 uint32_t newStateID{};
William A. Kennington III09568ff2018-05-11 00:03:12 -0700345 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
346 }
Patrick Williams0a675212021-09-02 09:49:43 -0500347 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700348 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500349 error("Error in state change - bad encoding: {ERROR} {REPLY_SIG}",
350 "ERROR", e, "REPLY_SIG", msg.get_signature());
William A. Kennington III09568ff2018-05-11 00:03:12 -0700351 return 0;
352 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600353
Andrew Geissler58a18012018-01-19 19:36:05 -0800354 if ((newStateUnit == CHASSIS_STATE_POWEROFF_TGT) &&
355 (newStateResult == "done") && (!stateActive(CHASSIS_STATE_POWERON_TGT)))
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600356 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500357 info("Received signal that power OFF is complete");
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600358 this->currentPowerState(server::Chassis::PowerState::Off);
Matt Spinler9eab9862018-07-11 14:13:52 -0500359 this->setStateChangeTime();
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600360 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800361 else if ((newStateUnit == CHASSIS_STATE_POWERON_TGT) &&
362 (newStateResult == "done") &&
363 (stateActive(CHASSIS_STATE_POWERON_TGT)))
364 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500365 info("Received signal that power ON is complete");
Andrew Geissler58a18012018-01-19 19:36:05 -0800366 this->currentPowerState(server::Chassis::PowerState::On);
Matt Spinler9eab9862018-07-11 14:13:52 -0500367 this->setStateChangeTime();
Andrew Geisslerf2b22e82021-03-12 14:47:03 -0600368
369 // Remove temporary file which is utilized for scenarios where the
370 // BMC is rebooted while the chassis power is still on.
371 // This file is used to indicate to chassis related systemd services
372 // that the chassis is already on and they should skip running.
373 // Once the chassis state is back to on we can clear this file.
374 auto size = std::snprintf(nullptr, 0, CHASSIS_ON_FILE, 0);
375 size++; // null
376 std::unique_ptr<char[]> chassisFile(new char[size]);
377 std::snprintf(chassisFile.get(), size, CHASSIS_ON_FILE, 0);
378 if (std::filesystem::exists(chassisFile.get()))
379 {
380 std::filesystem::remove(chassisFile.get());
381 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800382 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600383
384 return 0;
385}
386
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600387Chassis::Transition Chassis::requestedPowerTransition(Transition value)
388{
389
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500390 info("Change to Chassis Requested Power State: {REQ_POWER_TRAN}",
391 "REQ_POWER_TRAN", value);
Andrew Geisslerce80f242017-01-24 13:25:33 -0600392 executeTransition(value);
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600393 return server::Chassis::requestedPowerTransition(value);
394}
395
396Chassis::PowerState Chassis::currentPowerState(PowerState value)
397{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500398 PowerState chassisPowerState;
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500399 info("Change to Chassis Power State: {CUR_POWER_STATE}", "CUR_POWER_STATE",
400 value);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500401
402 chassisPowerState = server::Chassis::currentPowerState(value);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500403 pohTimer.setEnabled(chassisPowerState == PowerState::On);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500404 return chassisPowerState;
405}
406
Patrick Williams45a1ed72021-04-30 21:02:43 -0500407uint32_t Chassis::pohCounter(uint32_t value)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500408{
Patrick Williams45a1ed72021-04-30 21:02:43 -0500409 if (value != pohCounter())
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500410 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500411 ChassisInherit::pohCounter(value);
Matt Spinler81957842018-07-11 10:37:12 -0500412 serializePOH();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500413 }
Patrick Williams45a1ed72021-04-30 21:02:43 -0500414 return pohCounter();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500415}
416
Patrick Williams45a1ed72021-04-30 21:02:43 -0500417void Chassis::pohCallback()
William A. Kennington IIId998f822018-10-17 23:17:57 -0700418{
419 if (ChassisInherit::currentPowerState() == PowerState::On)
420 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500421 pohCounter(pohCounter() + 1);
William A. Kennington IIId998f822018-10-17 23:17:57 -0700422 }
423}
424
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500425void Chassis::restorePOHCounter()
426{
427 uint32_t counter;
Matt Spinler81957842018-07-11 10:37:12 -0500428 if (!deserializePOH(POH_COUNTER_PERSIST_PATH, counter))
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500429 {
430 // set to default value
Patrick Williams45a1ed72021-04-30 21:02:43 -0500431 pohCounter(0);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500432 }
433 else
434 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500435 pohCounter(counter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500436 }
437}
438
Matt Spinler81957842018-07-11 10:37:12 -0500439fs::path Chassis::serializePOH(const fs::path& path)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500440{
441 std::ofstream os(path.c_str(), std::ios::binary);
442 cereal::JSONOutputArchive oarchive(os);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500443 oarchive(pohCounter());
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500444 return path;
445}
446
Patrick Williams45a1ed72021-04-30 21:02:43 -0500447bool Chassis::deserializePOH(const fs::path& path, uint32_t& pohCounter)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500448{
449 try
450 {
451 if (fs::exists(path))
452 {
453 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
454 cereal::JSONInputArchive iarchive(is);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500455 iarchive(pohCounter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500456 return true;
457 }
458 return false;
459 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500460 catch (const cereal::Exception& e)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500461 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500462 error("deserialize exception: {ERROR}", "ERROR", e);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500463 fs::remove(path);
464 return false;
465 }
466 catch (const fs::filesystem_error& e)
467 {
468 return false;
469 }
470
471 return false;
472}
473
474void Chassis::startPOHCounter()
475{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500476 auto dir = fs::path(POH_COUNTER_PERSIST_PATH).parent_path();
477 fs::create_directories(dir);
478
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500479 try
480 {
William A. Kennington IIId998f822018-10-17 23:17:57 -0700481 auto event = sdeventplus::Event::get_default();
482 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
483 event.loop();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500484 }
William A. Kennington IIId998f822018-10-17 23:17:57 -0700485 catch (const sdeventplus::SdEventError& e)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500486 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500487 error("Error occurred during the sdeventplus loop: {ERROR}", "ERROR",
488 e);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500489 phosphor::logging::commit<InternalFailure>();
490 }
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600491}
492
Matt Spinler9eab9862018-07-11 14:13:52 -0500493void Chassis::serializeStateChangeTime()
494{
495 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
496 std::ofstream os(path.c_str(), std::ios::binary);
497 cereal::JSONOutputArchive oarchive(os);
498
499 oarchive(ChassisInherit::lastStateChangeTime(),
500 ChassisInherit::currentPowerState());
501}
502
503bool Chassis::deserializeStateChangeTime(uint64_t& time, PowerState& state)
504{
505 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
506
507 try
508 {
509 if (fs::exists(path))
510 {
511 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
512 cereal::JSONInputArchive iarchive(is);
513 iarchive(time, state);
514 return true;
515 }
516 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500517 catch (const std::exception& e)
Matt Spinler9eab9862018-07-11 14:13:52 -0500518 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500519 error("deserialize exception: {ERROR}", "ERROR", e);
Matt Spinler9eab9862018-07-11 14:13:52 -0500520 fs::remove(path);
521 }
522
523 return false;
524}
525
526void Chassis::restoreChassisStateChangeTime()
527{
528 uint64_t time;
529 PowerState state;
530
531 if (!deserializeStateChangeTime(time, state))
532 {
533 ChassisInherit::lastStateChangeTime(0);
534 }
535 else
536 {
537 ChassisInherit::lastStateChangeTime(time);
538 }
539}
540
541void Chassis::setStateChangeTime()
542{
543 using namespace std::chrono;
544 uint64_t lastTime;
545 PowerState lastState;
546
547 auto now =
548 duration_cast<milliseconds>(system_clock::now().time_since_epoch())
549 .count();
550
551 // If power is on when the BMC is rebooted, this function will get called
552 // because sysStateChange() runs. Since the power state didn't change
553 // in this case, neither should the state change time, so check that
554 // the power state actually did change here.
555 if (deserializeStateChangeTime(lastTime, lastState))
556 {
557 if (lastState == ChassisInherit::currentPowerState())
558 {
559 return;
560 }
561 }
562
563 ChassisInherit::lastStateChangeTime(now);
564 serializeStateChangeTime();
565}
566
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500567bool Chassis::standbyVoltageRegulatorFault()
568{
569 bool regulatorFault = false;
570
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600571 // find standby voltage regulator fault via gpiog
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500572
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600573 auto gpioval = utils::getGpioValue("regulator-standby-faulted");
574
575 if (-1 == gpioval)
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500576 {
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600577 error("Failed reading regulator-standby-faulted GPIO");
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500578 }
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600579
580 if (1 == gpioval)
581 {
582 info("Detected standby voltage regulator fault");
583 regulatorFault = true;
584 }
585
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500586 return regulatorFault;
587}
588
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600589} // namespace manager
590} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700591} // namespace phosphor