blob: 5b1e03bc11f00b7acfe3de0782b80156528ebe6e [file] [log] [blame]
Andrew Geissler36529022016-11-29 15:23:54 -06001#include <iostream>
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -06002#include <map>
3#include <string>
Andrew Geissleref3c1842016-12-01 12:33:09 -06004#include <systemd/sd-bus.h>
Michael Tritz206a8332017-02-06 16:01:23 -06005#include <sdbusplus/server.hpp>
Saqib Khana8006a22017-02-14 11:37:08 -06006#include <phosphor-logging/log.hpp>
Andrew Geissler36529022016-11-29 15:23:54 -06007#include "host_state_manager.hpp"
8
9namespace phosphor
10{
11namespace state
12{
13namespace manager
14{
15
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060016// When you see server:: you know we're referencing our base class
17namespace server = sdbusplus::xyz::openbmc_project::State::server;
18
Andrew Geissler1e3bf942016-12-13 15:32:22 -060019using namespace phosphor::logging;
20
Andrew Geissler4da7e002017-01-24 15:21:40 -060021constexpr auto HOST_STATE_POWEROFF_TGT = "obmc-chassis-stop@0.target";
22constexpr auto HOST_STATE_POWERON_TGT = "obmc-chassis-start@0.target";
Michael Tritz206a8332017-02-06 16:01:23 -060023constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-quiesce-host@0.target";
Andrew Geissler4da7e002017-01-24 15:21:40 -060024
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060025/* Map a transition to it's systemd target */
26const std::map<server::Host::Transition,std::string> SYSTEMD_TARGET_TABLE =
27{
Andrew Geissler4da7e002017-01-24 15:21:40 -060028 {server::Host::Transition::Off, HOST_STATE_POWEROFF_TGT},
29 {server::Host::Transition::On, HOST_STATE_POWERON_TGT}
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060030};
31
32constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
33constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
34constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
35
36constexpr auto SYSTEM_SERVICE = "org.openbmc.managers.System";
37constexpr auto SYSTEM_OBJ_PATH = "/org/openbmc/managers/System";
38constexpr auto SYSTEM_INTERFACE = SYSTEM_SERVICE;
39
Michael Tritz206a8332017-02-06 16:01:23 -060040constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
Leonel Gonzalezf318d872017-03-16 13:47:49 -050041constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
Michael Tritz206a8332017-02-06 16:01:23 -060042constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
43
Saqib Khancbe08d12017-03-10 01:29:20 -060044constexpr auto REBOOTCOUNTER_SERVICE("org.openbmc.Sensors");
45constexpr auto REBOOTCOUNTER_PATH("/org/openbmc/sensors/host/BootCount");
46constexpr auto REBOOTCOUNTER_INTERFACE("org.openbmc.SensorValue");
47
48const sdbusplus::message::variant<int> DEFAULT_BOOTCOUNT = 2;
49
Andrew Geissleref621162016-12-08 12:56:21 -060050/* Map a system state to the HostState */
Andrew Geissleref621162016-12-08 12:56:21 -060051const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
52 {"HOST_BOOTING", server::Host::HostState::Running},
Saqib Khanadaa7212017-02-23 13:19:28 -060053 {"HOST_POWERED_OFF", server::Host::HostState::Off},
54 {"HOST_QUIESCED", server::Host::HostState::Quiesced}
Andrew Geissleref621162016-12-08 12:56:21 -060055};
56
Andrew Geissler4da7e002017-01-24 15:21:40 -060057void Host::subscribeToSystemdSignals()
58{
59 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
60 SYSTEMD_OBJ_PATH,
61 SYSTEMD_INTERFACE,
62 "Subscribe");
63 this->bus.call_noreply(method);
64
65 return;
66}
67
Andrew Geissleref3c1842016-12-01 12:33:09 -060068// TODO - Will be rewritten once sdbusplus client bindings are in place
69// and persistent storage design is in place
70void Host::determineInitialState()
71{
72 std::string sysState;
73
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060074 auto method = this->bus.new_method_call(SYSTEM_SERVICE,
75 SYSTEM_OBJ_PATH,
76 SYSTEM_INTERFACE,
Andrew Geissleref3c1842016-12-01 12:33:09 -060077 "getSystemState");
78
79 auto reply = this->bus.call(method);
80
81 reply.read(sysState);
82
83 if(sysState == "HOST_BOOTED")
84 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060085 log<level::INFO>("Initial Host State will be Running",
86 entry("CURRENT_HOST_STATE=%s",
87 convertForMessage(HostState::Running).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060088 server::Host::currentHostState(HostState::Running);
89 server::Host::requestedHostTransition(Transition::On);
Andrew Geissleref3c1842016-12-01 12:33:09 -060090 }
91 else
92 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060093 log<level::INFO>("Initial Host State will be Off",
94 entry("CURRENT_HOST_STATE=%s",
95 convertForMessage(HostState::Off).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060096 server::Host::currentHostState(HostState::Off);
97 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060098 }
99
100 // Set transition initially to Off
101 // TODO - Eventually need to restore this from persistent storage
Andrew Geissler3e3b84b2016-12-02 15:46:17 -0600102 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600103
104 return;
105}
106
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600107void Host::executeTransition(Transition tranReq)
108{
109 auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
110
111 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
112 SYSTEMD_OBJ_PATH,
113 SYSTEMD_INTERFACE,
114 "StartUnit");
115
116 method.append(sysdUnit);
117 method.append("replace");
118
Andrew Geissler4da7e002017-01-24 15:21:40 -0600119 this->bus.call_noreply(method);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600120
121 return;
122}
123
Michael Tritz206a8332017-02-06 16:01:23 -0600124bool Host::isAutoReboot()
125{
126 sdbusplus::message::variant<std::string> autoRebootParam;
127 std::string strParam;
128
129 std::string HOST_PATH("/org/openbmc/settings/host0");
130 std::string HOST_INTERFACE("org.openbmc.settings.Host");
131
132 auto mapper = this->bus.new_method_call(MAPPER_BUSNAME,
133 MAPPER_PATH,
134 MAPPER_INTERFACE,
135 "GetObject");
136
137 mapper.append(HOST_PATH, std::vector<std::string>({HOST_INTERFACE}));
138 auto mapperResponseMsg = this->bus.call(mapper);
139
140 if (mapperResponseMsg.is_method_error())
141 {
142 log<level::ERR>("Error in mapper call");
143 return false;
144 }
145
146 std::map<std::string, std::vector<std::string>> mapperResponse;
147 mapperResponseMsg.read(mapperResponse);
148 if (mapperResponse.empty())
149 {
150 log<level::ERR>("Error reading mapper response");
151 return false;
152 }
153
154 const auto& host = mapperResponse.begin()->first;
155
156 auto method = this->bus.new_method_call(host.c_str(),
157 HOST_PATH.c_str(),
158 "org.freedesktop.DBus.Properties",
159 "Get");
160
161 method.append(HOST_INTERFACE.c_str(), "auto_reboot");
162 auto reply = this->bus.call(method);
163
164 if (reply.is_method_error())
165 {
166 log<level::ERR>("Error in auto_reboot Get");
167 return false;
168 }
169
170 reply.read(autoRebootParam);
171 strParam =
172 sdbusplus::message::variant_ns::get<std::string>(autoRebootParam);
173
174 if (strParam.empty())
175 {
176 log<level::ERR>("Error reading auto_reboot response");
177 return false;
178 }
179
Saqib Khancbe08d12017-03-10 01:29:20 -0600180 sdbusplus::message::variant<int> rebootCounterParam;
181 method = this->bus.new_method_call(REBOOTCOUNTER_SERVICE,
182 REBOOTCOUNTER_PATH,
183 REBOOTCOUNTER_INTERFACE,
184 "getValue");
185 reply = this->bus.call(method);
186 if (reply.is_method_error())
187 {
188 log<level::ERR>("Error in BOOTCOUNT getValue");
189 return false;
190 }
191 reply.read(rebootCounterParam);
192
Michael Tritz206a8332017-02-06 16:01:23 -0600193 if (strParam == "yes")
194 {
Saqib Khancbe08d12017-03-10 01:29:20 -0600195 method = this->bus.new_method_call(REBOOTCOUNTER_SERVICE,
196 REBOOTCOUNTER_PATH,
197 REBOOTCOUNTER_INTERFACE,
198 "setValue");
199 if( rebootCounterParam > 0)
200 {
201 // Reduce BOOTCOUNT by 1
202 method.append((sdbusplus::message::variant_ns::
203 get<int>(rebootCounterParam)) - 1);
204 this->bus.call_noreply(method);
205 return true;
206 }
207 if(rebootCounterParam == 0)
208 {
209 // Reset reboot counter and go to quiesce state
210 method.append(DEFAULT_BOOTCOUNT);
211 this->bus.call_noreply(method);
212 return false;
213 }
Michael Tritz206a8332017-02-06 16:01:23 -0600214 }
215
216 return false;
217}
218
Andrew Geissler4da7e002017-01-24 15:21:40 -0600219int Host::sysStateChangeSignal(sd_bus_message *msg, void *userData,
220 sd_bus_error *retError)
Andrew Geissleref621162016-12-08 12:56:21 -0600221{
Andrew Geissler4da7e002017-01-24 15:21:40 -0600222 return static_cast<Host*>(userData)->sysStateChange(msg, retError);
223}
Andrew Geissleref621162016-12-08 12:56:21 -0600224
Andrew Geissler4da7e002017-01-24 15:21:40 -0600225int Host::sysStateChange(sd_bus_message* msg,
226 sd_bus_error* retError)
227{
228 uint32_t newStateID {};
229 sdbusplus::message::object_path newStateObjPath;
230 std::string newStateUnit{};
231 std::string newStateResult{};
232
233 auto sdPlusMsg = sdbusplus::message::message(msg);
234 //Read the msg and populate each variable
235 sdPlusMsg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
236
237 if((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
238 (newStateResult == "done"))
Andrew Geissleref621162016-12-08 12:56:21 -0600239 {
Andrew Geissler4da7e002017-01-24 15:21:40 -0600240 log<level::INFO>("Recieved signal that host is off");
241 this->currentHostState(server::Host::HostState::Off);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600242
243 // Check if we need to start a new transition (i.e. a Reboot)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600244 if(this->server::Host::requestedHostTransition() ==
245 Transition::Reboot)
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600246 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600247 log<level::DEBUG>("Reached intermediate state, going to next");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600248 this->executeTransition(server::Host::Transition::On);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600249 }
Andrew Geissleref621162016-12-08 12:56:21 -0600250 }
Andrew Geissler4da7e002017-01-24 15:21:40 -0600251 else if((newStateUnit == HOST_STATE_POWERON_TGT) &&
252 (newStateResult == "done"))
253 {
254 log<level::INFO>("Recieved signal that host is running");
255 this->currentHostState(server::Host::HostState::Running);
256 }
Michael Tritz206a8332017-02-06 16:01:23 -0600257 else if((newStateUnit == HOST_STATE_QUIESCE_TGT) &&
258 (newStateResult == "done"))
259 {
260 if (Host::isAutoReboot())
261 {
262 log<level::INFO>("Auto reboot enabled. Beginning reboot...");
263 Host::requestedHostTransition(server::Host::Transition::Reboot);
264 }
265 else
266 {
267 log<level::INFO>("Auto reboot disabled. Maintaining quiesce.");
Saqib Khanadaa7212017-02-23 13:19:28 -0600268 this->currentHostState(server::Host::HostState::Quiesced);
Michael Tritz206a8332017-02-06 16:01:23 -0600269 }
270
271 }
Andrew Geissleref621162016-12-08 12:56:21 -0600272
273 return 0;
274}
275
Andrew Geissleref3c1842016-12-01 12:33:09 -0600276Host::Transition Host::requestedHostTransition(Transition value)
277{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600278 log<level::INFO>(
279 "Host State transaction request",
280 entry("REQUESTED_HOST_TRANSITION=%s",
281 convertForMessage(value).c_str()));
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600282
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600283 Transition tranReq = value;
284 if(value == server::Host::Transition::Reboot)
285 {
286 // On reboot requests we just need to do a off if we're on and
287 // vice versa. The handleSysStateChange() code above handles the
288 // second part of the reboot
289 if(this->server::Host::currentHostState() ==
290 server::Host::HostState::Off)
291 {
292 tranReq = server::Host::Transition::On;
293 }
294 else
295 {
296 tranReq = server::Host::Transition::Off;
297 }
298 }
299
300 executeTransition(tranReq);
Andrew Geissler3e3b84b2016-12-02 15:46:17 -0600301 return server::Host::requestedHostTransition(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600302}
303
Andrew Geissleref3c1842016-12-01 12:33:09 -0600304Host::HostState Host::currentHostState(HostState value)
305{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600306 log<level::INFO>("Change to Host State",
307 entry("CURRENT_HOST_STATE=%s",
308 convertForMessage(value).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -0600309 return server::Host::currentHostState(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600310}
311
Andrew Geissler36529022016-11-29 15:23:54 -0600312} // namespace manager
313} // namespace state
314} // namepsace phosphor