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( 319 uint16_t stateSetId, InstanceToEffecter& instanceToEffecterMap, 320 CompositeEffecterCount& effecterCount, uint8_t& stateIdPos) 321 { 322 PdrList pdrs{}; 323 324 auto& bus = open_power::occ::utils::getBus(); 325 try 326 { 327 auto method = bus.new_method_call( 328 "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm", 329 "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR"); 330 method.append(tid, static_cast<uint16_t>(PLDM_ENTITY_PROC), stateSetId); 331 332 auto responseMsg = bus.call(method); 333 responseMsg.read(pdrs); 334 } 335 catch (const sdbusplus::exception_t& e) 336 { 337 log<level::ERR>("pldm: Failed to fetch the state effecter PDRs", 338 entry("ERROR=%s", e.what())); 339 } 340 341 if (!pdrs.size()) 342 { 343 log<level::ERR>("pldm: state effecter PDRs not present"); 344 return; 345 } 346 347 bool offsetFound = false; 348 auto stateEffecterPDR = 349 reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data()); 350 auto possibleStatesPtr = stateEffecterPDR->possible_states; 351 for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count; 352 offset++) 353 { 354 auto possibleStates = 355 reinterpret_cast<const state_effecter_possible_states*>( 356 possibleStatesPtr); 357 358 if (possibleStates->state_set_id == stateSetId) 359 { 360 stateIdPos = offset; 361 effecterCount = stateEffecterPDR->composite_effecter_count; 362 offsetFound = true; 363 break; 364 } 365 possibleStatesPtr += sizeof(possibleStates->state_set_id) + 366 sizeof(possibleStates->possible_states_size) + 367 possibleStates->possible_states_size; 368 } 369 370 if (!offsetFound) 371 { 372 return; 373 } 374 375 std::map<uint32_t, EffecterID> entityInstMap{}; 376 for (auto& pdr : pdrs) 377 { 378 auto pdrPtr = 379 reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data()); 380 uint32_t key = pdrPtr->effecter_id; 381 entityInstMap.emplace(key, static_cast<SensorID>(pdrPtr->effecter_id)); 382 } 383 384 open_power::occ::instanceID position = start; 385 for (const auto& pair : entityInstMap) 386 { 387 instanceToEffecterMap.emplace(position, pair.second); 388 position++; 389 } 390 } 391 392 std::vector<uint8_t> Interface::prepareSetEffecterReq( 393 EffecterID effecterId, CompositeEffecterCount effecterCount, 394 uint8_t stateIdPos, uint8_t stateSetValue) 395 { 396 if (!getPldmInstanceId()) 397 { 398 return std::vector<uint8_t>(); 399 } 400 401 std::vector<uint8_t> request( 402 sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) + 403 (effecterCount * sizeof(set_effecter_state_field))); 404 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data()); 405 std::vector<set_effecter_state_field> stateField; 406 407 for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++) 408 { 409 if (effecterPos == stateIdPos) 410 { 411 stateField.emplace_back( 412 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue}); 413 } 414 else 415 { 416 stateField.emplace_back( 417 set_effecter_state_field{PLDM_NO_CHANGE, 0}); 418 } 419 } 420 auto rc = encode_set_state_effecter_states_req( 421 pldmInstanceID.value(), effecterId, effecterCount, stateField.data(), 422 requestMsg); 423 if (rc != PLDM_SUCCESS) 424 { 425 log<level::ERR>("encode set effecter states request returned error ", 426 entry("RC=%d", rc)); 427 request.clear(); 428 } 429 return request; 430 } 431 432 void Interface::resetOCC(open_power::occ::instanceID occInstanceId) 433 { 434 if (open_power::occ::utils::isHostRunning()) 435 { 436 if (!isPDREffecterCacheValid()) 437 { 438 fetchEffecterInfo(PLDM_STATE_SET_BOOT_RESTART_CAUSE, 439 occInstanceToEffecter, OCCEffecterCount, 440 bootRestartPosition); 441 } 442 443 // Find the matching effecter for the OCC instance 444 auto effecterEntry = occInstanceToEffecter.find(occInstanceId); 445 if (effecterEntry == occInstanceToEffecter.end()) 446 { 447 log<level::ERR>( 448 std::format( 449 "pldm: Failed to find a matching effecter for OCC instance {}", 450 occInstanceId) 451 .c_str()); 452 453 return; 454 } 455 456 // Prepare the SetStateEffecterStates request to reset the OCC 457 auto request = prepareSetEffecterReq( 458 effecterEntry->second, OCCEffecterCount, bootRestartPosition, 459 PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET); 460 461 if (request.empty()) 462 { 463 log<level::ERR>( 464 "pldm: SetStateEffecterStates OCC reset request empty"); 465 return; 466 } 467 468 // Send request to reset the OCCs/PM Complex (ignore response) 469 sendPldm(request, occInstanceId, false); 470 } 471 else 472 { 473 log<level::ERR>( 474 std::format("resetOCC: HOST is not running (OCC{})", occInstanceId) 475 .c_str()); 476 clearData(); 477 } 478 } 479 480 void Interface::sendHRESET(open_power::occ::instanceID sbeInstanceId) 481 { 482 if (open_power::occ::utils::isHostRunning()) 483 { 484 if (sbeInstanceToEffecter.empty()) 485 { 486 fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE, 487 sbeInstanceToEffecter, SBEEffecterCount, 488 sbeMaintenanceStatePosition); 489 } 490 491 auto effecterEntry = sbeInstanceToEffecter.find(sbeInstanceId); 492 if (effecterEntry == sbeInstanceToEffecter.end()) 493 { 494 log<level::ERR>( 495 "pldm: Failed to find a matching effecter for SBE instance", 496 entry("SBE=%d", sbeInstanceId)); 497 return; 498 } 499 500 // Prepare the SetStateEffecterStates request to HRESET the SBE 501 auto request = prepareSetEffecterReq( 502 effecterEntry->second, SBEEffecterCount, 503 sbeMaintenanceStatePosition, SBE_RETRY_REQUIRED); 504 505 if (request.empty()) 506 { 507 log<level::ERR>( 508 "pldm: SetStateEffecterStates HRESET request empty"); 509 return; 510 } 511 512 // Send request to issue HRESET of SBE (ignore response) 513 sendPldm(request, sbeInstanceId, false); 514 outstandingHResets.insert(sbeInstanceId); 515 } 516 else 517 { 518 log<level::ERR>(std::format("sendHRESET: HOST is not running (OCC{})", 519 sbeInstanceId) 520 .c_str()); 521 clearData(); 522 } 523 } 524 525 bool Interface::getPldmInstanceId() 526 { 527 pldm_instance_id_t id; 528 if (!pldmInstanceID) 529 { 530 // Request new instance ID 531 int rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid, &id); 532 if (rc == -EAGAIN) 533 { 534 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 535 rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid, &id); 536 } 537 538 if (rc) 539 { 540 log<level::ERR>( 541 std::format( 542 "getPldmInstanceId: Failed to alloc ID for TID {}. RC{}", 543 tid, rc) 544 .c_str()); 545 return false; 546 } 547 pldmInstanceID.emplace(id); 548 if (!throttleTraces) 549 { 550 log<level::INFO>( 551 std::format("got id {} and set PldmInstanceId to {}", id, 552 pldmInstanceID.value()) 553 .c_str()); 554 } 555 } 556 return true; 557 } 558 559 void Interface::freePldmInstanceId() 560 { 561 if (pldmInstanceID) 562 { 563 int rc = pldm_instance_id_free(pldmInstanceIdDb, tid, 564 pldmInstanceID.value()); 565 if (rc) 566 { 567 log<level::ERR>( 568 std::format( 569 "freePldmInstanceId: Failed to free ID {} for TID {}. RC{}", 570 pldmInstanceID.value(), tid, rc) 571 .c_str()); 572 return; 573 } 574 if (!throttleTraces) 575 { 576 log<level::INFO>( 577 std::format("Freed PLDM instance ID {}", pldmInstanceID.value()) 578 .c_str()); 579 } 580 pldmInstanceID = std::nullopt; 581 } 582 } 583 584 int Interface::openMctpDemuxTransport() 585 { 586 mctpDemux = nullptr; 587 int rc = pldm_transport_mctp_demux_init(&mctpDemux); 588 if (rc) 589 { 590 log<level::ERR>( 591 std::format( 592 "openMctpDemuxTransport: Failed to init MCTP demux transport, errno={}/{}", 593 rc, strerror(rc)) 594 .c_str()); 595 return -1; 596 } 597 598 if (pldm_transport_mctp_demux_map_tid(mctpDemux, mctpEid, mctpEid)) 599 { 600 log<level::ERR>( 601 std::format( 602 "openMctpDemuxTransport: Failed to setup tid to eid mapping, errno={}/{}", 603 errno, strerror(errno)) 604 .c_str()); 605 pldmClose(); 606 return -1; 607 } 608 pldmTransport = pldm_transport_mctp_demux_core(mctpDemux); 609 610 struct pollfd pollfd; 611 if (pldm_transport_mctp_demux_init_pollfd(pldmTransport, &pollfd)) 612 { 613 log<level::ERR>( 614 std::format( 615 "openMctpDemuxTransport: Failed to get pollfd , errno={}/{}", 616 errno, strerror(errno)) 617 .c_str()); 618 pldmClose(); 619 return -1; 620 } 621 pldmFd = pollfd.fd; 622 if (!throttleTraces) 623 { 624 log<level::INFO>( 625 std::format("openMctpDemuxTransport: pldmFd has fd={}", pldmFd) 626 .c_str()); 627 } 628 return 0; 629 } 630 631 int Interface::pldmOpen() 632 { 633 if (pldmTransport) 634 { 635 log<level::ERR>( 636 std::format("pldmOpen: pldmTransport already setup!, errno={}/{}", 637 errno, strerror(errno)) 638 .c_str()); 639 return -1; 640 } 641 return openMctpDemuxTransport(); 642 } 643 644 void Interface::sendPldm(const std::vector<uint8_t>& request, 645 const uint8_t instance, const bool rspExpected) 646 { 647 if (!pldmInstanceID) 648 { 649 log<level::ERR>("sendPldm: No PLDM Instance ID found!"); 650 return; 651 } 652 653 auto rc = pldmOpen(); 654 if (rc) 655 { 656 log<level::ERR>( 657 std::format("sendPldm: pldmOpen failed rc={}", rc).c_str()); 658 freePldmInstanceId(); 659 return; 660 } 661 662 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid); 663 // Send the PLDM request message to HBRT 664 if (rspExpected) 665 { 666 // Register callback when response is available 667 registerPldmRspCallback(); 668 669 // Send PLDM request 670 if (!throttleTraces) 671 { 672 log<level::INFO>( 673 std::format( 674 "sendPldm: calling pldm_transport_send_msg(OCC{}, instance:{}, {} bytes)", 675 instance, pldmInstanceID.value(), request.size()) 676 .c_str()); 677 } 678 pldmResponseReceived = false; 679 pldmResponseTimeout = false; 680 pldmResponseOcc = instance; 681 auto pldmRc = pldm_transport_send_msg(pldmTransport, pldmTID, 682 request.data(), request.size()); 683 auto sendErrno = errno; 684 if (pldmRc != PLDM_REQUESTER_SUCCESS) 685 { 686 log<level::ERR>( 687 std::format( 688 "sendPldm: pldm_transport_send_msg failed with rc={} and errno={}/{}", 689 static_cast< 690 std::underlying_type_t<pldm_requester_error_codes>>( 691 pldmRc), 692 sendErrno, strerror(sendErrno)) 693 .c_str()); 694 pldmClose(); 695 return; 696 } 697 698 // start timer waiting for the response 699 using namespace std::literals::chrono_literals; 700 pldmRspTimer.restartOnce(8s); 701 702 // Wait for response/timeout 703 } 704 else // not expecting the response 705 { 706 if (!throttleTraces) 707 { 708 log<level::INFO>( 709 std::format( 710 "sendPldm: calling pldm_transport_send_msg(mctpID:{}, fd:{}, {} bytes) for OCC{}", 711 mctpEid, pldmFd, request.size(), instance) 712 .c_str()); 713 } 714 auto rc = pldm_transport_send_msg(pldmTransport, pldmTID, 715 request.data(), request.size()); 716 auto sendErrno = errno; 717 if (rc) 718 { 719 log<level::ERR>( 720 std::format( 721 "sendPldm: pldm_transport_send_msg(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}", 722 mctpEid, pldmFd, request.size(), 723 static_cast< 724 std::underlying_type_t<pldm_requester_error_codes>>(rc), 725 sendErrno, strerror(sendErrno)) 726 .c_str()); 727 } 728 pldmClose(); 729 } 730 } 731 732 // Attaches the FD to event loop and registers the callback handler 733 void Interface::registerPldmRspCallback() 734 { 735 decltype(eventSource.get()) sourcePtr = nullptr; 736 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN, 737 pldmRspCallback, this); 738 if (rc < 0) 739 { 740 log<level::ERR>( 741 std::format( 742 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}", 743 rc, strerror(-rc), pldmFd) 744 .c_str()); 745 } 746 else 747 { 748 // puts sourcePtr in the event source. 749 eventSource.reset(sourcePtr); 750 } 751 } 752 753 // Add a timer to the event loop, default 30s. 754 void Interface::pldmRspExpired() 755 { 756 if (!pldmResponseReceived) 757 { 758 if (!throttleTraces) 759 { 760 log<level::WARNING>( 761 std::format( 762 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}", 763 pldmResponseOcc) 764 .c_str()); 765 } 766 pldmResponseTimeout = true; 767 if (pldmFd) 768 { 769 pldmClose(); 770 } 771 } 772 return; 773 }; 774 775 void Interface::pldmClose() 776 { 777 freePldmInstanceId(); 778 if (pldmRspTimer.isEnabled()) 779 { 780 // stop PLDM response timer 781 pldmRspTimer.setEnabled(false); 782 } 783 784 pldm_transport_mctp_demux_destroy(mctpDemux); 785 mctpDemux = NULL; 786 pldmFd = -1; 787 pldmTransport = NULL; 788 eventSource.reset(); 789 } 790 791 int Interface::pldmRspCallback(sd_event_source* /*es*/, 792 __attribute__((unused)) int fd, uint32_t revents, 793 void* userData) 794 { 795 if (!(revents & EPOLLIN)) 796 { 797 log<level::INFO>( 798 std::format("pldmRspCallback - revents={:08X}", revents).c_str()); 799 return -1; 800 } 801 802 auto pldmIface = static_cast<Interface*>(userData); 803 804 if (!pldmIface->pldmInstanceID) 805 { 806 log<level::ERR>( 807 "pldmRspCallback: No outstanding PLDM Instance ID found"); 808 return -1; 809 } 810 811 uint8_t* responseMsg = nullptr; 812 size_t responseMsgSize{}; 813 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid); 814 815 if (!throttleTraces) 816 { 817 log<level::INFO>( 818 std::format( 819 "pldmRspCallback: calling pldm_transport_recv_msg() instance:{}", 820 pldmIface->pldmInstanceID.value()) 821 .c_str()); 822 } 823 auto rc = pldm_transport_recv_msg(pldmIface->pldmTransport, &pldmTID, 824 (void**)&responseMsg, &responseMsgSize); 825 int lastErrno = errno; 826 if (rc) 827 { 828 if (!throttleTraces) 829 { 830 log<level::ERR>( 831 std::format( 832 "pldmRspCallback: pldm_transport_recv_msg failed with rc={}, errno={}/{}", 833 static_cast< 834 std::underlying_type_t<pldm_requester_error_codes>>(rc), 835 lastErrno, strerror(lastErrno)) 836 .c_str()); 837 } 838 return -1; 839 } 840 841 // We got the response for the PLDM request msg that was sent 842 if (!throttleTraces) 843 { 844 log<level::INFO>( 845 std::format( 846 "pldmRspCallback: pldm_transport_recv_msg() rsp was {} bytes", 847 responseMsgSize) 848 .c_str()); 849 } 850 851 if (pldmIface->pldmRspTimer.isEnabled()) 852 { 853 // stop PLDM response timer 854 pldmIface->pldmRspTimer.setEnabled(false); 855 } 856 857 // instance ID should be freed 858 pldmIface->pldmInstanceID = std::nullopt; 859 860 // Set pointer to autodelete 861 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{ 862 responseMsg, std::free}; 863 864 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get()); 865 if (response->payload[0] != PLDM_SUCCESS) 866 { 867 log<level::ERR>( 868 std::format("pldmRspCallback: payload[0] was not success: {}", 869 response->payload[0]) 870 .c_str()); 871 pldmIface->pldmClose(); 872 return -1; 873 } 874 875 // Decode the response 876 uint8_t compCode = 0, sensorCount = 1; 877 get_sensor_state_field field[6]; 878 responseMsgSize -= sizeof(pldm_msg_hdr); 879 auto msgRc = decode_get_state_sensor_readings_resp( 880 response, responseMsgSize, &compCode, &sensorCount, field); 881 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS)) 882 { 883 log<level::ERR>( 884 std::format( 885 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}", 886 msgRc, compCode) 887 .c_str()); 888 pldmIface->pldmClose(); 889 return -1; 890 } 891 892 pldmIface->pldmClose(); 893 894 const uint8_t instance = pldmIface->pldmResponseOcc; 895 const uint8_t occSensorState = field[0].present_state; 896 pldmIface->pldmResponseReceived = true; 897 898 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE) 899 { 900 log<level::INFO>( 901 std::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str()); 902 pldmIface->callBack(instance, true); 903 } 904 else if (occSensorState == 905 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT) 906 { 907 log<level::ERR>( 908 std::format( 909 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE", 910 instance) 911 .c_str()); 912 913 // Setting safe mode true 914 pldmIface->safeModeCallBack(true); 915 916 pldmIface->callBack(instance, false); 917 } 918 else if (occSensorState == 919 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED) 920 { 921 log<level::INFO>( 922 std::format("pldmRspCallback: OCC{} is not running", instance) 923 .c_str()); 924 pldmIface->callBack(instance, false); 925 } 926 else 927 { 928 const size_t rspLength = responseMsgSize + sizeof(pldm_msg_hdr); 929 std::vector<std::uint8_t> pldmResponse(rspLength); 930 memcpy(&pldmResponse[0], reinterpret_cast<std::uint8_t*>(response), 931 rspLength); 932 if (!throttleTraces) 933 { 934 log<level::WARNING>( 935 std::format( 936 "pldmRspCallback: Unexpected State: {} - PLDM response ({} bytes) for OCC{}:", 937 occSensorState, rspLength, instance) 938 .c_str()); 939 dump_hex(pldmResponse); 940 } 941 } 942 943 return 0; 944 }; 945 946 std::vector<uint8_t> 947 Interface::encodeGetStateSensorRequest(uint8_t instance, uint16_t sensorId) 948 { 949 if (!getPldmInstanceId()) 950 { 951 log<level::ERR>( 952 "encodeGetStateSensorRequest: failed to getPldmInstanceId"); 953 return std::vector<uint8_t>(); 954 } 955 956 bitfield8_t sRearm = {0}; 957 const size_t msgSize = 958 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES; 959 std::vector<uint8_t> request(msgSize); 960 961 auto msg = reinterpret_cast<pldm_msg*>(request.data()); 962 auto msgRc = encode_get_state_sensor_readings_req(pldmInstanceID.value(), 963 sensorId, sRearm, 0, msg); 964 if (msgRc != PLDM_SUCCESS) 965 { 966 log<level::ERR>( 967 std::format( 968 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})", 969 sensorId, instance, msgRc) 970 .c_str()); 971 } 972 return request; 973 } 974 975 // Initiate query of the specified OCC Active Sensor 976 void Interface::checkActiveSensor(uint8_t instance) 977 { 978 static bool tracedOnce = false; 979 if (pldmFd > 0) 980 { 981 if (!throttleTraces && !tracedOnce) 982 { 983 log<level::WARNING>( 984 std::format( 985 "checkActiveSensor: already waiting on OCC{} (fd={})", 986 pldmResponseOcc, pldmFd) 987 .c_str()); 988 tracedOnce = true; 989 } 990 return; 991 } 992 tracedOnce = false; 993 994 if (!isOCCSensorCacheValid()) 995 { 996 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS, 997 sensorToOCCInstance, OCCSensorOffset); 998 } 999 1000 // look up sensor id (key) based on instance 1001 auto entry = std::find_if( 1002 sensorToOCCInstance.begin(), sensorToOCCInstance.end(), 1003 [instance](const auto& entry) { return instance == entry.second; }); 1004 if (entry != sensorToOCCInstance.end()) 1005 { 1006 // Query the OCC Active Sensor state for this instance 1007 if (!throttleTraces) 1008 { 1009 log<level::INFO>( 1010 std::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}", 1011 instance, entry->first) 1012 .c_str()); 1013 } 1014 1015 // Encode GetStateSensorReadings PLDM message 1016 auto request = encodeGetStateSensorRequest(instance, entry->first); 1017 if (request.empty()) 1018 { 1019 return; 1020 } 1021 1022 // Send request to PLDM and setup callback for response 1023 sendPldm(request, instance, true); 1024 } 1025 else 1026 { 1027 if (!throttleTraces) 1028 { 1029 log<level::ERR>( 1030 std::format( 1031 "checkActiveSensor: Unable to find PLDM sensor for OCC{}", 1032 instance) 1033 .c_str()); 1034 log<level::INFO>( 1035 "checkActiveSensor: fetching STATE_SET_OPERATIONAL_RUNNING_STATUS"); 1036 } 1037 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS, 1038 sensorToOCCInstance, OCCSensorOffset); 1039 } 1040 } 1041 1042 void Interface::setTraceThrottle(const bool throttle) 1043 { 1044 if (throttle != throttleTraces) 1045 { 1046 if (throttle) 1047 { 1048 log<level::WARNING>("PLDM traces being throttled"); 1049 } 1050 else 1051 { 1052 log<level::INFO>("PLDM traces no longer being throttled"); 1053 } 1054 throttleTraces = throttle; 1055 } 1056 } 1057 1058 } // namespace pldm 1059