From 3eb117a322aca11f049bb05beea5eb2f6385cb8e Mon Sep 17 00:00:00 2001 From: Vishwanatha Subbanna Date: Wed, 12 Jul 2017 16:13:49 +0530 Subject: Use Host Command Manager in host interface implementation Change-Id: Icefce510a3a0022bf0288fa99518459b732a2e04 Signed-off-by: Vishwanatha Subbanna --- Makefile.am | 8 +-- configure.ac | 16 ++++-- host-cmd-manager.cpp | 1 - host-interface.cpp | 147 +++++++++++++++++++-------------------------------- host-interface.hpp | 66 +++++++++-------------- ipmid-host-cmd.hpp | 10 ++++ ipmid.cpp | 35 +++++++++++- softoff/softoff.cpp | 4 +- systemintfcmds.cpp | 60 ++++++++------------- timer.hpp | 1 + 10 files changed, 162 insertions(+), 186 deletions(-) create mode 100644 ipmid-host-cmd.hpp diff --git a/Makefile.am b/Makefile.am index ea44248..2f76317 100644 --- a/Makefile.am +++ b/Makefile.am @@ -75,18 +75,18 @@ libsysintfcmdsdir = ${libdir}/ipmid-providers libsysintfcmds_LTLIBRARIES = libsysintfcmds.la libsysintfcmds_la_SOURCES = \ systemintfcmds.cpp \ - host-interface.cpp \ - utils.cpp \ - timer.cpp + host-interface.cpp libsysintfcmds_la_LDFLAGS = $(SYSTEMD_LIBS) \ $(libmapper_LIBS) \ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \ $(PHOSPHOR_LOGGING_LIBS) \ + $(SDBUSPLUS_LIBS) \ -version-info 0:0:0 -shared libsysintfcmds_la_CXXFLAGS = $(SYSTEMD_CFLAGS) \ $(libmapper_CFLAGS) \ $(PHOSPHOR_DBUS_INTERFACES_CFLAGS) \ - $(PHOSPHOR_LOGGING_CFLAGS) + $(PHOSPHOR_LOGGING_CFLAGS) \ + $(SDBUSPLUS_CFLAGS) nobase_include_HEADERS = \ host-ipmid/ipmid-api.h diff --git a/configure.ac b/configure.ac index 9c909ea..dd6a194 100644 --- a/configure.ac +++ b/configure.ac @@ -133,11 +133,17 @@ AS_IF([test "x$CONTROL_HOST_BUSNAME" == "x"], [CONTROL_HOST_BUSNAME="xyz.openbmc_project.Control.Host"]) AC_DEFINE_UNQUOTED([CONTROL_HOST_BUSNAME], ["$CONTROL_HOST_BUSNAME"], [The Control Host Dbus busname to own]) -# Service dbus root -AC_ARG_VAR(CONTROL_HOST_OBJPATH, [The Control Host Dbus root]) -AS_IF([test "x$CONTROL_HOST_OBJPATH" == "x"], - [CONTROL_HOST_OBJPATH="/xyz/openbmc_project/control/host"]) -AC_DEFINE_UNQUOTED([CONTROL_HOST_OBJPATH], ["$CONTROL_HOST_OBJPATH"], [The Control Host Dbus root]) +# Host object name in the D-Bus +AC_ARG_VAR(HOST_NAME, [The Host name in the object path]) +AS_IF([test "x$HOST_NAME" == "x"], + [HOST_NAME="host"]) +AC_DEFINE_UNQUOTED([HOST_NAME], ["$HOST_NAME"], [The Host name in the object path]) + +# Service dbus object manager +AC_ARG_VAR(CONTROL_HOST_OBJ_MGR, [The Control Host D-Bus Object Manager]) +AS_IF([test "x$CONTROL_HOST_OBJ_MGR" == "x"], + [CONTROL_HOST_OBJ_MGR="/xyz/openbmc_project/control"]) +AC_DEFINE_UNQUOTED([CONTROL_HOST_OBJ_MGR], ["$CONTROL_HOST_OBJ_MGR"], [The Control Host D-Bus Object Manager]) # Create configured output AC_CONFIG_FILES([Makefile test/Makefile softoff/Makefile softoff/test/Makefile]) diff --git a/host-cmd-manager.cpp b/host-cmd-manager.cpp index 5b75b55..329e606 100644 --- a/host-cmd-manager.cpp +++ b/host-cmd-manager.cpp @@ -6,7 +6,6 @@ #include #include #include - namespace phosphor { namespace host diff --git a/host-interface.cpp b/host-interface.cpp index 0bce888..1de2629 100644 --- a/host-interface.cpp +++ b/host-interface.cpp @@ -1,122 +1,81 @@ -#include -#include +#include +#include +#include #include +#include #include -#include "host-interface.hpp" - +#include namespace phosphor { namespace host { +namespace command +{ -constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper"; -constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper"; -constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper"; - -using namespace phosphor::logging; +// When you see Base:: you know we're referencing our base class +namespace Base = sdbusplus::xyz::openbmc_project::Control::server; -// When you see base:: you know we're referencing our base class -namespace base = sdbusplus::xyz::openbmc_project::Control::server; +// IPMI OEM command. +// https://github.com/openbmc/openbmc/issues/2082 for handling +// Non-OEM commands that need to send SMS_ATN +using OEMCmd = uint8_t; -base::Host::Command Host::getNextCommand() -{ - // Stop the timer - auto r = timer.setTimer(SD_EVENT_OFF); - if (r < 0) +// Map of IPMI OEM command to its equivalent interface command. +// This is needed when invoking the callback handler to indicate +// the status of the executed command. +static const std::map intfCommand = { { - log("Failure to STOP the timer", - entry("ERROR=%s", strerror(-r))); - } - - if(this->workQueue.empty()) + CMD_HEARTBEAT, + Base::Host::Command::Heartbeat + }, { - // Just return a heartbeat in this case. A spurious SMS_ATN was - // asserted for the host (probably from a previous boot). - log("Control Host work queue is empty!"); - return (Command::Heartbeat); + CMD_POWER, + Base::Host::Command::SoftOff } +}; - // Pop the processed entry off the queue - Command command = this->workQueue.front(); - this->workQueue.pop(); - - // Issue command complete signal - this->commandComplete(command, Result::Success); - - // Check for another entry in the queue and kick it off - this->checkQueue(); - return command; -} - -void Host::hostTimeout() -{ - log("Host control timeout hit!"); - // Dequeue all entries and send fail signal - while(!this->workQueue.empty()) +// Map of Interface command to its corresponding IPMI OEM command. +// This is needed when pushing IPMI commands to command manager's +// queue. The same pair will be returned when IPMI asks us +// why a SMS_ATN was sent +static const std::map ipmiCommand = { { - auto command = this->workQueue.front(); - this->workQueue.pop(); - this->commandComplete(command,Result::Failure); - } -} - -void Host::checkQueue() -{ - if (this->workQueue.size() >= 1) + Base::Host::Command::Heartbeat, + std::make_pair(CMD_HEARTBEAT, 0x00) + }, { - log("Asserting SMS Attention"); - - std::string IPMI_PATH("/org/openbmc/HostIpmi/1"); - std::string IPMI_INTERFACE("org.openbmc.HostIpmi"); - - auto host = ::ipmi::getService(this->bus,IPMI_INTERFACE,IPMI_PATH); - - // Start the timer for this transaction - auto time = std::chrono::duration_cast( - std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS)); - auto r = timer.startTimer(time); - if (r < 0) - { - log("Error starting timer for control host"); - return; - } - - auto method = this->bus.new_method_call(host.c_str(), - IPMI_PATH.c_str(), - IPMI_INTERFACE.c_str(), - "setAttention"); - auto reply = this->bus.call(method); - - if (reply.is_method_error()) - { - log("Error in setting SMS attention"); - throw std::runtime_error("ERROR in call to setAttention"); - } - log("SMS Attention asserted"); + Base::Host::Command::SoftOff, + std::make_pair(CMD_POWER, SOFT_OFF) } -} +}; -void Host::execute(base::Host::Command command) +// Called at user request +void Host::execute(Base::Host::Command command) { + using namespace phosphor::logging; + log("Pushing cmd on to queue", entry("CONTROL_HOST_CMD=%s", convertForMessage(command))); - this->workQueue.push(command); + auto cmd = std::make_tuple(ipmiCommand.at(command), + std::bind(&Host::commandStatusHandler, + this, std::placeholders::_1, + std::placeholders::_2)); - // Alert host if this is only command in queue otherwise host will - // be notified of next message after processing the current one - if (this->workQueue.size() == 1) - { - this->checkQueue(); - } - else - { - log("Command in process, no attention"); - } + return ipmid_send_cmd_to_host(std::move(cmd)); +} + +// Called into by Command Manager +void Host::commandStatusHandler(IpmiCmdData cmd, bool status) +{ + // Need to convert to the equivalent one mentioned in spec + auto value = status ? Result::Success : Result::Failure; - return; + // Fire a signal + this->commandComplete(intfCommand.at(std::get<0>(cmd)), value); } +} // namespace command } // namespace host } // namepsace phosphor diff --git a/host-interface.hpp b/host-interface.hpp index 8901a2b..5b2ac68 100644 --- a/host-interface.hpp +++ b/host-interface.hpp @@ -1,17 +1,14 @@ #pragma once -#include #include -#include #include -#include - +#include namespace phosphor { namespace host { - -using namespace phosphor::logging; +namespace command +{ /** @class Host * @brief OpenBMC control host interface implementation. @@ -24,56 +21,43 @@ class Host : public sdbusplus::server::object::object< public: /** @brief Constructs Host Control Interface * - * @param[in] bus - The Dbus bus object - * @param[in] objPath - The Dbus object path - * @param[in] events - The sd_event pointer + * @param[in] bus - The Dbus bus object + * @param[in] objPath - The Dbus object path */ Host(sdbusplus::bus::bus& bus, - const char* objPath, - sd_event* events) : + const char* objPath) : sdbusplus::server::object::object< sdbusplus::xyz::openbmc_project::Control::server::Host>( bus, objPath), - bus(bus), - timer(events, - std::bind(&Host::hostTimeout, this)) - {} + bus(bus) + { + // Nothing to do + } /** @brief Send input command to host + * Note that the command will be queued in a FIFO if + * other commands to the host have yet to be run * - * Note that the command will be queued in a FIFO if other commands - * to the host have yet to be run - * - * @param[in] command - Input command to execute + * @param[in] command - Input command to execute */ void execute(Command command) override; - /** @brief Return the next entry in the queue - * - * Also signal that the command is complete since the interface - * contract is that we emit this signal once the message has been - * passed to the host (which is required when calling this interface) - * - */ - Command getNextCommand(); - private: - - /** @brief Check if anything in queue and alert host if so */ - void checkQueue(); - - /** @brief Call back interface on message timeouts to host */ - void hostTimeout(); - - /** @brief Persistent sdbusplus DBus bus connection. */ + /** @brief sdbusplus DBus bus connection. */ sdbusplus::bus::bus& bus; - /** @brief Queue to store the requested commands */ - std::queue workQueue{}; - - /** @brief Timer for commands to host */ - phosphor::ipmi::Timer timer; + /** @brief Callback function to be invoked by command manager + * + * @detail Conveys the status of the last Host bound command. + * Depending on the status, a CommandComplete or + * CommandFailure signal would be sent + * + * @param[in] cmd - IPMI command and data sent to Host + * @param[in] status - Success or Failure + */ + void commandStatusHandler(IpmiCmdData cmd, bool status); }; +} // namespace command } // namespace host } // namespace phosphor diff --git a/ipmid-host-cmd.hpp b/ipmid-host-cmd.hpp new file mode 100644 index 0000000..7ef8b39 --- /dev/null +++ b/ipmid-host-cmd.hpp @@ -0,0 +1,10 @@ +#include +#include +#include + +// Need this to use new sdbusplus compatible interfaces +using sdbusPtr = std::unique_ptr; +extern sdbusPtr& ipmid_get_sdbus_plus_handler(); + +// Global Host Bound Command manager +extern void ipmid_send_cmd_to_host(phosphor::host::command::CommandHandler&&); diff --git a/ipmid.cpp b/ipmid.cpp index 7583bb8..f41e27f 100644 --- a/ipmid.cpp +++ b/ipmid.cpp @@ -25,6 +25,8 @@ #include "sensorhandler.h" #include "ipmid.hpp" #include "settings.hpp" +#include +#include using namespace phosphor::logging; namespace sdbusRule = sdbusplus::bus::match::rules; @@ -33,6 +35,17 @@ sd_bus *bus = NULL; sd_bus_slot *ipmid_slot = NULL; sd_event *events = nullptr; +// Need this to use new sdbusplus compatible interfaces +sdbusPtr sdbusp; + +// Global Host Bound Command manager +using cmdManagerPtr = std::unique_ptr; +cmdManagerPtr cmdManager; + +// Command and handler tuple. Used when clients ask the command to be put +// into host message queue +using CommandHandler = phosphor::host::command::CommandHandler; + // Initialise restricted mode to true bool restricted_mode = true; @@ -238,7 +251,9 @@ static int send_ipmi_message(sd_bus_message *req, unsigned char seq, unsigned ch dest = sd_bus_message_get_sender(req); path = sd_bus_message_get_path(req); - r = sd_bus_message_new_method_call(bus,&m,dest,path,DBUS_INTF,"sendMessage"); + r = sd_bus_message_new_method_call(bus,&m,dest,path, + DBUS_INTF, + "sendMessage"); if (r < 0) { fprintf(stderr, "Failed to add the method object: %s\n", strerror(-r)); return -1; @@ -486,6 +501,19 @@ sd_bus_slot *ipmid_get_sd_bus_slot(void) { return ipmid_slot; } +// Calls host command manager to do the right thing for the command +void ipmid_send_cmd_to_host(CommandHandler&& cmd) { + return cmdManager->execute(std::move(cmd)); +} + +cmdManagerPtr& ipmid_get_host_cmd_manager() { + return cmdManager; +} + +sdbusPtr& ipmid_get_sdbus_plus_handler() { + return sdbusp; +} + int main(int argc, char *argv[]) { int r; @@ -536,6 +564,11 @@ int main(int argc, char *argv[]) goto finish; } + // Now create the Host Bound Command manager. Need sdbusplus + // to use the generated bindings + sdbusp = std::make_unique(bus); + cmdManager = std::make_unique( + *sdbusp, events); // Register all the handlers that provider implementation to IPMI commands. ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH); diff --git a/softoff/softoff.cpp b/softoff/softoff.cpp index 767eb90..4a3166c 100644 --- a/softoff/softoff.cpp +++ b/softoff/softoff.cpp @@ -29,8 +29,8 @@ using namespace sdbusplus::xyz::openbmc_project::Control::server; void SoftPowerOff::sendHostShutDownCmd() { - std::string ctrlHostPath{CONTROL_HOST_OBJPATH}; - ctrlHostPath += "0"; + auto ctrlHostPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + + HOST_NAME + '0'; auto host = ::ipmi::getService(this->bus, CONTROL_HOST_BUSNAME, ctrlHostPath.c_str()); diff --git a/systemintfcmds.cpp b/systemintfcmds.cpp index 60961d3..2258630 100644 --- a/systemintfcmds.cpp +++ b/systemintfcmds.cpp @@ -1,6 +1,8 @@ #include "systemintfcmds.h" #include "host-ipmid/ipmid-api.h" +#include "ipmid-host-cmd.hpp" #include "config.h" +#include "host-cmd-manager.hpp" #include "host-interface.hpp" #include @@ -10,8 +12,9 @@ void register_netfn_app_functions() __attribute__((constructor)); using namespace sdbusplus::xyz::openbmc_project::Control::server; -// Internal function to get next host command -Host::Command getNextHostCmd(); +// For accessing Host command manager +using cmdManagerPtr = std::unique_ptr; +extern cmdManagerPtr& ipmid_get_host_cmd_manager(); //------------------------------------------------------------------- // Called by Host post response from Get_Message_Flags @@ -40,19 +43,11 @@ ipmi_ret_t ipmi_app_read_event(ipmi_netfn_t netfn, ipmi_cmd_t cmd, // per IPMI spec NetFuntion for OEM oem_sel.netfun = 0x3A; - // Read from the queue to see what our response is here - Host::Command hCmd = getNextHostCmd(); - switch (hCmd) - { - case Host::Command::SoftOff: - oem_sel.cmd = CMD_POWER; - oem_sel.data[0] = SOFT_OFF; - break; - case Host::Command::Heartbeat: - oem_sel.cmd = CMD_HEARTBEAT; - oem_sel.data[0] = 0x00; - break; - } + // Read from the Command Manager queue. What gets returned is a + // pair of that can be directly used here + auto hostCmd = ipmid_get_host_cmd_manager()->getNextCommand(); + oem_sel.cmd = hostCmd.first; + oem_sel.data[0] = hostCmd.second; // All '0xFF' since unused. memset(&oem_sel.data[1], 0xFF, 3); @@ -105,8 +100,10 @@ ipmi_ret_t ipmi_app_set_bmc_global_enables(ipmi_netfn_t netfn, ipmi_cmd_t cmd, namespace { // Static storage to keep the object alive during process life -std::unique_ptr sdbus __attribute__((init_priority(101))); -std::unique_ptr host __attribute__((init_priority(101))); +std::unique_ptr host + __attribute__((init_priority(101))); +std::unique_ptr objManager + __attribute__((init_priority(101))); } #include @@ -129,31 +126,18 @@ void register_netfn_app_functions() ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_MSG_FLAGS, NULL, ipmi_app_get_msg_flags, SYSTEM_INTERFACE); - // Gets a hook onto SYSTEM bus used by host-ipmid - sd_bus *bus = ipmid_get_sd_bus_connection(); - - sdbus = std::make_unique(bus); - // Create new xyz.openbmc_project.host object on the bus - auto objPathInst = std::string{CONTROL_HOST_OBJPATH} + '0'; + auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0'; // Add sdbusplus ObjectManager. - sdbusplus::server::manager::manager objManager(*sdbus, - objPathInst.c_str()); - - // Get the sd_events pointer - auto events = ipmid_get_sd_event_connection(); - - host = std::make_unique(*sdbus, - objPathInst.c_str(), - events); + auto& sdbusPlusHandler = ipmid_get_sdbus_plus_handler(); + objManager = std::make_unique( + *sdbusPlusHandler, + CONTROL_HOST_OBJ_MGR); - sdbus->request_name(CONTROL_HOST_BUSNAME); + host = std::make_unique( + *sdbusPlusHandler, objPath.c_str()); + sdbusPlusHandler->request_name(CONTROL_HOST_BUSNAME); return; } - -Host::Command getNextHostCmd() -{ - return(host->getNextCommand()); -} diff --git a/timer.hpp b/timer.hpp index cbd3444..6a59c0d 100644 --- a/timer.hpp +++ b/timer.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include namespace phosphor -- cgit v1.2.1