blob: 6b13276be57377338065d071145a0a059408c518 [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>
Deepak Kodihalli55f132b2017-07-25 07:36:06 -05007#include <phosphor-logging/elog-errors.hpp>
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -05008#include <experimental/filesystem>
9#include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
Deepak Kodihalli55f132b2017-07-25 07:36:06 -050010#include <xyz/openbmc_project/Common/error.hpp>
Andrew Geissler36529022016-11-29 15:23:54 -060011#include "host_state_manager.hpp"
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050012#include "host_state_serialize.hpp"
13#include "config.h"
14
Andrew Geissler36529022016-11-29 15:23:54 -060015
16namespace phosphor
17{
18namespace state
19{
20namespace manager
21{
22
Andrew Geissler7b90a622017-08-08 11:41:08 -050023// When you see server:: or reboot:: you know we're referencing our base class
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060024namespace server = sdbusplus::xyz::openbmc_project::State::server;
Andrew Geissler7b90a622017-08-08 11:41:08 -050025namespace reboot = sdbusplus::xyz::openbmc_project::Control::Boot::server;
Dhruvaraj Subhashchandrana3b8d7e2017-08-10 05:40:04 -050026namespace bootprogress = sdbusplus::xyz::openbmc_project::State::Boot::server;
27namespace osstatus =
28 sdbusplus::xyz::openbmc_project::State::OperatingSystem::server;
Andrew Geissler1e3bf942016-12-13 15:32:22 -060029using namespace phosphor::logging;
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050030namespace fs = std::experimental::filesystem;
Andrew Geissler1e3bf942016-12-13 15:32:22 -060031
Andrew Geissler4f309e82017-05-24 15:18:01 -050032// host-shutdown notifies host of shutdown and that leads to host-stop being
33// called so initiate a host shutdown with the -shutdown target and consider the
34// host shut down when the -stop target is complete
35constexpr auto HOST_STATE_SOFT_POWEROFF_TGT = "obmc-host-shutdown@0.target";
Josh D. Kingca357922017-04-11 13:44:09 -050036constexpr auto HOST_STATE_POWEROFF_TGT = "obmc-host-stop@0.target";
37constexpr auto HOST_STATE_POWERON_TGT = "obmc-host-start@0.target";
Andrew Geisslera27a6e82017-07-27 16:44:43 -050038constexpr auto HOST_STATE_REBOOT_TGT = "obmc-host-reboot@0.target";
Josh D. Kingcc3fb5d2017-04-19 15:45:10 -050039constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target";
Andrew Geissler4da7e002017-01-24 15:21:40 -060040
Josh D. King929ef702017-03-02 10:58:11 -060041constexpr auto ACTIVE_STATE = "active";
42constexpr auto ACTIVATING_STATE = "activating";
43
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060044/* Map a transition to it's systemd target */
45const std::map<server::Host::Transition,std::string> SYSTEMD_TARGET_TABLE =
46{
Andrew Geissler4f309e82017-05-24 15:18:01 -050047 {server::Host::Transition::Off, HOST_STATE_SOFT_POWEROFF_TGT},
Andrew Geisslera27a6e82017-07-27 16:44:43 -050048 {server::Host::Transition::On, HOST_STATE_POWERON_TGT},
49 {server::Host::Transition::Reboot, HOST_STATE_REBOOT_TGT}
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060050};
51
52constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
53constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
54constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
55
Michael Tritz206a8332017-02-06 16:01:23 -060056constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
Leonel Gonzalezf318d872017-03-16 13:47:49 -050057constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
Michael Tritz206a8332017-02-06 16:01:23 -060058constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
59
Josh D. King929ef702017-03-02 10:58:11 -060060constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
61constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
62
Andrew Geissleref621162016-12-08 12:56:21 -060063/* Map a system state to the HostState */
Andrew Geissleref621162016-12-08 12:56:21 -060064const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
65 {"HOST_BOOTING", server::Host::HostState::Running},
Saqib Khanadaa7212017-02-23 13:19:28 -060066 {"HOST_POWERED_OFF", server::Host::HostState::Off},
67 {"HOST_QUIESCED", server::Host::HostState::Quiesced}
Andrew Geissleref621162016-12-08 12:56:21 -060068};
69
Andrew Geissler4da7e002017-01-24 15:21:40 -060070void Host::subscribeToSystemdSignals()
71{
72 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
73 SYSTEMD_OBJ_PATH,
74 SYSTEMD_INTERFACE,
75 "Subscribe");
76 this->bus.call_noreply(method);
77
78 return;
79}
80
Andrew Geissleref3c1842016-12-01 12:33:09 -060081void Host::determineInitialState()
82{
Andrew Geissleref3c1842016-12-01 12:33:09 -060083
Josh D. King222014e2017-05-16 13:35:21 -050084 if(stateActive(HOST_STATE_POWERON_TGT))
Andrew Geissleref3c1842016-12-01 12:33:09 -060085 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060086 log<level::INFO>("Initial Host State will be Running",
87 entry("CURRENT_HOST_STATE=%s",
88 convertForMessage(HostState::Running).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060089 server::Host::currentHostState(HostState::Running);
90 server::Host::requestedHostTransition(Transition::On);
Andrew Geissleref3c1842016-12-01 12:33:09 -060091 }
92 else
93 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060094 log<level::INFO>("Initial Host State will be Off",
95 entry("CURRENT_HOST_STATE=%s",
96 convertForMessage(HostState::Off).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060097 server::Host::currentHostState(HostState::Off);
98 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060099 }
100
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500101 auto restore = getStateRestoreSetting();
102
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500103 if ((!restore) || (!deserialize(HOST_STATE_PERSIST_PATH, *this)))
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500104 {
105 //set to default value.
106 server::Host::requestedHostTransition(Transition::Off);
107 }
Andrew Geissleref3c1842016-12-01 12:33:09 -0600108
109 return;
110}
111
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500112bool Host::getStateRestoreSetting() const
113{
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500114 using namespace settings;
115 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
116 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500117
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500118 auto method =
119 bus.new_method_call(
120 settings.service(settings.powerRestorePolicy,
121 powerRestoreIntf).c_str(),
122 settings.powerRestorePolicy.c_str(),
123 "org.freedesktop.DBus.Properties",
124 "Get");
125
126 method.append(powerRestoreIntf, "PowerRestorePolicy");
127 auto reply = bus.call(method);
128 if (reply.is_method_error())
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500129 {
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500130 log<level::ERR>("Error in PowerRestorePolicy Get");
131 elog<InternalFailure>();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500132 }
133
134 sdbusplus::message::variant<std::string> result;
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500135 reply.read(result);
136 auto powerPolicy = result.get<std::string>();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500137
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500138 if (RestorePolicy::Policy::Restore ==
139 RestorePolicy::convertPolicyFromString(powerPolicy))
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500140 {
141 return true;
142 }
143 return false;
144}
145
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600146void Host::executeTransition(Transition tranReq)
147{
148 auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
149
150 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
151 SYSTEMD_OBJ_PATH,
152 SYSTEMD_INTERFACE,
153 "StartUnit");
154
155 method.append(sysdUnit);
156 method.append("replace");
157
Andrew Geissler4da7e002017-01-24 15:21:40 -0600158 this->bus.call_noreply(method);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600159
160 return;
161}
162
Josh D. King929ef702017-03-02 10:58:11 -0600163bool Host::stateActive(const std::string& target)
164{
165 sdbusplus::message::variant<std::string> currentState;
166 sdbusplus::message::object_path unitTargetPath;
167
168 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
169 SYSTEMD_OBJ_PATH,
170 SYSTEMD_INTERFACE,
171 "GetUnit");
172
173 method.append(target);
174 auto result = this->bus.call(method);
175
176 //Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500177 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600178 {
179 log<level::ERR>("Error in bus call - could not resolve GetUnit for:",
180 entry(" %s", SYSTEMD_INTERFACE));
181 return false;
182 }
183
184 result.read(unitTargetPath);
185
186 method = this->bus.new_method_call(SYSTEMD_SERVICE,
187 static_cast<const std::string&>
188 (unitTargetPath).c_str(),
189 SYSTEMD_PROPERTY_IFACE,
190 "Get");
191
192 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
193 result = this->bus.call(method);
194
195 //Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500196 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600197 {
198 log<level::ERR>("Error in bus call - could not resolve Get for:",
199 entry(" %s", SYSTEMD_PROPERTY_IFACE));
200 return false;
201 }
202
203 result.read(currentState);
204
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500205 if (currentState != ACTIVE_STATE && currentState != ACTIVATING_STATE)
Josh D. King929ef702017-03-02 10:58:11 -0600206 {
207 //False - not active
208 return false;
209 }
210 //True - active
211 return true;
212}
213
Michael Tritz206a8332017-02-06 16:01:23 -0600214bool Host::isAutoReboot()
215{
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500216 using namespace settings;
Michael Tritz206a8332017-02-06 16:01:23 -0600217
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500218 auto method =
219 bus.new_method_call(
220 settings.service(settings.autoReboot, autoRebootIntf).c_str(),
221 settings.autoReboot.c_str(),
222 "org.freedesktop.DBus.Properties",
223 "Get");
224 method.append(autoRebootIntf, "AutoReboot");
225 auto reply = bus.call(method);
Michael Tritz206a8332017-02-06 16:01:23 -0600226 if (reply.is_method_error())
227 {
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500228 log<level::ERR>("Error in AutoReboot Get");
Michael Tritz206a8332017-02-06 16:01:23 -0600229 return false;
230 }
231
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500232 sdbusplus::message::variant<bool> result;
233 reply.read(result);
234 auto autoReboot = result.get<bool>();
Andrew Geissler7b90a622017-08-08 11:41:08 -0500235 auto rebootCounterParam = reboot::RebootAttempts::attemptsLeft();
Saqib Khancbe08d12017-03-10 01:29:20 -0600236
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500237 if (autoReboot)
Michael Tritz206a8332017-02-06 16:01:23 -0600238 {
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500239 if (rebootCounterParam > 0)
Saqib Khancbe08d12017-03-10 01:29:20 -0600240 {
241 // Reduce BOOTCOUNT by 1
Andrew Geissler7b90a622017-08-08 11:41:08 -0500242 log<level::INFO>("Auto reboot enabled, rebooting");
Saqib Khancbe08d12017-03-10 01:29:20 -0600243 return true;
244 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500245 else if(rebootCounterParam == 0)
Josh D. King929ef702017-03-02 10:58:11 -0600246 {
Saqib Khancbe08d12017-03-10 01:29:20 -0600247 // Reset reboot counter and go to quiesce state
Saqib Khand5ac6352017-04-04 09:53:59 -0500248 log<level::INFO>("Auto reboot enabled. "
249 "HOST BOOTCOUNT already set to 0.");
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500250 attemptsLeft(BOOT_COUNT_MAX_ALLOWED);
Saqib Khand5ac6352017-04-04 09:53:59 -0500251 return false;
252 }
253 else
254 {
255 log<level::INFO>("Auto reboot enabled. "
256 "HOST BOOTCOUNT has an invalid value.");
Saqib Khancbe08d12017-03-10 01:29:20 -0600257 return false;
258 }
Michael Tritz206a8332017-02-06 16:01:23 -0600259 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500260 else
261 {
262 log<level::INFO>("Auto reboot disabled.");
263 return false;
264 }
Michael Tritz206a8332017-02-06 16:01:23 -0600265}
266
Patrick Williamsd22706f2017-05-04 05:42:49 -0500267void Host::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600268{
269 uint32_t newStateID {};
270 sdbusplus::message::object_path newStateObjPath;
271 std::string newStateUnit{};
272 std::string newStateResult{};
273
Andrew Geissler4da7e002017-01-24 15:21:40 -0600274 //Read the msg and populate each variable
Patrick Williamsd22706f2017-05-04 05:42:49 -0500275 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Andrew Geissler4da7e002017-01-24 15:21:40 -0600276
277 if((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
Josh D. King929ef702017-03-02 10:58:11 -0600278 (newStateResult == "done") &&
279 (!stateActive(HOST_STATE_POWERON_TGT)))
Andrew Geissleref621162016-12-08 12:56:21 -0600280 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930281 log<level::INFO>("Received signal that host is off");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600282 this->currentHostState(server::Host::HostState::Off);
Dhruvaraj Subhashchandrana3b8d7e2017-08-10 05:40:04 -0500283 this->bootProgress(bootprogress::Progress::ProgressStages::Unspecified);
284 this->operatingSystemState(osstatus::Status::OSStatus::Inactive);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600285
Andrew Geissleref621162016-12-08 12:56:21 -0600286 }
Andrew Geissler4da7e002017-01-24 15:21:40 -0600287 else if((newStateUnit == HOST_STATE_POWERON_TGT) &&
Josh D. King929ef702017-03-02 10:58:11 -0600288 (newStateResult == "done") &&
289 (stateActive(HOST_STATE_POWERON_TGT)))
Andrew Geissler4da7e002017-01-24 15:21:40 -0600290 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930291 log<level::INFO>("Received signal that host is running");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600292 this->currentHostState(server::Host::HostState::Running);
293 }
Michael Tritz206a8332017-02-06 16:01:23 -0600294 else if((newStateUnit == HOST_STATE_QUIESCE_TGT) &&
Josh D. King29d025d2017-04-27 12:40:22 -0500295 (newStateResult == "done") &&
296 (stateActive(HOST_STATE_QUIESCE_TGT)))
Michael Tritz206a8332017-02-06 16:01:23 -0600297 {
298 if (Host::isAutoReboot())
299 {
Saqib Khand5ac6352017-04-04 09:53:59 -0500300 log<level::INFO>("Beginning reboot...");
Michael Tritz206a8332017-02-06 16:01:23 -0600301 Host::requestedHostTransition(server::Host::Transition::Reboot);
302 }
303 else
304 {
Saqib Khand5ac6352017-04-04 09:53:59 -0500305 log<level::INFO>("Maintaining quiesce");
Saqib Khanadaa7212017-02-23 13:19:28 -0600306 this->currentHostState(server::Host::HostState::Quiesced);
Michael Tritz206a8332017-02-06 16:01:23 -0600307 }
308
309 }
Andrew Geissleref621162016-12-08 12:56:21 -0600310}
311
Andrew Geissler7b90a622017-08-08 11:41:08 -0500312uint32_t Host::decrementRebootCount()
313{
314 auto rebootCount = reboot::RebootAttempts::attemptsLeft();
315 if(rebootCount > 0)
316 {
317 return(reboot::RebootAttempts::attemptsLeft(rebootCount - 1));
318 }
319 return rebootCount;
320}
321
Andrew Geissleref3c1842016-12-01 12:33:09 -0600322Host::Transition Host::requestedHostTransition(Transition value)
323{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600324 log<level::INFO>(
325 "Host State transaction request",
326 entry("REQUESTED_HOST_TRANSITION=%s",
327 convertForMessage(value).c_str()));
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600328
Andrew Geissler7b90a622017-08-08 11:41:08 -0500329 // If this is not a power off request then we need to
330 // decrement the reboot counter. This code should
331 // never prevent a power on, it should just decrement
332 // the count to 0. The quiesce handling is where the
333 // check of this count will occur
334 if(value != server::Host::Transition::Off)
335 {
336 decrementRebootCount();
337 }
338
Andrew Geisslera27a6e82017-07-27 16:44:43 -0500339 executeTransition(value);
Andrew Geissler7b90a622017-08-08 11:41:08 -0500340
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500341 auto retVal = server::Host::requestedHostTransition(value);
342 serialize(*this);
343 return retVal;
Andrew Geissleref3c1842016-12-01 12:33:09 -0600344}
345
Andrew Geissleref3c1842016-12-01 12:33:09 -0600346Host::HostState Host::currentHostState(HostState value)
347{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600348 log<level::INFO>("Change to Host State",
349 entry("CURRENT_HOST_STATE=%s",
350 convertForMessage(value).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -0600351 return server::Host::currentHostState(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600352}
353
Andrew Geissler36529022016-11-29 15:23:54 -0600354} // namespace manager
355} // namespace state
356} // namepsace phosphor