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