diff options
author | Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com> | 2017-07-12 16:13:49 +0530 |
---|---|---|
committer | Patrick Williams <patrick@stwcx.xyz> | 2017-08-14 18:47:08 +0000 |
commit | 3eb117a322aca11f049bb05beea5eb2f6385cb8e (patch) | |
tree | f3352df962e284c1d239e38a57955c1fa8b6ddca | |
parent | ac149a94543c9fae468cf45e47103998153c89a5 (diff) | |
download | phosphor-host-ipmid-3eb117a322aca11f049bb05beea5eb2f6385cb8e.tar.gz phosphor-host-ipmid-3eb117a322aca11f049bb05beea5eb2f6385cb8e.zip |
Use Host Command Manager in host interface implementation
Change-Id: Icefce510a3a0022bf0288fa99518459b732a2e04
Signed-off-by: Vishwanatha Subbanna <vishwa@linux.vnet.ibm.com>
-rw-r--r-- | Makefile.am | 8 | ||||
-rw-r--r-- | configure.ac | 16 | ||||
-rw-r--r-- | host-cmd-manager.cpp | 1 | ||||
-rw-r--r-- | host-interface.cpp | 147 | ||||
-rw-r--r-- | host-interface.hpp | 66 | ||||
-rw-r--r-- | ipmid-host-cmd.hpp | 10 | ||||
-rw-r--r-- | ipmid.cpp | 35 | ||||
-rw-r--r-- | softoff/softoff.cpp | 4 | ||||
-rw-r--r-- | systemintfcmds.cpp | 60 | ||||
-rw-r--r-- | timer.hpp | 1 |
10 files changed, 162 insertions, 186 deletions
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 <utils.hpp> #include <config.h> #include <host-cmd-manager.hpp> - 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 <chrono> -#include <phosphor-logging/log.hpp> +#include <functional> +#include <systemintfcmds.h> +#include <ipmid-host-cmd.hpp> #include <utils.hpp> +#include <phosphor-logging/log.hpp> #include <config.h> -#include "host-interface.hpp" - +#include <host-interface.hpp> 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<OEMCmd, Host::Command> intfCommand = { { - log<level::ERR>("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<level::INFO>("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<level::ERR>("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<Host::Command, IpmiCmdData> 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<level::INFO>("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::microseconds>( - std::chrono::seconds(IPMI_SMS_ATN_ACK_TIMEOUT_SECS)); - auto r = timer.startTimer(time); - if (r < 0) - { - log<level::ERR>("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<level::ERR>("Error in setting SMS attention"); - throw std::runtime_error("ERROR in call to setAttention"); - } - log<level::INFO>("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<level::INFO>("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<level::INFO>("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 <cmd> 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 <queue> #include <sdbusplus/bus.hpp> -#include <phosphor-logging/elog.hpp> #include <xyz/openbmc_project/Control/Host/server.hpp> -#include <timer.hpp> - +#include <host-cmd-manager.hpp> 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<Command> 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 <memory> +#include <sdbusplus/bus.hpp> +#include <host-cmd-utils.hpp> + +// Need this to use new sdbusplus compatible interfaces +using sdbusPtr = std::unique_ptr<sdbusplus::bus::bus>; +extern sdbusPtr& ipmid_get_sdbus_plus_handler(); + +// Global Host Bound Command manager +extern void ipmid_send_cmd_to_host(phosphor::host::command::CommandHandler&&); @@ -25,6 +25,8 @@ #include "sensorhandler.h" #include "ipmid.hpp" #include "settings.hpp" +#include <host-cmd-manager.hpp> +#include <ipmid-host-cmd.hpp> 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<phosphor::host::command::Manager>; +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<sdbusplus::bus::bus>(bus); + cmdManager = std::make_unique<phosphor::host::command::Manager>( + *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 <stdio.h> @@ -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<phosphor::host::command::Manager>; +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 <command, data> 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<sdbusplus::bus::bus> sdbus __attribute__((init_priority(101))); -std::unique_ptr<phosphor::host::Host> host __attribute__((init_priority(101))); +std::unique_ptr<phosphor::host::command::Host> host + __attribute__((init_priority(101))); +std::unique_ptr<sdbusplus::server::manager::manager> objManager + __attribute__((init_priority(101))); } #include <unistd.h> @@ -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<sdbusplus::bus::bus>(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<phosphor::host::Host>(*sdbus, - objPathInst.c_str(), - events); + auto& sdbusPlusHandler = ipmid_get_sdbus_plus_handler(); + objManager = std::make_unique<sdbusplus::server::manager::manager>( + *sdbusPlusHandler, + CONTROL_HOST_OBJ_MGR); - sdbus->request_name(CONTROL_HOST_BUSNAME); + host = std::make_unique<phosphor::host::command::Host>( + *sdbusPlusHandler, objPath.c_str()); + sdbusPlusHandler->request_name(CONTROL_HOST_BUSNAME); return; } - -Host::Command getNextHostCmd() -{ - return(host->getNextCommand()); -} @@ -1,5 +1,6 @@ #pragma once +#include <chrono> #include <functional> #include <systemd/sd-event.h> namespace phosphor |