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>
90b02be92SPatrick Venture #include <phosphor-logging/log.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 =
31*523e2d1bSWilly 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     {
52ac149a94SVishwanatha Subbanna         log<level::ERR>("Failure to STOP the timer",
53ac149a94SVishwanatha Subbanna                         entry("ERROR=%s", strerror(-r)));
54ac149a94SVishwanatha Subbanna     }
55ac149a94SVishwanatha Subbanna 
56ac149a94SVishwanatha Subbanna     if (this->workQueue.empty())
57ac149a94SVishwanatha Subbanna     {
58ac149a94SVishwanatha Subbanna         // Just return a heartbeat in this case.  A spurious SMS_ATN was
59ac149a94SVishwanatha Subbanna         // asserted for the host (probably from a previous boot).
605fb14603SAditya Saripalli         log<level::DEBUG>("Control Host work queue is empty!");
61ac149a94SVishwanatha Subbanna 
62ac149a94SVishwanatha Subbanna         return std::make_pair(CMD_HEARTBEAT, 0x00);
63ac149a94SVishwanatha Subbanna     }
64ac149a94SVishwanatha Subbanna 
65ac149a94SVishwanatha Subbanna     // Pop the processed entry off the queue
66ac149a94SVishwanatha Subbanna     auto command = this->workQueue.front();
67ac149a94SVishwanatha Subbanna     this->workQueue.pop();
68ac149a94SVishwanatha Subbanna 
69ac149a94SVishwanatha Subbanna     // IPMI command is the first element in pair
70ac149a94SVishwanatha Subbanna     auto ipmiCmdData = std::get<0>(command);
71ac149a94SVishwanatha Subbanna 
72ac149a94SVishwanatha Subbanna     // Now, call the user registered functions so that
73ac149a94SVishwanatha Subbanna     // implementation specific CommandComplete signals
74ac149a94SVishwanatha Subbanna     // can be sent. `true` indicating Success.
75ac149a94SVishwanatha Subbanna     std::get<CallBack>(command)(ipmiCmdData, true);
76ac149a94SVishwanatha Subbanna 
77ac149a94SVishwanatha Subbanna     // Check for another entry in the queue and kick it off
78ac149a94SVishwanatha Subbanna     this->checkQueueAndAlertHost();
79ac149a94SVishwanatha Subbanna 
80ac149a94SVishwanatha Subbanna     // Tuple of command and data
81ac149a94SVishwanatha Subbanna     return ipmiCmdData;
82ac149a94SVishwanatha Subbanna }
83ac149a94SVishwanatha Subbanna 
84ac149a94SVishwanatha Subbanna // Called when initial timer goes off post sending SMS_ATN
hostTimeout()85ac149a94SVishwanatha Subbanna void Manager::hostTimeout()
86ac149a94SVishwanatha Subbanna {
87ac149a94SVishwanatha Subbanna     log<level::ERR>("Host control timeout hit!");
88ac149a94SVishwanatha Subbanna 
8915309efcSMatt Spinler     clearQueue();
9015309efcSMatt Spinler }
9115309efcSMatt Spinler 
clearQueue()9215309efcSMatt Spinler void Manager::clearQueue()
9315309efcSMatt Spinler {
94ac149a94SVishwanatha Subbanna     // Dequeue all entries and send fail signal
95ac149a94SVishwanatha Subbanna     while (!this->workQueue.empty())
96ac149a94SVishwanatha Subbanna     {
97ac149a94SVishwanatha Subbanna         auto command = this->workQueue.front();
98ac149a94SVishwanatha Subbanna         this->workQueue.pop();
99ac149a94SVishwanatha Subbanna 
100ac149a94SVishwanatha Subbanna         // IPMI command is the first element in pair
101ac149a94SVishwanatha Subbanna         auto ipmiCmdData = std::get<0>(command);
102ac149a94SVishwanatha Subbanna 
103ac149a94SVishwanatha Subbanna         // Call the implementation specific Command Failure.
104ac149a94SVishwanatha Subbanna         // `false` indicating Failure
105ac149a94SVishwanatha Subbanna         std::get<CallBack>(command)(ipmiCmdData, false);
106ac149a94SVishwanatha Subbanna     }
107ac149a94SVishwanatha Subbanna }
108ac149a94SVishwanatha Subbanna 
109ac149a94SVishwanatha Subbanna // Called for alerting the host
checkQueueAndAlertHost()110ac149a94SVishwanatha Subbanna void Manager::checkQueueAndAlertHost()
111ac149a94SVishwanatha Subbanna {
112ac149a94SVishwanatha Subbanna     if (this->workQueue.size() >= 1)
113ac149a94SVishwanatha Subbanna     {
1145fb14603SAditya Saripalli         log<level::DEBUG>("Asserting SMS Attention");
115ac149a94SVishwanatha Subbanna 
116b18c8bc3SAndrew Geissler         std::string HOST_IPMI_SVC("org.openbmc.HostIpmi");
117ac149a94SVishwanatha Subbanna         std::string IPMI_PATH("/org/openbmc/HostIpmi/1");
118ac149a94SVishwanatha Subbanna         std::string IPMI_INTERFACE("org.openbmc.HostIpmi");
119ac149a94SVishwanatha Subbanna 
120ac149a94SVishwanatha Subbanna         // Start the timer for this transaction
121ac149a94SVishwanatha Subbanna         auto time = std::chrono::duration_cast<std::chrono::microseconds>(
122ac149a94SVishwanatha Subbanna             std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS));
123ac149a94SVishwanatha Subbanna 
1241181af74SVernon Mauery         auto r = timer.start(time);
125ac149a94SVishwanatha Subbanna         if (r < 0)
126ac149a94SVishwanatha Subbanna         {
127ac149a94SVishwanatha Subbanna             log<level::ERR>("Error starting timer for control host");
128ac149a94SVishwanatha Subbanna             return;
129ac149a94SVishwanatha Subbanna         }
130ac149a94SVishwanatha Subbanna 
1310b02be92SPatrick Venture         auto method =
132b18c8bc3SAndrew Geissler             this->bus.new_method_call(HOST_IPMI_SVC.c_str(), IPMI_PATH.c_str(),
1330b02be92SPatrick Venture                                       IPMI_INTERFACE.c_str(), "setAttention");
134897ae72fSThang Tran 
135897ae72fSThang Tran         try
136897ae72fSThang Tran         {
137ac149a94SVishwanatha Subbanna             auto reply = this->bus.call(method);
138ac149a94SVishwanatha Subbanna 
1395fb14603SAditya Saripalli             log<level::DEBUG>("SMS Attention asserted");
140ac149a94SVishwanatha Subbanna         }
1415d82f474SPatrick Williams         catch (sdbusplus::exception_t& e)
142897ae72fSThang Tran         {
143897ae72fSThang Tran             log<level::ERR>("Error when call setAttention method");
144897ae72fSThang Tran         }
145897ae72fSThang Tran     }
146ac149a94SVishwanatha Subbanna }
147ac149a94SVishwanatha Subbanna 
148ac149a94SVishwanatha Subbanna // Called by specific implementations that provide commands
execute(CommandHandler command)149ac149a94SVishwanatha Subbanna void Manager::execute(CommandHandler command)
150ac149a94SVishwanatha Subbanna {
1515fb14603SAditya Saripalli     log<level::DEBUG>("Pushing cmd on to queue",
152ac149a94SVishwanatha Subbanna                       entry("COMMAND=%d", std::get<0>(command).first));
153ac149a94SVishwanatha Subbanna 
154ac149a94SVishwanatha Subbanna     this->workQueue.emplace(command);
155ac149a94SVishwanatha Subbanna 
156ac149a94SVishwanatha Subbanna     // Alert host if this is only command in queue otherwise host will
157ac149a94SVishwanatha Subbanna     // be notified of next message after processing the current one
158ac149a94SVishwanatha Subbanna     if (this->workQueue.size() == 1)
159ac149a94SVishwanatha Subbanna     {
160ac149a94SVishwanatha Subbanna         this->checkQueueAndAlertHost();
161ac149a94SVishwanatha Subbanna     }
162ac149a94SVishwanatha Subbanna     else
163ac149a94SVishwanatha Subbanna     {
164ac149a94SVishwanatha Subbanna         log<level::INFO>("Command in process, no attention");
165ac149a94SVishwanatha Subbanna     }
166ac149a94SVishwanatha Subbanna 
167ac149a94SVishwanatha Subbanna     return;
168ac149a94SVishwanatha Subbanna }
169ac149a94SVishwanatha Subbanna 
clearQueueOnPowerOn(sdbusplus::message_t & msg)1705d82f474SPatrick Williams void Manager::clearQueueOnPowerOn(sdbusplus::message_t& msg)
17115309efcSMatt Spinler {
172*523e2d1bSWilly Tu     namespace server = sdbusplus::server::xyz::openbmc_project::state;
17315309efcSMatt Spinler 
17415309efcSMatt Spinler     ::ipmi::DbusInterface interface;
17515309efcSMatt Spinler     ::ipmi::PropertyMap properties;
17615309efcSMatt Spinler 
17715309efcSMatt Spinler     msg.read(interface, properties);
17815309efcSMatt Spinler 
17915309efcSMatt Spinler     if (properties.find(HOST_TRANS_PROP) == properties.end())
18015309efcSMatt Spinler     {
18115309efcSMatt Spinler         return;
18215309efcSMatt Spinler     }
18315309efcSMatt Spinler 
1844c008028SWilliam A. Kennington III     auto& requestedState =
185f442e119SVernon Mauery         std::get<std::string>(properties.at(HOST_TRANS_PROP));
18615309efcSMatt Spinler 
18715309efcSMatt Spinler     if (server::Host::convertTransitionFromString(requestedState) ==
18815309efcSMatt Spinler         server::Host::Transition::On)
18915309efcSMatt Spinler     {
19015309efcSMatt Spinler         clearQueue();
19115309efcSMatt Spinler     }
19215309efcSMatt Spinler }
19315309efcSMatt Spinler 
194ac149a94SVishwanatha Subbanna } // namespace command
195ac149a94SVishwanatha Subbanna } // namespace host
1960b02be92SPatrick Venture } // namespace phosphor
197