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