xref: /openbmc/phosphor-host-ipmid/host-cmd-manager.cpp (revision 59d6dbb6791da26063783f759f685e55730ca150)
146470a38SPatrick Venture #include "config.h"
246470a38SPatrick Venture 
346470a38SPatrick Venture #include "host-cmd-manager.hpp"
446470a38SPatrick Venture 
546470a38SPatrick Venture #include "systemintfcmds.hpp"
60b02be92SPatrick Venture 
76a98fe7fSVernon Mauery #include <ipmid/utils.hpp>
8ac149a94SVishwanatha Subbanna #include <phosphor-logging/elog-errors.hpp>
9*59d6dbb6SGeorge Liu #include <phosphor-logging/lg2.hpp>
104c008028SWilliam A. Kennington III #include <sdbusplus/message/types.hpp>
111181af74SVernon Mauery #include <sdbusplus/timer.hpp>
12ac149a94SVishwanatha Subbanna #include <xyz/openbmc_project/Common/error.hpp>
1315309efcSMatt Spinler #include <xyz/openbmc_project/State/Host/server.hpp>
146e8979d2SVishwanatha Subbanna 
15fbc6c9d7SPatrick Williams #include <chrono>
16fbc6c9d7SPatrick Williams 
17ac149a94SVishwanatha Subbanna namespace phosphor
18ac149a94SVishwanatha Subbanna {
19ac149a94SVishwanatha Subbanna namespace host
20ac149a94SVishwanatha Subbanna {
21ac149a94SVishwanatha Subbanna namespace command
22ac149a94SVishwanatha Subbanna {
23ac149a94SVishwanatha Subbanna 
2415309efcSMatt Spinler constexpr auto HOST_STATE_PATH = "/xyz/openbmc_project/state/host0";
2515309efcSMatt Spinler constexpr auto HOST_STATE_INTERFACE = "xyz.openbmc_project.State.Host";
2615309efcSMatt Spinler constexpr auto HOST_TRANS_PROP = "RequestedHostTransition";
27ac149a94SVishwanatha Subbanna 
28ac149a94SVishwanatha Subbanna // For throwing exceptions
29ac149a94SVishwanatha Subbanna using namespace phosphor::logging;
300b02be92SPatrick Venture using InternalFailure =
31523e2d1bSWilly Tu     sdbusplus::error::xyz::openbmc_project::common::InternalFailure;
32ac149a94SVishwanatha Subbanna 
3315309efcSMatt Spinler namespace sdbusRule = sdbusplus::bus::match::rules;
3415309efcSMatt Spinler 
Manager(sdbusplus::bus_t & bus)355d82f474SPatrick Williams Manager::Manager(sdbusplus::bus_t& bus) :
36316f23d9SVernon Mauery     bus(bus), timer(std::bind(&Manager::hostTimeout, this)),
370b02be92SPatrick Venture     hostTransitionMatch(
380b02be92SPatrick Venture         bus,
390b02be92SPatrick Venture         sdbusRule::propertiesChanged(HOST_STATE_PATH, HOST_STATE_INTERFACE),
400b02be92SPatrick Venture         std::bind(&Manager::clearQueueOnPowerOn, this, std::placeholders::_1))
416e8979d2SVishwanatha Subbanna {
426e8979d2SVishwanatha Subbanna     // Nothing to do here.
436e8979d2SVishwanatha Subbanna }
446e8979d2SVishwanatha Subbanna 
45ac149a94SVishwanatha Subbanna // Called as part of READ_MSG_DATA command
getNextCommand()46ac149a94SVishwanatha Subbanna IpmiCmdData Manager::getNextCommand()
47ac149a94SVishwanatha Subbanna {
48ac149a94SVishwanatha Subbanna     // Stop the timer. Don't have to Err failure doing so.
491181af74SVernon Mauery     auto r = timer.stop();
50ac149a94SVishwanatha Subbanna     if (r < 0)
51ac149a94SVishwanatha Subbanna     {
52*59d6dbb6SGeorge Liu         lg2::error("Failure to STOP the timer: {ERROR}", "ERROR", strerror(-r));
53ac149a94SVishwanatha Subbanna     }
54ac149a94SVishwanatha Subbanna 
55ac149a94SVishwanatha Subbanna     if (this->workQueue.empty())
56ac149a94SVishwanatha Subbanna     {
57ac149a94SVishwanatha Subbanna         // Just return a heartbeat in this case.  A spurious SMS_ATN was
58ac149a94SVishwanatha Subbanna         // asserted for the host (probably from a previous boot).
59*59d6dbb6SGeorge Liu         lg2::debug("Control Host work queue is empty!");
60ac149a94SVishwanatha Subbanna 
61ac149a94SVishwanatha Subbanna         return std::make_pair(CMD_HEARTBEAT, 0x00);
62ac149a94SVishwanatha Subbanna     }
63ac149a94SVishwanatha Subbanna 
64ac149a94SVishwanatha Subbanna     // Pop the processed entry off the queue
65ac149a94SVishwanatha Subbanna     auto command = this->workQueue.front();
66ac149a94SVishwanatha Subbanna     this->workQueue.pop();
67ac149a94SVishwanatha Subbanna 
68ac149a94SVishwanatha Subbanna     // IPMI command is the first element in pair
69ac149a94SVishwanatha Subbanna     auto ipmiCmdData = std::get<0>(command);
70ac149a94SVishwanatha Subbanna 
71ac149a94SVishwanatha Subbanna     // Now, call the user registered functions so that
72ac149a94SVishwanatha Subbanna     // implementation specific CommandComplete signals
73ac149a94SVishwanatha Subbanna     // can be sent. `true` indicating Success.
74ac149a94SVishwanatha Subbanna     std::get<CallBack>(command)(ipmiCmdData, true);
75ac149a94SVishwanatha Subbanna 
76ac149a94SVishwanatha Subbanna     // Check for another entry in the queue and kick it off
77ac149a94SVishwanatha Subbanna     this->checkQueueAndAlertHost();
78ac149a94SVishwanatha Subbanna 
79ac149a94SVishwanatha Subbanna     // Tuple of command and data
80ac149a94SVishwanatha Subbanna     return ipmiCmdData;
81ac149a94SVishwanatha Subbanna }
82ac149a94SVishwanatha Subbanna 
83ac149a94SVishwanatha Subbanna // Called when initial timer goes off post sending SMS_ATN
hostTimeout()84ac149a94SVishwanatha Subbanna void Manager::hostTimeout()
85ac149a94SVishwanatha Subbanna {
86*59d6dbb6SGeorge Liu     lg2::error("Host control timeout hit!");
87ac149a94SVishwanatha Subbanna 
8815309efcSMatt Spinler     clearQueue();
8915309efcSMatt Spinler }
9015309efcSMatt Spinler 
clearQueue()9115309efcSMatt Spinler void Manager::clearQueue()
9215309efcSMatt Spinler {
93ac149a94SVishwanatha Subbanna     // Dequeue all entries and send fail signal
94ac149a94SVishwanatha Subbanna     while (!this->workQueue.empty())
95ac149a94SVishwanatha Subbanna     {
96ac149a94SVishwanatha Subbanna         auto command = this->workQueue.front();
97ac149a94SVishwanatha Subbanna         this->workQueue.pop();
98ac149a94SVishwanatha Subbanna 
99ac149a94SVishwanatha Subbanna         // IPMI command is the first element in pair
100ac149a94SVishwanatha Subbanna         auto ipmiCmdData = std::get<0>(command);
101ac149a94SVishwanatha Subbanna 
102ac149a94SVishwanatha Subbanna         // Call the implementation specific Command Failure.
103ac149a94SVishwanatha Subbanna         // `false` indicating Failure
104ac149a94SVishwanatha Subbanna         std::get<CallBack>(command)(ipmiCmdData, false);
105ac149a94SVishwanatha Subbanna     }
106ac149a94SVishwanatha Subbanna }
107ac149a94SVishwanatha Subbanna 
108ac149a94SVishwanatha Subbanna // Called for alerting the host
checkQueueAndAlertHost()109ac149a94SVishwanatha Subbanna void Manager::checkQueueAndAlertHost()
110ac149a94SVishwanatha Subbanna {
111ac149a94SVishwanatha Subbanna     if (this->workQueue.size() >= 1)
112ac149a94SVishwanatha Subbanna     {
113*59d6dbb6SGeorge Liu         lg2::debug("Asserting SMS Attention");
114ac149a94SVishwanatha Subbanna 
115b18c8bc3SAndrew Geissler         std::string HOST_IPMI_SVC("org.openbmc.HostIpmi");
116ac149a94SVishwanatha Subbanna         std::string IPMI_PATH("/org/openbmc/HostIpmi/1");
117ac149a94SVishwanatha Subbanna         std::string IPMI_INTERFACE("org.openbmc.HostIpmi");
118ac149a94SVishwanatha Subbanna 
119ac149a94SVishwanatha Subbanna         // Start the timer for this transaction
120ac149a94SVishwanatha Subbanna         auto time = std::chrono::duration_cast<std::chrono::microseconds>(
121ac149a94SVishwanatha Subbanna             std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS));
122ac149a94SVishwanatha Subbanna 
1231181af74SVernon Mauery         auto r = timer.start(time);
124ac149a94SVishwanatha Subbanna         if (r < 0)
125ac149a94SVishwanatha Subbanna         {
126*59d6dbb6SGeorge Liu             lg2::error("Error starting timer for control host");
127ac149a94SVishwanatha Subbanna             return;
128ac149a94SVishwanatha Subbanna         }
129ac149a94SVishwanatha Subbanna 
1300b02be92SPatrick Venture         auto method =
131b18c8bc3SAndrew Geissler             this->bus.new_method_call(HOST_IPMI_SVC.c_str(), IPMI_PATH.c_str(),
1320b02be92SPatrick Venture                                       IPMI_INTERFACE.c_str(), "setAttention");
133897ae72fSThang Tran 
134897ae72fSThang Tran         try
135897ae72fSThang Tran         {
136ac149a94SVishwanatha Subbanna             auto reply = this->bus.call(method);
137ac149a94SVishwanatha Subbanna 
138*59d6dbb6SGeorge Liu             lg2::debug("SMS Attention asserted");
139ac149a94SVishwanatha Subbanna         }
1405d82f474SPatrick Williams         catch (sdbusplus::exception_t& e)
141897ae72fSThang Tran         {
142*59d6dbb6SGeorge Liu             lg2::error("Error when call setAttention method");
143897ae72fSThang Tran         }
144897ae72fSThang Tran     }
145ac149a94SVishwanatha Subbanna }
146ac149a94SVishwanatha Subbanna 
147ac149a94SVishwanatha Subbanna // Called by specific implementations that provide commands
execute(CommandHandler command)148ac149a94SVishwanatha Subbanna void Manager::execute(CommandHandler command)
149ac149a94SVishwanatha Subbanna {
150*59d6dbb6SGeorge Liu     lg2::debug("Pushing cmd on to queue, command: {COMMAND}", "COMMAND",
151*59d6dbb6SGeorge Liu                std::get<0>(command).first);
152ac149a94SVishwanatha Subbanna 
153ac149a94SVishwanatha Subbanna     this->workQueue.emplace(command);
154ac149a94SVishwanatha Subbanna 
155ac149a94SVishwanatha Subbanna     // Alert host if this is only command in queue otherwise host will
156ac149a94SVishwanatha Subbanna     // be notified of next message after processing the current one
157ac149a94SVishwanatha Subbanna     if (this->workQueue.size() == 1)
158ac149a94SVishwanatha Subbanna     {
159ac149a94SVishwanatha Subbanna         this->checkQueueAndAlertHost();
160ac149a94SVishwanatha Subbanna     }
161ac149a94SVishwanatha Subbanna     else
162ac149a94SVishwanatha Subbanna     {
163*59d6dbb6SGeorge Liu         lg2::info("Command in process, no attention");
164ac149a94SVishwanatha Subbanna     }
165ac149a94SVishwanatha Subbanna 
166ac149a94SVishwanatha Subbanna     return;
167ac149a94SVishwanatha Subbanna }
168ac149a94SVishwanatha Subbanna 
clearQueueOnPowerOn(sdbusplus::message_t & msg)1695d82f474SPatrick Williams void Manager::clearQueueOnPowerOn(sdbusplus::message_t& msg)
17015309efcSMatt Spinler {
171523e2d1bSWilly Tu     namespace server = sdbusplus::server::xyz::openbmc_project::state;
17215309efcSMatt Spinler 
17315309efcSMatt Spinler     ::ipmi::DbusInterface interface;
17415309efcSMatt Spinler     ::ipmi::PropertyMap properties;
17515309efcSMatt Spinler 
17615309efcSMatt Spinler     msg.read(interface, properties);
17715309efcSMatt Spinler 
17815309efcSMatt Spinler     if (properties.find(HOST_TRANS_PROP) == properties.end())
17915309efcSMatt Spinler     {
18015309efcSMatt Spinler         return;
18115309efcSMatt Spinler     }
18215309efcSMatt Spinler 
1834c008028SWilliam A. Kennington III     auto& requestedState =
184f442e119SVernon Mauery         std::get<std::string>(properties.at(HOST_TRANS_PROP));
18515309efcSMatt Spinler 
18615309efcSMatt Spinler     if (server::Host::convertTransitionFromString(requestedState) ==
18715309efcSMatt Spinler         server::Host::Transition::On)
18815309efcSMatt Spinler     {
18915309efcSMatt Spinler         clearQueue();
19015309efcSMatt Spinler     }
19115309efcSMatt Spinler }
19215309efcSMatt Spinler 
193ac149a94SVishwanatha Subbanna } // namespace command
194ac149a94SVishwanatha Subbanna } // namespace host
1950b02be92SPatrick Venture } // namespace phosphor
196