1 #pragma once
2 
3 #include <sdbusplus/bus.hpp>
4 #include <sdbusplus/server/object.hpp>
5 #include <functional>
6 #include <xyz/openbmc_project/Control/Host/server.hpp>
7 #include <xyz/openbmc_project/Ipmi/Internal/SoftPowerOff/server.hpp>
8 #include "timer.hpp"
9 #include "config.h"
10 namespace phosphor
11 {
12 namespace ipmi
13 {
14 
15 namespace Base = sdbusplus::xyz::openbmc_project::Ipmi::Internal::server;
16 using namespace sdbusplus::xyz::openbmc_project::Control::server;
17 
18 namespace sdbusRule = sdbusplus::bus::match::rules;
19 
20 /** @class SoftPowerOff
21  *  @brief Responsible for coordinating Host SoftPowerOff operation
22  */
23 class SoftPowerOff : public sdbusplus::server::object::object<
24                      Base::SoftPowerOff>
25 {
26     public:
27         /** @brief Constructs SoftPowerOff object.
28          *
29          *  @param[in] bus       - system dbus handler
30          *  @param[in] event     - sd_event handler
31          *  @param[in] objPath   - The Dbus path hosting SoftPowerOff function
32          */
33         SoftPowerOff(sdbusplus::bus::bus& bus,
34                      sd_event* event,
35                      const char* objPath) :
36             sdbusplus::server::object::object<
37                 Base::SoftPowerOff>(bus, objPath, false),
38                 bus(bus),
39                 timer(event),
40                 hostControlSignal(
41                         bus,
42                         sdbusRule::type::signal() +
43                         sdbusRule::member("CommandComplete") +
44                         sdbusRule::path("/xyz/openbmc_project/control/host0") +
45                         sdbusRule::interface(CONTROL_HOST_BUSNAME) +
46                         sdbusRule::argN(0,convertForMessage(
47                                 Host::Command::SoftOff)),
48                         std::bind(std::mem_fn(&SoftPowerOff::hostControlEvent),
49                                   this, 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::bus& 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::message& msg);
142 
143 };
144 } // namespace ipmi
145 } // namespace phosphor
146