BMC RR : Read and update the status for BMC reset

This commit reads the status of the host owned sensors by
sending a getStateSensorReading command and then
updates the D-Bus backend for BMC reset.

This commit also updates the TLPDR from the host
based on the valid bit in the TLPDR.

Earlier the PDR record handles where assigned in an incremental order
starting from 0, now the numbering has been decided
to be within the specified range as below
BMC: 0x00000001 to 0x00FFFFFF (0x00000000 is reserved per PLDM spec)
Hostboot: 0x01000000 to 0x01FFFFFF
PHYP: 0x02000000 to 0x02FFFFFF
Reserved: 0x03000000 to 0xFFFFFFFF

This commit handles the numbering of the PDR record handles.

Tested the following scenarios on a rainier system
1. restart pldmd when Host is not running
2. restart pldmd when Host is running
3. restart pldmd when Host is not running and then ipl

Using pldmtool the DBus backened is verified.

Signed-off-by: Pavithra Barithaya <pavithra.b@ibm.com>
Change-Id: Idb9eb642dbf766bb587a3a4075e4dce2c9da2de5
diff --git a/host-bmc/host_pdr_handler.cpp b/host-bmc/host_pdr_handler.cpp
index a786ed4..45b178b 100644
--- a/host-bmc/host_pdr_handler.cpp
+++ b/host-bmc/host_pdr_handler.cpp
@@ -367,6 +367,13 @@
     static PDRList stateSensorPDRs{};
     static TLPDRMap tlpdrInfo{};
     uint32_t nextRecordHandle{};
+    std::vector<TlInfo> tlInfo;
+    uint8_t tlEid = 0;
+    bool tlValid = true;
+    uint32_t rh = 0;
+    uint16_t terminusHandle = 0;
+    uint8_t tid = 0;
+
     uint8_t completionCode{};
     uint32_t nextDataTransferHandle{};
     uint8_t transferFlag{};
@@ -413,7 +420,23 @@
         }
         else
         {
+            // when nextRecordHandle is 0, we need the recordHandle of the last
+            // PDR and not 0-1.
+            if (!nextRecordHandle)
+            {
+                rh = nextRecordHandle;
+            }
+            else
+            {
+                rh = nextRecordHandle - 1;
+            }
+
             auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
+            if (!rh)
+            {
+                rh = pdrHdr->record_handle;
+            }
+
             if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
             {
                 this->mergeEntityAssociations(pdr);
@@ -430,12 +453,41 @@
                         static_cast<pldm::pdr::TerminusHandle>(
                             tlpdr->terminus_handle),
                         static_cast<pldm::pdr::TerminusID>(tlpdr->tid));
+
+                    terminusHandle = tlpdr->terminus_handle;
+                    tid = tlpdr->tid;
+                    auto terminus_locator_type = tlpdr->terminus_locator_type;
+                    if (terminus_locator_type ==
+                        PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID)
+                    {
+                        auto locatorValue = reinterpret_cast<
+                            const pldm_terminus_locator_type_mctp_eid*>(
+                            tlpdr->terminus_locator_value);
+                        tlEid = static_cast<uint8_t>(locatorValue->eid);
+                    }
+                    if (tlpdr->validity == 0)
+                    {
+                        tlValid = false;
+                    }
+                    tlInfo.emplace_back(
+                        TlInfo{tlpdr->validity, static_cast<uint8_t>(tlEid),
+                               tlpdr->tid, tlpdr->terminus_handle});
                 }
                 else if (pdrHdr->type == PLDM_STATE_SENSOR_PDR)
                 {
                     stateSensorPDRs.emplace_back(pdr);
                 }
-                pldm_pdr_add(repo, pdr.data(), respCount, 0, true);
+
+                // if the TLPDR is invalid update the repo accordingly
+                if (!tlValid)
+                {
+                    pldm_pdr_update_TL_pdr(repo, terminusHandle, tid, tlEid,
+                                           tlValid);
+                }
+                else
+                {
+                    pldm_pdr_add(repo, pdr.data(), respCount, rh, true);
+                }
             }
         }
     }
@@ -443,6 +495,10 @@
     {
         /*received last record*/
         this->parseStateSensorPDRs(stateSensorPDRs, tlpdrInfo);
+        if (isHostUp())
+        {
+            this->setHostSensorState(stateSensorPDRs, tlInfo);
+        }
         stateSensorPDRs.clear();
         tlpdrInfo.clear();
         if (merged)
@@ -596,4 +652,166 @@
     return responseReceived;
 }
 
+void HostPDRHandler::setHostSensorState(const PDRList& stateSensorPDRs,
+                                        const std::vector<TlInfo>& tlinfo)
+{
+    for (const auto& stateSensorPDR : stateSensorPDRs)
+    {
+        auto pdr = reinterpret_cast<const pldm_state_sensor_pdr*>(
+            stateSensorPDR.data());
+
+        if (!pdr)
+        {
+            std::cerr << "Failed to get State sensor PDR" << std::endl;
+            pldm::utils::reportError(
+                "xyz.openbmc_project.bmc.pldm.InternalFailure");
+            return;
+        }
+
+        uint16_t sensorId = pdr->sensor_id;
+
+        for (auto info : tlinfo)
+        {
+            if (info.terminusHandle == pdr->terminus_handle)
+            {
+                if (info.valid == PLDM_TL_PDR_VALID)
+                {
+                    mctp_eid = info.eid;
+                }
+
+                bitfield8_t sensorRearm;
+                sensorRearm.byte = 0;
+                uint8_t tid = info.tid;
+
+                auto instanceId = requester.getInstanceId(mctp_eid);
+                std::vector<uint8_t> requestMsg(
+                    sizeof(pldm_msg_hdr) +
+                    PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES);
+                auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+                auto rc = encode_get_state_sensor_readings_req(
+                    instanceId, sensorId, sensorRearm, 0, request);
+
+                if (rc != PLDM_SUCCESS)
+                {
+                    requester.markFree(mctp_eid, instanceId);
+                    std::cerr << "Failed to "
+                                 "encode_get_state_sensor_readings_req, rc = "
+                              << rc << std::endl;
+                    pldm::utils::reportError(
+                        "xyz.openbmc_project.bmc.pldm.InternalFailure");
+                    return;
+                }
+
+                auto getStateSensorReadingRespHandler = [=, this](
+                                                            mctp_eid_t /*eid*/,
+                                                            const pldm_msg*
+                                                                response,
+                                                            size_t respMsgLen) {
+                    if (response == nullptr || !respMsgLen)
+                    {
+                        std::cerr << "Failed to receive response for "
+                                     "getStateSensorReading command \n";
+                        return;
+                    }
+                    std::array<get_sensor_state_field, 8> stateField{};
+                    uint8_t completionCode = 0;
+                    uint8_t comp_sensor_count = 0;
+
+                    auto rc = decode_get_state_sensor_readings_resp(
+                        response, respMsgLen, &completionCode,
+                        &comp_sensor_count, stateField.data());
+
+                    if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
+                    {
+                        std::cerr
+                            << "Failed to "
+                               "decode_get_state_sensor_readings_resp, rc = "
+                            << rc
+                            << " cc=" << static_cast<unsigned>(completionCode)
+                            << std::endl;
+                        pldm::utils::reportError(
+                            "xyz.openbmc_project.bmc.pldm.InternalFailure");
+                    }
+
+                    uint8_t eventState;
+                    uint8_t previousEventState;
+                    uint8_t sensorOffset = comp_sensor_count - 1;
+
+                    for (size_t i = 0; i < comp_sensor_count; i++)
+                    {
+                        eventState = stateField[i].present_state;
+                        previousEventState = stateField[i].previous_state;
+
+                        emitStateSensorEventSignal(tid, sensorId, sensorOffset,
+                                                   eventState,
+                                                   previousEventState);
+
+                        SensorEntry sensorEntry{tid, sensorId};
+
+                        pldm::pdr::EntityInfo entityInfo{};
+                        pldm::pdr::CompositeSensorStates
+                            compositeSensorStates{};
+
+                        try
+                        {
+                            std::tie(entityInfo, compositeSensorStates) =
+                                lookupSensorInfo(sensorEntry);
+                        }
+                        catch (const std::out_of_range& e)
+                        {
+                            try
+                            {
+                                sensorEntry.terminusID = PLDM_TID_RESERVED;
+                                std::tie(entityInfo, compositeSensorStates) =
+                                    lookupSensorInfo(sensorEntry);
+                            }
+                            catch (const std::out_of_range& e)
+                            {
+                                std::cerr << "No mapping for the events"
+                                          << std::endl;
+                            }
+                        }
+
+                        if (sensorOffset > compositeSensorStates.size())
+                        {
+                            std::cerr
+                                << " Error Invalid data, Invalid sensor offset"
+                                << std::endl;
+                            return;
+                        }
+
+                        const auto& possibleStates =
+                            compositeSensorStates[sensorOffset];
+                        if (possibleStates.find(eventState) ==
+                            possibleStates.end())
+                        {
+                            std::cerr
+                                << " Error invalid_data, Invalid event state"
+                                << std::endl;
+                            return;
+                        }
+                        const auto& [containerId, entityType, entityInstance] =
+                            entityInfo;
+                        pldm::responder::events::StateSensorEntry
+                            stateSensorEntry{containerId, entityType,
+                                             entityInstance, sensorOffset};
+                        handleStateSensorEvent(stateSensorEntry, eventState);
+                    }
+                };
+
+                rc = handler->registerRequest(
+                    mctp_eid, instanceId, PLDM_PLATFORM,
+                    PLDM_GET_STATE_SENSOR_READINGS, std::move(requestMsg),
+                    std::move(getStateSensorReadingRespHandler));
+
+                if (rc != PLDM_SUCCESS)
+                {
+                    std::cerr << " Failed to send request to get State sensor "
+                                 "reading on Host "
+                              << std::endl;
+                }
+            }
+        }
+    }
+}
 } // namespace pldm
diff --git a/host-bmc/host_pdr_handler.hpp b/host-bmc/host_pdr_handler.hpp
index 96c0226..dc539ce 100644
--- a/host-bmc/host_pdr_handler.hpp
+++ b/host-bmc/host_pdr_handler.hpp
@@ -53,6 +53,18 @@
     }
 };
 
+/* @struct TerminusLocatorInfo
+ * Contains validity, eid, terminus_id and terminus handle
+ * of a terminus locator PDR.
+ */
+struct TlInfo
+{
+    uint8_t valid;
+    uint8_t eid;
+    uint8_t tid;
+    uint16_t terminusHandle;
+};
+
 using HostStateSensorMap = std::map<SensorEntry, pdr::SensorInfo>;
 using PDRList = std::vector<std::vector<uint8_t>>;
 
@@ -155,6 +167,14 @@
      */
     void setHostState();
 
+    /** @brief set HostSensorStates when pldmd starts or restarts
+     *  and updates the D-Bus property
+     *  @param[in] stateSensorPDRs - host state sensor PDRs
+     *  @param[in] tlinfo - vector of struct TlInfo
+     */
+    void setHostSensorState(const PDRList& stateSensorPDRs,
+                            const std::vector<TlInfo>& tlinfo);
+
     /** @brief check whether Host is running when pldmd starts
      */
     bool isHostUp();
diff --git a/libpldm/pdr.c b/libpldm/pdr.c
index ec9ffee..a9132c7 100644
--- a/libpldm/pdr.c
+++ b/libpldm/pdr.c
@@ -250,7 +250,8 @@
 uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
 				     uint16_t fru_rsi, uint16_t entity_type,
 				     uint16_t entity_instance_num,
-				     uint16_t container_id)
+				     uint16_t container_id,
+				     uint32_t bmc_record_handle)
 {
 	uint32_t size = sizeof(struct pldm_pdr_hdr) +
 			sizeof(struct pldm_pdr_fru_record_set);
@@ -258,7 +259,7 @@
 
 	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
 	hdr->version = 1;
-	hdr->record_handle = 0;
+	hdr->record_handle = bmc_record_handle;
 	hdr->type = PLDM_PDR_FRU_RECORD_SET;
 	hdr->record_change_num = 0;
 	hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
@@ -271,7 +272,7 @@
 	fru->entity_instance_num = htole16(entity_instance_num);
 	fru->container_id = htole16(container_id);
 
-	return pldm_pdr_add(repo, data, size, 0, false);
+	return pldm_pdr_add(repo, data, size, bmc_record_handle, false);
 }
 
 const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
@@ -313,6 +314,33 @@
 	return NULL;
 }
 
+void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminusHandle,
+			    uint8_t tid, uint8_t tlEid, bool validBit)
+{
+	uint8_t *outData = NULL;
+	uint32_t size = 0;
+	const pldm_pdr_record *record;
+	record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
+					      NULL, &outData, &size);
+
+	do {
+		if (record != NULL) {
+			struct pldm_terminus_locator_pdr *pdr =
+			    (struct pldm_terminus_locator_pdr *)outData;
+			struct pldm_terminus_locator_type_mctp_eid *value =
+			    (struct pldm_terminus_locator_type_mctp_eid *)
+				pdr->terminus_locator_value;
+			if (pdr->terminus_handle == terminusHandle &&
+			    pdr->tid == tid && value->eid == tlEid) {
+				pdr->validity = validBit;
+				break;
+			}
+		}
+		record = pldm_pdr_find_record_by_type(
+		    repo, PLDM_TERMINUS_LOCATOR_PDR, record, &outData, &size);
+	} while (record);
+}
+
 typedef struct pldm_entity_association_tree {
 	pldm_entity_node *root;
 	uint16_t last_used_container_id;
diff --git a/libpldm/pdr.h b/libpldm/pdr.h
index 8f4d893..45ac9a6 100644
--- a/libpldm/pdr.h
+++ b/libpldm/pdr.h
@@ -144,6 +144,18 @@
  */
 void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo);
 
+/** @brief Update the validity of TL PDR - the validity is decided based on
+ * whether the valid bit is set or not as per the spec DSP0248
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] terminusHandle - PLDM terminus handle
+ * @param[in] tid - Terminus ID
+ * @param[in] tlEid - MCTP endpoint EID
+ * @param[in] valid - validity bit of TLPDR
+ */
+void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminusHandle,
+			    uint8_t tid, uint8_t tlEid, bool valid);
+
 /* ======================= */
 /* FRU Record Set PDR APIs */
 /* ======================= */
@@ -157,13 +169,15 @@
  *  @param[in] entity_type - entity type of FRU
  *  @param[in] entity_instance_num - entity instance number of FRU
  *  @param[in] container_id - container id of FRU
+ *  @param[in] bmc_record_handle - handle used to construct the next record
  *
  *  @return uint32_t - record handle assigned to PDR record
  */
 uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
 				     uint16_t fru_rsi, uint16_t entity_type,
 				     uint16_t entity_instance_num,
-				     uint16_t container_id);
+				     uint16_t container_id,
+				     uint32_t bmc_record_handle);
 
 /** @brief Find a FRU record set PDR by FRU record set identifier
  *
diff --git a/libpldm/tests/libpldm_pdr_test.cpp b/libpldm/tests/libpldm_pdr_test.cpp
index 8c070a3..30bd760 100644
--- a/libpldm/tests/libpldm_pdr_test.cpp
+++ b/libpldm/tests/libpldm_pdr_test.cpp
@@ -396,7 +396,7 @@
 {
     auto repo = pldm_pdr_init();
 
-    auto handle = pldm_pdr_add_fru_record_set(repo, 1, 10, 1, 0, 100);
+    auto handle = pldm_pdr_add_fru_record_set(repo, 1, 10, 1, 0, 100, 0);
     EXPECT_EQ(handle, 1u);
     EXPECT_EQ(pldm_pdr_get_record_count(repo), 1u);
     EXPECT_EQ(pldm_pdr_get_repo_size(repo),
@@ -422,7 +422,7 @@
     EXPECT_EQ(fru->container_id, htole16(100));
     outData = nullptr;
 
-    handle = pldm_pdr_add_fru_record_set(repo, 2, 11, 2, 1, 101);
+    handle = pldm_pdr_add_fru_record_set(repo, 2, 11, 2, 1, 101, 0);
     EXPECT_EQ(handle, 2u);
     EXPECT_EQ(pldm_pdr_get_record_count(repo), 2u);
     EXPECT_EQ(pldm_pdr_get_repo_size(repo),
@@ -474,9 +474,9 @@
     uint16_t entityType{};
     uint16_t entityInstanceNum{};
     uint16_t containerId{};
-    auto first = pldm_pdr_add_fru_record_set(repo, 1, 1, 1, 0, 100);
-    auto second = pldm_pdr_add_fru_record_set(repo, 1, 2, 1, 1, 100);
-    auto third = pldm_pdr_add_fru_record_set(repo, 1, 3, 1, 2, 100);
+    auto first = pldm_pdr_add_fru_record_set(repo, 1, 1, 1, 0, 100, 1);
+    auto second = pldm_pdr_add_fru_record_set(repo, 1, 2, 1, 1, 100, 2);
+    auto third = pldm_pdr_add_fru_record_set(repo, 1, 3, 1, 2, 100, 3);
     EXPECT_EQ(first, pldm_pdr_get_record_handle(
                          repo, pldm_pdr_fru_record_set_find_by_rsi(
                                    repo, 1, &terminusHdl, &entityType,
@@ -1349,7 +1349,7 @@
                                                PLDM_ENTITY_ASSOCIAION_PHYSICAL);
     auto first = pldm_pdr_add_fru_record_set(
         repo, 1, 1, entities[1].entity_type, entities[1].entity_instance_num,
-        entities[1].entity_container_id);
+        entities[1].entity_container_id, 1);
     EXPECT_NE(l1, nullptr);
     EXPECT_EQ(entities[1].entity_instance_num, 63);
     EXPECT_EQ(first, pldm_pdr_get_record_handle(
@@ -1363,7 +1363,7 @@
                                                PLDM_ENTITY_ASSOCIAION_PHYSICAL);
     auto second = pldm_pdr_add_fru_record_set(
         repo, 1, 2, entities[2].entity_type, entities[2].entity_instance_num,
-        entities[2].entity_container_id);
+        entities[2].entity_container_id, 2);
     EXPECT_NE(l2, nullptr);
     EXPECT_EQ(entities[2].entity_instance_num, 37);
     EXPECT_EQ(second, pldm_pdr_get_record_handle(
@@ -1377,7 +1377,7 @@
                                                PLDM_ENTITY_ASSOCIAION_PHYSICAL);
     auto third = pldm_pdr_add_fru_record_set(
         repo, 1, 3, entities[3].entity_type, entities[3].entity_instance_num,
-        entities[3].entity_container_id);
+        entities[3].entity_container_id, 3);
     EXPECT_NE(l3, nullptr);
     EXPECT_EQ(entities[3].entity_instance_num, 44);
     EXPECT_EQ(third, pldm_pdr_get_record_handle(
@@ -1391,7 +1391,7 @@
                                                PLDM_ENTITY_ASSOCIAION_PHYSICAL);
     auto fourth = pldm_pdr_add_fru_record_set(
         repo, 1, 4, entities[4].entity_type, entities[4].entity_instance_num,
-        entities[4].entity_container_id);
+        entities[4].entity_container_id, 4);
     EXPECT_NE(l4, nullptr);
     EXPECT_EQ(entities[4].entity_instance_num, 89);
     EXPECT_EQ(fourth, pldm_pdr_get_record_handle(
@@ -1405,7 +1405,7 @@
                                                PLDM_ENTITY_ASSOCIAION_PHYSICAL);
     auto fifth = pldm_pdr_add_fru_record_set(
         repo, 1, 5, entities[5].entity_type, entities[5].entity_instance_num,
-        entities[5].entity_container_id);
+        entities[5].entity_container_id, 5);
     EXPECT_NE(l5, nullptr);
     EXPECT_EQ(entities[5].entity_instance_num, 90);
     EXPECT_EQ(fifth, pldm_pdr_get_record_handle(
@@ -1423,7 +1423,7 @@
                                                PLDM_ENTITY_ASSOCIAION_PHYSICAL);
     auto seventh = pldm_pdr_add_fru_record_set(
         repo, 1, 7, entities[7].entity_type, entities[7].entity_instance_num,
-        entities[7].entity_container_id);
+        entities[7].entity_container_id, 7);
     EXPECT_NE(l7, nullptr);
     EXPECT_EQ(entities[7].entity_instance_num, 100);
     EXPECT_EQ(seventh, pldm_pdr_get_record_handle(
@@ -1437,7 +1437,7 @@
                                                PLDM_ENTITY_ASSOCIAION_PHYSICAL);
     auto eighth = pldm_pdr_add_fru_record_set(
         repo, 1, 8, entities[8].entity_type, entities[8].entity_instance_num,
-        entities[8].entity_container_id);
+        entities[8].entity_container_id, 8);
     EXPECT_NE(l8, nullptr);
     EXPECT_EQ(entities[8].entity_instance_num, 100);
     EXPECT_EQ(eighth, pldm_pdr_get_record_handle(
diff --git a/libpldmresponder/fru.cpp b/libpldmresponder/fru.cpp
index 094ea34..d53b8a7 100644
--- a/libpldmresponder/fru.cpp
+++ b/libpldmresponder/fru.cpp
@@ -161,6 +161,7 @@
     // added for the FRU
     uint16_t recordSetIdentifier = 0;
     auto numRecsCount = numRecs;
+    static uint32_t bmc_record_handle = 0;
 
     for (auto const& [recType, encType, fieldInfos] : recordInfos)
     {
@@ -221,9 +222,11 @@
             if (numRecs == numRecsCount)
             {
                 recordSetIdentifier = nextRSI();
+                bmc_record_handle = nextRecordHandle();
                 pldm_pdr_add_fru_record_set(
                     pdrRepo, 0, recordSetIdentifier, entity.entity_type,
-                    entity.entity_instance_num, entity.entity_container_id);
+                    entity.entity_instance_num, entity.entity_container_id,
+                    bmc_record_handle);
             }
             auto curSize = table.size();
             table.resize(curSize + recHeaderSize + tlvs.size());
diff --git a/libpldmresponder/fru.hpp b/libpldmresponder/fru.hpp
index 963a606..986a3d2 100644
--- a/libpldmresponder/fru.hpp
+++ b/libpldmresponder/fru.hpp
@@ -155,6 +155,12 @@
         return ++rsi;
     }
 
+    uint32_t nextRecordHandle()
+    {
+        return ++rh;
+    }
+
+    uint32_t rh = 0;
     uint16_t rsi = 0;
     uint16_t numRecs = 0;
     uint8_t padBytes = 0;