#include "collect_slot_vpd.hpp" #include "oem_ibm_handler.hpp" #include PHOSPHOR_LOG2_USING; namespace pldm { namespace responder { using namespace oem_ibm_platform; void SlotHandler::timeOutHandler() { info( "Timer expired waiting for Event from Inventory on following pldm_entity: [ {ENTITY_TYP}, {ENTITY_NUM}, {ENTITY_ID} ]", "ENTITY_TYP", static_cast(currentOnGoingSlotEntity.entity_type), "ENTITY_NUM", static_cast(currentOnGoingSlotEntity.entity_instance_num), "ENTITY_ID", static_cast(currentOnGoingSlotEntity.entity_container_id)); // Disable the timer timer.setEnabled(false); // obtain the sensor Id auto sensorId = pldm::utils::findStateSensorId( pdrRepo, 0, PLDM_ENTITY_SLOT, currentOnGoingSlotEntity.entity_instance_num, currentOnGoingSlotEntity.entity_container_id, PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE); // send the sensor event to host with error state sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_ERROR, PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN); } void SlotHandler::enableSlot(uint16_t effecterId, const AssociatedEntityMap& fruAssociationMap, uint8_t stateFileValue) { info("CM: slot enable effecter id: {EFFECTER_ID}", "EFFECTER_ID", effecterId); const pldm_entity entity = getEntityIDfromEffecterID(effecterId); for (const auto& [key, value] : fruAssociationMap) { if (entity.entity_instance_num == value.entity_instance_num && entity.entity_type == value.entity_type && entity.entity_container_id == value.entity_container_id) { this->currentOnGoingSlotEntity.entity_type = value.entity_type; this->currentOnGoingSlotEntity.entity_instance_num = value.entity_instance_num; this->currentOnGoingSlotEntity.entity_container_id = value.entity_container_id; processSlotOperations(key, value, stateFileValue); } } } void SlotHandler::processSlotOperations(const std::string& slotObjectPath, const pldm_entity& entity, uint8_t stateFieldValue) { info("CM: processing the slot operations, SlotObject: {SLOT_OBJ}", "SLOT_OBJ", slotObjectPath); std::string adapterObjPath; try { // get the adapter dbus object path from the slot dbus object path adapterObjPath = getAdapterObjPath(slotObjectPath).value(); } catch (const std::bad_optional_access& e) { error("Failed to get the adapter dbus object ERROR={ERROR}", "ERROR", e); return; } info( "CM: Found an adapter under the slot, adapter object:{ADAPTER_OBJ_PATH}", "ADAPTER_OBJ_PATH", adapterObjPath); // create a presence match for the adpter present property createPresenceMatch(adapterObjPath, entity, stateFieldValue); // call the VPD Manager to collect/remove VPD objects callVPDManager(adapterObjPath, stateFieldValue); // start the 1 min timer timer.restart(std::chrono::seconds(60)); } void SlotHandler::callVPDManager(const std::string& adapterObjPath, uint8_t stateFieldValue) { static constexpr auto VPDObjPath = "/com/ibm/VPD/Manager"; static constexpr auto VPDInterface = "com.ibm.VPD.Manager"; auto& bus = pldm::utils::DBusHandler::getBus(); try { auto service = pldm::utils::DBusHandler().getService(VPDObjPath, VPDInterface); if (stateFieldValue == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_ADD) { auto method = bus.new_method_call(service.c_str(), VPDObjPath, VPDInterface, "CollectFRUVPD"); method.append( static_cast(adapterObjPath)); bus.call_noreply(method, dbusTimeout); } else if (stateFieldValue == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_REMOVE || stateFieldValue == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_REPLACE) { auto method = bus.new_method_call(service.c_str(), VPDObjPath, VPDInterface, "deleteFRUVPD"); method.append( static_cast(adapterObjPath)); bus.call_noreply(method, dbusTimeout); } } catch (const std::exception& e) { error( "failed to make a d-bus call to VPD Manager , Operation = {STATE_FILED_VAL}, ERROR={ERROR}", "STATE_FILED_VAL", (unsigned)stateFieldValue, "ERROR", e); } } std::optional SlotHandler::getAdapterObjPath(const std::string& slotObjPath) { static constexpr auto searchpath = "/xyz/openbmc_project/inventory"; int depth = 0; std::vector pcieAdapterInterface = { "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; pldm::utils::GetSubTreeResponse response = pldm::utils::DBusHandler().getSubtree(searchpath, depth, pcieAdapterInterface); for (const auto& [objPath, serviceMap] : response) { // An adapter is a child of a PCIe Slot Object if (objPath.contains(slotObjPath)) { // Found the Adapter under the slot return objPath; } } return std::nullopt; } void SlotHandler::createPresenceMatch(const std::string& adapterObjectPath, const pldm_entity& entity, uint8_t stateFieldValue) { fruPresenceMatch = std::make_unique( pldm::utils::DBusHandler::getBus(), propertiesChanged(adapterObjectPath, "xyz.openbmc_project.Inventory.Item"), [this, adapterObjectPath, stateFieldValue, entity](sdbusplus::message_t& msg) { pldm::utils::DbusChangedProps props{}; std::string intf; msg.read(intf, props); const auto itr = props.find("Present"); if (itr != props.end()) { bool value = std::get(itr->second); // Present Property is found this->processPresentPropertyChange(value, stateFieldValue, entity); } }); } void SlotHandler::processPresentPropertyChange( bool presentValue, uint8_t stateFiledvalue, const pldm_entity& entity) { // irrespective of true->false or false->true change, we should stop the // timer timer.setEnabled(false); // remove the prence match so that it does not monitor the change // even after we captured the property changed signal fruPresenceMatch = nullptr; // obtain the sensor id attached with this slot auto sensorId = pldm::utils::findStateSensorId( pdrRepo, 0, PLDM_ENTITY_SLOT, entity.entity_instance_num, entity.entity_container_id, PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE); uint8_t sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN; if (presentValue) { sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_ENABLED; } else { if (stateFiledvalue == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_REPLACE) { sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN; } else { sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_DISABLED; } } info( "CM: processing the property change from VPD Present value and sensor opState: {CURR_VAL} and {SENSOR_OP_STATE}", "CURR_VAL", presentValue, "SENSOR_OP_STATE", (unsigned)sensorOpState); // set the sensor state based on the stateFieldValue this->sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, sensorOpState, PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN); } pldm_entity SlotHandler::getEntityIDfromEffecterID(uint16_t effecterId) { pldm_entity parentFruEntity{}; uint8_t* pdrData = nullptr; uint32_t pdrSize{}; const pldm_pdr_record* record{}; do { record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR, record, &pdrData, &pdrSize); if (record && !pldm_pdr_record_is_remote(record)) { auto pdr = reinterpret_cast(pdrData); auto compositeEffecterCount = pdr->composite_effecter_count; auto possible_states_start = pdr->possible_states; for (auto effecters = 0x00; effecters < compositeEffecterCount; effecters++) { auto possibleStates = reinterpret_cast( possible_states_start); if (possibleStates->state_set_id == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_STATE && effecterId == pdr->effecter_id) { parentFruEntity.entity_type = pdr->entity_type; parentFruEntity.entity_instance_num = pdr->entity_instance; parentFruEntity.entity_container_id = pdr->container_id; return parentFruEntity; } } } } while (record); return parentFruEntity; } uint8_t SlotHandler::fetchSlotSensorState(const std::string& slotObjectPath) { std::string adapterObjPath; uint8_t sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN; try { // get the adapter dbus object path from the slot dbus object path adapterObjPath = getAdapterObjPath(slotObjectPath).value(); } catch (const std::bad_optional_access& e) { error( "Failed to get the adapterObjectPath from slotObjectPath : {SLOT_OBJ_PATH} with error ERROR={ERROR}", "SLOT_OBJ_PATH", slotObjectPath, "ERROR", e); return PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN; } if (fetchSensorStateFromDbus(adapterObjPath)) { sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_ENABLED; } else { sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_DISABLED; } return sensorOpState; } void SlotHandler::setOemPlatformHandler( pldm::responder::oem_platform::Handler* handler) { oemPlatformHandler = handler; } void SlotHandler::sendStateSensorEvent( uint16_t sensorId, enum sensor_event_class_states sensorEventClass, uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState) { pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = dynamic_cast( oemPlatformHandler); if (oemIbmPlatformHandler) { oemIbmPlatformHandler->sendStateSensorEvent( sensorId, sensorEventClass, sensorOffset, eventState, prevEventState); } } bool SlotHandler::fetchSensorStateFromDbus(const std::string& adapterObjectPath) { static constexpr auto ItemInterface = "xyz.openbmc_project.Inventory.Item"; try { auto presentProperty = pldm::utils::DBusHandler().getDbusPropertyVariant( adapterObjectPath.c_str(), "Present", ItemInterface); return std::get(presentProperty); } catch (const std::exception& e) { error( "failed to make a d-bus call to Inventory manager from adapterObjectPath : {ADAPTER_OBJ_PATH} with error ERROR={ERROR}", "ADAPTER_OBJ_PATH", adapterObjectPath, "ERROR", e); } return false; } } // namespace responder } // namespace pldm