1815f9f55STom Joseph #include "pldm.hpp" 2815f9f55STom Joseph 300325238STom Joseph #include "file.hpp" 400325238STom Joseph 5*a8857c50SChris Cain #include <fmt/core.h> 6815f9f55STom Joseph #include <libpldm/entity.h> 7815f9f55STom Joseph #include <libpldm/platform.h> 8815f9f55STom Joseph #include <libpldm/state_set.h> 9815f9f55STom Joseph 10815f9f55STom Joseph #include <phosphor-logging/log.hpp> 11815f9f55STom Joseph 12815f9f55STom Joseph namespace pldm 13815f9f55STom Joseph { 14815f9f55STom Joseph 15815f9f55STom Joseph using sdbusplus::exception::SdBusError; 16815f9f55STom Joseph using namespace phosphor::logging; 17815f9f55STom Joseph 18815f9f55STom Joseph void Interface::fetchOCCSensorInfo(const PdrList& pdrs, 19815f9f55STom Joseph SensorToOCCInstance& sensorInstanceMap, 20815f9f55STom Joseph SensorOffset& sensorOffset) 21815f9f55STom Joseph { 22815f9f55STom Joseph bool offsetFound = false; 23815f9f55STom Joseph auto pdr = 24815f9f55STom Joseph reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data()); 25815f9f55STom Joseph auto possibleStatesPtr = pdr->possible_states; 26815f9f55STom Joseph for (auto offset = 0; offset < pdr->composite_sensor_count; offset++) 27815f9f55STom Joseph { 28815f9f55STom Joseph auto possibleStates = 29815f9f55STom Joseph reinterpret_cast<const state_sensor_possible_states*>( 30815f9f55STom Joseph possibleStatesPtr); 31815f9f55STom Joseph 32815f9f55STom Joseph if (possibleStates->state_set_id == 33815f9f55STom Joseph PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS) 34815f9f55STom Joseph { 35815f9f55STom Joseph sensorOffset = offset; 36815f9f55STom Joseph offsetFound = true; 37815f9f55STom Joseph break; 38815f9f55STom Joseph } 39815f9f55STom Joseph possibleStatesPtr += sizeof(possibleStates->state_set_id) + 40815f9f55STom Joseph sizeof(possibleStates->possible_states_size) + 41815f9f55STom Joseph possibleStates->possible_states_size; 42815f9f55STom Joseph } 43815f9f55STom Joseph 44815f9f55STom Joseph if (!offsetFound) 45815f9f55STom Joseph { 46815f9f55STom Joseph log<level::ERR>("pldm: OCC state sensor PDR with StateSetId " 47815f9f55STom Joseph "PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS not found"); 48815f9f55STom Joseph return; 49815f9f55STom Joseph } 50815f9f55STom Joseph 51815f9f55STom Joseph // To order SensorID based on the EntityInstance 52815f9f55STom Joseph std::map<EntityInstance, SensorID> entityInstMap{}; 53815f9f55STom Joseph for (auto& pdr : pdrs) 54815f9f55STom Joseph { 55815f9f55STom Joseph auto pdrPtr = 56815f9f55STom Joseph reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data()); 57815f9f55STom Joseph entityInstMap.emplace( 58815f9f55STom Joseph static_cast<EntityInstance>(pdrPtr->entity_instance), 59815f9f55STom Joseph static_cast<SensorID>(pdrPtr->sensor_id)); 60815f9f55STom Joseph } 61815f9f55STom Joseph 62815f9f55STom Joseph open_power::occ::instanceID count = start; 63815f9f55STom Joseph for (auto const& pair : entityInstMap) 64815f9f55STom Joseph { 65815f9f55STom Joseph sensorInstanceMap.emplace(pair.second, count); 66815f9f55STom Joseph count++; 67815f9f55STom Joseph } 68815f9f55STom Joseph } 69815f9f55STom Joseph 70815f9f55STom Joseph void Interface::sensorEvent(sdbusplus::message::message& msg) 71815f9f55STom Joseph { 72815f9f55STom Joseph if (!isOCCSensorCacheValid()) 73815f9f55STom Joseph { 74815f9f55STom Joseph PdrList pdrs{}; 75815f9f55STom Joseph 76815f9f55STom Joseph try 77815f9f55STom Joseph { 78815f9f55STom Joseph auto method = bus.new_method_call( 79815f9f55STom Joseph "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm", 80815f9f55STom Joseph "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR"); 81815f9f55STom Joseph method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE, 82815f9f55STom Joseph (uint16_t)PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS); 83815f9f55STom Joseph 84815f9f55STom Joseph auto responseMsg = bus.call(method); 85815f9f55STom Joseph responseMsg.read(pdrs); 86815f9f55STom Joseph } 87815f9f55STom Joseph catch (const SdBusError& e) 88815f9f55STom Joseph { 89815f9f55STom Joseph log<level::ERR>("pldm: Failed to fetch the OCC state sensor PDRs", 90815f9f55STom Joseph entry("ERROR=%s", e.what())); 91815f9f55STom Joseph } 92815f9f55STom Joseph 93815f9f55STom Joseph if (!pdrs.size()) 94815f9f55STom Joseph { 95815f9f55STom Joseph log<level::ERR>("pldm: OCC state sensor PDRs not present"); 96815f9f55STom Joseph return; 97815f9f55STom Joseph } 98815f9f55STom Joseph 99815f9f55STom Joseph fetchOCCSensorInfo(pdrs, sensorToOCCInstance, sensorOffset); 100815f9f55STom Joseph } 101815f9f55STom Joseph 102815f9f55STom Joseph TerminusID tid{}; 103815f9f55STom Joseph SensorID sensorId{}; 104815f9f55STom Joseph SensorOffset msgSensorOffset{}; 105815f9f55STom Joseph EventState eventState{}; 106815f9f55STom Joseph EventState previousEventState{}; 107815f9f55STom Joseph 108a17f6e8cSGeorge Liu msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState); 109815f9f55STom Joseph 110815f9f55STom Joseph auto sensorEntry = sensorToOCCInstance.find(sensorId); 111815f9f55STom Joseph if (sensorEntry == sensorToOCCInstance.end() || 112815f9f55STom Joseph (msgSensorOffset != sensorOffset)) 113815f9f55STom Joseph { 114815f9f55STom Joseph // No action for non matching sensorEvents 115815f9f55STom Joseph return; 116815f9f55STom Joseph } 117815f9f55STom Joseph 118815f9f55STom Joseph if (eventState == static_cast<EventState>( 119815f9f55STom Joseph PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)) 120815f9f55STom Joseph { 121*a8857c50SChris Cain log<level::INFO>( 122*a8857c50SChris Cain fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second).c_str()); 123*a8857c50SChris Cain callBack(sensorEntry->second, true); 124815f9f55STom Joseph } 125815f9f55STom Joseph else if (eventState == 126815f9f55STom Joseph static_cast<EventState>( 127815f9f55STom Joseph PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED)) 128815f9f55STom Joseph { 129*a8857c50SChris Cain log<level::INFO>( 130*a8857c50SChris Cain fmt::format("PLDM: OCC{} has now STOPPED", sensorEntry->second) 131*a8857c50SChris Cain .c_str()); 132*a8857c50SChris Cain callBack(sensorEntry->second, false); 133815f9f55STom Joseph } 134815f9f55STom Joseph 135815f9f55STom Joseph return; 136815f9f55STom Joseph } 137815f9f55STom Joseph 138815f9f55STom Joseph void Interface::hostStateEvent(sdbusplus::message::message& msg) 139815f9f55STom Joseph { 140815f9f55STom Joseph std::map<std::string, std::variant<std::string>> properties{}; 141815f9f55STom Joseph std::string interface; 142815f9f55STom Joseph msg.read(interface, properties); 143815f9f55STom Joseph const auto stateEntry = properties.find("CurrentHostState"); 144815f9f55STom Joseph if (stateEntry != properties.end()) 145815f9f55STom Joseph { 146815f9f55STom Joseph auto stateEntryValue = stateEntry->second; 147815f9f55STom Joseph auto propVal = std::get<std::string>(stateEntryValue); 148815f9f55STom Joseph if (propVal == "xyz.openbmc_project.State.Host.HostState.Off") 149815f9f55STom Joseph { 150815f9f55STom Joseph sensorToOCCInstance.clear(); 15100325238STom Joseph occInstanceToEffecter.clear(); 152815f9f55STom Joseph } 153815f9f55STom Joseph } 154815f9f55STom Joseph } 155815f9f55STom Joseph 15600325238STom Joseph void Interface::fetchOCCEffecterInfo( 15700325238STom Joseph const PdrList& pdrs, OccInstanceToEffecter& instanceToEffecterMap, 15800325238STom Joseph CompositeEffecterCount& count, uint8_t& bootRestartPos) 15900325238STom Joseph { 16000325238STom Joseph bool offsetFound = false; 16100325238STom Joseph auto pdr = 16200325238STom Joseph reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data()); 16300325238STom Joseph auto possibleStatesPtr = pdr->possible_states; 16400325238STom Joseph for (auto offset = 0; offset < pdr->composite_effecter_count; offset++) 16500325238STom Joseph { 16600325238STom Joseph auto possibleStates = 16700325238STom Joseph reinterpret_cast<const state_effecter_possible_states*>( 16800325238STom Joseph possibleStatesPtr); 16900325238STom Joseph 17000325238STom Joseph if (possibleStates->state_set_id == PLDM_STATE_SET_BOOT_RESTART_CAUSE) 17100325238STom Joseph { 17200325238STom Joseph bootRestartPos = offset; 17300325238STom Joseph effecterCount = pdr->composite_effecter_count; 17400325238STom Joseph offsetFound = true; 17500325238STom Joseph break; 17600325238STom Joseph } 17700325238STom Joseph possibleStatesPtr += sizeof(possibleStates->state_set_id) + 17800325238STom Joseph sizeof(possibleStates->possible_states_size) + 17900325238STom Joseph possibleStates->possible_states_size; 18000325238STom Joseph } 18100325238STom Joseph 18200325238STom Joseph if (!offsetFound) 18300325238STom Joseph { 18400325238STom Joseph return; 18500325238STom Joseph } 18600325238STom Joseph 18700325238STom Joseph std::map<EntityInstance, EffecterID> entityInstMap{}; 18800325238STom Joseph for (auto& pdr : pdrs) 18900325238STom Joseph { 19000325238STom Joseph auto pdrPtr = 19100325238STom Joseph reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data()); 19200325238STom Joseph entityInstMap.emplace( 19300325238STom Joseph static_cast<EntityInstance>(pdrPtr->entity_instance), 19400325238STom Joseph static_cast<SensorID>(pdrPtr->effecter_id)); 19500325238STom Joseph } 19600325238STom Joseph 19700325238STom Joseph open_power::occ::instanceID position = start; 19800325238STom Joseph for (auto const& pair : entityInstMap) 19900325238STom Joseph { 20000325238STom Joseph occInstanceToEffecter.emplace(position, pair.second); 20100325238STom Joseph position++; 20200325238STom Joseph } 20300325238STom Joseph } 20400325238STom Joseph 20500325238STom Joseph std::vector<uint8_t> 20600325238STom Joseph Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId, 20700325238STom Joseph CompositeEffecterCount effecterCount, 20800325238STom Joseph uint8_t bootRestartPos) 20900325238STom Joseph { 21000325238STom Joseph std::vector<uint8_t> request( 21100325238STom Joseph sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) + 21200325238STom Joseph (effecterCount * sizeof(set_effecter_state_field))); 21300325238STom Joseph auto requestMsg = reinterpret_cast<pldm_msg*>(request.data()); 21400325238STom Joseph std::vector<set_effecter_state_field> stateField; 21500325238STom Joseph 21600325238STom Joseph for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++) 21700325238STom Joseph { 21800325238STom Joseph if (effecterPos == bootRestartPos) 21900325238STom Joseph { 22000325238STom Joseph stateField.emplace_back(set_effecter_state_field{ 22100325238STom Joseph PLDM_REQUEST_SET, 22200325238STom Joseph PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET}); 22300325238STom Joseph } 22400325238STom Joseph else 22500325238STom Joseph { 22600325238STom Joseph stateField.emplace_back( 22700325238STom Joseph set_effecter_state_field{PLDM_NO_CHANGE, 0}); 22800325238STom Joseph } 22900325238STom Joseph } 23000325238STom Joseph auto rc = encode_set_state_effecter_states_req( 23100325238STom Joseph instanceId, effecterId, effecterCount, stateField.data(), requestMsg); 23200325238STom Joseph if (rc != PLDM_SUCCESS) 23300325238STom Joseph { 23400325238STom Joseph log<level::ERR>("encode set effecter states request returned error ", 23500325238STom Joseph entry("RC=%d", rc)); 23600325238STom Joseph request.clear(); 23700325238STom Joseph } 23800325238STom Joseph return request; 23900325238STom Joseph } 24000325238STom Joseph 24100325238STom Joseph void Interface::resetOCC(open_power::occ::instanceID occInstanceId) 24200325238STom Joseph { 24300325238STom Joseph if (!isPDREffecterCacheValid()) 24400325238STom Joseph { 24500325238STom Joseph PdrList pdrs{}; 24600325238STom Joseph 24700325238STom Joseph try 24800325238STom Joseph { 24900325238STom Joseph auto method = bus.new_method_call( 25000325238STom Joseph "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm", 25100325238STom Joseph "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR"); 25200325238STom Joseph method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE, 25300325238STom Joseph (uint16_t)PLDM_STATE_SET_BOOT_RESTART_CAUSE); 25400325238STom Joseph 25500325238STom Joseph auto responseMsg = bus.call(method); 25600325238STom Joseph responseMsg.read(pdrs); 25700325238STom Joseph } 25800325238STom Joseph catch (const SdBusError& e) 25900325238STom Joseph { 26000325238STom Joseph log<level::ERR>("pldm: Failed to fetch the OCC state effecter PDRs", 26100325238STom Joseph entry("ERROR=%s", e.what())); 26200325238STom Joseph } 26300325238STom Joseph 26400325238STom Joseph if (!pdrs.size()) 26500325238STom Joseph { 26600325238STom Joseph log<level::ERR>("pldm: OCC state effecter PDRs not present"); 26700325238STom Joseph return; 26800325238STom Joseph } 26900325238STom Joseph 27000325238STom Joseph fetchOCCEffecterInfo(pdrs, occInstanceToEffecter, effecterCount, 27100325238STom Joseph bootRestartPosition); 27200325238STom Joseph } 27300325238STom Joseph 27400325238STom Joseph // Find the matching effecter for the OCC instance 27500325238STom Joseph auto effecterEntry = occInstanceToEffecter.find(occInstanceId); 27600325238STom Joseph if (effecterEntry == occInstanceToEffecter.end()) 27700325238STom Joseph { 27800325238STom Joseph log<level::ERR>( 27900325238STom Joseph "pldm: Failed to find a matching effecter for OCC instance", 28000325238STom Joseph entry("OCC_INSTANCE_ID=%d", occInstanceId)); 28100325238STom Joseph 28200325238STom Joseph return; 28300325238STom Joseph } 28400325238STom Joseph 28500325238STom Joseph uint8_t instanceId{}; 28600325238STom Joseph 28700325238STom Joseph try 28800325238STom Joseph { 28900325238STom Joseph auto method = bus.new_method_call( 29000325238STom Joseph "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm", 29100325238STom Joseph "xyz.openbmc_project.PLDM.Requester", "GetInstanceId"); 29200325238STom Joseph method.append(mctpEid); 29300325238STom Joseph auto reply = bus.call(method); 29400325238STom Joseph reply.read(instanceId); 29500325238STom Joseph } 29600325238STom Joseph catch (const SdBusError& e) 29700325238STom Joseph { 29800325238STom Joseph log<level::ERR>("pldm: GetInstanceId returned error", 29900325238STom Joseph entry("ERROR=%s", e.what())); 30000325238STom Joseph return; 30100325238STom Joseph } 30200325238STom Joseph 30300325238STom Joseph // Prepare the SetStateEffecterStates request to reset the OCC 30400325238STom Joseph auto request = prepareSetEffecterReq(instanceId, effecterEntry->second, 30500325238STom Joseph effecterCount, bootRestartPosition); 30600325238STom Joseph 30700325238STom Joseph if (request.empty()) 30800325238STom Joseph { 30900325238STom Joseph log<level::ERR>("pldm: SetStateEffecterStates request message empty"); 31000325238STom Joseph return; 31100325238STom Joseph } 31200325238STom Joseph 31300325238STom Joseph // Connect to MCTP scoket 31400325238STom Joseph int fd = pldm_open(); 31500325238STom Joseph if (fd == -1) 31600325238STom Joseph { 31700325238STom Joseph log<level::ERR>("pldm: Failed to connect to MCTP socket"); 31800325238STom Joseph return; 31900325238STom Joseph } 32000325238STom Joseph open_power::occ::FileDescriptor fileFd(fd); 32100325238STom Joseph 32200325238STom Joseph // Send the PLDM request message to HBRT 32300325238STom Joseph uint8_t* response = nullptr; 32400325238STom Joseph size_t responseSize{}; 32500325238STom Joseph auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(), 32600325238STom Joseph &response, &responseSize); 32700325238STom Joseph std::unique_ptr<uint8_t, decltype(std::free)*> responsePtr{response, 32800325238STom Joseph std::free}; 32900325238STom Joseph if (rc) 33000325238STom Joseph { 33100325238STom Joseph log<level::ERR>("pldm: pldm_send_recv failed for OCC reset", 33200325238STom Joseph entry("RC=%d", rc)); 33300325238STom Joseph } 33400325238STom Joseph 33500325238STom Joseph uint8_t completionCode{}; 33600325238STom Joseph auto responseMsg = reinterpret_cast<const pldm_msg*>(responsePtr.get()); 33700325238STom Joseph auto rcDecode = decode_set_state_effecter_states_resp( 33800325238STom Joseph responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode); 33900325238STom Joseph if (rcDecode || completionCode) 34000325238STom Joseph { 34100325238STom Joseph log<level::ERR>( 34200325238STom Joseph "pldm: decode_set_state_effecter_states_resp returned error", 34300325238STom Joseph entry("RC=%d", rcDecode), 34400325238STom Joseph entry("COMPLETION_CODE=%d", completionCode)); 34500325238STom Joseph } 34600325238STom Joseph 34700325238STom Joseph return; 34800325238STom Joseph } 34900325238STom Joseph 350815f9f55STom Joseph } // namespace pldm 351