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