blob: e413fb7c6b5c827c31f7327bee902a3f85feee4e [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
8#include <functional>
William A. Kennington III194375f2018-12-14 02:14:33 -08009#include <ipmid-host/cmd-utils.hpp>
10#include <ipmid-host/cmd.hpp>
Andrew Geissler758e3af2021-04-29 21:38:39 -050011#include <ipmid/api.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070012#include <ipmid/utils.hpp>
Andrew Geissler758e3af2021-04-29 21:38:39 -050013#include <memory>
14#include <optional>
Patrick Venture0b02be92018-08-31 11:55:55 -070015#include <phosphor-logging/log.hpp>
Patrick Venture46470a32018-09-07 19:26:25 -070016
Andrew Geisslerdd2c6fd2017-03-16 15:53:20 -050017namespace phosphor
18{
19namespace host
20{
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053021namespace command
Andrew Geissler83159702017-04-03 13:31:13 -050022{
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053023
Andrew Geissler758e3af2021-04-29 21:38:39 -050024using namespace phosphor::logging;
25
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053026// When you see Base:: you know we're referencing our base class
27namespace Base = sdbusplus::xyz::openbmc_project::Control::server;
28
29// IPMI OEM command.
30// https://github.com/openbmc/openbmc/issues/2082 for handling
31// Non-OEM commands that need to send SMS_ATN
32using OEMCmd = uint8_t;
33
34// Map of IPMI OEM command to its equivalent interface command.
35// This is needed when invoking the callback handler to indicate
36// the status of the executed command.
37static const std::map<OEMCmd, Host::Command> intfCommand = {
Patrick Venture0b02be92018-08-31 11:55:55 -070038 {CMD_HEARTBEAT, Base::Host::Command::Heartbeat},
39 {CMD_POWER, Base::Host::Command::SoftOff}};
Andrew Geissler83159702017-04-03 13:31:13 -050040
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053041// Map of Interface command to its corresponding IPMI OEM command.
42// This is needed when pushing IPMI commands to command manager's
43// queue. The same pair will be returned when IPMI asks us
44// why a SMS_ATN was sent
45static const std::map<Host::Command, IpmiCmdData> ipmiCommand = {
Patrick Venture0b02be92018-08-31 11:55:55 -070046 {Base::Host::Command::Heartbeat, std::make_pair(CMD_HEARTBEAT, 0x00)},
47 {Base::Host::Command::SoftOff, std::make_pair(CMD_POWER, SOFT_OFF)}};
Andrew Geissler83159702017-04-03 13:31:13 -050048
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053049// Called at user request
50void Host::execute(Base::Host::Command command)
Andrew Geissler83159702017-04-03 13:31:13 -050051{
Patrick Venture0b02be92018-08-31 11:55:55 -070052 log<level::DEBUG>(
53 "Pushing cmd on to queue",
54 entry("CONTROL_HOST_CMD=%s", convertForMessage(command).c_str()));
Andrew Geissler0c07c322017-03-22 14:02:30 -050055
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053056 auto cmd = std::make_tuple(ipmiCommand.at(command),
Patrick Venture0b02be92018-08-31 11:55:55 -070057 std::bind(&Host::commandStatusHandler, this,
58 std::placeholders::_1,
59 std::placeholders::_2));
Andrew Geissler0c07c322017-03-22 14:02:30 -050060
Chen,Yugang0e862fa2019-09-06 11:03:05 +080061 ipmid_send_cmd_to_host(std::move(cmd));
Andrew Geissler62817fa92017-03-20 14:20:49 -050062}
63
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +053064// Called into by Command Manager
65void Host::commandStatusHandler(IpmiCmdData cmd, bool status)
66{
67 // Need to convert <cmd> to the equivalent one mentioned in spec
68 auto value = status ? Result::Success : Result::Failure;
69
70 // Fire a signal
71 this->commandComplete(intfCommand.at(std::get<0>(cmd)), value);
72}
73
Andrew Geisslerc7021b82021-04-28 15:22:35 -050074Host::FirmwareCondition Host::currentFirmwareCondition() const
75{
Andrew Geissler758e3af2021-04-29 21:38:39 -050076 // shared object used to wait for host response
77 auto hostCondition =
78 std::make_shared<std::optional<Host::FirmwareCondition>>();
79
80 // callback for command to host
Willy Tu11d68892022-01-20 10:37:34 -080081 auto hostAckCallback = [hostCondition](IpmiCmdData, bool status) {
Andrew Geissler758e3af2021-04-29 21:38:39 -050082 auto value = status ? Host::FirmwareCondition::Running
83 : Host::FirmwareCondition::Off;
84
85 log<level::DEBUG>("currentFirmwareCondition:hostAckCallback fired",
86 entry("CONTROL_HOST_CMD=%i", value));
87
88 *(hostCondition.get()) = value;
89 return;
90 };
91
92 auto cmd = phosphor::host::command::CommandHandler(
93 ipmiCommand.at(Base::Host::Command::Heartbeat),
94 std::move(hostAckCallback));
95
96 ipmid_send_cmd_to_host(std::move(cmd));
97
98 // Timer to ensure this function returns something within a reasonable time
99 phosphor::Timer hostAckTimer([hostCondition]() {
100 log<level::DEBUG>("currentFirmwareCondition: timer expired!");
101 *(hostCondition.get()) = Host::FirmwareCondition::Off;
102 });
103
104 // Wait 1 second past the ATN_ACK timeout to ensure we wait for as
105 // long as the timeout
106 hostAckTimer.start(std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS + 1));
107
108 auto io = getIoContext();
109
110 while (!hostCondition.get()->has_value())
111 {
112 log<level::DEBUG>(
113 "currentFirmwareCondition: waiting for host response");
114 io->run_for(std::chrono::milliseconds(100));
115 }
116 hostAckTimer.stop();
117
118 log<level::DEBUG>("currentFirmwareCondition: hostCondition is ready!");
119 return hostCondition.get()->value();
Andrew Geisslerc7021b82021-04-28 15:22:35 -0500120}
121
Vishwanatha Subbanna3eb117a2017-07-12 16:13:49 +0530122} // namespace command
Andrew Geisslerdd2c6fd2017-03-16 15:53:20 -0500123} // namespace host
Patrick Venture0b02be92018-08-31 11:55:55 -0700124} // namespace phosphor