blob: 6ffca5f61d4ff80dc8f731b2b453106df9242653 [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>
Chaul Lyde03ada2024-12-18 03:16:25 +000024#include <xyz/openbmc_project/Chassis/Intrusion/client.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070025#include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
26
27#include <fstream>
28#include <iostream>
29#include <regex>
Jason M. Billsb08f84e2019-06-10 12:59:42 -070030#include <stdexcept>
31#include <string_view>
Yuan Li60e7aaf2019-05-28 14:22:40 +080032
Jason M. Billsb08f84e2019-06-10 12:59:42 -070033using namespace phosphor::logging;
34
35namespace ipmi::chassis
Yuan Li60e7aaf2019-05-28 14:22:40 +080036{
Jason M. Billsb08f84e2019-06-10 12:59:42 -070037static constexpr const char* buttonIntf = "xyz.openbmc_project.Chassis.Buttons";
Yuan Li60e7aaf2019-05-28 14:22:40 +080038
Jason M. Billsb08f84e2019-06-10 12:59:42 -070039const static constexpr char* idButtonPath =
40 "/xyz/openbmc_project/chassis/buttons/id";
41static constexpr const char* powerButtonPath =
42 "/xyz/openbmc_project/chassis/buttons/power";
43static constexpr const char* resetButtonPath =
44 "/xyz/openbmc_project/chassis/buttons/reset";
45static constexpr const char* interruptButtonPath =
46 "/xyz/openbmc_project/chassis/buttons/nmi";
47
48const static constexpr char* idButtonProp = "ButtonPressed";
49
50const static constexpr char* ledService =
Yuan Li60e7aaf2019-05-28 14:22:40 +080051 "xyz.openbmc_project.LED.GroupManager";
Jason M. Billsb08f84e2019-06-10 12:59:42 -070052const static constexpr char* ledIDOnObj =
Yuan Li60e7aaf2019-05-28 14:22:40 +080053 "/xyz/openbmc_project/led/groups/enclosure_identify";
Jason M. Billsb08f84e2019-06-10 12:59:42 -070054const static constexpr char* ledIDBlinkObj =
Yuan Li60e7aaf2019-05-28 14:22:40 +080055 "/xyz/openbmc_project/led/groups/enclosure_identify_blink";
Jason M. Billsb08f84e2019-06-10 12:59:42 -070056const static constexpr char* ledInterface = "xyz.openbmc_project.Led.Group";
57const static constexpr char* ledProp = "Asserted";
Jason M. Bills09221d72019-07-26 13:38:28 -070058enum class ChassisIDState
59{
60 off = 0,
61 temporary = 1,
62 indefinite = 2,
63};
64static ChassisIDState chassisIDState = ChassisIDState::off;
Yuan Li60e7aaf2019-05-28 14:22:40 +080065
66constexpr size_t defaultIdentifyTimeOut = 15;
67
Patrick Williamsf0feb492023-12-05 12:45:02 -060068std::unique_ptr<sdbusplus::Timer> identifyTimer
Yuan Li60e7aaf2019-05-28 14:22:40 +080069 __attribute__((init_priority(101)));
70std::unique_ptr<sdbusplus::bus::match_t> matchPtr
71 __attribute__((init_priority(101)));
72
73static void registerChassisFunctions() __attribute__((constructor));
74
75static ipmi::ServiceCache LEDService(ledInterface, ledIDBlinkObj);
76
Jason M. Billsb08f84e2019-06-10 12:59:42 -070077void enclosureIdentifyLed(const char* objName, bool isIdLedOn)
Yuan Li60e7aaf2019-05-28 14:22:40 +080078{
79 auto bus = getSdBus();
80
81 try
82 {
83 std::string service = LEDService.getService(*bus);
84 setDbusProperty(*bus, service, objName, ledInterface, ledProp,
85 isIdLedOn);
86 }
Jason M. Billsb08f84e2019-06-10 12:59:42 -070087 catch (const std::exception& e)
Yuan Li60e7aaf2019-05-28 14:22:40 +080088 {
Jason M. Billsb08f84e2019-06-10 12:59:42 -070089 log<level::ERR>("enclosureIdentifyLed: can't set property",
90 entry("ERR=%s", e.what()));
Yuan Li60e7aaf2019-05-28 14:22:40 +080091 }
92}
93
Jason M. Billsb08f84e2019-06-10 12:59:42 -070094bool getIDState(const char* objName, bool& state)
Yuan Li60e7aaf2019-05-28 14:22:40 +080095{
96 auto bus = getSdBus();
97
98 try
99 {
100 std::string service = LEDService.getService(*bus);
Patrick Williams1bcced02024-08-16 15:20:24 -0400101 ipmi::Value enabled =
102 getDbusProperty(*bus, service, objName, ledInterface, ledProp);
Yuan Li60e7aaf2019-05-28 14:22:40 +0800103 state = std::get<bool>(enabled);
104 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500105 catch (const sdbusplus::exception_t& e)
Yuan Li60e7aaf2019-05-28 14:22:40 +0800106 {
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700107 log<level::ERR>("Fail to get property", entry("PATH=%s", objName),
108 entry("ERROR=%s", e.what()));
Yuan Li60e7aaf2019-05-28 14:22:40 +0800109 return false;
110 }
111 return true;
112}
113
114void enclosureIdentifyLedBlinkOff()
115{
Jason M. Bills09221d72019-07-26 13:38:28 -0700116 chassisIDState = ChassisIDState::off;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800117 enclosureIdentifyLed(ledIDBlinkObj, false);
118}
119
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500120void idButtonPropChanged(sdbusplus::message_t& msg)
Yuan Li60e7aaf2019-05-28 14:22:40 +0800121{
122 bool asserted = false;
123 bool buttonPressed = false;
124
125 std::map<std::string, ipmi::Value> props;
126 std::vector<std::string> inval;
127 std::string iface;
128 msg.read(iface, props, inval);
129
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700130 for (const auto& t : props)
Yuan Li60e7aaf2019-05-28 14:22:40 +0800131 {
132 auto key = t.first;
133 auto value = t.second;
134
135 if (key == idButtonProp)
136 {
137 buttonPressed = std::get<bool>(value);
138 }
139 break;
140 }
141
142 if (buttonPressed)
143 {
144 if (identifyTimer->isRunning())
145 {
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700146 log<level::INFO>("ID timer is running");
Yuan Li60e7aaf2019-05-28 14:22:40 +0800147 }
148
149 // make sure timer is stopped
150 identifyTimer->stop();
151
152 if (!getIDState(ledIDBlinkObj, asserted))
153 {
154 return;
155 }
156
157 if (asserted)
158 {
159 // LED is blinking, turn off the LED
Jason M. Bills09221d72019-07-26 13:38:28 -0700160 chassisIDState = ChassisIDState::off;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800161 enclosureIdentifyLed(ledIDBlinkObj, false);
162 enclosureIdentifyLed(ledIDOnObj, false);
163 }
164 else
165 {
166 // toggle the IED on/off
167 if (!getIDState(ledIDOnObj, asserted))
168 {
169 return;
170 }
171 enclosureIdentifyLed(ledIDOnObj, !asserted);
172 }
173 }
174}
175
176void createIdentifyTimer()
177{
178 if (!identifyTimer)
179 {
180 identifyTimer =
Patrick Williamsf0feb492023-12-05 12:45:02 -0600181 std::make_unique<sdbusplus::Timer>(enclosureIdentifyLedBlinkOff);
Yuan Li60e7aaf2019-05-28 14:22:40 +0800182 }
183}
184
185ipmi::RspType<> ipmiChassisIdentify(std::optional<uint8_t> interval,
186 std::optional<uint8_t> force)
187{
188 uint8_t identifyInterval = interval.value_or(defaultIdentifyTimeOut);
189 bool forceIdentify = force.value_or(0) & 0x01;
190
191 enclosureIdentifyLed(ledIDOnObj, false);
192 identifyTimer->stop();
193
194 if (identifyInterval || forceIdentify)
195 {
196 enclosureIdentifyLed(ledIDBlinkObj, true);
197 if (forceIdentify)
198 {
Jason M. Bills09221d72019-07-26 13:38:28 -0700199 chassisIDState = ChassisIDState::indefinite;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800200 return ipmi::responseSuccess();
201 }
Jason M. Bills09221d72019-07-26 13:38:28 -0700202 chassisIDState = ChassisIDState::temporary;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800203 // start the timer
204 auto time = std::chrono::duration_cast<std::chrono::microseconds>(
205 std::chrono::seconds(identifyInterval));
206 identifyTimer->start(time);
207 }
208 else
209 {
Jason M. Bills09221d72019-07-26 13:38:28 -0700210 chassisIDState = ChassisIDState::off;
Yuan Li60e7aaf2019-05-28 14:22:40 +0800211 enclosureIdentifyLed(ledIDBlinkObj, false);
212 }
213 return ipmi::responseSuccess();
214}
215
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700216namespace power_policy
217{
218/* helper function for Get Chassis Status Command
219 */
220std::optional<uint2_t> getPowerRestorePolicy()
221{
222 constexpr const char* powerRestorePath =
223 "/xyz/openbmc_project/control/host0/power_restore_policy";
224 constexpr const char* powerRestoreIntf =
225 "xyz.openbmc_project.Control.Power.RestorePolicy";
226 uint2_t restorePolicy = 0;
227 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
228
229 try
230 {
Patrick Williams1bcced02024-08-16 15:20:24 -0400231 auto service =
232 ipmi::getService(*busp, powerRestoreIntf, powerRestorePath);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700233
234 ipmi::Value result =
235 ipmi::getDbusProperty(*busp, service, powerRestorePath,
236 powerRestoreIntf, "PowerRestorePolicy");
237 auto powerRestore = sdbusplus::xyz::openbmc_project::Control::Power::
238 server::RestorePolicy::convertPolicyFromString(
239 std::get<std::string>(result));
240
241 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
242 switch (powerRestore)
243 {
244 case RestorePolicy::Policy::AlwaysOff:
245 restorePolicy = 0x00;
246 break;
247 case RestorePolicy::Policy::Restore:
248 restorePolicy = 0x01;
249 break;
250 case RestorePolicy::Policy::AlwaysOn:
251 restorePolicy = 0x02;
252 break;
Vernon Mauerydcff1502022-09-28 11:12:46 -0700253 default:
254 break;
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700255 }
256 }
257 catch (const std::exception& e)
258 {
259 log<level::ERR>("Failed to fetch PowerRestorePolicy property",
260 entry("ERROR=%s", e.what()),
261 entry("PATH=%s", powerRestorePath),
262 entry("INTERFACE=%s", powerRestoreIntf));
263 return std::nullopt;
264 }
265 return std::make_optional(restorePolicy);
266}
267
268/*
269 * getPowerStatus
270 * helper function for Get Chassis Status Command
271 * return - optional value for pgood (no value on error)
272 */
273std::optional<bool> getPowerStatus()
274{
275 bool powerGood = false;
276 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
277 try
278 {
279 constexpr const char* chassisStatePath =
280 "/xyz/openbmc_project/state/chassis0";
281 constexpr const char* chassisStateIntf =
282 "xyz.openbmc_project.State.Chassis";
Patrick Williams1bcced02024-08-16 15:20:24 -0400283 auto service =
284 ipmi::getService(*busp, chassisStateIntf, chassisStatePath);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700285
286 ipmi::Value variant =
287 ipmi::getDbusProperty(*busp, service, chassisStatePath,
288 chassisStateIntf, "CurrentPowerState");
289 std::string powerState = std::get<std::string>(variant);
290 if (powerState == "xyz.openbmc_project.State.Chassis.PowerState.On")
291 {
292 powerGood = true;
293 }
294 }
295 catch (const std::exception& e)
296 {
297 log<level::ERR>("Failed to fetch power state property",
298 entry("ERROR=%s", e.what()));
299 return std::nullopt;
300 }
301 return std::make_optional(powerGood);
302}
303
304/*
305 * getACFailStatus
306 * helper function for Get Chassis Status Command
307 * return - bool value for ACFail (false on error)
308 */
309bool getACFailStatus()
310{
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700311 constexpr const char* acBootObj =
312 "/xyz/openbmc_project/control/host0/ac_boot";
313 constexpr const char* acBootIntf = "xyz.openbmc_project.Common.ACBoot";
314 std::string acFail;
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700315 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
316 try
317 {
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700318 auto service = ipmi::getService(*bus, acBootIntf, acBootObj);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700319
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700320 ipmi::Value variant = ipmi::getDbusProperty(*bus, service, acBootObj,
321 acBootIntf, "ACBoot");
322 acFail = std::get<std::string>(variant);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700323 }
324 catch (const std::exception& e)
325 {
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700326 log<level::ERR>(
327 "Failed to fetch ACBoot property", entry("ERROR=%s", e.what()),
328 entry("PATH=%s", acBootObj), entry("INTERFACE=%s", acBootIntf));
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700329 }
Jason M. Billsa2b4c7a2019-06-24 16:55:21 -0700330 return acFail == "True";
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700331}
332} // namespace power_policy
333
334static std::optional<bool> getButtonEnabled(const std::string& buttonPath)
335{
336 bool buttonDisabled = false;
337 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
338 try
339 {
340 auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
341 ipmi::Value disabled = ipmi::getDbusProperty(
342 *busp, service, buttonPath, buttonIntf, "ButtonMasked");
343 buttonDisabled = std::get<bool>(disabled);
344 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500345 catch (const sdbusplus::exception_t& e)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700346 {
347 log<level::ERR>("Fail to get button disabled property",
348 entry("PATH=%s", buttonPath.c_str()),
349 entry("ERROR=%s", e.what()));
350 return std::nullopt;
351 }
352 return std::make_optional(buttonDisabled);
353}
354
355static bool setButtonEnabled(const std::string& buttonPath, const bool disabled)
356{
357 try
358 {
359 auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
360 ipmi::setDbusProperty(*getSdBus(), service, buttonPath, buttonIntf,
361 "ButtonMasked", disabled);
362 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500363 catch (const std::exception& e)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700364 {
365 log<level::ERR>("Failed to set button disabled",
366 entry("EXCEPTION=%s, REQUEST=%x", e.what(), disabled));
367 return -1;
368 }
369
370 return 0;
371}
372
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700373static bool getRestartCause(ipmi::Context::ptr& ctx, std::string& restartCause)
Jason M. Bills8c615392019-07-26 13:45:41 -0700374{
375 constexpr const char* restartCausePath =
376 "/xyz/openbmc_project/control/host0/restart_cause";
377 constexpr const char* restartCauseIntf =
Jason M. Billsbf124d42019-10-04 10:50:43 -0700378 "xyz.openbmc_project.Control.Host.RestartCause";
Jason M. Bills8c615392019-07-26 13:45:41 -0700379
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700380 std::string service;
Patrick Williams1bcced02024-08-16 15:20:24 -0400381 boost::system::error_code ec =
382 ipmi::getService(ctx, restartCauseIntf, restartCausePath, service);
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700383
384 if (!ec)
Jason M. Bills8c615392019-07-26 13:45:41 -0700385 {
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700386 ec = ipmi::getDbusProperty(ctx, service, restartCausePath,
387 restartCauseIntf, "RestartCause",
388 restartCause);
Jason M. Bills8c615392019-07-26 13:45:41 -0700389 }
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700390 if (ec)
Jason M. Bills8c615392019-07-26 13:45:41 -0700391 {
392 log<level::ERR>("Failed to fetch RestartCause property",
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700393 entry("ERROR=%s", ec.message().c_str()),
Jason M. Bills8c615392019-07-26 13:45:41 -0700394 entry("PATH=%s", restartCausePath),
395 entry("INTERFACE=%s", restartCauseIntf));
396 return false;
397 }
398 return true;
399}
400
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700401static bool checkIPMIRestartCause(ipmi::Context::ptr& ctx,
402 bool& ipmiRestartCause)
Jason M. Bills8c615392019-07-26 13:45:41 -0700403{
404 std::string restartCause;
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700405 if (!getRestartCause(ctx, restartCause))
Jason M. Bills8c615392019-07-26 13:45:41 -0700406 {
407 return false;
408 }
409 ipmiRestartCause =
410 (restartCause ==
411 "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand");
412 return true;
413}
414
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700415//----------------------------------------------------------------------
416// Get Chassis Status commands
417//----------------------------------------------------------------------
418ipmi::RspType<bool, // Power is on
419 bool, // Power overload
420 bool, // Interlock
421 bool, // power fault
422 bool, // power control fault
423 uint2_t, // power restore policy
424 bool, // reserved
425
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500426 bool, // AC failed
427 bool, // last power down caused by a Power overload
428 bool, // last power down caused by a power interlock
429 bool, // last power down caused by power fault
Jason M. Bills48437462025-01-13 14:26:02 -0800430 bool, // last ‘Power is on’ state was entered via IPMI command
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700431 uint3_t, // reserved
432
433 bool, // Chassis intrusion active
434 bool, // Front Panel Lockout active
435 bool, // Drive Fault
436 bool, // Cooling/fan fault detected
437 uint2_t, // Chassis Identify State
438 bool, // Chassis Identify command and state info supported
439 bool, // reserved
440
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500441 bool, // Power off button disabled
442 bool, // Reset button disabled
443 bool, // Diagnostic Interrupt button disabled
444 bool, // Standby (sleep) button disabled
445 bool, // Power off button disable allowed
446 bool, // Reset button disable allowed
447 bool, // Diagnostic Interrupt button disable allowed
448 bool // Standby (sleep) button disable allowed
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700449 >
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700450 ipmiGetChassisStatus(ipmi::Context::ptr ctx)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700451{
452 std::optional<uint2_t> restorePolicy =
453 power_policy::getPowerRestorePolicy();
454 std::optional<bool> powerGood = power_policy::getPowerStatus();
455 if (!restorePolicy || !powerGood)
456 {
457 return ipmi::responseUnspecifiedError();
458 }
459
460 // Front Panel Button Capabilities and disable/enable status(Optional)
461 std::optional<bool> powerButtonReading = getButtonEnabled(powerButtonPath);
462 // allow disable if the interface is present
463 bool powerButtonDisableAllow = static_cast<bool>(powerButtonReading);
464 // default return the button is enabled (not disabled)
465 bool powerButtonDisabled = false;
466 if (powerButtonDisableAllow)
467 {
468 // return the real value of the button status, if present
469 powerButtonDisabled = *powerButtonReading;
470 }
471
472 std::optional<bool> resetButtonReading = getButtonEnabled(resetButtonPath);
473 // allow disable if the interface is present
474 bool resetButtonDisableAllow = static_cast<bool>(resetButtonReading);
475 // default return the button is enabled (not disabled)
476 bool resetButtonDisabled = false;
477 if (resetButtonDisableAllow)
478 {
479 // return the real value of the button status, if present
480 resetButtonDisabled = *resetButtonReading;
481 }
482
483 std::optional<bool> interruptButtonReading =
484 getButtonEnabled(interruptButtonPath);
485 // allow disable if the interface is present
486 bool interruptButtonDisableAllow =
487 static_cast<bool>(interruptButtonReading);
488 // default return the button is enabled (not disabled)
489 bool interruptButtonDisabled = false;
490 if (interruptButtonDisableAllow)
491 {
492 // return the real value of the button status, if present
493 interruptButtonDisabled = *interruptButtonReading;
494 }
495
496 bool powerDownAcFailed = power_policy::getACFailStatus();
497
Jason M. Bills8c615392019-07-26 13:45:41 -0700498 bool powerStatusIPMI = false;
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700499 if (!checkIPMIRestartCause(ctx, powerStatusIPMI))
Jason M. Bills8c615392019-07-26 13:45:41 -0700500 {
501 return ipmi::responseUnspecifiedError();
502 }
503
Chaul Lyde03ada2024-12-18 03:16:25 +0000504 using Intrusion =
505 sdbusplus::client::xyz::openbmc_project::chassis::Intrusion<>;
Matt Simmering7f819e82022-12-08 12:56:45 -0800506
Chaul Lyde03ada2024-12-18 03:16:25 +0000507 std::vector<std::string> chassisIntrusionIntf = {
508 std::string(Intrusion::interface)};
509 ipmi::ObjectTree chassisIntrusionObjs;
510 bool chassisIntrusionActive = false;
511
512 boost::system::error_code ec = ipmi::getSubTree(
513 ctx, chassisIntrusionIntf, std::string("/"), 0, chassisIntrusionObjs);
514
Vernon Mauerydcff1502022-09-28 11:12:46 -0700515 if (ec)
Matt Simmering7f819e82022-12-08 12:56:45 -0800516 {
Chaul Lyde03ada2024-12-18 03:16:25 +0000517 log<level::ERR>("Failed to find Chassis Intrusion Interface on D-Bus",
Vernon Mauerydcff1502022-09-28 11:12:46 -0700518 entry("ERROR=%s", ec.message().c_str()));
Matt Simmering7f819e82022-12-08 12:56:45 -0800519 }
520
Chaul Lyde03ada2024-12-18 03:16:25 +0000521 chassisIntrusionActive = !chassisIntrusionObjs.empty();
Vernon Mauerydcff1502022-09-28 11:12:46 -0700522
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700523 // This response has a lot of hard-coded, unsupported fields
524 // They are set to false or 0
525 constexpr bool powerOverload = false;
526 constexpr bool chassisInterlock = false;
527 constexpr bool powerFault = false;
528 constexpr bool powerControlFault = false;
529 constexpr bool powerDownOverload = false;
530 constexpr bool powerDownInterlock = false;
531 constexpr bool powerDownPowerFault = false;
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700532 constexpr bool frontPanelLockoutActive = false;
533 constexpr bool driveFault = false;
534 constexpr bool coolingFanFault = false;
535 // chassisIdentifySupport set because this command is implemented
536 constexpr bool chassisIdentifySupport = true;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700537 uint2_t chassisIdentifyState = types::enum_cast<uint2_t>(chassisIDState);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700538 constexpr bool sleepButtonDisabled = false;
539 constexpr bool sleepButtonDisableAllow = false;
540
541 return ipmi::responseSuccess(
542 *powerGood, powerOverload, chassisInterlock, powerFault,
543 powerControlFault, *restorePolicy,
544 false, // reserved
545
546 powerDownAcFailed, powerDownOverload, powerDownInterlock,
547 powerDownPowerFault, powerStatusIPMI,
548 uint3_t(0), // reserved
549
550 chassisIntrusionActive, frontPanelLockoutActive, driveFault,
551 coolingFanFault, chassisIdentifyState, chassisIdentifySupport,
552 false, // reserved
553
554 powerButtonDisabled, resetButtonDisabled, interruptButtonDisabled,
555 sleepButtonDisabled, powerButtonDisableAllow, resetButtonDisableAllow,
556 interruptButtonDisableAllow, sleepButtonDisableAllow);
557}
558
Jason M. Bills8c615392019-07-26 13:45:41 -0700559static uint4_t getRestartCauseValue(const std::string& cause)
Jason M. Bills3efc6452019-06-20 15:51:47 -0700560{
561 uint4_t restartCauseValue = 0;
562 if (cause == "xyz.openbmc_project.State.Host.RestartCause.Unknown")
563 {
564 restartCauseValue = 0x0;
565 }
566 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand")
567 {
568 restartCauseValue = 0x1;
569 }
570 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.ResetButton")
571 {
572 restartCauseValue = 0x2;
573 }
574 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PowerButton")
575 {
576 restartCauseValue = 0x3;
577 }
578 else if (cause ==
579 "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
580 {
581 restartCauseValue = 0x4;
582 }
583 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.OEM")
584 {
585 restartCauseValue = 0x5;
586 }
587 else if (cause ==
588 "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn")
589 {
590 restartCauseValue = 0x6;
591 }
592 else if (cause == "xyz.openbmc_project.State.Host.RestartCause."
593 "PowerPolicyPreviousState")
594 {
595 restartCauseValue = 0x7;
596 }
597 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PEFReset")
598 {
599 restartCauseValue = 0x8;
600 }
601 else if (cause ==
602 "xyz.openbmc_project.State.Host.RestartCause.PEFPowerCycle")
603 {
604 restartCauseValue = 0x9;
605 }
606 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.SoftReset")
607 {
608 restartCauseValue = 0xa;
609 }
610 else if (cause == "xyz.openbmc_project.State.Host.RestartCause.RTCWakeup")
611 {
612 restartCauseValue = 0xb;
613 }
614 return restartCauseValue;
615}
616
617ipmi::RspType<uint4_t, // Restart Cause
618 uint4_t, // reserved
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700619 uint8_t // channel number
Jason M. Bills3efc6452019-06-20 15:51:47 -0700620 >
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700621 ipmiGetSystemRestartCause(ipmi::Context::ptr ctx)
Jason M. Bills3efc6452019-06-20 15:51:47 -0700622{
Jason M. Bills3efc6452019-06-20 15:51:47 -0700623 std::string restartCauseStr;
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700624 if (!getRestartCause(ctx, restartCauseStr))
Jason M. Bills3efc6452019-06-20 15:51:47 -0700625 {
Jason M. Bills3efc6452019-06-20 15:51:47 -0700626 return ipmi::responseUnspecifiedError();
627 }
Vernon Mauery1b751dc2021-06-16 11:21:05 -0700628 constexpr uint4_t reserved = 0;
629 auto channel = static_cast<uint8_t>(ctx->channel);
630 return ipmi::responseSuccess(getRestartCauseValue(restartCauseStr),
631 reserved, channel);
Jason M. Bills3efc6452019-06-20 15:51:47 -0700632}
633
Vernon Mauerydcff1502022-09-28 11:12:46 -0700634ipmi::RspType<> ipmiSetFrontPanelButtonEnables(
635 bool disablePowerButton, bool disableResetButton,
636 bool disableInterruptButton, [[maybe_unused]] bool disableSleepButton,
637 uint4_t reserved)
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700638{
sunitakx3ff63712021-06-09 15:47:32 +0000639 if (reserved)
640 {
641 return ipmi::responseInvalidFieldRequest();
642 }
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700643 bool error = false;
644
645 error |= setButtonEnabled(powerButtonPath, disablePowerButton);
646 error |= setButtonEnabled(resetButtonPath, disableResetButton);
647 error |= setButtonEnabled(interruptButtonPath, disableInterruptButton);
648
649 if (error)
650 {
651 return ipmi::responseUnspecifiedError();
652 }
sunitakx3ff63712021-06-09 15:47:32 +0000653
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700654 return ipmi::responseSuccess();
655}
656
Yuan Li60e7aaf2019-05-28 14:22:40 +0800657static void registerChassisFunctions(void)
658{
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700659 log<level::INFO>("Registering Chassis commands");
Yuan Li60e7aaf2019-05-28 14:22:40 +0800660
661 createIdentifyTimer();
662
663 if (matchPtr == nullptr)
664 {
665 using namespace sdbusplus::bus::match::rules;
666 auto bus = getSdBus();
667
668 matchPtr = std::make_unique<sdbusplus::bus::match_t>(
669 *bus,
670 sdbusplus::bus::match::rules::propertiesChanged(idButtonPath,
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700671 buttonIntf),
Yuan Li60e7aaf2019-05-28 14:22:40 +0800672 std::bind(idButtonPropChanged, std::placeholders::_1));
673 }
674
675 // <Chassis Identify>
676 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
677 ipmi::chassis::cmdChassisIdentify,
678 ipmi::Privilege::Operator, ipmiChassisIdentify);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700679 // <Get Chassis Status>
680 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
681 ipmi::chassis::cmdGetChassisStatus,
682 ipmi::Privilege::User, ipmiGetChassisStatus);
Jason M. Bills3efc6452019-06-20 15:51:47 -0700683 // <Get System Restart Cause>
684 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
685 ipmi::chassis::cmdGetSystemRestartCause,
686 ipmi::Privilege::User, ipmiGetSystemRestartCause);
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700687 // <Set Front Panel Enables>
688 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
689 ipmi::chassis::cmdSetFrontPanelButtonEnables,
AppaRao Puli51acbdf2019-11-10 21:05:34 +0530690 ipmi::Privilege::Admin,
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700691 ipmiSetFrontPanelButtonEnables);
Yuan Li60e7aaf2019-05-28 14:22:40 +0800692}
693
Jason M. Billsb08f84e2019-06-10 12:59:42 -0700694} // namespace ipmi::chassis