1758e3af9SAndrew Geissler
246470a38SPatrick Venture #include "config.h"
346470a38SPatrick Venture
446470a38SPatrick Venture #include "host-interface.hpp"
546470a38SPatrick Venture
646470a38SPatrick Venture #include "systemintfcmds.hpp"
70b02be92SPatrick Venture
8194375f2SWilliam A. Kennington III #include <ipmid-host/cmd-utils.hpp>
9194375f2SWilliam A. Kennington III #include <ipmid-host/cmd.hpp>
10758e3af9SAndrew Geissler #include <ipmid/api.hpp>
116a98fe7fSVernon Mauery #include <ipmid/utils.hpp>
12ca424ae2SGeorge Liu #include <phosphor-logging/lg2.hpp>
13fbc6c9d7SPatrick Williams
14fbc6c9d7SPatrick Williams #include <functional>
15758e3af9SAndrew Geissler #include <memory>
16758e3af9SAndrew Geissler #include <optional>
1746470a38SPatrick Venture
18dd2c6fdcSAndrew Geissler namespace phosphor
19dd2c6fdcSAndrew Geissler {
20dd2c6fdcSAndrew Geissler namespace host
21dd2c6fdcSAndrew Geissler {
223eb117a3SVishwanatha Subbanna namespace command
233eb117a3SVishwanatha Subbanna {
24dd2c6fdcSAndrew Geissler
253eb117a3SVishwanatha Subbanna // When you see Base:: you know we're referencing our base class
26523e2d1bSWilly Tu namespace Base = sdbusplus::server::xyz::openbmc_project::control;
271b9d4e5cSAndrew Geissler
283eb117a3SVishwanatha Subbanna // IPMI OEM command.
293eb117a3SVishwanatha Subbanna // https://github.com/openbmc/openbmc/issues/2082 for handling
303eb117a3SVishwanatha Subbanna // Non-OEM commands that need to send SMS_ATN
313eb117a3SVishwanatha Subbanna using OEMCmd = uint8_t;
323eb117a3SVishwanatha Subbanna
333eb117a3SVishwanatha Subbanna // Map of IPMI OEM command to its equivalent interface command.
343eb117a3SVishwanatha Subbanna // This is needed when invoking the callback handler to indicate
353eb117a3SVishwanatha Subbanna // the status of the executed command.
363eb117a3SVishwanatha Subbanna static const std::map<OEMCmd, Host::Command> intfCommand = {
370b02be92SPatrick Venture {CMD_HEARTBEAT, Base::Host::Command::Heartbeat},
380b02be92SPatrick Venture {CMD_POWER, Base::Host::Command::SoftOff}};
393eb117a3SVishwanatha Subbanna
403eb117a3SVishwanatha Subbanna // Map of Interface command to its corresponding IPMI OEM command.
413eb117a3SVishwanatha Subbanna // This is needed when pushing IPMI commands to command manager's
423eb117a3SVishwanatha Subbanna // queue. The same pair will be returned when IPMI asks us
433eb117a3SVishwanatha Subbanna // why a SMS_ATN was sent
443eb117a3SVishwanatha Subbanna static const std::map<Host::Command, IpmiCmdData> ipmiCommand = {
450b02be92SPatrick Venture {Base::Host::Command::Heartbeat, std::make_pair(CMD_HEARTBEAT, 0x00)},
460b02be92SPatrick Venture {Base::Host::Command::SoftOff, std::make_pair(CMD_POWER, SOFT_OFF)}};
473eb117a3SVishwanatha Subbanna
483eb117a3SVishwanatha Subbanna // Called at user request
execute(Base::Host::Command command)493eb117a3SVishwanatha Subbanna void Host::execute(Base::Host::Command command)
503eb117a3SVishwanatha Subbanna {
51ca424ae2SGeorge Liu lg2::debug("Pushing cmd on to queue, control host cmd: {CONTROL_HOST_CMD}",
52ca424ae2SGeorge Liu "CONTROL_HOST_CMD", convertForMessage(command));
530c07c320SAndrew Geissler
54*1318a5edSPatrick Williams auto cmd = std::make_tuple(
55*1318a5edSPatrick Williams ipmiCommand.at(command),
56*1318a5edSPatrick Williams std::bind(&Host::commandStatusHandler, this, std::placeholders::_1,
573eb117a3SVishwanatha Subbanna std::placeholders::_2));
580c07c320SAndrew Geissler
590e862fabSChen,Yugang ipmid_send_cmd_to_host(std::move(cmd));
603eb117a3SVishwanatha Subbanna }
613eb117a3SVishwanatha Subbanna
623eb117a3SVishwanatha Subbanna // Called into by Command Manager
commandStatusHandler(IpmiCmdData cmd,bool status)633eb117a3SVishwanatha Subbanna void Host::commandStatusHandler(IpmiCmdData cmd, bool status)
640c07c320SAndrew Geissler {
653eb117a3SVishwanatha Subbanna // Need to convert <cmd> to the equivalent one mentioned in spec
663eb117a3SVishwanatha Subbanna auto value = status ? Result::Success : Result::Failure;
673eb117a3SVishwanatha Subbanna
683eb117a3SVishwanatha Subbanna // Fire a signal
693eb117a3SVishwanatha Subbanna this->commandComplete(intfCommand.at(std::get<0>(cmd)), value);
700c07c320SAndrew Geissler }
711b9d4e5cSAndrew Geissler
currentFirmwareCondition() const72c7021b86SAndrew Geissler Host::FirmwareCondition Host::currentFirmwareCondition() const
73c7021b86SAndrew Geissler {
74758e3af9SAndrew Geissler // shared object used to wait for host response
75758e3af9SAndrew Geissler auto hostCondition =
76758e3af9SAndrew Geissler std::make_shared<std::optional<Host::FirmwareCondition>>();
77758e3af9SAndrew Geissler
78758e3af9SAndrew Geissler // callback for command to host
7911d68897SWilly Tu auto hostAckCallback = [hostCondition](IpmiCmdData, bool status) {
80758e3af9SAndrew Geissler auto value = status ? Host::FirmwareCondition::Running
81758e3af9SAndrew Geissler : Host::FirmwareCondition::Off;
82758e3af9SAndrew Geissler
83ca424ae2SGeorge Liu lg2::debug("currentFirmwareCondition:hostAckCallback fired, "
84ca424ae2SGeorge Liu "control host cmd: {CONTROL_HOST_CMD}",
85ca424ae2SGeorge Liu "CONTROL_HOST_CMD", value);
86758e3af9SAndrew Geissler
87758e3af9SAndrew Geissler *(hostCondition.get()) = value;
88758e3af9SAndrew Geissler return;
89758e3af9SAndrew Geissler };
90758e3af9SAndrew Geissler
91758e3af9SAndrew Geissler auto cmd = phosphor::host::command::CommandHandler(
92758e3af9SAndrew Geissler ipmiCommand.at(Base::Host::Command::Heartbeat),
93758e3af9SAndrew Geissler std::move(hostAckCallback));
94758e3af9SAndrew Geissler
95758e3af9SAndrew Geissler ipmid_send_cmd_to_host(std::move(cmd));
96758e3af9SAndrew Geissler
97758e3af9SAndrew Geissler // Timer to ensure this function returns something within a reasonable time
9895655220SPatrick Williams sdbusplus::Timer hostAckTimer([hostCondition]() {
99ca424ae2SGeorge Liu lg2::debug("currentFirmwareCondition: timer expired!");
100758e3af9SAndrew Geissler *(hostCondition.get()) = Host::FirmwareCondition::Off;
101758e3af9SAndrew Geissler });
102758e3af9SAndrew Geissler
103758e3af9SAndrew Geissler // Wait 1 second past the ATN_ACK timeout to ensure we wait for as
104758e3af9SAndrew Geissler // long as the timeout
105758e3af9SAndrew Geissler hostAckTimer.start(std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS + 1));
106758e3af9SAndrew Geissler
107758e3af9SAndrew Geissler auto io = getIoContext();
108758e3af9SAndrew Geissler
109758e3af9SAndrew Geissler while (!hostCondition.get()->has_value())
110758e3af9SAndrew Geissler {
111ca424ae2SGeorge Liu lg2::debug("currentFirmwareCondition: waiting for host response");
112758e3af9SAndrew Geissler io->run_for(std::chrono::milliseconds(100));
113758e3af9SAndrew Geissler }
114758e3af9SAndrew Geissler hostAckTimer.stop();
115758e3af9SAndrew Geissler
116ca424ae2SGeorge Liu lg2::debug("currentFirmwareCondition: hostCondition is ready!");
117758e3af9SAndrew Geissler return hostCondition.get()->value();
118c7021b86SAndrew Geissler }
119c7021b86SAndrew Geissler
1203eb117a3SVishwanatha Subbanna } // namespace command
121dd2c6fdcSAndrew Geissler } // namespace host
1220b02be92SPatrick Venture } // namespace phosphor
123