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::object<
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::bus& 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         determineInitialState();
70 
71         restorePOHCounter(); // restore POHCounter from persisted file
72 
73         // We deferred this until we could get our property correct
74         this->emit_object_added();
75     }
76 
77     /** @brief Set value of RequestedPowerTransition */
78     Transition requestedPowerTransition(Transition value) override;
79 
80     /** @brief Set value of CurrentPowerState */
81     PowerState currentPowerState(PowerState value) override;
82 
83     /** @brief Get value of POHCounter */
84     using ChassisInherit::pohCounter;
85 
86     /** @brief Increment POHCounter if Chassis Power state is ON */
87     void startPOHCounter();
88 
89   private:
90     /** @brief Create systemd target instance names and mapping table */
91     void createSystemdTargetTable();
92 
93     /** @brief Determine initial chassis state and set internally */
94     void determineInitialState();
95 
96     /** @brief Determine status of power into system by examining all the
97      *        power-related interfaces of interest
98      */
99     void determineStatusOfPower();
100 
101     /** @brief Determine status of power provided by an Uninterruptible Power
102      *         Supply into the system
103      */
104     void determineStatusOfUPSPower();
105 
106     /** @brief Determine status of power provided by the power supply units into
107      *         the system
108      */
109     void determineStatusOfPSUPower();
110 
111     /**
112      * @brief subscribe to the systemd signals
113      *
114      * This object needs to capture when it's systemd targets complete
115      * so it can keep it's state updated
116      *
117      **/
118     void subscribeToSystemdSignals();
119 
120     /** @brief Start the systemd unit requested
121      *
122      * This function calls `StartUnit` on the systemd unit given.
123      *
124      * @param[in] sysdUnit    - Systemd unit
125      */
126     void startUnit(const std::string& sysdUnit);
127 
128     /**
129      * @brief Determine if target is active
130      *
131      * This function determines if the target is active and
132      * helps prevent misleading log recorded states.
133      *
134      * @param[in] target - Target string to check on
135      *
136      * @return boolean corresponding to state active
137      **/
138     bool stateActive(const std::string& target);
139 
140     /** @brief Check if systemd state change is relevant to this object
141      *
142      * Instance specific interface to handle the detected systemd state
143      * change
144      *
145      * @param[in]  msg       - Data associated with subscribed signal
146      *
147      */
148     int sysStateChange(sdbusplus::message::message& msg);
149 
150     /** @brief Persistent sdbusplus DBus connection. */
151     sdbusplus::bus::bus& bus;
152 
153     /** @brief Used to subscribe to dbus systemd signals **/
154     sdbusplus::bus::match_t systemdSignals;
155 
156     /** @brief Watch for any changes to UPS properties **/
157     std::unique_ptr<sdbusplus::bus::match_t> uPowerPropChangeSignal;
158 
159     /** @brief Watch for any changes to PowerSystemInputs properties **/
160     std::unique_ptr<sdbusplus::bus::match_t> powerSysInputsPropChangeSignal;
161 
162     /** @brief Chassis id. **/
163     const size_t id = 0;
164 
165     /** @brief Transition state to systemd target mapping table. **/
166     std::map<Transition, std::string> systemdTargetTable;
167 
168     /** @brief Used to Set value of POHCounter */
169     uint32_t pohCounter(uint32_t value) override;
170 
171     /** @brief Used by the timer to update the POHCounter */
172     void pohCallback();
173 
174     /** @brief Used to restore POHCounter value from persisted file */
175     void restorePOHCounter();
176 
177     /** @brief Serialize and persist requested POH counter.
178      *
179      *  @param[in] dir - pathname of file where the serialized POH counter will
180      *                   be placed.
181      *
182      *  @return fs::path - pathname of persisted requested POH counter.
183      */
184     fs::path
185         serializePOH(const fs::path& dir = fs::path(POH_COUNTER_PERSIST_PATH));
186 
187     /** @brief Deserialize a persisted requested POH counter.
188      *
189      *  @param[in] path - pathname of persisted POH counter file
190      *  @param[in] retCounter - deserialized POH counter value
191      *
192      *  @return bool - true if the deserialization was successful, false
193      *                 otherwise.
194      */
195     bool deserializePOH(const fs::path& path, uint32_t& retCounter);
196 
197     /** @brief Sets the LastStateChangeTime property and persists it. */
198     void setStateChangeTime();
199 
200     /** @brief Serialize the last power state change time.
201      *
202      *  Save the time the state changed and the state itself.
203      *  The state needs to be saved as well so that during rediscovery
204      *  on reboots there's a way to know not to update the time again.
205      */
206     void serializeStateChangeTime();
207 
208     /** @brief Deserialize the last power state change time.
209      *
210      *  @param[out] time - Deserialized time
211      *  @param[out] state - Deserialized power state
212      *
213      *  @return bool - true if successful, false otherwise.
214      */
215     bool deserializeStateChangeTime(uint64_t& time, PowerState& state);
216 
217     /** @brief Restores the power state change time.
218      *
219      *  The time is loaded into the LastStateChangeTime D-Bus property.
220      *  On the very first start after this code has been applied but
221      *  before the state has changed, the LastStateChangeTime value
222      *  will be zero.
223      */
224     void restoreChassisStateChangeTime();
225 
226     /** @brief Timer used for tracking power on hours */
227     sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> pohTimer;
228 
229     /** @brief Function to check for a standby voltage regulator fault
230      *
231      *  Determine if a standby voltage regulator fault was detected and
232      *  return true or false accordingly.
233      *
234      *  @return true if fault detected, else false
235      */
236     bool standbyVoltageRegulatorFault();
237 
238     /** @brief Process UPS property changes
239      *
240      * Instance specific interface to monitor for changes to the UPS
241      * properties which may impact CurrentPowerStatus
242      *
243      * @param[in]  msg              - Data associated with subscribed signal
244      *
245      */
246     void uPowerChangeEvent(sdbusplus::message::message& msg);
247 
248     /** @brief Process PowerSystemInputs property changes
249      *
250      * Instance specific interface to monitor for changes to the
251      * PowerSystemInputs properties which may impact CurrentPowerStatus
252      *
253      * @param[in]  msg              - Data associated with subscribed signal
254      *
255      */
256     void powerSysInputsChangeEvent(sdbusplus::message::message& msg);
257 };
258 
259 } // namespace manager
260 } // namespace state
261 } // namespace phosphor
262