blob: 72d2f6551e006772acaca91db9278efcd7b886a1 [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
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));
49
Naveen Mosesab8dac52022-07-15 19:32:27 +053050 powerButtonLongPressed = std::make_unique<sdbusplus::bus::match_t>(
51 bus,
52 sdbusRule::type::signal() + sdbusRule::member("PressedLong") +
53 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
54 sdbusRule::interface(powerButtonIface),
55 std::bind(std::mem_fn(&Handler::longPowerPressed), this,
56 std::placeholders::_1));
Matt Spinler963c65f2018-11-26 14:46:41 -060057 }
58 }
Patrick Williams9a529a62022-07-22 19:26:54 -050059 catch (const sdbusplus::exception_t& e)
Matt Spinler963c65f2018-11-26 14:46:41 -060060 {
61 // The button wasn't implemented
62 }
Matt Spinler06a5bdd2018-11-26 14:50:48 -060063
64 try
65 {
Matt Spinler69f93512018-11-26 14:55:58 -060066 if (!getService(ID_DBUS_OBJECT_NAME, idButtonIface).empty())
67 {
George Liu9fb15972022-06-20 14:54:38 +080068 lg2::info("Registering ID button handler");
Matt Spinler69f93512018-11-26 14:55:58 -060069 idButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
70 bus,
71 sdbusRule::type::signal() + sdbusRule::member("Released") +
72 sdbusRule::path(ID_DBUS_OBJECT_NAME) +
73 sdbusRule::interface(idButtonIface),
Naveen Mosesab8dac52022-07-15 19:32:27 +053074 std::bind(std::mem_fn(&Handler::idReleased), this,
Matt Spinler69f93512018-11-26 14:55:58 -060075 std::placeholders::_1));
76 }
77 }
Patrick Williams9a529a62022-07-22 19:26:54 -050078 catch (const sdbusplus::exception_t& e)
Matt Spinler69f93512018-11-26 14:55:58 -060079 {
80 // The button wasn't implemented
81 }
82
83 try
84 {
Matt Spinler06a5bdd2018-11-26 14:50:48 -060085 if (!getService(RESET_DBUS_OBJECT_NAME, resetButtonIface).empty())
86 {
George Liu9fb15972022-06-20 14:54:38 +080087 lg2::info("Registering reset button handler");
Matt Spinler06a5bdd2018-11-26 14:50:48 -060088 resetButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
89 bus,
90 sdbusRule::type::signal() + sdbusRule::member("Released") +
91 sdbusRule::path(RESET_DBUS_OBJECT_NAME) +
92 sdbusRule::interface(resetButtonIface),
Naveen Mosesab8dac52022-07-15 19:32:27 +053093 std::bind(std::mem_fn(&Handler::resetReleased), this,
Matt Spinler06a5bdd2018-11-26 14:50:48 -060094 std::placeholders::_1));
95 }
96 }
Patrick Williams9a529a62022-07-22 19:26:54 -050097 catch (const sdbusplus::exception_t& e)
Matt Spinler06a5bdd2018-11-26 14:50:48 -060098 {
99 // The button wasn't implemented
100 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600101}
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530102bool Handler::isMultiHost()
103{
104 // return true in case host selector object is available
105 return (!getService(HS_DBUS_OBJECT_NAME, hostSelectorIface).empty());
106}
Matt Spinler963c65f2018-11-26 14:46:41 -0600107std::string Handler::getService(const std::string& path,
108 const std::string& interface) const
109{
110 auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface,
111 "GetObject");
112 method.append(path, std::vector{interface});
113 auto result = bus.call(method);
114
115 std::map<std::string, std::vector<std::string>> objectData;
116 result.read(objectData);
117
118 return objectData.begin()->first;
119}
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530120size_t Handler::getHostSelectorValue()
Matt Spinler963c65f2018-11-26 14:46:41 -0600121{
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530122 auto HSService = getService(HS_DBUS_OBJECT_NAME, hostSelectorIface);
123
124 if (HSService.empty())
125 {
George Liu9fb15972022-06-20 14:54:38 +0800126 lg2::info("Host Selector dbus object not available");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530127 throw std::invalid_argument("Host selector dbus object not available");
128 }
129
130 try
131 {
132 auto method = bus.new_method_call(
133 HSService.c_str(), HS_DBUS_OBJECT_NAME, propertyIface, "Get");
134 method.append(hostSelectorIface, "Position");
135 auto result = bus.call(method);
136
137 std::variant<size_t> HSPositionVariant;
138 result.read(HSPositionVariant);
139
140 auto position = std::get<size_t>(HSPositionVariant);
141 return position;
142 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500143 catch (const sdbusplus::exception_t& e)
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530144 {
George Liu9fb15972022-06-20 14:54:38 +0800145 lg2::error("Error reading Host selector Position: {ERROR}", "ERROR", e);
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530146 throw;
147 }
148}
149bool Handler::poweredOn(size_t hostNumber) const
150{
151 auto chassisObjectName =
152 CHASSIS_STATE_OBJECT_NAME + std::to_string(hostNumber);
153 auto service = getService(chassisObjectName.c_str(), chassisIface);
Matt Spinler963c65f2018-11-26 14:46:41 -0600154 auto method = bus.new_method_call(
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530155 service.c_str(), chassisObjectName.c_str(), propertyIface, "Get");
Matt Spinler963c65f2018-11-26 14:46:41 -0600156 method.append(chassisIface, "CurrentPowerState");
157 auto result = bus.call(method);
158
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500159 std::variant<std::string> state;
Matt Spinler963c65f2018-11-26 14:46:41 -0600160 result.read(state);
161
162 return Chassis::PowerState::On ==
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500163 Chassis::convertPowerStateFromString(std::get<std::string>(state));
Matt Spinler963c65f2018-11-26 14:46:41 -0600164}
165
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530166void Handler::handlePowerEvent(PowerEvent powerEventType)
Matt Spinler963c65f2018-11-26 14:46:41 -0600167{
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530168 std::string objPathName;
169 std::string dbusIfaceName;
170 std::string transitionName;
171 std::variant<Host::Transition, Chassis::Transition> transition;
Matt Spinler963c65f2018-11-26 14:46:41 -0600172
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530173 size_t hostNumber = 0;
174 auto isMultiHostSystem = isMultiHost();
175 if (isMultiHostSystem)
Matt Spinler963c65f2018-11-26 14:46:41 -0600176 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530177 hostNumber = getHostSelectorValue();
George Liu9fb15972022-06-20 14:54:38 +0800178 lg2::info("Multi host system detected : {POSITION}", "POSITION",
179 hostNumber);
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530180 }
181
182 std::string hostNumStr = std::to_string(hostNumber);
183
184 // ignore power and reset button events if BMC is selected.
185 if (isMultiHostSystem && (hostNumber == BMC_POSITION) &&
186 (powerEventType != PowerEvent::longPowerPressed))
187 {
George Liu9fb15972022-06-20 14:54:38 +0800188 lg2::info(
189 "handlePowerEvent : BMC selected on multihost system. ignoring power and reset button events...");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530190 return;
191 }
192
193 switch (powerEventType)
194 {
Naveen Mosesab8dac52022-07-15 19:32:27 +0530195 case PowerEvent::powerReleased:
George Liu5b98f4d2022-06-20 13:31:14 +0800196 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530197 objPathName = HOST_STATE_OBJECT_NAME + hostNumStr;
198 dbusIfaceName = hostIface;
199 transitionName = "RequestedHostTransition";
200
201 transition = Host::Transition::On;
202
203 if (poweredOn(hostNumber))
204 {
205 transition = Host::Transition::Off;
206 }
George Liu9fb15972022-06-20 14:54:38 +0800207 lg2::info("handlePowerEvent : handle power button press ");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530208
209 break;
210 }
George Liu5b98f4d2022-06-20 13:31:14 +0800211 case PowerEvent::longPowerPressed:
212 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530213 dbusIfaceName = chassisIface;
214 transitionName = "RequestedPowerTransition";
215 objPathName = CHASSIS_STATE_OBJECT_NAME + hostNumStr;
216 transition = Chassis::Transition::Off;
217
218 /* multi host system :
219 hosts (1 to N) - host shutdown
220 bmc (0) - sled cycle
221 single host system :
222 host(0) - host shutdown
223 */
224 if (isMultiHostSystem && (hostNumber == BMC_POSITION))
225 {
226#if CHASSIS_SYSTEM_RESET_ENABLED
227 objPathName = CHASSISSYSTEM_STATE_OBJECT_NAME + hostNumStr;
228 transition = Chassis::Transition::PowerCycle;
229#else
230 return;
231#endif
232 }
233 else if (!poweredOn(hostNumber))
234 {
George Liu9fb15972022-06-20 14:54:38 +0800235 lg2::info("Power is off so ignoring long power button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530236 return;
237 }
George Liu9fb15972022-06-20 14:54:38 +0800238 lg2::info("handlePowerEvent : handle long power button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530239
240 break;
Matt Spinler963c65f2018-11-26 14:46:41 -0600241 }
242
Naveen Mosesab8dac52022-07-15 19:32:27 +0530243 case PowerEvent::resetReleased:
George Liu5b98f4d2022-06-20 13:31:14 +0800244 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530245 objPathName = HOST_STATE_OBJECT_NAME + hostNumStr;
246 dbusIfaceName = hostIface;
247 transitionName = "RequestedHostTransition";
Matt Spinler963c65f2018-11-26 14:46:41 -0600248
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530249 if (!poweredOn(hostNumber))
250 {
George Liu9fb15972022-06-20 14:54:38 +0800251 lg2::info("Power is off so ignoring reset button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530252 return;
253 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600254
George Liu9fb15972022-06-20 14:54:38 +0800255 lg2::info("Handling reset button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530256 transition = Host::Transition::Reboot;
257 break;
258 }
George Liu5b98f4d2022-06-20 13:31:14 +0800259 default:
260 {
George Liu9fb15972022-06-20 14:54:38 +0800261 lg2::error("{EVENT} is invalid power event. skipping...", "EVENT",
262 static_cast<std::underlying_type_t<PowerEvent>>(
263 powerEventType));
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530264
265 return;
266 }
267 }
268 auto service = getService(objPathName.c_str(), dbusIfaceName);
269 auto method = bus.new_method_call(service.c_str(), objPathName.c_str(),
270 propertyIface, "Set");
271 method.append(dbusIfaceName, transitionName, transition);
272 bus.call(method);
273}
Patrick Williams9a529a62022-07-22 19:26:54 -0500274void Handler::powerReleased(sdbusplus::message_t& /* msg */)
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530275{
276 try
277 {
Naveen Mosesab8dac52022-07-15 19:32:27 +0530278 handlePowerEvent(PowerEvent::powerReleased);
Matt Spinler963c65f2018-11-26 14:46:41 -0600279 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500280 catch (const sdbusplus::exception_t& e)
Matt Spinler963c65f2018-11-26 14:46:41 -0600281 {
George Liu9fb15972022-06-20 14:54:38 +0800282 lg2::error("Failed power state change on a power button press: {ERROR}",
283 "ERROR", e);
Matt Spinler963c65f2018-11-26 14:46:41 -0600284 }
285}
Patrick Williams9a529a62022-07-22 19:26:54 -0500286void Handler::longPowerPressed(sdbusplus::message_t& /* msg */)
Matt Spinler963c65f2018-11-26 14:46:41 -0600287{
288 try
289 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530290 handlePowerEvent(PowerEvent::longPowerPressed);
Matt Spinler963c65f2018-11-26 14:46:41 -0600291 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500292 catch (const sdbusplus::exception_t& e)
Matt Spinler963c65f2018-11-26 14:46:41 -0600293 {
George Liu9fb15972022-06-20 14:54:38 +0800294 lg2::error("Failed powering off on long power button press: {ERROR}",
295 "ERROR", e);
Matt Spinler963c65f2018-11-26 14:46:41 -0600296 }
Matt Spinlerfb35a322018-11-26 14:30:30 -0600297}
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600298
Patrick Williams9a529a62022-07-22 19:26:54 -0500299void Handler::resetReleased(sdbusplus::message_t& /* msg */)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600300{
301 try
302 {
Naveen Mosesab8dac52022-07-15 19:32:27 +0530303 handlePowerEvent(PowerEvent::resetReleased);
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600304 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500305 catch (const sdbusplus::exception_t& e)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600306 {
George Liu9fb15972022-06-20 14:54:38 +0800307 lg2::error("Failed power state change on a reset button press: {ERROR}",
308 "ERROR", e);
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600309 }
310}
Matt Spinler69f93512018-11-26 14:55:58 -0600311
Patrick Williams9a529a62022-07-22 19:26:54 -0500312void Handler::idReleased(sdbusplus::message_t& /* msg */)
Matt Spinler69f93512018-11-26 14:55:58 -0600313{
314 std::string groupPath{ledGroupBasePath};
315 groupPath += ID_LED_GROUP;
316
317 auto service = getService(groupPath, ledGroupIface);
318
319 if (service.empty())
320 {
George Liu9fb15972022-06-20 14:54:38 +0800321 lg2::info("No found {GROUP} during ID button press:", "GROUP",
322 groupPath);
Matt Spinler69f93512018-11-26 14:55:58 -0600323 return;
324 }
325
326 try
327 {
328 auto method = bus.new_method_call(service.c_str(), groupPath.c_str(),
329 propertyIface, "Get");
330 method.append(ledGroupIface, "Asserted");
331 auto result = bus.call(method);
332
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500333 std::variant<bool> state;
Matt Spinler69f93512018-11-26 14:55:58 -0600334 result.read(state);
335
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500336 state = !std::get<bool>(state);
Matt Spinler69f93512018-11-26 14:55:58 -0600337
George Liu9fb15972022-06-20 14:54:38 +0800338 lg2::info(
339 "Changing ID LED group state on ID LED press, GROUP = {GROUP}, STATE = {STATE}",
340 "GROUP", groupPath, "STATE", std::get<bool>(state));
Matt Spinler69f93512018-11-26 14:55:58 -0600341
342 method = bus.new_method_call(service.c_str(), groupPath.c_str(),
343 propertyIface, "Set");
344
345 method.append(ledGroupIface, "Asserted", state);
346 result = bus.call(method);
347 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500348 catch (const sdbusplus::exception_t& e)
Matt Spinler69f93512018-11-26 14:55:58 -0600349 {
George Liu9fb15972022-06-20 14:54:38 +0800350 lg2::error("Error toggling ID LED group on ID button press: {ERROR}",
351 "ERROR", e);
Matt Spinler69f93512018-11-26 14:55:58 -0600352 }
353}
Matt Spinlerfb35a322018-11-26 14:30:30 -0600354} // namespace button
355} // namespace phosphor