blob: 3b00fde98011cfe959f7650aa007982cb5fbf213 [file] [log] [blame]
Andrew Geissler0029a5d2017-01-24 14:48:35 -06001#include <sdbusplus/bus.hpp>
Saqib Khana8006a22017-02-14 11:37:08 -06002#include <phosphor-logging/log.hpp>
Andrew Geisslera90a31a2016-12-13 16:16:28 -06003#include "chassis_state_manager.hpp"
4
5namespace phosphor
6{
7namespace state
8{
9namespace manager
10{
11
12// When you see server:: you know we're referencing our base class
13namespace server = sdbusplus::xyz::openbmc_project::State::server;
14
15using namespace phosphor::logging;
16
Josh D. King6838ea92017-04-11 13:39:18 -050017constexpr auto CHASSIS_STATE_POWEROFF_TGT = "obmc-chassis-poweroff@0.target";
18constexpr auto CHASSIS_STATE_POWERON_TGT = "obmc-chassis-poweron@0.target";
Andrew Geissler0029a5d2017-01-24 14:48:35 -060019
Josh D. King697474c2017-03-02 11:15:55 -060020constexpr auto ACTIVE_STATE = "active";
21constexpr auto ACTIVATING_STATE = "activating";
22
Andrew Geisslerce80f242017-01-24 13:25:33 -060023/* Map a transition to it's systemd target */
24const std::map<server::Chassis::Transition,std::string> SYSTEMD_TARGET_TABLE =
25{
Andrew Geissler0029a5d2017-01-24 14:48:35 -060026 {server::Chassis::Transition::Off, CHASSIS_STATE_POWEROFF_TGT},
27 {server::Chassis::Transition::On, CHASSIS_STATE_POWERON_TGT}
Andrew Geisslerce80f242017-01-24 13:25:33 -060028};
29
30constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
31constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
32constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
33
Josh D. King697474c2017-03-02 11:15:55 -060034constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
35constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
36
Andrew Geissler0029a5d2017-01-24 14:48:35 -060037void Chassis::subscribeToSystemdSignals()
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060038{
Andrew Geissler0029a5d2017-01-24 14:48:35 -060039 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
40 SYSTEMD_OBJ_PATH,
41 SYSTEMD_INTERFACE,
42 "Subscribe");
43 this->bus.call_noreply(method);
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060044
Andrew Geissler0029a5d2017-01-24 14:48:35 -060045 return;
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060046}
47
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060048// TODO - Will be rewritten once sdbusplus client bindings are in place
49// and persistent storage design is in place and sdbusplus
50// has read property function
51void Chassis::determineInitialState()
52{
53 sdbusplus::message::variant<int> pgood = -1;
54 auto method = this->bus.new_method_call("org.openbmc.control.Power",
55 "/org/openbmc/control/power0",
56 "org.freedesktop.DBus.Properties",
57 "Get");
58
59 method.append("org.openbmc.control.Power", "pgood");
60 auto reply = this->bus.call(method);
61 reply.read(pgood);
62
63 if(pgood == 1)
64 {
65 log<level::INFO>("Initial Chassis State will be On",
66 entry("CHASSIS_CURRENT_POWER_STATE=%s",
67 convertForMessage(PowerState::On).c_str()));
68 server::Chassis::currentPowerState(PowerState::On);
69 server::Chassis::requestedPowerTransition(Transition::On);
70 }
71 else
72 {
73 log<level::INFO>("Initial Chassis State will be Off",
74 entry("CHASSIS_CURRENT_POWER_STATE=%s",
75 convertForMessage(PowerState::Off).c_str()));
76 server::Chassis::currentPowerState(PowerState::Off);
77 server::Chassis::requestedPowerTransition(Transition::Off);
78 }
79
80 return;
81}
82
Andrew Geisslerce80f242017-01-24 13:25:33 -060083void Chassis::executeTransition(Transition tranReq)
84{
85 auto sysdTarget = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
86
87 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
88 SYSTEMD_OBJ_PATH,
89 SYSTEMD_INTERFACE,
90 "StartUnit");
91
92 method.append(sysdTarget);
93 method.append("replace");
94
95 this->bus.call_noreply(method);
96
97 return;
98}
99
Josh D. King697474c2017-03-02 11:15:55 -0600100bool Chassis::stateActive(const std::string& target)
101{
102 sdbusplus::message::variant<std::string> currentState;
103 sdbusplus::message::object_path unitTargetPath;
104
105 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
106 SYSTEMD_OBJ_PATH,
107 SYSTEMD_INTERFACE,
108 "GetUnit");
109
110 method.append(target);
111 auto result = this->bus.call(method);
112
113 //Check that the bus call didn't result in an error
114 if(result.is_method_error())
115 {
116 log<level::ERR>("Error in bus call - could not resolve GetUnit for:",
117 entry(" %s", SYSTEMD_INTERFACE));
118 return false;
119 }
120
121 result.read(unitTargetPath);
122
123 method = this->bus.new_method_call(SYSTEMD_SERVICE,
124 static_cast<const std::string&>
125 (unitTargetPath).c_str(),
126 SYSTEMD_PROPERTY_IFACE,
127 "Get");
128
129 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
130 result = this->bus.call(method);
131
132 //Check that the bus call didn't result in an error
133 if(result.is_method_error())
134 {
135 log<level::ERR>("Error in bus call - could not resolve Get for:",
136 entry(" %s", SYSTEMD_PROPERTY_IFACE));
137 return false;
138 }
139
140 result.read(currentState);
141
142 if(currentState != ACTIVE_STATE && currentState != ACTIVATING_STATE)
143 {
144 //False - not active
145 return false;
146 }
147 //True - active
148 return true;
149
150}
151
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600152int Chassis::sysStateChangeSignal(sd_bus_message *msg, void *userData,
153 sd_bus_error *retError)
154{
155 return static_cast<Chassis*>(userData)->sysStateChange(msg, retError);
156}
157
158int Chassis::sysStateChange(sd_bus_message* msg,
159 sd_bus_error* retError)
160{
161 uint32_t newStateID {};
162 sdbusplus::message::object_path newStateObjPath;
163 std::string newStateUnit{};
164 std::string newStateResult{};
165
166 auto sdPlusMsg = sdbusplus::message::message(msg);
167 //Read the msg and populate each variable
168 sdPlusMsg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
169
170 if((newStateUnit == CHASSIS_STATE_POWEROFF_TGT) &&
Josh D. King697474c2017-03-02 11:15:55 -0600171 (newStateResult == "done") &&
172 (!stateActive(CHASSIS_STATE_POWERON_TGT)))
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600173 {
174 log<level::INFO>("Recieved signal that power OFF is complete");
175 this->currentPowerState(server::Chassis::PowerState::Off);
176 }
177 else if((newStateUnit == CHASSIS_STATE_POWERON_TGT) &&
Josh D. King697474c2017-03-02 11:15:55 -0600178 (newStateResult == "done") &&
179 (stateActive(CHASSIS_STATE_POWERON_TGT)))
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600180 {
181 log<level::INFO>("Recieved signal that power ON is complete");
182 this->currentPowerState(server::Chassis::PowerState::On);
183 }
184
185 return 0;
186}
187
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600188Chassis::Transition Chassis::requestedPowerTransition(Transition value)
189{
190
191 log<level::INFO>("Change to Chassis Requested Power State",
192 entry("CHASSIS_REQUESTED_POWER_STATE=%s",
193 convertForMessage(value).c_str()));
Andrew Geisslerce80f242017-01-24 13:25:33 -0600194 executeTransition(value);
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600195 return server::Chassis::requestedPowerTransition(value);
196}
197
198Chassis::PowerState Chassis::currentPowerState(PowerState value)
199{
200 log<level::INFO>("Change to Chassis Power State",
201 entry("CHASSIS_CURRENT_POWER_STATE=%s",
202 convertForMessage(value).c_str()));
203 return server::Chassis::currentPowerState(value);
204}
205
206} // namespace manager
207} // namespace state
208} // namepsace phosphor