xref: /openbmc/openpower-occ-control/occ_status.hpp (revision a8857c50864a60c372fdf631865a32e6eff53330)
1 #pragma once
2 
3 #include "i2c_occ.hpp"
4 #include "occ_command.hpp"
5 #include "occ_device.hpp"
6 #include "occ_events.hpp"
7 
8 #include <functional>
9 #include <org/open_power/Control/Host/server.hpp>
10 #include <org/open_power/OCC/Status/server.hpp>
11 #include <sdbusplus/bus.hpp>
12 #include <sdbusplus/server/object.hpp>
13 
14 namespace open_power
15 {
16 namespace occ
17 {
18 
19 class Manager;
20 namespace Base = sdbusplus::org::open_power::OCC::server;
21 using Interface = sdbusplus::server::object::object<Base::Status>;
22 
23 // IPMID's host control application
24 namespace Control = sdbusplus::org::open_power::Control::server;
25 
26 // For waiting on signals
27 namespace sdbusRule = sdbusplus::bus::match::rules;
28 
29 // OCC status instance. Ex. for "occ0", the instance is 0
30 using instanceID = int;
31 
32 // IPMI sensor ID for a given OCC instance
33 using sensorID = uint8_t;
34 
35 // Human readable sensor name for DBus tree. E.g. "CPU0_OCC"
36 using sensorName = std::string;
37 
38 // OCC sensors definitions in the map
39 using sensorDefs = std::tuple<sensorID, sensorName>;
40 
41 // OCC sysfs name prefix
42 const std::string sysfsName = "occ-hwmon";
43 
44 /** @class Status
45  *  @brief Implementation of OCC Active Status
46  */
47 class Status : public Interface
48 {
49   public:
50     Status() = delete;
51     ~Status() = default;
52     Status(const Status&) = delete;
53     Status& operator=(const Status&) = delete;
54     Status(Status&&) = default;
55     Status& operator=(Status&&) = default;
56 
57     /** @brief Constructs the Status object and
58      *         the underlying device object
59      *
60      *  @param[in] bus      - DBus bus to attach to
61      *  @param[in] event    - sd_event unique pointer reference
62      *  @param[in] path     - DBus object path
63      *  @param[in] manager  - OCC manager instance
64      *  @param[in] callBack - Callback handler to invoke during
65      *                        property change
66      *  @param[in] resetCallBack - callback handler to invoke for resetting the
67      *                             OCC if PLDM is the host communication
68      *                             protocol
69      */
70     Status(sdbusplus::bus::bus& bus, EventPtr& event, const char* path,
71            const Manager& manager, std::function<void(bool)> callBack = nullptr
72 #ifdef PLDM
73            ,
74            std::function<void(instanceID)> resetCallBack = nullptr
75 #endif
76            ) :
77 
78         Interface(bus, getDbusPath(path).c_str(), true),
79         bus(bus), path(path), callBack(callBack), instance(getInstance(path)),
80         device(event,
81 #ifdef I2C_OCC
82                fs::path(DEV_PATH) / i2c_occ::getI2cDeviceName(path),
83 #else
84                fs::path(DEV_PATH) /
85                    fs::path(sysfsName + "." + std::to_string(instance + 1)),
86 #endif
87                manager, *this,
88                std::bind(std::mem_fn(&Status::deviceErrorHandler), this,
89                          std::placeholders::_1)),
90         hostControlSignal(
91             bus,
92             sdbusRule::type::signal() + sdbusRule::member("CommandComplete") +
93                 sdbusRule::path("/org/open_power/control/host0") +
94                 sdbusRule::interface("org.open_power.Control.Host") +
95                 sdbusRule::argN(0, Control::convertForMessage(
96                                        Control::Host::Command::OCCReset)),
97             std::bind(std::mem_fn(&Status::hostControlEvent), this,
98                       std::placeholders::_1)),
99         occCmd(instance, bus,
100                (fs::path(OCC_CONTROL_ROOT) /
101                 (std::string(OCC_NAME) + std::to_string(instance)))
102                    .c_str())
103 #ifdef PLDM
104         ,
105         resetCallBack(resetCallBack)
106 #endif
107     {
108         // Check to see if we have OCC already bound.  If so, just set it
109         if (device.bound())
110         {
111             this->occActive(true);
112         }
113 
114         // Announce that we are ready
115         this->emit_object_added();
116     }
117 
118     /** @brief Since we are overriding the setter-occActive but not the
119      *         getter-occActive, we need to have this using in order to
120      *         allow passthrough usage of the getter-occActive
121      */
122     using Base::Status::occActive;
123 
124     /** @brief SET OccActive to True or False
125      *
126      *  @param[in] value - Intended value
127      *
128      *  @return          - Updated value of the property
129      */
130     bool occActive(bool value) override;
131 
132     /** @brief Starts OCC error detection */
133     inline void addErrorWatch()
134     {
135         return device.addErrorWatch();
136     }
137 
138     /** @brief Stops OCC error detection */
139     inline void removeErrorWatch()
140     {
141         return device.removeErrorWatch();
142     }
143 
144     /** @brief Starts to watch how many OCCs are present on the master */
145     inline void addPresenceWatchMaster()
146     {
147         return device.addPresenceWatchMaster();
148     }
149 
150     /** @brief Read OCC state (will trigger kernel to poll the OCC) */
151     void readOccState();
152 
153   private:
154     /** @brief sdbus handle */
155     sdbusplus::bus::bus& bus;
156 
157     /** @brief OCC dbus object path */
158     std::string path;
159 
160     /** @brief Callback handler to be invoked during property change.
161      *         This is a handler in Manager class
162      */
163     std::function<void(bool)> callBack;
164 
165     /** @brief OCC instance number. Ex, 0,1, etc */
166     unsigned int instance;
167 
168     /** @brief The last state read from the OCC */
169     unsigned int lastState = 0;
170 
171     /** @brief OCC instance to Sensor definitions mapping */
172     static const std::map<instanceID, sensorDefs> sensorMap;
173 
174     /** @brief OCC device object to do bind and unbind */
175     Device device;
176 
177     /** @brief Subscribe to host control signal
178      *
179      *  Once the OCC reset is requested, BMC sends that message to host.
180      *  If the host does not ack the message, then there would be a timeout
181      *  and we need to catch that to log an error
182      **/
183     sdbusplus::bus::match_t hostControlSignal;
184 
185     /** @brief Command object to send commands to the OCC */
186     OccCommand occCmd;
187 
188     /** @brief Callback handler when device errors are detected
189      *
190      *  @param[in]  error - True if an error is reported, false otherwise
191      */
192     void deviceErrorHandler(bool error);
193 
194     /** @brief Callback function on host control signals
195      *
196      *  @param[in]  msg - Data associated with subscribed signal
197      */
198     void hostControlEvent(sdbusplus::message::message& msg);
199 
200     /** @brief Sends a message to host control command handler to reset OCC
201      */
202     void resetOCC();
203 
204     /** @brief Determines the instance ID by specified object path.
205      *  @param[in]  path  Estimated OCC Dbus object path
206      *  @return  Instance number
207      */
208     static int getInstance(const std::string& path)
209     {
210         return (path.empty() ? 0 : path.back() - '0');
211     }
212 
213     /** @brief Override the sensor name with name from the definition.
214      *  @param[in]  estimatedPath - Estimated OCC Dbus object path
215      *  @return  Fixed OCC DBus object path
216      */
217     static std::string getDbusPath(const std::string& estimatedPath)
218     {
219         if (!estimatedPath.empty())
220         {
221             auto it = sensorMap.find(getInstance(estimatedPath));
222             if (sensorMap.end() != it)
223             {
224                 auto& name = std::get<1>(it->second);
225                 if (!name.empty() && name != "None")
226                 {
227                     auto path = fs::path(estimatedPath);
228                     path.replace_filename(name);
229                     return path.string();
230                 }
231             }
232         }
233 
234         return estimatedPath;
235     }
236 #ifdef PLDM
237     std::function<void(instanceID)> resetCallBack = nullptr;
238 #endif
239 };
240 
241 } // namespace occ
242 } // namespace open_power
243