1 #include <chrono>
2 #include <phosphor-logging/log.hpp>
3 #include <utils.hpp>
4 #include <config.h>
5 #include "host-interface.hpp"
6 #include "elog-errors.hpp"
7 
8 namespace phosphor
9 {
10 namespace host
11 {
12 
13 constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
14 constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
15 constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
16 
17 using namespace phosphor::logging;
18 
19 // When you see base:: you know we're referencing our base class
20 namespace base = sdbusplus::xyz::openbmc_project::Control::server;
21 
22 base::Host::Command Host::getNextCommand()
23 {
24     // Stop the timer
25     auto r = timer.setTimer(SD_EVENT_OFF);
26     if (r < 0)
27     {
28         log<level::ERR>("Failure to STOP the timer",
29                 entry("ERROR=%s", strerror(-r)));
30     }
31 
32     if(this->workQueue.empty())
33     {
34         log<level::ERR>("Control Host work queue is empty!");
35         elog<xyz::openbmc_project::Control::Internal::Host::QueueEmpty>();
36     }
37 
38     // Pop the processed entry off the queue
39     Command command = this->workQueue.front();
40     this->workQueue.pop();
41 
42     // Issue command complete signal
43     this->commandComplete(command, Result::Success);
44 
45     // Check for another entry in the queue and kick it off
46     this->checkQueue();
47     return command;
48 }
49 
50 void Host::hostTimeout()
51 {
52     log<level::ERR>("Host control timeout hit!");
53     // Dequeue all entries and send fail signal
54     while(!this->workQueue.empty())
55     {
56         auto command = this->workQueue.front();
57         this->workQueue.pop();
58         this->commandComplete(command,Result::Failure);
59     }
60 }
61 
62 void Host::checkQueue()
63 {
64     if (this->workQueue.size() >= 1)
65     {
66         log<level::INFO>("Asserting SMS Attention");
67 
68         std::string IPMI_PATH("/org/openbmc/HostIpmi/1");
69         std::string IPMI_INTERFACE("org.openbmc.HostIpmi");
70 
71         auto host = ::ipmi::getService(this->bus,IPMI_INTERFACE,IPMI_PATH);
72 
73         // Start the timer for this transaction
74         auto time = std::chrono::duration_cast<std::chrono::microseconds>(
75                         std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS));
76         auto r = timer.startTimer(time);
77         if (r < 0)
78         {
79             log<level::ERR>("Error starting timer for control host");
80             return;
81         }
82 
83         auto method = this->bus.new_method_call(host.c_str(),
84                                                 IPMI_PATH.c_str(),
85                                                 IPMI_INTERFACE.c_str(),
86                                                 "setAttention");
87         auto reply = this->bus.call(method);
88 
89         if (reply.is_method_error())
90         {
91             log<level::ERR>("Error in setting SMS attention");
92             throw std::runtime_error("ERROR in call to setAttention");
93         }
94         log<level::INFO>("SMS Attention asserted");
95     }
96 }
97 
98 void Host::execute(base::Host::Command command)
99 {
100     log<level::INFO>("Pushing cmd on to queue",
101             entry("CONTROL_HOST_CMD=%s",
102                   convertForMessage(command)));
103 
104     this->workQueue.push(command);
105 
106     // Alert host if this is only command in queue otherwise host will
107     // be notified of next message after processing the current one
108     if (this->workQueue.size() == 1)
109     {
110         this->checkQueue();
111     }
112     else
113     {
114         log<level::INFO>("Command in process, no attention");
115     }
116 
117     return;
118 }
119 
120 } // namespace host
121 } // namepsace phosphor
122