blob: f38882ec4a35cd621552b5ab097d536c1c4b597a [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 =
Naveen Mosesa6d4e652022-04-13 19:27:25 +053026 "xyz.openbmc_project.Chassis.Buttons.Button";
Naveen Moses3bd1cfc2022-02-14 18:04:20 +053027
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
Patrick Williams9a529a62022-07-22 19:26:54 -050035Handler::Handler(sdbusplus::bus_t& bus) : bus(bus)
Matt Spinlerfb35a322018-11-26 14:30:30 -060036{
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),
Naveen Mosesab8dac52022-07-15 19:32:27 +053047 std::bind(std::mem_fn(&Handler::powerReleased), this,
Matt Spinler963c65f2018-11-26 14:46:41 -060048 std::placeholders::_1));
Matt Spinler963c65f2018-11-26 14:46:41 -060049 }
50 }
Patrick Williams9a529a62022-07-22 19:26:54 -050051 catch (const sdbusplus::exception_t& e)
Matt Spinler963c65f2018-11-26 14:46:41 -060052 {
53 // The button wasn't implemented
54 }
Matt Spinler06a5bdd2018-11-26 14:50:48 -060055
56 try
57 {
Matt Spinler69f93512018-11-26 14:55:58 -060058 if (!getService(ID_DBUS_OBJECT_NAME, idButtonIface).empty())
59 {
George Liu9fb15972022-06-20 14:54:38 +080060 lg2::info("Registering ID button handler");
Matt Spinler69f93512018-11-26 14:55:58 -060061 idButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
62 bus,
63 sdbusRule::type::signal() + sdbusRule::member("Released") +
64 sdbusRule::path(ID_DBUS_OBJECT_NAME) +
65 sdbusRule::interface(idButtonIface),
Naveen Mosesab8dac52022-07-15 19:32:27 +053066 std::bind(std::mem_fn(&Handler::idReleased), this,
Matt Spinler69f93512018-11-26 14:55:58 -060067 std::placeholders::_1));
68 }
69 }
Patrick Williams9a529a62022-07-22 19:26:54 -050070 catch (const sdbusplus::exception_t& e)
Matt Spinler69f93512018-11-26 14:55:58 -060071 {
72 // The button wasn't implemented
73 }
74
75 try
76 {
Matt Spinler06a5bdd2018-11-26 14:50:48 -060077 if (!getService(RESET_DBUS_OBJECT_NAME, resetButtonIface).empty())
78 {
George Liu9fb15972022-06-20 14:54:38 +080079 lg2::info("Registering reset button handler");
Matt Spinler06a5bdd2018-11-26 14:50:48 -060080 resetButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
81 bus,
82 sdbusRule::type::signal() + sdbusRule::member("Released") +
83 sdbusRule::path(RESET_DBUS_OBJECT_NAME) +
84 sdbusRule::interface(resetButtonIface),
Naveen Mosesab8dac52022-07-15 19:32:27 +053085 std::bind(std::mem_fn(&Handler::resetReleased), this,
Matt Spinler06a5bdd2018-11-26 14:50:48 -060086 std::placeholders::_1));
87 }
88 }
Patrick Williams9a529a62022-07-22 19:26:54 -050089 catch (const sdbusplus::exception_t& e)
Matt Spinler06a5bdd2018-11-26 14:50:48 -060090 {
91 // The button wasn't implemented
92 }
Naveen Mosesa6d4e652022-04-13 19:27:25 +053093 try
94 {
95 if (!getService(DBG_HS_DBUS_OBJECT_NAME, debugHostSelectorIface)
96 .empty())
97 {
98 lg2::info("Registering debug host selector button handler");
99 debugHSButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
100 bus,
101 sdbusRule::type::signal() + sdbusRule::member("Released") +
102 sdbusRule::path(DBG_HS_DBUS_OBJECT_NAME) +
103 sdbusRule::interface(debugHostSelectorIface),
104 std::bind(std::mem_fn(&Handler::debugHostSelectorReleased),
105 this, std::placeholders::_1));
106 }
107 }
Patrick Williamse3b4e112022-11-26 09:41:58 -0600108 catch (const sdbusplus::exception_t& e)
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530109 {
110 // The button wasn't implemented
111 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600112}
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530113bool Handler::isMultiHost()
114{
115 // return true in case host selector object is available
116 return (!getService(HS_DBUS_OBJECT_NAME, hostSelectorIface).empty());
117}
Matt Spinler963c65f2018-11-26 14:46:41 -0600118std::string Handler::getService(const std::string& path,
119 const std::string& interface) const
120{
121 auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface,
122 "GetObject");
123 method.append(path, std::vector{interface});
Thang Q. Nguyen42507852022-08-12 09:11:35 +0700124 try
125 {
126 auto result = bus.call(method);
127 std::map<std::string, std::vector<std::string>> objectData;
128 result.read(objectData);
129 return objectData.begin()->first;
130 }
Patrick Williamse3b4e112022-11-26 09:41:58 -0600131 catch (const sdbusplus::exception_t& e)
Thang Q. Nguyen42507852022-08-12 09:11:35 +0700132 {
133 return std::string();
134 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600135}
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530136size_t Handler::getHostSelectorValue()
Matt Spinler963c65f2018-11-26 14:46:41 -0600137{
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530138 auto HSService = getService(HS_DBUS_OBJECT_NAME, hostSelectorIface);
139
140 if (HSService.empty())
141 {
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530142 lg2::info("Host selector dbus object not available");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530143 throw std::invalid_argument("Host selector dbus object not available");
144 }
145
146 try
147 {
148 auto method = bus.new_method_call(
149 HSService.c_str(), HS_DBUS_OBJECT_NAME, propertyIface, "Get");
150 method.append(hostSelectorIface, "Position");
151 auto result = bus.call(method);
152
153 std::variant<size_t> HSPositionVariant;
154 result.read(HSPositionVariant);
155
156 auto position = std::get<size_t>(HSPositionVariant);
157 return position;
158 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500159 catch (const sdbusplus::exception_t& e)
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530160 {
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530161 lg2::error("Error reading host selector position: {ERROR}", "ERROR", e);
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530162 throw;
163 }
164}
165bool Handler::poweredOn(size_t hostNumber) const
166{
Potin Laic0fee462022-12-23 14:19:23 +0800167 auto hostObjectName = HOST_STATE_OBJECT_NAME + std::to_string(hostNumber);
168 auto service = getService(hostObjectName.c_str(), hostIface);
169 auto method = bus.new_method_call(service.c_str(), hostObjectName.c_str(),
170 propertyIface, "Get");
171 method.append(hostIface, "CurrentHostState");
Matt Spinler963c65f2018-11-26 14:46:41 -0600172 auto result = bus.call(method);
173
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500174 std::variant<std::string> state;
Matt Spinler963c65f2018-11-26 14:46:41 -0600175 result.read(state);
176
Potin Laic0fee462022-12-23 14:19:23 +0800177 return Host::HostState::Off !=
178 Host::convertHostStateFromString(std::get<std::string>(state));
Matt Spinler963c65f2018-11-26 14:46:41 -0600179}
180
DelphineCCChiu395c7642023-04-19 10:46:47 +0800181void Handler::handlePowerEvent(PowerEvent powerEventType,
182 std::chrono::microseconds duration)
Matt Spinler963c65f2018-11-26 14:46:41 -0600183{
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530184 std::string objPathName;
185 std::string dbusIfaceName;
186 std::string transitionName;
187 std::variant<Host::Transition, Chassis::Transition> transition;
DelphineCCChiu395c7642023-04-19 10:46:47 +0800188 uint64_t durationMs =
189 std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
Matt Spinler963c65f2018-11-26 14:46:41 -0600190
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530191 size_t hostNumber = 0;
192 auto isMultiHostSystem = isMultiHost();
193 if (isMultiHostSystem)
Matt Spinler963c65f2018-11-26 14:46:41 -0600194 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530195 hostNumber = getHostSelectorValue();
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530196 lg2::info("Multi-host system detected : {POSITION}", "POSITION",
George Liu9fb15972022-06-20 14:54:38 +0800197 hostNumber);
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530198 }
199
200 std::string hostNumStr = std::to_string(hostNumber);
201
202 // ignore power and reset button events if BMC is selected.
203 if (isMultiHostSystem && (hostNumber == BMC_POSITION) &&
DelphineCCChiu395c7642023-04-19 10:46:47 +0800204 (powerEventType != PowerEvent::powerReleased) &&
205 (durationMs <= LONG_PRESS_TIME_MS))
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530206 {
George Liu9fb15972022-06-20 14:54:38 +0800207 lg2::info(
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530208 "handlePowerEvent : BMC selected on multi-host system. ignoring power and reset button events...");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530209 return;
210 }
211
212 switch (powerEventType)
213 {
Naveen Mosesab8dac52022-07-15 19:32:27 +0530214 case PowerEvent::powerReleased:
George Liu5b98f4d2022-06-20 13:31:14 +0800215 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800216 if (durationMs <= LONG_PRESS_TIME_MS)
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530217 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800218 objPathName = HOST_STATE_OBJECT_NAME + hostNumStr;
219 dbusIfaceName = hostIface;
220 transitionName = "RequestedHostTransition";
221
222 transition = Host::Transition::On;
223
224 if (poweredOn(hostNumber))
225 {
226 transition = Host::Transition::Off;
227 }
228 lg2::info("handlePowerEvent : Handle power button press ");
229
230 break;
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530231 }
DelphineCCChiu395c7642023-04-19 10:46:47 +0800232 else
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530233 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800234 dbusIfaceName = chassisIface;
235 transitionName = "RequestedPowerTransition";
236 objPathName = CHASSIS_STATE_OBJECT_NAME + hostNumStr;
237 transition = Chassis::Transition::Off;
238
239 /* multi host system :
240 hosts (1 to N) - host shutdown
241 bmc (0) - sled cycle
242 single host system :
243 host(0) - host shutdown
244 */
245 if (isMultiHostSystem && (hostNumber == BMC_POSITION))
246 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530247#if CHASSIS_SYSTEM_RESET_ENABLED
DelphineCCChiu395c7642023-04-19 10:46:47 +0800248 objPathName = CHASSISSYSTEM_STATE_OBJECT_NAME + hostNumStr;
249 transition = Chassis::Transition::PowerCycle;
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530250#else
DelphineCCChiu395c7642023-04-19 10:46:47 +0800251 return;
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530252#endif
DelphineCCChiu395c7642023-04-19 10:46:47 +0800253 }
254 else if (!poweredOn(hostNumber))
255 {
256 lg2::info(
257 "Power is off so ignoring long power button press");
258 return;
259 }
260 lg2::info("handlePowerEvent : handle long power button press");
261 break;
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530262 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600263 }
Naveen Mosesab8dac52022-07-15 19:32:27 +0530264 case PowerEvent::resetReleased:
George Liu5b98f4d2022-06-20 13:31:14 +0800265 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530266 objPathName = HOST_STATE_OBJECT_NAME + hostNumStr;
267 dbusIfaceName = hostIface;
268 transitionName = "RequestedHostTransition";
Matt Spinler963c65f2018-11-26 14:46:41 -0600269
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530270 if (!poweredOn(hostNumber))
271 {
George Liu9fb15972022-06-20 14:54:38 +0800272 lg2::info("Power is off so ignoring reset button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530273 return;
274 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600275
George Liu9fb15972022-06-20 14:54:38 +0800276 lg2::info("Handling reset button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530277 transition = Host::Transition::Reboot;
278 break;
279 }
George Liu5b98f4d2022-06-20 13:31:14 +0800280 default:
281 {
George Liu9fb15972022-06-20 14:54:38 +0800282 lg2::error("{EVENT} is invalid power event. skipping...", "EVENT",
283 static_cast<std::underlying_type_t<PowerEvent>>(
284 powerEventType));
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530285
286 return;
287 }
288 }
289 auto service = getService(objPathName.c_str(), dbusIfaceName);
290 auto method = bus.new_method_call(service.c_str(), objPathName.c_str(),
291 propertyIface, "Set");
292 method.append(dbusIfaceName, transitionName, transition);
293 bus.call(method);
294}
DelphineCCChiu395c7642023-04-19 10:46:47 +0800295void Handler::powerReleased(sdbusplus::message_t& msg)
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530296{
297 try
298 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800299 uint64_t time;
300 msg.read(time);
301
302 handlePowerEvent(PowerEvent::powerReleased,
303 std::chrono::microseconds(time));
Matt Spinler963c65f2018-11-26 14:46:41 -0600304 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500305 catch (const sdbusplus::exception_t& e)
Matt Spinler963c65f2018-11-26 14:46:41 -0600306 {
George Liu9fb15972022-06-20 14:54:38 +0800307 lg2::error("Failed power state change on a power button press: {ERROR}",
308 "ERROR", e);
Matt Spinler963c65f2018-11-26 14:46:41 -0600309 }
310}
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600311
Patrick Williams9a529a62022-07-22 19:26:54 -0500312void Handler::resetReleased(sdbusplus::message_t& /* msg */)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600313{
314 try
315 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800316 // No need to calculate duration, set to 0.
317 handlePowerEvent(PowerEvent::resetReleased,
318 std::chrono::microseconds(0));
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600319 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500320 catch (const sdbusplus::exception_t& e)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600321 {
George Liu9fb15972022-06-20 14:54:38 +0800322 lg2::error("Failed power state change on a reset button press: {ERROR}",
323 "ERROR", e);
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600324 }
325}
Matt Spinler69f93512018-11-26 14:55:58 -0600326
Patrick Williams9a529a62022-07-22 19:26:54 -0500327void Handler::idReleased(sdbusplus::message_t& /* msg */)
Matt Spinler69f93512018-11-26 14:55:58 -0600328{
329 std::string groupPath{ledGroupBasePath};
330 groupPath += ID_LED_GROUP;
331
332 auto service = getService(groupPath, ledGroupIface);
333
334 if (service.empty())
335 {
George Liu9fb15972022-06-20 14:54:38 +0800336 lg2::info("No found {GROUP} during ID button press:", "GROUP",
337 groupPath);
Matt Spinler69f93512018-11-26 14:55:58 -0600338 return;
339 }
340
341 try
342 {
343 auto method = bus.new_method_call(service.c_str(), groupPath.c_str(),
344 propertyIface, "Get");
345 method.append(ledGroupIface, "Asserted");
346 auto result = bus.call(method);
347
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500348 std::variant<bool> state;
Matt Spinler69f93512018-11-26 14:55:58 -0600349 result.read(state);
350
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500351 state = !std::get<bool>(state);
Matt Spinler69f93512018-11-26 14:55:58 -0600352
George Liu9fb15972022-06-20 14:54:38 +0800353 lg2::info(
354 "Changing ID LED group state on ID LED press, GROUP = {GROUP}, STATE = {STATE}",
355 "GROUP", groupPath, "STATE", std::get<bool>(state));
Matt Spinler69f93512018-11-26 14:55:58 -0600356
357 method = bus.new_method_call(service.c_str(), groupPath.c_str(),
358 propertyIface, "Set");
359
360 method.append(ledGroupIface, "Asserted", state);
361 result = bus.call(method);
362 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500363 catch (const sdbusplus::exception_t& e)
Matt Spinler69f93512018-11-26 14:55:58 -0600364 {
George Liu9fb15972022-06-20 14:54:38 +0800365 lg2::error("Error toggling ID LED group on ID button press: {ERROR}",
366 "ERROR", e);
Matt Spinler69f93512018-11-26 14:55:58 -0600367 }
368}
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530369
370void Handler::increaseHostSelectorPosition()
371{
372 try
373 {
374 auto HSService = getService(HS_DBUS_OBJECT_NAME, hostSelectorIface);
375
376 if (HSService.empty())
377 {
378 lg2::error("Host selector service not available");
379 return;
380 }
381
382 auto method =
383 bus.new_method_call(HSService.c_str(), HS_DBUS_OBJECT_NAME,
384 phosphor::button::propertyIface, "GetAll");
385 method.append(phosphor::button::hostSelectorIface);
386 auto result = bus.call(method);
387 std::unordered_map<std::string, std::variant<size_t>> properties;
388 result.read(properties);
389
390 auto maxPosition = std::get<size_t>(properties.at("MaxPosition"));
391 auto position = std::get<size_t>(properties.at("Position"));
392
393 std::variant<size_t> HSPositionVariant =
394 (position < maxPosition) ? (position + 1) : 0;
395
396 method = bus.new_method_call(HSService.c_str(), HS_DBUS_OBJECT_NAME,
397 phosphor::button::propertyIface, "Set");
398 method.append(phosphor::button::hostSelectorIface, "Position");
399
400 method.append(HSPositionVariant);
401 result = bus.call(method);
402 }
Patrick Williamse3b4e112022-11-26 09:41:58 -0600403 catch (const sdbusplus::exception_t& e)
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530404 {
405 lg2::error("Error modifying host selector position : {ERROR}", "ERROR",
406 e);
407 }
408}
409
Patrick Williamse3b4e112022-11-26 09:41:58 -0600410void Handler::debugHostSelectorReleased(sdbusplus::message_t& /* msg */)
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530411{
412 try
413 {
414 increaseHostSelectorPosition();
415 }
Patrick Williamse3b4e112022-11-26 09:41:58 -0600416 catch (const sdbusplus::exception_t& e)
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530417 {
418 lg2::error(
419 "Failed power process debug host selector button press : {ERROR}",
420 "ERROR", e);
421 }
422}
423
Matt Spinlerfb35a322018-11-26 14:30:30 -0600424} // namespace button
425} // namespace phosphor