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