oem_ibm: Add Slot enable infrastructure in BMC

With this commit PDRs are created for each of these
PCIe slots and adapters which have a corresponding
entry in the entity associate map. The sensor/effector
states are monitored and accordingly D-Bus calls are
sent for enabling a slot, process property change
of a PCIe slot, etc.

Tested By: SIMICS power on/off and reset reload.

Signed-off-by: Manojkiran Eda <manojkiran.eda@gmail.com>
Change-Id: I51b79b75c909ddf2cc29872fec6aa01c2d56b418
diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
index 6a39328..9721bc1 100644
--- a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
@@ -1,11 +1,13 @@
 #include "oem_ibm_handler.hpp"
 
+#include "collect_slot_vpd.hpp"
 #include "file_io_type_lid.hpp"
 #include "libpldmresponder/file_io.hpp"
 #include "libpldmresponder/pdr_utils.hpp"
 
 #include <libpldm/entity.h>
 #include <libpldm/oem/ibm/entity.h>
+#include <libpldm/pldm.h>
 
 #include <phosphor-logging/lg2.hpp>
 #include <xyz/openbmc_project/State/BMC/client.hpp>
@@ -24,9 +26,11 @@
 int pldm::responder::oem_ibm_platform::Handler::
     getOemStateSensorReadingsHandler(
         pldm::pdr::EntityType entityType, EntityInstance entityInstance,
-        StateSetId stateSetId, CompositeCount compSensorCnt,
+        ContainerID containerId, StateSetId stateSetId,
+        CompositeCount compSensorCnt, uint16_t /*sensorId*/,
         std::vector<get_sensor_state_field>& stateField)
 {
+    auto& entityAssociationMap = getAssociateEntityMap();
     int rc = PLDM_SUCCESS;
     stateField.clear();
 
@@ -38,6 +42,20 @@
         {
             sensorOpState = fetchBootSide(entityInstance, codeUpdate);
         }
+        else if (entityType == PLDM_ENTITY_SLOT &&
+                 stateSetId == PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE)
+        {
+            for (const auto& [key, value] : entityAssociationMap)
+            {
+                if (value.entity_type == entityType &&
+                    value.entity_instance_num == entityInstance &&
+                    value.entity_container_id == containerId)
+                {
+                    sensorOpState = slotHandler->fetchSlotSensorState(key);
+                    break;
+                }
+            }
+        }
         else
         {
             rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
@@ -53,10 +71,10 @@
     oemSetStateEffecterStatesHandler(
         uint16_t entityType, uint16_t entityInstance, uint16_t stateSetId,
         uint8_t compEffecterCnt,
-        std::vector<set_effecter_state_field>& stateField,
-        uint16_t /*effecterId*/)
+        std::vector<set_effecter_state_field>& stateField, uint16_t effecterId)
 {
     int rc = PLDM_SUCCESS;
+    auto& entityAssociationMap = getAssociateEntityMap();
 
     for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
     {
@@ -141,6 +159,11 @@
                                       this, std::placeholders::_1));
                 }
             }
+            else if (stateSetId == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_STATE)
+            {
+                slotHandler->enableSlot(effecterId, entityAssociationMap,
+                                        stateField[currState].effecter_state);
+            }
             else
             {
                 rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
@@ -206,6 +229,71 @@
     repo.addRecord(pdrEntry);
 }
 
+void buildAllSlotEnableEffecterPDR(oem_ibm_platform::Handler* platformHandler,
+                                   pdr_utils::Repo& repo,
+                                   const std::vector<std::string>& slotobjpaths)
+{
+    size_t pdrSize = 0;
+    pdrSize = sizeof(pldm_state_effecter_pdr) +
+              sizeof(state_effecter_possible_states);
+    std::vector<uint8_t> entry{};
+    entry.resize(pdrSize);
+    pldm_state_effecter_pdr* pdr =
+        reinterpret_cast<pldm_state_effecter_pdr*>(entry.data());
+    if (!pdr)
+    {
+        error("Failed to get record by PDR type, ERROR:{ERR}", "ERR", lg2::hex,
+              static_cast<unsigned>(PLDM_PLATFORM_INVALID_EFFECTER_ID));
+        return;
+    }
+
+    auto& associatedEntityMap = platformHandler->getAssociateEntityMap();
+    for (const auto& entity_path : slotobjpaths)
+    {
+        pdr->hdr.record_handle = 0;
+        pdr->hdr.version = 1;
+        pdr->hdr.type = PLDM_STATE_EFFECTER_PDR;
+        pdr->hdr.record_change_num = 0;
+        pdr->hdr.length =
+            sizeof(pldm_state_effecter_pdr) - sizeof(pldm_pdr_hdr);
+        pdr->terminus_handle = TERMINUS_HANDLE;
+        pdr->effecter_id = platformHandler->getNextEffecterId();
+
+        if (entity_path != "" && associatedEntityMap.contains(entity_path))
+        {
+            pdr->entity_type = associatedEntityMap.at(entity_path).entity_type;
+            pdr->entity_instance =
+                associatedEntityMap.at(entity_path).entity_instance_num;
+            pdr->container_id =
+                associatedEntityMap.at(entity_path).entity_container_id;
+            platformHandler->effecterIdToDbusMap[pdr->effecter_id] =
+                entity_path;
+        }
+        else
+        {
+            // the slots are not present, dont create the PDR
+            continue;
+        }
+        pdr->effecter_semantic_id = 0;
+        pdr->effecter_init = PLDM_NO_INIT;
+        pdr->has_description_pdr = false;
+        pdr->composite_effecter_count = 1;
+
+        auto* possibleStatesPtr = pdr->possible_states;
+        auto possibleStates = reinterpret_cast<state_effecter_possible_states*>(
+            possibleStatesPtr);
+        possibleStates->state_set_id = PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_STATE;
+        possibleStates->possible_states_size = 2;
+        auto state =
+            reinterpret_cast<state_effecter_possible_states*>(possibleStates);
+        state->states[0].byte = 14;
+        pldm::responder::pdr_utils::PdrEntry pdrEntry{};
+        pdrEntry.data = entry.data();
+        pdrEntry.size = pdrSize;
+        repo.addRecord(pdrEntry);
+    }
+}
+
 void buildAllCodeUpdateSensorPDR(oem_ibm_platform::Handler* platformHandler,
                                  uint16_t entityType, uint16_t entityInstance,
                                  uint16_t stateSetID, pdr_utils::Repo& repo)
@@ -255,6 +343,66 @@
     repo.addRecord(pdrEntry);
 }
 
+void buildAllSlotEnableSensorPDR(oem_ibm_platform::Handler* platformHandler,
+                                 pdr_utils::Repo& repo,
+                                 const std::vector<std::string>& slotobjpaths)
+{
+    size_t pdrSize = 0;
+    pdrSize = sizeof(pldm_state_sensor_pdr) +
+              sizeof(state_sensor_possible_states);
+    std::vector<uint8_t> entry{};
+    entry.resize(pdrSize);
+    pldm_state_sensor_pdr* pdr =
+        reinterpret_cast<pldm_state_sensor_pdr*>(entry.data());
+    if (!pdr)
+    {
+        error("Failed to get record by PDR type, ERROR:{ERR}", "ERR", lg2::hex,
+              static_cast<unsigned>(PLDM_PLATFORM_INVALID_SENSOR_ID));
+        return;
+    }
+    auto& associatedEntityMap = platformHandler->getAssociateEntityMap();
+    for (const auto& entity_path : slotobjpaths)
+    {
+        pdr->hdr.record_handle = 0;
+        pdr->hdr.version = 1;
+        pdr->hdr.type = PLDM_STATE_SENSOR_PDR;
+        pdr->hdr.record_change_num = 0;
+        pdr->hdr.length = sizeof(pldm_state_sensor_pdr) - sizeof(pldm_pdr_hdr);
+        pdr->terminus_handle = TERMINUS_HANDLE;
+        pdr->sensor_id = platformHandler->getNextSensorId();
+        if (entity_path != "" && associatedEntityMap.contains(entity_path))
+        {
+            pdr->entity_type = associatedEntityMap.at(entity_path).entity_type;
+            pdr->entity_instance =
+                associatedEntityMap.at(entity_path).entity_instance_num;
+            pdr->container_id =
+                associatedEntityMap.at(entity_path).entity_container_id;
+        }
+        else
+        {
+            // the slots are not present, dont create the PDR
+            continue;
+        }
+
+        pdr->sensor_init = PLDM_NO_INIT;
+        pdr->sensor_auxiliary_names_pdr = false;
+        pdr->composite_sensor_count = 1;
+
+        auto* possibleStatesPtr = pdr->possible_states;
+        auto possibleStates =
+            reinterpret_cast<state_sensor_possible_states*>(possibleStatesPtr);
+        possibleStates->state_set_id = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE;
+        possibleStates->possible_states_size = 1;
+        auto state =
+            reinterpret_cast<state_sensor_possible_states*>(possibleStates);
+        state->states[0].byte = 15;
+        pldm::responder::pdr_utils::PdrEntry pdrEntry{};
+        pdrEntry.data = entry.data();
+        pdrEntry.size = pdrSize;
+        repo.addRecord(pdrEntry);
+    }
+}
+
 void pldm::responder::oem_ibm_platform::Handler::buildOEMPDR(
     pdr_utils::Repo& repo)
 {
@@ -271,6 +419,13 @@
                                   ENTITY_INSTANCE_1,
                                   PLDM_OEM_IBM_SYSTEM_POWER_STATE, repo);
 
+    static constexpr auto objectPath = "/xyz/openbmc_project/inventory/system";
+    const std::vector<std::string> slotInterface = {
+        "xyz.openbmc_project.Inventory.Item.PCIeSlot"};
+    auto slotPaths = dBusIntf->getSubTreePaths(objectPath, 0, slotInterface);
+    buildAllSlotEnableEffecterPDR(this, repo, slotPaths);
+    buildAllSlotEnableSensorPDR(this, repo, slotPaths);
+
     buildAllCodeUpdateSensorPDR(this, PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE,
                                 ENTITY_INSTANCE_0, PLDM_OEM_IBM_BOOT_STATE,
                                 repo);