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 if (!throttleTraces) 713 { 714 log<level::ERR>( 715 std::format("sendPldm: pldmOpen failed rc={}", rc).c_str()); 716 } 717 freePldmInstanceId(); 718 return; 719 } 720 721 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid); 722 // Send the PLDM request message to HBRT 723 if (rspExpected) 724 { 725 // Register callback when response is available 726 registerPldmRspCallback(); 727 728 // Send PLDM request 729 if (!throttleTraces) 730 { 731 log<level::INFO>( 732 std::format( 733 "sendPldm: calling pldm_transport_send_msg(OCC{}, instance:{}, {} bytes)", 734 instance, pldmInstanceID.value(), request.size()) 735 .c_str()); 736 } 737 pldmResponseReceived = false; 738 pldmResponseTimeout = false; 739 pldmResponseOcc = instance; 740 auto pldmRc = pldm_transport_send_msg(pldmTransport, pldmTID, 741 request.data(), request.size()); 742 auto sendErrno = errno; 743 if (pldmRc != PLDM_REQUESTER_SUCCESS) 744 { 745 log<level::ERR>( 746 std::format( 747 "sendPldm: pldm_transport_send_msg failed with rc={} and errno={}/{}", 748 static_cast< 749 std::underlying_type_t<pldm_requester_error_codes>>( 750 pldmRc), 751 sendErrno, strerror(sendErrno)) 752 .c_str()); 753 pldmClose(); 754 return; 755 } 756 757 // start timer waiting for the response 758 using namespace std::literals::chrono_literals; 759 pldmRspTimer.restartOnce(8s); 760 761 // Wait for response/timeout 762 } 763 else // not expecting the response 764 { 765 if (!throttleTraces) 766 { 767 log<level::INFO>( 768 std::format( 769 "sendPldm: calling pldm_transport_send_msg(mctpID:{}, fd:{}, {} bytes) for OCC{}", 770 mctpEid, pldmFd, request.size(), instance) 771 .c_str()); 772 } 773 auto rc = pldm_transport_send_msg(pldmTransport, pldmTID, 774 request.data(), request.size()); 775 auto sendErrno = errno; 776 if (rc) 777 { 778 log<level::ERR>( 779 std::format( 780 "sendPldm: pldm_transport_send_msg(mctpID:{}, fd:{}, {} bytes) failed with rc={} and errno={}/{}", 781 mctpEid, pldmFd, request.size(), 782 static_cast< 783 std::underlying_type_t<pldm_requester_error_codes>>(rc), 784 sendErrno, strerror(sendErrno)) 785 .c_str()); 786 } 787 pldmClose(); 788 } 789 } 790 791 // Attaches the FD to event loop and registers the callback handler 792 void Interface::registerPldmRspCallback() 793 { 794 decltype(eventSource.get()) sourcePtr = nullptr; 795 auto rc = sd_event_add_io(event.get(), &sourcePtr, pldmFd, EPOLLIN, 796 pldmRspCallback, this); 797 if (rc < 0) 798 { 799 log<level::ERR>( 800 std::format( 801 "registerPldmRspCallback: sd_event_add_io: Error({})={} : fd={}", 802 rc, strerror(-rc), pldmFd) 803 .c_str()); 804 } 805 else 806 { 807 // puts sourcePtr in the event source. 808 eventSource.reset(sourcePtr); 809 } 810 } 811 812 // Add a timer to the event loop, default 30s. 813 void Interface::pldmRspExpired() 814 { 815 if (!pldmResponseReceived) 816 { 817 if (!throttleTraces) 818 { 819 log<level::WARNING>( 820 std::format( 821 "pldmRspExpired: timerCallback - timeout waiting for pldm response for OCC{}", 822 pldmResponseOcc) 823 .c_str()); 824 } 825 pldmResponseTimeout = true; 826 if (pldmFd) 827 { 828 pldmClose(); 829 } 830 } 831 return; 832 }; 833 834 void Interface::pldmClose() 835 { 836 freePldmInstanceId(); 837 if (pldmRspTimer.isEnabled()) 838 { 839 // stop PLDM response timer 840 pldmRspTimer.setEnabled(false); 841 } 842 843 #if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX) 844 pldm_transport_mctp_demux_destroy(impl.mctpDemux); 845 impl.mctpDemux = NULL; 846 #elif defined(PLDM_TRANSPORT_WITH_AF_MCTP) 847 pldm_transport_af_mctp_destroy(impl.afMctp); 848 impl.afMctp = NULL; 849 #endif 850 pldmFd = -1; 851 pldmTransport = NULL; 852 eventSource.reset(); 853 } 854 855 int Interface::pldmRspCallback(sd_event_source* /*es*/, 856 __attribute__((unused)) int fd, uint32_t revents, 857 void* userData) 858 { 859 if (!(revents & EPOLLIN)) 860 { 861 log<level::INFO>( 862 std::format("pldmRspCallback - revents={:08X}", revents).c_str()); 863 return -1; 864 } 865 866 auto pldmIface = static_cast<Interface*>(userData); 867 868 if (!pldmIface->pldmInstanceID) 869 { 870 log<level::ERR>( 871 "pldmRspCallback: No outstanding PLDM Instance ID found"); 872 return -1; 873 } 874 875 uint8_t* responseMsg = nullptr; 876 size_t responseMsgSize{}; 877 pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid); 878 879 if (!throttleTraces) 880 { 881 log<level::INFO>( 882 std::format( 883 "pldmRspCallback: calling pldm_transport_recv_msg() instance:{}", 884 pldmIface->pldmInstanceID.value()) 885 .c_str()); 886 } 887 auto rc = pldm_transport_recv_msg(pldmIface->pldmTransport, &pldmTID, 888 (void**)&responseMsg, &responseMsgSize); 889 int lastErrno = errno; 890 if (rc) 891 { 892 if (!throttleTraces) 893 { 894 log<level::ERR>( 895 std::format( 896 "pldmRspCallback: pldm_transport_recv_msg failed with rc={}, errno={}/{}", 897 static_cast< 898 std::underlying_type_t<pldm_requester_error_codes>>(rc), 899 lastErrno, strerror(lastErrno)) 900 .c_str()); 901 } 902 return -1; 903 } 904 905 // We got the response for the PLDM request msg that was sent 906 if (!throttleTraces) 907 { 908 log<level::INFO>( 909 std::format( 910 "pldmRspCallback: pldm_transport_recv_msg() rsp was {} bytes", 911 responseMsgSize) 912 .c_str()); 913 } 914 915 if (pldmIface->pldmRspTimer.isEnabled()) 916 { 917 // stop PLDM response timer 918 pldmIface->pldmRspTimer.setEnabled(false); 919 } 920 921 // instance ID should be freed 922 pldmIface->pldmInstanceID = std::nullopt; 923 924 // Set pointer to autodelete 925 std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{ 926 responseMsg, std::free}; 927 928 auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get()); 929 if (response->payload[0] != PLDM_SUCCESS) 930 { 931 log<level::ERR>( 932 std::format("pldmRspCallback: payload[0] was not success: {}", 933 response->payload[0]) 934 .c_str()); 935 pldmIface->pldmClose(); 936 return -1; 937 } 938 939 // Decode the response 940 uint8_t compCode = 0, sensorCount = 1; 941 get_sensor_state_field field[6]; 942 responseMsgSize -= sizeof(pldm_msg_hdr); 943 auto msgRc = decode_get_state_sensor_readings_resp( 944 response, responseMsgSize, &compCode, &sensorCount, field); 945 if ((msgRc != PLDM_SUCCESS) || (compCode != PLDM_SUCCESS)) 946 { 947 log<level::ERR>( 948 std::format( 949 "pldmRspCallback: decode_get_state_sensor_readings failed with rc={} and compCode={}", 950 msgRc, compCode) 951 .c_str()); 952 pldmIface->pldmClose(); 953 return -1; 954 } 955 956 pldmIface->pldmClose(); 957 958 const uint8_t instance = pldmIface->pldmResponseOcc; 959 const uint8_t occSensorState = field[0].present_state; 960 pldmIface->pldmResponseReceived = true; 961 962 if (occSensorState == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE) 963 { 964 log<level::INFO>( 965 std::format("pldmRspCallback: OCC{} is RUNNING", instance).c_str()); 966 pldmIface->callBack(instance, true); 967 } 968 else if (occSensorState == 969 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT) 970 { 971 log<level::ERR>( 972 std::format( 973 "pldmRspCallback: OCC{} has now STOPPED and system is in SAFE MODE", 974 instance) 975 .c_str()); 976 977 // Setting safe mode true 978 pldmIface->safeModeCallBack(true); 979 980 pldmIface->callBack(instance, false); 981 } 982 else if (occSensorState == 983 PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED) 984 { 985 log<level::INFO>( 986 std::format("pldmRspCallback: OCC{} is not running", instance) 987 .c_str()); 988 pldmIface->callBack(instance, false); 989 } 990 else 991 { 992 const size_t rspLength = responseMsgSize + sizeof(pldm_msg_hdr); 993 std::vector<std::uint8_t> pldmResponse(rspLength); 994 memcpy(&pldmResponse[0], reinterpret_cast<std::uint8_t*>(response), 995 rspLength); 996 if (!throttleTraces) 997 { 998 log<level::WARNING>( 999 std::format( 1000 "pldmRspCallback: Unexpected State: {} - PLDM response ({} bytes) for OCC{}:", 1001 occSensorState, rspLength, instance) 1002 .c_str()); 1003 dump_hex(pldmResponse); 1004 } 1005 } 1006 1007 return 0; 1008 }; 1009 1010 std::vector<uint8_t> 1011 Interface::encodeGetStateSensorRequest(uint8_t instance, uint16_t sensorId) 1012 { 1013 if (!getPldmInstanceId()) 1014 { 1015 log<level::ERR>( 1016 "encodeGetStateSensorRequest: failed to getPldmInstanceId"); 1017 return std::vector<uint8_t>(); 1018 } 1019 1020 bitfield8_t sRearm = {0}; 1021 const size_t msgSize = 1022 sizeof(pldm_msg_hdr) + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES; 1023 std::vector<uint8_t> request(msgSize); 1024 1025 auto msg = reinterpret_cast<pldm_msg*>(request.data()); 1026 auto msgRc = encode_get_state_sensor_readings_req(pldmInstanceID.value(), 1027 sensorId, sRearm, 0, msg); 1028 if (msgRc != PLDM_SUCCESS) 1029 { 1030 log<level::ERR>( 1031 std::format( 1032 "encodeGetStateSensorRequest: Failed to encode sensorId:0x{:08X} for OCC{} (rc={})", 1033 sensorId, instance, msgRc) 1034 .c_str()); 1035 } 1036 return request; 1037 } 1038 1039 // Initiate query of the specified OCC Active Sensor 1040 void Interface::checkActiveSensor(uint8_t instance) 1041 { 1042 static bool tracedOnce = false; 1043 if (pldmFd > 0) 1044 { 1045 if (!throttleTraces && !tracedOnce) 1046 { 1047 log<level::WARNING>( 1048 std::format( 1049 "checkActiveSensor: already waiting on OCC{} (fd={})", 1050 pldmResponseOcc, pldmFd) 1051 .c_str()); 1052 tracedOnce = true; 1053 } 1054 return; 1055 } 1056 tracedOnce = false; 1057 1058 if (!isOCCSensorCacheValid()) 1059 { 1060 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS, 1061 sensorToOCCInstance, OCCSensorOffset); 1062 } 1063 1064 // look up sensor id (key) based on instance 1065 auto entry = std::find_if( 1066 sensorToOCCInstance.begin(), sensorToOCCInstance.end(), 1067 [instance](const auto& entry) { return instance == entry.second; }); 1068 if (entry != sensorToOCCInstance.end()) 1069 { 1070 // Query the OCC Active Sensor state for this instance 1071 if (!throttleTraces) 1072 { 1073 log<level::INFO>( 1074 std::format("checkActiveSensor: OCC{} / sensorID: 0x{:04X}", 1075 instance, entry->first) 1076 .c_str()); 1077 } 1078 1079 // Encode GetStateSensorReadings PLDM message 1080 auto request = encodeGetStateSensorRequest(instance, entry->first); 1081 if (request.empty()) 1082 { 1083 return; 1084 } 1085 1086 // Send request to PLDM and setup callback for response 1087 sendPldm(request, instance, true); 1088 } 1089 else 1090 { 1091 if (!throttleTraces) 1092 { 1093 log<level::ERR>( 1094 std::format( 1095 "checkActiveSensor: Unable to find PLDM sensor for OCC{}", 1096 instance) 1097 .c_str()); 1098 log<level::INFO>( 1099 "checkActiveSensor: fetching STATE_SET_OPERATIONAL_RUNNING_STATUS"); 1100 } 1101 fetchSensorInfo(PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS, 1102 sensorToOCCInstance, OCCSensorOffset); 1103 } 1104 } 1105 1106 void Interface::setTraceThrottle(const bool throttle) 1107 { 1108 if (throttle != throttleTraces) 1109 { 1110 if (throttle) 1111 { 1112 log<level::WARNING>("PLDM traces being throttled"); 1113 } 1114 else 1115 { 1116 log<level::INFO>("PLDM traces no longer being throttled"); 1117 } 1118 throttleTraces = throttle; 1119 } 1120 } 1121 1122 } // namespace pldm 1123