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