1 #pragma once
2 
3 #include "config.h"
4 
5 #include <functional>
6 #include <sdbusplus/bus.hpp>
7 #include <sdbusplus/server/object.hpp>
8 #include <sdbusplus/timer.hpp>
9 #include <xyz/openbmc_project/Control/Host/server.hpp>
10 #include <xyz/openbmc_project/Ipmi/Internal/SoftPowerOff/server.hpp>
11 namespace phosphor
12 {
13 namespace ipmi
14 {
15 
16 namespace Base = sdbusplus::xyz::openbmc_project::Ipmi::Internal::server;
17 using namespace sdbusplus::xyz::openbmc_project::Control::server;
18 
19 namespace sdbusRule = sdbusplus::bus::match::rules;
20 
21 namespace
22 {
23 using SoftPowerOffInherit = sdbusplus::server::object_t<Base::SoftPowerOff>;
24 }
25 
26 /** @class SoftPowerOff
27  *  @brief Responsible for coordinating Host SoftPowerOff operation
28  */
29 class SoftPowerOff : public SoftPowerOffInherit
30 {
31   public:
32     /** @brief Constructs SoftPowerOff object.
33      *
34      *  @param[in] bus       - system dbus handler
35      *  @param[in] event     - sd_event handler
36      *  @param[in] objPath   - The Dbus path hosting SoftPowerOff function
37      */
38     SoftPowerOff(sdbusplus::bus_t& bus, sd_event* event, const char* objPath) :
39         SoftPowerOffInherit(bus, objPath,
40                             SoftPowerOffInherit::action::defer_emit),
41         bus(bus), timer(event),
42         hostControlSignal(
43             bus,
44             sdbusRule::type::signal() + sdbusRule::member("CommandComplete") +
45                 sdbusRule::path("/xyz/openbmc_project/control/host0") +
46                 sdbusRule::interface(CONTROL_HOST_BUSNAME) +
47                 sdbusRule::argN(0, convertForMessage(Host::Command::SoftOff)),
48             std::bind(std::mem_fn(&SoftPowerOff::hostControlEvent), this,
49                       std::placeholders::_1))
50     {
51         // Need to announce since we may get the response
52         // very quickly on host shutdown command
53         emit_object_added();
54 
55         // The whole purpose of this application is to send a host shutdown
56         // command and watch for the soft power off to go through. We need
57         // the interface added signal emitted before we send the shutdown
58         // command just to attend to lightning fast response from host
59         sendHostShutDownCmd();
60     }
61 
62     /** @brief Tells if the objective of this application is completed */
63     inline auto isCompleted()
64     {
65         return completed;
66     }
67 
68     /** @brief Tells if the referenced timer is expired or not */
69     inline auto isTimerExpired()
70     {
71         return timer.isExpired();
72     }
73 
74     /** @brief overloaded property setter function
75      *
76      *  @param[in] value - One of SoftOffReceived / HostShutdown
77      *
78      *  @return Success or exception thrown
79      */
80     HostResponse responseReceived(HostResponse value) override;
81 
82     /** @brief Using the base class's getter method */
83     using Base::SoftPowerOff::responseReceived;
84 
85     /** @brief Calls to start a timer
86      *
87      *  @param[in] usec - Time in microseconds
88      *
89      *  @return Success or exception thrown
90      */
91     int startTimer(const std::chrono::microseconds& usec);
92 
93   private:
94     // Need this to send SMS_ATTN
95     // TODO : Switch over to using mapper service in a different patch
96     static constexpr auto HOST_IPMI_BUS = "org.openbmc.HostIpmi";
97     static constexpr auto HOST_IPMI_OBJ = "/org/openbmc/HostIpmi/1";
98     static constexpr auto HOST_IPMI_INTF = "org.openbmc.HostIpmi";
99 
100     /* @brief sdbusplus handle */
101     sdbusplus::bus_t& bus;
102 
103     /** @brief Reference to Timer object */
104     Timer timer;
105 
106     /** @brief Marks the end of life of this application.
107      *
108      *  This is set to true if host gives appropriate responses
109      *  for the sequence of commands.
110      */
111     bool completed = false;
112 
113     /** @brief Subscribe to host control signals
114      *
115      *  Protocol is to send the host power off request to the host
116      *  control interface and then wait for a signal indicating pass/fail
117      **/
118     sdbusplus::bus::match_t hostControlSignal;
119 
120     /** @brief Sends host control command to tell host to shut down
121      *
122      *  After sending the command, wait for a signal indicating the status
123      *  of the command.
124      *
125      *  After receiving the initial response, start a timer for 30 minutes
126      *  to let host do a clean shutdown of partitions. When the response is
127      *  received from the host, it indicates that BMC can do a power off.
128      *  If BMC fails to get any response, then a hard power off would
129      *  be forced.
130      *
131      *  @return - Does not return anything. Error will result in exception
132      *            being thrown
133      */
134     void sendHostShutDownCmd();
135 
136     /** @brief Callback function on host control signals
137      *
138      * @param[in]  msg       - Data associated with subscribed signal
139      *
140      */
141     void hostControlEvent(sdbusplus::message_t& msg);
142 };
143 } // namespace ipmi
144 } // namespace phosphor
145