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