146470a38SPatrick Venture #include "config.h"
246470a38SPatrick Venture 
346470a38SPatrick Venture #include "host-cmd-manager.hpp"
446470a38SPatrick Venture 
546470a38SPatrick Venture #include "systemintfcmds.hpp"
60b02be92SPatrick Venture 
7ac149a94SVishwanatha Subbanna #include <chrono>
8*6a98fe7fSVernon Mauery #include <ipmid/utils.hpp>
9ac149a94SVishwanatha Subbanna #include <phosphor-logging/elog-errors.hpp>
100b02be92SPatrick Venture #include <phosphor-logging/log.hpp>
114c008028SWilliam A. Kennington III #include <sdbusplus/message/types.hpp>
121181af74SVernon Mauery #include <sdbusplus/timer.hpp>
13ac149a94SVishwanatha Subbanna #include <xyz/openbmc_project/Common/error.hpp>
1415309efcSMatt Spinler #include <xyz/openbmc_project/State/Host/server.hpp>
156e8979d2SVishwanatha Subbanna 
16ac149a94SVishwanatha Subbanna namespace phosphor
17ac149a94SVishwanatha Subbanna {
18ac149a94SVishwanatha Subbanna namespace host
19ac149a94SVishwanatha Subbanna {
20ac149a94SVishwanatha Subbanna namespace command
21ac149a94SVishwanatha Subbanna {
22ac149a94SVishwanatha Subbanna 
23ac149a94SVishwanatha Subbanna constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
24ac149a94SVishwanatha Subbanna constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
25ac149a94SVishwanatha Subbanna constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
2615309efcSMatt Spinler constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
2715309efcSMatt Spinler constexpr auto HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host";
2815309efcSMatt Spinler constexpr auto HOST_TRANS_PROP = "RequestedHostTransition";
29ac149a94SVishwanatha Subbanna 
30ac149a94SVishwanatha Subbanna // For throwing exceptions
31ac149a94SVishwanatha Subbanna using namespace phosphor::logging;
320b02be92SPatrick Venture using InternalFailure =
330b02be92SPatrick Venture     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
34ac149a94SVishwanatha Subbanna 
3515309efcSMatt Spinler namespace sdbusRule = sdbusplus::bus::match::rules;
364c008028SWilliam A. Kennington III namespace variant_ns = sdbusplus::message::variant_ns;
3715309efcSMatt Spinler 
38316f23d9SVernon Mauery Manager::Manager(sdbusplus::bus::bus& bus) :
39316f23d9SVernon Mauery     bus(bus), timer(std::bind(&Manager::hostTimeout, this)),
400b02be92SPatrick Venture     hostTransitionMatch(
410b02be92SPatrick Venture         bus,
420b02be92SPatrick Venture         sdbusRule::propertiesChanged(HOST_STATE_PATH, HOST_STATE_INTERFACE),
430b02be92SPatrick Venture         std::bind(&Manager::clearQueueOnPowerOn, this, std::placeholders::_1))
446e8979d2SVishwanatha Subbanna {
456e8979d2SVishwanatha Subbanna     // Nothing to do here.
466e8979d2SVishwanatha Subbanna }
476e8979d2SVishwanatha Subbanna 
48ac149a94SVishwanatha Subbanna // Called as part of READ_MSG_DATA command
49ac149a94SVishwanatha Subbanna IpmiCmdData Manager::getNextCommand()
50ac149a94SVishwanatha Subbanna {
51ac149a94SVishwanatha Subbanna     // Stop the timer. Don't have to Err failure doing so.
521181af74SVernon Mauery     auto r = timer.stop();
53ac149a94SVishwanatha Subbanna     if (r < 0)
54ac149a94SVishwanatha Subbanna     {
55ac149a94SVishwanatha Subbanna         log<level::ERR>("Failure to STOP the timer",
56ac149a94SVishwanatha Subbanna                         entry("ERROR=%s", strerror(-r)));
57ac149a94SVishwanatha Subbanna     }
58ac149a94SVishwanatha Subbanna 
59ac149a94SVishwanatha Subbanna     if (this->workQueue.empty())
60ac149a94SVishwanatha Subbanna     {
61ac149a94SVishwanatha Subbanna         // Just return a heartbeat in this case.  A spurious SMS_ATN was
62ac149a94SVishwanatha Subbanna         // asserted for the host (probably from a previous boot).
635fb14603SAditya Saripalli         log<level::DEBUG>("Control Host work queue is empty!");
64ac149a94SVishwanatha Subbanna 
65ac149a94SVishwanatha Subbanna         return std::make_pair(CMD_HEARTBEAT, 0x00);
66ac149a94SVishwanatha Subbanna     }
67ac149a94SVishwanatha Subbanna 
68ac149a94SVishwanatha Subbanna     // Pop the processed entry off the queue
69ac149a94SVishwanatha Subbanna     auto command = this->workQueue.front();
70ac149a94SVishwanatha Subbanna     this->workQueue.pop();
71ac149a94SVishwanatha Subbanna 
72ac149a94SVishwanatha Subbanna     // IPMI command is the first element in pair
73ac149a94SVishwanatha Subbanna     auto ipmiCmdData = std::get<0>(command);
74ac149a94SVishwanatha Subbanna 
75ac149a94SVishwanatha Subbanna     // Now, call the user registered functions so that
76ac149a94SVishwanatha Subbanna     // implementation specific CommandComplete signals
77ac149a94SVishwanatha Subbanna     // can be sent. `true` indicating Success.
78ac149a94SVishwanatha Subbanna     std::get<CallBack>(command)(ipmiCmdData, true);
79ac149a94SVishwanatha Subbanna 
80ac149a94SVishwanatha Subbanna     // Check for another entry in the queue and kick it off
81ac149a94SVishwanatha Subbanna     this->checkQueueAndAlertHost();
82ac149a94SVishwanatha Subbanna 
83ac149a94SVishwanatha Subbanna     // Tuple of command and data
84ac149a94SVishwanatha Subbanna     return ipmiCmdData;
85ac149a94SVishwanatha Subbanna }
86ac149a94SVishwanatha Subbanna 
87ac149a94SVishwanatha Subbanna // Called when initial timer goes off post sending SMS_ATN
88ac149a94SVishwanatha Subbanna void Manager::hostTimeout()
89ac149a94SVishwanatha Subbanna {
90ac149a94SVishwanatha Subbanna     log<level::ERR>("Host control timeout hit!");
91ac149a94SVishwanatha Subbanna 
9215309efcSMatt Spinler     clearQueue();
9315309efcSMatt Spinler }
9415309efcSMatt Spinler 
9515309efcSMatt Spinler void Manager::clearQueue()
9615309efcSMatt Spinler {
97ac149a94SVishwanatha Subbanna     // Dequeue all entries and send fail signal
98ac149a94SVishwanatha Subbanna     while (!this->workQueue.empty())
99ac149a94SVishwanatha Subbanna     {
100ac149a94SVishwanatha Subbanna         auto command = this->workQueue.front();
101ac149a94SVishwanatha Subbanna         this->workQueue.pop();
102ac149a94SVishwanatha Subbanna 
103ac149a94SVishwanatha Subbanna         // IPMI command is the first element in pair
104ac149a94SVishwanatha Subbanna         auto ipmiCmdData = std::get<0>(command);
105ac149a94SVishwanatha Subbanna 
106ac149a94SVishwanatha Subbanna         // Call the implementation specific Command Failure.
107ac149a94SVishwanatha Subbanna         // `false` indicating Failure
108ac149a94SVishwanatha Subbanna         std::get<CallBack>(command)(ipmiCmdData, false);
109ac149a94SVishwanatha Subbanna     }
110ac149a94SVishwanatha Subbanna }
111ac149a94SVishwanatha Subbanna 
112ac149a94SVishwanatha Subbanna // Called for alerting the host
113ac149a94SVishwanatha Subbanna void Manager::checkQueueAndAlertHost()
114ac149a94SVishwanatha Subbanna {
115ac149a94SVishwanatha Subbanna     if (this->workQueue.size() >= 1)
116ac149a94SVishwanatha Subbanna     {
1175fb14603SAditya Saripalli         log<level::DEBUG>("Asserting SMS Attention");
118ac149a94SVishwanatha Subbanna 
119ac149a94SVishwanatha Subbanna         std::string IPMI_PATH("/org/openbmc/HostIpmi/1");
120ac149a94SVishwanatha Subbanna         std::string IPMI_INTERFACE("org.openbmc.HostIpmi");
121ac149a94SVishwanatha Subbanna 
122ac149a94SVishwanatha Subbanna         auto host = ::ipmi::getService(this->bus, IPMI_INTERFACE, IPMI_PATH);
123ac149a94SVishwanatha Subbanna 
124ac149a94SVishwanatha Subbanna         // Start the timer for this transaction
125ac149a94SVishwanatha Subbanna         auto time = std::chrono::duration_cast<std::chrono::microseconds>(
126ac149a94SVishwanatha Subbanna             std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS));
127ac149a94SVishwanatha Subbanna 
1281181af74SVernon Mauery         auto r = timer.start(time);
129ac149a94SVishwanatha Subbanna         if (r < 0)
130ac149a94SVishwanatha Subbanna         {
131ac149a94SVishwanatha Subbanna             log<level::ERR>("Error starting timer for control host");
132ac149a94SVishwanatha Subbanna             return;
133ac149a94SVishwanatha Subbanna         }
134ac149a94SVishwanatha Subbanna 
1350b02be92SPatrick Venture         auto method =
1360b02be92SPatrick Venture             this->bus.new_method_call(host.c_str(), IPMI_PATH.c_str(),
1370b02be92SPatrick Venture                                       IPMI_INTERFACE.c_str(), "setAttention");
138ac149a94SVishwanatha Subbanna         auto reply = this->bus.call(method);
139ac149a94SVishwanatha Subbanna 
140ac149a94SVishwanatha Subbanna         if (reply.is_method_error())
141ac149a94SVishwanatha Subbanna         {
142ac149a94SVishwanatha Subbanna             log<level::ERR>("Error in setting SMS attention");
143ac149a94SVishwanatha Subbanna             elog<InternalFailure>();
144ac149a94SVishwanatha Subbanna         }
1455fb14603SAditya Saripalli         log<level::DEBUG>("SMS Attention asserted");
146ac149a94SVishwanatha Subbanna     }
147ac149a94SVishwanatha Subbanna }
148ac149a94SVishwanatha Subbanna 
149ac149a94SVishwanatha Subbanna // Called by specific implementations that provide commands
150ac149a94SVishwanatha Subbanna void Manager::execute(CommandHandler command)
151ac149a94SVishwanatha Subbanna {
1525fb14603SAditya Saripalli     log<level::DEBUG>("Pushing cmd on to queue",
153ac149a94SVishwanatha Subbanna                       entry("COMMAND=%d", std::get<0>(command).first));
154ac149a94SVishwanatha Subbanna 
155ac149a94SVishwanatha Subbanna     this->workQueue.emplace(command);
156ac149a94SVishwanatha Subbanna 
157ac149a94SVishwanatha Subbanna     // Alert host if this is only command in queue otherwise host will
158ac149a94SVishwanatha Subbanna     // be notified of next message after processing the current one
159ac149a94SVishwanatha Subbanna     if (this->workQueue.size() == 1)
160ac149a94SVishwanatha Subbanna     {
161ac149a94SVishwanatha Subbanna         this->checkQueueAndAlertHost();
162ac149a94SVishwanatha Subbanna     }
163ac149a94SVishwanatha Subbanna     else
164ac149a94SVishwanatha Subbanna     {
165ac149a94SVishwanatha Subbanna         log<level::INFO>("Command in process, no attention");
166ac149a94SVishwanatha Subbanna     }
167ac149a94SVishwanatha Subbanna 
168ac149a94SVishwanatha Subbanna     return;
169ac149a94SVishwanatha Subbanna }
170ac149a94SVishwanatha Subbanna 
17115309efcSMatt Spinler void Manager::clearQueueOnPowerOn(sdbusplus::message::message& msg)
17215309efcSMatt Spinler {
17315309efcSMatt Spinler     namespace server = sdbusplus::xyz::openbmc_project::State::server;
17415309efcSMatt Spinler 
17515309efcSMatt Spinler     ::ipmi::DbusInterface interface;
17615309efcSMatt Spinler     ::ipmi::PropertyMap properties;
17715309efcSMatt Spinler 
17815309efcSMatt Spinler     msg.read(interface, properties);
17915309efcSMatt Spinler 
18015309efcSMatt Spinler     if (properties.find(HOST_TRANS_PROP) == properties.end())
18115309efcSMatt Spinler     {
18215309efcSMatt Spinler         return;
18315309efcSMatt Spinler     }
18415309efcSMatt Spinler 
1854c008028SWilliam A. Kennington III     auto& requestedState =
1864c008028SWilliam A. Kennington III         variant_ns::get<std::string>(properties.at(HOST_TRANS_PROP));
18715309efcSMatt Spinler 
18815309efcSMatt Spinler     if (server::Host::convertTransitionFromString(requestedState) ==
18915309efcSMatt Spinler         server::Host::Transition::On)
19015309efcSMatt Spinler     {
19115309efcSMatt Spinler         clearQueue();
19215309efcSMatt Spinler     }
19315309efcSMatt Spinler }
19415309efcSMatt Spinler 
195ac149a94SVishwanatha Subbanna } // namespace command
196ac149a94SVishwanatha Subbanna } // namespace host
1970b02be92SPatrick Venture } // namespace phosphor
198