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