blob: 93ab200145bfe32cae14685e4057d17e4bd81bfd [file] [log] [blame]
Yuan Li60e7aaf2019-05-28 14:22:40 +08001/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include "xyz/openbmc_project/Common/error.hpp"
17
Yuan Li60e7aaf2019-05-28 14:22:40 +080018#include <ipmid/api.hpp>
19#include <ipmid/utils.hpp>
20#include <nlohmann/json.hpp>
21#include <phosphor-logging/elog-errors.hpp>
Jason M. Billsb08f84e2019-06-10 12:59:42 -070022#include <phosphor-logging/log.hpp>
Yuan Li60e7aaf2019-05-28 14:22:40 +080023#include <sdbusplus/timer.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070024#include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
25
26#include <fstream>
27#include <iostream>
28#include <regex>
Jason M. Billsb08f84e2019-06-10 12:59:42 -070029#include <stdexcept>
30#include <string_view>
Yuan Li60e7aaf2019-05-28 14:22:40 +080031
Jason M. Billsb08f84e2019-06-10 12:59:42 -070032using namespace phosphor::logging;
33
34namespace ipmi::chassis
Yuan Li60e7aaf2019-05-28 14:22:40 +080035{
Jason M. Billsb08f84e2019-06-10 12:59:42 -070036static constexpr const char* buttonIntf = "xyz.openbmc_project.Chassis.Buttons";
Yuan Li60e7aaf2019-05-28 14:22:40 +080037
Jason M. Billsb08f84e2019-06-10 12:59:42 -070038const static constexpr char* idButtonPath =
39 "/xyz/openbmc_project/chassis/buttons/id";
40static constexpr const char* powerButtonPath =
41 "/xyz/openbmc_project/chassis/buttons/power";
42static constexpr const char* resetButtonPath =
43 "/xyz/openbmc_project/chassis/buttons/reset";
44static constexpr const char* interruptButtonPath =
45 "/xyz/openbmc_project/chassis/buttons/nmi";
46
47const static constexpr char* idButtonProp = "ButtonPressed";
48
49const static constexpr char* ledService =
Yuan Li60e7aaf2019-05-28 14:22:40 +080050 "xyz.openbmc_project.LED.GroupManager";
Jason M. Billsb08f84e2019-06-10 12:59:42 -070051const static constexpr char* ledIDOnObj =
Yuan Li60e7aaf2019-05-28 14:22:40 +080052 "/xyz/openbmc_project/led/groups/enclosure_identify";
Jason M. Billsb08f84e2019-06-10 12:59:42 -070053const static constexpr char* ledIDBlinkObj =
Yuan Li60e7aaf2019-05-28 14:22:40 +080054 "/xyz/openbmc_project/led/groups/enclosure_identify_blink";
Jason M. Billsb08f84e2019-06-10 12:59:42 -070055const static constexpr char* ledInterface = "xyz.openbmc_project.Led.Group";
56const static constexpr char* ledProp = "Asserted";
Jason M. Bills09221d72019-07-26 13:38:28 -070057enum class ChassisIDState
58{
59 off = 0,
60 temporary = 1,
61 indefinite = 2,
62};
63static ChassisIDState chassisIDState = ChassisIDState::off;
Yuan Li60e7aaf2019-05-28 14:22:40 +080064
65constexpr size_t defaultIdentifyTimeOut = 15;
66
67std::unique_ptr<phosphor::Timer> identifyTimer
68 __attribute__((init_priority(101)));
69std::unique_ptr<sdbusplus::bus::match_t> matchPtr
70 __attribute__((init_priority(101)));
71
72static void registerChassisFunctions() __attribute__((constructor));
73
74static ipmi::ServiceCache LEDService(ledInterface, ledIDBlinkObj);
75
Jason M. Billsb08f84e2019-06-10 12:59:42 -070076void enclosureIdentifyLed(const char* objName, bool isIdLedOn)
Yuan Li60e7aaf2019-05-28 14:22:40 +080077{
78 auto bus = getSdBus();
79
80 try
81 {
82 std::string service = LEDService.getService(*bus);
83 setDbusProperty(*bus, service, objName, ledInterface, ledProp,
84 isIdLedOn);
85 }
Jason M. Billsb08f84e2019-06-10 12:59:42 -070086 catch (const std::exception& e)
Yuan Li60e7aaf2019-05-28 14:22:40 +080087 {
Jason M. Billsb08f84e2019-06-10 12:59:42 -070088 log<level::ERR>("enclosureIdentifyLed: can't set property",
89 entry("ERR=%s", e.what()));
Yuan Li60e7aaf2019-05-28 14:22:40 +080090 }
91}
92
Jason M. Billsb08f84e2019-06-10 12:59:42 -070093bool getIDState(const char* objName, bool& state)
Yuan Li60e7aaf2019-05-28 14:22:40 +080094{
95 auto bus = getSdBus();
96
97 try
98 {
99 std::string service = LEDService.getService(*bus);
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500100 ipmi::Value enabled = getDbusProperty(*bus, service, objName,
101 ledInterface, ledProp);
Yuan Li60e7aaf2019-05-28 14:22:40 +0800102 state = std::get<bool>(enabled);
103 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500104 catch (const sdbusplus::exception_t& e)
Yuan Li60e7aaf2019-05-28 14:22:40 +0800105 {
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700106 log<level::ERR>("Fail to get property", entry("PATH=%s", objName),
107 entry("ERROR=%s", e.what()));
Yuan Li60e7aaf2019-05-28 14:22:40 +0800108 return false;
109 }
110 return true;
111}
112
113void enclosureIdentifyLedBlinkOff()
114{
Jason M. Bills09221d72019-07-26 13:38:28 -0700115 chassisIDState = ChassisIDState::off;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800116 enclosureIdentifyLed(ledIDBlinkObj, false);
117}
118
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500119void idButtonPropChanged(sdbusplus::message_t& msg)
Yuan Li60e7aaf2019-05-28 14:22:40 +0800120{
121 bool asserted = false;
122 bool buttonPressed = false;
123
124 std::map<std::string, ipmi::Value> props;
125 std::vector<std::string> inval;
126 std::string iface;
127 msg.read(iface, props, inval);
128
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700129 for (const auto& t : props)
Yuan Li60e7aaf2019-05-28 14:22:40 +0800130 {
131 auto key = t.first;
132 auto value = t.second;
133
134 if (key == idButtonProp)
135 {
136 buttonPressed = std::get<bool>(value);
137 }
138 break;
139 }
140
141 if (buttonPressed)
142 {
143 if (identifyTimer->isRunning())
144 {
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700145 log<level::INFO>("ID timer is running");
Yuan Li60e7aaf2019-05-28 14:22:40 +0800146 }
147
148 // make sure timer is stopped
149 identifyTimer->stop();
150
151 if (!getIDState(ledIDBlinkObj, asserted))
152 {
153 return;
154 }
155
156 if (asserted)
157 {
158 // LED is blinking, turn off the LED
Jason M. Bills09221d72019-07-26 13:38:28 -0700159 chassisIDState = ChassisIDState::off;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800160 enclosureIdentifyLed(ledIDBlinkObj, false);
161 enclosureIdentifyLed(ledIDOnObj, false);
162 }
163 else
164 {
165 // toggle the IED on/off
166 if (!getIDState(ledIDOnObj, asserted))
167 {
168 return;
169 }
170 enclosureIdentifyLed(ledIDOnObj, !asserted);
171 }
172 }
173}
174
175void createIdentifyTimer()
176{
177 if (!identifyTimer)
178 {
179 identifyTimer =
180 std::make_unique<phosphor::Timer>(enclosureIdentifyLedBlinkOff);
181 }
182}
183
184ipmi::RspType<> ipmiChassisIdentify(std::optional<uint8_t> interval,
185 std::optional<uint8_t> force)
186{
187 uint8_t identifyInterval = interval.value_or(defaultIdentifyTimeOut);
188 bool forceIdentify = force.value_or(0) & 0x01;
189
190 enclosureIdentifyLed(ledIDOnObj, false);
191 identifyTimer->stop();
192
193 if (identifyInterval || forceIdentify)
194 {
195 enclosureIdentifyLed(ledIDBlinkObj, true);
196 if (forceIdentify)
197 {
Jason M. Bills09221d72019-07-26 13:38:28 -0700198 chassisIDState = ChassisIDState::indefinite;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800199 return ipmi::responseSuccess();
200 }
Jason M. Bills09221d72019-07-26 13:38:28 -0700201 chassisIDState = ChassisIDState::temporary;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800202 // start the timer
203 auto time = std::chrono::duration_cast<std::chrono::microseconds>(
204 std::chrono::seconds(identifyInterval));
205 identifyTimer->start(time);
206 }
207 else
208 {
Jason M. Bills09221d72019-07-26 13:38:28 -0700209 chassisIDState = ChassisIDState::off;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800210 enclosureIdentifyLed(ledIDBlinkObj, false);
211 }
212 return ipmi::responseSuccess();
213}
214
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700215namespace power_policy
216{
217/* helper function for Get Chassis Status Command
218 */
219std::optional<uint2_t> getPowerRestorePolicy()
220{
221 constexpr const char* powerRestorePath =
222 "/xyz/openbmc_project/control/host0/power_restore_policy";
223 constexpr const char* powerRestoreIntf =
224 "xyz.openbmc_project.Control.Power.RestorePolicy";
225 uint2_t restorePolicy = 0;
226 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
227
228 try
229 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500230 auto service = ipmi::getService(*busp, powerRestoreIntf,
231 powerRestorePath);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700232
233 ipmi::Value result =
234 ipmi::getDbusProperty(*busp, service, powerRestorePath,
235 powerRestoreIntf, "PowerRestorePolicy");
236 auto powerRestore = sdbusplus::xyz::openbmc_project::Control::Power::
237 server::RestorePolicy::convertPolicyFromString(
238 std::get<std::string>(result));
239
240 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
241 switch (powerRestore)
242 {
243 case RestorePolicy::Policy::AlwaysOff:
244 restorePolicy = 0x00;
245 break;
246 case RestorePolicy::Policy::Restore:
247 restorePolicy = 0x01;
248 break;
249 case RestorePolicy::Policy::AlwaysOn:
250 restorePolicy = 0x02;
251 break;
Vernon Mauerydcff1502022-09-28 11:12:46 -0700252 default:
253 break;
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700254 }
255 }
256 catch (const std::exception& e)
257 {
258 log<level::ERR>("Failed to fetch PowerRestorePolicy property",
259 entry("ERROR=%s", e.what()),
260 entry("PATH=%s", powerRestorePath),
261 entry("INTERFACE=%s", powerRestoreIntf));
262 return std::nullopt;
263 }
264 return std::make_optional(restorePolicy);
265}
266
267/*
268 * getPowerStatus
269 * helper function for Get Chassis Status Command
270 * return - optional value for pgood (no value on error)
271 */
272std::optional<bool> getPowerStatus()
273{
274 bool powerGood = false;
275 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
276 try
277 {
278 constexpr const char* chassisStatePath =
279 "/xyz/openbmc_project/state/chassis0";
280 constexpr const char* chassisStateIntf =
281 "xyz.openbmc_project.State.Chassis";
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500282 auto service = ipmi::getService(*busp, chassisStateIntf,
283 chassisStatePath);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700284
285 ipmi::Value variant =
286 ipmi::getDbusProperty(*busp, service, chassisStatePath,
287 chassisStateIntf, "CurrentPowerState");
288 std::string powerState = std::get<std::string>(variant);
289 if (powerState == "xyz.openbmc_project.State.Chassis.PowerState.On")
290 {
291 powerGood = true;
292 }
293 }
294 catch (const std::exception& e)
295 {
296 log<level::ERR>("Failed to fetch power state property",
297 entry("ERROR=%s", e.what()));
298 return std::nullopt;
299 }
300 return std::make_optional(powerGood);
301}
302
303/*
304 * getACFailStatus
305 * helper function for Get Chassis Status Command
306 * return - bool value for ACFail (false on error)
307 */
308bool getACFailStatus()
309{
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700310 constexpr const char* acBootObj =
311 "/xyz/openbmc_project/control/host0/ac_boot";
312 constexpr const char* acBootIntf = "xyz.openbmc_project.Common.ACBoot";
313 std::string acFail;
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700314 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
315 try
316 {
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700317 auto service = ipmi::getService(*bus, acBootIntf, acBootObj);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700318
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700319 ipmi::Value variant = ipmi::getDbusProperty(*bus, service, acBootObj,
320 acBootIntf, "ACBoot");
321 acFail = std::get<std::string>(variant);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700322 }
323 catch (const std::exception& e)
324 {
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700325 log<level::ERR>(
326 "Failed to fetch ACBoot property", entry("ERROR=%s", e.what()),
327 entry("PATH=%s", acBootObj), entry("INTERFACE=%s", acBootIntf));
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700328 }
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700329 return acFail == "True";
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700330}
331} // namespace power_policy
332
333static std::optional<bool> getButtonEnabled(const std::string& buttonPath)
334{
335 bool buttonDisabled = false;
336 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
337 try
338 {
339 auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
340 ipmi::Value disabled = ipmi::getDbusProperty(
341 *busp, service, buttonPath, buttonIntf, "ButtonMasked");
342 buttonDisabled = std::get<bool>(disabled);
343 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500344 catch (const sdbusplus::exception_t& e)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700345 {
346 log<level::ERR>("Fail to get button disabled property",
347 entry("PATH=%s", buttonPath.c_str()),
348 entry("ERROR=%s", e.what()));
349 return std::nullopt;
350 }
351 return std::make_optional(buttonDisabled);
352}
353
354static bool setButtonEnabled(const std::string& buttonPath, const bool disabled)
355{
356 try
357 {
358 auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
359 ipmi::setDbusProperty(*getSdBus(), service, buttonPath, buttonIntf,
360 "ButtonMasked", disabled);
361 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500362 catch (const std::exception& e)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700363 {
364 log<level::ERR>("Failed to set button disabled",
365 entry("EXCEPTION=%s, REQUEST=%x", e.what(), disabled));
366 return -1;
367 }
368
369 return 0;
370}
371
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700372static bool getRestartCause(ipmi::Context::ptr& ctx, std::string& restartCause)
Jason M. Bills8c615392019-07-26 13:45:41 -0700373{
374 constexpr const char* restartCausePath =
375 "/xyz/openbmc_project/control/host0/restart_cause";
376 constexpr const char* restartCauseIntf =
Jason M. Billsbf124d42019-10-04 10:50:43 -0700377 "xyz.openbmc_project.Control.Host.RestartCause";
Jason M. Bills8c615392019-07-26 13:45:41 -0700378
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700379 std::string service;
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500380 boost::system::error_code ec = ipmi::getService(ctx, restartCauseIntf,
381 restartCausePath, service);
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700382
383 if (!ec)
Jason M. Bills8c615392019-07-26 13:45:41 -0700384 {
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700385 ec = ipmi::getDbusProperty(ctx, service, restartCausePath,
386 restartCauseIntf, "RestartCause",
387 restartCause);
Jason M. Bills8c615392019-07-26 13:45:41 -0700388 }
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700389 if (ec)
Jason M. Bills8c615392019-07-26 13:45:41 -0700390 {
391 log<level::ERR>("Failed to fetch RestartCause property",
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700392 entry("ERROR=%s", ec.message().c_str()),
Jason M. Bills8c615392019-07-26 13:45:41 -0700393 entry("PATH=%s", restartCausePath),
394 entry("INTERFACE=%s", restartCauseIntf));
395 return false;
396 }
397 return true;
398}
399
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700400static bool checkIPMIRestartCause(ipmi::Context::ptr& ctx,
401 bool& ipmiRestartCause)
Jason M. Bills8c615392019-07-26 13:45:41 -0700402{
403 std::string restartCause;
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700404 if (!getRestartCause(ctx, restartCause))
Jason M. Bills8c615392019-07-26 13:45:41 -0700405 {
406 return false;
407 }
408 ipmiRestartCause =
409 (restartCause ==
410 "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand");
411 return true;
412}
413
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700414//----------------------------------------------------------------------
415// Get Chassis Status commands
416//----------------------------------------------------------------------
417ipmi::RspType<bool, // Power is on
418 bool, // Power overload
419 bool, // Interlock
420 bool, // power fault
421 bool, // power control fault
422 uint2_t, // power restore policy
423 bool, // reserved
424
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500425 bool, // AC failed
426 bool, // last power down caused by a Power overload
427 bool, // last power down caused by a power interlock
428 bool, // last power down caused by power fault
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700429 bool, // last ‘Power is on’ state was entered via IPMI command
430 uint3_t, // reserved
431
432 bool, // Chassis intrusion active
433 bool, // Front Panel Lockout active
434 bool, // Drive Fault
435 bool, // Cooling/fan fault detected
436 uint2_t, // Chassis Identify State
437 bool, // Chassis Identify command and state info supported
438 bool, // reserved
439
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500440 bool, // Power off button disabled
441 bool, // Reset button disabled
442 bool, // Diagnostic Interrupt button disabled
443 bool, // Standby (sleep) button disabled
444 bool, // Power off button disable allowed
445 bool, // Reset button disable allowed
446 bool, // Diagnostic Interrupt button disable allowed
447 bool // Standby (sleep) button disable allowed
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700448 >
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700449 ipmiGetChassisStatus(ipmi::Context::ptr ctx)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700450{
451 std::optional<uint2_t> restorePolicy =
452 power_policy::getPowerRestorePolicy();
453 std::optional<bool> powerGood = power_policy::getPowerStatus();
454 if (!restorePolicy || !powerGood)
455 {
456 return ipmi::responseUnspecifiedError();
457 }
458
459 // Front Panel Button Capabilities and disable/enable status(Optional)
460 std::optional<bool> powerButtonReading = getButtonEnabled(powerButtonPath);
461 // allow disable if the interface is present
462 bool powerButtonDisableAllow = static_cast<bool>(powerButtonReading);
463 // default return the button is enabled (not disabled)
464 bool powerButtonDisabled = false;
465 if (powerButtonDisableAllow)
466 {
467 // return the real value of the button status, if present
468 powerButtonDisabled = *powerButtonReading;
469 }
470
471 std::optional<bool> resetButtonReading = getButtonEnabled(resetButtonPath);
472 // allow disable if the interface is present
473 bool resetButtonDisableAllow = static_cast<bool>(resetButtonReading);
474 // default return the button is enabled (not disabled)
475 bool resetButtonDisabled = false;
476 if (resetButtonDisableAllow)
477 {
478 // return the real value of the button status, if present
479 resetButtonDisabled = *resetButtonReading;
480 }
481
482 std::optional<bool> interruptButtonReading =
483 getButtonEnabled(interruptButtonPath);
484 // allow disable if the interface is present
485 bool interruptButtonDisableAllow =
486 static_cast<bool>(interruptButtonReading);
487 // default return the button is enabled (not disabled)
488 bool interruptButtonDisabled = false;
489 if (interruptButtonDisableAllow)
490 {
491 // return the real value of the button status, if present
492 interruptButtonDisabled = *interruptButtonReading;
493 }
494
495 bool powerDownAcFailed = power_policy::getACFailStatus();
496
Jason M. Bills8c615392019-07-26 13:45:41 -0700497 bool powerStatusIPMI = false;
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700498 if (!checkIPMIRestartCause(ctx, powerStatusIPMI))
Jason M. Bills8c615392019-07-26 13:45:41 -0700499 {
500 return ipmi::responseUnspecifiedError();
501 }
502
Matt Simmering7f819e82022-12-08 12:56:45 -0800503 bool chassisIntrusionActive = false;
Vernon Mauerydcff1502022-09-28 11:12:46 -0700504 constexpr const char* chassisIntrusionObj =
505 "/xyz/openbmc_project/Chassis/Intrusion";
506 constexpr const char* chassisIntrusionInf =
507 "xyz.openbmc_project.Chassis.Intrusion";
Matt Simmering7f819e82022-12-08 12:56:45 -0800508
Vernon Mauerydcff1502022-09-28 11:12:46 -0700509 std::string intrusionService;
510 boost::system::error_code ec = ipmi::getService(
511 ctx, chassisIntrusionInf, chassisIntrusionObj, intrusionService);
512 if (ec)
Matt Simmering7f819e82022-12-08 12:56:45 -0800513 {
514 log<level::ERR>("Failed to get Chassis Intrusion service",
Vernon Mauerydcff1502022-09-28 11:12:46 -0700515 entry("ERROR=%s", ec.message().c_str()));
Matt Simmering7f819e82022-12-08 12:56:45 -0800516 }
517
Vernon Mauerydcff1502022-09-28 11:12:46 -0700518 chassisIntrusionActive = !intrusionService.empty();
519
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700520 // This response has a lot of hard-coded, unsupported fields
521 // They are set to false or 0
522 constexpr bool powerOverload = false;
523 constexpr bool chassisInterlock = false;
524 constexpr bool powerFault = false;
525 constexpr bool powerControlFault = false;
526 constexpr bool powerDownOverload = false;
527 constexpr bool powerDownInterlock = false;
528 constexpr bool powerDownPowerFault = false;
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700529 constexpr bool frontPanelLockoutActive = false;
530 constexpr bool driveFault = false;
531 constexpr bool coolingFanFault = false;
532 // chassisIdentifySupport set because this command is implemented
533 constexpr bool chassisIdentifySupport = true;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700534 uint2_t chassisIdentifyState = types::enum_cast<uint2_t>(chassisIDState);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700535 constexpr bool sleepButtonDisabled = false;
536 constexpr bool sleepButtonDisableAllow = false;
537
538 return ipmi::responseSuccess(
539 *powerGood, powerOverload, chassisInterlock, powerFault,
540 powerControlFault, *restorePolicy,
541 false, // reserved
542
543 powerDownAcFailed, powerDownOverload, powerDownInterlock,
544 powerDownPowerFault, powerStatusIPMI,
545 uint3_t(0), // reserved
546
547 chassisIntrusionActive, frontPanelLockoutActive, driveFault,
548 coolingFanFault, chassisIdentifyState, chassisIdentifySupport,
549 false, // reserved
550
551 powerButtonDisabled, resetButtonDisabled, interruptButtonDisabled,
552 sleepButtonDisabled, powerButtonDisableAllow, resetButtonDisableAllow,
553 interruptButtonDisableAllow, sleepButtonDisableAllow);
554}
555
Jason M. Bills8c615392019-07-26 13:45:41 -0700556static uint4_t getRestartCauseValue(const std::string& cause)
Jason M. Bills3efc6452019-06-20 15:51:47 -0700557{
558 uint4_t restartCauseValue = 0;
559 if (cause == "xyz.openbmc_project.State.Host.RestartCause.Unknown")
560 {
561 restartCauseValue = 0x0;
562 }
563 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand")
564 {
565 restartCauseValue = 0x1;
566 }
567 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.ResetButton")
568 {
569 restartCauseValue = 0x2;
570 }
571 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PowerButton")
572 {
573 restartCauseValue = 0x3;
574 }
575 else if (cause ==
576 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
577 {
578 restartCauseValue = 0x4;
579 }
580 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.OEM")
581 {
582 restartCauseValue = 0x5;
583 }
584 else if (cause ==
585 "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn")
586 {
587 restartCauseValue = 0x6;
588 }
589 else if (cause == "xyz.openbmc_project.State.Host.RestartCause."
590 "PowerPolicyPreviousState")
591 {
592 restartCauseValue = 0x7;
593 }
594 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PEFReset")
595 {
596 restartCauseValue = 0x8;
597 }
598 else if (cause ==
599 "xyz.openbmc_project.State.Host.RestartCause.PEFPowerCycle")
600 {
601 restartCauseValue = 0x9;
602 }
603 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.SoftReset")
604 {
605 restartCauseValue = 0xa;
606 }
607 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.RTCWakeup")
608 {
609 restartCauseValue = 0xb;
610 }
611 return restartCauseValue;
612}
613
614ipmi::RspType<uint4_t, // Restart Cause
615 uint4_t, // reserved
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700616 uint8_t // channel number
Jason M. Bills3efc6452019-06-20 15:51:47 -0700617 >
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700618 ipmiGetSystemRestartCause(ipmi::Context::ptr ctx)
Jason M. Bills3efc6452019-06-20 15:51:47 -0700619{
Jason M. Bills3efc6452019-06-20 15:51:47 -0700620 std::string restartCauseStr;
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700621 if (!getRestartCause(ctx, restartCauseStr))
Jason M. Bills3efc6452019-06-20 15:51:47 -0700622 {
Jason M. Bills3efc6452019-06-20 15:51:47 -0700623 return ipmi::responseUnspecifiedError();
624 }
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700625 constexpr uint4_t reserved = 0;
626 auto channel = static_cast<uint8_t>(ctx->channel);
627 return ipmi::responseSuccess(getRestartCauseValue(restartCauseStr),
628 reserved, channel);
Jason M. Bills3efc6452019-06-20 15:51:47 -0700629}
630
Vernon Mauerydcff1502022-09-28 11:12:46 -0700631ipmi::RspType<> ipmiSetFrontPanelButtonEnables(
632 bool disablePowerButton, bool disableResetButton,
633 bool disableInterruptButton, [[maybe_unused]] bool disableSleepButton,
634 uint4_t reserved)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700635{
sunitakx3ff63712021-06-09 15:47:32 +0000636 if (reserved)
637 {
638 return ipmi::responseInvalidFieldRequest();
639 }
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700640 bool error = false;
641
642 error |= setButtonEnabled(powerButtonPath, disablePowerButton);
643 error |= setButtonEnabled(resetButtonPath, disableResetButton);
644 error |= setButtonEnabled(interruptButtonPath, disableInterruptButton);
645
646 if (error)
647 {
648 return ipmi::responseUnspecifiedError();
649 }
sunitakx3ff63712021-06-09 15:47:32 +0000650
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700651 return ipmi::responseSuccess();
652}
653
Yuan Li60e7aaf2019-05-28 14:22:40 +0800654static void registerChassisFunctions(void)
655{
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700656 log<level::INFO>("Registering Chassis commands");
Yuan Li60e7aaf2019-05-28 14:22:40 +0800657
658 createIdentifyTimer();
659
660 if (matchPtr == nullptr)
661 {
662 using namespace sdbusplus::bus::match::rules;
663 auto bus = getSdBus();
664
665 matchPtr = std::make_unique<sdbusplus::bus::match_t>(
666 *bus,
667 sdbusplus::bus::match::rules::propertiesChanged(idButtonPath,
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700668 buttonIntf),
Yuan Li60e7aaf2019-05-28 14:22:40 +0800669 std::bind(idButtonPropChanged, std::placeholders::_1));
670 }
671
672 // <Chassis Identify>
673 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
674 ipmi::chassis::cmdChassisIdentify,
675 ipmi::Privilege::Operator, ipmiChassisIdentify);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700676 // <Get Chassis Status>
677 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
678 ipmi::chassis::cmdGetChassisStatus,
679 ipmi::Privilege::User, ipmiGetChassisStatus);
Jason M. Bills3efc6452019-06-20 15:51:47 -0700680 // <Get System Restart Cause>
681 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
682 ipmi::chassis::cmdGetSystemRestartCause,
683 ipmi::Privilege::User, ipmiGetSystemRestartCause);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700684 // <Set Front Panel Enables>
685 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
686 ipmi::chassis::cmdSetFrontPanelButtonEnables,
AppaRao Puli51acbdf2019-11-10 21:05:34 +0530687 ipmi::Privilege::Admin,
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700688 ipmiSetFrontPanelButtonEnables);
Yuan Li60e7aaf2019-05-28 14:22:40 +0800689}
690
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700691} // namespace ipmi::chassis