blob: 1da1130cbb967a8e44ee0571c44240aa8b7bed98 [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";
Matthew Barthbe6efab2022-03-01 13:21:45 -060040constexpr auto RESET_HOST_SENSORS_SVC =
41 "phosphor-reset-sensor-states@0.service";
Andrew Geissler0029a5d2017-01-24 14:48:35 -060042
Josh D. King697474c2017-03-02 11:15:55 -060043constexpr auto ACTIVE_STATE = "active";
44constexpr auto ACTIVATING_STATE = "activating";
45
Andrew Geissler2cf2a262022-02-02 14:38:41 -060046// Details at https://upower.freedesktop.org/docs/Device.html
47constexpr uint TYPE_UPS = 3;
48constexpr uint STATE_FULLY_CHARGED = 4;
49constexpr uint BATTERY_LVL_FULL = 8;
50
Andrew Geisslerce80f242017-01-24 13:25:33 -060051/* Map a transition to it's systemd target */
Andrew Geissler58a18012018-01-19 19:36:05 -080052const std::map<server::Chassis::Transition, std::string> SYSTEMD_TARGET_TABLE =
53 {
Andrew Geissler8cf2f9a2017-07-21 11:58:04 -050054 // Use the hard off target to ensure we shutdown immediately
55 {server::Chassis::Transition::Off, CHASSIS_STATE_HARD_POWEROFF_TGT},
Andrew Geissler58a18012018-01-19 19:36:05 -080056 {server::Chassis::Transition::On, CHASSIS_STATE_POWERON_TGT}};
Andrew Geisslerce80f242017-01-24 13:25:33 -060057
Andrew Geissler58a18012018-01-19 19:36:05 -080058constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
59constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Andrew Geisslerce80f242017-01-24 13:25:33 -060060constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
61
Josh D. King697474c2017-03-02 11:15:55 -060062constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
63constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
64
Andrew Geissler8b1f8622022-01-28 16:37:07 -060065constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
66constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
67constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
68constexpr auto UPOWER_INTERFACE = "org.freedesktop.UPower.Device";
69constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
70
Andrew Geissler0029a5d2017-01-24 14:48:35 -060071void Chassis::subscribeToSystemdSignals()
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060072{
Andrew Geissler3a30b052019-05-14 15:54:37 -050073 try
74 {
75 auto method = this->bus.new_method_call(
76 SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, SYSTEMD_INTERFACE, "Subscribe");
Andrew Geissler5b950272019-05-24 12:27:51 -050077 this->bus.call(method);
Andrew Geissler3a30b052019-05-14 15:54:37 -050078 }
Andrew Geissler8ffdb262021-09-20 15:25:19 -050079 catch (const sdbusplus::exception::exception& e)
Andrew Geissler3a30b052019-05-14 15:54:37 -050080 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050081 error("Failed to subscribe to systemd signals: {ERROR}", "ERROR", e);
Andrew Geissler3a30b052019-05-14 15:54:37 -050082 elog<InternalFailure>();
83 }
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060084
Andrew Geissler0029a5d2017-01-24 14:48:35 -060085 return;
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060086}
87
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060088// TODO - Will be rewritten once sdbusplus client bindings are in place
89// and persistent storage design is in place and sdbusplus
90// has read property function
91void Chassis::determineInitialState()
92{
Andrew Geissler2cf2a262022-02-02 14:38:41 -060093
94 // Monitor for any properties changed signals on UPower device path
95 uPowerPropChangeSignal = std::make_unique<sdbusplus::bus::match_t>(
96 bus,
97 sdbusplus::bus::match::rules::propertiesChangedNamespace(
98 "/org/freedesktop/UPower", UPOWER_INTERFACE),
99 [this](auto& msg) { this->uPowerChangeEvent(msg); });
100
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600101 determineStatusOfPower();
102
Patrick Williams2975e262020-05-13 18:01:09 -0500103 std::variant<int> pgood = -1;
Andrew Geissler58a18012018-01-19 19:36:05 -0800104 auto method = this->bus.new_method_call(
105 "org.openbmc.control.Power", "/org/openbmc/control/power0",
106 "org.freedesktop.DBus.Properties", "Get");
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600107
108 method.append("org.openbmc.control.Power", "pgood");
William A. Kennington III09568ff2018-05-11 00:03:12 -0700109 try
110 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700111 auto reply = this->bus.call(method);
Anthony Wilson32c532e2018-10-25 21:56:07 -0500112 reply.read(pgood);
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700113
Patrick Williams37413dc2020-05-13 11:29:54 -0500114 if (std::get<int>(pgood) == 1)
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700115 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500116 info("Initial Chassis State will be On");
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700117 server::Chassis::currentPowerState(PowerState::On);
118 server::Chassis::requestedPowerTransition(Transition::On);
119 return;
120 }
Matt Spinler9eab9862018-07-11 14:13:52 -0500121 else
122 {
123 // The system is off. If we think it should be on then
124 // we probably lost AC while up, so set a new state
125 // change time.
126 uint64_t lastTime;
127 PowerState lastState;
128
129 if (deserializeStateChangeTime(lastTime, lastState))
130 {
Andrew Geissler7ed36232022-01-26 13:49:28 -0600131 // If power was on before the BMC reboot and the reboot reason
132 // was not a pinhole reset, log an error
Matt Spinler9eab9862018-07-11 14:13:52 -0500133 if (lastState == PowerState::On)
134 {
Andrew Geissler7ed36232022-01-26 13:49:28 -0600135 info(
136 "Chassis power was on before the BMC reboot and it is off now");
Matthew Barthbe6efab2022-03-01 13:21:45 -0600137
138 // Reset host sensors since system is off now
139 startUnit(RESET_HOST_SENSORS_SVC);
140
Matt Spinler9eab9862018-07-11 14:13:52 -0500141 setStateChangeTime();
Andrew Geissler7ed36232022-01-26 13:49:28 -0600142
Brandon Wyman4fe860f2022-03-16 00:56:53 +0000143 // 0 indicates pinhole reset. 1 is NOT pinhole reset
Andrew Geissler7ed36232022-01-26 13:49:28 -0600144 if (phosphor::state::manager::utils::getGpioValue(
Brandon Wyman4fe860f2022-03-16 00:56:53 +0000145 "reset-cause-pinhole") != 0)
Andrew Geissler7ed36232022-01-26 13:49:28 -0600146 {
147 if (standbyVoltageRegulatorFault())
148 {
149 report<Regulator>();
150 }
151 else
152 {
153 report<Blackout>();
154 }
155 }
Brandon Wyman4fe860f2022-03-16 00:56:53 +0000156 else
157 {
158 info("Pinhole reset");
159 }
Matt Spinler9eab9862018-07-11 14:13:52 -0500160 }
161 }
162 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700163 }
Patrick Williams0a675212021-09-02 09:49:43 -0500164 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700165 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700166 // It's acceptable for the pgood state service to not be available
167 // since it will notify us of the pgood state when it comes up.
168 if (e.name() != nullptr &&
169 strcmp("org.freedesktop.DBus.Error.ServiceUnknown", e.name()) == 0)
170 {
171 goto fail;
172 }
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600173
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700174 // Only log for unexpected error types.
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500175 error("Error performing call to get pgood: {ERROR}", "ERROR", e);
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700176 goto fail;
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600177 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700178
179fail:
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500180 info("Initial Chassis State will be Off");
William A. Kennington III09568ff2018-05-11 00:03:12 -0700181 server::Chassis::currentPowerState(PowerState::Off);
182 server::Chassis::requestedPowerTransition(Transition::Off);
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600183
184 return;
185}
186
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600187void Chassis::determineStatusOfPower()
188{
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600189 // Default PowerStatus to good
190 server::Chassis::currentPowerStatus(PowerStatus::Good);
191
192 // Find all implementations of the UPower interface
193 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
194 MAPPER_INTERFACE, "GetSubTree");
195
196 mapper.append("/", 0, std::vector<std::string>({UPOWER_INTERFACE}));
197
198 std::map<std::string, std::map<std::string, std::vector<std::string>>>
199 mapperResponse;
200
201 try
202 {
203 auto mapperResponseMsg = bus.call(mapper);
204 mapperResponseMsg.read(mapperResponse);
205 }
206 catch (const sdbusplus::exception::exception& e)
207 {
208 error("Error in mapper GetSubTree call for UPS: {ERROR}", "ERROR", e);
209 throw;
210 }
211
212 if (mapperResponse.empty())
213 {
214 debug("No UPower devices found in system");
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600215 }
216
217 // Iterate through all returned Upower interfaces and look for UPS's
218 for (const auto& [path, services] : mapperResponse)
219 {
220 for (const auto& serviceIter : services)
221 {
222 const std::string& service = serviceIter.first;
223
224 try
225 {
226 auto method = bus.new_method_call(service.c_str(), path.c_str(),
227 PROPERTY_INTERFACE, "GetAll");
228 method.append(UPOWER_INTERFACE);
229
230 auto response = bus.call(method);
231 using Property = std::string;
232 using Value = std::variant<bool, uint>;
233 using PropertyMap = std::map<Property, Value>;
234 PropertyMap properties;
235 response.read(properties);
236
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600237 if (std::get<uint>(properties["Type"]) != TYPE_UPS)
238 {
239 info("UPower device {OBJ_PATH} is not a UPS device",
240 "OBJ_PATH", path);
241 continue;
242 }
243
Andrew Geissler2cf2a262022-02-02 14:38:41 -0600244 if (std::get<bool>(properties["IsPresent"]) != true)
245 {
246 // There is a UPS detected but it is not officially
247 // "present" yet. Monitor it for state change.
248 info("UPower device {OBJ_PATH} is not present", "OBJ_PATH",
249 path);
250 continue;
251 }
252
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600253 if (std::get<uint>(properties["State"]) == STATE_FULLY_CHARGED)
254 {
255 info("UPS is fully charged");
256 }
257 else
258 {
259 info("UPS is not fully charged: {UPS_STATE}", "UPS_STATE",
260 std::get<uint>(properties["State"]));
261 server::Chassis::currentPowerStatus(
262 PowerStatus::UninterruptiblePowerSupply);
263 return;
264 }
265
266 if (std::get<uint>(properties["BatteryLevel"]) ==
267 BATTERY_LVL_FULL)
268 {
269 info("UPS Battery Level is Full");
Andrew Geissler2cf2a262022-02-02 14:38:41 -0600270 // Only one UPS per system, we've found it and it's all
271 // good so exit function
272 return;
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600273 }
274 else
275 {
276 info("UPS Battery Level is Low: {UPS_BAT_LEVEL}",
277 "UPS_BAT_LEVEL",
278 std::get<uint>(properties["BatteryLevel"]));
279 server::Chassis::currentPowerStatus(
280 PowerStatus::UninterruptiblePowerSupply);
281 return;
282 }
283 }
284 catch (const sdbusplus::exception::exception& e)
285 {
286 error("Error reading UPS property, error: {ERROR}, "
287 "service: {SERVICE} path: {PATH}",
288 "ERROR", e, "SERVICE", service, "PATH", path);
289 throw;
290 }
291 }
292 }
293 return;
294}
295
Andrew Geissler2cf2a262022-02-02 14:38:41 -0600296void Chassis::uPowerChangeEvent(sdbusplus::message::message& msg)
297{
298 debug("UPS Property Change Event Triggered");
299 std::string statusInterface;
300 std::map<std::string, std::variant<uint, bool>> msgData;
301 msg.read(statusInterface, msgData);
302
303 // If the change is to any of the three properties we are interested in
304 // then call determineStatusOfPower() to see if a power status change
305 // is needed
306 auto propertyMap = msgData.find("IsPresent");
307 if (propertyMap != msgData.end())
308 {
309 info("UPS presence changed to {UPS_PRES_INFO}", "UPS_PRES_INFO",
310 std::get<bool>(propertyMap->second));
311 determineStatusOfPower();
312 return;
313 }
314
315 propertyMap = msgData.find("State");
316 if (propertyMap != msgData.end())
317 {
318 info("UPS State changed to {UPS_STATE}", "UPS_STATE",
319 std::get<uint>(propertyMap->second));
320 determineStatusOfPower();
321 return;
322 }
323
324 propertyMap = msgData.find("BatteryLevel");
325 if (propertyMap != msgData.end())
326 {
327 info("UPS BatteryLevel changed to {UPS_BAT_LEVEL}", "UPS_BAT_LEVEL",
328 std::get<uint>(propertyMap->second));
329 determineStatusOfPower();
330 return;
331 }
332 return;
333}
334
Matthew Barthbe6efab2022-03-01 13:21:45 -0600335void Chassis::startUnit(const std::string& sysdUnit)
Andrew Geisslerce80f242017-01-24 13:25:33 -0600336{
Andrew Geissler58a18012018-01-19 19:36:05 -0800337 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
338 SYSTEMD_INTERFACE, "StartUnit");
Andrew Geisslerce80f242017-01-24 13:25:33 -0600339
Matthew Barthbe6efab2022-03-01 13:21:45 -0600340 method.append(sysdUnit);
Andrew Geisslerce80f242017-01-24 13:25:33 -0600341 method.append("replace");
342
343 this->bus.call_noreply(method);
344
345 return;
346}
347
Josh D. King697474c2017-03-02 11:15:55 -0600348bool Chassis::stateActive(const std::string& target)
349{
Patrick Williams2975e262020-05-13 18:01:09 -0500350 std::variant<std::string> currentState;
Josh D. King697474c2017-03-02 11:15:55 -0600351 sdbusplus::message::object_path unitTargetPath;
352
Andrew Geissler58a18012018-01-19 19:36:05 -0800353 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
354 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King697474c2017-03-02 11:15:55 -0600355
356 method.append(target);
Josh D. King697474c2017-03-02 11:15:55 -0600357
William A. Kennington III09568ff2018-05-11 00:03:12 -0700358 try
359 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500360 auto result = this->bus.call(method);
William A. Kennington III09568ff2018-05-11 00:03:12 -0700361 result.read(unitTargetPath);
362 }
Patrick Williams0a675212021-09-02 09:49:43 -0500363 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700364 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500365 error("Error in GetUnit call: {ERROR}", "ERROR", e);
William A. Kennington III09568ff2018-05-11 00:03:12 -0700366 return false;
367 }
Josh D. King697474c2017-03-02 11:15:55 -0600368
Andrew Geissler58a18012018-01-19 19:36:05 -0800369 method = this->bus.new_method_call(
370 SYSTEMD_SERVICE,
371 static_cast<const std::string&>(unitTargetPath).c_str(),
372 SYSTEMD_PROPERTY_IFACE, "Get");
Josh D. King697474c2017-03-02 11:15:55 -0600373
374 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
Josh D. King697474c2017-03-02 11:15:55 -0600375
Anthony Wilson32c532e2018-10-25 21:56:07 -0500376 try
Josh D. King697474c2017-03-02 11:15:55 -0600377 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500378 auto result = this->bus.call(method);
379 result.read(currentState);
380 }
Patrick Williams0a675212021-09-02 09:49:43 -0500381 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500382 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500383 error("Error in ActiveState Get: {ERROR}", "ERROR", e);
Josh D. King697474c2017-03-02 11:15:55 -0600384 return false;
385 }
386
Patrick Williams37413dc2020-05-13 11:29:54 -0500387 const auto& currentStateStr = std::get<std::string>(currentState);
William A. Kennington III7a0689a2018-11-12 17:19:33 -0800388 return currentStateStr == ACTIVE_STATE ||
389 currentStateStr == ACTIVATING_STATE;
Josh D. King697474c2017-03-02 11:15:55 -0600390}
391
Patrick Williams8f8ba392017-05-05 15:47:39 -0500392int Chassis::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600393{
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600394 sdbusplus::message::object_path newStateObjPath;
395 std::string newStateUnit{};
396 std::string newStateResult{};
397
Andrew Geissler58a18012018-01-19 19:36:05 -0800398 // Read the msg and populate each variable
William A. Kennington III09568ff2018-05-11 00:03:12 -0700399 try
400 {
Andrew Geissler9b8af4f2019-09-12 14:19:14 -0500401 // newStateID is a throwaway that is needed in order to read the
402 // parameters that are useful out of the dbus message
403 uint32_t newStateID{};
William A. Kennington III09568ff2018-05-11 00:03:12 -0700404 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
405 }
Patrick Williams0a675212021-09-02 09:49:43 -0500406 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700407 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500408 error("Error in state change - bad encoding: {ERROR} {REPLY_SIG}",
409 "ERROR", e, "REPLY_SIG", msg.get_signature());
William A. Kennington III09568ff2018-05-11 00:03:12 -0700410 return 0;
411 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600412
Andrew Geissler58a18012018-01-19 19:36:05 -0800413 if ((newStateUnit == CHASSIS_STATE_POWEROFF_TGT) &&
414 (newStateResult == "done") && (!stateActive(CHASSIS_STATE_POWERON_TGT)))
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600415 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500416 info("Received signal that power OFF is complete");
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600417 this->currentPowerState(server::Chassis::PowerState::Off);
Matt Spinler9eab9862018-07-11 14:13:52 -0500418 this->setStateChangeTime();
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600419 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800420 else if ((newStateUnit == CHASSIS_STATE_POWERON_TGT) &&
421 (newStateResult == "done") &&
422 (stateActive(CHASSIS_STATE_POWERON_TGT)))
423 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500424 info("Received signal that power ON is complete");
Andrew Geissler58a18012018-01-19 19:36:05 -0800425 this->currentPowerState(server::Chassis::PowerState::On);
Matt Spinler9eab9862018-07-11 14:13:52 -0500426 this->setStateChangeTime();
Andrew Geisslerf2b22e82021-03-12 14:47:03 -0600427
428 // Remove temporary file which is utilized for scenarios where the
429 // BMC is rebooted while the chassis power is still on.
430 // This file is used to indicate to chassis related systemd services
431 // that the chassis is already on and they should skip running.
432 // Once the chassis state is back to on we can clear this file.
433 auto size = std::snprintf(nullptr, 0, CHASSIS_ON_FILE, 0);
434 size++; // null
435 std::unique_ptr<char[]> chassisFile(new char[size]);
436 std::snprintf(chassisFile.get(), size, CHASSIS_ON_FILE, 0);
437 if (std::filesystem::exists(chassisFile.get()))
438 {
439 std::filesystem::remove(chassisFile.get());
440 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800441 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600442
443 return 0;
444}
445
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600446Chassis::Transition Chassis::requestedPowerTransition(Transition value)
447{
448
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500449 info("Change to Chassis Requested Power State: {REQ_POWER_TRAN}",
450 "REQ_POWER_TRAN", value);
Matthew Barthbe6efab2022-03-01 13:21:45 -0600451 startUnit(SYSTEMD_TARGET_TABLE.find(value)->second);
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600452 return server::Chassis::requestedPowerTransition(value);
453}
454
455Chassis::PowerState Chassis::currentPowerState(PowerState value)
456{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500457 PowerState chassisPowerState;
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500458 info("Change to Chassis Power State: {CUR_POWER_STATE}", "CUR_POWER_STATE",
459 value);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500460
461 chassisPowerState = server::Chassis::currentPowerState(value);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500462 pohTimer.setEnabled(chassisPowerState == PowerState::On);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500463 return chassisPowerState;
464}
465
Patrick Williams45a1ed72021-04-30 21:02:43 -0500466uint32_t Chassis::pohCounter(uint32_t value)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500467{
Patrick Williams45a1ed72021-04-30 21:02:43 -0500468 if (value != pohCounter())
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500469 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500470 ChassisInherit::pohCounter(value);
Matt Spinler81957842018-07-11 10:37:12 -0500471 serializePOH();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500472 }
Patrick Williams45a1ed72021-04-30 21:02:43 -0500473 return pohCounter();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500474}
475
Patrick Williams45a1ed72021-04-30 21:02:43 -0500476void Chassis::pohCallback()
William A. Kennington IIId998f822018-10-17 23:17:57 -0700477{
478 if (ChassisInherit::currentPowerState() == PowerState::On)
479 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500480 pohCounter(pohCounter() + 1);
William A. Kennington IIId998f822018-10-17 23:17:57 -0700481 }
482}
483
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500484void Chassis::restorePOHCounter()
485{
486 uint32_t counter;
Matt Spinler81957842018-07-11 10:37:12 -0500487 if (!deserializePOH(POH_COUNTER_PERSIST_PATH, counter))
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500488 {
489 // set to default value
Patrick Williams45a1ed72021-04-30 21:02:43 -0500490 pohCounter(0);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500491 }
492 else
493 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500494 pohCounter(counter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500495 }
496}
497
Matt Spinler81957842018-07-11 10:37:12 -0500498fs::path Chassis::serializePOH(const fs::path& path)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500499{
500 std::ofstream os(path.c_str(), std::ios::binary);
501 cereal::JSONOutputArchive oarchive(os);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500502 oarchive(pohCounter());
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500503 return path;
504}
505
Patrick Williams45a1ed72021-04-30 21:02:43 -0500506bool Chassis::deserializePOH(const fs::path& path, uint32_t& pohCounter)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500507{
508 try
509 {
510 if (fs::exists(path))
511 {
512 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
513 cereal::JSONInputArchive iarchive(is);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500514 iarchive(pohCounter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500515 return true;
516 }
517 return false;
518 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500519 catch (const cereal::Exception& e)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500520 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500521 error("deserialize exception: {ERROR}", "ERROR", e);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500522 fs::remove(path);
523 return false;
524 }
525 catch (const fs::filesystem_error& e)
526 {
527 return false;
528 }
529
530 return false;
531}
532
533void Chassis::startPOHCounter()
534{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500535 auto dir = fs::path(POH_COUNTER_PERSIST_PATH).parent_path();
536 fs::create_directories(dir);
537
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500538 try
539 {
William A. Kennington IIId998f822018-10-17 23:17:57 -0700540 auto event = sdeventplus::Event::get_default();
541 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
542 event.loop();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500543 }
William A. Kennington IIId998f822018-10-17 23:17:57 -0700544 catch (const sdeventplus::SdEventError& e)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500545 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500546 error("Error occurred during the sdeventplus loop: {ERROR}", "ERROR",
547 e);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500548 phosphor::logging::commit<InternalFailure>();
549 }
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600550}
551
Matt Spinler9eab9862018-07-11 14:13:52 -0500552void Chassis::serializeStateChangeTime()
553{
554 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
555 std::ofstream os(path.c_str(), std::ios::binary);
556 cereal::JSONOutputArchive oarchive(os);
557
558 oarchive(ChassisInherit::lastStateChangeTime(),
559 ChassisInherit::currentPowerState());
560}
561
562bool Chassis::deserializeStateChangeTime(uint64_t& time, PowerState& state)
563{
564 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
565
566 try
567 {
568 if (fs::exists(path))
569 {
570 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
571 cereal::JSONInputArchive iarchive(is);
572 iarchive(time, state);
573 return true;
574 }
575 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500576 catch (const std::exception& e)
Matt Spinler9eab9862018-07-11 14:13:52 -0500577 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500578 error("deserialize exception: {ERROR}", "ERROR", e);
Matt Spinler9eab9862018-07-11 14:13:52 -0500579 fs::remove(path);
580 }
581
582 return false;
583}
584
585void Chassis::restoreChassisStateChangeTime()
586{
587 uint64_t time;
588 PowerState state;
589
590 if (!deserializeStateChangeTime(time, state))
591 {
592 ChassisInherit::lastStateChangeTime(0);
593 }
594 else
595 {
596 ChassisInherit::lastStateChangeTime(time);
597 }
598}
599
600void Chassis::setStateChangeTime()
601{
602 using namespace std::chrono;
603 uint64_t lastTime;
604 PowerState lastState;
605
606 auto now =
607 duration_cast<milliseconds>(system_clock::now().time_since_epoch())
608 .count();
609
610 // If power is on when the BMC is rebooted, this function will get called
611 // because sysStateChange() runs. Since the power state didn't change
612 // in this case, neither should the state change time, so check that
613 // the power state actually did change here.
614 if (deserializeStateChangeTime(lastTime, lastState))
615 {
616 if (lastState == ChassisInherit::currentPowerState())
617 {
618 return;
619 }
620 }
621
622 ChassisInherit::lastStateChangeTime(now);
623 serializeStateChangeTime();
624}
625
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500626bool Chassis::standbyVoltageRegulatorFault()
627{
628 bool regulatorFault = false;
629
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600630 // find standby voltage regulator fault via gpiog
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500631
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600632 auto gpioval = utils::getGpioValue("regulator-standby-faulted");
633
634 if (-1 == gpioval)
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500635 {
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600636 error("Failed reading regulator-standby-faulted GPIO");
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500637 }
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600638
639 if (1 == gpioval)
640 {
641 info("Detected standby voltage regulator fault");
642 regulatorFault = true;
643 }
644
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500645 return regulatorFault;
646}
647
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600648} // namespace manager
649} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700650} // namespace phosphor