#include "pldm.hpp" #include "file.hpp" #include #include #include #include #include namespace pldm { using sdbusplus::exception::SdBusError; using namespace phosphor::logging; void Interface::fetchOCCSensorInfo(const PdrList& pdrs, SensorToOCCInstance& sensorInstanceMap, SensorOffset& sensorOffset) { bool offsetFound = false; auto pdr = reinterpret_cast(pdrs.front().data()); auto possibleStatesPtr = pdr->possible_states; for (auto offset = 0; offset < pdr->composite_sensor_count; offset++) { auto possibleStates = reinterpret_cast( possibleStatesPtr); if (possibleStates->state_set_id == PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS) { sensorOffset = offset; offsetFound = true; break; } possibleStatesPtr += sizeof(possibleStates->state_set_id) + sizeof(possibleStates->possible_states_size) + possibleStates->possible_states_size; } if (!offsetFound) { log("pldm: OCC state sensor PDR with StateSetId " "PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS not found"); return; } // To order SensorID based on the EntityInstance std::map entityInstMap{}; for (auto& pdr : pdrs) { auto pdrPtr = reinterpret_cast(pdr.data()); entityInstMap.emplace( static_cast(pdrPtr->entity_instance), static_cast(pdrPtr->sensor_id)); } open_power::occ::instanceID count = start; for (auto const& pair : entityInstMap) { sensorInstanceMap.emplace(pair.second, count); count++; } } void Interface::sensorEvent(sdbusplus::message::message& msg) { if (!isOCCSensorCacheValid()) { PdrList pdrs{}; try { auto method = bus.new_method_call( "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm", "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR"); method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE, (uint16_t)PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS); auto responseMsg = bus.call(method); responseMsg.read(pdrs); } catch (const SdBusError& e) { log("pldm: Failed to fetch the OCC state sensor PDRs", entry("ERROR=%s", e.what())); } if (!pdrs.size()) { log("pldm: OCC state sensor PDRs not present"); return; } fetchOCCSensorInfo(pdrs, sensorToOCCInstance, sensorOffset); } TerminusID tid{}; SensorID sensorId{}; SensorOffset msgSensorOffset{}; EventState eventState{}; EventState previousEventState{}; msg.read(tid, sensorId, msgSensorOffset, eventState, previousEventState); auto sensorEntry = sensorToOCCInstance.find(sensorId); if (sensorEntry == sensorToOCCInstance.end() || (msgSensorOffset != sensorOffset)) { // No action for non matching sensorEvents return; } if (eventState == static_cast( PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE)) { log( fmt::format("PLDM: OCC{} is RUNNING", sensorEntry->second).c_str()); callBack(sensorEntry->second, true); } else if (eventState == static_cast( PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED)) { log( fmt::format("PLDM: OCC{} has now STOPPED", sensorEntry->second) .c_str()); callBack(sensorEntry->second, false); } return; } void Interface::hostStateEvent(sdbusplus::message::message& msg) { std::map> properties{}; std::string interface; msg.read(interface, properties); const auto stateEntry = properties.find("CurrentHostState"); if (stateEntry != properties.end()) { auto stateEntryValue = stateEntry->second; auto propVal = std::get(stateEntryValue); if (propVal == "xyz.openbmc_project.State.Host.HostState.Off") { sensorToOCCInstance.clear(); occInstanceToEffecter.clear(); } } } void Interface::fetchOCCEffecterInfo( const PdrList& pdrs, OccInstanceToEffecter& instanceToEffecterMap, CompositeEffecterCount& count, uint8_t& bootRestartPos) { bool offsetFound = false; auto pdr = reinterpret_cast(pdrs.front().data()); auto possibleStatesPtr = pdr->possible_states; for (auto offset = 0; offset < pdr->composite_effecter_count; offset++) { auto possibleStates = reinterpret_cast( possibleStatesPtr); if (possibleStates->state_set_id == PLDM_STATE_SET_BOOT_RESTART_CAUSE) { bootRestartPos = offset; effecterCount = pdr->composite_effecter_count; offsetFound = true; break; } possibleStatesPtr += sizeof(possibleStates->state_set_id) + sizeof(possibleStates->possible_states_size) + possibleStates->possible_states_size; } if (!offsetFound) { return; } std::map entityInstMap{}; for (auto& pdr : pdrs) { auto pdrPtr = reinterpret_cast(pdr.data()); entityInstMap.emplace( static_cast(pdrPtr->entity_instance), static_cast(pdrPtr->effecter_id)); } open_power::occ::instanceID position = start; for (auto const& pair : entityInstMap) { occInstanceToEffecter.emplace(position, pair.second); position++; } } std::vector Interface::prepareSetEffecterReq(uint8_t instanceId, EffecterID effecterId, CompositeEffecterCount effecterCount, uint8_t bootRestartPos) { std::vector request( sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) + (effecterCount * sizeof(set_effecter_state_field))); auto requestMsg = reinterpret_cast(request.data()); std::vector stateField; for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++) { if (effecterPos == bootRestartPos) { stateField.emplace_back(set_effecter_state_field{ PLDM_REQUEST_SET, PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET}); } else { stateField.emplace_back( set_effecter_state_field{PLDM_NO_CHANGE, 0}); } } auto rc = encode_set_state_effecter_states_req( instanceId, effecterId, effecterCount, stateField.data(), requestMsg); if (rc != PLDM_SUCCESS) { log("encode set effecter states request returned error ", entry("RC=%d", rc)); request.clear(); } return request; } void Interface::resetOCC(open_power::occ::instanceID occInstanceId) { if (!isPDREffecterCacheValid()) { PdrList pdrs{}; try { auto method = bus.new_method_call( "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm", "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR"); method.append(tid, (uint16_t)PLDM_ENTITY_PROC_MODULE, (uint16_t)PLDM_STATE_SET_BOOT_RESTART_CAUSE); auto responseMsg = bus.call(method); responseMsg.read(pdrs); } catch (const SdBusError& e) { log("pldm: Failed to fetch the OCC state effecter PDRs", entry("ERROR=%s", e.what())); } if (!pdrs.size()) { log("pldm: OCC state effecter PDRs not present"); return; } fetchOCCEffecterInfo(pdrs, occInstanceToEffecter, effecterCount, bootRestartPosition); } // Find the matching effecter for the OCC instance auto effecterEntry = occInstanceToEffecter.find(occInstanceId); if (effecterEntry == occInstanceToEffecter.end()) { log( "pldm: Failed to find a matching effecter for OCC instance", entry("OCC_INSTANCE_ID=%d", occInstanceId)); return; } uint8_t instanceId{}; try { auto method = bus.new_method_call( "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm", "xyz.openbmc_project.PLDM.Requester", "GetInstanceId"); method.append(mctpEid); auto reply = bus.call(method); reply.read(instanceId); } catch (const SdBusError& e) { log("pldm: GetInstanceId returned error", entry("ERROR=%s", e.what())); return; } // Prepare the SetStateEffecterStates request to reset the OCC auto request = prepareSetEffecterReq(instanceId, effecterEntry->second, effecterCount, bootRestartPosition); if (request.empty()) { log("pldm: SetStateEffecterStates request message empty"); return; } // Connect to MCTP scoket int fd = pldm_open(); if (fd == -1) { log("pldm: Failed to connect to MCTP socket"); return; } open_power::occ::FileDescriptor fileFd(fd); // Send the PLDM request message to HBRT uint8_t* response = nullptr; size_t responseSize{}; auto rc = pldm_send_recv(mctpEid, fileFd(), request.data(), request.size(), &response, &responseSize); std::unique_ptr responsePtr{response, std::free}; if (rc) { log("pldm: pldm_send_recv failed for OCC reset", entry("RC=%d", rc)); } uint8_t completionCode{}; auto responseMsg = reinterpret_cast(responsePtr.get()); auto rcDecode = decode_set_state_effecter_states_resp( responseMsg, responseSize - sizeof(pldm_msg_hdr), &completionCode); if (rcDecode || completionCode) { log( "pldm: decode_set_state_effecter_states_resp returned error", entry("RC=%d", rcDecode), entry("COMPLETION_CODE=%d", completionCode)); } return; } } // namespace pldm