1 #pragma once 2 #include "config.h" 3 4 #include "i2c_occ.hpp" 5 #include "occ_command.hpp" 6 #include "occ_device.hpp" 7 #include "occ_events.hpp" 8 #include "powermode.hpp" 9 #include "utils.hpp" 10 11 #include <org/open_power/Control/Host/server.hpp> 12 #include <org/open_power/OCC/Status/server.hpp> 13 #include <sdbusplus/bus.hpp> 14 #include <sdbusplus/server/object.hpp> 15 #ifdef POWER10 16 #include <sdeventplus/event.hpp> 17 #include <sdeventplus/utility/timer.hpp> 18 #endif 19 20 #include <functional> 21 22 namespace open_power 23 { 24 namespace occ 25 { 26 27 class Manager; 28 namespace Base = sdbusplus::org::open_power::OCC::server; 29 using Interface = sdbusplus::server::object::object<Base::Status>; 30 31 // IPMID's host control application 32 namespace Control = sdbusplus::org::open_power::Control::server; 33 34 // For waiting on signals 35 namespace sdbusRule = sdbusplus::bus::match::rules; 36 37 // OCC status instance. Ex. for "occ0", the instance is 0 38 using instanceID = int; 39 40 // IPMI sensor ID for a given OCC instance 41 using sensorID = uint8_t; 42 43 // Human readable sensor name for DBus tree. E.g. "CPU0_OCC" 44 using sensorName = std::string; 45 46 // OCC sensors definitions in the map 47 using sensorDefs = std::tuple<sensorID, sensorName>; 48 49 // OCC sysfs name prefix 50 const std::string sysfsName = "occ-hwmon"; 51 52 /** @class Status 53 * @brief Implementation of OCC Active Status 54 */ 55 class Status : public Interface 56 { 57 public: 58 Status() = delete; 59 ~Status() = default; 60 Status(const Status&) = delete; 61 Status& operator=(const Status&) = delete; 62 Status(Status&&) = default; 63 Status& operator=(Status&&) = default; 64 65 /** @brief Constructs the Status object and 66 * the underlying device object 67 * 68 * @param[in] event - sd_event unique pointer reference 69 * @param[in] path - DBus object path 70 * @param[in] manager - OCC manager instance 71 * @param[in] callBack - Callback handler to invoke during 72 * property change 73 * @param[in] resetCallBack - callback handler to invoke for resetting the 74 * OCC if PLDM is the host communication 75 * protocol 76 */ 77 Status(EventPtr& event, const char* path, Manager& managerRef, 78 #ifdef POWER10 79 std::unique_ptr<open_power::occ::powermode::PowerMode>& powerModeRef, 80 #endif 81 std::function<void(bool)> callBack = nullptr 82 #ifdef PLDM 83 , 84 std::function<void(instanceID)> resetCallBack = nullptr 85 #endif 86 ) : 87 88 Interface(utils::getBus(), getDbusPath(path).c_str(), true), 89 path(path), callBack(callBack), instance(getInstance(path)), 90 manager(managerRef), 91 #ifdef POWER10 92 pmode(powerModeRef), 93 #endif 94 device(event, 95 #ifdef I2C_OCC 96 fs::path(DEV_PATH) / i2c_occ::getI2cDeviceName(path), 97 #else 98 fs::path(DEV_PATH) / 99 fs::path(sysfsName + "." + std::to_string(instance + 1)), 100 #endif 101 managerRef, *this, instance), 102 hostControlSignal( 103 utils::getBus(), 104 sdbusRule::type::signal() + sdbusRule::member("CommandComplete") + 105 sdbusRule::path("/org/open_power/control/host0") + 106 sdbusRule::interface("org.open_power.Control.Host") + 107 sdbusRule::argN(0, Control::convertForMessage( 108 Control::Host::Command::OCCReset)), 109 std::bind(std::mem_fn(&Status::hostControlEvent), this, 110 std::placeholders::_1)), 111 occCmd(instance, (fs::path(OCC_CONTROL_ROOT) / 112 (std::string(OCC_NAME) + std::to_string(instance))) 113 .c_str()) 114 #ifdef POWER10 115 , 116 sdpEvent(sdeventplus::Event::get_default()), 117 safeStateDelayTimer( 118 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>( 119 sdpEvent, std::bind(&Status::safeStateDelayExpired, this))) 120 #endif 121 #ifdef PLDM 122 , 123 resetCallBack(resetCallBack) 124 #endif 125 { 126 // Check to see if we have OCC already bound. If so, just set it 127 if (device.bound()) 128 { 129 this->occActive(true); 130 } 131 132 // Announce that we are ready 133 this->emit_object_added(); 134 } 135 136 /** @brief Since we are overriding the setter-occActive but not the 137 * getter-occActive, we need to have this using in order to 138 * allow passthrough usage of the getter-occActive 139 */ 140 using Base::Status::occActive; 141 142 /** @brief SET OccActive to True or False 143 * 144 * @param[in] value - Intended value 145 * 146 * @return - Updated value of the property 147 */ 148 bool occActive(bool value) override; 149 150 /** @brief Starts OCC error detection */ 151 inline void addErrorWatch() 152 { 153 return device.addErrorWatch(); 154 } 155 156 /** @brief Stops OCC error detection */ 157 inline void removeErrorWatch() 158 { 159 return device.removeErrorWatch(); 160 } 161 162 /** @brief Starts to watch how many OCCs are present on the master */ 163 inline void addPresenceWatchMaster() 164 { 165 return device.addPresenceWatchMaster(); 166 } 167 168 /** @brief Gets the occ instance number */ 169 unsigned int getOccInstanceID() 170 { 171 return instance; 172 } 173 174 /** @brief Is this OCC the master OCC */ 175 bool isMasterOcc() 176 { 177 return device.master(); 178 } 179 180 /** @brief Read OCC state (will trigger kernel to poll the OCC) */ 181 void readOccState(); 182 183 /** @brief Called when device errors are detected */ 184 void deviceError(); 185 186 #ifdef POWER10 187 /** @brief Handle additional tasks when the OCCs reach active state */ 188 void occsWentActive(); 189 190 /** @brief Send Ambient & Altitude data to OCC 191 * 192 * @param[in] ambient - temperature to send (0xFF will force read 193 * of current temperature and altitude) 194 * @param[in] altitude - altitude to send (0xFFFF = unavailable) 195 * 196 * @return SUCCESS on success 197 */ 198 CmdStatus sendAmbient(const uint8_t ambient = 0xFF, 199 const uint16_t altitude = 0xFFFF); 200 #endif // POWER10 201 202 private: 203 /** @brief OCC dbus object path */ 204 std::string path; 205 206 /** @brief Callback handler to be invoked during property change. 207 * This is a handler in Manager class 208 */ 209 std::function<void(bool)> callBack; 210 211 /** @brief OCC instance number. Ex, 0,1, etc */ 212 unsigned int instance; 213 214 /** @brief The last state read from the OCC */ 215 unsigned int lastState = 0; 216 217 /** @brief OCC instance to Sensor definitions mapping */ 218 static const std::map<instanceID, sensorDefs> sensorMap; 219 220 /** @brief OCC manager object */ 221 const Manager& manager; 222 223 #ifdef POWER10 224 /** @brief OCC PowerMode object */ 225 std::unique_ptr<open_power::occ::powermode::PowerMode>& pmode; 226 #endif 227 228 /** @brief OCC device object to do bind and unbind */ 229 Device device; 230 231 /** @brief Subscribe to host control signal 232 * 233 * Once the OCC reset is requested, BMC sends that message to host. 234 * If the host does not ack the message, then there would be a timeout 235 * and we need to catch that to log an error 236 **/ 237 sdbusplus::bus::match_t hostControlSignal; 238 239 /** @brief Command object to send commands to the OCC */ 240 OccCommand occCmd; 241 242 #ifdef POWER10 243 /** @brief timer event */ 244 sdeventplus::Event sdpEvent; 245 #endif 246 247 /** @brief Callback function on host control signals 248 * 249 * @param[in] msg - Data associated with subscribed signal 250 */ 251 void hostControlEvent(sdbusplus::message::message& msg); 252 253 /** @brief Sends a message to host control command handler to reset OCC 254 */ 255 void resetOCC(); 256 257 /** @brief Determines the instance ID by specified object path. 258 * @param[in] path Estimated OCC Dbus object path 259 * @return Instance number 260 */ 261 static int getInstance(const std::string& path) 262 { 263 return (path.empty() ? 0 : path.back() - '0'); 264 } 265 266 #ifdef POWER10 267 /** 268 * @brief Timer that is started when OCC is detected to be in safe mode 269 */ 270 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> 271 safeStateDelayTimer; 272 273 /** @brief Callback for timer that is started when OCC was detected to be in 274 * safe mode. Called to verify and then disable and reset the OCCs. 275 */ 276 void safeStateDelayExpired(); 277 #endif // POWER10 278 279 /** @brief Override the sensor name with name from the definition. 280 * @param[in] estimatedPath - Estimated OCC Dbus object path 281 * @return Fixed OCC DBus object path 282 */ 283 static std::string getDbusPath(const std::string& estimatedPath) 284 { 285 if (!estimatedPath.empty()) 286 { 287 auto it = sensorMap.find(getInstance(estimatedPath)); 288 if (sensorMap.end() != it) 289 { 290 auto& name = std::get<1>(it->second); 291 if (!name.empty() && name != "None") 292 { 293 auto objectPath = fs::path(estimatedPath); 294 objectPath.replace_filename(name); 295 return objectPath.string(); 296 } 297 } 298 } 299 300 return estimatedPath; 301 } 302 #ifdef PLDM 303 std::function<void(instanceID)> resetCallBack = nullptr; 304 #endif 305 }; 306 307 } // namespace occ 308 } // namespace open_power 309