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