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/common/test/mocked_utils.hpp b/common/test/mocked_utils.hpp
index 1e7cf6e..8e887a5 100644
--- a/common/test/mocked_utils.hpp
+++ b/common/test/mocked_utils.hpp
@@ -68,4 +68,8 @@
     MOCK_METHOD(pldm::utils::GetSubTreeResponse, getSubtree,
                 (const std::string&, int, const std::vector<std::string>&),
                 (const override));
+
+    MOCK_METHOD(pldm::utils::GetSubTreePathsResponse, getSubTreePaths,
+                (const std::string&, int, const std::vector<std::string>&),
+                (const override));
 };
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index 2e0ed5a..cf6ecf5 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -54,6 +54,7 @@
         '../oem/ibm/libpldmresponder/oem_ibm_handler.cpp',
         '../oem/ibm/libpldmresponder/inband_code_update.cpp',
         '../oem/ibm/requester/dbus_to_file_handler.cpp',
+        '../oem/ibm/libpldmresponder/collect_slot_vpd.cpp',
         '../oem/ibm/libpldmresponder/file_io_type_progress_src.cpp',
         '../oem/ibm/libpldmresponder/file_io_type_vpd.cpp',
         '../oem/ibm/libpldmresponder/file_io_type_pcie.cpp',
diff --git a/libpldmresponder/oem_handler.hpp b/libpldmresponder/oem_handler.hpp
index bd65dd2..8215b37 100644
--- a/libpldmresponder/oem_handler.hpp
+++ b/libpldmresponder/oem_handler.hpp
@@ -22,8 +22,10 @@
      *
      *  @param[in] entityType - entity type corresponding to the sensor
      *  @param[in] entityInstance - entity instance number
+     *  @param[in] entityContainerID - container id
      *  @param[in] stateSetId - state set id
      *  @param[in] compSensorCnt - composite sensor count
+     *  @param[in] sensorId - sensor ID
      *  @param[out] stateField - The state field data for each of the states,
      *                           equal to composite sensor count in number
      *
@@ -34,8 +36,9 @@
     virtual int getOemStateSensorReadingsHandler(
         pldm::pdr::EntityType entityType,
         pldm::pdr::EntityInstance entityInstance,
+        pldm::pdr::ContainerID entityContainerId,
         pldm::pdr::StateSetId stateSetId,
-        pldm::pdr::CompositeCount compSensorCnt,
+        pldm::pdr::CompositeCount compSensorCnt, uint16_t sensorId,
         std::vector<get_sensor_state_field>& stateField) = 0;
 
     /** @brief Interface to set the effecter requested by pldm requester
diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp
index 0a0de64..d04bb1e 100644
--- a/libpldmresponder/platform.cpp
+++ b/libpldmresponder/platform.cpp
@@ -789,13 +789,15 @@
     uint16_t entityType{};
     uint16_t entityInstance{};
     uint16_t stateSetId{};
+    uint16_t containerId{};
 
     if (isOemStateSensor(*this, sensorId, sensorRearmCount, comSensorCnt,
-                         entityType, entityInstance, stateSetId) &&
-        oemPlatformHandler != nullptr && !sensorDbusObjMaps.contains(sensorId))
+                         entityType, entityInstance, stateSetId, containerId) &&
+        oemPlatformHandler && !sensorDbusObjMaps.contains(sensorId))
     {
         rc = oemPlatformHandler->getOemStateSensorReadingsHandler(
-            entityType, entityInstance, stateSetId, comSensorCnt, stateField);
+            entityType, entityInstance, containerId, stateSetId, comSensorCnt,
+            sensorId, stateField);
     }
     else
     {
@@ -835,7 +837,7 @@
 bool isOemStateSensor(Handler& handler, uint16_t sensorId,
                       uint8_t sensorRearmCount, uint8_t& compSensorCnt,
                       uint16_t& entityType, uint16_t& entityInstance,
-                      uint16_t& stateSetId)
+                      uint16_t& stateSetId, uint16_t& containerId)
 {
     pldm_state_sensor_pdr* pdr = nullptr;
 
@@ -868,6 +870,7 @@
         }
         auto tmpEntityType = pdr->entity_type;
         auto tmpEntityInstance = pdr->entity_instance;
+        auto tmpEntityContainerId = pdr->container_id;
         auto tmpCompSensorCnt = pdr->composite_sensor_count;
         auto tmpPossibleStates =
             reinterpret_cast<state_sensor_possible_states*>(
@@ -892,6 +895,7 @@
             entityInstance = tmpEntityInstance;
             stateSetId = tmpStateSetId;
             compSensorCnt = tmpCompSensorCnt;
+            containerId = tmpEntityContainerId;
             return true;
         }
         else
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index 97e5aa5..6c30c52 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -529,6 +529,7 @@
  *  @param[out] entityType - entity type
  *  @param[out] entityInstance - entity instance number
  *  @param[out] stateSetId - state set id
+ *  @param[out] containerId - container id
  *
  *  @return true if the sensor is OEM. All out parameters are invalid
  *               for a non OEM sensor
@@ -536,7 +537,7 @@
 bool isOemStateSensor(Handler& handler, uint16_t sensorId,
                       uint8_t sensorRearmCount, uint8_t& compSensorCnt,
                       uint16_t& entityType, uint16_t& entityInstance,
-                      uint16_t& stateSetId);
+                      uint16_t& stateSetId, uint16_t& containerId);
 
 /** @brief Function to check if an effecter falls in OEM range
  *         An effecter is considered to be oem if either of entity
diff --git a/oem/ibm/libpldmresponder/collect_slot_vpd.cpp b/oem/ibm/libpldmresponder/collect_slot_vpd.cpp
new file mode 100644
index 0000000..2d0f4f9
--- /dev/null
+++ b/oem/ibm/libpldmresponder/collect_slot_vpd.cpp
@@ -0,0 +1,333 @@
+#include "collect_slot_vpd.hpp"
+
+#include "oem_ibm_handler.hpp"
+
+#include <phosphor-logging/lg2.hpp>
+
+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<unsigned>(currentOnGoingSlotEntity.entity_type),
+        "ENTITY_NUM",
+        static_cast<unsigned>(currentOnGoingSlotEntity.entity_instance_num),
+        "ENTITY_ID",
+        static_cast<unsigned>(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<sdbusplus::message::object_path>(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<sdbusplus::message::object_path>(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<std::string>
+    SlotHandler::getAdapterObjPath(const std::string& slotObjPath)
+{
+    static constexpr auto searchpath = "/xyz/openbmc_project/inventory";
+    int depth = 0;
+    std::vector<std::string> 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<sdbusplus::bus::match_t>(
+        pldm::utils::DBusHandler::getBus(),
+        propertiesChanged(adapterObjectPath,
+                          "xyz.openbmc_project.Inventory.Item"),
+        [this, adapterObjectPath, stateFieldValue,
+         entity](sdbusplus::message::message& 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<bool>(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<pldm_state_effecter_pdr*>(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<state_effecter_possible_states*>(
+                        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<pldm::responder::oem_ibm_platform::Handler*>(
+            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<bool>(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
diff --git a/oem/ibm/libpldmresponder/collect_slot_vpd.hpp b/oem/ibm/libpldmresponder/collect_slot_vpd.hpp
new file mode 100644
index 0000000..0d398ce
--- /dev/null
+++ b/oem/ibm/libpldmresponder/collect_slot_vpd.hpp
@@ -0,0 +1,173 @@
+#pragma once
+
+#include "libpldmresponder/platform.hpp"
+
+#include <libpldm/pdr.h>
+#include <libpldm/platform.h>
+
+#include <sdbusplus/bus/match.hpp>
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/utility/timer.hpp>
+
+#include <memory>
+
+namespace pldm
+{
+
+using namespace sdbusplus::bus::match::rules;
+
+namespace responder
+{
+
+using ObjectPath = std::string;
+using AssociatedEntityMap = std::map<ObjectPath, pldm_entity>;
+
+/** @class SlotHandler
+ *
+ *  @brief This class performs the necessary operation in pldm for
+ *         Slot Enable operation. That includes taking actions on the
+ *         setStateEffecterStates calls from Host and also sending
+ *         notification to inventory manager application
+ */
+class SlotHandler
+{
+  public:
+    SlotHandler() = delete;
+    ~SlotHandler() = default;
+    SlotHandler(const SlotHandler&) = delete;
+    SlotHandler& operator=(const SlotHandler&) = delete;
+    SlotHandler(SlotHandler&&) = delete;
+    SlotHandler& operator=(SlotHandler&&) = delete;
+
+    /** @brief SlotHandler Constructor
+     *
+     * @param[in] event - reference for the main event loop
+     * @param[in] repo - pointer to the BMC's Primary PDR repo
+     *
+     */
+    SlotHandler(const sdeventplus::Event& event, pldm_pdr* repo) :
+        timer(event,
+              std::bind(std::mem_fn(&SlotHandler::timeOutHandler), this)),
+        pdrRepo(repo)
+    {
+        fruPresenceMatch = nullptr;
+        currentOnGoingSlotEntity.entity_type = 0;
+        currentOnGoingSlotEntity.entity_instance_num = 0;
+        currentOnGoingSlotEntity.entity_container_id = 0;
+    }
+
+    /** @brief Method to be called when enabling a Slot for ADD/REMOVE/REPLACE
+     *  @param[in] effecterID - The effecter ID of the effecter that is set from
+     *                          host
+     *  @param[in] fruAssociationMap - the dbus path to pldm entity stored while
+     *                                 creating the pldm fru records
+     *  @param[in] stateFieldValue - the current Effecter stateFieldValue
+     */
+    void enableSlot(uint16_t effecterId,
+                    const AssociatedEntityMap& fruAssociationMap,
+                    uint8_t stateFieldValue);
+
+    /** @brief Method to be used for fetching the slot sensor value
+     *  @param[in] slotObjectPath - the dbus object path for slot object
+     *  @return - returns the sensor state for the respective slot sensor
+     */
+    uint8_t fetchSlotSensorState(const std::string& slotObjectPath);
+
+    /** @brief Method to set the oem platform handler in SlotHandler class
+     *  @param[in] handler - pointer to the oem platform handler
+     */
+    void setOemPlatformHandler(pldm::responder::oem_platform::Handler* handler);
+
+  private:
+    /** @brief call back method called when the timer is expired. This handler
+     *  is called when the change of state cannot be made for a slot.
+     */
+    void timeOutHandler();
+
+    /** @brief Abstracted method for obtaining the entityID from effecterID
+     *  @param[in]  effecterID - The effecterID of the BMC effecter
+     *  @return - pldm entity ID for the given effecter ID
+     */
+    pldm_entity getEntityIDfromEffecterID(uint16_t effecterID);
+
+    /** @brief Abstracted method for processing the Slot Operations
+     *  @param[in] slotObjPath - The slot dbus object path
+     *  @param[in] entity - the current slot pldm entity under operation
+     *  @param[in] stateFieldValue - the current Effecter stateFieldValue
+     */
+    void processSlotOperations(const std::string& slotObjectPath,
+                               const pldm_entity& entity,
+                               uint8_t stateFieldValue);
+
+    /** @brief Method to obtain the Adapter dbus Object Path from Slot Adapter
+     * path
+     *  @param[in] slotObjPath - The slot dbus object path
+     *  @return - if Successfull, returns the adapter dbus object path
+     */
+    std::optional<std::string>
+        getAdapterObjPath(const std::string& slotObjPath);
+
+    /** @brief Method to call VPD collection & VPD removal API's
+     *  @param[in] adapterObjectPath - The adapter D-Bus object path
+     *  @param[in] stateFieldvalue - The current stateField value from set
+     *                               effecter call
+     */
+    void callVPDManager(const std::string& adapterObjPath,
+                        uint8_t stateFieldValue);
+
+    /** @brief Method to create a matcher to catch the property change signal
+     *  @param[in] adapterObjectPath - The adapter D-Bus object path
+     *  @param[in] stateFieldvalue - The current stateField value from set
+     *                               effecter call
+     *  @param[in] entity - the current slot pldm entity under operation
+     */
+    void createPresenceMatch(const std::string& adapterObjectPath,
+                             const pldm_entity& entity,
+                             uint8_t stateFieldValue);
+
+    /** @brief Method to process the Property change signal from Preset Property
+     *  @param[in] presentValue - The current value of present Value
+     *  @param[in] stateFieldvalue - The current stateField value from set
+     *                               effecter call
+     *  @param[in] entity - the current slot pldm entity under operation
+     */
+    void processPresentPropertyChange(
+        bool presentValue, uint8_t stateFieldvalue, const pldm_entity& entity);
+
+    /** @brief Get the sensor state from D-Bus
+     *  @param[in] adapterObjectPath - reference of the Adapter dbus object path
+     *  @return - Boolean value of sensor state
+     */
+
+    bool fetchSensorStateFromDbus(const std::string& adapterObjectPath);
+
+    /* @brief Method to send a state sensor event to Host from SlotHandler class
+     * @param[in] sensorId - sensor id for the event
+     * @param[in] sensorEventClass - sensor event class wrt DSP0248
+     * @param[in] sensorOffset - sensor offset
+     * @param[in] eventState - new event state
+     * @param[in] prevEventState - previous state
+     */
+    void sendStateSensorEvent(uint16_t sensorId,
+                              enum sensor_event_class_states sensorEventClass,
+                              uint8_t sensorOffset, uint8_t eventState,
+                              uint8_t prevEventState);
+
+    pldm::responder::oem_platform::Handler* oemPlatformHandler =
+        nullptr; //!< oem platform handler
+
+    /** @brief pointer to tha matcher for Present State for adapter object*/
+    std::unique_ptr<sdbusplus::bus::match_t> fruPresenceMatch;
+
+    /** @brief Timer used for Slot VPD Collection operation */
+    sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic> timer;
+
+    /** @brief pointer to BMC's primary PDR repo */
+    const pldm_pdr* pdrRepo;
+
+    /** @brief variable to store the current slot entity under operation */
+    pldm_entity currentOnGoingSlotEntity;
+};
+
+} // namespace responder
+} // namespace pldm
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);
diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
index b5749c3..907f2cb 100644
--- a/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "collect_slot_vpd.hpp"
+#include "common/utils.hpp"
 #include "inband_code_update.hpp"
 #include "libpldmresponder/oem_handler.hpp"
 #include "libpldmresponder/pdr_utils.hpp"
@@ -20,6 +22,8 @@
 {
 namespace responder
 {
+using ObjectPath = std::string;
+using AssociatedEntityMap = std::map<ObjectPath, pldm_entity>;
 namespace oem_ibm_platform
 {
 constexpr uint16_t ENTITY_INSTANCE_0 = 0;
@@ -43,13 +47,15 @@
 {
   public:
     Handler(const pldm::utils::DBusHandler* dBusIntf,
-            pldm::responder::CodeUpdate* codeUpdate, int mctp_fd,
+            pldm::responder::CodeUpdate* codeUpdate,
+            pldm::responder::SlotHandler* slotHandler, int mctp_fd,
             uint8_t mctp_eid, pldm::InstanceIdDb& instanceIdDb,
             sdeventplus::Event& event,
             pldm::requester::Handler<pldm::requester::Request>* handler) :
         oem_platform::Handler(dBusIntf), codeUpdate(codeUpdate),
-        platformHandler(nullptr), mctp_fd(mctp_fd), mctp_eid(mctp_eid),
-        instanceIdDb(instanceIdDb), event(event), handler(handler),
+        slotHandler(slotHandler), platformHandler(nullptr), mctp_fd(mctp_fd),
+        mctp_eid(mctp_eid), instanceIdDb(instanceIdDb), event(event),
+        handler(handler),
         timer(event, std::bind(std::mem_fn(&Handler::setSurvTimer), this,
                                HYPERVISOR_TID, false)),
         hostTransitioningToOff(true)
@@ -146,8 +152,8 @@
     int getOemStateSensorReadingsHandler(
         pldm::pdr::EntityType entityType,
         pldm::pdr::EntityInstance entityInstance,
-        pldm::pdr::StateSetId stateSetId,
-        pldm::pdr::CompositeCount compSensorCnt,
+        pldm::pdr::ContainerID containerId, pldm::pdr::StateSetId stateSetId,
+        pldm::pdr::CompositeCount compSensorCnt, uint16_t sensorId,
         std::vector<get_sensor_state_field>& stateField);
 
     int oemSetStateEffecterStatesHandler(
@@ -181,6 +187,17 @@
         return platformHandler->getNextSensorId();
     }
 
+    /** @brief Get std::map associated with the entity
+     *         key: object path
+     *         value: pldm_entity
+     *
+     *  @return std::map<ObjectPath, pldm_entity>
+     */
+    virtual const AssociatedEntityMap& getAssociateEntityMap()
+    {
+        return platformHandler->getAssociateEntityMap();
+    }
+
     /** @brief Method to Generate the OEM PDRs
      *
      * @param[in] repo - instance of concrete implementation of Repo
@@ -298,6 +315,10 @@
     ~Handler() = default;
 
     pldm::responder::CodeUpdate* codeUpdate; //!< pointer to CodeUpdate object
+
+    pldm::responder::SlotHandler*
+        slotHandler; //!< pointer to SlotHandler object
+
     pldm::responder::platform::Handler*
         platformHandler; //!< pointer to PLDM platform handler
 
@@ -315,6 +336,10 @@
     std::unique_ptr<sdeventplus::source::Defer> startUpdateEvent;
     std::unique_ptr<sdeventplus::source::Defer> systemRebootEvent;
 
+    /** @brief Effecterid to dbus object path map
+     */
+    std::unordered_map<uint16_t, std::string> effecterIdToDbusMap;
+
     /** @brief reference of main event loop of pldmd, primarily used to schedule
      *  work
      */
diff --git a/oem/ibm/test/libpldmresponder_oem_platform_test.cpp b/oem/ibm/test/libpldmresponder_oem_platform_test.cpp
index a8199f5..ddce8dc 100644
--- a/oem/ibm/test/libpldmresponder_oem_platform_test.cpp
+++ b/oem/ibm/test/libpldmresponder_oem_platform_test.cpp
@@ -2,9 +2,11 @@
 #include "common/utils.hpp"
 #include "host-bmc/utils.hpp"
 #include "libpldmresponder/event_parser.hpp"
+#include "libpldmresponder/fru.hpp"
 #include "libpldmresponder/pdr.hpp"
 #include "libpldmresponder/pdr_utils.hpp"
 #include "libpldmresponder/platform.hpp"
+#include "oem/ibm/libpldmresponder/collect_slot_vpd.hpp"
 #include "oem/ibm/libpldmresponder/inband_code_update.hpp"
 #include "oem/ibm/libpldmresponder/oem_ibm_handler.hpp"
 #include "oem/ibm/libpldmresponder/utils.hpp"
@@ -27,6 +29,7 @@
 using namespace pldm::responder::pdr_utils;
 using namespace pldm::responder::oem_ibm_platform;
 using ::testing::Return;
+using ::testing::ReturnRef;
 
 class MockOemUtilsHandler : public oem_ibm_utils::Handler
 {
@@ -46,18 +49,30 @@
     MOCK_METHOD(void, setVersions, (), (override));
 };
 
+class MockSlotHandler : public SlotHandler
+{
+  public:
+    MockSlotHandler(const sdeventplus::Event& event, pldm_pdr* repo) :
+        SlotHandler(event, repo)
+    {}
+};
+
 class MockOemPlatformHandler : public oem_ibm_platform::Handler
 {
   public:
     MockOemPlatformHandler(const pldm::utils::DBusHandler* dBusIntf,
-                           pldm::responder::CodeUpdate* codeUpdate, int mctp_fd,
-                           uint8_t mctp_eid, pldm::InstanceIdDb& instanceIdDb,
+                           pldm::responder::CodeUpdate* codeUpdate,
+                           pldm::responder::SlotHandler* slotHandler,
+                           int mctp_fd, uint8_t mctp_eid,
+                           pldm::InstanceIdDb& instanceIdDb,
                            sdeventplus::Event& event) :
-        oem_ibm_platform::Handler(dBusIntf, codeUpdate, mctp_fd, mctp_eid,
-                                  instanceIdDb, event, nullptr)
+        oem_ibm_platform::Handler(dBusIntf, codeUpdate, slotHandler, mctp_fd,
+                                  mctp_eid, instanceIdDb, event, nullptr)
     {}
     MOCK_METHOD(uint16_t, getNextEffecterId, ());
     MOCK_METHOD(uint16_t, getNextSensorId, ());
+    MOCK_METHOD((const AssociatedEntityMap&), getAssociateEntityMap, (),
+                (override));
 };
 
 TEST(OemSetStateEffecterStatesHandler, testGoodRequest)
@@ -65,8 +80,10 @@
     uint16_t entityID_ = PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE;
     uint16_t stateSetId_ = PLDM_OEM_IBM_BOOT_STATE;
     uint16_t entityInstance_ = 0;
+    uint16_t containerId_ = 0;
     uint8_t compSensorCnt_ = 1;
     uint16_t effecterId = 0xA;
+    uint16_t sensorId = 0x1;
     TestInstanceIdDb instanceIdDb;
 
     sdbusplus::bus_t bus(sdbusplus::bus::new_default());
@@ -76,14 +93,18 @@
     auto mockDbusHandler = std::make_unique<MockdBusHandler>();
     std::unique_ptr<CodeUpdate> mockCodeUpdate =
         std::make_unique<MockCodeUpdate>(mockDbusHandler.get());
-    std::unique_ptr<oem_platform::Handler> oemPlatformHandler{};
+    std::unique_ptr<MockOemPlatformHandler> oemPlatformHandler =
+        std::make_unique<MockOemPlatformHandler>(
+            mockDbusHandler.get(), mockCodeUpdate.get(), nullptr, 0x1, 0x9,
+            instanceIdDb, event);
 
-    oemPlatformHandler = std::make_unique<oem_ibm_platform::Handler>(
-        mockDbusHandler.get(), mockCodeUpdate.get(), 0x1, 0x9, instanceIdDb,
-        event, nullptr);
+    const AssociatedEntityMap associateMap = {};
+    EXPECT_CALL(*oemPlatformHandler, getAssociateEntityMap())
+        .WillRepeatedly(ReturnRef(associateMap));
 
     auto rc = oemPlatformHandler->getOemStateSensorReadingsHandler(
-        entityID_, entityInstance_, stateSetId_, compSensorCnt_, stateField);
+        entityID_, entityInstance_, containerId_, stateSetId_, compSensorCnt_,
+        sensorId, stateField);
 
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(stateField.size(), 1);
@@ -96,21 +117,24 @@
 
     std::vector<get_sensor_state_field> stateField1;
     rc = oemPlatformHandler->getOemStateSensorReadingsHandler(
-        entityID_, entityInstance_, stateSetId_, compSensorCnt_, stateField1);
+        entityID_, entityInstance_, containerId_, stateSetId_, compSensorCnt_,
+        sensorId, stateField1);
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(stateField1.size(), 1);
     ASSERT_EQ(stateField1[0].event_state, tSideNum);
 
     entityInstance_ = 2;
     rc = oemPlatformHandler->getOemStateSensorReadingsHandler(
-        entityID_, entityInstance_, stateSetId_, compSensorCnt_, stateField1);
+        entityID_, entityInstance_, containerId_, stateSetId_, compSensorCnt_,
+        sensorId, stateField1);
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(stateField1[0].event_state, PLDM_SENSOR_UNKNOWN);
 
     entityID_ = 40;
     stateSetId_ = 50;
     rc = oemPlatformHandler->getOemStateSensorReadingsHandler(
-        entityID_, entityInstance_, stateSetId_, compSensorCnt_, stateField1);
+        entityID_, entityInstance_, containerId_, stateSetId_, compSensorCnt_,
+        sensorId, stateField1);
     ASSERT_EQ(rc, PLDM_PLATFORM_INVALID_STATE_VALUE);
 
     entityID_ = PLDM_OEM_IBM_ENTITY_FIRMWARE_UPDATE;
@@ -130,7 +154,6 @@
     rc = oemPlatformHandler->oemSetStateEffecterStatesHandler(
         entityID_, entityInstance_, stateSetId_, compSensorCnt_,
         setEffecterStateField, effecterId);
-
     ASSERT_EQ(rc, PLDM_PLATFORM_INVALID_STATE_VALUE);
 
     entityID_ = 34;
@@ -202,6 +225,7 @@
 
 TEST(generateStateEffecterOEMPDR, testGoodRequest)
 {
+    const AssociatedEntityMap associateMap = {};
     auto inPDRRepo = pldm_pdr_init();
     sdbusplus::bus_t bus(sdbusplus::bus::new_default());
     TestInstanceIdDb instanceIdDb;
@@ -209,12 +233,15 @@
     auto event = sdeventplus::Event::get_default();
     std::unique_ptr<CodeUpdate> mockCodeUpdate =
         std::make_unique<MockCodeUpdate>(mockDbusHandler.get());
-    std::unique_ptr<oem_ibm_platform::Handler> mockoemPlatformHandler =
+    std::unique_ptr<MockOemPlatformHandler> mockoemPlatformHandler =
         std::make_unique<MockOemPlatformHandler>(
-            mockDbusHandler.get(), mockCodeUpdate.get(), 0x1, 0x9, instanceIdDb,
-            event);
+            mockDbusHandler.get(), mockCodeUpdate.get(), nullptr, 0x1, 0x9,
+            instanceIdDb, event);
     Repo inRepo(inPDRRepo);
 
+    EXPECT_CALL(*mockoemPlatformHandler, getAssociateEntityMap())
+        .WillRepeatedly(ReturnRef(associateMap));
+
     mockoemPlatformHandler->buildOEMPDR(inRepo);
     ASSERT_EQ(inRepo.empty(), false);
 
@@ -307,6 +334,7 @@
 
 TEST(generateStateSensorOEMPDR, testGoodRequest)
 {
+    const AssociatedEntityMap associateMap = {};
     auto inPDRRepo = pldm_pdr_init();
     sdbusplus::bus_t bus(sdbusplus::bus::new_default());
     TestInstanceIdDb instanceIdDb;
@@ -315,10 +343,12 @@
     auto event = sdeventplus::Event::get_default();
     std::unique_ptr<CodeUpdate> mockCodeUpdate =
         std::make_unique<MockCodeUpdate>(mockDbusHandler.get());
-    std::unique_ptr<oem_ibm_platform::Handler> mockoemPlatformHandler =
+    std::unique_ptr<MockOemPlatformHandler> mockoemPlatformHandler =
         std::make_unique<MockOemPlatformHandler>(
-            mockDbusHandler.get(), mockCodeUpdate.get(), 0x1, 0x9, instanceIdDb,
-            event);
+            mockDbusHandler.get(), mockCodeUpdate.get(), nullptr, 0x1, 0x9,
+            instanceIdDb, event);
+    EXPECT_CALL(*mockoemPlatformHandler, getAssociateEntityMap())
+        .WillRepeatedly(ReturnRef(associateMap));
     Repo inRepo(inPDRRepo);
     mockoemPlatformHandler->buildOEMPDR(inRepo);
     ASSERT_EQ(inRepo.empty(), false);
@@ -416,8 +446,8 @@
         std::make_unique<MockCodeUpdate>(mockDbusHandler.get());
     std::unique_ptr<oem_ibm_platform::Handler> mockoemPlatformHandler =
         std::make_unique<MockOemPlatformHandler>(
-            mockDbusHandler.get(), mockCodeUpdate.get(), 0x1, 0x9, instanceIdDb,
-            event);
+            mockDbusHandler.get(), mockCodeUpdate.get(), nullptr, 0x1, 0x9,
+            instanceIdDb, event);
     std::string dbuspath = "/inventory/system1/chassis1/motherboard1/dcm0";
     mockoemPlatformHandler->updateOemDbusPaths(dbuspath);
     EXPECT_EQ(dbuspath, "/inventory/system/chassis/motherboard/dcm0");
diff --git a/pldmd/oem_ibm.hpp b/pldmd/oem_ibm.hpp
index 67ad482..6003125 100644
--- a/pldmd/oem_ibm.hpp
+++ b/pldmd/oem_ibm.hpp
@@ -75,6 +75,7 @@
         oemIbmFruHandler->setIBMFruHandler(fruHandler);
 
         createCodeUpdate();
+        createSlotHandler();
         createOemPlatformHandler();
         createOemIbmUtilsHandler();
         codeUpdate->setOemPlatformHandler(oemPlatformHandler.get());
@@ -82,6 +83,7 @@
         hostPDRHandler->setOemUtilsHandler(oemUtilsHandler.get());
         platformHandler->setOemPlatformHandler(oemPlatformHandler.get());
         baseHandler->setOemPlatformHandler(oemPlatformHandler.get());
+        slotHandler->setOemPlatformHandler(oemPlatformHandler.get());
 
         createOemIbmPlatformHandler();
         oemIbmPlatformHandler->setPlatformHandler(platformHandler);
@@ -99,6 +101,13 @@
         codeUpdate->clearDirPath(LID_STAGING_DIR);
     }
 
+    /** @brief Method for creating slot handler */
+    void createSlotHandler()
+    {
+        slotHandler =
+            std::make_unique<pldm::responder::SlotHandler>(event, repo);
+    }
+
     /** @brief Method for creating oemPlatformHandler
      *
      *  This method also assigns the oemPlatformHandler to the below
@@ -106,10 +115,9 @@
      */
     void createOemPlatformHandler()
     {
-        oemPlatformHandler =
-            std::make_unique<responder::oem_ibm_platform::Handler>(
-                dBusIntf, codeUpdate.get(), mctp_fd, mctp_eid, instanceIdDb,
-                event, reqHandler);
+        oemPlatformHandler = std::make_unique<oem_ibm_platform::Handler>(
+            dBusIntf, codeUpdate.get(), slotHandler.get(), mctp_fd, mctp_eid,
+            instanceIdDb, event, reqHandler);
     }
 
     /** @brief Method for creating oemIbmPlatformHandler */
@@ -195,6 +203,9 @@
     /** @brief pointer to the CodeUpdate class*/
     std::unique_ptr<pldm::responder::CodeUpdate> codeUpdate{};
 
+    /** @brief pointer to the SlotHanlder class*/
+    std::unique_ptr<pldm::responder::SlotHandler> slotHandler{};
+
     /** @brief oem IBM Platform handler*/
     pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = nullptr;