blob: 92d9ef82fea9d91729c77effeb95bb44b36cc434 [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>
Anthony Wilson32c532e2018-10-25 21:56:07 -05003#include <sdbusplus/exception.hpp>
Matt Spinlere6710b72018-07-12 16:05:55 -05004#include <sys/sysinfo.h>
Josh D. Kingbdd9cb72016-12-19 11:13:43 -06005#include "bmc_state_manager.hpp"
6
7namespace phosphor
8{
9namespace state
10{
11namespace manager
12{
13
Josh D. King6db38222016-12-19 14:52:40 -060014// When you see server:: you know we're referencing our base class
15namespace server = sdbusplus::xyz::openbmc_project::State::server;
16
17using namespace phosphor::logging;
Anthony Wilson32c532e2018-10-25 21:56:07 -050018using sdbusplus::exception::SdBusError;
Josh D. King6db38222016-12-19 14:52:40 -060019
Anthony Wilsoneef31f82019-04-23 17:04:09 -050020constexpr auto obmcStandbyTarget = "multi-user.target";
Josh D. Kingd613b812016-12-19 16:47:45 -060021constexpr auto signalDone = "done";
Josh D. Kingd3e58472017-02-02 11:09:11 -060022constexpr auto activeState = "active";
Josh D. Kingd613b812016-12-19 16:47:45 -060023
Josh D. King5162a7b2016-12-19 16:15:00 -060024/* Map a transition to it's systemd target */
Andrew Geissler58a18012018-01-19 19:36:05 -080025const std::map<server::BMC::Transition, const char*> SYSTEMD_TABLE = {
26 {server::BMC::Transition::Reboot, "reboot.target"}};
Josh D. King5162a7b2016-12-19 16:15:00 -060027
Andrew Geissler58a18012018-01-19 19:36:05 -080028constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
29constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
30constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
Josh D. Kingd3e58472017-02-02 11:09:11 -060031constexpr auto SYSTEMD_PRP_INTERFACE = "org.freedesktop.DBus.Properties";
Josh D. Kingd3e58472017-02-02 11:09:11 -060032
33void BMC::discoverInitialState()
34{
35 sdbusplus::message::variant<std::string> currentState;
Josh D. King2b5d8872017-02-21 13:37:17 -060036 sdbusplus::message::object_path unitTargetPath;
Josh D. Kingd3e58472017-02-02 11:09:11 -060037
Andrew Geissler58a18012018-01-19 19:36:05 -080038 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
39 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King2b5d8872017-02-21 13:37:17 -060040
41 method.append(obmcStandbyTarget);
42
Anthony Wilson32c532e2018-10-25 21:56:07 -050043 try
Josh D. King2b5d8872017-02-21 13:37:17 -060044 {
Anthony Wilson32c532e2018-10-25 21:56:07 -050045 auto result = this->bus.call(method);
46 result.read(unitTargetPath);
47 }
48 catch (const SdBusError& e)
49 {
50 log<level::ERR>("Error in GetUnit call", entry("ERROR=%s", e.what()));
Josh D. King2b5d8872017-02-21 13:37:17 -060051 return;
52 }
53
Andrew Geissler58a18012018-01-19 19:36:05 -080054 method = this->bus.new_method_call(
55 SYSTEMD_SERVICE,
56 static_cast<const std::string&>(unitTargetPath).c_str(),
57 SYSTEMD_PRP_INTERFACE, "Get");
Josh D. Kingd3e58472017-02-02 11:09:11 -060058
59 method.append("org.freedesktop.systemd1.Unit", "ActiveState");
60
Anthony Wilson32c532e2018-10-25 21:56:07 -050061 try
Josh D. King2b5d8872017-02-21 13:37:17 -060062 {
Anthony Wilson32c532e2018-10-25 21:56:07 -050063 auto result = this->bus.call(method);
64
65 // Is obmc-standby.target active or inactive?
66 result.read(currentState);
67 }
68 catch (const SdBusError& e)
69 {
70 log<level::INFO>("Error in ActiveState Get",
71 entry("ERROR=%s", e.what()));
Josh D. King2b5d8872017-02-21 13:37:17 -060072 return;
73 }
Josh D. Kingd3e58472017-02-02 11:09:11 -060074
Anthony Wilson32c532e2018-10-25 21:56:07 -050075 auto currentStateStr =
76 sdbusplus::message::variant_ns::get<std::string>(currentState);
77 if (currentStateStr == activeState)
Josh D. Kingd3e58472017-02-02 11:09:11 -060078 {
79 log<level::INFO>("Setting the BMCState field",
Andrew Geissler58a18012018-01-19 19:36:05 -080080 entry("CURRENT_BMC_STATE=%s", "BMC_READY"));
Josh D. Kingd3e58472017-02-02 11:09:11 -060081 this->currentBMCState(BMCState::Ready);
82
Andrew Geissler58a18012018-01-19 19:36:05 -080083 // Unsubscribe so we stop processing all other signals
84 method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
85 SYSTEMD_INTERFACE, "Unsubscribe");
Anthony Wilson32c532e2018-10-25 21:56:07 -050086 try
87 {
88 this->bus.call(method);
89 this->stateSignal.release();
90 }
91 catch (const SdBusError& e)
92 {
93 log<level::INFO>("Error in Unsubscribe",
94 entry("ERROR=%s", e.what()));
95 }
Josh D. Kingd3e58472017-02-02 11:09:11 -060096 }
97 else
98 {
99 log<level::INFO>("Setting the BMCState field",
Andrew Geissler58a18012018-01-19 19:36:05 -0800100 entry("CURRENT_BMC_STATE=%s", "BMC_NOTREADY"));
Josh D. Kingd3e58472017-02-02 11:09:11 -0600101 this->currentBMCState(BMCState::NotReady);
102 }
103
104 return;
105}
106
Josh D. King6db38222016-12-19 14:52:40 -0600107void BMC::subscribeToSystemdSignals()
108{
Andrew Geissler58a18012018-01-19 19:36:05 -0800109 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
110 SYSTEMD_INTERFACE, "Subscribe");
Anthony Wilson32c532e2018-10-25 21:56:07 -0500111
112 try
113 {
114 this->bus.call(method);
115 }
116 catch (const SdBusError& e)
117 {
118 log<level::INFO>("Error in Subscribe", entry("ERROR=%s", e.what()));
119 }
Josh D. King6db38222016-12-19 14:52:40 -0600120
121 return;
122}
123
Josh D. King5162a7b2016-12-19 16:15:00 -0600124void BMC::executeTransition(const Transition tranReq)
125{
Andrew Geissler58a18012018-01-19 19:36:05 -0800126 // Check to make sure it can be found
Josh D. King5162a7b2016-12-19 16:15:00 -0600127 auto iter = SYSTEMD_TABLE.find(tranReq);
Andrew Geissler58a18012018-01-19 19:36:05 -0800128 if (iter == SYSTEMD_TABLE.end())
129 return;
Josh D. King5162a7b2016-12-19 16:15:00 -0600130
131 const auto& sysdUnit = iter->second;
132
Andrew Geissler58a18012018-01-19 19:36:05 -0800133 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
134 SYSTEMD_INTERFACE, "StartUnit");
Andrew Geissler181f8362017-06-30 16:43:05 -0500135 // The only valid transition is reboot and that
136 // needs to be irreversible once started
137 method.append(sysdUnit, "replace-irreversibly");
Josh D. King5162a7b2016-12-19 16:15:00 -0600138
Anthony Wilson32c532e2018-10-25 21:56:07 -0500139 try
140 {
141 this->bus.call(method);
142 }
143 catch (const SdBusError& e)
144 {
145 log<level::INFO>("Error in StartUnit - replace-irreversibly",
146 entry("ERROR=%s", e.what()));
147 }
148
Josh D. King5162a7b2016-12-19 16:15:00 -0600149 return;
150}
151
Patrick Williamsd32f8182017-05-05 15:55:24 -0500152int BMC::bmcStateChange(sdbusplus::message::message& msg)
Josh D. Kingd613b812016-12-19 16:47:45 -0600153{
Andrew Geissler58a18012018-01-19 19:36:05 -0800154 uint32_t newStateID{};
Josh D. Kingd613b812016-12-19 16:47:45 -0600155 sdbusplus::message::object_path newStateObjPath;
156 std::string newStateUnit{};
157 std::string newStateResult{};
158
Andrew Geissler58a18012018-01-19 19:36:05 -0800159 // Read the msg and populate each variable
Patrick Williamsd32f8182017-05-05 15:55:24 -0500160 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Josh D. Kingd613b812016-12-19 16:47:45 -0600161
Andrew Geissler58a18012018-01-19 19:36:05 -0800162 // Caught the signal that indicates the BMC is now BMC_READY
163 if ((newStateUnit == obmcStandbyTarget) && (newStateResult == signalDone))
Josh D. Kingd613b812016-12-19 16:47:45 -0600164 {
165 log<level::INFO>("BMC_READY");
166 this->currentBMCState(BMCState::Ready);
167
Andrew Geissler58a18012018-01-19 19:36:05 -0800168 // Unsubscribe so we stop processing all other signals
169 auto method =
170 this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
171 SYSTEMD_INTERFACE, "Unsubscribe");
Anthony Wilson32c532e2018-10-25 21:56:07 -0500172
173 try
174 {
175 this->bus.call(method);
176 this->stateSignal.release();
177 }
178 catch (const SdBusError& e)
179 {
180 log<level::INFO>("Error in Unsubscribe",
181 entry("ERROR=%s", e.what()));
182 }
Josh D. Kingd613b812016-12-19 16:47:45 -0600183 }
184
185 return 0;
186}
187
Josh D. King6db38222016-12-19 14:52:40 -0600188BMC::Transition BMC::requestedBMCTransition(Transition value)
189{
Andrew Geissler58a18012018-01-19 19:36:05 -0800190 log<level::INFO>("Setting the RequestedBMCTransition field",
191 entry("REQUESTED_BMC_TRANSITION=0x%s",
192 convertForMessage(value).c_str()));
Josh D. King6db38222016-12-19 14:52:40 -0600193
Josh D. King5162a7b2016-12-19 16:15:00 -0600194 executeTransition(value);
195 return server::BMC::requestedBMCTransition(value);
Josh D. King6db38222016-12-19 14:52:40 -0600196}
197
Josh D. Kingd613b812016-12-19 16:47:45 -0600198BMC::BMCState BMC::currentBMCState(BMCState value)
199{
200 log<level::INFO>(
Andrew Geissler58a18012018-01-19 19:36:05 -0800201 "Setting the BMCState field",
202 entry("CURRENT_BMC_STATE=0x%s", convertForMessage(value).c_str()));
Josh D. Kingd613b812016-12-19 16:47:45 -0600203
204 return server::BMC::currentBMCState(value);
205}
206
Matt Spinlere6710b72018-07-12 16:05:55 -0500207uint64_t BMC::lastRebootTime() const
208{
209 using namespace std::chrono;
210 struct sysinfo info;
211
212 auto rc = sysinfo(&info);
213 assert(rc == 0);
214
215 // Since uptime is in seconds, also get the current time in seconds.
216 auto now = time_point_cast<seconds>(system_clock::now());
217 auto rebootTime = now - seconds(info.uptime);
218
219 return duration_cast<milliseconds>(rebootTime.time_since_epoch()).count();
220}
221
Josh D. Kingbdd9cb72016-12-19 11:13:43 -0600222} // namespace manager
223} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700224} // namespace phosphor