xref: /openbmc/intel-ipmi-oem/src/chassiscommands.cpp (revision 4843746a466f09f4592752e666eb0d15cabf54ee)
160e7aaf5SYuan Li /*
260e7aaf5SYuan Li // Copyright (c) 2019 Intel Corporation
360e7aaf5SYuan Li //
460e7aaf5SYuan Li // Licensed under the Apache License, Version 2.0 (the "License");
560e7aaf5SYuan Li // you may not use this file except in compliance with the License.
660e7aaf5SYuan Li // You may obtain a copy of the License at
760e7aaf5SYuan Li //
860e7aaf5SYuan Li //      http://www.apache.org/licenses/LICENSE-2.0
960e7aaf5SYuan Li //
1060e7aaf5SYuan Li // Unless required by applicable law or agreed to in writing, software
1160e7aaf5SYuan Li // distributed under the License is distributed on an "AS IS" BASIS,
1260e7aaf5SYuan Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1360e7aaf5SYuan Li // See the License for the specific language governing permissions and
1460e7aaf5SYuan Li // limitations under the License.
1560e7aaf5SYuan Li */
1660e7aaf5SYuan Li #include "xyz/openbmc_project/Common/error.hpp"
1760e7aaf5SYuan Li 
1860e7aaf5SYuan Li #include <ipmid/api.hpp>
1960e7aaf5SYuan Li #include <ipmid/utils.hpp>
2060e7aaf5SYuan Li #include <nlohmann/json.hpp>
2160e7aaf5SYuan Li #include <phosphor-logging/elog-errors.hpp>
22b08f84e3SJason M. Bills #include <phosphor-logging/log.hpp>
2360e7aaf5SYuan Li #include <sdbusplus/timer.hpp>
24fcd2d3a9SJames Feist #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
25fcd2d3a9SJames Feist 
26fcd2d3a9SJames Feist #include <fstream>
27fcd2d3a9SJames Feist #include <iostream>
28fcd2d3a9SJames Feist #include <regex>
29b08f84e3SJason M. Bills #include <stdexcept>
30b08f84e3SJason M. Bills #include <string_view>
3160e7aaf5SYuan Li 
32b08f84e3SJason M. Bills using namespace phosphor::logging;
33b08f84e3SJason M. Bills 
34b08f84e3SJason M. Bills namespace ipmi::chassis
3560e7aaf5SYuan Li {
36b08f84e3SJason M. Bills static constexpr const char* buttonIntf = "xyz.openbmc_project.Chassis.Buttons";
37b08f84e3SJason M. Bills 
3860e7aaf5SYuan Li const static constexpr char* idButtonPath =
3960e7aaf5SYuan Li     "/xyz/openbmc_project/chassis/buttons/id";
40b08f84e3SJason M. Bills static constexpr const char* powerButtonPath =
41b08f84e3SJason M. Bills     "/xyz/openbmc_project/chassis/buttons/power";
42b08f84e3SJason M. Bills static constexpr const char* resetButtonPath =
43b08f84e3SJason M. Bills     "/xyz/openbmc_project/chassis/buttons/reset";
44b08f84e3SJason M. Bills static constexpr const char* interruptButtonPath =
45b08f84e3SJason M. Bills     "/xyz/openbmc_project/chassis/buttons/nmi";
46b08f84e3SJason M. Bills 
4760e7aaf5SYuan Li const static constexpr char* idButtonProp = "ButtonPressed";
4860e7aaf5SYuan Li 
4960e7aaf5SYuan Li const static constexpr char* ledService =
5060e7aaf5SYuan Li     "xyz.openbmc_project.LED.GroupManager";
5160e7aaf5SYuan Li const static constexpr char* ledIDOnObj =
5260e7aaf5SYuan Li     "/xyz/openbmc_project/led/groups/enclosure_identify";
5360e7aaf5SYuan Li const static constexpr char* ledIDBlinkObj =
5460e7aaf5SYuan Li     "/xyz/openbmc_project/led/groups/enclosure_identify_blink";
5560e7aaf5SYuan Li const static constexpr char* ledInterface = "xyz.openbmc_project.Led.Group";
5660e7aaf5SYuan Li const static constexpr char* ledProp = "Asserted";
5709221d70SJason M. Bills enum class ChassisIDState
5809221d70SJason M. Bills {
5909221d70SJason M. Bills     off = 0,
6009221d70SJason M. Bills     temporary = 1,
6109221d70SJason M. Bills     indefinite = 2,
6209221d70SJason M. Bills };
6309221d70SJason M. Bills static ChassisIDState chassisIDState = ChassisIDState::off;
6460e7aaf5SYuan Li 
6560e7aaf5SYuan Li constexpr size_t defaultIdentifyTimeOut = 15;
6660e7aaf5SYuan Li 
67f0feb49cSPatrick Williams std::unique_ptr<sdbusplus::Timer> identifyTimer
6860e7aaf5SYuan Li     __attribute__((init_priority(101)));
6960e7aaf5SYuan Li std::unique_ptr<sdbusplus::bus::match_t> matchPtr
7060e7aaf5SYuan Li     __attribute__((init_priority(101)));
7160e7aaf5SYuan Li 
7260e7aaf5SYuan Li static void registerChassisFunctions() __attribute__((constructor));
7360e7aaf5SYuan Li 
7460e7aaf5SYuan Li static ipmi::ServiceCache LEDService(ledInterface, ledIDBlinkObj);
7560e7aaf5SYuan Li 
enclosureIdentifyLed(const char * objName,bool isIdLedOn)7660e7aaf5SYuan Li void enclosureIdentifyLed(const char* objName, bool isIdLedOn)
7760e7aaf5SYuan Li {
7860e7aaf5SYuan Li     auto bus = getSdBus();
7960e7aaf5SYuan Li 
8060e7aaf5SYuan Li     try
8160e7aaf5SYuan Li     {
8260e7aaf5SYuan Li         std::string service = LEDService.getService(*bus);
8360e7aaf5SYuan Li         setDbusProperty(*bus, service, objName, ledInterface, ledProp,
8460e7aaf5SYuan Li                         isIdLedOn);
8560e7aaf5SYuan Li     }
8660e7aaf5SYuan Li     catch (const std::exception& e)
8760e7aaf5SYuan Li     {
88b08f84e3SJason M. Bills         log<level::ERR>("enclosureIdentifyLed: can't set property",
89b08f84e3SJason M. Bills                         entry("ERR=%s", e.what()));
9060e7aaf5SYuan Li     }
9160e7aaf5SYuan Li }
9260e7aaf5SYuan Li 
getIDState(const char * objName,bool & state)9360e7aaf5SYuan Li bool getIDState(const char* objName, bool& state)
9460e7aaf5SYuan Li {
9560e7aaf5SYuan Li     auto bus = getSdBus();
9660e7aaf5SYuan Li 
9760e7aaf5SYuan Li     try
9860e7aaf5SYuan Li     {
9960e7aaf5SYuan Li         std::string service = LEDService.getService(*bus);
100*1bcced08SPatrick Williams         ipmi::Value enabled =
101*1bcced08SPatrick Williams             getDbusProperty(*bus, service, objName, ledInterface, ledProp);
10260e7aaf5SYuan Li         state = std::get<bool>(enabled);
10360e7aaf5SYuan Li     }
104f944d2e5SPatrick Williams     catch (const sdbusplus::exception_t& e)
10560e7aaf5SYuan Li     {
106b08f84e3SJason M. Bills         log<level::ERR>("Fail to get property", entry("PATH=%s", objName),
107b08f84e3SJason M. Bills                         entry("ERROR=%s", e.what()));
10860e7aaf5SYuan Li         return false;
10960e7aaf5SYuan Li     }
11060e7aaf5SYuan Li     return true;
11160e7aaf5SYuan Li }
11260e7aaf5SYuan Li 
enclosureIdentifyLedBlinkOff()11360e7aaf5SYuan Li void enclosureIdentifyLedBlinkOff()
11460e7aaf5SYuan Li {
11509221d70SJason M. Bills     chassisIDState = ChassisIDState::off;
11660e7aaf5SYuan Li     enclosureIdentifyLed(ledIDBlinkObj, false);
11760e7aaf5SYuan Li }
11860e7aaf5SYuan Li 
idButtonPropChanged(sdbusplus::message_t & msg)119f944d2e5SPatrick Williams void idButtonPropChanged(sdbusplus::message_t& msg)
12060e7aaf5SYuan Li {
12160e7aaf5SYuan Li     bool asserted = false;
12260e7aaf5SYuan Li     bool buttonPressed = false;
12360e7aaf5SYuan Li 
12460e7aaf5SYuan Li     std::map<std::string, ipmi::Value> props;
12560e7aaf5SYuan Li     std::vector<std::string> inval;
12660e7aaf5SYuan Li     std::string iface;
12760e7aaf5SYuan Li     msg.read(iface, props, inval);
12860e7aaf5SYuan Li 
12960e7aaf5SYuan Li     for (const auto& t : props)
13060e7aaf5SYuan Li     {
13160e7aaf5SYuan Li         auto key = t.first;
13260e7aaf5SYuan Li         auto value = t.second;
13360e7aaf5SYuan Li 
13460e7aaf5SYuan Li         if (key == idButtonProp)
13560e7aaf5SYuan Li         {
13660e7aaf5SYuan Li             buttonPressed = std::get<bool>(value);
13760e7aaf5SYuan Li         }
13860e7aaf5SYuan Li         break;
13960e7aaf5SYuan Li     }
14060e7aaf5SYuan Li 
14160e7aaf5SYuan Li     if (buttonPressed)
14260e7aaf5SYuan Li     {
14360e7aaf5SYuan Li         if (identifyTimer->isRunning())
14460e7aaf5SYuan Li         {
145b08f84e3SJason M. Bills             log<level::INFO>("ID timer is running");
14660e7aaf5SYuan Li         }
14760e7aaf5SYuan Li 
14860e7aaf5SYuan Li         // make sure timer is stopped
14960e7aaf5SYuan Li         identifyTimer->stop();
15060e7aaf5SYuan Li 
15160e7aaf5SYuan Li         if (!getIDState(ledIDBlinkObj, asserted))
15260e7aaf5SYuan Li         {
15360e7aaf5SYuan Li             return;
15460e7aaf5SYuan Li         }
15560e7aaf5SYuan Li 
15660e7aaf5SYuan Li         if (asserted)
15760e7aaf5SYuan Li         {
15860e7aaf5SYuan Li             // LED is blinking, turn off the LED
15909221d70SJason M. Bills             chassisIDState = ChassisIDState::off;
16060e7aaf5SYuan Li             enclosureIdentifyLed(ledIDBlinkObj, false);
16160e7aaf5SYuan Li             enclosureIdentifyLed(ledIDOnObj, false);
16260e7aaf5SYuan Li         }
16360e7aaf5SYuan Li         else
16460e7aaf5SYuan Li         {
16560e7aaf5SYuan Li             // toggle the IED on/off
16660e7aaf5SYuan Li             if (!getIDState(ledIDOnObj, asserted))
16760e7aaf5SYuan Li             {
16860e7aaf5SYuan Li                 return;
16960e7aaf5SYuan Li             }
17060e7aaf5SYuan Li             enclosureIdentifyLed(ledIDOnObj, !asserted);
17160e7aaf5SYuan Li         }
17260e7aaf5SYuan Li     }
17360e7aaf5SYuan Li }
17460e7aaf5SYuan Li 
createIdentifyTimer()17560e7aaf5SYuan Li void createIdentifyTimer()
17660e7aaf5SYuan Li {
17760e7aaf5SYuan Li     if (!identifyTimer)
17860e7aaf5SYuan Li     {
17960e7aaf5SYuan Li         identifyTimer =
180f0feb49cSPatrick Williams             std::make_unique<sdbusplus::Timer>(enclosureIdentifyLedBlinkOff);
18160e7aaf5SYuan Li     }
18260e7aaf5SYuan Li }
18360e7aaf5SYuan Li 
ipmiChassisIdentify(std::optional<uint8_t> interval,std::optional<uint8_t> force)18460e7aaf5SYuan Li ipmi::RspType<> ipmiChassisIdentify(std::optional<uint8_t> interval,
18560e7aaf5SYuan Li                                     std::optional<uint8_t> force)
18660e7aaf5SYuan Li {
18760e7aaf5SYuan Li     uint8_t identifyInterval = interval.value_or(defaultIdentifyTimeOut);
18860e7aaf5SYuan Li     bool forceIdentify = force.value_or(0) & 0x01;
18960e7aaf5SYuan Li 
19060e7aaf5SYuan Li     enclosureIdentifyLed(ledIDOnObj, false);
19160e7aaf5SYuan Li     identifyTimer->stop();
19260e7aaf5SYuan Li 
19360e7aaf5SYuan Li     if (identifyInterval || forceIdentify)
19460e7aaf5SYuan Li     {
19560e7aaf5SYuan Li         enclosureIdentifyLed(ledIDBlinkObj, true);
19660e7aaf5SYuan Li         if (forceIdentify)
19760e7aaf5SYuan Li         {
19809221d70SJason M. Bills             chassisIDState = ChassisIDState::indefinite;
19960e7aaf5SYuan Li             return ipmi::responseSuccess();
20060e7aaf5SYuan Li         }
20109221d70SJason M. Bills         chassisIDState = ChassisIDState::temporary;
20260e7aaf5SYuan Li         // start the timer
20360e7aaf5SYuan Li         auto time = std::chrono::duration_cast<std::chrono::microseconds>(
20460e7aaf5SYuan Li             std::chrono::seconds(identifyInterval));
20560e7aaf5SYuan Li         identifyTimer->start(time);
20660e7aaf5SYuan Li     }
20760e7aaf5SYuan Li     else
20860e7aaf5SYuan Li     {
20909221d70SJason M. Bills         chassisIDState = ChassisIDState::off;
21060e7aaf5SYuan Li         enclosureIdentifyLed(ledIDBlinkObj, false);
21160e7aaf5SYuan Li     }
21260e7aaf5SYuan Li     return ipmi::responseSuccess();
21360e7aaf5SYuan Li }
21460e7aaf5SYuan Li 
215b08f84e3SJason M. Bills namespace power_policy
216b08f84e3SJason M. Bills {
217b08f84e3SJason M. Bills /* helper function for Get Chassis Status Command
218b08f84e3SJason M. Bills  */
getPowerRestorePolicy()219b08f84e3SJason M. Bills std::optional<uint2_t> getPowerRestorePolicy()
220b08f84e3SJason M. Bills {
221b08f84e3SJason M. Bills     constexpr const char* powerRestorePath =
222b08f84e3SJason M. Bills         "/xyz/openbmc_project/control/host0/power_restore_policy";
223b08f84e3SJason M. Bills     constexpr const char* powerRestoreIntf =
224b08f84e3SJason M. Bills         "xyz.openbmc_project.Control.Power.RestorePolicy";
225b08f84e3SJason M. Bills     uint2_t restorePolicy = 0;
226b08f84e3SJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
227b08f84e3SJason M. Bills 
228b08f84e3SJason M. Bills     try
229b08f84e3SJason M. Bills     {
230*1bcced08SPatrick Williams         auto service =
231*1bcced08SPatrick Williams             ipmi::getService(*busp, powerRestoreIntf, powerRestorePath);
232b08f84e3SJason M. Bills 
233b08f84e3SJason M. Bills         ipmi::Value result =
234b08f84e3SJason M. Bills             ipmi::getDbusProperty(*busp, service, powerRestorePath,
235b08f84e3SJason M. Bills                                   powerRestoreIntf, "PowerRestorePolicy");
236b08f84e3SJason M. Bills         auto powerRestore = sdbusplus::xyz::openbmc_project::Control::Power::
237b08f84e3SJason M. Bills             server::RestorePolicy::convertPolicyFromString(
238b08f84e3SJason M. Bills                 std::get<std::string>(result));
239b08f84e3SJason M. Bills 
240b08f84e3SJason M. Bills         using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
241b08f84e3SJason M. Bills         switch (powerRestore)
242b08f84e3SJason M. Bills         {
243b08f84e3SJason M. Bills             case RestorePolicy::Policy::AlwaysOff:
244b08f84e3SJason M. Bills                 restorePolicy = 0x00;
245b08f84e3SJason M. Bills                 break;
246b08f84e3SJason M. Bills             case RestorePolicy::Policy::Restore:
247b08f84e3SJason M. Bills                 restorePolicy = 0x01;
248b08f84e3SJason M. Bills                 break;
249b08f84e3SJason M. Bills             case RestorePolicy::Policy::AlwaysOn:
250b08f84e3SJason M. Bills                 restorePolicy = 0x02;
251b08f84e3SJason M. Bills                 break;
252dcff1506SVernon Mauery             default:
253dcff1506SVernon Mauery                 break;
254b08f84e3SJason M. Bills         }
255b08f84e3SJason M. Bills     }
256b08f84e3SJason M. Bills     catch (const std::exception& e)
257b08f84e3SJason M. Bills     {
258b08f84e3SJason M. Bills         log<level::ERR>("Failed to fetch PowerRestorePolicy property",
259b08f84e3SJason M. Bills                         entry("ERROR=%s", e.what()),
260b08f84e3SJason M. Bills                         entry("PATH=%s", powerRestorePath),
261b08f84e3SJason M. Bills                         entry("INTERFACE=%s", powerRestoreIntf));
262b08f84e3SJason M. Bills         return std::nullopt;
263b08f84e3SJason M. Bills     }
264b08f84e3SJason M. Bills     return std::make_optional(restorePolicy);
265b08f84e3SJason M. Bills }
266b08f84e3SJason M. Bills 
267b08f84e3SJason M. Bills /*
268b08f84e3SJason M. Bills  * getPowerStatus
269b08f84e3SJason M. Bills  * helper function for Get Chassis Status Command
270b08f84e3SJason M. Bills  * return - optional value for pgood (no value on error)
271b08f84e3SJason M. Bills  */
getPowerStatus()272b08f84e3SJason M. Bills std::optional<bool> getPowerStatus()
273b08f84e3SJason M. Bills {
274b08f84e3SJason M. Bills     bool powerGood = false;
275b08f84e3SJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
276b08f84e3SJason M. Bills     try
277b08f84e3SJason M. Bills     {
278b08f84e3SJason M. Bills         constexpr const char* chassisStatePath =
279b08f84e3SJason M. Bills             "/xyz/openbmc_project/state/chassis0";
280b08f84e3SJason M. Bills         constexpr const char* chassisStateIntf =
281b08f84e3SJason M. Bills             "xyz.openbmc_project.State.Chassis";
282*1bcced08SPatrick Williams         auto service =
283*1bcced08SPatrick Williams             ipmi::getService(*busp, chassisStateIntf, chassisStatePath);
284b08f84e3SJason M. Bills 
285b08f84e3SJason M. Bills         ipmi::Value variant =
286b08f84e3SJason M. Bills             ipmi::getDbusProperty(*busp, service, chassisStatePath,
287b08f84e3SJason M. Bills                                   chassisStateIntf, "CurrentPowerState");
288b08f84e3SJason M. Bills         std::string powerState = std::get<std::string>(variant);
289b08f84e3SJason M. Bills         if (powerState == "xyz.openbmc_project.State.Chassis.PowerState.On")
290b08f84e3SJason M. Bills         {
291b08f84e3SJason M. Bills             powerGood = true;
292b08f84e3SJason M. Bills         }
293b08f84e3SJason M. Bills     }
294b08f84e3SJason M. Bills     catch (const std::exception& e)
295b08f84e3SJason M. Bills     {
296b08f84e3SJason M. Bills         log<level::ERR>("Failed to fetch power state property",
297b08f84e3SJason M. Bills                         entry("ERROR=%s", e.what()));
298b08f84e3SJason M. Bills         return std::nullopt;
299b08f84e3SJason M. Bills     }
300b08f84e3SJason M. Bills     return std::make_optional(powerGood);
301b08f84e3SJason M. Bills }
302b08f84e3SJason M. Bills 
303b08f84e3SJason M. Bills /*
304b08f84e3SJason M. Bills  * getACFailStatus
305b08f84e3SJason M. Bills  * helper function for Get Chassis Status Command
306b08f84e3SJason M. Bills  * return - bool value for ACFail (false on error)
307b08f84e3SJason M. Bills  */
getACFailStatus()308b08f84e3SJason M. Bills bool getACFailStatus()
309b08f84e3SJason M. Bills {
310a2b4c7a1SJason M. Bills     constexpr const char* acBootObj =
311a2b4c7a1SJason M. Bills         "/xyz/openbmc_project/control/host0/ac_boot";
312a2b4c7a1SJason M. Bills     constexpr const char* acBootIntf = "xyz.openbmc_project.Common.ACBoot";
313a2b4c7a1SJason M. Bills     std::string acFail;
314b08f84e3SJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
315b08f84e3SJason M. Bills     try
316b08f84e3SJason M. Bills     {
317a2b4c7a1SJason M. Bills         auto service = ipmi::getService(*bus, acBootIntf, acBootObj);
318b08f84e3SJason M. Bills 
319a2b4c7a1SJason M. Bills         ipmi::Value variant = ipmi::getDbusProperty(*bus, service, acBootObj,
320a2b4c7a1SJason M. Bills                                                     acBootIntf, "ACBoot");
321a2b4c7a1SJason M. Bills         acFail = std::get<std::string>(variant);
322b08f84e3SJason M. Bills     }
323b08f84e3SJason M. Bills     catch (const std::exception& e)
324b08f84e3SJason M. Bills     {
325a2b4c7a1SJason M. Bills         log<level::ERR>(
326a2b4c7a1SJason M. Bills             "Failed to fetch ACBoot property", entry("ERROR=%s", e.what()),
327a2b4c7a1SJason M. Bills             entry("PATH=%s", acBootObj), entry("INTERFACE=%s", acBootIntf));
328b08f84e3SJason M. Bills     }
329a2b4c7a1SJason M. Bills     return acFail == "True";
330b08f84e3SJason M. Bills }
331b08f84e3SJason M. Bills } // namespace power_policy
332b08f84e3SJason M. Bills 
getButtonEnabled(const std::string & buttonPath)333b08f84e3SJason M. Bills static std::optional<bool> getButtonEnabled(const std::string& buttonPath)
334b08f84e3SJason M. Bills {
335b08f84e3SJason M. Bills     bool buttonDisabled = false;
336b08f84e3SJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
337b08f84e3SJason M. Bills     try
338b08f84e3SJason M. Bills     {
339b08f84e3SJason M. Bills         auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
340b08f84e3SJason M. Bills         ipmi::Value disabled = ipmi::getDbusProperty(
341b08f84e3SJason M. Bills             *busp, service, buttonPath, buttonIntf, "ButtonMasked");
342b08f84e3SJason M. Bills         buttonDisabled = std::get<bool>(disabled);
343b08f84e3SJason M. Bills     }
344f944d2e5SPatrick Williams     catch (const sdbusplus::exception_t& e)
345b08f84e3SJason M. Bills     {
346b08f84e3SJason M. Bills         log<level::ERR>("Fail to get button disabled property",
347b08f84e3SJason M. Bills                         entry("PATH=%s", buttonPath.c_str()),
348b08f84e3SJason M. Bills                         entry("ERROR=%s", e.what()));
349b08f84e3SJason M. Bills         return std::nullopt;
350b08f84e3SJason M. Bills     }
351b08f84e3SJason M. Bills     return std::make_optional(buttonDisabled);
352b08f84e3SJason M. Bills }
353b08f84e3SJason M. Bills 
setButtonEnabled(const std::string & buttonPath,const bool disabled)354b08f84e3SJason M. Bills static bool setButtonEnabled(const std::string& buttonPath, const bool disabled)
355b08f84e3SJason M. Bills {
356b08f84e3SJason M. Bills     try
357b08f84e3SJason M. Bills     {
358b08f84e3SJason M. Bills         auto service = ipmi::getService(*getSdBus(), buttonIntf, buttonPath);
359b08f84e3SJason M. Bills         ipmi::setDbusProperty(*getSdBus(), service, buttonPath, buttonIntf,
360b08f84e3SJason M. Bills                               "ButtonMasked", disabled);
361b08f84e3SJason M. Bills     }
362bd51e6a9SPatrick Williams     catch (const std::exception& e)
363b08f84e3SJason M. Bills     {
364b08f84e3SJason M. Bills         log<level::ERR>("Failed to set button disabled",
365b08f84e3SJason M. Bills                         entry("EXCEPTION=%s, REQUEST=%x", e.what(), disabled));
366b08f84e3SJason M. Bills         return -1;
367b08f84e3SJason M. Bills     }
368b08f84e3SJason M. Bills 
369b08f84e3SJason M. Bills     return 0;
370b08f84e3SJason M. Bills }
371b08f84e3SJason M. Bills 
getRestartCause(ipmi::Context::ptr & ctx,std::string & restartCause)3721b751dc2SVernon Mauery static bool getRestartCause(ipmi::Context::ptr& ctx, std::string& restartCause)
3738c61539aSJason M. Bills {
3748c61539aSJason M. Bills     constexpr const char* restartCausePath =
3758c61539aSJason M. Bills         "/xyz/openbmc_project/control/host0/restart_cause";
3768c61539aSJason M. Bills     constexpr const char* restartCauseIntf =
377bf124d46SJason M. Bills         "xyz.openbmc_project.Control.Host.RestartCause";
3788c61539aSJason M. Bills 
3791b751dc2SVernon Mauery     std::string service;
380*1bcced08SPatrick Williams     boost::system::error_code ec =
381*1bcced08SPatrick Williams         ipmi::getService(ctx, restartCauseIntf, restartCausePath, service);
3821b751dc2SVernon Mauery 
3831b751dc2SVernon Mauery     if (!ec)
3848c61539aSJason M. Bills     {
3851b751dc2SVernon Mauery         ec = ipmi::getDbusProperty(ctx, service, restartCausePath,
3861b751dc2SVernon Mauery                                    restartCauseIntf, "RestartCause",
3871b751dc2SVernon Mauery                                    restartCause);
3888c61539aSJason M. Bills     }
3891b751dc2SVernon Mauery     if (ec)
3908c61539aSJason M. Bills     {
3918c61539aSJason M. Bills         log<level::ERR>("Failed to fetch RestartCause property",
3921b751dc2SVernon Mauery                         entry("ERROR=%s", ec.message().c_str()),
3938c61539aSJason M. Bills                         entry("PATH=%s", restartCausePath),
3948c61539aSJason M. Bills                         entry("INTERFACE=%s", restartCauseIntf));
3958c61539aSJason M. Bills         return false;
3968c61539aSJason M. Bills     }
3978c61539aSJason M. Bills     return true;
3988c61539aSJason M. Bills }
3998c61539aSJason M. Bills 
checkIPMIRestartCause(ipmi::Context::ptr & ctx,bool & ipmiRestartCause)4001b751dc2SVernon Mauery static bool checkIPMIRestartCause(ipmi::Context::ptr& ctx,
4011b751dc2SVernon Mauery                                   bool& ipmiRestartCause)
4028c61539aSJason M. Bills {
4038c61539aSJason M. Bills     std::string restartCause;
4041b751dc2SVernon Mauery     if (!getRestartCause(ctx, restartCause))
4058c61539aSJason M. Bills     {
4068c61539aSJason M. Bills         return false;
4078c61539aSJason M. Bills     }
4088c61539aSJason M. Bills     ipmiRestartCause =
4098c61539aSJason M. Bills         (restartCause ==
4108c61539aSJason M. Bills          "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand");
4118c61539aSJason M. Bills     return true;
4128c61539aSJason M. Bills }
4138c61539aSJason M. Bills 
414b08f84e3SJason M. Bills //----------------------------------------------------------------------
415b08f84e3SJason M. Bills // Get Chassis Status commands
416b08f84e3SJason M. Bills //----------------------------------------------------------------------
417b08f84e3SJason M. Bills ipmi::RspType<bool,    // Power is on
418b08f84e3SJason M. Bills               bool,    // Power overload
419b08f84e3SJason M. Bills               bool,    // Interlock
420b08f84e3SJason M. Bills               bool,    // power fault
421b08f84e3SJason M. Bills               bool,    // power control fault
422b08f84e3SJason M. Bills               uint2_t, // power restore policy
423b08f84e3SJason M. Bills               bool,    // reserved
424b08f84e3SJason M. Bills 
425b08f84e3SJason M. Bills               bool,    // AC failed
426b08f84e3SJason M. Bills               bool,    // last power down caused by a Power overload
427b08f84e3SJason M. Bills               bool,    // last power down caused by a power interlock
428b08f84e3SJason M. Bills               bool,    // last power down caused by power fault
429b08f84e3SJason M. Bills               bool,    // last ‘Power is on’ state was entered via IPMI command
430b08f84e3SJason M. Bills               uint3_t, // reserved
431b08f84e3SJason M. Bills 
432b08f84e3SJason M. Bills               bool,    // Chassis intrusion active
433b08f84e3SJason M. Bills               bool,    // Front Panel Lockout active
434b08f84e3SJason M. Bills               bool,    // Drive Fault
435b08f84e3SJason M. Bills               bool,    // Cooling/fan fault detected
436b08f84e3SJason M. Bills               uint2_t, // Chassis Identify State
437b08f84e3SJason M. Bills               bool,    // Chassis Identify command and state info supported
438b08f84e3SJason M. Bills               bool,    // reserved
439b08f84e3SJason M. Bills 
440b08f84e3SJason M. Bills               bool,    // Power off button disabled
441b08f84e3SJason M. Bills               bool,    // Reset button disabled
442b08f84e3SJason M. Bills               bool,    // Diagnostic Interrupt button disabled
443b08f84e3SJason M. Bills               bool,    // Standby (sleep) button disabled
444b08f84e3SJason M. Bills               bool,    // Power off button disable allowed
445b08f84e3SJason M. Bills               bool,    // Reset button disable allowed
446b08f84e3SJason M. Bills               bool,    // Diagnostic Interrupt button disable allowed
447b08f84e3SJason M. Bills               bool     // Standby (sleep) button disable allowed
448b08f84e3SJason M. Bills               >
ipmiGetChassisStatus(ipmi::Context::ptr ctx)4491b751dc2SVernon Mauery     ipmiGetChassisStatus(ipmi::Context::ptr ctx)
450b08f84e3SJason M. Bills {
451b08f84e3SJason M. Bills     std::optional<uint2_t> restorePolicy =
452b08f84e3SJason M. Bills         power_policy::getPowerRestorePolicy();
453b08f84e3SJason M. Bills     std::optional<bool> powerGood = power_policy::getPowerStatus();
454b08f84e3SJason M. Bills     if (!restorePolicy || !powerGood)
455b08f84e3SJason M. Bills     {
456b08f84e3SJason M. Bills         return ipmi::responseUnspecifiedError();
457b08f84e3SJason M. Bills     }
458b08f84e3SJason M. Bills 
459b08f84e3SJason M. Bills     //  Front Panel Button Capabilities and disable/enable status(Optional)
460b08f84e3SJason M. Bills     std::optional<bool> powerButtonReading = getButtonEnabled(powerButtonPath);
461b08f84e3SJason M. Bills     // allow disable if the interface is present
462b08f84e3SJason M. Bills     bool powerButtonDisableAllow = static_cast<bool>(powerButtonReading);
463b08f84e3SJason M. Bills     // default return the button is enabled (not disabled)
464b08f84e3SJason M. Bills     bool powerButtonDisabled = false;
465b08f84e3SJason M. Bills     if (powerButtonDisableAllow)
466b08f84e3SJason M. Bills     {
467b08f84e3SJason M. Bills         // return the real value of the button status, if present
468b08f84e3SJason M. Bills         powerButtonDisabled = *powerButtonReading;
469b08f84e3SJason M. Bills     }
470b08f84e3SJason M. Bills 
471b08f84e3SJason M. Bills     std::optional<bool> resetButtonReading = getButtonEnabled(resetButtonPath);
472b08f84e3SJason M. Bills     // allow disable if the interface is present
473b08f84e3SJason M. Bills     bool resetButtonDisableAllow = static_cast<bool>(resetButtonReading);
474b08f84e3SJason M. Bills     // default return the button is enabled (not disabled)
475b08f84e3SJason M. Bills     bool resetButtonDisabled = false;
476b08f84e3SJason M. Bills     if (resetButtonDisableAllow)
477b08f84e3SJason M. Bills     {
478b08f84e3SJason M. Bills         // return the real value of the button status, if present
479b08f84e3SJason M. Bills         resetButtonDisabled = *resetButtonReading;
480b08f84e3SJason M. Bills     }
481b08f84e3SJason M. Bills 
482b08f84e3SJason M. Bills     std::optional<bool> interruptButtonReading =
483b08f84e3SJason M. Bills         getButtonEnabled(interruptButtonPath);
484b08f84e3SJason M. Bills     // allow disable if the interface is present
485b08f84e3SJason M. Bills     bool interruptButtonDisableAllow =
486b08f84e3SJason M. Bills         static_cast<bool>(interruptButtonReading);
487b08f84e3SJason M. Bills     // default return the button is enabled (not disabled)
488b08f84e3SJason M. Bills     bool interruptButtonDisabled = false;
489b08f84e3SJason M. Bills     if (interruptButtonDisableAllow)
490b08f84e3SJason M. Bills     {
491b08f84e3SJason M. Bills         // return the real value of the button status, if present
492b08f84e3SJason M. Bills         interruptButtonDisabled = *interruptButtonReading;
493b08f84e3SJason M. Bills     }
494b08f84e3SJason M. Bills 
495b08f84e3SJason M. Bills     bool powerDownAcFailed = power_policy::getACFailStatus();
496b08f84e3SJason M. Bills 
4978c61539aSJason M. Bills     bool powerStatusIPMI = false;
4981b751dc2SVernon Mauery     if (!checkIPMIRestartCause(ctx, powerStatusIPMI))
4998c61539aSJason M. Bills     {
5008c61539aSJason M. Bills         return ipmi::responseUnspecifiedError();
5018c61539aSJason M. Bills     }
5028c61539aSJason M. Bills 
5037f819e8bSMatt Simmering     bool chassisIntrusionActive = false;
5047f819e8bSMatt Simmering     constexpr const char* chassisIntrusionObj =
505c56005e5SMatt Simmering         "/xyz/openbmc_project/Chassis/Intrusion";
5067f819e8bSMatt Simmering     constexpr const char* chassisIntrusionInf =
5077f819e8bSMatt Simmering         "xyz.openbmc_project.Chassis.Intrusion";
5087f819e8bSMatt Simmering 
5097f819e8bSMatt Simmering     std::string intrusionService;
5107f819e8bSMatt Simmering     boost::system::error_code ec = ipmi::getService(
5117f819e8bSMatt Simmering         ctx, chassisIntrusionInf, chassisIntrusionObj, intrusionService);
512dcff1506SVernon Mauery     if (ec)
5137f819e8bSMatt Simmering     {
5147f819e8bSMatt Simmering         log<level::ERR>("Failed to get Chassis Intrusion service",
515dcff1506SVernon Mauery                         entry("ERROR=%s", ec.message().c_str()));
5167f819e8bSMatt Simmering     }
5177f819e8bSMatt Simmering 
518dcff1506SVernon Mauery     chassisIntrusionActive = !intrusionService.empty();
519dcff1506SVernon Mauery 
520b08f84e3SJason M. Bills     // This response has a lot of hard-coded, unsupported fields
521b08f84e3SJason M. Bills     // They are set to false or 0
522b08f84e3SJason M. Bills     constexpr bool powerOverload = false;
523b08f84e3SJason M. Bills     constexpr bool chassisInterlock = false;
524b08f84e3SJason M. Bills     constexpr bool powerFault = false;
525b08f84e3SJason M. Bills     constexpr bool powerControlFault = false;
526b08f84e3SJason M. Bills     constexpr bool powerDownOverload = false;
527b08f84e3SJason M. Bills     constexpr bool powerDownInterlock = false;
528b08f84e3SJason M. Bills     constexpr bool powerDownPowerFault = false;
529b08f84e3SJason M. Bills     constexpr bool frontPanelLockoutActive = false;
530b08f84e3SJason M. Bills     constexpr bool driveFault = false;
531b08f84e3SJason M. Bills     constexpr bool coolingFanFault = false;
532b08f84e3SJason M. Bills     // chassisIdentifySupport set because this command is implemented
533b08f84e3SJason M. Bills     constexpr bool chassisIdentifySupport = true;
53424df90f7SJason M. Bills     uint2_t chassisIdentifyState = types::enum_cast<uint2_t>(chassisIDState);
535b08f84e3SJason M. Bills     constexpr bool sleepButtonDisabled = false;
536b08f84e3SJason M. Bills     constexpr bool sleepButtonDisableAllow = false;
537b08f84e3SJason M. Bills 
538b08f84e3SJason M. Bills     return ipmi::responseSuccess(
539b08f84e3SJason M. Bills         *powerGood, powerOverload, chassisInterlock, powerFault,
540b08f84e3SJason M. Bills         powerControlFault, *restorePolicy,
541b08f84e3SJason M. Bills         false, // reserved
542b08f84e3SJason M. Bills 
543b08f84e3SJason M. Bills         powerDownAcFailed, powerDownOverload, powerDownInterlock,
544b08f84e3SJason M. Bills         powerDownPowerFault, powerStatusIPMI,
545b08f84e3SJason M. Bills         uint3_t(0), // reserved
546b08f84e3SJason M. Bills 
547b08f84e3SJason M. Bills         chassisIntrusionActive, frontPanelLockoutActive, driveFault,
548b08f84e3SJason M. Bills         coolingFanFault, chassisIdentifyState, chassisIdentifySupport,
549b08f84e3SJason M. Bills         false, // reserved
550b08f84e3SJason M. Bills 
551b08f84e3SJason M. Bills         powerButtonDisabled, resetButtonDisabled, interruptButtonDisabled,
552b08f84e3SJason M. Bills         sleepButtonDisabled, powerButtonDisableAllow, resetButtonDisableAllow,
553b08f84e3SJason M. Bills         interruptButtonDisableAllow, sleepButtonDisableAllow);
554b08f84e3SJason M. Bills }
555b08f84e3SJason M. Bills 
getRestartCauseValue(const std::string & cause)5568c61539aSJason M. Bills static uint4_t getRestartCauseValue(const std::string& cause)
5573efc645eSJason M. Bills {
5583efc645eSJason M. Bills     uint4_t restartCauseValue = 0;
5593efc645eSJason M. Bills     if (cause == "xyz.openbmc_project.State.Host.RestartCause.Unknown")
5603efc645eSJason M. Bills     {
5613efc645eSJason M. Bills         restartCauseValue = 0x0;
5623efc645eSJason M. Bills     }
5633efc645eSJason M. Bills     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.IpmiCommand")
5643efc645eSJason M. Bills     {
5653efc645eSJason M. Bills         restartCauseValue = 0x1;
5663efc645eSJason M. Bills     }
5673efc645eSJason M. Bills     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.ResetButton")
5683efc645eSJason M. Bills     {
5693efc645eSJason M. Bills         restartCauseValue = 0x2;
5703efc645eSJason M. Bills     }
5713efc645eSJason M. Bills     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PowerButton")
5723efc645eSJason M. Bills     {
5733efc645eSJason M. Bills         restartCauseValue = 0x3;
5743efc645eSJason M. Bills     }
5753efc645eSJason M. Bills     else if (cause ==
5763efc645eSJason M. Bills              "xyz.openbmc_project.State.Host.RestartCause.WatchdogTimer")
5773efc645eSJason M. Bills     {
5783efc645eSJason M. Bills         restartCauseValue = 0x4;
5793efc645eSJason M. Bills     }
5803efc645eSJason M. Bills     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.OEM")
5813efc645eSJason M. Bills     {
5823efc645eSJason M. Bills         restartCauseValue = 0x5;
5833efc645eSJason M. Bills     }
5843efc645eSJason M. Bills     else if (cause ==
5853efc645eSJason M. Bills              "xyz.openbmc_project.State.Host.RestartCause.PowerPolicyAlwaysOn")
5863efc645eSJason M. Bills     {
5873efc645eSJason M. Bills         restartCauseValue = 0x6;
5883efc645eSJason M. Bills     }
5893efc645eSJason M. Bills     else if (cause == "xyz.openbmc_project.State.Host.RestartCause."
5903efc645eSJason M. Bills                       "PowerPolicyPreviousState")
5913efc645eSJason M. Bills     {
5923efc645eSJason M. Bills         restartCauseValue = 0x7;
5933efc645eSJason M. Bills     }
5943efc645eSJason M. Bills     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.PEFReset")
5953efc645eSJason M. Bills     {
5963efc645eSJason M. Bills         restartCauseValue = 0x8;
5973efc645eSJason M. Bills     }
5983efc645eSJason M. Bills     else if (cause ==
5993efc645eSJason M. Bills              "xyz.openbmc_project.State.Host.RestartCause.PEFPowerCycle")
6003efc645eSJason M. Bills     {
6013efc645eSJason M. Bills         restartCauseValue = 0x9;
6023efc645eSJason M. Bills     }
6033efc645eSJason M. Bills     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.SoftReset")
6043efc645eSJason M. Bills     {
6053efc645eSJason M. Bills         restartCauseValue = 0xa;
6063efc645eSJason M. Bills     }
6073efc645eSJason M. Bills     else if (cause == "xyz.openbmc_project.State.Host.RestartCause.RTCWakeup")
6083efc645eSJason M. Bills     {
6093efc645eSJason M. Bills         restartCauseValue = 0xb;
6103efc645eSJason M. Bills     }
6113efc645eSJason M. Bills     return restartCauseValue;
6123efc645eSJason M. Bills }
6133efc645eSJason M. Bills 
6143efc645eSJason M. Bills ipmi::RspType<uint4_t, // Restart Cause
6153efc645eSJason M. Bills               uint4_t, // reserved
6161b751dc2SVernon Mauery               uint8_t  // channel number
6173efc645eSJason M. Bills               >
ipmiGetSystemRestartCause(ipmi::Context::ptr ctx)6181b751dc2SVernon Mauery     ipmiGetSystemRestartCause(ipmi::Context::ptr ctx)
6193efc645eSJason M. Bills {
6203efc645eSJason M. Bills     std::string restartCauseStr;
6211b751dc2SVernon Mauery     if (!getRestartCause(ctx, restartCauseStr))
6223efc645eSJason M. Bills     {
6233efc645eSJason M. Bills         return ipmi::responseUnspecifiedError();
6243efc645eSJason M. Bills     }
6251b751dc2SVernon Mauery     constexpr uint4_t reserved = 0;
6261b751dc2SVernon Mauery     auto channel = static_cast<uint8_t>(ctx->channel);
6271b751dc2SVernon Mauery     return ipmi::responseSuccess(getRestartCauseValue(restartCauseStr),
6281b751dc2SVernon Mauery                                  reserved, channel);
6293efc645eSJason M. Bills }
6303efc645eSJason M. Bills 
ipmiSetFrontPanelButtonEnables(bool disablePowerButton,bool disableResetButton,bool disableInterruptButton,bool disableSleepButton,uint4_t reserved)631dcff1506SVernon Mauery ipmi::RspType<> ipmiSetFrontPanelButtonEnables(
632dcff1506SVernon Mauery     bool disablePowerButton, bool disableResetButton,
633dcff1506SVernon Mauery     bool disableInterruptButton, [[maybe_unused]] bool disableSleepButton,
634b08f84e3SJason M. Bills     uint4_t reserved)
635b08f84e3SJason M. Bills {
6363ff6371bSsunitakx     if (reserved)
6373ff6371bSsunitakx     {
6383ff6371bSsunitakx         return ipmi::responseInvalidFieldRequest();
6393ff6371bSsunitakx     }
640b08f84e3SJason M. Bills     bool error = false;
641b08f84e3SJason M. Bills 
642b08f84e3SJason M. Bills     error |= setButtonEnabled(powerButtonPath, disablePowerButton);
643b08f84e3SJason M. Bills     error |= setButtonEnabled(resetButtonPath, disableResetButton);
644b08f84e3SJason M. Bills     error |= setButtonEnabled(interruptButtonPath, disableInterruptButton);
645b08f84e3SJason M. Bills 
646b08f84e3SJason M. Bills     if (error)
647b08f84e3SJason M. Bills     {
648b08f84e3SJason M. Bills         return ipmi::responseUnspecifiedError();
649b08f84e3SJason M. Bills     }
6503ff6371bSsunitakx 
651b08f84e3SJason M. Bills     return ipmi::responseSuccess();
652b08f84e3SJason M. Bills }
653b08f84e3SJason M. Bills 
registerChassisFunctions(void)65460e7aaf5SYuan Li static void registerChassisFunctions(void)
65560e7aaf5SYuan Li {
656b08f84e3SJason M. Bills     log<level::INFO>("Registering Chassis commands");
65760e7aaf5SYuan Li 
65860e7aaf5SYuan Li     createIdentifyTimer();
65960e7aaf5SYuan Li 
66060e7aaf5SYuan Li     if (matchPtr == nullptr)
66160e7aaf5SYuan Li     {
66260e7aaf5SYuan Li         using namespace sdbusplus::bus::match::rules;
66360e7aaf5SYuan Li         auto bus = getSdBus();
66460e7aaf5SYuan Li 
66560e7aaf5SYuan Li         matchPtr = std::make_unique<sdbusplus::bus::match_t>(
66660e7aaf5SYuan Li             *bus,
66760e7aaf5SYuan Li             sdbusplus::bus::match::rules::propertiesChanged(idButtonPath,
668b08f84e3SJason M. Bills                                                             buttonIntf),
66960e7aaf5SYuan Li             std::bind(idButtonPropChanged, std::placeholders::_1));
67060e7aaf5SYuan Li     }
67160e7aaf5SYuan Li 
67260e7aaf5SYuan Li     // <Chassis Identify>
67360e7aaf5SYuan Li     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
67460e7aaf5SYuan Li                           ipmi::chassis::cmdChassisIdentify,
67560e7aaf5SYuan Li                           ipmi::Privilege::Operator, ipmiChassisIdentify);
676b08f84e3SJason M. Bills     // <Get Chassis Status>
677b08f84e3SJason M. Bills     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
678b08f84e3SJason M. Bills                           ipmi::chassis::cmdGetChassisStatus,
679b08f84e3SJason M. Bills                           ipmi::Privilege::User, ipmiGetChassisStatus);
6803efc645eSJason M. Bills     // <Get System Restart Cause>
6813efc645eSJason M. Bills     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
6823efc645eSJason M. Bills                           ipmi::chassis::cmdGetSystemRestartCause,
6833efc645eSJason M. Bills                           ipmi::Privilege::User, ipmiGetSystemRestartCause);
684b08f84e3SJason M. Bills     // <Set Front Panel Enables>
685b08f84e3SJason M. Bills     ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
686b08f84e3SJason M. Bills                           ipmi::chassis::cmdSetFrontPanelButtonEnables,
68751acbdf0SAppaRao Puli                           ipmi::Privilege::Admin,
688b08f84e3SJason M. Bills                           ipmiSetFrontPanelButtonEnables);
68960e7aaf5SYuan Li }
69060e7aaf5SYuan Li 
691b08f84e3SJason M. Bills } // namespace ipmi::chassis
692