1 #pragma once
2 
3 #include "config.h"
4 
5 #include "utils.hpp"
6 
7 #include <cereal/cereal.hpp>
8 #include <sdbusplus/bus.hpp>
9 #include <sdeventplus/clock.hpp>
10 #include <sdeventplus/event.hpp>
11 #include <sdeventplus/utility/timer.hpp>
12 #include <xyz/openbmc_project/State/Chassis/server.hpp>
13 #include <xyz/openbmc_project/State/PowerOnHours/server.hpp>
14 
15 #include <chrono>
16 #include <filesystem>
17 
18 namespace phosphor
19 {
20 namespace state
21 {
22 namespace manager
23 {
24 
25 using ChassisInherit = sdbusplus::server::object_t<
26     sdbusplus::server::xyz::openbmc_project::state::Chassis,
27     sdbusplus::server::xyz::openbmc_project::state::PowerOnHours>;
28 namespace sdbusRule = sdbusplus::bus::match::rules;
29 namespace fs = std::filesystem;
30 
31 /** @class Chassis
32  *  @brief OpenBMC chassis state management implementation.
33  *  @details A concrete implementation for xyz.openbmc_project.State.Chassis
34  *  DBus API.
35  */
36 class Chassis : public ChassisInherit
37 {
38   public:
39     /** @brief Constructs Chassis State Manager
40      *
41      * @note This constructor passes 'true' to the base class in order to
42      *       defer dbus object registration until we can run
43      *       determineInitialState() and set our properties
44      *
45      * @param[in] bus       - The Dbus bus object
46      * @param[in] objPath   - The Dbus object path
47      * @param[in] id        - Chassis id
48      */
49     Chassis(sdbusplus::bus_t& bus, const char* objPath, size_t id) :
50         ChassisInherit(bus, objPath, ChassisInherit::action::defer_emit),
51         bus(bus),
52         systemdSignals(
53             bus,
54             sdbusRule::type::signal() + sdbusRule::member("JobRemoved") +
55                 sdbusRule::path("/org/freedesktop/systemd1") +
56                 sdbusRule::interface("org.freedesktop.systemd1.Manager"),
57             [this](sdbusplus::message_t& m) { sysStateChange(m); }),
58         id(id),
59         pohTimer(
60             sdeventplus::Event::get_default(), [this](auto&) { pohCallback(); },
61             std::chrono::hours{1}, std::chrono::minutes{1})
62     {
63         utils::subscribeToSystemdSignals(bus);
64 
65         createSystemdTargetTable();
66 
67         restoreChassisStateChangeTime();
68 
69         // No default in PDI so start at Good, skip D-Bus signal for now
70         currentPowerStatus(PowerStatus::Good, true);
71         determineInitialState();
72 
73         restorePOHCounter(); // restore POHCounter from persisted file
74 
75         // We deferred this until we could get our property correct
76         this->emit_object_added();
77     }
78 
79     /** @brief Set value of RequestedPowerTransition */
80     Transition requestedPowerTransition(Transition value) override;
81 
82     /** @brief Set value of CurrentPowerState */
83     PowerState currentPowerState(PowerState value) override;
84 
85     /** @brief Get value of POHCounter */
86     using ChassisInherit::pohCounter;
87 
88     /** @brief Increment POHCounter if Chassis Power state is ON */
89     void startPOHCounter();
90 
91   private:
92     /** @brief Create systemd target instance names and mapping table */
93     void createSystemdTargetTable();
94 
95     /** @brief Determine initial chassis state and set internally */
96     void determineInitialState();
97 
98     /** @brief Determine status of power into system by examining all the
99      *        power-related interfaces of interest
100      */
101     void determineStatusOfPower();
102 
103     /** @brief Determine status of power provided by an Uninterruptible Power
104      *         Supply into the system
105      *
106      *  @return True if UPS power is good, false otherwise
107      */
108     bool determineStatusOfUPSPower();
109 
110     /** @brief Determine status of power provided by the power supply units into
111      *         the system
112      *
113      *  @return True if PSU power is good, false otherwise
114      */
115     bool determineStatusOfPSUPower();
116 
117     /** @brief Start the systemd unit requested
118      *
119      * This function calls `StartUnit` on the systemd unit given.
120      *
121      * @param[in] sysdUnit    - Systemd unit
122      */
123     void startUnit(const std::string& sysdUnit);
124 
125     /** @brief Restart the systemd unit requested
126      *
127      * This function calls `RestartUnit` on the systemd unit given.
128      * This is useful when needing to restart a service that is already running
129      *
130      * @param[in] sysdUnit    - Systemd unit to restart
131      */
132     void restartUnit(const std::string& sysdUnit);
133 
134     /**
135      * @brief Determine if target is active
136      *
137      * This function determines if the target is active and
138      * helps prevent misleading log recorded states.
139      *
140      * @param[in] target - Target string to check on
141      *
142      * @return boolean corresponding to state active
143      **/
144     bool stateActive(const std::string& target);
145 
146     /** @brief Check if systemd state change is relevant to this object
147      *
148      * Instance specific interface to handle the detected systemd state
149      * change
150      *
151      * @param[in]  msg       - Data associated with subscribed signal
152      *
153      */
154     int sysStateChange(sdbusplus::message_t& msg);
155 
156     /** @brief Persistent sdbusplus DBus connection. */
157     sdbusplus::bus_t& bus;
158 
159     /** @brief Used to subscribe to dbus systemd signals **/
160     sdbusplus::bus::match_t systemdSignals;
161 
162     /** @brief Watch for any changes to UPS properties **/
163     std::unique_ptr<sdbusplus::bus::match_t> uPowerPropChangeSignal;
164 
165     /** @brief Watch for any changes to PowerSystemInputs properties **/
166     std::unique_ptr<sdbusplus::bus::match_t> powerSysInputsPropChangeSignal;
167 
168     /** @brief Chassis id. **/
169     const size_t id = 0;
170 
171     /** @brief Transition state to systemd target mapping table. **/
172     std::map<Transition, std::string> systemdTargetTable;
173 
174     /** @brief Used to Set value of POHCounter */
175     uint32_t pohCounter(uint32_t value) override;
176 
177     /** @brief Used by the timer to update the POHCounter */
178     void pohCallback();
179 
180     /** @brief Used to restore POHCounter value from persisted file */
181     void restorePOHCounter();
182 
183     /** @brief Serialize and persist requested POH counter.
184      *
185      *  @return fs::path - pathname of persisted requested POH counter.
186      */
187     fs::path serializePOH();
188 
189     /** @brief Deserialize a persisted requested POH counter.
190      *
191      *  @param[in] retCounter - deserialized POH counter value
192      *
193      *  @return bool - true if the deserialization was successful, false
194      *                 otherwise.
195      */
196     bool deserializePOH(uint32_t& retCounter);
197 
198     /** @brief Sets the LastStateChangeTime property and persists it. */
199     void setStateChangeTime();
200 
201     /** @brief Serialize the last power state change time.
202      *
203      *  Save the time the state changed and the state itself.
204      *  The state needs to be saved as well so that during rediscovery
205      *  on reboots there's a way to know not to update the time again.
206      */
207     void serializeStateChangeTime();
208 
209     /** @brief Deserialize the last power state change time.
210      *
211      *  @param[out] time - Deserialized time
212      *  @param[out] state - Deserialized power state
213      *
214      *  @return bool - true if successful, false otherwise.
215      */
216     bool deserializeStateChangeTime(uint64_t& time, PowerState& state);
217 
218     /** @brief Restores the power state change time.
219      *
220      *  The time is loaded into the LastStateChangeTime D-Bus property.
221      *  On the very first start after this code has been applied but
222      *  before the state has changed, the LastStateChangeTime value
223      *  will be zero.
224      */
225     void restoreChassisStateChangeTime();
226 
227     /** @brief Timer used for tracking power on hours */
228     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> pohTimer;
229 
230     /** @brief Function to check for a standby voltage regulator fault
231      *
232      *  Determine if a standby voltage regulator fault was detected and
233      *  return true or false accordingly.
234      *
235      *  @return true if fault detected, else false
236      */
237     bool standbyVoltageRegulatorFault();
238 
239     /** @brief Process UPS property changes
240      *
241      * Instance specific interface to monitor for changes to the UPS
242      * properties which may impact CurrentPowerStatus
243      *
244      * @param[in]  msg              - Data associated with subscribed signal
245      *
246      */
247     void uPowerChangeEvent(sdbusplus::message_t& msg);
248 
249     /** @brief Process PowerSystemInputs property changes
250      *
251      * Instance specific interface to monitor for changes to the
252      * PowerSystemInputs properties which may impact CurrentPowerStatus
253      *
254      * @param[in]  msg              - Data associated with subscribed signal
255      *
256      */
257     void powerSysInputsChangeEvent(sdbusplus::message_t& msg);
258 };
259 
260 } // namespace manager
261 } // namespace state
262 } // namespace phosphor
263