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