blob: b248b01b9829db65f03f68b4abdc547f0dc8b91d [file] [log] [blame]
Josh D. Kingbdd9cb72016-12-19 11:13:43 -06001#include "bmc_state_manager.hpp"
Andrew Geisslere426b582020-05-28 12:40:55 -05002
Andrew Geissler98e64e62022-01-25 16:02:56 -06003#include "utils.hpp"
Andrew Geissler2f60aae2019-09-12 13:25:21 -05004#include "xyz/openbmc_project/Common/error.hpp"
Josh D. Kingbdd9cb72016-12-19 11:13:43 -06005
Andrew Geissler98e64e62022-01-25 16:02:56 -06006#include <gpiod.h>
Andrew Geisslere426b582020-05-28 12:40:55 -05007#include <sys/sysinfo.h>
8
9#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler429100a2021-09-09 12:50:24 -050010#include <phosphor-logging/lg2.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -050011#include <sdbusplus/exception.hpp>
12
13#include <cassert>
Tim Lee2bfb1ef2021-03-17 09:50:35 +080014#include <filesystem>
15#include <fstream>
16#include <iostream>
Andrew Geisslere426b582020-05-28 12:40:55 -050017
Josh D. Kingbdd9cb72016-12-19 11:13:43 -060018namespace phosphor
19{
20namespace state
21{
22namespace manager
23{
24
Andrew Geissler429100a2021-09-09 12:50:24 -050025PHOSPHOR_LOG2_USING;
26
Josh D. King6db38222016-12-19 14:52:40 -060027// When you see server:: you know we're referencing our base class
28namespace server = sdbusplus::xyz::openbmc_project::State::server;
29
30using namespace phosphor::logging;
Andrew Geissler2f60aae2019-09-12 13:25:21 -050031using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
Josh D. King6db38222016-12-19 14:52:40 -060032
Anthony Wilsoneef31f82019-04-23 17:04:09 -050033constexpr auto obmcStandbyTarget = "multi-user.target";
Josh D. Kingd613b812016-12-19 16:47:45 -060034constexpr auto signalDone = "done";
Josh D. Kingd3e58472017-02-02 11:09:11 -060035constexpr auto activeState = "active";
Josh D. Kingd613b812016-12-19 16:47:45 -060036
Josh D. King5162a7b2016-12-19 16:15:00 -060037/* Map a transition to it's systemd target */
Andrew Geissler58a18012018-01-19 19:36:05 -080038const std::map<server::BMC::Transition, const char*> SYSTEMD_TABLE = {
39 {server::BMC::Transition::Reboot, "reboot.target"}};
Josh D. King5162a7b2016-12-19 16:15:00 -060040
Andrew Geissler58a18012018-01-19 19:36:05 -080041constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
42constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
43constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
Josh D. Kingd3e58472017-02-02 11:09:11 -060044constexpr auto SYSTEMD_PRP_INTERFACE = "org.freedesktop.DBus.Properties";
Josh D. Kingd3e58472017-02-02 11:09:11 -060045
46void BMC::discoverInitialState()
47{
Patrick Williams2975e262020-05-13 18:01:09 -050048 std::variant<std::string> currentState;
Josh D. King2b5d8872017-02-21 13:37:17 -060049 sdbusplus::message::object_path unitTargetPath;
Josh D. Kingd3e58472017-02-02 11:09:11 -060050
Andrew Geissler58a18012018-01-19 19:36:05 -080051 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
52 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King2b5d8872017-02-21 13:37:17 -060053
54 method.append(obmcStandbyTarget);
55
Anthony Wilson32c532e2018-10-25 21:56:07 -050056 try
Josh D. King2b5d8872017-02-21 13:37:17 -060057 {
Anthony Wilson32c532e2018-10-25 21:56:07 -050058 auto result = this->bus.call(method);
59 result.read(unitTargetPath);
60 }
Patrick Williams0a675212021-09-02 09:49:43 -050061 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -050062 {
Andrew Geissler429100a2021-09-09 12:50:24 -050063 error("Error in GetUnit call: {ERROR}", "ERROR", e);
Josh D. King2b5d8872017-02-21 13:37:17 -060064 return;
65 }
66
Andrew Geissler58a18012018-01-19 19:36:05 -080067 method = this->bus.new_method_call(
68 SYSTEMD_SERVICE,
69 static_cast<const std::string&>(unitTargetPath).c_str(),
70 SYSTEMD_PRP_INTERFACE, "Get");
Josh D. Kingd3e58472017-02-02 11:09:11 -060071
72 method.append("org.freedesktop.systemd1.Unit", "ActiveState");
73
Anthony Wilson32c532e2018-10-25 21:56:07 -050074 try
Josh D. King2b5d8872017-02-21 13:37:17 -060075 {
Anthony Wilson32c532e2018-10-25 21:56:07 -050076 auto result = this->bus.call(method);
77
78 // Is obmc-standby.target active or inactive?
79 result.read(currentState);
80 }
Patrick Williams0a675212021-09-02 09:49:43 -050081 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -050082 {
Andrew Geissler429100a2021-09-09 12:50:24 -050083 info("Error in ActiveState Get: {ERROR}", "ERROR", e);
Josh D. King2b5d8872017-02-21 13:37:17 -060084 return;
85 }
Josh D. Kingd3e58472017-02-02 11:09:11 -060086
Patrick Williams37413dc2020-05-13 11:29:54 -050087 auto currentStateStr = std::get<std::string>(currentState);
Anthony Wilson32c532e2018-10-25 21:56:07 -050088 if (currentStateStr == activeState)
Josh D. Kingd3e58472017-02-02 11:09:11 -060089 {
Andrew Geissler429100a2021-09-09 12:50:24 -050090 info("Setting the BMCState field to BMC_READY");
Josh D. Kingd3e58472017-02-02 11:09:11 -060091 this->currentBMCState(BMCState::Ready);
92
Andrew Geissler58a18012018-01-19 19:36:05 -080093 // Unsubscribe so we stop processing all other signals
94 method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
95 SYSTEMD_INTERFACE, "Unsubscribe");
Anthony Wilson32c532e2018-10-25 21:56:07 -050096 try
97 {
98 this->bus.call(method);
99 this->stateSignal.release();
100 }
Patrick Williams0a675212021-09-02 09:49:43 -0500101 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500102 {
Andrew Geissler429100a2021-09-09 12:50:24 -0500103 info("Error in Unsubscribe: {ERROR}", "ERROR", e);
Anthony Wilson32c532e2018-10-25 21:56:07 -0500104 }
Josh D. Kingd3e58472017-02-02 11:09:11 -0600105 }
106 else
107 {
Andrew Geissler429100a2021-09-09 12:50:24 -0500108 info("Setting the BMCState field to BMC_NOTREADY");
Josh D. Kingd3e58472017-02-02 11:09:11 -0600109 this->currentBMCState(BMCState::NotReady);
110 }
111
112 return;
113}
114
Josh D. King6db38222016-12-19 14:52:40 -0600115void BMC::subscribeToSystemdSignals()
116{
Andrew Geissler58a18012018-01-19 19:36:05 -0800117 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
118 SYSTEMD_INTERFACE, "Subscribe");
Anthony Wilson32c532e2018-10-25 21:56:07 -0500119
120 try
121 {
122 this->bus.call(method);
123 }
Patrick Williams0a675212021-09-02 09:49:43 -0500124 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500125 {
Andrew Geissler429100a2021-09-09 12:50:24 -0500126 error("Failed to subscribe to systemd signals: {ERROR}", "ERROR", e);
Andrew Geissler2f60aae2019-09-12 13:25:21 -0500127 elog<InternalFailure>();
Anthony Wilson32c532e2018-10-25 21:56:07 -0500128 }
Josh D. King6db38222016-12-19 14:52:40 -0600129
130 return;
131}
132
Josh D. King5162a7b2016-12-19 16:15:00 -0600133void BMC::executeTransition(const Transition tranReq)
134{
Jayaprakash Mutyala44c223c2020-08-14 00:08:03 +0000135 // HardReboot does not shutdown any services and immediately transitions
136 // into the reboot process
137 if (server::BMC::Transition::HardReboot == tranReq)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500138 {
Jayaprakash Mutyala44c223c2020-08-14 00:08:03 +0000139 auto method = this->bus.new_method_call(
140 SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, SYSTEMD_INTERFACE, "Reboot");
141 try
142 {
143 this->bus.call(method);
144 }
Patrick Williams0a675212021-09-02 09:49:43 -0500145 catch (const sdbusplus::exception::exception& e)
Jayaprakash Mutyala44c223c2020-08-14 00:08:03 +0000146 {
Andrew Geissler429100a2021-09-09 12:50:24 -0500147 info("Error in HardReboot: {ERROR}", "ERROR", e);
Jayaprakash Mutyala44c223c2020-08-14 00:08:03 +0000148 }
Anthony Wilson32c532e2018-10-25 21:56:07 -0500149 }
Jayaprakash Mutyala44c223c2020-08-14 00:08:03 +0000150 else
Anthony Wilson32c532e2018-10-25 21:56:07 -0500151 {
Jayaprakash Mutyala44c223c2020-08-14 00:08:03 +0000152 // Check to make sure it can be found
153 auto iter = SYSTEMD_TABLE.find(tranReq);
154 if (iter == SYSTEMD_TABLE.end())
155 return;
Anthony Wilson32c532e2018-10-25 21:56:07 -0500156
Jayaprakash Mutyala44c223c2020-08-14 00:08:03 +0000157 const auto& sysdUnit = iter->second;
158
159 auto method = this->bus.new_method_call(
160 SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH, SYSTEMD_INTERFACE, "StartUnit");
161 // The only valid transition is reboot and that
162 // needs to be irreversible once started
163
164 method.append(sysdUnit, "replace-irreversibly");
165
166 try
167 {
168 this->bus.call(method);
169 }
Patrick Williams0a675212021-09-02 09:49:43 -0500170 catch (const sdbusplus::exception::exception& e)
Jayaprakash Mutyala44c223c2020-08-14 00:08:03 +0000171 {
Andrew Geissler429100a2021-09-09 12:50:24 -0500172 info("Error in StartUnit - replace-irreversibly: {ERROR}", "ERROR",
173 e);
Jayaprakash Mutyala44c223c2020-08-14 00:08:03 +0000174 }
175 }
Josh D. King5162a7b2016-12-19 16:15:00 -0600176 return;
177}
178
Patrick Williamsd32f8182017-05-05 15:55:24 -0500179int BMC::bmcStateChange(sdbusplus::message::message& msg)
Josh D. Kingd613b812016-12-19 16:47:45 -0600180{
Andrew Geissler58a18012018-01-19 19:36:05 -0800181 uint32_t newStateID{};
Josh D. Kingd613b812016-12-19 16:47:45 -0600182 sdbusplus::message::object_path newStateObjPath;
183 std::string newStateUnit{};
184 std::string newStateResult{};
185
Andrew Geissler58a18012018-01-19 19:36:05 -0800186 // Read the msg and populate each variable
Patrick Williamsd32f8182017-05-05 15:55:24 -0500187 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Josh D. Kingd613b812016-12-19 16:47:45 -0600188
Andrew Geissler58a18012018-01-19 19:36:05 -0800189 // Caught the signal that indicates the BMC is now BMC_READY
190 if ((newStateUnit == obmcStandbyTarget) && (newStateResult == signalDone))
Josh D. Kingd613b812016-12-19 16:47:45 -0600191 {
Andrew Geissler429100a2021-09-09 12:50:24 -0500192 info("BMC_READY");
Josh D. Kingd613b812016-12-19 16:47:45 -0600193 this->currentBMCState(BMCState::Ready);
194
Andrew Geissler58a18012018-01-19 19:36:05 -0800195 // Unsubscribe so we stop processing all other signals
196 auto method =
197 this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
198 SYSTEMD_INTERFACE, "Unsubscribe");
Anthony Wilson32c532e2018-10-25 21:56:07 -0500199
200 try
201 {
202 this->bus.call(method);
203 this->stateSignal.release();
204 }
Patrick Williams0a675212021-09-02 09:49:43 -0500205 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500206 {
Andrew Geissler429100a2021-09-09 12:50:24 -0500207 info("Error in Unsubscribe: {ERROR}", "ERROR", e);
Anthony Wilson32c532e2018-10-25 21:56:07 -0500208 }
Josh D. Kingd613b812016-12-19 16:47:45 -0600209 }
210
211 return 0;
212}
213
Josh D. King6db38222016-12-19 14:52:40 -0600214BMC::Transition BMC::requestedBMCTransition(Transition value)
215{
Andrew Geissler429100a2021-09-09 12:50:24 -0500216 info("Setting the RequestedBMCTransition field to "
217 "{REQUESTED_BMC_TRANSITION}",
218 "REQUESTED_BMC_TRANSITION", value);
Josh D. King6db38222016-12-19 14:52:40 -0600219
Josh D. King5162a7b2016-12-19 16:15:00 -0600220 executeTransition(value);
221 return server::BMC::requestedBMCTransition(value);
Josh D. King6db38222016-12-19 14:52:40 -0600222}
223
Josh D. Kingd613b812016-12-19 16:47:45 -0600224BMC::BMCState BMC::currentBMCState(BMCState value)
225{
Andrew Geissler429100a2021-09-09 12:50:24 -0500226
227 info("Setting the BMCState field to {CURRENT_BMC_STATE}",
228 "CURRENT_BMC_STATE", value);
Josh D. Kingd613b812016-12-19 16:47:45 -0600229
230 return server::BMC::currentBMCState(value);
231}
232
Tim Lee2bfb1ef2021-03-17 09:50:35 +0800233BMC::RebootCause BMC::lastRebootCause(RebootCause value)
234{
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500235 info("Setting the RebootCause field to {LAST_REBOOT_CAUSE}",
236 "LAST_REBOOT_CAUSE", value);
Tim Lee2bfb1ef2021-03-17 09:50:35 +0800237
238 return server::BMC::lastRebootCause(value);
239}
240
Matt Spinlere6710b72018-07-12 16:05:55 -0500241uint64_t BMC::lastRebootTime() const
242{
243 using namespace std::chrono;
244 struct sysinfo info;
245
246 auto rc = sysinfo(&info);
247 assert(rc == 0);
248
249 // Since uptime is in seconds, also get the current time in seconds.
250 auto now = time_point_cast<seconds>(system_clock::now());
251 auto rebootTime = now - seconds(info.uptime);
252
253 return duration_cast<milliseconds>(rebootTime.time_since_epoch()).count();
254}
255
Tim Lee2bfb1ef2021-03-17 09:50:35 +0800256void BMC::discoverLastRebootCause()
257{
258 uint64_t bootReason = 0;
259 std::ifstream file;
260 auto bootstatusPath = "/sys/class/watchdog/watchdog0/bootstatus";
261
262 file.exceptions(std::ifstream::failbit | std::ifstream::badbit |
263 std::ifstream::eofbit);
264
265 try
266 {
267 file.open(bootstatusPath);
268 file >> bootReason;
269 }
270 catch (const std::exception& e)
271 {
272 auto rc = errno;
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500273 error("Failed to read sysfs file {FILE} with errno {ERRNO}", "FILE",
274 bootstatusPath, "ERRNO", rc);
Tim Lee2bfb1ef2021-03-17 09:50:35 +0800275 }
276
277 switch (bootReason)
278 {
279 case WDIOF_EXTERN1:
280 this->lastRebootCause(RebootCause::Watchdog);
Andrew Geissler98e64e62022-01-25 16:02:56 -0600281 return;
Tim Lee2bfb1ef2021-03-17 09:50:35 +0800282 case WDIOF_CARDRESET:
283 this->lastRebootCause(RebootCause::POR);
Andrew Geissler98e64e62022-01-25 16:02:56 -0600284 return;
Tim Lee2bfb1ef2021-03-17 09:50:35 +0800285 default:
286 this->lastRebootCause(RebootCause::Unknown);
Andrew Geissler98e64e62022-01-25 16:02:56 -0600287 // Continue below to see if more details can be found
288 // on reason for reboot
Tim Lee2bfb1ef2021-03-17 09:50:35 +0800289 break;
290 }
291
Andrew Geissler98e64e62022-01-25 16:02:56 -0600292 // If the above code could not detect a reason, look for a the
293 // reset-cause-pinhole gpio to see if it is the reason for the reboot
294 auto gpioval =
295 phosphor::state::manager::utils::getGpioValue("reset-cause-pinhole");
296
297 if (1 == gpioval)
298 {
299 info("The BMC reset was caused by a pinhole reset");
300 this->lastRebootCause(RebootCause::PinholeReset);
301 }
302
Tim Lee2bfb1ef2021-03-17 09:50:35 +0800303 return;
304}
305
Josh D. Kingbdd9cb72016-12-19 11:13:43 -0600306} // namespace manager
307} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700308} // namespace phosphor