1*ac149a94SVishwanatha Subbanna #include <chrono>
2*ac149a94SVishwanatha Subbanna #include <phosphor-logging/log.hpp>
3*ac149a94SVishwanatha Subbanna #include <phosphor-logging/elog-errors.hpp>
4*ac149a94SVishwanatha Subbanna #include <xyz/openbmc_project/Common/error.hpp>
5*ac149a94SVishwanatha Subbanna #include <systemintfcmds.h>
6*ac149a94SVishwanatha Subbanna #include <utils.hpp>
7*ac149a94SVishwanatha Subbanna #include <config.h>
8*ac149a94SVishwanatha Subbanna #include <host-cmd-manager.hpp>
9*ac149a94SVishwanatha Subbanna 
10*ac149a94SVishwanatha Subbanna namespace phosphor
11*ac149a94SVishwanatha Subbanna {
12*ac149a94SVishwanatha Subbanna namespace host
13*ac149a94SVishwanatha Subbanna {
14*ac149a94SVishwanatha Subbanna namespace command
15*ac149a94SVishwanatha Subbanna {
16*ac149a94SVishwanatha Subbanna 
17*ac149a94SVishwanatha Subbanna constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
18*ac149a94SVishwanatha Subbanna constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
19*ac149a94SVishwanatha Subbanna constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
20*ac149a94SVishwanatha Subbanna 
21*ac149a94SVishwanatha Subbanna // For throwing exceptions
22*ac149a94SVishwanatha Subbanna using namespace phosphor::logging;
23*ac149a94SVishwanatha Subbanna using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
24*ac149a94SVishwanatha Subbanna                             Error::InternalFailure;
25*ac149a94SVishwanatha Subbanna 
26*ac149a94SVishwanatha Subbanna // Called as part of READ_MSG_DATA command
27*ac149a94SVishwanatha Subbanna IpmiCmdData Manager::getNextCommand()
28*ac149a94SVishwanatha Subbanna {
29*ac149a94SVishwanatha Subbanna     // Stop the timer. Don't have to Err failure doing so.
30*ac149a94SVishwanatha Subbanna     auto r = timer.setTimer(SD_EVENT_OFF);
31*ac149a94SVishwanatha Subbanna     if (r < 0)
32*ac149a94SVishwanatha Subbanna     {
33*ac149a94SVishwanatha Subbanna         log<level::ERR>("Failure to STOP the timer",
34*ac149a94SVishwanatha Subbanna                 entry("ERROR=%s", strerror(-r)));
35*ac149a94SVishwanatha Subbanna     }
36*ac149a94SVishwanatha Subbanna 
37*ac149a94SVishwanatha Subbanna     if(this->workQueue.empty())
38*ac149a94SVishwanatha Subbanna     {
39*ac149a94SVishwanatha Subbanna         // Just return a heartbeat in this case.  A spurious SMS_ATN was
40*ac149a94SVishwanatha Subbanna         // asserted for the host (probably from a previous boot).
41*ac149a94SVishwanatha Subbanna         log<level::INFO>("Control Host work queue is empty!");
42*ac149a94SVishwanatha Subbanna 
43*ac149a94SVishwanatha Subbanna         return std::make_pair(CMD_HEARTBEAT, 0x00);
44*ac149a94SVishwanatha Subbanna     }
45*ac149a94SVishwanatha Subbanna 
46*ac149a94SVishwanatha Subbanna     // Pop the processed entry off the queue
47*ac149a94SVishwanatha Subbanna     auto command = this->workQueue.front();
48*ac149a94SVishwanatha Subbanna     this->workQueue.pop();
49*ac149a94SVishwanatha Subbanna 
50*ac149a94SVishwanatha Subbanna     // IPMI command is the first element in pair
51*ac149a94SVishwanatha Subbanna     auto ipmiCmdData = std::get<0>(command);
52*ac149a94SVishwanatha Subbanna 
53*ac149a94SVishwanatha Subbanna     // Now, call the user registered functions so that
54*ac149a94SVishwanatha Subbanna     // implementation specific CommandComplete signals
55*ac149a94SVishwanatha Subbanna     // can be sent. `true` indicating Success.
56*ac149a94SVishwanatha Subbanna     std::get<CallBack>(command)(ipmiCmdData, true);
57*ac149a94SVishwanatha Subbanna 
58*ac149a94SVishwanatha Subbanna     // Check for another entry in the queue and kick it off
59*ac149a94SVishwanatha Subbanna     this->checkQueueAndAlertHost();
60*ac149a94SVishwanatha Subbanna 
61*ac149a94SVishwanatha Subbanna     // Tuple of command and data
62*ac149a94SVishwanatha Subbanna     return ipmiCmdData;
63*ac149a94SVishwanatha Subbanna }
64*ac149a94SVishwanatha Subbanna 
65*ac149a94SVishwanatha Subbanna // Called when initial timer goes off post sending SMS_ATN
66*ac149a94SVishwanatha Subbanna void Manager::hostTimeout()
67*ac149a94SVishwanatha Subbanna {
68*ac149a94SVishwanatha Subbanna     log<level::ERR>("Host control timeout hit!");
69*ac149a94SVishwanatha Subbanna 
70*ac149a94SVishwanatha Subbanna     // Dequeue all entries and send fail signal
71*ac149a94SVishwanatha Subbanna     while(!this->workQueue.empty())
72*ac149a94SVishwanatha Subbanna     {
73*ac149a94SVishwanatha Subbanna         auto command = this->workQueue.front();
74*ac149a94SVishwanatha Subbanna         this->workQueue.pop();
75*ac149a94SVishwanatha Subbanna 
76*ac149a94SVishwanatha Subbanna         // IPMI command is the first element in pair
77*ac149a94SVishwanatha Subbanna         auto ipmiCmdData = std::get<0>(command);
78*ac149a94SVishwanatha Subbanna 
79*ac149a94SVishwanatha Subbanna         // Call the implementation specific Command Failure.
80*ac149a94SVishwanatha Subbanna         // `false` indicating Failure
81*ac149a94SVishwanatha Subbanna         std::get<CallBack>(command)(ipmiCmdData, false);
82*ac149a94SVishwanatha Subbanna     }
83*ac149a94SVishwanatha Subbanna }
84*ac149a94SVishwanatha Subbanna 
85*ac149a94SVishwanatha Subbanna // Called for alerting the host
86*ac149a94SVishwanatha Subbanna void Manager::checkQueueAndAlertHost()
87*ac149a94SVishwanatha Subbanna {
88*ac149a94SVishwanatha Subbanna     if (this->workQueue.size() >= 1)
89*ac149a94SVishwanatha Subbanna     {
90*ac149a94SVishwanatha Subbanna         log<level::INFO>("Asserting SMS Attention");
91*ac149a94SVishwanatha Subbanna 
92*ac149a94SVishwanatha Subbanna         std::string IPMI_PATH("/org/openbmc/HostIpmi/1");
93*ac149a94SVishwanatha Subbanna         std::string IPMI_INTERFACE("org.openbmc.HostIpmi");
94*ac149a94SVishwanatha Subbanna 
95*ac149a94SVishwanatha Subbanna         auto host = ::ipmi::getService(this->bus,IPMI_INTERFACE,IPMI_PATH);
96*ac149a94SVishwanatha Subbanna 
97*ac149a94SVishwanatha Subbanna         // Start the timer for this transaction
98*ac149a94SVishwanatha Subbanna         auto time = std::chrono::duration_cast<std::chrono::microseconds>(
99*ac149a94SVishwanatha Subbanna                         std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS));
100*ac149a94SVishwanatha Subbanna 
101*ac149a94SVishwanatha Subbanna         auto r = timer.startTimer(time);
102*ac149a94SVishwanatha Subbanna         if (r < 0)
103*ac149a94SVishwanatha Subbanna         {
104*ac149a94SVishwanatha Subbanna             log<level::ERR>("Error starting timer for control host");
105*ac149a94SVishwanatha Subbanna             return;
106*ac149a94SVishwanatha Subbanna         }
107*ac149a94SVishwanatha Subbanna 
108*ac149a94SVishwanatha Subbanna         auto method = this->bus.new_method_call(host.c_str(),
109*ac149a94SVishwanatha Subbanna                                                 IPMI_PATH.c_str(),
110*ac149a94SVishwanatha Subbanna                                                 IPMI_INTERFACE.c_str(),
111*ac149a94SVishwanatha Subbanna                                                 "setAttention");
112*ac149a94SVishwanatha Subbanna         auto reply = this->bus.call(method);
113*ac149a94SVishwanatha Subbanna 
114*ac149a94SVishwanatha Subbanna         if (reply.is_method_error())
115*ac149a94SVishwanatha Subbanna         {
116*ac149a94SVishwanatha Subbanna             log<level::ERR>("Error in setting SMS attention");
117*ac149a94SVishwanatha Subbanna             elog<InternalFailure>();
118*ac149a94SVishwanatha Subbanna         }
119*ac149a94SVishwanatha Subbanna         log<level::INFO>("SMS Attention asserted");
120*ac149a94SVishwanatha Subbanna     }
121*ac149a94SVishwanatha Subbanna }
122*ac149a94SVishwanatha Subbanna 
123*ac149a94SVishwanatha Subbanna // Called by specific implementations that provide commands
124*ac149a94SVishwanatha Subbanna void Manager::execute(CommandHandler command)
125*ac149a94SVishwanatha Subbanna {
126*ac149a94SVishwanatha Subbanna     log<level::INFO>("Pushing cmd on to queue",
127*ac149a94SVishwanatha Subbanna             entry("COMMAND=%d", std::get<0>(command).first));
128*ac149a94SVishwanatha Subbanna 
129*ac149a94SVishwanatha Subbanna     this->workQueue.emplace(command);
130*ac149a94SVishwanatha Subbanna 
131*ac149a94SVishwanatha Subbanna     // Alert host if this is only command in queue otherwise host will
132*ac149a94SVishwanatha Subbanna     // be notified of next message after processing the current one
133*ac149a94SVishwanatha Subbanna     if (this->workQueue.size() == 1)
134*ac149a94SVishwanatha Subbanna     {
135*ac149a94SVishwanatha Subbanna         this->checkQueueAndAlertHost();
136*ac149a94SVishwanatha Subbanna     }
137*ac149a94SVishwanatha Subbanna     else
138*ac149a94SVishwanatha Subbanna     {
139*ac149a94SVishwanatha Subbanna         log<level::INFO>("Command in process, no attention");
140*ac149a94SVishwanatha Subbanna     }
141*ac149a94SVishwanatha Subbanna 
142*ac149a94SVishwanatha Subbanna     return;
143*ac149a94SVishwanatha Subbanna }
144*ac149a94SVishwanatha Subbanna 
145*ac149a94SVishwanatha Subbanna } // namespace command
146*ac149a94SVishwanatha Subbanna } // namespace host
147*ac149a94SVishwanatha Subbanna } // namepsace phosphor
148