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