1 #pragma once
2 
3 #include "config.h"
4 
5 #include "xyz/openbmc_project/State/Chassis/server.hpp"
6 #include "xyz/openbmc_project/State/PowerOnHours/server.hpp"
7 
8 #include <cereal/cereal.hpp>
9 #include <sdbusplus/bus.hpp>
10 #include <sdeventplus/clock.hpp>
11 #include <sdeventplus/event.hpp>
12 #include <sdeventplus/utility/timer.hpp>
13 
14 #include <chrono>
15 #include <filesystem>
16 #include <functional>
17 
18 namespace phosphor
19 {
20 namespace state
21 {
22 namespace manager
23 {
24 
25 using ChassisInherit = sdbusplus::server::object_t<
26     sdbusplus::xyz::openbmc_project::State::server::Chassis,
27     sdbusplus::xyz::openbmc_project::State::server::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             std::bind(std::mem_fn(&Chassis::sysStateChange), this,
58                       std::placeholders::_1)),
59         id(id), pohTimer(sdeventplus::Event::get_default(),
60                          std::bind(&Chassis::pohCallback, this),
61                          std::chrono::hours{1}, std::chrono::minutes{1})
62     {
63         subscribeToSystemdSignals();
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     /**
118      * @brief subscribe to the systemd signals
119      *
120      * This object needs to capture when it's systemd targets complete
121      * so it can keep it's state updated
122      *
123      **/
124     void subscribeToSystemdSignals();
125 
126     /** @brief Start the systemd unit requested
127      *
128      * This function calls `StartUnit` on the systemd unit given.
129      *
130      * @param[in] sysdUnit    - Systemd unit
131      */
132     void startUnit(const std::string& sysdUnit);
133 
134     /** @brief Restart the systemd unit requested
135      *
136      * This function calls `RestartUnit` on the systemd unit given.
137      * This is useful when needing to restart a service that is already running
138      *
139      * @param[in] sysdUnit    - Systemd unit to restart
140      */
141     void restartUnit(const std::string& sysdUnit);
142 
143     /**
144      * @brief Determine if target is active
145      *
146      * This function determines if the target is active and
147      * helps prevent misleading log recorded states.
148      *
149      * @param[in] target - Target string to check on
150      *
151      * @return boolean corresponding to state active
152      **/
153     bool stateActive(const std::string& target);
154 
155     /** @brief Check if systemd state change is relevant to this object
156      *
157      * Instance specific interface to handle the detected systemd state
158      * change
159      *
160      * @param[in]  msg       - Data associated with subscribed signal
161      *
162      */
163     int sysStateChange(sdbusplus::message_t& msg);
164 
165     /** @brief Persistent sdbusplus DBus connection. */
166     sdbusplus::bus_t& bus;
167 
168     /** @brief Used to subscribe to dbus systemd signals **/
169     sdbusplus::bus::match_t systemdSignals;
170 
171     /** @brief Watch for any changes to UPS properties **/
172     std::unique_ptr<sdbusplus::bus::match_t> uPowerPropChangeSignal;
173 
174     /** @brief Watch for any changes to PowerSystemInputs properties **/
175     std::unique_ptr<sdbusplus::bus::match_t> powerSysInputsPropChangeSignal;
176 
177     /** @brief Chassis id. **/
178     const size_t id = 0;
179 
180     /** @brief Transition state to systemd target mapping table. **/
181     std::map<Transition, std::string> systemdTargetTable;
182 
183     /** @brief Used to Set value of POHCounter */
184     uint32_t pohCounter(uint32_t value) override;
185 
186     /** @brief Used by the timer to update the POHCounter */
187     void pohCallback();
188 
189     /** @brief Used to restore POHCounter value from persisted file */
190     void restorePOHCounter();
191 
192     /** @brief Serialize and persist requested POH counter.
193      *
194      *  @return fs::path - pathname of persisted requested POH counter.
195      */
196     fs::path serializePOH();
197 
198     /** @brief Deserialize a persisted requested POH counter.
199      *
200      *  @param[in] retCounter - deserialized POH counter value
201      *
202      *  @return bool - true if the deserialization was successful, false
203      *                 otherwise.
204      */
205     bool deserializePOH(uint32_t& retCounter);
206 
207     /** @brief Sets the LastStateChangeTime property and persists it. */
208     void setStateChangeTime();
209 
210     /** @brief Serialize the last power state change time.
211      *
212      *  Save the time the state changed and the state itself.
213      *  The state needs to be saved as well so that during rediscovery
214      *  on reboots there's a way to know not to update the time again.
215      */
216     void serializeStateChangeTime();
217 
218     /** @brief Deserialize the last power state change time.
219      *
220      *  @param[out] time - Deserialized time
221      *  @param[out] state - Deserialized power state
222      *
223      *  @return bool - true if successful, false otherwise.
224      */
225     bool deserializeStateChangeTime(uint64_t& time, PowerState& state);
226 
227     /** @brief Restores the power state change time.
228      *
229      *  The time is loaded into the LastStateChangeTime D-Bus property.
230      *  On the very first start after this code has been applied but
231      *  before the state has changed, the LastStateChangeTime value
232      *  will be zero.
233      */
234     void restoreChassisStateChangeTime();
235 
236     /** @brief Timer used for tracking power on hours */
237     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> pohTimer;
238 
239     /** @brief Function to check for a standby voltage regulator fault
240      *
241      *  Determine if a standby voltage regulator fault was detected and
242      *  return true or false accordingly.
243      *
244      *  @return true if fault detected, else false
245      */
246     bool standbyVoltageRegulatorFault();
247 
248     /** @brief Process UPS property changes
249      *
250      * Instance specific interface to monitor for changes to the UPS
251      * properties which may impact CurrentPowerStatus
252      *
253      * @param[in]  msg              - Data associated with subscribed signal
254      *
255      */
256     void uPowerChangeEvent(sdbusplus::message_t& msg);
257 
258     /** @brief Process PowerSystemInputs property changes
259      *
260      * Instance specific interface to monitor for changes to the
261      * PowerSystemInputs properties which may impact CurrentPowerStatus
262      *
263      * @param[in]  msg              - Data associated with subscribed signal
264      *
265      */
266     void powerSysInputsChangeEvent(sdbusplus::message_t& msg);
267 };
268 
269 } // namespace manager
270 } // namespace state
271 } // namespace phosphor
272