blob: b1c7ef98c39a89cd3a716dc4d0f58d4a696e9986 [file] [log] [blame]
George Liud6a1bae2022-06-20 13:47:31 +08001#include "config.h"
Matt Spinlerfb35a322018-11-26 14:30:30 -06002
George Liud6a1bae2022-06-20 13:47:31 +08003#include "button_handler.hpp"
Matt Spinler69f93512018-11-26 14:55:58 -06004
George Liu9fb15972022-06-20 14:54:38 +08005#include <phosphor-logging/lg2.hpp>
Matt Spinler963c65f2018-11-26 14:46:41 -06006#include <xyz/openbmc_project/State/Chassis/server.hpp>
7#include <xyz/openbmc_project/State/Host/server.hpp>
Matt Spinlerfb35a322018-11-26 14:30:30 -06008namespace phosphor
9{
10namespace button
11{
Matt Spinler963c65f2018-11-26 14:46:41 -060012
13namespace sdbusRule = sdbusplus::bus::match::rules;
14using namespace sdbusplus::xyz::openbmc_project::State::server;
Matt Spinler963c65f2018-11-26 14:46:41 -060015
Matt Spinler963c65f2018-11-26 14:46:41 -060016constexpr auto chassisIface = "xyz.openbmc_project.State.Chassis";
17constexpr auto hostIface = "xyz.openbmc_project.State.Host";
18constexpr auto powerButtonIface = "xyz.openbmc_project.Chassis.Buttons.Power";
Matt Spinler69f93512018-11-26 14:55:58 -060019constexpr auto idButtonIface = "xyz.openbmc_project.Chassis.Buttons.ID";
Matt Spinler06a5bdd2018-11-26 14:50:48 -060020constexpr auto resetButtonIface = "xyz.openbmc_project.Chassis.Buttons.Reset";
Matt Spinler69f93512018-11-26 14:55:58 -060021constexpr auto ledGroupIface = "xyz.openbmc_project.Led.Group";
Naveen Moses3bd1cfc2022-02-14 18:04:20 +053022constexpr auto ledGroupBasePath = "/xyz/openbmc_project/led/groups/";
23constexpr auto hostSelectorIface =
24 "xyz.openbmc_project.Chassis.Buttons.HostSelector";
25constexpr auto debugHostSelectorIface =
26 "xyz.openbmc_project.Chassis.Buttons.DebugHostSelector";
27
28constexpr auto propertyIface = "org.freedesktop.DBus.Properties";
29constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
Matt Spinler963c65f2018-11-26 14:46:41 -060030
31constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
32constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
Naveen Moses3bd1cfc2022-02-14 18:04:20 +053033constexpr auto BMC_POSITION = 0;
Matt Spinler963c65f2018-11-26 14:46:41 -060034
Matt Spinlerfb35a322018-11-26 14:30:30 -060035Handler::Handler(sdbusplus::bus::bus& bus) : bus(bus)
36{
Matt Spinler963c65f2018-11-26 14:46:41 -060037 try
38 {
39 if (!getService(POWER_DBUS_OBJECT_NAME, powerButtonIface).empty())
40 {
George Liu9fb15972022-06-20 14:54:38 +080041 lg2::info("Starting power button handler");
Matt Spinler963c65f2018-11-26 14:46:41 -060042 powerButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
43 bus,
44 sdbusRule::type::signal() + sdbusRule::member("Released") +
45 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
46 sdbusRule::interface(powerButtonIface),
47 std::bind(std::mem_fn(&Handler::powerPressed), this,
48 std::placeholders::_1));
49
50 powerButtonLongPressReleased =
51 std::make_unique<sdbusplus::bus::match_t>(
52 bus,
53 sdbusRule::type::signal() +
54 sdbusRule::member("PressedLong") +
55 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
56 sdbusRule::interface(powerButtonIface),
57 std::bind(std::mem_fn(&Handler::longPowerPressed), this,
58 std::placeholders::_1));
59 }
60 }
Patrick Williams6d724ce2021-10-06 12:40:26 -050061 catch (const sdbusplus::exception::exception& e)
Matt Spinler963c65f2018-11-26 14:46:41 -060062 {
63 // The button wasn't implemented
64 }
Matt Spinler06a5bdd2018-11-26 14:50:48 -060065
66 try
67 {
Matt Spinler69f93512018-11-26 14:55:58 -060068 if (!getService(ID_DBUS_OBJECT_NAME, idButtonIface).empty())
69 {
George Liu9fb15972022-06-20 14:54:38 +080070 lg2::info("Registering ID button handler");
Matt Spinler69f93512018-11-26 14:55:58 -060071 idButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
72 bus,
73 sdbusRule::type::signal() + sdbusRule::member("Released") +
74 sdbusRule::path(ID_DBUS_OBJECT_NAME) +
75 sdbusRule::interface(idButtonIface),
76 std::bind(std::mem_fn(&Handler::idPressed), this,
77 std::placeholders::_1));
78 }
79 }
Patrick Williams6d724ce2021-10-06 12:40:26 -050080 catch (const sdbusplus::exception::exception& e)
Matt Spinler69f93512018-11-26 14:55:58 -060081 {
82 // The button wasn't implemented
83 }
84
85 try
86 {
Matt Spinler06a5bdd2018-11-26 14:50:48 -060087 if (!getService(RESET_DBUS_OBJECT_NAME, resetButtonIface).empty())
88 {
George Liu9fb15972022-06-20 14:54:38 +080089 lg2::info("Registering reset button handler");
Matt Spinler06a5bdd2018-11-26 14:50:48 -060090 resetButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
91 bus,
92 sdbusRule::type::signal() + sdbusRule::member("Released") +
93 sdbusRule::path(RESET_DBUS_OBJECT_NAME) +
94 sdbusRule::interface(resetButtonIface),
95 std::bind(std::mem_fn(&Handler::resetPressed), this,
96 std::placeholders::_1));
97 }
98 }
Patrick Williams6d724ce2021-10-06 12:40:26 -050099 catch (const sdbusplus::exception::exception& e)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600100 {
101 // The button wasn't implemented
102 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600103}
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530104bool Handler::isMultiHost()
105{
106 // return true in case host selector object is available
107 return (!getService(HS_DBUS_OBJECT_NAME, hostSelectorIface).empty());
108}
Matt Spinler963c65f2018-11-26 14:46:41 -0600109std::string Handler::getService(const std::string& path,
110 const std::string& interface) const
111{
112 auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface,
113 "GetObject");
114 method.append(path, std::vector{interface});
115 auto result = bus.call(method);
116
117 std::map<std::string, std::vector<std::string>> objectData;
118 result.read(objectData);
119
120 return objectData.begin()->first;
121}
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530122size_t Handler::getHostSelectorValue()
Matt Spinler963c65f2018-11-26 14:46:41 -0600123{
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530124 auto HSService = getService(HS_DBUS_OBJECT_NAME, hostSelectorIface);
125
126 if (HSService.empty())
127 {
George Liu9fb15972022-06-20 14:54:38 +0800128 lg2::info("Host Selector dbus object not available");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530129 throw std::invalid_argument("Host selector dbus object not available");
130 }
131
132 try
133 {
134 auto method = bus.new_method_call(
135 HSService.c_str(), HS_DBUS_OBJECT_NAME, propertyIface, "Get");
136 method.append(hostSelectorIface, "Position");
137 auto result = bus.call(method);
138
139 std::variant<size_t> HSPositionVariant;
140 result.read(HSPositionVariant);
141
142 auto position = std::get<size_t>(HSPositionVariant);
143 return position;
144 }
145 catch (const sdbusplus::exception::exception& e)
146 {
George Liu9fb15972022-06-20 14:54:38 +0800147 lg2::error("Error reading Host selector Position: {ERROR}", "ERROR", e);
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530148 throw;
149 }
150}
151bool Handler::poweredOn(size_t hostNumber) const
152{
153 auto chassisObjectName =
154 CHASSIS_STATE_OBJECT_NAME + std::to_string(hostNumber);
155 auto service = getService(chassisObjectName.c_str(), chassisIface);
Matt Spinler963c65f2018-11-26 14:46:41 -0600156 auto method = bus.new_method_call(
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530157 service.c_str(), chassisObjectName.c_str(), propertyIface, "Get");
Matt Spinler963c65f2018-11-26 14:46:41 -0600158 method.append(chassisIface, "CurrentPowerState");
159 auto result = bus.call(method);
160
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500161 std::variant<std::string> state;
Matt Spinler963c65f2018-11-26 14:46:41 -0600162 result.read(state);
163
164 return Chassis::PowerState::On ==
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500165 Chassis::convertPowerStateFromString(std::get<std::string>(state));
Matt Spinler963c65f2018-11-26 14:46:41 -0600166}
167
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530168void Handler::handlePowerEvent(PowerEvent powerEventType)
Matt Spinler963c65f2018-11-26 14:46:41 -0600169{
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530170 std::string objPathName;
171 std::string dbusIfaceName;
172 std::string transitionName;
173 std::variant<Host::Transition, Chassis::Transition> transition;
Matt Spinler963c65f2018-11-26 14:46:41 -0600174
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530175 size_t hostNumber = 0;
176 auto isMultiHostSystem = isMultiHost();
177 if (isMultiHostSystem)
Matt Spinler963c65f2018-11-26 14:46:41 -0600178 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530179 hostNumber = getHostSelectorValue();
George Liu9fb15972022-06-20 14:54:38 +0800180 lg2::info("Multi host system detected : {POSITION}", "POSITION",
181 hostNumber);
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530182 }
183
184 std::string hostNumStr = std::to_string(hostNumber);
185
186 // ignore power and reset button events if BMC is selected.
187 if (isMultiHostSystem && (hostNumber == BMC_POSITION) &&
188 (powerEventType != PowerEvent::longPowerPressed))
189 {
George Liu9fb15972022-06-20 14:54:38 +0800190 lg2::info(
191 "handlePowerEvent : BMC selected on multihost system. ignoring power and reset button events...");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530192 return;
193 }
194
195 switch (powerEventType)
196 {
George Liu5b98f4d2022-06-20 13:31:14 +0800197 case PowerEvent::powerPressed:
198 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530199 objPathName = HOST_STATE_OBJECT_NAME + hostNumStr;
200 dbusIfaceName = hostIface;
201 transitionName = "RequestedHostTransition";
202
203 transition = Host::Transition::On;
204
205 if (poweredOn(hostNumber))
206 {
207 transition = Host::Transition::Off;
208 }
George Liu9fb15972022-06-20 14:54:38 +0800209 lg2::info("handlePowerEvent : handle power button press ");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530210
211 break;
212 }
George Liu5b98f4d2022-06-20 13:31:14 +0800213 case PowerEvent::longPowerPressed:
214 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530215 dbusIfaceName = chassisIface;
216 transitionName = "RequestedPowerTransition";
217 objPathName = CHASSIS_STATE_OBJECT_NAME + hostNumStr;
218 transition = Chassis::Transition::Off;
219
220 /* multi host system :
221 hosts (1 to N) - host shutdown
222 bmc (0) - sled cycle
223 single host system :
224 host(0) - host shutdown
225 */
226 if (isMultiHostSystem && (hostNumber == BMC_POSITION))
227 {
228#if CHASSIS_SYSTEM_RESET_ENABLED
229 objPathName = CHASSISSYSTEM_STATE_OBJECT_NAME + hostNumStr;
230 transition = Chassis::Transition::PowerCycle;
231#else
232 return;
233#endif
234 }
235 else if (!poweredOn(hostNumber))
236 {
George Liu9fb15972022-06-20 14:54:38 +0800237 lg2::info("Power is off so ignoring long power button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530238 return;
239 }
George Liu9fb15972022-06-20 14:54:38 +0800240 lg2::info("handlePowerEvent : handle long power button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530241
242 break;
Matt Spinler963c65f2018-11-26 14:46:41 -0600243 }
244
George Liu5b98f4d2022-06-20 13:31:14 +0800245 case PowerEvent::resetPressed:
246 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530247 objPathName = HOST_STATE_OBJECT_NAME + hostNumStr;
248 dbusIfaceName = hostIface;
249 transitionName = "RequestedHostTransition";
Matt Spinler963c65f2018-11-26 14:46:41 -0600250
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530251 if (!poweredOn(hostNumber))
252 {
George Liu9fb15972022-06-20 14:54:38 +0800253 lg2::info("Power is off so ignoring reset button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530254 return;
255 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600256
George Liu9fb15972022-06-20 14:54:38 +0800257 lg2::info("Handling reset button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530258 transition = Host::Transition::Reboot;
259 break;
260 }
George Liu5b98f4d2022-06-20 13:31:14 +0800261 default:
262 {
George Liu9fb15972022-06-20 14:54:38 +0800263 lg2::error("{EVENT} is invalid power event. skipping...", "EVENT",
264 static_cast<std::underlying_type_t<PowerEvent>>(
265 powerEventType));
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530266
267 return;
268 }
269 }
270 auto service = getService(objPathName.c_str(), dbusIfaceName);
271 auto method = bus.new_method_call(service.c_str(), objPathName.c_str(),
272 propertyIface, "Set");
273 method.append(dbusIfaceName, transitionName, transition);
274 bus.call(method);
275}
George Liu94afa4b2022-06-20 13:36:43 +0800276void Handler::powerPressed(sdbusplus::message::message& /* msg */)
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530277{
278 try
279 {
280 handlePowerEvent(PowerEvent::powerPressed);
Matt Spinler963c65f2018-11-26 14:46:41 -0600281 }
Patrick Williams6d724ce2021-10-06 12:40:26 -0500282 catch (const sdbusplus::exception::exception& e)
Matt Spinler963c65f2018-11-26 14:46:41 -0600283 {
George Liu9fb15972022-06-20 14:54:38 +0800284 lg2::error("Failed power state change on a power button press: {ERROR}",
285 "ERROR", e);
Matt Spinler963c65f2018-11-26 14:46:41 -0600286 }
287}
George Liu94afa4b2022-06-20 13:36:43 +0800288void Handler::longPowerPressed(sdbusplus::message::message& /* msg */)
Matt Spinler963c65f2018-11-26 14:46:41 -0600289{
290 try
291 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530292 handlePowerEvent(PowerEvent::longPowerPressed);
Matt Spinler963c65f2018-11-26 14:46:41 -0600293 }
Patrick Williams6d724ce2021-10-06 12:40:26 -0500294 catch (const sdbusplus::exception::exception& e)
Matt Spinler963c65f2018-11-26 14:46:41 -0600295 {
George Liu9fb15972022-06-20 14:54:38 +0800296 lg2::error("Failed powering off on long power button press: {ERROR}",
297 "ERROR", e);
Matt Spinler963c65f2018-11-26 14:46:41 -0600298 }
Matt Spinlerfb35a322018-11-26 14:30:30 -0600299}
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600300
George Liu94afa4b2022-06-20 13:36:43 +0800301void Handler::resetPressed(sdbusplus::message::message& /* msg */)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600302{
303 try
304 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530305 handlePowerEvent(PowerEvent::resetPressed);
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600306 }
Patrick Williams6d724ce2021-10-06 12:40:26 -0500307 catch (const sdbusplus::exception::exception& e)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600308 {
George Liu9fb15972022-06-20 14:54:38 +0800309 lg2::error("Failed power state change on a reset button press: {ERROR}",
310 "ERROR", e);
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600311 }
312}
Matt Spinler69f93512018-11-26 14:55:58 -0600313
George Liu94afa4b2022-06-20 13:36:43 +0800314void Handler::idPressed(sdbusplus::message::message& /* msg */)
Matt Spinler69f93512018-11-26 14:55:58 -0600315{
316 std::string groupPath{ledGroupBasePath};
317 groupPath += ID_LED_GROUP;
318
319 auto service = getService(groupPath, ledGroupIface);
320
321 if (service.empty())
322 {
George Liu9fb15972022-06-20 14:54:38 +0800323 lg2::info("No found {GROUP} during ID button press:", "GROUP",
324 groupPath);
Matt Spinler69f93512018-11-26 14:55:58 -0600325 return;
326 }
327
328 try
329 {
330 auto method = bus.new_method_call(service.c_str(), groupPath.c_str(),
331 propertyIface, "Get");
332 method.append(ledGroupIface, "Asserted");
333 auto result = bus.call(method);
334
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500335 std::variant<bool> state;
Matt Spinler69f93512018-11-26 14:55:58 -0600336 result.read(state);
337
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500338 state = !std::get<bool>(state);
Matt Spinler69f93512018-11-26 14:55:58 -0600339
George Liu9fb15972022-06-20 14:54:38 +0800340 lg2::info(
341 "Changing ID LED group state on ID LED press, GROUP = {GROUP}, STATE = {STATE}",
342 "GROUP", groupPath, "STATE", std::get<bool>(state));
Matt Spinler69f93512018-11-26 14:55:58 -0600343
344 method = bus.new_method_call(service.c_str(), groupPath.c_str(),
345 propertyIface, "Set");
346
347 method.append(ledGroupIface, "Asserted", state);
348 result = bus.call(method);
349 }
Patrick Williams6d724ce2021-10-06 12:40:26 -0500350 catch (const sdbusplus::exception::exception& e)
Matt Spinler69f93512018-11-26 14:55:58 -0600351 {
George Liu9fb15972022-06-20 14:54:38 +0800352 lg2::error("Error toggling ID LED group on ID button press: {ERROR}",
353 "ERROR", e);
Matt Spinler69f93512018-11-26 14:55:58 -0600354 }
355}
Matt Spinlerfb35a322018-11-26 14:30:30 -0600356} // namespace button
357} // namespace phosphor