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