blob: e16d0ded1d7393ae732e3ec4414b9c136ed7345c [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>
Andrew Geissler1e3bf942016-12-13 15:32:22 -06005#include <log.hpp>
Andrew Geissler36529022016-11-29 15:23:54 -06006#include "host_state_manager.hpp"
7
8namespace phosphor
9{
10namespace state
11{
12namespace manager
13{
14
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060015// When you see server:: you know we're referencing our base class
16namespace server = sdbusplus::xyz::openbmc_project::State::server;
17
Andrew Geissler1e3bf942016-12-13 15:32:22 -060018using namespace phosphor::logging;
19
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060020/* Map a transition to it's systemd target */
21const std::map<server::Host::Transition,std::string> SYSTEMD_TARGET_TABLE =
22{
Andrew Geissleref621162016-12-08 12:56:21 -060023 {server::Host::Transition::Off, "obmc-chassis-stop@0.target"},
24 {server::Host::Transition::On, "obmc-chassis-start@0.target"}
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060025};
26
27constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
28constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
29constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
30
31constexpr auto SYSTEM_SERVICE = "org.openbmc.managers.System";
32constexpr auto SYSTEM_OBJ_PATH = "/org/openbmc/managers/System";
33constexpr auto SYSTEM_INTERFACE = SYSTEM_SERVICE;
34
Andrew Geissleref621162016-12-08 12:56:21 -060035/* Map a system state to the HostState */
36/* TODO:Issue 774 - Use systemd target signals to control host states */
37const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
38 {"HOST_BOOTING", server::Host::HostState::Running},
39 {"HOST_POWERED_OFF", server::Host::HostState::Off}
40};
41
Andrew Geissleref3c1842016-12-01 12:33:09 -060042// TODO - Will be rewritten once sdbusplus client bindings are in place
43// and persistent storage design is in place
44void Host::determineInitialState()
45{
46 std::string sysState;
47
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060048 auto method = this->bus.new_method_call(SYSTEM_SERVICE,
49 SYSTEM_OBJ_PATH,
50 SYSTEM_INTERFACE,
Andrew Geissleref3c1842016-12-01 12:33:09 -060051 "getSystemState");
52
53 auto reply = this->bus.call(method);
54
55 reply.read(sysState);
56
57 if(sysState == "HOST_BOOTED")
58 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060059 log<level::INFO>("Initial Host State will be Running",
60 entry("CURRENT_HOST_STATE=%s",
61 convertForMessage(HostState::Running).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -060062 currentHostState(HostState::Running);
Andrew Geissler359aaaf2016-12-13 13:23:53 -060063 requestedHostTransition(Transition::On);
Andrew Geissleref3c1842016-12-01 12:33:09 -060064 }
65 else
66 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060067 log<level::INFO>("Initial Host State will be Off",
68 entry("CURRENT_HOST_STATE=%s",
69 convertForMessage(HostState::Off).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -060070 currentHostState(HostState::Off);
Andrew Geissler359aaaf2016-12-13 13:23:53 -060071 requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060072 }
73
74 // Set transition initially to Off
75 // TODO - Eventually need to restore this from persistent storage
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060076 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060077
78 return;
79}
80
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060081void Host::executeTransition(Transition tranReq)
82{
83 auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
84
85 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
86 SYSTEMD_OBJ_PATH,
87 SYSTEMD_INTERFACE,
88 "StartUnit");
89
90 method.append(sysdUnit);
91 method.append("replace");
92
93 this->bus.call(method);
94
95 return;
96}
97
Andrew Geissleref621162016-12-08 12:56:21 -060098int Host::handleSysStateChange(sd_bus_message *msg, void *usrData,
99 sd_bus_error *retError)
100{
101 const char *newState = nullptr;
102 auto sdPlusMsg = sdbusplus::message::message(msg);
103 sdPlusMsg.read(newState);
104
Andrew Geissleref621162016-12-08 12:56:21 -0600105 auto it = SYS_HOST_STATE_TABLE.find(newState);
106 if(it != SYS_HOST_STATE_TABLE.end())
107 {
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600108 // This is a state change we're interested in so process it
109 Host::HostState gotoState = it->second;
110 // Grab the host object instance from the userData
Andrew Geissleref621162016-12-08 12:56:21 -0600111 auto hostInst = static_cast<Host*>(usrData);
112 hostInst->currentHostState(gotoState);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600113
114 // Check if we need to start a new transition (i.e. a Reboot)
115 if((gotoState == server::Host::HostState::Off) &&
116 (hostInst->server::Host::requestedHostTransition() ==
117 Transition::Reboot))
118 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600119 log<level::DEBUG>("Reached intermediate state, going to next");
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600120 hostInst->executeTransition(server::Host::Transition::On);
121 }
122 else
123 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600124 log<level::DEBUG>("Reached final state");
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600125 }
Andrew Geissleref621162016-12-08 12:56:21 -0600126 }
Andrew Geissleref621162016-12-08 12:56:21 -0600127
128 return 0;
129}
130
Andrew Geissleref3c1842016-12-01 12:33:09 -0600131Host::Transition Host::requestedHostTransition(Transition value)
132{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600133 log<level::INFO>(
134 "Host State transaction request",
135 entry("REQUESTED_HOST_TRANSITION=%s",
136 convertForMessage(value).c_str()));
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600137
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600138 Transition tranReq = value;
139 if(value == server::Host::Transition::Reboot)
140 {
141 // On reboot requests we just need to do a off if we're on and
142 // vice versa. The handleSysStateChange() code above handles the
143 // second part of the reboot
144 if(this->server::Host::currentHostState() ==
145 server::Host::HostState::Off)
146 {
147 tranReq = server::Host::Transition::On;
148 }
149 else
150 {
151 tranReq = server::Host::Transition::Off;
152 }
153 }
154
155 executeTransition(tranReq);
Andrew Geissler3e3b84b2016-12-02 15:46:17 -0600156 return server::Host::requestedHostTransition(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600157}
158
Andrew Geissleref3c1842016-12-01 12:33:09 -0600159Host::HostState Host::currentHostState(HostState value)
160{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600161 log<level::INFO>("Change to Host State",
162 entry("CURRENT_HOST_STATE=%s",
163 convertForMessage(value).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -0600164 return server::Host::currentHostState(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600165}
166
Andrew Geissler36529022016-11-29 15:23:54 -0600167} // namespace manager
168} // namespace state
169} // namepsace phosphor