blob: 6651d2f5337fe96056f9b4ba2a89303cfae5d32d [file] [log] [blame]
William A. Kennington III436f3b82018-11-12 17:25:00 -08001#include <cassert>
Saqib Khana8006a22017-02-14 11:37:08 -06002#include <phosphor-logging/log.hpp>
Matt Spinlere6710b72018-07-12 16:05:55 -05003#include <sys/sysinfo.h>
Josh D. Kingbdd9cb72016-12-19 11:13:43 -06004#include "bmc_state_manager.hpp"
5
6namespace phosphor
7{
8namespace state
9{
10namespace manager
11{
12
Josh D. King6db38222016-12-19 14:52:40 -060013// When you see server:: you know we're referencing our base class
14namespace server = sdbusplus::xyz::openbmc_project::State::server;
15
16using namespace phosphor::logging;
17
Josh D. Kingd613b812016-12-19 16:47:45 -060018constexpr auto obmcStandbyTarget = "obmc-standby.target";
19constexpr auto signalDone = "done";
Josh D. Kingd3e58472017-02-02 11:09:11 -060020constexpr auto activeState = "active";
Josh D. Kingd613b812016-12-19 16:47:45 -060021
Josh D. King5162a7b2016-12-19 16:15:00 -060022/* Map a transition to it's systemd target */
Andrew Geissler58a18012018-01-19 19:36:05 -080023const std::map<server::BMC::Transition, const char*> SYSTEMD_TABLE = {
24 {server::BMC::Transition::Reboot, "reboot.target"}};
Josh D. King5162a7b2016-12-19 16:15:00 -060025
Andrew Geissler58a18012018-01-19 19:36:05 -080026constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
27constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
28constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
Josh D. Kingd3e58472017-02-02 11:09:11 -060029constexpr auto SYSTEMD_PRP_INTERFACE = "org.freedesktop.DBus.Properties";
Josh D. Kingd3e58472017-02-02 11:09:11 -060030
31void BMC::discoverInitialState()
32{
33 sdbusplus::message::variant<std::string> currentState;
Josh D. King2b5d8872017-02-21 13:37:17 -060034 sdbusplus::message::object_path unitTargetPath;
Josh D. Kingd3e58472017-02-02 11:09:11 -060035
Andrew Geissler58a18012018-01-19 19:36:05 -080036 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
37 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King2b5d8872017-02-21 13:37:17 -060038
39 method.append(obmcStandbyTarget);
40
41 auto result = this->bus.call(method);
42
Andrew Geissler58a18012018-01-19 19:36:05 -080043 // Check that the bus call didn't result in an error
44 if (result.is_method_error())
Josh D. King2b5d8872017-02-21 13:37:17 -060045 {
46 log<level::ERR>("Error in bus call.");
47 return;
48 }
49
50 result.read(unitTargetPath);
51
Andrew Geissler58a18012018-01-19 19:36:05 -080052 method = this->bus.new_method_call(
53 SYSTEMD_SERVICE,
54 static_cast<const std::string&>(unitTargetPath).c_str(),
55 SYSTEMD_PRP_INTERFACE, "Get");
Josh D. Kingd3e58472017-02-02 11:09:11 -060056
57 method.append("org.freedesktop.systemd1.Unit", "ActiveState");
58
Josh D. King2b5d8872017-02-21 13:37:17 -060059 result = this->bus.call(method);
60
Andrew Geissler58a18012018-01-19 19:36:05 -080061 // Check that the bus call didn't result in an error
62 if (result.is_method_error())
Josh D. King2b5d8872017-02-21 13:37:17 -060063 {
64 log<level::INFO>("Error in bus call.");
65 return;
66 }
Josh D. Kingd3e58472017-02-02 11:09:11 -060067
Andrew Geissler58a18012018-01-19 19:36:05 -080068 // Is obmc-standby.target active or inactive?
Josh D. Kingd3e58472017-02-02 11:09:11 -060069 result.read(currentState);
70
Andrew Geissler58a18012018-01-19 19:36:05 -080071 if (currentState == activeState)
Josh D. Kingd3e58472017-02-02 11:09:11 -060072 {
73 log<level::INFO>("Setting the BMCState field",
Andrew Geissler58a18012018-01-19 19:36:05 -080074 entry("CURRENT_BMC_STATE=%s", "BMC_READY"));
Josh D. Kingd3e58472017-02-02 11:09:11 -060075 this->currentBMCState(BMCState::Ready);
76
Andrew Geissler58a18012018-01-19 19:36:05 -080077 // Unsubscribe so we stop processing all other signals
78 method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
79 SYSTEMD_INTERFACE, "Unsubscribe");
Josh D. Kingd3e58472017-02-02 11:09:11 -060080 this->bus.call(method);
81 this->stateSignal.release();
82 }
83 else
84 {
85 log<level::INFO>("Setting the BMCState field",
Andrew Geissler58a18012018-01-19 19:36:05 -080086 entry("CURRENT_BMC_STATE=%s", "BMC_NOTREADY"));
Josh D. Kingd3e58472017-02-02 11:09:11 -060087 this->currentBMCState(BMCState::NotReady);
88 }
89
90 return;
91}
92
Josh D. King6db38222016-12-19 14:52:40 -060093void BMC::subscribeToSystemdSignals()
94{
Andrew Geissler58a18012018-01-19 19:36:05 -080095 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
96 SYSTEMD_INTERFACE, "Subscribe");
Josh D. King6db38222016-12-19 14:52:40 -060097 this->bus.call(method);
98
99 return;
100}
101
Josh D. King5162a7b2016-12-19 16:15:00 -0600102void BMC::executeTransition(const Transition tranReq)
103{
Andrew Geissler58a18012018-01-19 19:36:05 -0800104 // Check to make sure it can be found
Josh D. King5162a7b2016-12-19 16:15:00 -0600105 auto iter = SYSTEMD_TABLE.find(tranReq);
Andrew Geissler58a18012018-01-19 19:36:05 -0800106 if (iter == SYSTEMD_TABLE.end())
107 return;
Josh D. King5162a7b2016-12-19 16:15:00 -0600108
109 const auto& sysdUnit = iter->second;
110
Andrew Geissler58a18012018-01-19 19:36:05 -0800111 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
112 SYSTEMD_INTERFACE, "StartUnit");
Andrew Geissler181f8362017-06-30 16:43:05 -0500113 // The only valid transition is reboot and that
114 // needs to be irreversible once started
115 method.append(sysdUnit, "replace-irreversibly");
Josh D. King5162a7b2016-12-19 16:15:00 -0600116
117 this->bus.call(method);
Josh D. King5162a7b2016-12-19 16:15:00 -0600118 return;
119}
120
Patrick Williamsd32f8182017-05-05 15:55:24 -0500121int BMC::bmcStateChange(sdbusplus::message::message& msg)
Josh D. Kingd613b812016-12-19 16:47:45 -0600122{
Andrew Geissler58a18012018-01-19 19:36:05 -0800123 uint32_t newStateID{};
Josh D. Kingd613b812016-12-19 16:47:45 -0600124 sdbusplus::message::object_path newStateObjPath;
125 std::string newStateUnit{};
126 std::string newStateResult{};
127
Andrew Geissler58a18012018-01-19 19:36:05 -0800128 // Read the msg and populate each variable
Patrick Williamsd32f8182017-05-05 15:55:24 -0500129 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Josh D. Kingd613b812016-12-19 16:47:45 -0600130
Andrew Geissler58a18012018-01-19 19:36:05 -0800131 // Caught the signal that indicates the BMC is now BMC_READY
132 if ((newStateUnit == obmcStandbyTarget) && (newStateResult == signalDone))
Josh D. Kingd613b812016-12-19 16:47:45 -0600133 {
134 log<level::INFO>("BMC_READY");
135 this->currentBMCState(BMCState::Ready);
136
Andrew Geissler58a18012018-01-19 19:36:05 -0800137 // Unsubscribe so we stop processing all other signals
138 auto method =
139 this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
140 SYSTEMD_INTERFACE, "Unsubscribe");
Josh D. Kingd613b812016-12-19 16:47:45 -0600141 this->bus.call(method);
142 this->stateSignal.release();
143 }
144
145 return 0;
146}
147
Josh D. King6db38222016-12-19 14:52:40 -0600148BMC::Transition BMC::requestedBMCTransition(Transition value)
149{
Andrew Geissler58a18012018-01-19 19:36:05 -0800150 log<level::INFO>("Setting the RequestedBMCTransition field",
151 entry("REQUESTED_BMC_TRANSITION=0x%s",
152 convertForMessage(value).c_str()));
Josh D. King6db38222016-12-19 14:52:40 -0600153
Josh D. King5162a7b2016-12-19 16:15:00 -0600154 executeTransition(value);
155 return server::BMC::requestedBMCTransition(value);
Josh D. King6db38222016-12-19 14:52:40 -0600156}
157
Josh D. Kingd613b812016-12-19 16:47:45 -0600158BMC::BMCState BMC::currentBMCState(BMCState value)
159{
160 log<level::INFO>(
Andrew Geissler58a18012018-01-19 19:36:05 -0800161 "Setting the BMCState field",
162 entry("CURRENT_BMC_STATE=0x%s", convertForMessage(value).c_str()));
Josh D. Kingd613b812016-12-19 16:47:45 -0600163
164 return server::BMC::currentBMCState(value);
165}
166
Matt Spinlere6710b72018-07-12 16:05:55 -0500167uint64_t BMC::lastRebootTime() const
168{
169 using namespace std::chrono;
170 struct sysinfo info;
171
172 auto rc = sysinfo(&info);
173 assert(rc == 0);
174
175 // Since uptime is in seconds, also get the current time in seconds.
176 auto now = time_point_cast<seconds>(system_clock::now());
177 auto rebootTime = now - seconds(info.uptime);
178
179 return duration_cast<milliseconds>(rebootTime.time_since_epoch()).count();
180}
181
Josh D. Kingbdd9cb72016-12-19 11:13:43 -0600182} // namespace manager
183} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700184} // namespace phosphor