blob: 03026ff19442d496ae987e906c64b574f6f6ce68 [file] [log] [blame]
Josh D. Kingbdd9cb72016-12-19 11:13:43 -06001#include <iostream>
Josh D. King5162a7b2016-12-19 16:15:00 -06002#include <string>
Saqib Khana8006a22017-02-14 11:37:08 -06003#include <phosphor-logging/log.hpp>
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 */
23const std::map<server::BMC::Transition, const char*> SYSTEMD_TABLE =
24{
25 {server::BMC::Transition::Reboot, "reboot.target"}
26};
27
Josh D. King6db38222016-12-19 14:52:40 -060028constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
29constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
30constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
31
Josh D. Kingd3e58472017-02-02 11:09:11 -060032constexpr auto SYSTEMD_PRP_INTERFACE = "org.freedesktop.DBus.Properties";
33constexpr auto SYSTEMD_TGT_PATH = "/org/freedesktop/systemd1/unit/"
34 "obmc_2dstandby_2etarget";
35
36void BMC::discoverInitialState()
37{
38 sdbusplus::message::variant<std::string> currentState;
39
40 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
41 SYSTEMD_TGT_PATH,
42 SYSTEMD_PRP_INTERFACE,
43 "Get");
44
45 method.append("org.freedesktop.systemd1.Unit", "ActiveState");
46
47 auto result = this->bus.call(method);
48
49 //Is obmc-standby.target active or inactive?
50 result.read(currentState);
51
52 if(currentState == activeState)
53 {
54 log<level::INFO>("Setting the BMCState field",
55 entry("CURRENT_BMC_STATE=%s",
56 "BMC_READY"));
57 this->currentBMCState(BMCState::Ready);
58
59 //Unsubscribe so we stop processing all other signals
60 method = this->bus.new_method_call(SYSTEMD_SERVICE,
61 SYSTEMD_OBJ_PATH,
62 SYSTEMD_INTERFACE,
63 "Unsubscribe");
64 this->bus.call(method);
65 this->stateSignal.release();
66 }
67 else
68 {
69 log<level::INFO>("Setting the BMCState field",
70 entry("CURRENT_BMC_STATE=%s",
71 "BMC_NOTREADY"));
72 this->currentBMCState(BMCState::NotReady);
73 }
74
75 return;
76}
77
Josh D. King6db38222016-12-19 14:52:40 -060078void BMC::subscribeToSystemdSignals()
79{
80 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
81 SYSTEMD_OBJ_PATH,
82 SYSTEMD_INTERFACE,
83 "Subscribe");
84 this->bus.call(method);
85
86 return;
87}
88
Josh D. King5162a7b2016-12-19 16:15:00 -060089void BMC::executeTransition(const Transition tranReq)
90{
91 //Check to make sure it can be found
92 auto iter = SYSTEMD_TABLE.find(tranReq);
93 if (iter == SYSTEMD_TABLE.end()) return;
94
95 const auto& sysdUnit = iter->second;
96
97 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
98 SYSTEMD_OBJ_PATH,
99 SYSTEMD_INTERFACE,
100 "StartUnit");
101
102 method.append(sysdUnit, "replace");
103
104 this->bus.call(method);
105
106 return;
107}
108
Josh D. Kingd613b812016-12-19 16:47:45 -0600109int BMC::bmcStateChangeSignal(sd_bus_message *msg, void *userData,
110 sd_bus_error *retError)
111{
112 return static_cast<BMC*>(userData)->bmcStateChange(msg, retError);
113}
114
115int BMC::bmcStateChange(sd_bus_message *msg,
116 sd_bus_error *retError)
117{
118 uint32_t newStateID {};
119 sdbusplus::message::object_path newStateObjPath;
120 std::string newStateUnit{};
121 std::string newStateResult{};
122
123 auto sdPlusMsg = sdbusplus::message::message(msg);
124 //Read the msg and populate each variable
125 sdPlusMsg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
126
127 //Caught the signal that indicates the BMC is now BMC_READY
128 if((newStateUnit == obmcStandbyTarget) &&
129 (newStateResult == signalDone))
130 {
131 log<level::INFO>("BMC_READY");
132 this->currentBMCState(BMCState::Ready);
133
134 //Unsubscribe so we stop processing all other signals
135 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
136 SYSTEMD_OBJ_PATH,
137 SYSTEMD_INTERFACE,
138 "Unsubscribe");
139 this->bus.call(method);
140 this->stateSignal.release();
141 }
142
143 return 0;
144}
145
Josh D. King6db38222016-12-19 14:52:40 -0600146BMC::Transition BMC::requestedBMCTransition(Transition value)
147{
148 log<level::INFO>(
149 "Setting the RequestedBMCTransition field",
150 entry("REQUESTED_BMC_TRANSITION=0x%s",
151 convertForMessage(value).c_str()));
Josh D. King6db38222016-12-19 14:52:40 -0600152
Josh D. King5162a7b2016-12-19 16:15:00 -0600153 executeTransition(value);
154 return server::BMC::requestedBMCTransition(value);
Josh D. King6db38222016-12-19 14:52:40 -0600155}
156
Josh D. Kingd613b812016-12-19 16:47:45 -0600157BMC::BMCState BMC::currentBMCState(BMCState value)
158{
159 log<level::INFO>(
160 "Setting the BMCState field",
161 entry("CURRENT_BMC_STATE=0x%s",
162 convertForMessage(value).c_str()));
163
164 return server::BMC::currentBMCState(value);
165}
166
Josh D. King6db38222016-12-19 14:52:40 -0600167
Josh D. Kingbdd9cb72016-12-19 11:13:43 -0600168} // namespace manager
169} // namespace state
170} // namepsace phosphor
171