blob: 9c771bd9e99b8345f9633a2bc2d04a1d31f7febe [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";
Andrew Geissler8cf2f9a2017-07-21 11:58:04 -050018constexpr auto CHASSIS_STATE_HARD_POWEROFF_TGT = "obmc-chassis-hard-poweroff@0.target";
Josh D. King6838ea92017-04-11 13:39:18 -050019constexpr auto CHASSIS_STATE_POWERON_TGT = "obmc-chassis-poweron@0.target";
Andrew Geissler0029a5d2017-01-24 14:48:35 -060020
Josh D. King697474c2017-03-02 11:15:55 -060021constexpr auto ACTIVE_STATE = "active";
22constexpr auto ACTIVATING_STATE = "activating";
23
Andrew Geisslerce80f242017-01-24 13:25:33 -060024/* Map a transition to it's systemd target */
25const std::map<server::Chassis::Transition,std::string> SYSTEMD_TARGET_TABLE =
26{
Andrew Geissler8cf2f9a2017-07-21 11:58:04 -050027 // Use the hard off target to ensure we shutdown immediately
28 {server::Chassis::Transition::Off, CHASSIS_STATE_HARD_POWEROFF_TGT},
Andrew Geissler0029a5d2017-01-24 14:48:35 -060029 {server::Chassis::Transition::On, CHASSIS_STATE_POWERON_TGT}
Andrew Geisslerce80f242017-01-24 13:25:33 -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
Josh D. King697474c2017-03-02 11:15:55 -060036constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
37constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
38
Andrew Geissler0029a5d2017-01-24 14:48:35 -060039void Chassis::subscribeToSystemdSignals()
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060040{
Andrew Geissler0029a5d2017-01-24 14:48:35 -060041 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
42 SYSTEMD_OBJ_PATH,
43 SYSTEMD_INTERFACE,
44 "Subscribe");
45 this->bus.call_noreply(method);
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060046
Andrew Geissler0029a5d2017-01-24 14:48:35 -060047 return;
Andrew Geissler2ec3a7e2016-12-13 22:01:28 -060048}
49
Andrew Geisslerdff50ed2016-12-13 20:39:04 -060050// TODO - Will be rewritten once sdbusplus client bindings are in place
51// and persistent storage design is in place and sdbusplus
52// has read property function
53void Chassis::determineInitialState()
54{
55 sdbusplus::message::variant<int> pgood = -1;
56 auto method = this->bus.new_method_call("org.openbmc.control.Power",
57 "/org/openbmc/control/power0",
58 "org.freedesktop.DBus.Properties",
59 "Get");
60
61 method.append("org.openbmc.control.Power", "pgood");
62 auto reply = this->bus.call(method);
63 reply.read(pgood);
64
65 if(pgood == 1)
66 {
67 log<level::INFO>("Initial Chassis State will be On",
68 entry("CHASSIS_CURRENT_POWER_STATE=%s",
69 convertForMessage(PowerState::On).c_str()));
70 server::Chassis::currentPowerState(PowerState::On);
71 server::Chassis::requestedPowerTransition(Transition::On);
72 }
73 else
74 {
75 log<level::INFO>("Initial Chassis State will be Off",
76 entry("CHASSIS_CURRENT_POWER_STATE=%s",
77 convertForMessage(PowerState::Off).c_str()));
78 server::Chassis::currentPowerState(PowerState::Off);
79 server::Chassis::requestedPowerTransition(Transition::Off);
80 }
81
82 return;
83}
84
Andrew Geisslerce80f242017-01-24 13:25:33 -060085void Chassis::executeTransition(Transition tranReq)
86{
87 auto sysdTarget = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
88
89 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
90 SYSTEMD_OBJ_PATH,
91 SYSTEMD_INTERFACE,
92 "StartUnit");
93
94 method.append(sysdTarget);
95 method.append("replace");
96
97 this->bus.call_noreply(method);
98
99 return;
100}
101
Josh D. King697474c2017-03-02 11:15:55 -0600102bool Chassis::stateActive(const std::string& target)
103{
104 sdbusplus::message::variant<std::string> currentState;
105 sdbusplus::message::object_path unitTargetPath;
106
107 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
108 SYSTEMD_OBJ_PATH,
109 SYSTEMD_INTERFACE,
110 "GetUnit");
111
112 method.append(target);
113 auto result = this->bus.call(method);
114
115 //Check that the bus call didn't result in an error
116 if(result.is_method_error())
117 {
118 log<level::ERR>("Error in bus call - could not resolve GetUnit for:",
119 entry(" %s", SYSTEMD_INTERFACE));
120 return false;
121 }
122
123 result.read(unitTargetPath);
124
125 method = this->bus.new_method_call(SYSTEMD_SERVICE,
126 static_cast<const std::string&>
127 (unitTargetPath).c_str(),
128 SYSTEMD_PROPERTY_IFACE,
129 "Get");
130
131 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
132 result = this->bus.call(method);
133
134 //Check that the bus call didn't result in an error
135 if(result.is_method_error())
136 {
137 log<level::ERR>("Error in bus call - could not resolve Get for:",
138 entry(" %s", SYSTEMD_PROPERTY_IFACE));
139 return false;
140 }
141
142 result.read(currentState);
143
144 if(currentState != ACTIVE_STATE && currentState != ACTIVATING_STATE)
145 {
146 //False - not active
147 return false;
148 }
149 //True - active
150 return true;
151
152}
153
Patrick Williams8f8ba392017-05-05 15:47:39 -0500154int Chassis::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600155{
156 uint32_t newStateID {};
157 sdbusplus::message::object_path newStateObjPath;
158 std::string newStateUnit{};
159 std::string newStateResult{};
160
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600161 //Read the msg and populate each variable
Patrick Williams8f8ba392017-05-05 15:47:39 -0500162 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600163
164 if((newStateUnit == CHASSIS_STATE_POWEROFF_TGT) &&
Josh D. King697474c2017-03-02 11:15:55 -0600165 (newStateResult == "done") &&
166 (!stateActive(CHASSIS_STATE_POWERON_TGT)))
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600167 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930168 log<level::INFO>("Received signal that power OFF is complete");
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600169 this->currentPowerState(server::Chassis::PowerState::Off);
170 }
171 else if((newStateUnit == CHASSIS_STATE_POWERON_TGT) &&
Josh D. King697474c2017-03-02 11:15:55 -0600172 (newStateResult == "done") &&
173 (stateActive(CHASSIS_STATE_POWERON_TGT)))
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600174 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930175 log<level::INFO>("Received signal that power ON is complete");
Andrew Geissler0029a5d2017-01-24 14:48:35 -0600176 this->currentPowerState(server::Chassis::PowerState::On);
177 }
178
179 return 0;
180}
181
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600182Chassis::Transition Chassis::requestedPowerTransition(Transition value)
183{
184
185 log<level::INFO>("Change to Chassis Requested Power State",
186 entry("CHASSIS_REQUESTED_POWER_STATE=%s",
187 convertForMessage(value).c_str()));
Andrew Geisslerce80f242017-01-24 13:25:33 -0600188 executeTransition(value);
Andrew Geisslera90a31a2016-12-13 16:16:28 -0600189 return server::Chassis::requestedPowerTransition(value);
190}
191
192Chassis::PowerState Chassis::currentPowerState(PowerState value)
193{
194 log<level::INFO>("Change to Chassis Power State",
195 entry("CHASSIS_CURRENT_POWER_STATE=%s",
196 convertForMessage(value).c_str()));
197 return server::Chassis::currentPowerState(value);
198}
199
200} // namespace manager
201} // namespace state
202} // namepsace phosphor