1 #include "pldm.hpp" 2 3 #include "libpldm/instance-id.h" 4 5 #include "file.hpp" 6 7 #include <libpldm/entity.h> 8 #include <libpldm/oem/ibm/state_set.h> 9 #include <libpldm/platform.h> 10 #include <libpldm/state_set.h> 11 #include <libpldm/transport.h> 12 #include <libpldm/transport/af-mctp.h> 13 #include <libpldm/transport/mctp-demux.h> 14 #include <poll.h> 15 16 #include <phosphor-logging/lg2.hpp> 17 #include <sdbusplus/bus.hpp> 18 #include <sdeventplus/clock.hpp> 19 #include <sdeventplus/exception.hpp> 20 #include <sdeventplus/source/io.hpp> 21 #include <sdeventplus/source/time.hpp> 22 23 #include <algorithm> 24 25 namespace pldm 26 { 27 28 using namespace sdeventplus; 29 using namespace sdeventplus::source; 30 constexpr auto clockId = sdeventplus::ClockId::RealTime; 31 using Clock = sdeventplus::Clock<clockId>; 32 using Timer = Time<clockId>; 33 bool Interface::throttleTraces = false; 34 enum pldm_msg_type Interface::msgType = MSG_UNDEFINED; 35 open_power::occ::instanceID Interface::resetInstance = 0; 36 fetchSensorInfo(uint16_t stateSetId,SensorToInstance & sensorInstanceMap,SensorOffset & sensorOffset)37 void Interface::fetchSensorInfo(uint16_t stateSetId, 38 SensorToInstance& sensorInstanceMap, 39 SensorOffset& sensorOffset) 40 { 41 PdrList pdrs{}; 42 static bool tracedError = false; 43 44 auto& bus = open_power::occ::utils::getBus(); 45 try 46 { 47 auto method = bus.new_method_call( 48 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm", 49 "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR"); 50 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId); 51 52 auto responseMsg = bus.call(method); 53 responseMsg.read(pdrs); 54 } 55 catch (const sdbusplus::exception_t& e) 56 { 57 if (!tracedError) 58 { 59 lg2::error( 60 "fetchSensorInfo: Failed to find stateSetID:{ID} PDR: {ERR}", 61 "ID", stateSetId, "ERR", e.what()); 62 tracedError = true; 63 } 64 } 65 66 if (pdrs.empty()) 67 { 68 if (!tracedError) 69 { 70 lg2::error("fetchSensorInfo: state sensor PDRs ({ID}) not present", 71 "ID", stateSetId); 72 tracedError = true; 73 } 74 return; 75 } 76 77 // Found PDR 78 if (tracedError) 79 { 80 lg2::info("fetchSensorInfo: found {NUM} PDRs", "NUM", pdrs.size()); 81 tracedError = false; 82 } 83 84 bool offsetFound = false; 85 auto stateSensorPDR = 86 reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data()); 87 auto possibleStatesPtr = stateSensorPDR->possible_states; 88 for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count; 89 offset++) 90 { 91 auto possibleStates = 92 reinterpret_cast<const state_sensor_possible_states*>( 93 possibleStatesPtr); 94 95 if (possibleStates->state_set_id == stateSetId) 96 { 97 sensorOffset = offset; 98 offsetFound = true; 99 break; 100 } 101 possibleStatesPtr += sizeof(possibleStates->state_set_id) + 102 sizeof(possibleStates->possible_states_size) + 103 possibleStates->possible_states_size; 104 } 105 106 if (!offsetFound) 107 { 108 lg2::error("pldm: state sensor PDR not found"); 109 return; 110 } 111 112 // To order SensorID based on the EntityInstance. 113 // Note that when a proc is on a DCM, the PDRs for these sensors 114 // could have the same instance IDs but different container IDs. 115 std::map<uint32_t, SensorID> entityInstMap{}; 116 for (auto& pdr : pdrs) 117 { 118 auto pdrPtr = 119 reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data()); 120 uint32_t key = pdrPtr->sensor_id; 121 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->sensor_id)); 122 } 123 124 open_power::occ::instanceID count = start; 125 for (const auto& pair : entityInstMap) 126 { 127 sensorInstanceMap.emplace(pair.second, count); 128 count++; 129 } 130 } 131 sensorEvent(sdbusplus::message_t & msg)132 void Interface::sensorEvent(sdbusplus::message_t& msg) 133 { 134 if (!isOCCSensorCacheValid()) 135 { 136 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS, 137 sensorToOCCInstance, OCCSensorOffset); 138 } 139 140 if (sensorToSBEInstance.empty()) 141 { 142 fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSBEInstance, 143 SBESensorOffset); 144 } 145 146 TerminusID sensorTid{}; 147 SensorID sensorId{}; 148 SensorOffset msgSensorOffset{}; 149 EventState eventState{}; 150 EventState previousEventState{}; 151 152 msg.read(sensorTid, sensorId, msgSensorOffset, eventState, 153 previousEventState); 154 155 if (msgSensorOffset == OCCSensorOffset) 156 { 157 auto sensorEntry = sensorToOCCInstance.find(sensorId); 158 159 if (sensorEntry != sensorToOCCInstance.end()) 160 { 161 const uint8_t instance = sensorEntry->second; 162 bool validEvent = true; 163 bool isRunning = false; 164 if (eventState == 165 static_cast<EventState>( 166 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)) 167 { 168 lg2::info("PLDM: OCC{INST} is RUNNING", "INST", instance); 169 isRunning = true; 170 } 171 else if (eventState == 172 static_cast<EventState>( 173 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED)) 174 { 175 lg2::info("PLDM: OCC{INST} has now STOPPED", "INST", instance); 176 } 177 else if (eventState == 178 static_cast<EventState>( 179 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT)) 180 { 181 lg2::error( 182 "PLDM: OCC{INST} has now STOPPED and system is in SAFE MODE", 183 "INST", instance); 184 185 // Setting safe mode true 186 safeModeCallBack(true); 187 } 188 else 189 { 190 lg2::warning( 191 "PLDM: Unexpected OCC Active sensor state {STATE} for OCC{INST}", 192 "STATE", eventState, "INST", instance); 193 validEvent = false; 194 } 195 if (validEvent) 196 { 197 if ((pldmFd > 0) && (instance == pldmResponseOcc)) 198 { 199 // Waiting for a response for this OCC, can stop waiting 200 pldmClose(); 201 } 202 occActiveCallBack(instance, isRunning); 203 } 204 return; 205 } 206 } 207 208 if (msgSensorOffset == SBESensorOffset) 209 { 210 auto sensorEntry = sensorToSBEInstance.find(sensorId); 211 212 if (sensorEntry != sensorToSBEInstance.end()) 213 { 214 const uint8_t instance = sensorEntry->second; 215 auto match = std::find(outstandingHResets.begin(), 216 outstandingHResets.end(), instance); 217 if (match != outstandingHResets.end()) 218 { 219 outstandingHResets.erase(match); 220 if (eventState == static_cast<EventState>(SBE_HRESET_NOT_READY)) 221 { 222 lg2::error("pldm: HRESET is NOT READY (OCC{INST})", "INST", 223 instance); 224 // Stop OCC comm - OCC not usable until it becomes READY 225 occActiveCallBack(instance, false); 226 // Collect SBE FFDC 227 sbeCallBack(instance, false); 228 // Try PM Complex reset 229 lg2::error( 230 "sensorEvent: Requesting OCC reset for OCC{INST}", 231 "INST", instance); 232 resetOCC(resetInstance); 233 } 234 else if (eventState == 235 static_cast<EventState>(SBE_HRESET_READY)) 236 { 237 sbeCallBack(instance, true); 238 } 239 else if (eventState == 240 static_cast<EventState>(SBE_HRESET_FAILED)) 241 { 242 sbeCallBack(instance, false); 243 } 244 else 245 { 246 if (eventState == 247 static_cast<EventState>(SBE_HRESET_FAILED)) 248 lg2::error( 249 "pldm: Unexpected HRESET state {STATE} (OCC{INST})", 250 "STATE", eventState, "INST", instance); 251 sbeCallBack(instance, false); 252 } 253 } 254 // else request was not from us 255 } 256 } 257 } 258 hostStateEvent(sdbusplus::message_t & msg)259 void Interface::hostStateEvent(sdbusplus::message_t& msg) 260 { 261 std::map<std::string, std::variant<std::string>> properties{}; 262 std::string interface; 263 msg.read(interface, properties); 264 const auto stateEntry = properties.find("CurrentHostState"); 265 if (stateEntry != properties.end()) 266 { 267 auto stateEntryValue = stateEntry->second; 268 auto propVal = std::get<std::string>(stateEntryValue); 269 if (propVal == "xyz.openbmc_project.State.Host.HostState.Off") 270 { 271 clearData(); 272 } 273 } 274 } 275 clearData()276 void Interface::clearData() 277 { 278 if (!sensorToOCCInstance.empty()) 279 { 280 lg2::info("clearData: Clearing sensorToOCCInstance ({NUM} entries)", 281 "NUM", sensorToOCCInstance.size()); 282 for (auto entry : sensorToOCCInstance) 283 { 284 lg2::info("clearData: OCC{INST} / sensorID: {ID}", "INST", 285 entry.second, "ID", lg2::hex, entry.first); 286 occActiveCallBack(entry.second, false); 287 } 288 sensorToOCCInstance.clear(); 289 } 290 if (!occInstanceToEffecter.empty()) 291 { 292 lg2::debug("clearData: Clearing occInstanceToEffecter ({NUM} entries)", 293 "NUM", occInstanceToEffecter.size()); 294 occInstanceToEffecter.clear(); 295 } 296 if (!sensorToSBEInstance.empty()) 297 { 298 lg2::debug("clearData: Clearing sensorToSBEInstance ({NUM} entries)", 299 "NUM", sensorToSBEInstance.size()); 300 sensorToSBEInstance.clear(); 301 } 302 if (!sbeInstanceToEffecter.empty()) 303 { 304 lg2::debug("clearData: Clearing sbeInstanceToEffecter ({NUM} entries)", 305 "NUM", sbeInstanceToEffecter.size()); 306 sbeInstanceToEffecter.clear(); 307 } 308 } 309 fetchEffecterInfo(uint16_t stateSetId,InstanceToEffecter & instanceToEffecterMap,CompositeEffecterCount & effecterCount,uint8_t & stateIdPos)310 void Interface::fetchEffecterInfo( 311 uint16_t stateSetId, InstanceToEffecter& instanceToEffecterMap, 312 CompositeEffecterCount& effecterCount, uint8_t& stateIdPos) 313 { 314 PdrList pdrs{}; 315 316 auto& bus = open_power::occ::utils::getBus(); 317 try 318 { 319 auto method = bus.new_method_call( 320 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm", 321 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR"); 322 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId); 323 324 auto responseMsg = bus.call(method); 325 responseMsg.read(pdrs); 326 } 327 catch (const sdbusplus::exception_t& e) 328 { 329 lg2::error("pldm: Failed to fetch the state effecter PDRs: {ERR}", 330 "ERR", e.what()); 331 } 332 333 if (!pdrs.size()) 334 { 335 lg2::error("pldm: state effecter PDRs not present"); 336 return; 337 } 338 339 bool offsetFound = false; 340 auto stateEffecterPDR = 341 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data()); 342 auto possibleStatesPtr = stateEffecterPDR->possible_states; 343 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count; 344 offset++) 345 { 346 auto possibleStates = 347 reinterpret_cast<const state_effecter_possible_states*>( 348 possibleStatesPtr); 349 350 if (possibleStates->state_set_id == stateSetId) 351 { 352 stateIdPos = offset; 353 effecterCount = stateEffecterPDR->composite_effecter_count; 354 offsetFound = true; 355 break; 356 } 357 possibleStatesPtr += sizeof(possibleStates->state_set_id) + 358 sizeof(possibleStates->possible_states_size) + 359 possibleStates->possible_states_size; 360 } 361 362 if (!offsetFound) 363 { 364 return; 365 } 366 367 std::map<uint32_t, EffecterID> entityInstMap{}; 368 for (auto& pdr : pdrs) 369 { 370 auto pdrPtr = 371 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data()); 372 uint32_t key = pdrPtr->effecter_id; 373 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id)); 374 } 375 376 open_power::occ::instanceID position = start; 377 for (const auto& pair : entityInstMap) 378 { 379 instanceToEffecterMap.emplace(position, pair.second); 380 position++; 381 } 382 } 383 prepareSetEffecterReq(EffecterID effecterId,CompositeEffecterCount effecterCount,uint8_t stateIdPos,uint8_t stateSetValue)384 std::vector<uint8_t> Interface::prepareSetEffecterReq( 385 EffecterID effecterId, CompositeEffecterCount effecterCount, 386 uint8_t stateIdPos, uint8_t stateSetValue) 387 { 388 if (!getPldmInstanceId()) 389 { 390 return std::vector<uint8_t>(); 391 } 392 393 std::vector<uint8_t> request( 394 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) + 395 (effecterCount * sizeof(set_effecter_state_field))); 396 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data()); 397 std::vector<set_effecter_state_field> stateField; 398 399 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++) 400 { 401 if (effecterPos == stateIdPos) 402 { 403 stateField.emplace_back( 404 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue}); 405 } 406 else 407 { 408 stateField.emplace_back( 409 set_effecter_state_field{PLDM_NO_CHANGE, 0}); 410 } 411 } 412 auto rc = encode_set_state_effecter_states_req( 413 pldmInstanceID.value(), effecterId, effecterCount, stateField.data(), 414 requestMsg); 415 if (rc != PLDM_SUCCESS) 416 { 417 lg2::error("encode set effecter states request returned error rc={RC}", 418 "RC", rc); 419 request.clear(); 420 } 421 return request; 422 } 423 resetOCC(open_power::occ::instanceID occInstanceId)424 void Interface::resetOCC(open_power::occ::instanceID occInstanceId) 425 { 426 if (open_power::occ::utils::isHostRunning()) 427 { 428 if (!isPDREffecterCacheValid()) 429 { 430 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE, 431 occInstanceToEffecter, OCCEffecterCount, 432 bootRestartPosition); 433 } 434 435 // Find the matching effecter for the OCC instance 436 auto effecterEntry = occInstanceToEffecter.find(occInstanceId); 437 if (effecterEntry == occInstanceToEffecter.end()) 438 { 439 lg2::error( 440 "pldm: Failed to find a matching effecter for OCC instance {INST}", 441 "INST", occInstanceId); 442 443 return; 444 } 445 446 // Prepare the SetStateEffecterStates request to reset the OCC 447 auto request = prepareSetEffecterReq( 448 effecterEntry->second, OCCEffecterCount, bootRestartPosition, 449 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET); 450 451 if (request.empty()) 452 { 453 lg2::error("pldm: SetStateEffecterStates OCC reset request empty"); 454 return; 455 } 456 457 // Send request to reset the OCCs/PM Complex (and wait for response) 458 msgType = MSG_OCC_RESET; 459 resetInstance = occInstanceId; 460 sendPldm(request, occInstanceId, true); 461 } 462 else 463 { 464 lg2::error("resetOCC: HOST is not running (OCC{INST})", "INST", 465 occInstanceId); 466 clearData(); 467 } 468 } 469 sendHRESET(open_power::occ::instanceID sbeInstanceId)470 void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId) 471 { 472 if (open_power::occ::utils::isHostRunning()) 473 { 474 if (sbeInstanceToEffecter.empty()) 475 { 476 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE, 477 sbeInstanceToEffecter, SBEEffecterCount, 478 sbeMaintenanceStatePosition); 479 } 480 481 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId); 482 if (effecterEntry == sbeInstanceToEffecter.end()) 483 { 484 lg2::error( 485 "pldm: Failed to find a matching effecter for SBE instance {INST}", 486 "INST", sbeInstanceId); 487 return; 488 } 489 490 // Prepare the SetStateEffecterStates request to HRESET the SBE 491 auto request = prepareSetEffecterReq( 492 effecterEntry->second, SBEEffecterCount, 493 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED); 494 495 if (request.empty()) 496 { 497 lg2::error("pldm: SetStateEffecterStates HRESET request empty"); 498 return; 499 } 500 501 // Send request to issue HRESET of SBE (and wait for response) 502 msgType = MSG_HRESET; 503 resetInstance = sbeInstanceId; 504 sendPldm(request, sbeInstanceId, true); 505 outstandingHResets.insert(sbeInstanceId); 506 } 507 else 508 { 509 lg2::error("sendHRESET: HOST is not running (OCC{INST})", "INST", 510 sbeInstanceId); 511 clearData(); 512 } 513 } 514 getPldmInstanceId()515 bool Interface::getPldmInstanceId() 516 { 517 pldm_instance_id_t id; 518 if (!pldmInstanceID) 519 { 520 // Request new instance ID 521 int rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid, &id); 522 if (rc == -EAGAIN) 523 { 524 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 525 rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid, &id); 526 } 527 528 if (rc) 529 { 530 lg2::error( 531 "getPldmInstanceId: Failed to alloc ID for TID {TID}. RC{RC}", 532 "TID", tid, "RC", rc); 533 return false; 534 } 535 pldmInstanceID.emplace(id); 536 if (!throttleTraces) 537 { 538 lg2::info("got id {ID} and set PldmInstanceId to {INST}", "ID", id, 539 "INST", pldmInstanceID.value()); 540 } 541 } 542 return true; 543 } 544 freePldmInstanceId()545 void Interface::freePldmInstanceId() 546 { 547 if (pldmInstanceID) 548 { 549 int rc = pldm_instance_id_free(pldmInstanceIdDb, tid, 550 pldmInstanceID.value()); 551 if (rc) 552 { 553 lg2::error( 554 "freePldmInstanceId: Failed to free ID {ID} for TID {TID}. RC{RC}", 555 "ID", pldmInstanceID.value(), "TID", tid, "RC", rc); 556 return; 557 } 558 if (!throttleTraces) 559 { 560 lg2::info("Freed PLDM instance ID {ID}", "ID", 561 pldmInstanceID.value()); 562 } 563 pldmInstanceID = std::nullopt; 564 } 565 } 566 openMctpDemuxTransport()567 [[maybe_unused]] int Interface::openMctpDemuxTransport() 568 { 569 impl.mctpDemux = nullptr; 570 int rc = pldm_transport_mctp_demux_init(&impl.mctpDemux); 571 if (rc) 572 { 573 lg2::error( 574 "openMctpDemuxTransport: Failed to init MCTP demux transport, errno={ERR}/{STR}", 575 "ERR", rc, "STR", strerror(rc)); 576 return -1; 577 } 578 579 if (pldm_transport_mctp_demux_map_tid(impl.mctpDemux, mctpEid, mctpEid)) 580 { 581 lg2::error( 582 "openMctpDemuxTransport: Failed to setup tid to eid mapping, errno={ERR}/{STR}", 583 "ERR", errno, "STR", strerror(errno)); 584 pldmClose(); 585 return -1; 586 } 587 pldmTransport = pldm_transport_mctp_demux_core(impl.mctpDemux); 588 589 struct pollfd pollfd; 590 if (pldm_transport_mctp_demux_init_pollfd(pldmTransport, &pollfd)) 591 { 592 lg2::error( 593 "openMctpDemuxTransport: Failed to get pollfd , errno={ERR}/{STR}", 594 "ERR", errno, "STR", strerror(errno)); 595 pldmClose(); 596 return -1; 597 } 598 pldmFd = pollfd.fd; 599 if (!throttleTraces) 600 { 601 lg2::info("openMctpDemuxTransport: pldmFd has fd={FD}", "FD", pldmFd); 602 } 603 return 0; 604 } 605 openAfMctpTransport()606 [[maybe_unused]] int Interface::openAfMctpTransport() 607 { 608 impl.afMctp = nullptr; 609 int rc = pldm_transport_af_mctp_init(&impl.afMctp); 610 if (rc) 611 { 612 lg2::error( 613 "openAfMctpTransport: Failed to init af MCTP transport, errno={ERR}/{STR}", 614 "ERR", rc, "STR", strerror(rc)); 615 return -1; 616 } 617 618 if (pldm_transport_af_mctp_map_tid(impl.afMctp, mctpEid, mctpEid)) 619 { 620 lg2::error( 621 "openAfMctpTransport: Failed to setup tid to eid mapping, errno={ERR}/{STR}", 622 "ERR", errno, "STR", strerror(errno)); 623 pldmClose(); 624 return -1; 625 } 626 pldmTransport = pldm_transport_af_mctp_core(impl.afMctp); 627 628 struct pollfd pollfd; 629 if (pldm_transport_af_mctp_init_pollfd(pldmTransport, &pollfd)) 630 { 631 lg2::error( 632 "openAfMctpTransport: Failed to get pollfd , errno={ERR}/{STR}", 633 "ERR", errno, "STR", strerror(errno)); 634 pldmClose(); 635 return -1; 636 } 637 pldmFd = pollfd.fd; 638 if (!throttleTraces) 639 { 640 lg2::info("openAfMctpTransport: pldmFd has fd={FD}", "FD", pldmFd); 641 } 642 return 0; 643 } 644 pldmOpen()645 int Interface::pldmOpen() 646 { 647 if (pldmTransport) 648 { 649 lg2::error("pldmOpen: pldmTransport already setup!, errno={ERR}/{STR}", 650 "ERR", errno, "STR", strerror(errno)); 651 return -1; 652 } 653 #if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX) 654 return openMctpDemuxTransport(); 655 #elif defined(PLDM_TRANSPORT_WITH_AF_MCTP) 656 return openAfMctpTransport(); 657 #else 658 lg2::error("pldmOpen: Undefined pldmTransport!, errno={ERR}/{STR}", "ERR", 659 errno, "STR", strerror(errno)); 660 return -1; 661 #endif 662 663 return 0; 664 } 665 sendPldm(const std::vector<uint8_t> & request,const uint8_t instance,const bool rspExpected)666 void Interface::sendPldm(const std::vector<uint8_t>& request, 667 const uint8_t instance, const bool rspExpected) 668 { 669 if (!pldmInstanceID) 670 { 671 lg2::error("sendPldm: No PLDM Instance ID found!"); 672 return; 673 } 674 675 auto rc = pldmOpen(); 676 if (rc) 677 { 678 if (!throttleTraces) 679 { 680 lg2::error("sendPldm: pldmOpen failed rc={RC}", "RC", rc); 681 } 682 freePldmInstanceId(); 683 return; 684 } 685 686 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid); 687 // Send the PLDM request message to HBRT 688 if (rspExpected) 689 { 690 // Register callback when response is available 691 registerPldmRspCallback(); 692 693 using namespace std::literals::chrono_literals; 694 std::chrono::duration timeout = 8s; 695 if ((msgType == MSG_OCC_RESET) || (msgType == MSG_HRESET)) 696 { 697 timeout = 30s; 698 } 699 700 // Send PLDM request 701 if (!throttleTraces) 702 { 703 lg2::info("sendPldm: calling pldm_transport_send_msg(OCC{INST}, " 704 "instance:{ID}, {LEN} bytes, timeout {TO})", 705 "INST", instance, "ID", pldmInstanceID.value(), "LEN", 706 request.size(), "TO", timeout.count()); 707 } 708 pldmResponseReceived = false; 709 pldmResponseTimeout = false; 710 pldmResponseOcc = instance; 711 auto pldmRc = pldm_transport_send_msg(pldmTransport, pldmTID, 712 request.data(), request.size()); 713 auto sendErrno = errno; 714 if (pldmRc != PLDM_REQUESTER_SUCCESS) 715 { 716 lg2::error( 717 "sendPldm: pldm_transport_send_msg failed with rc={RC} and errno={ERR}/{STR}", 718 "RC", 719 static_cast<std::underlying_type_t<pldm_requester_error_codes>>( 720 pldmRc), 721 "ERR", sendErrno, "STR", strerror(sendErrno)); 722 pldmClose(); 723 return; 724 } 725 726 // start timer waiting for the response 727 pldmRspTimer.restartOnce(timeout); 728 729 // Wait for response/timeout 730 } 731 else // not expecting the response 732 { 733 if (!throttleTraces) 734 { 735 lg2::info( 736 "sendPldm: calling pldm_transport_send_msg(mctpID:{ID}, fd:{FD}, " 737 "{LEN} bytes) for OCC{INST}", 738 "ID", mctpEid, "FD", pldmFd, "LEN", request.size(), "INST", 739 instance); 740 } 741 auto rc = pldm_transport_send_msg(pldmTransport, pldmTID, 742 request.data(), request.size()); 743 auto sendErrno = errno; 744 if (rc) 745 { 746 lg2::error( 747 "sendPldm: pldm_transport_send_msg(mctpID:{ID}, fd:{FD}, {LEN} bytes) " 748 "failed with rc={RC} and errno={ERR}/{STR}", 749 "ID", mctpEid, "FD", pldmFd, "LEN", request.size(), "RC", 750 static_cast<std::underlying_type_t<pldm_requester_error_codes>>( 751 rc), 752 "ERR", sendErrno, "STR", strerror(sendErrno)); 753 } 754 pldmClose(); 755 } 756 } 757 758 // Attaches the FD to event loop and registers the callback handler registerPldmRspCallback()759 void Interface::registerPldmRspCallback() 760 { 761 decltype(eventSource.get()) sourcePtr = nullptr; 762 int rc = 0; 763 if ((msgType == MSG_OCC_RESET) || (msgType == MSG_HRESET)) 764 { 765 rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN, 766 pldmResetCallback, this); 767 } 768 else 769 { 770 rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN, 771 pldmRspCallback, this); 772 } 773 if (rc < 0) 774 { 775 lg2::error( 776 "registerPldmRspCallback: sd_event_add_io: Error({ERR})={STR} : fd={FD} (msgType={MSG})", 777 "ERR", rc, "STR", strerror(-rc), "FD", pldmFd, "MSG", msgType); 778 } 779 else 780 { 781 // puts sourcePtr in the event source. 782 eventSource.reset(sourcePtr); 783 } 784 } 785 786 // Add a timer to the event loop, default 30s. pldmRspExpired()787 void Interface::pldmRspExpired() 788 { 789 if (!pldmResponseReceived) 790 { 791 if (!throttleTraces) 792 { 793 lg2::warning( 794 "pldmRspExpired: timerCallback - timeout waiting for pldm " 795 "response to msg:{MSG} for OCC{INST}", 796 "MSG", msgType, "INST", pldmResponseOcc); 797 } 798 pldmResponseTimeout = true; 799 if (pldmFd) 800 { 801 pldmClose(); 802 } 803 if (msgType == MSG_OCC_RESET) 804 { 805 // reset not acked, try again 806 lg2::error("pldmRspExpired: retrying reset request for OCC{INST}", 807 "INST", pldmResponseOcc); 808 resetOCC(pldmResponseOcc); 809 } 810 } 811 return; 812 }; 813 pldmClose()814 void Interface::pldmClose() 815 { 816 freePldmInstanceId(); 817 if (pldmRspTimer.isEnabled()) 818 { 819 // stop PLDM response timer 820 pldmRspTimer.setEnabled(false); 821 } 822 823 #if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX) 824 pldm_transport_mctp_demux_destroy(impl.mctpDemux); 825 impl.mctpDemux = NULL; 826 #elif defined(PLDM_TRANSPORT_WITH_AF_MCTP) 827 pldm_transport_af_mctp_destroy(impl.afMctp); 828 impl.afMctp = NULL; 829 #endif 830 pldmFd = -1; 831 pldmTransport = NULL; 832 eventSource.reset(); 833 } 834 pldmRspCallback(sd_event_source *,int fd,uint32_t revents,void * userData)835 int Interface::pldmRspCallback(sd_event_source* /*es*/, 836 __attribute__((unused)) int fd, uint32_t revents, 837 void* userData) 838 { 839 if (!(revents & EPOLLIN)) 840 { 841 lg2::info("pldmRspCallback - revents={NUM}", "NUM", lg2::hex, revents); 842 return -1; 843 } 844 845 auto pldmIface = static_cast<Interface*>(userData); 846 847 if (!pldmIface->pldmInstanceID) 848 { 849 lg2::error("pldmRspCallback: No outstanding PLDM Instance ID found"); 850 return -1; 851 } 852 853 uint8_t* responseMsg = nullptr; 854 size_t responseMsgSize{}; 855 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid); 856 857 if (!throttleTraces) 858 { 859 lg2::info( 860 "pldmRspCallback: calling pldm_transport_recv_msg() instance:{INST}", 861 "INST", pldmIface->pldmInstanceID.value()); 862 } 863 auto rc = pldm_transport_recv_msg(pldmIface->pldmTransport, &pldmTID, 864 (void**)&responseMsg, &responseMsgSize); 865 int lastErrno = errno; 866 if (rc) 867 { 868 if (!throttleTraces) 869 { 870 lg2::error( 871 "pldmRspCallback: pldm_transport_recv_msg failed with rc={RC}, errno={ERR}/{STR}", 872 "RC", 873 static_cast<std::underlying_type_t<pldm_requester_error_codes>>( 874 rc), 875 "ERR", lastErrno, "STR", strerror(lastErrno)); 876 } 877 return -1; 878 } 879 880 // We got the response for the PLDM request msg that was sent 881 if (!throttleTraces) 882 { 883 lg2::info( 884 "pldmRspCallback: pldm_transport_recv_msg() rsp was {LEN} bytes", 885 "LEN", responseMsgSize); 886 } 887 888 if (pldmIface->pldmRspTimer.isEnabled()) 889 { 890 // stop PLDM response timer 891 pldmIface->pldmRspTimer.setEnabled(false); 892 } 893 894 // instance ID should be freed 895 pldmIface->pldmInstanceID = std::nullopt; 896 897 // Set pointer to autodelete 898 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{ 899 responseMsg, std::free}; 900 901 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get()); 902 if (response->payload[0] != PLDM_SUCCESS) 903 { 904 lg2::error("pldmRspCallback: payload[0] was not success: {STATUS}", 905 "STATUS", response->payload[0]); 906 pldmIface->pldmClose(); 907 return -1; 908 } 909 910 // Decode the response 911 uint8_t compCode = 0, sensorCount = 1; 912 get_sensor_state_field field[6]; 913 responseMsgSize -= sizeof(pldm_msg_hdr); 914 auto msgRc = decode_get_state_sensor_readings_resp( 915 response, responseMsgSize, &compCode, &sensorCount, field); 916 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS)) 917 { 918 lg2::error( 919 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={RC} and compCode={CC}", 920 "RC", msgRc, "CC", compCode); 921 pldmIface->pldmClose(); 922 return -1; 923 } 924 925 pldmIface->pldmClose(); 926 927 const uint8_t instance = pldmIface->pldmResponseOcc; 928 const uint8_t occSensorState = field[0].present_state; 929 pldmIface->pldmResponseReceived = true; 930 931 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE) 932 { 933 lg2::info("pldmRspCallback: OCC{INST} is RUNNING", "INST", instance); 934 pldmIface->occActiveCallBack(instance, true); 935 } 936 else if (occSensorState == 937 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT) 938 { 939 lg2::error( 940 "pldmRspCallback: OCC{INST} has now STOPPED and system is in SAFE MODE", 941 "INST", instance); 942 943 // Setting safe mode true 944 pldmIface->safeModeCallBack(true); 945 946 pldmIface->occActiveCallBack(instance, false); 947 } 948 else if (occSensorState == 949 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED) 950 { 951 lg2::info("pldmRspCallback: OCC{INST} is not running", "INST", 952 instance); 953 pldmIface->occActiveCallBack(instance, false); 954 } 955 else 956 { 957 const size_t rspLength = responseMsgSize + sizeof(pldm_msg_hdr); 958 std::vector<std::uint8_t> pldmResponse(rspLength); 959 memcpy(&pldmResponse[0], reinterpret_cast<std::uint8_t*>(response), 960 rspLength); 961 if (!throttleTraces) 962 { 963 lg2::warning( 964 "pldmRspCallback: Unexpected State: {STATE} - PLDM response " 965 "({LEN} bytes) for OCC{INST}:", 966 "STATE", occSensorState, "LEN", rspLength, "INST", instance); 967 dump_hex(pldmResponse); 968 } 969 } 970 971 return 0; 972 }; 973 pldmResetCallback(sd_event_source *,int fd,uint32_t revents,void * userData)974 int Interface::pldmResetCallback(sd_event_source* /*es*/, 975 __attribute__((unused)) int fd, 976 uint32_t revents, void* userData) 977 { 978 if (!(revents & EPOLLIN)) 979 { 980 lg2::info("pldmResetCallback - revents={NUM}", "NUM", lg2::hex, 981 revents); 982 return -1; 983 } 984 985 auto pldmIface = static_cast<Interface*>(userData); 986 987 if (!pldmIface->pldmInstanceID) 988 { 989 lg2::error("pldmResetCallback: No outstanding PLDM Instance ID found"); 990 return -1; 991 } 992 993 uint8_t* responseMsg = nullptr; 994 size_t responseMsgSize{}; 995 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid); 996 997 if (!throttleTraces) 998 { 999 lg2::info( 1000 "pldmResetCallback: calling pldm_transport_recv_msg() instance:{ID}", 1001 "ID", pldmIface->pldmInstanceID.value()); 1002 } 1003 auto rc = pldm_transport_recv_msg(pldmIface->pldmTransport, &pldmTID, 1004 (void**)&responseMsg, &responseMsgSize); 1005 int lastErrno = errno; 1006 if (rc) 1007 { 1008 if (!throttleTraces) 1009 { 1010 lg2::error( 1011 "pldmResetCallback: pldm_transport_recv_msg failed with rc={RC}, errno={ERR}/{STR}", 1012 "RC", 1013 static_cast<std::underlying_type_t<pldm_requester_error_codes>>( 1014 rc), 1015 "ERR", lastErrno, "STR", strerror(lastErrno)); 1016 } 1017 return -1; 1018 } 1019 1020 // We got the response for the PLDM request msg that was sent 1021 if (!throttleTraces) 1022 { 1023 lg2::info( 1024 "pldmResetCallback: pldm_transport_recv_msg() rsp was {LEN} bytes", 1025 "LEN", responseMsgSize); 1026 } 1027 1028 if (pldmIface->pldmRspTimer.isEnabled()) 1029 { 1030 // stop PLDM response timer 1031 pldmIface->pldmRspTimer.setEnabled(false); 1032 } 1033 1034 // instance ID should be freed 1035 pldmIface->pldmInstanceID = std::nullopt; 1036 1037 // Set pointer to autodelete 1038 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{ 1039 responseMsg, std::free}; 1040 1041 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get()); 1042 if (response->payload[0] != PLDM_SUCCESS) 1043 { 1044 lg2::error( 1045 "pldmResetCallback: Reset FAILED ({MSG}) - payload[0] was not success: {STATUS}", 1046 "MSG", msgType, "STATUS", response->payload[0]); 1047 pldmIface->pldmClose(); 1048 1049 if (msgType == MSG_OCC_RESET) 1050 { 1051 // Retry reset request 1052 lg2::error( 1053 "pldmResetCallback: retrying reset request for OCC{INST}", 1054 "INST", resetInstance); 1055 pldmIface->resetOCC(resetInstance); 1056 } 1057 return -1; 1058 } 1059 else 1060 { 1061 lg2::info("pldmResetCallback: Reset has been successfully started"); 1062 } 1063 1064 pldmIface->pldmClose(); 1065 1066 pldmIface->pldmResponseReceived = true; 1067 1068 return 0; 1069 } 1070 1071 std::vector<uint8_t> encodeGetStateSensorRequest(uint8_t instance,uint16_t sensorId)1072 Interface::encodeGetStateSensorRequest(uint8_t instance, uint16_t sensorId) 1073 { 1074 if (!getPldmInstanceId()) 1075 { 1076 lg2::error("encodeGetStateSensorRequest: failed to getPldmInstanceId"); 1077 return std::vector<uint8_t>(); 1078 } 1079 1080 bitfield8_t sRearm = {0}; 1081 const size_t msgSize = 1082 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES; 1083 std::vector<uint8_t> request(msgSize); 1084 1085 auto msg = reinterpret_cast<pldm_msg*>(request.data()); 1086 auto msgRc = encode_get_state_sensor_readings_req(pldmInstanceID.value(), 1087 sensorId, sRearm, 0, msg); 1088 if (msgRc != PLDM_SUCCESS) 1089 { 1090 lg2::error( 1091 "encodeGetStateSensorRequest: Failed to encode sensorId:{ID} for OCC{INST} (rc={RC})", 1092 "ID", lg2::hex, sensorId, "INST", instance, "RC", msgRc); 1093 } 1094 return request; 1095 } 1096 1097 // Initiate query of the specified OCC Active Sensor checkActiveSensor(uint8_t instance)1098 void Interface::checkActiveSensor(uint8_t instance) 1099 { 1100 static bool tracedOnce = false; 1101 if (pldmFd > 0) 1102 { 1103 if (!throttleTraces && !tracedOnce) 1104 { 1105 lg2::warning( 1106 "checkActiveSensor: already waiting on OCC{INST} (fd={FD})", 1107 "INST", pldmResponseOcc, "FD", pldmFd); 1108 tracedOnce = true; 1109 } 1110 return; 1111 } 1112 tracedOnce = false; 1113 1114 if (!isOCCSensorCacheValid()) 1115 { 1116 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS, 1117 sensorToOCCInstance, OCCSensorOffset); 1118 } 1119 1120 // look up sensor id (key) based on instance 1121 auto entry = std::find_if( 1122 sensorToOCCInstance.begin(), sensorToOCCInstance.end(), 1123 [instance](const auto& entry) { return instance == entry.second; }); 1124 if (entry != sensorToOCCInstance.end()) 1125 { 1126 // Query the OCC Active Sensor state for this instance 1127 if (!throttleTraces) 1128 { 1129 lg2::info("checkActiveSensor: OCC{INST} / sensorID: {ID}", "INST", 1130 instance, "ID", lg2::hex, entry->first); 1131 } 1132 1133 // Encode GetStateSensorReadings PLDM message 1134 auto request = encodeGetStateSensorRequest(instance, entry->first); 1135 if (request.empty()) 1136 { 1137 return; 1138 } 1139 1140 // Send request to PLDM and setup callback for response 1141 msgType = MSG_SENSOR_STATUS; 1142 sendPldm(request, instance, true); 1143 } 1144 else 1145 { 1146 if (!throttleTraces) 1147 { 1148 lg2::error( 1149 "checkActiveSensor: Unable to find PLDM sensor for OCC{INST}", 1150 "INST", instance); 1151 lg2::info( 1152 "checkActiveSensor: fetching STATE_SET_OPERATIONAL_RUNNING_STATUS"); 1153 } 1154 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS, 1155 sensorToOCCInstance, OCCSensorOffset); 1156 } 1157 } 1158 setTraceThrottle(const bool throttle)1159 void Interface::setTraceThrottle(const bool throttle) 1160 { 1161 if (throttle != throttleTraces) 1162 { 1163 if (throttle) 1164 { 1165 lg2::warning("PLDM traces being throttled"); 1166 } 1167 else 1168 { 1169 lg2::info("PLDM traces no longer being throttled"); 1170 } 1171 throttleTraces = throttle; 1172 } 1173 } 1174 1175 } // namespace pldm 1176