blob: a7de92081d57c26f5967b69c13a2e296b61085eb [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";
41constexpr auto MAPPER_PATH = "/xyz/openbmc_project/ObjectMapper";
42constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
43
Andrew Geissleref621162016-12-08 12:56:21 -060044/* Map a system state to the HostState */
Andrew Geissleref621162016-12-08 12:56:21 -060045const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
46 {"HOST_BOOTING", server::Host::HostState::Running},
Saqib Khanadaa7212017-02-23 13:19:28 -060047 {"HOST_POWERED_OFF", server::Host::HostState::Off},
48 {"HOST_QUIESCED", server::Host::HostState::Quiesced}
Andrew Geissleref621162016-12-08 12:56:21 -060049};
50
Andrew Geissler4da7e002017-01-24 15:21:40 -060051void Host::subscribeToSystemdSignals()
52{
53 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
54 SYSTEMD_OBJ_PATH,
55 SYSTEMD_INTERFACE,
56 "Subscribe");
57 this->bus.call_noreply(method);
58
59 return;
60}
61
Andrew Geissleref3c1842016-12-01 12:33:09 -060062// TODO - Will be rewritten once sdbusplus client bindings are in place
63// and persistent storage design is in place
64void Host::determineInitialState()
65{
66 std::string sysState;
67
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060068 auto method = this->bus.new_method_call(SYSTEM_SERVICE,
69 SYSTEM_OBJ_PATH,
70 SYSTEM_INTERFACE,
Andrew Geissleref3c1842016-12-01 12:33:09 -060071 "getSystemState");
72
73 auto reply = this->bus.call(method);
74
75 reply.read(sysState);
76
77 if(sysState == "HOST_BOOTED")
78 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060079 log<level::INFO>("Initial Host State will be Running",
80 entry("CURRENT_HOST_STATE=%s",
81 convertForMessage(HostState::Running).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060082 server::Host::currentHostState(HostState::Running);
83 server::Host::requestedHostTransition(Transition::On);
Andrew Geissleref3c1842016-12-01 12:33:09 -060084 }
85 else
86 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060087 log<level::INFO>("Initial Host State will be Off",
88 entry("CURRENT_HOST_STATE=%s",
89 convertForMessage(HostState::Off).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060090 server::Host::currentHostState(HostState::Off);
91 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060092 }
93
94 // Set transition initially to Off
95 // TODO - Eventually need to restore this from persistent storage
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060096 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060097
98 return;
99}
100
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600101void Host::executeTransition(Transition tranReq)
102{
103 auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
104
105 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
106 SYSTEMD_OBJ_PATH,
107 SYSTEMD_INTERFACE,
108 "StartUnit");
109
110 method.append(sysdUnit);
111 method.append("replace");
112
Andrew Geissler4da7e002017-01-24 15:21:40 -0600113 this->bus.call_noreply(method);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600114
115 return;
116}
117
Michael Tritz206a8332017-02-06 16:01:23 -0600118bool Host::isAutoReboot()
119{
120 sdbusplus::message::variant<std::string> autoRebootParam;
121 std::string strParam;
122
123 std::string HOST_PATH("/org/openbmc/settings/host0");
124 std::string HOST_INTERFACE("org.openbmc.settings.Host");
125
126 auto mapper = this->bus.new_method_call(MAPPER_BUSNAME,
127 MAPPER_PATH,
128 MAPPER_INTERFACE,
129 "GetObject");
130
131 mapper.append(HOST_PATH, std::vector<std::string>({HOST_INTERFACE}));
132 auto mapperResponseMsg = this->bus.call(mapper);
133
134 if (mapperResponseMsg.is_method_error())
135 {
136 log<level::ERR>("Error in mapper call");
137 return false;
138 }
139
140 std::map<std::string, std::vector<std::string>> mapperResponse;
141 mapperResponseMsg.read(mapperResponse);
142 if (mapperResponse.empty())
143 {
144 log<level::ERR>("Error reading mapper response");
145 return false;
146 }
147
148 const auto& host = mapperResponse.begin()->first;
149
150 auto method = this->bus.new_method_call(host.c_str(),
151 HOST_PATH.c_str(),
152 "org.freedesktop.DBus.Properties",
153 "Get");
154
155 method.append(HOST_INTERFACE.c_str(), "auto_reboot");
156 auto reply = this->bus.call(method);
157
158 if (reply.is_method_error())
159 {
160 log<level::ERR>("Error in auto_reboot Get");
161 return false;
162 }
163
164 reply.read(autoRebootParam);
165 strParam =
166 sdbusplus::message::variant_ns::get<std::string>(autoRebootParam);
167
168 if (strParam.empty())
169 {
170 log<level::ERR>("Error reading auto_reboot response");
171 return false;
172 }
173
174 if (strParam == "yes")
175 {
176 return true;
177 }
178
179 return false;
180}
181
Andrew Geissler4da7e002017-01-24 15:21:40 -0600182int Host::sysStateChangeSignal(sd_bus_message *msg, void *userData,
183 sd_bus_error *retError)
Andrew Geissleref621162016-12-08 12:56:21 -0600184{
Andrew Geissler4da7e002017-01-24 15:21:40 -0600185 return static_cast<Host*>(userData)->sysStateChange(msg, retError);
186}
Andrew Geissleref621162016-12-08 12:56:21 -0600187
Andrew Geissler4da7e002017-01-24 15:21:40 -0600188int Host::sysStateChange(sd_bus_message* msg,
189 sd_bus_error* retError)
190{
191 uint32_t newStateID {};
192 sdbusplus::message::object_path newStateObjPath;
193 std::string newStateUnit{};
194 std::string newStateResult{};
195
196 auto sdPlusMsg = sdbusplus::message::message(msg);
197 //Read the msg and populate each variable
198 sdPlusMsg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
199
200 if((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
201 (newStateResult == "done"))
Andrew Geissleref621162016-12-08 12:56:21 -0600202 {
Andrew Geissler4da7e002017-01-24 15:21:40 -0600203 log<level::INFO>("Recieved signal that host is off");
204 this->currentHostState(server::Host::HostState::Off);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600205
206 // Check if we need to start a new transition (i.e. a Reboot)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600207 if(this->server::Host::requestedHostTransition() ==
208 Transition::Reboot)
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600209 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600210 log<level::DEBUG>("Reached intermediate state, going to next");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600211 this->executeTransition(server::Host::Transition::On);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600212 }
Andrew Geissleref621162016-12-08 12:56:21 -0600213 }
Andrew Geissler4da7e002017-01-24 15:21:40 -0600214 else if((newStateUnit == HOST_STATE_POWERON_TGT) &&
215 (newStateResult == "done"))
216 {
217 log<level::INFO>("Recieved signal that host is running");
218 this->currentHostState(server::Host::HostState::Running);
219 }
Michael Tritz206a8332017-02-06 16:01:23 -0600220 else if((newStateUnit == HOST_STATE_QUIESCE_TGT) &&
221 (newStateResult == "done"))
222 {
223 if (Host::isAutoReboot())
224 {
225 log<level::INFO>("Auto reboot enabled. Beginning reboot...");
226 Host::requestedHostTransition(server::Host::Transition::Reboot);
227 }
228 else
229 {
230 log<level::INFO>("Auto reboot disabled. Maintaining quiesce.");
Saqib Khanadaa7212017-02-23 13:19:28 -0600231 this->currentHostState(server::Host::HostState::Quiesced);
Michael Tritz206a8332017-02-06 16:01:23 -0600232 }
233
234 }
Andrew Geissleref621162016-12-08 12:56:21 -0600235
236 return 0;
237}
238
Andrew Geissleref3c1842016-12-01 12:33:09 -0600239Host::Transition Host::requestedHostTransition(Transition value)
240{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600241 log<level::INFO>(
242 "Host State transaction request",
243 entry("REQUESTED_HOST_TRANSITION=%s",
244 convertForMessage(value).c_str()));
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600245
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600246 Transition tranReq = value;
247 if(value == server::Host::Transition::Reboot)
248 {
249 // On reboot requests we just need to do a off if we're on and
250 // vice versa. The handleSysStateChange() code above handles the
251 // second part of the reboot
252 if(this->server::Host::currentHostState() ==
253 server::Host::HostState::Off)
254 {
255 tranReq = server::Host::Transition::On;
256 }
257 else
258 {
259 tranReq = server::Host::Transition::Off;
260 }
261 }
262
263 executeTransition(tranReq);
Andrew Geissler3e3b84b2016-12-02 15:46:17 -0600264 return server::Host::requestedHostTransition(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600265}
266
Andrew Geissleref3c1842016-12-01 12:33:09 -0600267Host::HostState Host::currentHostState(HostState value)
268{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600269 log<level::INFO>("Change to Host State",
270 entry("CURRENT_HOST_STATE=%s",
271 convertForMessage(value).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -0600272 return server::Host::currentHostState(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600273}
274
Andrew Geissler36529022016-11-29 15:23:54 -0600275} // namespace manager
276} // namespace state
277} // namepsace phosphor