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