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