blob: fc1abac69a9bbf9f2db3e34781ebb338196605a8 [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
Potin Lai70f36d82022-03-15 10:25:39 +08009#include <fmt/format.h>
10
Andrew Geisslere426b582020-05-28 12:40:55 -050011#include <cereal/archives/json.hpp>
12#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler8ffdb262021-09-20 15:25:19 -050013#include <phosphor-logging/lg2.hpp>
Andrew Geissler0029a5d2017-01-24 14:48:35 -060014#include <sdbusplus/bus.hpp>
William A. Kennington III09568ff2018-05-11 00:03:12 -070015#include <sdbusplus/exception.hpp>
William A. Kennington IIId998f822018-10-17 23:17:57 -070016#include <sdeventplus/event.hpp>
17#include <sdeventplus/exception.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -050018
Andrew Geisslerf2b22e82021-03-12 14:47:03 -060019#include <filesystem>
Andrew Geisslere426b582020-05-28 12:40:55 -050020#include <fstream>
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -050021
Andrew Geisslera90a31a2016-12-13 16:16:28 -060022namespace phosphor
23{
24namespace state
25{
26namespace manager
27{
28
Andrew Geissler8ffdb262021-09-20 15:25:19 -050029PHOSPHOR_LOG2_USING;
30
Andrew Geisslera90a31a2016-12-13 16:16:28 -060031// When you see server:: you know we're referencing our base class
32namespace server = sdbusplus::xyz::openbmc_project::State::server;
33
34using namespace phosphor::logging;
William A. Kennington IIId998f822018-10-17 23:17:57 -070035using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Aatir Manzur27115ae2019-07-23 16:25:38 -050036using sdbusplus::xyz::openbmc_project::State::Shutdown::Power::Error::Blackout;
Ben Tyner2c36e5a2021-07-12 14:56:49 -050037using sdbusplus::xyz::openbmc_project::State::Shutdown::Power::Error::Regulator;
Potin Lai70f36d82022-03-15 10:25:39 +080038constexpr auto CHASSIS_STATE_POWEROFF_TGT_FMT =
39 "obmc-chassis-poweroff@{}.target";
40constexpr auto CHASSIS_STATE_HARD_POWEROFF_TGT_FMT =
41 "obmc-chassis-hard-poweroff@{}.target";
42constexpr auto CHASSIS_STATE_POWERON_TGT_FMT = "obmc-chassis-poweron@{}.target";
43constexpr auto RESET_HOST_SENSORS_SVC_FMT =
44 "phosphor-reset-sensor-states@{}.service";
Josh D. King697474c2017-03-02 11:15:55 -060045constexpr auto ACTIVE_STATE = "active";
46constexpr auto ACTIVATING_STATE = "activating";
47
Andrew Geissler2cf2a262022-02-02 14:38:41 -060048// Details at https://upower.freedesktop.org/docs/Device.html
49constexpr uint TYPE_UPS = 3;
50constexpr uint STATE_FULLY_CHARGED = 4;
51constexpr uint BATTERY_LVL_FULL = 8;
52
Andrew Geissler58a18012018-01-19 19:36:05 -080053constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
54constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Andrew Geisslerce80f242017-01-24 13:25:33 -060055constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
56
Josh D. King697474c2017-03-02 11:15:55 -060057constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
58constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
59
Andrew Geissler8b1f8622022-01-28 16:37:07 -060060constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
61constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
62constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
63constexpr auto UPOWER_INTERFACE = "org.freedesktop.UPower.Device";
64constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
65
Andrew Geissler0029a5d2017-01-24 14:48:35 -060066void Chassis::subscribeToSystemdSignals()
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060067{
Andrew Geissler3a30b052019-05-14 15:54:37 -050068 try
69 {
70 auto method = this->bus.new_method_call(
71 SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, SYSTEMD_INTERFACE, "Subscribe");
Andrew Geissler5b950272019-05-24 12:27:51 -050072 this->bus.call(method);
Andrew Geissler3a30b052019-05-14 15:54:37 -050073 }
Andrew Geissler8ffdb262021-09-20 15:25:19 -050074 catch (const sdbusplus::exception::exception& e)
Andrew Geissler3a30b052019-05-14 15:54:37 -050075 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050076 error("Failed to subscribe to systemd signals: {ERROR}", "ERROR", e);
Andrew Geissler3a30b052019-05-14 15:54:37 -050077 elog<InternalFailure>();
78 }
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060079
Andrew Geissler0029a5d2017-01-24 14:48:35 -060080 return;
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060081}
82
Potin Lai70f36d82022-03-15 10:25:39 +080083void Chassis::createSystemdTargetTable()
84{
85 systemdTargetTable = {
86 // Use the hard off target to ensure we shutdown immediately
87 {Transition::Off, fmt::format(CHASSIS_STATE_HARD_POWEROFF_TGT_FMT, id)},
88 {Transition::On, fmt::format(CHASSIS_STATE_POWERON_TGT_FMT, id)}};
89}
90
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060091// TODO - Will be rewritten once sdbusplus client bindings are in place
92// and persistent storage design is in place and sdbusplus
93// has read property function
94void Chassis::determineInitialState()
95{
Andrew Geissler2cf2a262022-02-02 14:38:41 -060096
97 // Monitor for any properties changed signals on UPower device path
98 uPowerPropChangeSignal = std::make_unique<sdbusplus::bus::match_t>(
99 bus,
100 sdbusplus::bus::match::rules::propertiesChangedNamespace(
101 "/org/freedesktop/UPower", UPOWER_INTERFACE),
102 [this](auto& msg) { this->uPowerChangeEvent(msg); });
103
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600104 determineStatusOfPower();
105
Patrick Williams2975e262020-05-13 18:01:09 -0500106 std::variant<int> pgood = -1;
Andrew Geissler58a18012018-01-19 19:36:05 -0800107 auto method = this->bus.new_method_call(
108 "org.openbmc.control.Power", "/org/openbmc/control/power0",
109 "org.freedesktop.DBus.Properties", "Get");
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600110
111 method.append("org.openbmc.control.Power", "pgood");
William A. Kennington III09568ff2018-05-11 00:03:12 -0700112 try
113 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700114 auto reply = this->bus.call(method);
Anthony Wilson32c532e2018-10-25 21:56:07 -0500115 reply.read(pgood);
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700116
Patrick Williams37413dc2020-05-13 11:29:54 -0500117 if (std::get<int>(pgood) == 1)
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700118 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500119 info("Initial Chassis State will be On");
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700120 server::Chassis::currentPowerState(PowerState::On);
121 server::Chassis::requestedPowerTransition(Transition::On);
122 return;
123 }
Matt Spinler9eab9862018-07-11 14:13:52 -0500124 else
125 {
126 // The system is off. If we think it should be on then
127 // we probably lost AC while up, so set a new state
128 // change time.
129 uint64_t lastTime;
130 PowerState lastState;
131
132 if (deserializeStateChangeTime(lastTime, lastState))
133 {
Andrew Geissler7ed36232022-01-26 13:49:28 -0600134 // If power was on before the BMC reboot and the reboot reason
135 // was not a pinhole reset, log an error
Matt Spinler9eab9862018-07-11 14:13:52 -0500136 if (lastState == PowerState::On)
137 {
Andrew Geissler7ed36232022-01-26 13:49:28 -0600138 info(
139 "Chassis power was on before the BMC reboot and it is off now");
Matthew Barthbe6efab2022-03-01 13:21:45 -0600140
141 // Reset host sensors since system is off now
Potin Lai70f36d82022-03-15 10:25:39 +0800142 startUnit(fmt::format(RESET_HOST_SENSORS_SVC_FMT, id));
Matthew Barthbe6efab2022-03-01 13:21:45 -0600143
Matt Spinler9eab9862018-07-11 14:13:52 -0500144 setStateChangeTime();
Andrew Geissler7ed36232022-01-26 13:49:28 -0600145
Brandon Wyman4fe860f2022-03-16 00:56:53 +0000146 // 0 indicates pinhole reset. 1 is NOT pinhole reset
Andrew Geissler7ed36232022-01-26 13:49:28 -0600147 if (phosphor::state::manager::utils::getGpioValue(
Brandon Wyman4fe860f2022-03-16 00:56:53 +0000148 "reset-cause-pinhole") != 0)
Andrew Geissler7ed36232022-01-26 13:49:28 -0600149 {
150 if (standbyVoltageRegulatorFault())
151 {
152 report<Regulator>();
153 }
154 else
155 {
Mike Capps073fa2b2022-03-15 16:06:45 -0400156 report<Blackout>(Entry::Level::Critical);
Andrew Geissler7ed36232022-01-26 13:49:28 -0600157 }
158 }
Brandon Wyman4fe860f2022-03-16 00:56:53 +0000159 else
160 {
161 info("Pinhole reset");
162 }
Matt Spinler9eab9862018-07-11 14:13:52 -0500163 }
164 }
165 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700166 }
Patrick Williams0a675212021-09-02 09:49:43 -0500167 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700168 {
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700169 // It's acceptable for the pgood state service to not be available
170 // since it will notify us of the pgood state when it comes up.
171 if (e.name() != nullptr &&
172 strcmp("org.freedesktop.DBus.Error.ServiceUnknown", e.name()) == 0)
173 {
174 goto fail;
175 }
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600176
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700177 // Only log for unexpected error types.
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500178 error("Error performing call to get pgood: {ERROR}", "ERROR", e);
William A. Kennington III9a2f37c2018-06-28 16:18:37 -0700179 goto fail;
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600180 }
William A. Kennington III09568ff2018-05-11 00:03:12 -0700181
182fail:
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500183 info("Initial Chassis State will be Off");
William A. Kennington III09568ff2018-05-11 00:03:12 -0700184 server::Chassis::currentPowerState(PowerState::Off);
185 server::Chassis::requestedPowerTransition(Transition::Off);
Andrew Geisslerdff50ed2016-12-13 20:39:04 -0600186
187 return;
188}
189
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600190void Chassis::determineStatusOfPower()
191{
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600192 // Default PowerStatus to good
193 server::Chassis::currentPowerStatus(PowerStatus::Good);
194
195 // Find all implementations of the UPower interface
196 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
197 MAPPER_INTERFACE, "GetSubTree");
198
199 mapper.append("/", 0, std::vector<std::string>({UPOWER_INTERFACE}));
200
201 std::map<std::string, std::map<std::string, std::vector<std::string>>>
202 mapperResponse;
203
204 try
205 {
206 auto mapperResponseMsg = bus.call(mapper);
207 mapperResponseMsg.read(mapperResponse);
208 }
209 catch (const sdbusplus::exception::exception& e)
210 {
211 error("Error in mapper GetSubTree call for UPS: {ERROR}", "ERROR", e);
212 throw;
213 }
214
215 if (mapperResponse.empty())
216 {
217 debug("No UPower devices found in system");
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600218 }
219
220 // Iterate through all returned Upower interfaces and look for UPS's
221 for (const auto& [path, services] : mapperResponse)
222 {
223 for (const auto& serviceIter : services)
224 {
225 const std::string& service = serviceIter.first;
226
227 try
228 {
229 auto method = bus.new_method_call(service.c_str(), path.c_str(),
230 PROPERTY_INTERFACE, "GetAll");
231 method.append(UPOWER_INTERFACE);
232
233 auto response = bus.call(method);
234 using Property = std::string;
235 using Value = std::variant<bool, uint>;
236 using PropertyMap = std::map<Property, Value>;
237 PropertyMap properties;
238 response.read(properties);
239
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600240 if (std::get<uint>(properties["Type"]) != TYPE_UPS)
241 {
242 info("UPower device {OBJ_PATH} is not a UPS device",
243 "OBJ_PATH", path);
244 continue;
245 }
246
Andrew Geissler2cf2a262022-02-02 14:38:41 -0600247 if (std::get<bool>(properties["IsPresent"]) != true)
248 {
249 // There is a UPS detected but it is not officially
250 // "present" yet. Monitor it for state change.
251 info("UPower device {OBJ_PATH} is not present", "OBJ_PATH",
252 path);
253 continue;
254 }
255
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600256 if (std::get<uint>(properties["State"]) == STATE_FULLY_CHARGED)
257 {
258 info("UPS is fully charged");
259 }
260 else
261 {
262 info("UPS is not fully charged: {UPS_STATE}", "UPS_STATE",
263 std::get<uint>(properties["State"]));
264 server::Chassis::currentPowerStatus(
265 PowerStatus::UninterruptiblePowerSupply);
266 return;
267 }
268
269 if (std::get<uint>(properties["BatteryLevel"]) ==
270 BATTERY_LVL_FULL)
271 {
272 info("UPS Battery Level is Full");
Andrew Geissler2cf2a262022-02-02 14:38:41 -0600273 // Only one UPS per system, we've found it and it's all
274 // good so exit function
275 return;
Andrew Geissler8b1f8622022-01-28 16:37:07 -0600276 }
277 else
278 {
279 info("UPS Battery Level is Low: {UPS_BAT_LEVEL}",
280 "UPS_BAT_LEVEL",
281 std::get<uint>(properties["BatteryLevel"]));
282 server::Chassis::currentPowerStatus(
283 PowerStatus::UninterruptiblePowerSupply);
284 return;
285 }
286 }
287 catch (const sdbusplus::exception::exception& e)
288 {
289 error("Error reading UPS property, error: {ERROR}, "
290 "service: {SERVICE} path: {PATH}",
291 "ERROR", e, "SERVICE", service, "PATH", path);
292 throw;
293 }
294 }
295 }
296 return;
297}
298
Andrew Geissler2cf2a262022-02-02 14:38:41 -0600299void Chassis::uPowerChangeEvent(sdbusplus::message::message& msg)
300{
301 debug("UPS Property Change Event Triggered");
302 std::string statusInterface;
303 std::map<std::string, std::variant<uint, bool>> msgData;
304 msg.read(statusInterface, msgData);
305
306 // If the change is to any of the three properties we are interested in
307 // then call determineStatusOfPower() to see if a power status change
308 // is needed
309 auto propertyMap = msgData.find("IsPresent");
310 if (propertyMap != msgData.end())
311 {
312 info("UPS presence changed to {UPS_PRES_INFO}", "UPS_PRES_INFO",
313 std::get<bool>(propertyMap->second));
314 determineStatusOfPower();
315 return;
316 }
317
318 propertyMap = msgData.find("State");
319 if (propertyMap != msgData.end())
320 {
321 info("UPS State changed to {UPS_STATE}", "UPS_STATE",
322 std::get<uint>(propertyMap->second));
323 determineStatusOfPower();
324 return;
325 }
326
327 propertyMap = msgData.find("BatteryLevel");
328 if (propertyMap != msgData.end())
329 {
330 info("UPS BatteryLevel changed to {UPS_BAT_LEVEL}", "UPS_BAT_LEVEL",
331 std::get<uint>(propertyMap->second));
332 determineStatusOfPower();
333 return;
334 }
335 return;
336}
337
Matthew Barthbe6efab2022-03-01 13:21:45 -0600338void Chassis::startUnit(const std::string& sysdUnit)
Andrew Geisslerce80f242017-01-24 13:25:33 -0600339{
Andrew Geissler58a18012018-01-19 19:36:05 -0800340 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
341 SYSTEMD_INTERFACE, "StartUnit");
Andrew Geisslerce80f242017-01-24 13:25:33 -0600342
Matthew Barthbe6efab2022-03-01 13:21:45 -0600343 method.append(sysdUnit);
Andrew Geisslerce80f242017-01-24 13:25:33 -0600344 method.append("replace");
345
346 this->bus.call_noreply(method);
347
348 return;
349}
350
Josh D. King697474c2017-03-02 11:15:55 -0600351bool Chassis::stateActive(const std::string& target)
352{
Patrick Williams2975e262020-05-13 18:01:09 -0500353 std::variant<std::string> currentState;
Josh D. King697474c2017-03-02 11:15:55 -0600354 sdbusplus::message::object_path unitTargetPath;
355
Andrew Geissler58a18012018-01-19 19:36:05 -0800356 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
357 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King697474c2017-03-02 11:15:55 -0600358
359 method.append(target);
Josh D. King697474c2017-03-02 11:15:55 -0600360
William A. Kennington III09568ff2018-05-11 00:03:12 -0700361 try
362 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500363 auto result = this->bus.call(method);
William A. Kennington III09568ff2018-05-11 00:03:12 -0700364 result.read(unitTargetPath);
365 }
Patrick Williams0a675212021-09-02 09:49:43 -0500366 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700367 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500368 error("Error in GetUnit call: {ERROR}", "ERROR", e);
William A. Kennington III09568ff2018-05-11 00:03:12 -0700369 return false;
370 }
Josh D. King697474c2017-03-02 11:15:55 -0600371
Andrew Geissler58a18012018-01-19 19:36:05 -0800372 method = this->bus.new_method_call(
373 SYSTEMD_SERVICE,
374 static_cast<const std::string&>(unitTargetPath).c_str(),
375 SYSTEMD_PROPERTY_IFACE, "Get");
Josh D. King697474c2017-03-02 11:15:55 -0600376
377 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
Josh D. King697474c2017-03-02 11:15:55 -0600378
Anthony Wilson32c532e2018-10-25 21:56:07 -0500379 try
Josh D. King697474c2017-03-02 11:15:55 -0600380 {
Anthony Wilson32c532e2018-10-25 21:56:07 -0500381 auto result = this->bus.call(method);
382 result.read(currentState);
383 }
Patrick Williams0a675212021-09-02 09:49:43 -0500384 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500385 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500386 error("Error in ActiveState Get: {ERROR}", "ERROR", e);
Josh D. King697474c2017-03-02 11:15:55 -0600387 return false;
388 }
389
Patrick Williams37413dc2020-05-13 11:29:54 -0500390 const auto& currentStateStr = std::get<std::string>(currentState);
William A. Kennington III7a0689a2018-11-12 17:19:33 -0800391 return currentStateStr == ACTIVE_STATE ||
392 currentStateStr == ACTIVATING_STATE;
Josh D. King697474c2017-03-02 11:15:55 -0600393}
394
Patrick Williams8f8ba392017-05-05 15:47:39 -0500395int Chassis::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600396{
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600397 sdbusplus::message::object_path newStateObjPath;
398 std::string newStateUnit{};
399 std::string newStateResult{};
400
Andrew Geissler58a18012018-01-19 19:36:05 -0800401 // Read the msg and populate each variable
William A. Kennington III09568ff2018-05-11 00:03:12 -0700402 try
403 {
Andrew Geissler9b8af4f2019-09-12 14:19:14 -0500404 // newStateID is a throwaway that is needed in order to read the
405 // parameters that are useful out of the dbus message
406 uint32_t newStateID{};
William A. Kennington III09568ff2018-05-11 00:03:12 -0700407 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
408 }
Patrick Williams0a675212021-09-02 09:49:43 -0500409 catch (const sdbusplus::exception::exception& e)
William A. Kennington III09568ff2018-05-11 00:03:12 -0700410 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500411 error("Error in state change - bad encoding: {ERROR} {REPLY_SIG}",
412 "ERROR", e, "REPLY_SIG", msg.get_signature());
William A. Kennington III09568ff2018-05-11 00:03:12 -0700413 return 0;
414 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600415
Allen.Wangc0895622022-03-23 15:46:47 +0800416 if ((newStateUnit == fmt::format(CHASSIS_STATE_POWEROFF_TGT_FMT, id)) &&
Potin Lai70f36d82022-03-15 10:25:39 +0800417 (newStateResult == "done") &&
418 (!stateActive(systemdTargetTable[Transition::On])))
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600419 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500420 info("Received signal that power OFF is complete");
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600421 this->currentPowerState(server::Chassis::PowerState::Off);
Matt Spinler9eab9862018-07-11 14:13:52 -0500422 this->setStateChangeTime();
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600423 }
Potin Lai70f36d82022-03-15 10:25:39 +0800424 else if ((newStateUnit == systemdTargetTable[Transition::On]) &&
Andrew Geissler58a18012018-01-19 19:36:05 -0800425 (newStateResult == "done") &&
Potin Lai70f36d82022-03-15 10:25:39 +0800426 (stateActive(systemdTargetTable[Transition::On])))
Andrew Geissler58a18012018-01-19 19:36:05 -0800427 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500428 info("Received signal that power ON is complete");
Andrew Geissler58a18012018-01-19 19:36:05 -0800429 this->currentPowerState(server::Chassis::PowerState::On);
Matt Spinler9eab9862018-07-11 14:13:52 -0500430 this->setStateChangeTime();
Andrew Geisslerf2b22e82021-03-12 14:47:03 -0600431
432 // Remove temporary file which is utilized for scenarios where the
433 // BMC is rebooted while the chassis power is still on.
434 // This file is used to indicate to chassis related systemd services
435 // that the chassis is already on and they should skip running.
436 // Once the chassis state is back to on we can clear this file.
437 auto size = std::snprintf(nullptr, 0, CHASSIS_ON_FILE, 0);
438 size++; // null
439 std::unique_ptr<char[]> chassisFile(new char[size]);
440 std::snprintf(chassisFile.get(), size, CHASSIS_ON_FILE, 0);
441 if (std::filesystem::exists(chassisFile.get()))
442 {
443 std::filesystem::remove(chassisFile.get());
444 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800445 }
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600446
447 return 0;
448}
449
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600450Chassis::Transition Chassis::requestedPowerTransition(Transition value)
451{
452
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500453 info("Change to Chassis Requested Power State: {REQ_POWER_TRAN}",
454 "REQ_POWER_TRAN", value);
Potin Lai70f36d82022-03-15 10:25:39 +0800455 startUnit(systemdTargetTable.find(value)->second);
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600456 return server::Chassis::requestedPowerTransition(value);
457}
458
459Chassis::PowerState Chassis::currentPowerState(PowerState value)
460{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500461 PowerState chassisPowerState;
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500462 info("Change to Chassis Power State: {CUR_POWER_STATE}", "CUR_POWER_STATE",
463 value);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500464
465 chassisPowerState = server::Chassis::currentPowerState(value);
shamim ali6d582a82022-03-15 18:19:32 +0530466 if (chassisPowerState == PowerState::On)
467 {
468 pohTimer.resetRemaining();
469 }
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500470 return chassisPowerState;
471}
472
Patrick Williams45a1ed72021-04-30 21:02:43 -0500473uint32_t Chassis::pohCounter(uint32_t value)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500474{
Patrick Williams45a1ed72021-04-30 21:02:43 -0500475 if (value != pohCounter())
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500476 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500477 ChassisInherit::pohCounter(value);
Matt Spinler81957842018-07-11 10:37:12 -0500478 serializePOH();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500479 }
Patrick Williams45a1ed72021-04-30 21:02:43 -0500480 return pohCounter();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500481}
482
Patrick Williams45a1ed72021-04-30 21:02:43 -0500483void Chassis::pohCallback()
William A. Kennington IIId998f822018-10-17 23:17:57 -0700484{
485 if (ChassisInherit::currentPowerState() == PowerState::On)
486 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500487 pohCounter(pohCounter() + 1);
William A. Kennington IIId998f822018-10-17 23:17:57 -0700488 }
489}
490
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500491void Chassis::restorePOHCounter()
492{
493 uint32_t counter;
Matt Spinler81957842018-07-11 10:37:12 -0500494 if (!deserializePOH(POH_COUNTER_PERSIST_PATH, counter))
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500495 {
496 // set to default value
Patrick Williams45a1ed72021-04-30 21:02:43 -0500497 pohCounter(0);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500498 }
499 else
500 {
Patrick Williams45a1ed72021-04-30 21:02:43 -0500501 pohCounter(counter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500502 }
503}
504
Matt Spinler81957842018-07-11 10:37:12 -0500505fs::path Chassis::serializePOH(const fs::path& path)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500506{
507 std::ofstream os(path.c_str(), std::ios::binary);
508 cereal::JSONOutputArchive oarchive(os);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500509 oarchive(pohCounter());
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500510 return path;
511}
512
Patrick Williams45a1ed72021-04-30 21:02:43 -0500513bool Chassis::deserializePOH(const fs::path& path, uint32_t& pohCounter)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500514{
515 try
516 {
517 if (fs::exists(path))
518 {
519 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
520 cereal::JSONInputArchive iarchive(is);
Patrick Williams45a1ed72021-04-30 21:02:43 -0500521 iarchive(pohCounter);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500522 return true;
523 }
524 return false;
525 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500526 catch (const cereal::Exception& e)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500527 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500528 error("deserialize exception: {ERROR}", "ERROR", e);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500529 fs::remove(path);
530 return false;
531 }
532 catch (const fs::filesystem_error& e)
533 {
534 return false;
535 }
536
537 return false;
538}
539
540void Chassis::startPOHCounter()
541{
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500542 auto dir = fs::path(POH_COUNTER_PERSIST_PATH).parent_path();
543 fs::create_directories(dir);
544
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500545 try
546 {
William A. Kennington IIId998f822018-10-17 23:17:57 -0700547 auto event = sdeventplus::Event::get_default();
548 bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
549 event.loop();
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500550 }
William A. Kennington IIId998f822018-10-17 23:17:57 -0700551 catch (const sdeventplus::SdEventError& e)
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500552 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500553 error("Error occurred during the sdeventplus loop: {ERROR}", "ERROR",
554 e);
Nagaraju Goruganticb781fe2018-04-06 13:41:01 -0500555 phosphor::logging::commit<InternalFailure>();
556 }
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600557}
558
Matt Spinler9eab9862018-07-11 14:13:52 -0500559void Chassis::serializeStateChangeTime()
560{
561 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
562 std::ofstream os(path.c_str(), std::ios::binary);
563 cereal::JSONOutputArchive oarchive(os);
564
565 oarchive(ChassisInherit::lastStateChangeTime(),
566 ChassisInherit::currentPowerState());
567}
568
569bool Chassis::deserializeStateChangeTime(uint64_t& time, PowerState& state)
570{
571 fs::path path{CHASSIS_STATE_CHANGE_PERSIST_PATH};
572
573 try
574 {
575 if (fs::exists(path))
576 {
577 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
578 cereal::JSONInputArchive iarchive(is);
579 iarchive(time, state);
580 return true;
581 }
582 }
Patrick Williams8583b3b2021-10-06 12:19:20 -0500583 catch (const std::exception& e)
Matt Spinler9eab9862018-07-11 14:13:52 -0500584 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500585 error("deserialize exception: {ERROR}", "ERROR", e);
Matt Spinler9eab9862018-07-11 14:13:52 -0500586 fs::remove(path);
587 }
588
589 return false;
590}
591
592void Chassis::restoreChassisStateChangeTime()
593{
594 uint64_t time;
595 PowerState state;
596
597 if (!deserializeStateChangeTime(time, state))
598 {
599 ChassisInherit::lastStateChangeTime(0);
600 }
601 else
602 {
603 ChassisInherit::lastStateChangeTime(time);
604 }
605}
606
607void Chassis::setStateChangeTime()
608{
609 using namespace std::chrono;
610 uint64_t lastTime;
611 PowerState lastState;
612
613 auto now =
614 duration_cast<milliseconds>(system_clock::now().time_since_epoch())
615 .count();
616
617 // If power is on when the BMC is rebooted, this function will get called
618 // because sysStateChange() runs. Since the power state didn't change
619 // in this case, neither should the state change time, so check that
620 // the power state actually did change here.
621 if (deserializeStateChangeTime(lastTime, lastState))
622 {
623 if (lastState == ChassisInherit::currentPowerState())
624 {
625 return;
626 }
627 }
628
629 ChassisInherit::lastStateChangeTime(now);
630 serializeStateChangeTime();
631}
632
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500633bool Chassis::standbyVoltageRegulatorFault()
634{
635 bool regulatorFault = false;
636
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600637 // find standby voltage regulator fault via gpiog
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500638
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600639 auto gpioval = utils::getGpioValue("regulator-standby-faulted");
640
641 if (-1 == gpioval)
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500642 {
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600643 error("Failed reading regulator-standby-faulted GPIO");
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500644 }
Andrew Geisslerf8ae6a02022-01-21 17:00:20 -0600645
646 if (1 == gpioval)
647 {
648 info("Detected standby voltage regulator fault");
649 regulatorFault = true;
650 }
651
Ben Tyner2c36e5a2021-07-12 14:56:49 -0500652 return regulatorFault;
653}
654
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600655} // namespace manager
656} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700657} // namespace phosphor