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                i2c_occ::getI2cDeviceName(path),
69 #else
70                sysfsName + "." + std::to_string(instance + 1),
71 #endif
72                manager, *this,
73                std::bind(std::mem_fn(&Status::deviceErrorHandler), this,
74                          std::placeholders::_1)),
75         hostControlSignal(
76             bus,
77             sdbusRule::type::signal() + sdbusRule::member("CommandComplete") +
78                 sdbusRule::path("/org/open_power/control/host0") +
79                 sdbusRule::interface("org.open_power.Control.Host") +
80                 sdbusRule::argN(0, Control::convertForMessage(
81                                        Control::Host::Command::OCCReset)),
82             std::bind(std::mem_fn(&Status::hostControlEvent), this,
83                       std::placeholders::_1))
84     {
85         // Check to see if we have OCC already bound.  If so, just set it
86         if (device.bound())
87         {
88             this->occActive(true);
89         }
90 
91         // Announce that we are ready
92         this->emit_object_added();
93     }
94 
95     /** @brief Since we are overriding the setter-occActive but not the
96      *         getter-occActive, we need to have this using in order to
97      *         allow passthrough usage of the getter-occActive
98      */
99     using Base::Status::occActive;
100 
101     /** @brief SET OccActive to True or False
102      *
103      *  @param[in] value - Intended value
104      *
105      *  @return          - Updated value of the property
106      */
107     bool occActive(bool value) override;
108 
109     /** @brief Starts OCC error detection */
110     inline void addErrorWatch()
111     {
112         return device.addErrorWatch();
113     }
114 
115     /** @brief Stops OCC error detection */
116     inline void removeErrorWatch()
117     {
118         return device.removeErrorWatch();
119     }
120 
121     /** @brief Starts to watch how many OCCs are present on the master */
122     inline void addPresenceWatchMaster()
123     {
124         return device.addPresenceWatchMaster();
125     }
126 
127   private:
128     /** @brief sdbus handle */
129     sdbusplus::bus::bus& bus;
130 
131     /** @brief OCC dbus object path */
132     std::string path;
133 
134     /** @brief Callback handler to be invoked during property change.
135      *         This is a handler in Manager class
136      */
137     std::function<void(bool)> callBack;
138 
139     /** @brief OCC instance number. Ex, 0,1, etc */
140     int instance;
141 
142     /** @brief OCC instance to Sensor ID mapping */
143     static const std::map<instanceID, sensorID> sensorMap;
144 
145     /** @brief OCC device object to do bind and unbind */
146     Device device;
147 
148     /** @brief Subscribe to host control signal
149      *
150      *  Once the OCC reset is requested, BMC sends that message to host.
151      *  If the host does not ack the message, then there would be a timeout
152      *  and we need to catch that to log an error
153      **/
154     sdbusplus::bus::match_t hostControlSignal;
155 
156     /** @brief Callback handler when device errors are detected
157      *
158      *  @param[in]  error - True if an error is reported, false otherwise
159      */
160     void deviceErrorHandler(bool error);
161 
162     /** @brief Callback function on host control signals
163      *
164      *  @param[in]  msg - Data associated with subscribed signal
165      */
166     void hostControlEvent(sdbusplus::message::message& msg);
167 
168     /** @brief Sends a message to host control command handler to reset OCC
169      */
170     void resetOCC();
171 };
172 
173 } // namespace occ
174 } // namespace open_power
175