summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am8
-rw-r--r--configure.ac16
-rw-r--r--host-cmd-manager.cpp1
-rw-r--r--host-interface.cpp147
-rw-r--r--host-interface.hpp66
-rw-r--r--ipmid-host-cmd.hpp10
-rw-r--r--ipmid.cpp35
-rw-r--r--softoff/softoff.cpp4
-rw-r--r--systemintfcmds.cpp60
-rw-r--r--timer.hpp1
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&&);
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 <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());
-}
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 <chrono>
#include <functional>
#include <systemd/sd-event.h>
namespace phosphor
OpenPOWER on IntegriCloud