blob: 4f748ffbaaf86d22075bb5786407651f544fee06 [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);
100 ipmi::Value enabled =
101 getDbusProperty(*bus, service, objName, ledInterface, ledProp);
102 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 {
230 auto service =
231 ipmi::getService(*busp, powerRestoreIntf, powerRestorePath);
232
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;
252 }
253 }
254 catch (const std::exception& e)
255 {
256 log<level::ERR>("Failed to fetch PowerRestorePolicy property",
257 entry("ERROR=%s", e.what()),
258 entry("PATH=%s", powerRestorePath),
259 entry("INTERFACE=%s", powerRestoreIntf));
260 return std::nullopt;
261 }
262 return std::make_optional(restorePolicy);
263}
264
265/*
266 * getPowerStatus
267 * helper function for Get Chassis Status Command
268 * return - optional value for pgood (no value on error)
269 */
270std::optional<bool> getPowerStatus()
271{
272 bool powerGood = false;
273 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
274 try
275 {
276 constexpr const char* chassisStatePath =
277 "/xyz/openbmc_project/state/chassis0";
278 constexpr const char* chassisStateIntf =
279 "xyz.openbmc_project.State.Chassis";
280 auto service =
281 ipmi::getService(*busp, chassisStateIntf, chassisStatePath);
282
283 ipmi::Value variant =
284 ipmi::getDbusProperty(*busp, service, chassisStatePath,
285 chassisStateIntf, "CurrentPowerState");
286 std::string powerState = std::get<std::string>(variant);
287 if (powerState == "xyz.openbmc_project.State.Chassis.PowerState.On")
288 {
289 powerGood = true;
290 }
291 }
292 catch (const std::exception& e)
293 {
294 log<level::ERR>("Failed to fetch power state property",
295 entry("ERROR=%s", e.what()));
296 return std::nullopt;
297 }
298 return std::make_optional(powerGood);
299}
300
301/*
302 * getACFailStatus
303 * helper function for Get Chassis Status Command
304 * return - bool value for ACFail (false on error)
305 */
306bool getACFailStatus()
307{
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700308 constexpr const char* acBootObj =
309 "/xyz/openbmc_project/control/host0/ac_boot";
310 constexpr const char* acBootIntf = "xyz.openbmc_project.Common.ACBoot";
311 std::string acFail;
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700312 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
313 try
314 {
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700315 auto service = ipmi::getService(*bus, acBootIntf, acBootObj);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700316
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700317 ipmi::Value variant = ipmi::getDbusProperty(*bus, service, acBootObj,
318 acBootIntf, "ACBoot");
319 acFail = std::get<std::string>(variant);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700320 }
321 catch (const std::exception& e)
322 {
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700323 log<level::ERR>(
324 "Failed to fetch ACBoot property", entry("ERROR=%s", e.what()),
325 entry("PATH=%s", acBootObj), entry("INTERFACE=%s", acBootIntf));
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700326 }
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700327 return acFail == "True";
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700328}
329} // namespace power_policy
330
331static std::optional<bool> getButtonEnabled(const std::string& buttonPath)
332{
333 bool buttonDisabled = false;
334 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
335 try
336 {
337 auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
338 ipmi::Value disabled = ipmi::getDbusProperty(
339 *busp, service, buttonPath, buttonIntf, "ButtonMasked");
340 buttonDisabled = std::get<bool>(disabled);
341 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500342 catch (const sdbusplus::exception_t& e)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700343 {
344 log<level::ERR>("Fail to get button disabled property",
345 entry("PATH=%s", buttonPath.c_str()),
346 entry("ERROR=%s", e.what()));
347 return std::nullopt;
348 }
349 return std::make_optional(buttonDisabled);
350}
351
352static bool setButtonEnabled(const std::string& buttonPath, const bool disabled)
353{
354 try
355 {
356 auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
357 ipmi::setDbusProperty(*getSdBus(), service, buttonPath, buttonIntf,
358 "ButtonMasked", disabled);
359 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500360 catch (const std::exception& e)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700361 {
362 log<level::ERR>("Failed to set button disabled",
363 entry("EXCEPTION=%s, REQUEST=%x", e.what(), disabled));
364 return -1;
365 }
366
367 return 0;
368}
369
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700370static bool getRestartCause(ipmi::Context::ptr& ctx, std::string& restartCause)
Jason M. Bills8c615392019-07-26 13:45:41 -0700371{
372 constexpr const char* restartCausePath =
373 "/xyz/openbmc_project/control/host0/restart_cause";
374 constexpr const char* restartCauseIntf =
Jason M. Billsbf124d42019-10-04 10:50:43 -0700375 "xyz.openbmc_project.Control.Host.RestartCause";
Jason M. Bills8c615392019-07-26 13:45:41 -0700376
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700377 std::string service;
378 boost::system::error_code ec =
379 ipmi::getService(ctx, restartCauseIntf, restartCausePath, service);
380
381 if (!ec)
Jason M. Bills8c615392019-07-26 13:45:41 -0700382 {
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700383 ec = ipmi::getDbusProperty(ctx, service, restartCausePath,
384 restartCauseIntf, "RestartCause",
385 restartCause);
Jason M. Bills8c615392019-07-26 13:45:41 -0700386 }
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700387 if (ec)
Jason M. Bills8c615392019-07-26 13:45:41 -0700388 {
389 log<level::ERR>("Failed to fetch RestartCause property",
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700390 entry("ERROR=%s", ec.message().c_str()),
Jason M. Bills8c615392019-07-26 13:45:41 -0700391 entry("PATH=%s", restartCausePath),
392 entry("INTERFACE=%s", restartCauseIntf));
393 return false;
394 }
395 return true;
396}
397
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700398static bool checkIPMIRestartCause(ipmi::Context::ptr& ctx,
399 bool& ipmiRestartCause)
Jason M. Bills8c615392019-07-26 13:45:41 -0700400{
401 std::string restartCause;
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700402 if (!getRestartCause(ctx, restartCause))
Jason M. Bills8c615392019-07-26 13:45:41 -0700403 {
404 return false;
405 }
406 ipmiRestartCause =
407 (restartCause ==
408 "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand");
409 return true;
410}
411
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700412//----------------------------------------------------------------------
413// Get Chassis Status commands
414//----------------------------------------------------------------------
415ipmi::RspType<bool, // Power is on
416 bool, // Power overload
417 bool, // Interlock
418 bool, // power fault
419 bool, // power control fault
420 uint2_t, // power restore policy
421 bool, // reserved
422
423 bool, // AC failed
424 bool, // last power down caused by a Power overload
425 bool, // last power down caused by a power interlock
426 bool, // last power down caused by power fault
427 bool, // last ‘Power is on’ state was entered via IPMI command
428 uint3_t, // reserved
429
430 bool, // Chassis intrusion active
431 bool, // Front Panel Lockout active
432 bool, // Drive Fault
433 bool, // Cooling/fan fault detected
434 uint2_t, // Chassis Identify State
435 bool, // Chassis Identify command and state info supported
436 bool, // reserved
437
438 bool, // Power off button disabled
439 bool, // Reset button disabled
440 bool, // Diagnostic Interrupt button disabled
441 bool, // Standby (sleep) button disabled
442 bool, // Power off button disable allowed
443 bool, // Reset button disable allowed
444 bool, // Diagnostic Interrupt button disable allowed
445 bool // Standby (sleep) button disable allowed
446 >
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700447 ipmiGetChassisStatus(ipmi::Context::ptr ctx)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700448{
449 std::optional<uint2_t> restorePolicy =
450 power_policy::getPowerRestorePolicy();
451 std::optional<bool> powerGood = power_policy::getPowerStatus();
452 if (!restorePolicy || !powerGood)
453 {
454 return ipmi::responseUnspecifiedError();
455 }
456
457 // Front Panel Button Capabilities and disable/enable status(Optional)
458 std::optional<bool> powerButtonReading = getButtonEnabled(powerButtonPath);
459 // allow disable if the interface is present
460 bool powerButtonDisableAllow = static_cast<bool>(powerButtonReading);
461 // default return the button is enabled (not disabled)
462 bool powerButtonDisabled = false;
463 if (powerButtonDisableAllow)
464 {
465 // return the real value of the button status, if present
466 powerButtonDisabled = *powerButtonReading;
467 }
468
469 std::optional<bool> resetButtonReading = getButtonEnabled(resetButtonPath);
470 // allow disable if the interface is present
471 bool resetButtonDisableAllow = static_cast<bool>(resetButtonReading);
472 // default return the button is enabled (not disabled)
473 bool resetButtonDisabled = false;
474 if (resetButtonDisableAllow)
475 {
476 // return the real value of the button status, if present
477 resetButtonDisabled = *resetButtonReading;
478 }
479
480 std::optional<bool> interruptButtonReading =
481 getButtonEnabled(interruptButtonPath);
482 // allow disable if the interface is present
483 bool interruptButtonDisableAllow =
484 static_cast<bool>(interruptButtonReading);
485 // default return the button is enabled (not disabled)
486 bool interruptButtonDisabled = false;
487 if (interruptButtonDisableAllow)
488 {
489 // return the real value of the button status, if present
490 interruptButtonDisabled = *interruptButtonReading;
491 }
492
493 bool powerDownAcFailed = power_policy::getACFailStatus();
494
Jason M. Bills8c615392019-07-26 13:45:41 -0700495 bool powerStatusIPMI = false;
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700496 if (!checkIPMIRestartCause(ctx, powerStatusIPMI))
Jason M. Bills8c615392019-07-26 13:45:41 -0700497 {
498 return ipmi::responseUnspecifiedError();
499 }
500
Matt Simmering7f819e82022-12-08 12:56:45 -0800501 bool chassisIntrusionActive = false;
502 try
503 {
504 constexpr const char* chassisIntrusionObj =
505 "/xyz/openbmc_project/Intrusion/Chassis_Intrusion";
506 constexpr const char* chassisIntrusionInf =
507 "xyz.openbmc_project.Chassis.Intrusion";
508
509 std::string intrusionService;
510 boost::system::error_code ec = ipmi::getService(
511 ctx, chassisIntrusionInf, chassisIntrusionObj, intrusionService);
512
513 chassisIntrusionActive = !intrusionService.empty();
514 }
515 catch (const std::exception& e)
516 {
517 log<level::ERR>("Failed to get Chassis Intrusion service",
518 entry("ERROR=%s", e.what()));
519 }
520
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700521 // This response has a lot of hard-coded, unsupported fields
522 // They are set to false or 0
523 constexpr bool powerOverload = false;
524 constexpr bool chassisInterlock = false;
525 constexpr bool powerFault = false;
526 constexpr bool powerControlFault = false;
527 constexpr bool powerDownOverload = false;
528 constexpr bool powerDownInterlock = false;
529 constexpr bool powerDownPowerFault = false;
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700530 constexpr bool frontPanelLockoutActive = false;
531 constexpr bool driveFault = false;
532 constexpr bool coolingFanFault = false;
533 // chassisIdentifySupport set because this command is implemented
534 constexpr bool chassisIdentifySupport = true;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700535 uint2_t chassisIdentifyState = types::enum_cast<uint2_t>(chassisIDState);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700536 constexpr bool sleepButtonDisabled = false;
537 constexpr bool sleepButtonDisableAllow = false;
538
539 return ipmi::responseSuccess(
540 *powerGood, powerOverload, chassisInterlock, powerFault,
541 powerControlFault, *restorePolicy,
542 false, // reserved
543
544 powerDownAcFailed, powerDownOverload, powerDownInterlock,
545 powerDownPowerFault, powerStatusIPMI,
546 uint3_t(0), // reserved
547
548 chassisIntrusionActive, frontPanelLockoutActive, driveFault,
549 coolingFanFault, chassisIdentifyState, chassisIdentifySupport,
550 false, // reserved
551
552 powerButtonDisabled, resetButtonDisabled, interruptButtonDisabled,
553 sleepButtonDisabled, powerButtonDisableAllow, resetButtonDisableAllow,
554 interruptButtonDisableAllow, sleepButtonDisableAllow);
555}
556
Jason M. Bills8c615392019-07-26 13:45:41 -0700557static uint4_t getRestartCauseValue(const std::string& cause)
Jason M. Bills3efc6452019-06-20 15:51:47 -0700558{
559 uint4_t restartCauseValue = 0;
560 if (cause == "xyz.openbmc_project.State.Host.RestartCause.Unknown")
561 {
562 restartCauseValue = 0x0;
563 }
564 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand")
565 {
566 restartCauseValue = 0x1;
567 }
568 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.ResetButton")
569 {
570 restartCauseValue = 0x2;
571 }
572 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PowerButton")
573 {
574 restartCauseValue = 0x3;
575 }
576 else if (cause ==
577 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
578 {
579 restartCauseValue = 0x4;
580 }
581 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.OEM")
582 {
583 restartCauseValue = 0x5;
584 }
585 else if (cause ==
586 "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn")
587 {
588 restartCauseValue = 0x6;
589 }
590 else if (cause == "xyz.openbmc_project.State.Host.RestartCause."
591 "PowerPolicyPreviousState")
592 {
593 restartCauseValue = 0x7;
594 }
595 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PEFReset")
596 {
597 restartCauseValue = 0x8;
598 }
599 else if (cause ==
600 "xyz.openbmc_project.State.Host.RestartCause.PEFPowerCycle")
601 {
602 restartCauseValue = 0x9;
603 }
604 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.SoftReset")
605 {
606 restartCauseValue = 0xa;
607 }
608 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.RTCWakeup")
609 {
610 restartCauseValue = 0xb;
611 }
612 return restartCauseValue;
613}
614
615ipmi::RspType<uint4_t, // Restart Cause
616 uint4_t, // reserved
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700617 uint8_t // channel number
Jason M. Bills3efc6452019-06-20 15:51:47 -0700618 >
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700619 ipmiGetSystemRestartCause(ipmi::Context::ptr ctx)
Jason M. Bills3efc6452019-06-20 15:51:47 -0700620{
Jason M. Bills3efc6452019-06-20 15:51:47 -0700621 std::string restartCauseStr;
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700622 if (!getRestartCause(ctx, restartCauseStr))
Jason M. Bills3efc6452019-06-20 15:51:47 -0700623 {
Jason M. Bills3efc6452019-06-20 15:51:47 -0700624 return ipmi::responseUnspecifiedError();
625 }
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700626 constexpr uint4_t reserved = 0;
627 auto channel = static_cast<uint8_t>(ctx->channel);
628 return ipmi::responseSuccess(getRestartCauseValue(restartCauseStr),
629 reserved, channel);
Jason M. Bills3efc6452019-06-20 15:51:47 -0700630}
631
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700632ipmi::RspType<> ipmiSetFrontPanelButtonEnables(bool disablePowerButton,
633 bool disableResetButton,
634 bool disableInterruptButton,
635 bool disableSleepButton,
636 uint4_t reserved)
637{
sunitakx3ff63712021-06-09 15:47:32 +0000638 if (reserved)
639 {
640 return ipmi::responseInvalidFieldRequest();
641 }
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700642 bool error = false;
643
644 error |= setButtonEnabled(powerButtonPath, disablePowerButton);
645 error |= setButtonEnabled(resetButtonPath, disableResetButton);
646 error |= setButtonEnabled(interruptButtonPath, disableInterruptButton);
647
648 if (error)
649 {
650 return ipmi::responseUnspecifiedError();
651 }
sunitakx3ff63712021-06-09 15:47:32 +0000652
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700653 return ipmi::responseSuccess();
654}
655
Yuan Li60e7aaf2019-05-28 14:22:40 +0800656static void registerChassisFunctions(void)
657{
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700658 log<level::INFO>("Registering Chassis commands");
Yuan Li60e7aaf2019-05-28 14:22:40 +0800659
660 createIdentifyTimer();
661
662 if (matchPtr == nullptr)
663 {
664 using namespace sdbusplus::bus::match::rules;
665 auto bus = getSdBus();
666
667 matchPtr = std::make_unique<sdbusplus::bus::match_t>(
668 *bus,
669 sdbusplus::bus::match::rules::propertiesChanged(idButtonPath,
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700670 buttonIntf),
Yuan Li60e7aaf2019-05-28 14:22:40 +0800671 std::bind(idButtonPropChanged, std::placeholders::_1));
672 }
673
674 // <Chassis Identify>
675 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
676 ipmi::chassis::cmdChassisIdentify,
677 ipmi::Privilege::Operator, ipmiChassisIdentify);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700678 // <Get Chassis Status>
679 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
680 ipmi::chassis::cmdGetChassisStatus,
681 ipmi::Privilege::User, ipmiGetChassisStatus);
Jason M. Bills3efc6452019-06-20 15:51:47 -0700682 // <Get System Restart Cause>
683 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
684 ipmi::chassis::cmdGetSystemRestartCause,
685 ipmi::Privilege::User, ipmiGetSystemRestartCause);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700686 // <Set Front Panel Enables>
687 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
688 ipmi::chassis::cmdSetFrontPanelButtonEnables,
AppaRao Puli51acbdf2019-11-10 21:05:34 +0530689 ipmi::Privilege::Admin,
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700690 ipmiSetFrontPanelButtonEnables);
Yuan Li60e7aaf2019-05-28 14:22:40 +0800691}
692
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700693} // namespace ipmi::chassis