1 #pragma once 2 3 #include "occ_events.hpp" 4 #include "occ_status.hpp" 5 #include "utils.hpp" 6 7 #include <libpldm/instance-id.h> 8 #include <libpldm/pldm.h> 9 #include <libpldm/transport.h> 10 #include <libpldm/transport/af-mctp.h> 11 #include <libpldm/transport/mctp-demux.h> 12 13 #include <sdbusplus/bus/match.hpp> 14 #include <sdeventplus/event.hpp> 15 #include <sdeventplus/utility/timer.hpp> 16 17 enum pldm_msg_type 18 { 19 MSG_UNDEFINED = 0, 20 MSG_SENSOR_STATUS = 1, 21 MSG_OCC_RESET = 2, 22 MSG_HRESET = 3 23 }; 24 25 namespace pldm 26 { 27 28 namespace MatchRules = sdbusplus::bus::match::rules; 29 using namespace open_power::occ; 30 31 using CompositeEffecterCount = uint8_t; 32 using EffecterID = uint16_t; 33 using EntityType = uint16_t; 34 using EntityInstance = uint16_t; 35 using EventState = uint8_t; 36 using InstanceToEffecter = std::map<open_power::occ::instanceID, EffecterID>; 37 using PdrList = std::vector<std::vector<uint8_t>>; 38 using SensorID = uint16_t; 39 using SensorOffset = uint8_t; 40 using SensorToInstance = std::map<SensorID, open_power::occ::instanceID>; 41 using TerminusID = uint8_t; 42 43 /** @brief OCC instance starts with 0 for example "occ0" */ 44 constexpr open_power::occ::instanceID start = 0; 45 46 /** @brief Hardcoded mctpEid for HBRT */ 47 constexpr mctp_eid_t mctpEid = 10; 48 49 /** @brief Hardcoded TID */ 50 constexpr TerminusID tid = mctpEid; 51 52 /** @class Interface 53 * 54 * @brief Abstracts the PLDM details related to the OCC 55 */ 56 class Interface 57 { 58 public: 59 Interface() = delete; 60 //~Interface() = default; 61 Interface(const Interface&) = delete; 62 Interface& operator=(const Interface&) = delete; 63 Interface(Interface&&) = delete; 64 Interface& operator=(Interface&&) = delete; 65 66 /** @brief Constructs the PLDM Interface object for OCC functions 67 * 68 * @param[in] occActiveCallBack - callBack handler to invoke when the OCC 69 * state changes. 70 * @param[in] sbeCallBack - callBack handler to invoke when the SBE 71 * state changes. 72 * @param[in] safeModeCallBack - callBack handler to invoke when the 73 * system is in safe mode. 74 * @param[in] poweredOffCallBack - callBack handler to invoke when the 75 * host is powered off. 76 */ Interface(std::function<bool (open_power::occ::instanceID,bool)> occActiveCallBack,std::function<void (open_power::occ::instanceID,bool)> sbeCallBack,std::function<void (bool)> safeModeCallBack,std::function<void ()> poweredOffCallBack,EventPtr & event)77 explicit Interface( 78 std::function<bool(open_power::occ::instanceID, bool)> 79 occActiveCallBack, 80 std::function<void(open_power::occ::instanceID, bool)> sbeCallBack, 81 std::function<void(bool)> safeModeCallBack, 82 std::function<void()> poweredOffCallBack, EventPtr& event) : 83 occActiveCallBack(occActiveCallBack), sbeCallBack(sbeCallBack), 84 safeModeCallBack(safeModeCallBack), 85 poweredOffCallBack(poweredOffCallBack), event(event), 86 pldmEventSignal( 87 open_power::occ::utils::getBus(), 88 MatchRules::type::signal() + 89 MatchRules::member("StateSensorEvent") + 90 MatchRules::path("/xyz/openbmc_project/pldm") + 91 MatchRules::interface("xyz.openbmc_project.PLDM.Event"), 92 std::bind(std::mem_fn(&Interface::sensorEvent), this, 93 std::placeholders::_1)), 94 hostStateSignal( 95 open_power::occ::utils::getBus(), 96 MatchRules::propertiesChanged("/xyz/openbmc_project/state/host0", 97 "xyz.openbmc_project.State.Host"), 98 std::bind(std::mem_fn(&Interface::hostStateEvent), this, 99 std::placeholders::_1)), 100 sdpEvent(sdeventplus::Event::get_default()), 101 pldmRspTimer( 102 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>( 103 sdpEvent, std::bind(&Interface::pldmRspExpired, this))) 104 { 105 int rc = pldm_instance_db_init_default(&pldmInstanceIdDb); 106 if (rc) 107 { 108 throw std::system_category().default_error_condition(rc); 109 } 110 } 111 ~Interface()112 ~Interface() 113 { 114 int rc = pldm_instance_db_destroy(pldmInstanceIdDb); 115 if (rc) 116 { 117 std::cout << "pldm_instance_db_destroy failed, rc =" << rc << "\n"; 118 } 119 } 120 121 /** @brief Fetch the state sensor PDRs and populate the cache with 122 * sensorId to OCC/SBE instance mapping information and the sensor 123 * offset for the relevent state set. 124 * 125 * @param[in] stateSetId - the state set ID to look for 126 * @param[out] sensorInstanceMap - map of sensorID to instance 127 * @param[out] sensorOffset - sensor offset of interested state set ID 128 */ 129 void fetchSensorInfo(uint16_t stateSetId, 130 SensorToInstance& sensorInstanceMap, 131 SensorOffset& sensorOffset); 132 133 /** @brief Fetch the OCC/SBE state effecter PDRs and populate the cache 134 * with OCC/SBE instance to EffecterID information. 135 * 136 * @param[in] stateSetId - the state set ID to look for 137 * @param[out] instanceToEffecterMap - map of instance to effecterID 138 * @param[out] count - sensor offset of interested state set ID 139 * @param[out] stateIdPos - position of the stateSetID 140 */ 141 void fetchEffecterInfo(uint16_t stateSetId, 142 InstanceToEffecter& instanceToEffecterMap, 143 CompositeEffecterCount& count, uint8_t& stateIdPos); 144 145 /** @brief Prepare the request for SetStateEffecterStates command 146 * 147 * @param[in] effecterId - the instance effecter ID 148 * @param[in] effecterCount - compositeEffecterCount for the effecter PDR 149 * @param[in] stateIdPos - position of the stateSetID 150 * @param[in] stateSetValue - the value to set the state set to 151 * 152 * @return PLDM request message to be sent to host for OCC reset or SBE 153 * HRESET, empty response in the case of failure. 154 */ 155 std::vector<uint8_t> prepareSetEffecterReq( 156 EffecterID effecterId, CompositeEffecterCount effecterCount, 157 uint8_t stateIdPos, uint8_t stateSetValue); 158 159 /** @brief Send the PLDM message to reset the OCC 160 * 161 * @param[in] instanceId - OCC instance to reset 162 * 163 */ 164 void resetOCC(open_power::occ::instanceID occInstanceId); 165 166 /** @brief Send the PLDM message to perform the HRESET 167 * 168 * @param[in] instanceID - SBE instance to HRESET 169 */ 170 void sendHRESET(open_power::occ::instanceID sbeInstanceId); 171 172 /** @brief Check if the OCC active sensor is available 173 * On successful read, the Manager callback will be called to update 174 * the status 175 * 176 * @param[in] instance - OCC instance to check 177 */ 178 void checkActiveSensor(uint8_t instance); 179 180 /** @brief Set the throttleTraces flag 181 * 182 * @param[in] throttle - Flag to indicate if traces should be throttled 183 */ 184 void setTraceThrottle(const bool throttle); 185 186 private: 187 /** @brief PLDM instance ID database object used to get instance IDs 188 */ 189 pldm_instance_db* pldmInstanceIdDb = nullptr; 190 191 /** @brief PLDM instance number used in PLDM requests 192 */ 193 std::optional<uint8_t> pldmInstanceID; 194 195 /** @brief Callback handler to be invoked when the state of the OCC 196 * changes 197 */ 198 std::function<bool(open_power::occ::instanceID, bool)> occActiveCallBack = 199 nullptr; 200 201 /** @brief Callback handler to be invoked when the maintenance state of the 202 * SBE changes 203 */ 204 std::function<void(open_power::occ::instanceID, bool)> sbeCallBack = 205 nullptr; 206 207 /** @brief Callback handler to be invoked when the OCC is in SAFE Mode = 208 * true or when OCCs are in_service = false. 209 */ 210 std::function<void(bool)> safeModeCallBack = nullptr; 211 212 /** @brief Callback handler to be invoked when the host is powered off */ 213 std::function<void()> poweredOffCallBack = nullptr; 214 215 /** @brief reference to sd_event wrapped in unique_ptr */ 216 EventPtr& event; 217 218 /** @brief event source wrapped in unique_ptr */ 219 EventSourcePtr eventSource; 220 221 /** @brief Used to subscribe to D-Bus PLDM StateSensorEvent signal and 222 * processes if the event corresponds to OCC state change. 223 */ 224 sdbusplus::bus::match_t pldmEventSignal; 225 226 /** @brief Used to subscribe for host state change signal */ 227 sdbusplus::bus::match_t hostStateSignal; 228 229 /** @brief PLDM Sensor ID to OCC Instance mapping 230 */ 231 SensorToInstance sensorToOCCInstance; 232 233 /** @brief PLDM Sensor ID to SBE Instance mapping 234 */ 235 SensorToInstance sensorToSBEInstance; 236 237 /** @brief Sensor offset of OCC state set ID 238 * PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS in state sensor PDR. 239 */ 240 SensorOffset OCCSensorOffset = 0; 241 242 /** @brief Sensor offset of the SBE state set ID 243 * PLDM_OEM_IBM_SBE_HRESET_STATE in state sensor PDR. 244 */ 245 SensorOffset SBESensorOffset = 0; 246 247 /** @brief OCC Instance mapping to PLDM Effecter ID 248 */ 249 InstanceToEffecter occInstanceToEffecter; 250 251 /** @brief SBE instance mapping to PLDM Effecter ID 252 */ 253 InstanceToEffecter sbeInstanceToEffecter; 254 255 /** @brief compositeEffecterCount for OCC reset state effecter PDR */ 256 CompositeEffecterCount OCCEffecterCount = 0; 257 258 /** @brief compositeEffecterCount for SBE HRESET state effecter PDR */ 259 CompositeEffecterCount SBEEffecterCount = 0; 260 261 /** @brief Position of Boot/Restart Cause stateSetID in OCC state 262 * effecter PDR 263 */ 264 uint8_t bootRestartPosition = 0; 265 266 /** @brief Position of the SBE maintenance stateSetID in the state 267 * effecter PDR 268 */ 269 uint8_t sbeMaintenanceStatePosition = 0; 270 271 /** @brief OCC instance number for the PLDM message */ 272 uint8_t pldmResponseOcc = 0; 273 274 /** @brief File descriptor for PLDM messages */ 275 int pldmFd = -1; 276 277 /** pldm transport instance */ 278 struct pldm_transport* pldmTransport = NULL; 279 280 static enum pldm_msg_type msgType; 281 282 union TransportImpl 283 { 284 struct pldm_transport_mctp_demux* mctpDemux; 285 struct pldm_transport_af_mctp* afMctp; 286 }; 287 288 TransportImpl impl; 289 290 /** @brief The response for the PLDM request msg is received flag. 291 */ 292 bool pldmResponseReceived = false; 293 294 /** @brief The response for the PLDM request has timed out. 295 */ 296 bool pldmResponseTimeout = false; 297 298 /** @brief The instance ID for the OCC/HRESET request */ 299 static open_power::occ::instanceID resetInstance; 300 301 /** @brief timer event */ 302 sdeventplus::Event sdpEvent; 303 304 /** @brief Timer that is started when PLDM command is sent 305 */ 306 sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> pldmRspTimer; 307 308 std::set<uint8_t> outstandingHResets; 309 310 /** @brief Flag to indicate that traces should be throttled. 311 Used to limit traces when there are issues getting OCC status. 312 */ 313 static bool throttleTraces; 314 315 /** @brief Callback when PLDM response has not been received within the 316 * timeout period. 317 */ 318 void pldmRspExpired(); 319 320 /** @brief Close the MCTP file */ 321 void pldmClose(); 322 323 /** @brief When the OCC state changes host sends PlatformEventMessage 324 * StateSensorEvent, this function processes the D-Bus signal 325 * with the sensor event information and invokes the callback 326 * to change the OCC state. 327 * 328 * @param[in] msg - data associated with the subscribed signal 329 */ 330 void sensorEvent(sdbusplus::message_t& msg); 331 332 /** @brief When the host state changes and if the CurrentHostState is 333 * xyz.openbmc_project.State.Host.HostState.Off then 334 * the cache of OCC sensors and effecters mapping is cleared. 335 * 336 * @param[in] msg - data associated with the subscribed signal 337 */ 338 void hostStateEvent(sdbusplus::message_t& msg); 339 340 /** @brief Called when it is determined that the Host is not running. 341 * The cache of OCC sensors and effecters mapping is cleared. 342 */ 343 void clearData(); 344 345 /** @brief Check if the PDR cache for PLDM OCC sensors is valid 346 * 347 * @return true if cache is populated and false if the cache is not 348 * populated. 349 */ isOCCSensorCacheValid()350 auto isOCCSensorCacheValid() 351 { 352 return (sensorToOCCInstance.empty() ? false : true); 353 } 354 355 /** @brief Check if the PDR cache for PLDM OCC effecters is valid 356 * 357 * @return true if cache is populated and false if the cache is not 358 * populated. 359 */ isPDREffecterCacheValid()360 auto isPDREffecterCacheValid() 361 { 362 return (occInstanceToEffecter.empty() ? false : true); 363 } 364 365 /** @brief Get a PLDM requester instance id 366 * 367 * @return true if the id was found and false if not 368 */ 369 bool getPldmInstanceId(); 370 371 /** @brief Free PLDM requester instance id */ 372 void freePldmInstanceId(); 373 374 /** @brief Encode a GetStateSensor command into a PLDM request 375 * @param[in] instance - OCC instance number 376 * @param[in] sensorId - OCC Active sensor ID number 377 * 378 * @return request - The encoded PLDM messsage to be sent 379 */ 380 std::vector<uint8_t> encodeGetStateSensorRequest(uint8_t instance, 381 uint16_t sensorId); 382 383 /** @brief setup PLDM transport for sending and receiving PLDM messages. 384 * 385 * @return true on success, otherwise return false 386 */ 387 int pldmOpen(void); 388 389 /** @brief Opens the MCTP socket for sending and receiving messages. 390 * 391 * @return 0 on success, otherwise returns a negative error code 392 */ 393 int openMctpDemuxTransport(); 394 395 /** @brief Opens the MCTP AF_MCTP for sending and receiving messages. 396 * 397 * @return 0 on success, otherwise returns a negative error code 398 */ 399 int openAfMctpTransport(); 400 401 /** @brief Send the PLDM request 402 * 403 * @param[in] request - the request data 404 * @param[in] rspExpected - false: no need to wait for the response 405 * true: will need to process response in callback 406 */ 407 void sendPldm(const std::vector<uint8_t>& request, const uint8_t instance, 408 const bool rspExpected = false); 409 410 /** @brief Register a callback function to handle the PLDM response */ 411 void registerPldmRspCallback(); 412 413 /** @brief callback for the PLDM response event 414 * 415 * @param[in] es - Populated event source 416 * @param[in] fd - Associated File descriptor 417 * @param[in] revents - Type of event 418 * @param[in] userData - User data that was passed during registration 419 * 420 * @return - 0 or positive number on success and negative 421 * errno otherwise 422 */ 423 static int pldmRspCallback(sd_event_source* es, int fd, uint32_t revents, 424 void* userData); 425 426 /** @brief callback for a OCC / HRESET response event 427 * 428 * @param[in] es - Populated event source 429 * @param[in] fd - Associated File descriptor 430 * @param[in] revents - Type of event 431 * @param[in] userData - User data that was passed during registration 432 * 433 * @return - 0 or positive number on success and negative 434 * errno otherwise 435 */ 436 static int pldmResetCallback(sd_event_source* /*es*/, 437 __attribute__((unused)) int fd, 438 uint32_t revents, void* userData); 439 }; 440 441 } // namespace pldm 442 443 template <> 444 struct std::formatter<enum pldm_msg_type> : formatter<int> 445 { formatstd::formatter446 auto format(enum pldm_msg_type m, format_context& ctx) const 447 { 448 return formatter<int>::format(std::to_underlying(m), ctx); 449 } 450 }; 451