#pragma once #include #include #include #include #include #include "timer.hpp" #include "config.h" namespace phosphor { namespace ipmi { namespace Base = sdbusplus::xyz::openbmc_project::Ipmi::Internal::server; using namespace sdbusplus::xyz::openbmc_project::Control::server; namespace sdbusRule = sdbusplus::bus::match::rules; /** @class SoftPowerOff * @brief Responsible for coordinating Host SoftPowerOff operation */ class SoftPowerOff : public sdbusplus::server::object::object< Base::SoftPowerOff> { public: /** @brief Constructs SoftPowerOff object. * * @param[in] bus - system dbus handler * @param[in] event - sd_event handler * @param[in] objPath - The Dbus path hosting SoftPowerOff function */ SoftPowerOff(sdbusplus::bus::bus& bus, sd_event* event, const char* objPath) : sdbusplus::server::object::object< Base::SoftPowerOff>(bus, objPath, false), bus(bus), timer(event), hostControlSignal( bus, sdbusRule::type::signal() + sdbusRule::member("CommandComplete") + sdbusRule::path("/xyz/openbmc_project/control/host0") + sdbusRule::interface(CONTROL_HOST_BUSNAME) + sdbusRule::argN(0,convertForMessage( Host::Command::SoftOff)), std::bind(std::mem_fn(&SoftPowerOff::hostControlEvent), this, std::placeholders::_1)) { // Need to announce since we may get the response // very quickly on host shutdown command emit_object_added(); // The whole purpose of this application is to send a host shutdown // command and watch for the soft power off to go through. We need // the interface added signal emitted before we send the shutdown // command just to attend to lightning fast response from host sendHostShutDownCmd(); } /** @brief Tells if the objective of this application is completed */ inline auto isCompleted() { return completed; } /** @brief Tells if the referenced timer is expired or not */ inline auto isTimerExpired() { return timer.isExpired(); } /** @brief overloaded property setter function * * @param[in] value - One of SoftOffReceived / HostShutdown * * @return Success or exception thrown */ HostResponse responseReceived(HostResponse value) override; /** @brief Using the base class's getter method */ using Base::SoftPowerOff::responseReceived; /** @brief Calls to start a timer * * @param[in] usec - Time in microseconds * * @return Success or exception thrown */ int startTimer(const std::chrono::microseconds& usec); private: // Need this to send SMS_ATTN // TODO : Switch over to using mapper service in a different patch static constexpr auto HOST_IPMI_BUS = "org.openbmc.HostIpmi"; static constexpr auto HOST_IPMI_OBJ = "/org/openbmc/HostIpmi/1"; static constexpr auto HOST_IPMI_INTF = "org.openbmc.HostIpmi"; /* @brief sdbusplus handle */ sdbusplus::bus::bus& bus; /** @brief Reference to Timer object */ Timer timer; /** @brief Marks the end of life of this application. * * This is set to true if host gives appropriate responses * for the sequence of commands. */ bool completed = false; /** @brief Subscribe to host control signals * * Protocol is to send the host power off request to the host * control interface and then wait for a signal indicating pass/fail **/ sdbusplus::bus::match_t hostControlSignal; /** @brief Sends host control command to tell host to shut down * * After sending the command, wait for a signal indicating the status * of the command. * * After receiving the initial response, start a timer for 30 minutes * to let host do a clean shutdown of partitions. When the response is * received from the host, it indicates that BMC can do a power off. * If BMC fails to get any response, then a hard power off would * be forced. * * @return - Does not return anything. Error will result in exception * being thrown */ void sendHostShutDownCmd(); /** @brief Callback function on host control signals * * @param[in] msg - Data associated with subscribed signal * */ void hostControlEvent(sdbusplus::message::message& msg); }; } // namespace ipmi } // namespace phosphor