summaryrefslogtreecommitdiffstats
path: root/softoff/softoff.hpp
blob: 43bc3034ba2ee60a2134609602ddef9339d8dc66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#pragma once

#include <sdbusplus/bus.hpp>
#include <sdbusplus/server/object.hpp>
#include <functional>
#include <xyz/openbmc_project/Control/Host/server.hpp>
#include <xyz/openbmc_project/Ipmi/Internal/SoftPowerOff/server.hpp>
#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
OpenPOWER on IntegriCloud