blob: 4bbbb5534647102e848043d5d593c0f603d1abcf [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>
George Liu59d6dbb2024-07-17 20:20:32 +08009#include <phosphor-logging/lg2.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
Alexander Hansen76bfd752025-11-07 17:04:32 +010017using HostState = sdbusplus::common::xyz::openbmc_project::state::Host;
18
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053019namespace phosphor
20{
21namespace host
22{
23namespace command
24{
25
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053026// For throwing exceptions
27using namespace phosphor::logging;
Patrick Venture0b02be92018-08-31 11:55:55 -070028using InternalFailure =
Willy Tu523e2d12023-09-05 11:36:48 -070029 sdbusplus::error::xyz::openbmc_project::common::InternalFailure;
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053030
Matt Spinler15309ef2018-06-27 13:01:25 -050031namespace sdbusRule = sdbusplus::bus::match::rules;
32
Patrick Williams5d82f472022-07-22 19:26:53 -050033Manager::Manager(sdbusplus::bus_t& bus) :
Vernon Mauery316f23d2018-10-29 13:34:26 -070034 bus(bus), timer(std::bind(&Manager::hostTimeout, this)),
Patrick Venture0b02be92018-08-31 11:55:55 -070035 hostTransitionMatch(
36 bus,
Alexander Hansen76bfd752025-11-07 17:04:32 +010037 sdbusRule::propertiesChanged("/xyz/openbmc_project/state/host0",
38 HostState::interface),
Patrick Venture0b02be92018-08-31 11:55:55 -070039 std::bind(&Manager::clearQueueOnPowerOn, this, std::placeholders::_1))
Vishwanatha Subbanna6e8979d2017-07-13 16:48:20 +053040{
41 // Nothing to do here.
42}
43
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053044// Called as part of READ_MSG_DATA command
45IpmiCmdData Manager::getNextCommand()
46{
47 // Stop the timer. Don't have to Err failure doing so.
Vernon Mauery1181af72018-10-08 12:05:00 -070048 auto r = timer.stop();
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053049 if (r < 0)
50 {
George Liu59d6dbb2024-07-17 20:20:32 +080051 lg2::error("Failure to STOP the timer: {ERROR}", "ERROR", strerror(-r));
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053052 }
53
Patrick Venture0b02be92018-08-31 11:55:55 -070054 if (this->workQueue.empty())
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053055 {
56 // Just return a heartbeat in this case. A spurious SMS_ATN was
57 // asserted for the host (probably from a previous boot).
George Liu59d6dbb2024-07-17 20:20:32 +080058 lg2::debug("Control Host work queue is empty!");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053059
60 return std::make_pair(CMD_HEARTBEAT, 0x00);
61 }
62
63 // Pop the processed entry off the queue
64 auto command = this->workQueue.front();
65 this->workQueue.pop();
66
67 // IPMI command is the first element in pair
68 auto ipmiCmdData = std::get<0>(command);
69
70 // Now, call the user registered functions so that
71 // implementation specific CommandComplete signals
72 // can be sent. `true` indicating Success.
73 std::get<CallBack>(command)(ipmiCmdData, true);
74
75 // Check for another entry in the queue and kick it off
76 this->checkQueueAndAlertHost();
77
78 // Tuple of command and data
79 return ipmiCmdData;
80}
81
82// Called when initial timer goes off post sending SMS_ATN
83void Manager::hostTimeout()
84{
George Liu59d6dbb2024-07-17 20:20:32 +080085 lg2::error("Host control timeout hit!");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053086
Matt Spinler15309ef2018-06-27 13:01:25 -050087 clearQueue();
88}
89
90void Manager::clearQueue()
91{
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053092 // Dequeue all entries and send fail signal
Patrick Venture0b02be92018-08-31 11:55:55 -070093 while (!this->workQueue.empty())
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +053094 {
95 auto command = this->workQueue.front();
96 this->workQueue.pop();
97
98 // IPMI command is the first element in pair
99 auto ipmiCmdData = std::get<0>(command);
100
101 // Call the implementation specific Command Failure.
102 // `false` indicating Failure
103 std::get<CallBack>(command)(ipmiCmdData, false);
104 }
105}
106
107// Called for alerting the host
108void Manager::checkQueueAndAlertHost()
109{
110 if (this->workQueue.size() >= 1)
111 {
George Liu59d6dbb2024-07-17 20:20:32 +0800112 lg2::debug("Asserting SMS Attention");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530113
Andrew Geisslerb18c8bc2020-08-05 15:54:44 -0500114 std::string HOST_IPMI_SVC("org.openbmc.HostIpmi");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530115 std::string IPMI_PATH("/org/openbmc/HostIpmi/1");
116 std::string IPMI_INTERFACE("org.openbmc.HostIpmi");
117
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530118 // Start the timer for this transaction
119 auto time = std::chrono::duration_cast<std::chrono::microseconds>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700120 std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS));
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530121
Vernon Mauery1181af72018-10-08 12:05:00 -0700122 auto r = timer.start(time);
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530123 if (r < 0)
124 {
George Liu59d6dbb2024-07-17 20:20:32 +0800125 lg2::error("Error starting timer for control host");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530126 return;
127 }
128
Patrick Venture0b02be92018-08-31 11:55:55 -0700129 auto method =
Andrew Geisslerb18c8bc2020-08-05 15:54:44 -0500130 this->bus.new_method_call(HOST_IPMI_SVC.c_str(), IPMI_PATH.c_str(),
Patrick Venture0b02be92018-08-31 11:55:55 -0700131 IPMI_INTERFACE.c_str(), "setAttention");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530132
Thang Tran897ae722022-03-06 10:26:18 +0700133 try
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530134 {
Thang Tran897ae722022-03-06 10:26:18 +0700135 auto reply = this->bus.call(method);
136
George Liu59d6dbb2024-07-17 20:20:32 +0800137 lg2::debug("SMS Attention asserted");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530138 }
Patrick Williams5d82f472022-07-22 19:26:53 -0500139 catch (sdbusplus::exception_t& e)
Thang Tran897ae722022-03-06 10:26:18 +0700140 {
George Liu59d6dbb2024-07-17 20:20:32 +0800141 lg2::error("Error when call setAttention method");
Thang Tran897ae722022-03-06 10:26:18 +0700142 }
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530143 }
144}
145
146// Called by specific implementations that provide commands
147void Manager::execute(CommandHandler command)
148{
George Liu59d6dbb2024-07-17 20:20:32 +0800149 lg2::debug("Pushing cmd on to queue, command: {COMMAND}", "COMMAND",
150 std::get<0>(command).first);
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530151
152 this->workQueue.emplace(command);
153
154 // Alert host if this is only command in queue otherwise host will
155 // be notified of next message after processing the current one
156 if (this->workQueue.size() == 1)
157 {
158 this->checkQueueAndAlertHost();
159 }
160 else
161 {
George Liu59d6dbb2024-07-17 20:20:32 +0800162 lg2::info("Command in process, no attention");
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530163 }
164
165 return;
166}
167
Patrick Williams5d82f472022-07-22 19:26:53 -0500168void Manager::clearQueueOnPowerOn(sdbusplus::message_t& msg)
Matt Spinler15309ef2018-06-27 13:01:25 -0500169{
Willy Tu523e2d12023-09-05 11:36:48 -0700170 namespace server = sdbusplus::server::xyz::openbmc_project::state;
Matt Spinler15309ef2018-06-27 13:01:25 -0500171
172 ::ipmi::DbusInterface interface;
173 ::ipmi::PropertyMap properties;
174
175 msg.read(interface, properties);
176
Alexander Hansen76bfd752025-11-07 17:04:32 +0100177 if (properties.find(HostState::property_names::requested_host_transition) ==
178 properties.end())
Matt Spinler15309ef2018-06-27 13:01:25 -0500179 {
180 return;
181 }
182
Alexander Hansen76bfd752025-11-07 17:04:32 +0100183 auto& requestedState = std::get<std::string>(
184 properties.at(HostState::property_names::requested_host_transition));
Matt Spinler15309ef2018-06-27 13:01:25 -0500185
186 if (server::Host::convertTransitionFromString(requestedState) ==
Patrick Venture0b02be92018-08-31 11:55:55 -0700187 server::Host::Transition::On)
Matt Spinler15309ef2018-06-27 13:01:25 -0500188 {
189 clearQueue();
190 }
191}
192
Vishwanatha Subbannaac149a92017-07-11 18:16:50 +0530193} // namespace command
194} // namespace host
Patrick Venture0b02be92018-08-31 11:55:55 -0700195} // namespace phosphor