1 #pragma once
2 
3 #include "i2c_occ.hpp"
4 #include "occ_device.hpp"
5 #include "occ_events.hpp"
6 
7 #include <functional>
8 #include <org/open_power/Control/Host/server.hpp>
9 #include <org/open_power/OCC/Status/server.hpp>
10 #include <sdbusplus/bus.hpp>
11 #include <sdbusplus/server/object.hpp>
12 
13 namespace open_power
14 {
15 namespace occ
16 {
17 
18 class Manager;
19 namespace Base = sdbusplus::org::open_power::OCC::server;
20 using Interface = sdbusplus::server::object::object<Base::Status>;
21 
22 // IPMID's host control application
23 namespace Control = sdbusplus::org::open_power::Control::server;
24 
25 // For waiting on signals
26 namespace sdbusRule = sdbusplus::bus::match::rules;
27 
28 // OCC status instance. Ex. for "occ0", the instance is 0
29 using instanceID = int;
30 
31 // IPMI sensor ID for a given OCC instance
32 using sensorID = uint8_t;
33 
34 // OCC sysfs name prefix
35 const std::string sysfsName = "occ-hwmon";
36 
37 /** @class Status
38  *  @brief Implementation of OCC Active Status
39  */
40 class Status : public Interface
41 {
42   public:
43     Status() = delete;
44     ~Status() = default;
45     Status(const Status&) = delete;
46     Status& operator=(const Status&) = delete;
47     Status(Status&&) = default;
48     Status& operator=(Status&&) = default;
49 
50     /** @brief Constructs the Status object and
51      *         the underlying device object
52      *
53      *  @param[in] bus      - DBus bus to attach to
54      *  @param[in] event    - sd_event unique pointer reference
55      *  @param[in] path     - DBus object path
56      *  @param[in] manager  - OCC manager instance
57      *  @param[in] callBack - Callback handler to invoke during
58      *                        property change
59      */
60     Status(sdbusplus::bus::bus& bus, EventPtr& event, const char* path,
61            const Manager& manager,
62            std::function<void(bool)> callBack = nullptr) :
63         Interface(bus, path, true),
64         bus(bus), path(path), callBack(callBack),
65         instance(((this->path.back() - '0'))),
66         device(event,
67 #ifdef I2C_OCC
68                fs::path(DEV_PATH) / i2c_occ::getI2cDeviceName(path),
69 #else
70                fs::path(DEV_PATH) /
71                    fs::path(sysfsName + "." + std::to_string(instance + 1)),
72 #endif
73                manager, *this,
74                std::bind(std::mem_fn(&Status::deviceErrorHandler), this,
75                          std::placeholders::_1)),
76         hostControlSignal(
77             bus,
78             sdbusRule::type::signal() + sdbusRule::member("CommandComplete") +
79                 sdbusRule::path("/org/open_power/control/host0") +
80                 sdbusRule::interface("org.open_power.Control.Host") +
81                 sdbusRule::argN(0, Control::convertForMessage(
82                                        Control::Host::Command::OCCReset)),
83             std::bind(std::mem_fn(&Status::hostControlEvent), this,
84                       std::placeholders::_1))
85     {
86         // Check to see if we have OCC already bound.  If so, just set it
87         if (device.bound())
88         {
89             this->occActive(true);
90         }
91 
92         // Announce that we are ready
93         this->emit_object_added();
94     }
95 
96     /** @brief Since we are overriding the setter-occActive but not the
97      *         getter-occActive, we need to have this using in order to
98      *         allow passthrough usage of the getter-occActive
99      */
100     using Base::Status::occActive;
101 
102     /** @brief SET OccActive to True or False
103      *
104      *  @param[in] value - Intended value
105      *
106      *  @return          - Updated value of the property
107      */
108     bool occActive(bool value) override;
109 
110     /** @brief Starts OCC error detection */
111     inline void addErrorWatch()
112     {
113         return device.addErrorWatch();
114     }
115 
116     /** @brief Stops OCC error detection */
117     inline void removeErrorWatch()
118     {
119         return device.removeErrorWatch();
120     }
121 
122     /** @brief Starts to watch how many OCCs are present on the master */
123     inline void addPresenceWatchMaster()
124     {
125         return device.addPresenceWatchMaster();
126     }
127 
128   private:
129     /** @brief sdbus handle */
130     sdbusplus::bus::bus& bus;
131 
132     /** @brief OCC dbus object path */
133     std::string path;
134 
135     /** @brief Callback handler to be invoked during property change.
136      *         This is a handler in Manager class
137      */
138     std::function<void(bool)> callBack;
139 
140     /** @brief OCC instance number. Ex, 0,1, etc */
141     int instance;
142 
143     /** @brief OCC instance to Sensor ID mapping */
144     static const std::map<instanceID, sensorID> sensorMap;
145 
146     /** @brief OCC device object to do bind and unbind */
147     Device device;
148 
149     /** @brief Subscribe to host control signal
150      *
151      *  Once the OCC reset is requested, BMC sends that message to host.
152      *  If the host does not ack the message, then there would be a timeout
153      *  and we need to catch that to log an error
154      **/
155     sdbusplus::bus::match_t hostControlSignal;
156 
157     /** @brief Callback handler when device errors are detected
158      *
159      *  @param[in]  error - True if an error is reported, false otherwise
160      */
161     void deviceErrorHandler(bool error);
162 
163     /** @brief Callback function on host control signals
164      *
165      *  @param[in]  msg - Data associated with subscribed signal
166      */
167     void hostControlEvent(sdbusplus::message::message& msg);
168 
169     /** @brief Sends a message to host control command handler to reset OCC
170      */
171     void resetOCC();
172 };
173 
174 } // namespace occ
175 } // namespace open_power
176