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