blob: dabaf322d8f9975987f97e4be70f8bc7472df885 [file] [log] [blame]
Andrew Geissler758e3af2021-04-29 21:38:39 -05001
Patrick Venture46470a32018-09-07 19:26:25 -07002#include "config.h"
3
4#include "host-interface.hpp"
5
6#include "systemintfcmds.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07007
William A. Kennington III194375f2018-12-14 02:14:33 -08008#include <ipmid-host/cmd-utils.hpp>
9#include <ipmid-host/cmd.hpp>
Andrew Geissler758e3af2021-04-29 21:38:39 -050010#include <ipmid/api.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070011#include <ipmid/utils.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050012#include <phosphor-logging/log.hpp>
13
14#include <functional>
Andrew Geissler758e3af2021-04-29 21:38:39 -050015#include <memory>
16#include <optional>
Patrick Venture46470a32018-09-07 19:26:25 -070017
Andrew Geisslerdd2c6fd2017-03-16 15:53:20 -050018namespace phosphor
19{
20namespace host
21{
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053022namespace command
Andrew Geissler83159702017-04-03 13:31:13 -050023{
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053024
Andrew Geissler758e3af2021-04-29 21:38:39 -050025using namespace phosphor::logging;
26
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053027// When you see Base:: you know we're referencing our base class
28namespace Base = sdbusplus::xyz::openbmc_project::Control::server;
29
30// IPMI OEM command.
31// https://github.com/openbmc/openbmc/issues/2082 for handling
32// Non-OEM commands that need to send SMS_ATN
33using OEMCmd = uint8_t;
34
35// Map of IPMI OEM command to its equivalent interface command.
36// This is needed when invoking the callback handler to indicate
37// the status of the executed command.
38static const std::map<OEMCmd, Host::Command> intfCommand = {
Patrick Venture0b02be92018-08-31 11:55:55 -070039 {CMD_HEARTBEAT, Base::Host::Command::Heartbeat},
40 {CMD_POWER, Base::Host::Command::SoftOff}};
Andrew Geissler83159702017-04-03 13:31:13 -050041
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053042// Map of Interface command to its corresponding IPMI OEM command.
43// This is needed when pushing IPMI commands to command manager's
44// queue. The same pair will be returned when IPMI asks us
45// why a SMS_ATN was sent
46static const std::map<Host::Command, IpmiCmdData> ipmiCommand = {
Patrick Venture0b02be92018-08-31 11:55:55 -070047 {Base::Host::Command::Heartbeat, std::make_pair(CMD_HEARTBEAT, 0x00)},
48 {Base::Host::Command::SoftOff, std::make_pair(CMD_POWER, SOFT_OFF)}};
Andrew Geissler83159702017-04-03 13:31:13 -050049
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053050// Called at user request
51void Host::execute(Base::Host::Command command)
Andrew Geissler83159702017-04-03 13:31:13 -050052{
Patrick Venture0b02be92018-08-31 11:55:55 -070053 log<level::DEBUG>(
54 "Pushing cmd on to queue",
55 entry("CONTROL_HOST_CMD=%s", convertForMessage(command).c_str()));
Andrew Geissler0c07c322017-03-22 14:02:30 -050056
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053057 auto cmd = std::make_tuple(ipmiCommand.at(command),
Patrick Venture0b02be92018-08-31 11:55:55 -070058 std::bind(&Host::commandStatusHandler, this,
59 std::placeholders::_1,
60 std::placeholders::_2));
Andrew Geissler0c07c322017-03-22 14:02:30 -050061
Chen,Yugang0e862fa2019-09-06 11:03:05 +080062 ipmid_send_cmd_to_host(std::move(cmd));
Andrew Geissler62817fa92017-03-20 14:20:49 -050063}
64
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053065// Called into by Command Manager
66void Host::commandStatusHandler(IpmiCmdData cmd, bool status)
67{
68 // Need to convert <cmd> to the equivalent one mentioned in spec
69 auto value = status ? Result::Success : Result::Failure;
70
71 // Fire a signal
72 this->commandComplete(intfCommand.at(std::get<0>(cmd)), value);
73}
74
Andrew Geisslerc7021b82021-04-28 15:22:35 -050075Host::FirmwareCondition Host::currentFirmwareCondition() const
76{
Andrew Geissler758e3af2021-04-29 21:38:39 -050077 // shared object used to wait for host response
78 auto hostCondition =
79 std::make_shared<std::optional<Host::FirmwareCondition>>();
80
81 // callback for command to host
Willy Tu11d68892022-01-20 10:37:34 -080082 auto hostAckCallback = [hostCondition](IpmiCmdData, bool status) {
Andrew Geissler758e3af2021-04-29 21:38:39 -050083 auto value = status ? Host::FirmwareCondition::Running
84 : Host::FirmwareCondition::Off;
85
86 log<level::DEBUG>("currentFirmwareCondition:hostAckCallback fired",
87 entry("CONTROL_HOST_CMD=%i", value));
88
89 *(hostCondition.get()) = value;
90 return;
91 };
92
93 auto cmd = phosphor::host::command::CommandHandler(
94 ipmiCommand.at(Base::Host::Command::Heartbeat),
95 std::move(hostAckCallback));
96
97 ipmid_send_cmd_to_host(std::move(cmd));
98
99 // Timer to ensure this function returns something within a reasonable time
100 phosphor::Timer hostAckTimer([hostCondition]() {
101 log<level::DEBUG>("currentFirmwareCondition: timer expired!");
102 *(hostCondition.get()) = Host::FirmwareCondition::Off;
103 });
104
105 // Wait 1 second past the ATN_ACK timeout to ensure we wait for as
106 // long as the timeout
107 hostAckTimer.start(std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS + 1));
108
109 auto io = getIoContext();
110
111 while (!hostCondition.get()->has_value())
112 {
113 log<level::DEBUG>(
114 "currentFirmwareCondition: waiting for host response");
115 io->run_for(std::chrono::milliseconds(100));
116 }
117 hostAckTimer.stop();
118
119 log<level::DEBUG>("currentFirmwareCondition: hostCondition is ready!");
120 return hostCondition.get()->value();
Andrew Geisslerc7021b82021-04-28 15:22:35 -0500121}
122
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530123} // namespace command
Andrew Geisslerdd2c6fd2017-03-16 15:53:20 -0500124} // namespace host
Patrick Venture0b02be92018-08-31 11:55:55 -0700125} // namespace phosphor