blob: c539aa2bedcc917db87ab54869f1a20a2a2f4084 [file] [log] [blame]
Patrick Venture46470a32018-09-07 19:26:25 -07001#include "config.h"
2
3#include "host-cmd-manager.hpp"
4
5#include "systemintfcmds.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07006
Vernon Mauery6a98fe72019-03-11 15:57:48 -07007#include <ipmid/utils.hpp>
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +05308#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -07009#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070010#include <sdbusplus/message/types.hpp>
Vernon Mauery1181af72018-10-08 12:05:00 -070011#include <sdbusplus/timer.hpp>
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053012#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinler15309ef2018-06-27 13:01:25 -050013#include <xyz/openbmc_project/State/Host/server.hpp>
Vishwanatha Subbanna6e8979d2017-07-13 16:48:20 +053014
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -050015#include <chrono>
16
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053017namespace phosphor
18{
19namespace host
20{
21namespace command
22{
23
Matt Spinler15309ef2018-06-27 13:01:25 -050024constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
25constexpr auto HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host";
26constexpr auto HOST_TRANS_PROP = "RequestedHostTransition";
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053027
28// For throwing exceptions
29using namespace phosphor::logging;
Patrick Venture0b02be92018-08-31 11:55:55 -070030using InternalFailure =
Willy Tu523e2d12023-09-05 11:36:48 -070031 sdbusplus::error::xyz::openbmc_project::common::InternalFailure;
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053032
Matt Spinler15309ef2018-06-27 13:01:25 -050033namespace sdbusRule = sdbusplus::bus::match::rules;
34
Patrick Williams5d82f472022-07-22 19:26:53 -050035Manager::Manager(sdbusplus::bus_t& bus) :
Vernon Mauery316f23d2018-10-29 13:34:26 -070036 bus(bus), timer(std::bind(&Manager::hostTimeout, this)),
Patrick Venture0b02be92018-08-31 11:55:55 -070037 hostTransitionMatch(
38 bus,
39 sdbusRule::propertiesChanged(HOST_STATE_PATH, HOST_STATE_INTERFACE),
40 std::bind(&Manager::clearQueueOnPowerOn, this, std::placeholders::_1))
Vishwanatha Subbanna6e8979d2017-07-13 16:48:20 +053041{
42 // Nothing to do here.
43}
44
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053045// Called as part of READ_MSG_DATA command
46IpmiCmdData Manager::getNextCommand()
47{
48 // Stop the timer. Don't have to Err failure doing so.
Vernon Mauery1181af72018-10-08 12:05:00 -070049 auto r = timer.stop();
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053050 if (r < 0)
51 {
52 log<level::ERR>("Failure to STOP the timer",
Patrick Venture0b02be92018-08-31 11:55:55 -070053 entry("ERROR=%s", strerror(-r)));
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053054 }
55
Patrick Venture0b02be92018-08-31 11:55:55 -070056 if (this->workQueue.empty())
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053057 {
58 // Just return a heartbeat in this case. A spurious SMS_ATN was
59 // asserted for the host (probably from a previous boot).
Aditya Saripalli5fb14602017-11-09 14:46:27 +053060 log<level::DEBUG>("Control Host work queue is empty!");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053061
62 return std::make_pair(CMD_HEARTBEAT, 0x00);
63 }
64
65 // Pop the processed entry off the queue
66 auto command = this->workQueue.front();
67 this->workQueue.pop();
68
69 // IPMI command is the first element in pair
70 auto ipmiCmdData = std::get<0>(command);
71
72 // Now, call the user registered functions so that
73 // implementation specific CommandComplete signals
74 // can be sent. `true` indicating Success.
75 std::get<CallBack>(command)(ipmiCmdData, true);
76
77 // Check for another entry in the queue and kick it off
78 this->checkQueueAndAlertHost();
79
80 // Tuple of command and data
81 return ipmiCmdData;
82}
83
84// Called when initial timer goes off post sending SMS_ATN
85void Manager::hostTimeout()
86{
87 log<level::ERR>("Host control timeout hit!");
88
Matt Spinler15309ef2018-06-27 13:01:25 -050089 clearQueue();
90}
91
92void Manager::clearQueue()
93{
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053094 // Dequeue all entries and send fail signal
Patrick Venture0b02be92018-08-31 11:55:55 -070095 while (!this->workQueue.empty())
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053096 {
97 auto command = this->workQueue.front();
98 this->workQueue.pop();
99
100 // IPMI command is the first element in pair
101 auto ipmiCmdData = std::get<0>(command);
102
103 // Call the implementation specific Command Failure.
104 // `false` indicating Failure
105 std::get<CallBack>(command)(ipmiCmdData, false);
106 }
107}
108
109// Called for alerting the host
110void Manager::checkQueueAndAlertHost()
111{
112 if (this->workQueue.size() >= 1)
113 {
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530114 log<level::DEBUG>("Asserting SMS Attention");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530115
Andrew Geisslerb18c8bc2020-08-05 15:54:44 -0500116 std::string HOST_IPMI_SVC("org.openbmc.HostIpmi");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530117 std::string IPMI_PATH("/org/openbmc/HostIpmi/1");
118 std::string IPMI_INTERFACE("org.openbmc.HostIpmi");
119
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530120 // Start the timer for this transaction
121 auto time = std::chrono::duration_cast<std::chrono::microseconds>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700122 std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS));
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530123
Vernon Mauery1181af72018-10-08 12:05:00 -0700124 auto r = timer.start(time);
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530125 if (r < 0)
126 {
127 log<level::ERR>("Error starting timer for control host");
128 return;
129 }
130
Patrick Venture0b02be92018-08-31 11:55:55 -0700131 auto method =
Andrew Geisslerb18c8bc2020-08-05 15:54:44 -0500132 this->bus.new_method_call(HOST_IPMI_SVC.c_str(), IPMI_PATH.c_str(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700133 IPMI_INTERFACE.c_str(), "setAttention");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530134
Thang Tran897ae722022-03-06 10:26:18 +0700135 try
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530136 {
Thang Tran897ae722022-03-06 10:26:18 +0700137 auto reply = this->bus.call(method);
138
139 log<level::DEBUG>("SMS Attention asserted");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530140 }
Patrick Williams5d82f472022-07-22 19:26:53 -0500141 catch (sdbusplus::exception_t& e)
Thang Tran897ae722022-03-06 10:26:18 +0700142 {
143 log<level::ERR>("Error when call setAttention method");
144 }
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530145 }
146}
147
148// Called by specific implementations that provide commands
149void Manager::execute(CommandHandler command)
150{
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530151 log<level::DEBUG>("Pushing cmd on to queue",
Patrick Venture0b02be92018-08-31 11:55:55 -0700152 entry("COMMAND=%d", std::get<0>(command).first));
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530153
154 this->workQueue.emplace(command);
155
156 // Alert host if this is only command in queue otherwise host will
157 // be notified of next message after processing the current one
158 if (this->workQueue.size() == 1)
159 {
160 this->checkQueueAndAlertHost();
161 }
162 else
163 {
164 log<level::INFO>("Command in process, no attention");
165 }
166
167 return;
168}
169
Patrick Williams5d82f472022-07-22 19:26:53 -0500170void Manager::clearQueueOnPowerOn(sdbusplus::message_t& msg)
Matt Spinler15309ef2018-06-27 13:01:25 -0500171{
Willy Tu523e2d12023-09-05 11:36:48 -0700172 namespace server = sdbusplus::server::xyz::openbmc_project::state;
Matt Spinler15309ef2018-06-27 13:01:25 -0500173
174 ::ipmi::DbusInterface interface;
175 ::ipmi::PropertyMap properties;
176
177 msg.read(interface, properties);
178
179 if (properties.find(HOST_TRANS_PROP) == properties.end())
180 {
181 return;
182 }
183
William A. Kennington III4c008022018-10-12 17:18:14 -0700184 auto& requestedState =
Vernon Maueryf442e112019-04-09 11:44:36 -0700185 std::get<std::string>(properties.at(HOST_TRANS_PROP));
Matt Spinler15309ef2018-06-27 13:01:25 -0500186
187 if (server::Host::convertTransitionFromString(requestedState) ==
Patrick Venture0b02be92018-08-31 11:55:55 -0700188 server::Host::Transition::On)
Matt Spinler15309ef2018-06-27 13:01:25 -0500189 {
190 clearQueue();
191 }
192}
193
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530194} // namespace command
195} // namespace host
Patrick Venture0b02be92018-08-31 11:55:55 -0700196} // namespace phosphor