xref: /openbmc/openpower-hw-diags/util/pldm.cpp (revision 316acdacb382ec27a6ede244e8fda3847db37fa7)
19b1a0b6bSPavithra Barithaya #include "config.h"
29b1a0b6bSPavithra Barithaya 
3a001020fSAndrew Jeffery #include <libpldm/oem/ibm/state_set.h>
4bb90afc7SBen Tyner #include <libpldm/platform.h>
5bb90afc7SBen Tyner #include <libpldm/pldm.h>
69b1a0b6bSPavithra Barithaya #include <libpldm/transport.h>
7*316acdacSPavithra Barithaya #include <libpldm/transport/af-mctp.h>
89b1a0b6bSPavithra Barithaya #include <libpldm/transport/mctp-demux.h>
99b1a0b6bSPavithra Barithaya #include <poll.h>
10bb90afc7SBen Tyner 
11bb90afc7SBen Tyner #include <util/dbus.hpp>
1236b043e9SPavithra Barithaya #include <util/pldm.hpp>
13bb90afc7SBen Tyner #include <util/trace.hpp>
14bb90afc7SBen Tyner 
15bb90afc7SBen Tyner namespace util
16bb90afc7SBen Tyner {
17bb90afc7SBen Tyner namespace pldm
18bb90afc7SBen Tyner {
1936b043e9SPavithra Barithaya 
2036b043e9SPavithra Barithaya class PLDMInstanceManager
2136b043e9SPavithra Barithaya {
2236b043e9SPavithra Barithaya   public:
2336b043e9SPavithra Barithaya     // Singleton access method
getInstance()2436b043e9SPavithra Barithaya     static PLDMInstanceManager& getInstance()
2536b043e9SPavithra Barithaya     {
2636b043e9SPavithra Barithaya         static PLDMInstanceManager instance;
2736b043e9SPavithra Barithaya         return instance;
2836b043e9SPavithra Barithaya     }
2936b043e9SPavithra Barithaya 
3036b043e9SPavithra Barithaya     bool getPldmInstanceID(uint8_t& pldmInstance, uint8_t tid);
3136b043e9SPavithra Barithaya     void freePLDMInstanceID(pldm_instance_id_t instanceID, uint8_t tid);
3236b043e9SPavithra Barithaya 
339b1a0b6bSPavithra Barithaya     /**
349b1a0b6bSPavithra Barithaya      * @brief setup PLDM transport for sending and receiving messages
359b1a0b6bSPavithra Barithaya      *
369b1a0b6bSPavithra Barithaya      * @param[in] eid - MCTP endpoint ID
379b1a0b6bSPavithra Barithaya      * @return file descriptor on success and throw
389b1a0b6bSPavithra Barithaya      *         exception (xyz::openbmc_project::Common::Error::NotAllowed) on
399b1a0b6bSPavithra Barithaya      *         failures.
409b1a0b6bSPavithra Barithaya      */
419b1a0b6bSPavithra Barithaya     int openPLDM(mctp_eid_t eid);
429b1a0b6bSPavithra Barithaya     /** @brief Opens the MCTP socket for sending and receiving messages.
439b1a0b6bSPavithra Barithaya      *
449b1a0b6bSPavithra Barithaya      * @param[in] eid - MCTP endpoint ID
459b1a0b6bSPavithra Barithaya      */
469b1a0b6bSPavithra Barithaya     int openMctpDemuxTransport(mctp_eid_t eid);
479b1a0b6bSPavithra Barithaya 
489b1a0b6bSPavithra Barithaya     /** @brief Close the PLDM file */
499b1a0b6bSPavithra Barithaya     void closePLDM();
509b1a0b6bSPavithra Barithaya 
519b1a0b6bSPavithra Barithaya     /** @brief sending PLDM file */
529b1a0b6bSPavithra Barithaya     bool sendPldm(const std::vector<uint8_t>& request, uint8_t mctpEid);
539b1a0b6bSPavithra Barithaya 
54*316acdacSPavithra Barithaya     /** @brief Opens the MCTP AF_MCTP for sending and receiving messages.
55*316acdacSPavithra Barithaya      *
56*316acdacSPavithra Barithaya      * @param[in] eid - MCTP endpoint ID
57*316acdacSPavithra Barithaya      */
58*316acdacSPavithra Barithaya     int openAfMctpTransport(mctp_eid_t eid);
59*316acdacSPavithra Barithaya 
60*316acdacSPavithra Barithaya     union TransportImpl
61*316acdacSPavithra Barithaya     {
62*316acdacSPavithra Barithaya         pldm_transport_mctp_demux* mctpDemux;
63*316acdacSPavithra Barithaya         pldm_transport_af_mctp* afMctp;
64*316acdacSPavithra Barithaya     };
65*316acdacSPavithra Barithaya 
6636b043e9SPavithra Barithaya   private:
6736b043e9SPavithra Barithaya     // Private constructor and destructor to prevent creating multiple instances
6836b043e9SPavithra Barithaya     PLDMInstanceManager();
6936b043e9SPavithra Barithaya     ~PLDMInstanceManager();
7036b043e9SPavithra Barithaya 
7136b043e9SPavithra Barithaya     // Deleted copy constructor and assignment operator to prevent copying
7236b043e9SPavithra Barithaya     PLDMInstanceManager(const PLDMInstanceManager&) = delete;
7336b043e9SPavithra Barithaya     PLDMInstanceManager& operator=(const PLDMInstanceManager&) = delete;
7436b043e9SPavithra Barithaya 
7536b043e9SPavithra Barithaya     // Private member for the instance database
7636b043e9SPavithra Barithaya     pldm_instance_db* pldmInstanceIdDb;
779b1a0b6bSPavithra Barithaya 
789b1a0b6bSPavithra Barithaya     /** pldm transport instance  */
799b1a0b6bSPavithra Barithaya     struct pldm_transport* pldmTransport = NULL;
809b1a0b6bSPavithra Barithaya 
81*316acdacSPavithra Barithaya     // type of transport implementation instance
82*316acdacSPavithra Barithaya     TransportImpl impl;
8336b043e9SPavithra Barithaya };
8436b043e9SPavithra Barithaya 
PLDMInstanceManager()8536b043e9SPavithra Barithaya PLDMInstanceManager::PLDMInstanceManager() : pldmInstanceIdDb(nullptr)
8636b043e9SPavithra Barithaya {
8736b043e9SPavithra Barithaya     // Initialize the database object directly in the constructor
8836b043e9SPavithra Barithaya     auto rc = pldm_instance_db_init_default(&pldmInstanceIdDb);
8936b043e9SPavithra Barithaya     if (rc)
9036b043e9SPavithra Barithaya     {
9136b043e9SPavithra Barithaya         trace::err("Error calling pldm_instance_db_init_default, rc = %d",
9236b043e9SPavithra Barithaya                    (unsigned)rc);
9336b043e9SPavithra Barithaya     }
9436b043e9SPavithra Barithaya }
9536b043e9SPavithra Barithaya 
~PLDMInstanceManager()9636b043e9SPavithra Barithaya PLDMInstanceManager::~PLDMInstanceManager()
9736b043e9SPavithra Barithaya {
9836b043e9SPavithra Barithaya     // Directly destroy the database object in the destructor
9936b043e9SPavithra Barithaya     if (pldmInstanceIdDb)
10036b043e9SPavithra Barithaya     {
10136b043e9SPavithra Barithaya         auto rc = pldm_instance_db_destroy(pldmInstanceIdDb);
10236b043e9SPavithra Barithaya         if (rc)
10336b043e9SPavithra Barithaya         {
10436b043e9SPavithra Barithaya             trace::err("pldm_instance_db_destroy failed rc = %d", (unsigned)rc);
10536b043e9SPavithra Barithaya         }
10636b043e9SPavithra Barithaya     }
10736b043e9SPavithra Barithaya }
10836b043e9SPavithra Barithaya 
10936b043e9SPavithra Barithaya // Get the PLDM instance ID for the given terminus ID
getPldmInstanceID(uint8_t & pldmInstance,uint8_t tid)11036b043e9SPavithra Barithaya bool PLDMInstanceManager::getPldmInstanceID(uint8_t& pldmInstance, uint8_t tid)
11136b043e9SPavithra Barithaya {
11236b043e9SPavithra Barithaya     pldm_instance_id_t id;
11336b043e9SPavithra Barithaya     int rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid, &id);
11436b043e9SPavithra Barithaya     if (rc == -EAGAIN)
11536b043e9SPavithra Barithaya     {
11636b043e9SPavithra Barithaya         std::this_thread::sleep_for(
11736b043e9SPavithra Barithaya             std::chrono::milliseconds(100)); // Retry after 100ms
11836b043e9SPavithra Barithaya         rc = pldm_instance_id_alloc(pldmInstanceIdDb, tid,
11936b043e9SPavithra Barithaya                                     &id);    // Retry allocation
12036b043e9SPavithra Barithaya     }
12136b043e9SPavithra Barithaya 
12236b043e9SPavithra Barithaya     if (rc)
12336b043e9SPavithra Barithaya     {
12436b043e9SPavithra Barithaya         trace::err("getPldmInstanceId: Failed to alloc ID for TID = %d, RC= %d",
12536b043e9SPavithra Barithaya                    (unsigned)tid, (unsigned)rc);
12636b043e9SPavithra Barithaya         return false;
12736b043e9SPavithra Barithaya     }
12836b043e9SPavithra Barithaya 
12936b043e9SPavithra Barithaya     pldmInstance = id; // Return the allocated instance ID
13036b043e9SPavithra Barithaya     trace::inf("Got instanceId: %d, for PLDM TID: %d", (unsigned)pldmInstance,
13136b043e9SPavithra Barithaya                (unsigned)tid);
13236b043e9SPavithra Barithaya     return true;
13336b043e9SPavithra Barithaya }
13436b043e9SPavithra Barithaya 
13536b043e9SPavithra Barithaya // Free the PLDM instance ID associated with the terminus ID
freePLDMInstanceID(pldm_instance_id_t instanceID,uint8_t tid)13636b043e9SPavithra Barithaya void PLDMInstanceManager::freePLDMInstanceID(pldm_instance_id_t instanceID,
13736b043e9SPavithra Barithaya                                              uint8_t tid)
13836b043e9SPavithra Barithaya {
13936b043e9SPavithra Barithaya     int rc = pldm_instance_id_free(pldmInstanceIdDb, tid, instanceID);
14036b043e9SPavithra Barithaya     if (rc)
14136b043e9SPavithra Barithaya     {
14236b043e9SPavithra Barithaya         trace::err(
14336b043e9SPavithra Barithaya             "pldm_instance_id_free failed to free id=%d of TID=%d with rc= %d",
14436b043e9SPavithra Barithaya             (unsigned)instanceID, (unsigned)tid, (unsigned)rc);
14536b043e9SPavithra Barithaya     }
14636b043e9SPavithra Barithaya }
14736b043e9SPavithra Barithaya 
openPLDM(mctp_eid_t eid)1489b1a0b6bSPavithra Barithaya int PLDMInstanceManager::openPLDM(mctp_eid_t eid)
1499b1a0b6bSPavithra Barithaya {
1509b1a0b6bSPavithra Barithaya     auto fd = -1;
1519b1a0b6bSPavithra Barithaya     if (pldmTransport)
1529b1a0b6bSPavithra Barithaya     {
1539b1a0b6bSPavithra Barithaya         trace::inf("open: pldmTransport already setup!");
1549b1a0b6bSPavithra Barithaya         return fd;
1559b1a0b6bSPavithra Barithaya     }
156*316acdacSPavithra Barithaya #if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX)
1579b1a0b6bSPavithra Barithaya     fd = openMctpDemuxTransport(eid);
158*316acdacSPavithra Barithaya #elif defined(PLDM_TRANSPORT_WITH_AF_MCTP)
159*316acdacSPavithra Barithaya     fd = openAfMctpTransport(eid);
160*316acdacSPavithra Barithaya #else
161*316acdacSPavithra Barithaya     trace::err("open: No valid transport defined!");
162*316acdacSPavithra Barithaya #endif
1639b1a0b6bSPavithra Barithaya     if (fd < 0)
1649b1a0b6bSPavithra Barithaya     {
1659b1a0b6bSPavithra Barithaya         auto e = errno;
1669b1a0b6bSPavithra Barithaya         trace::err("openPLDM failed, fd = %d and error= %d", (unsigned)fd, e);
1679b1a0b6bSPavithra Barithaya     }
1689b1a0b6bSPavithra Barithaya     return fd;
1699b1a0b6bSPavithra Barithaya }
1709b1a0b6bSPavithra Barithaya 
openMctpDemuxTransport(mctp_eid_t eid)171*316acdacSPavithra Barithaya [[maybe_unused]] int PLDMInstanceManager::openMctpDemuxTransport(mctp_eid_t eid)
1729b1a0b6bSPavithra Barithaya {
173*316acdacSPavithra Barithaya     impl.mctpDemux = nullptr;
174*316acdacSPavithra Barithaya     int rc = pldm_transport_mctp_demux_init(&impl.mctpDemux);
1759b1a0b6bSPavithra Barithaya     if (rc)
1769b1a0b6bSPavithra Barithaya     {
1779b1a0b6bSPavithra Barithaya         trace::err(
1789b1a0b6bSPavithra Barithaya             "openMctpDemuxTransport: Failed to setup tid to eid mapping. rc = %d",
1799b1a0b6bSPavithra Barithaya             (unsigned)rc);
1809b1a0b6bSPavithra Barithaya         closePLDM();
1819b1a0b6bSPavithra Barithaya         return rc;
1829b1a0b6bSPavithra Barithaya     }
1839b1a0b6bSPavithra Barithaya 
184*316acdacSPavithra Barithaya     rc = pldm_transport_mctp_demux_map_tid(impl.mctpDemux, eid, eid);
1859b1a0b6bSPavithra Barithaya     if (rc)
1869b1a0b6bSPavithra Barithaya     {
1879b1a0b6bSPavithra Barithaya         trace::err(
1889b1a0b6bSPavithra Barithaya             "openMctpDemuxTransport: Failed to setup tid to eid mapping. rc = %d",
1899b1a0b6bSPavithra Barithaya             (unsigned)rc);
1909b1a0b6bSPavithra Barithaya         closePLDM();
1919b1a0b6bSPavithra Barithaya         return rc;
1929b1a0b6bSPavithra Barithaya     }
1939b1a0b6bSPavithra Barithaya 
194*316acdacSPavithra Barithaya     pldmTransport = pldm_transport_mctp_demux_core(impl.mctpDemux);
1959b1a0b6bSPavithra Barithaya     struct pollfd pollfd;
1969b1a0b6bSPavithra Barithaya     rc = pldm_transport_mctp_demux_init_pollfd(pldmTransport, &pollfd);
1979b1a0b6bSPavithra Barithaya     if (rc)
1989b1a0b6bSPavithra Barithaya     {
1999b1a0b6bSPavithra Barithaya         trace::err("openMctpDemuxTransport: Failed to get pollfd. rc= %d",
2009b1a0b6bSPavithra Barithaya                    (unsigned)rc);
2019b1a0b6bSPavithra Barithaya         closePLDM();
2029b1a0b6bSPavithra Barithaya         return rc;
2039b1a0b6bSPavithra Barithaya     }
2049b1a0b6bSPavithra Barithaya     return pollfd.fd;
2059b1a0b6bSPavithra Barithaya }
206*316acdacSPavithra Barithaya 
openAfMctpTransport(mctp_eid_t eid)207*316acdacSPavithra Barithaya [[maybe_unused]] int PLDMInstanceManager::openAfMctpTransport(mctp_eid_t eid)
208*316acdacSPavithra Barithaya {
209*316acdacSPavithra Barithaya     impl.afMctp = nullptr;
210*316acdacSPavithra Barithaya     int rc = pldm_transport_af_mctp_init(&impl.afMctp);
211*316acdacSPavithra Barithaya     if (rc)
212*316acdacSPavithra Barithaya     {
213*316acdacSPavithra Barithaya         trace::err(
214*316acdacSPavithra Barithaya             "openAfMctpTransport: Failed to init AF MCTP transport. rc = %d",
215*316acdacSPavithra Barithaya             (unsigned)rc);
216*316acdacSPavithra Barithaya         return rc;
217*316acdacSPavithra Barithaya     }
218*316acdacSPavithra Barithaya     rc = pldm_transport_af_mctp_map_tid(impl.afMctp, eid, eid);
219*316acdacSPavithra Barithaya     if (rc)
220*316acdacSPavithra Barithaya     {
221*316acdacSPavithra Barithaya         trace::err(
222*316acdacSPavithra Barithaya             "openAfMctpTransport: Failed to setup tid to eid mapping. rc = %d",
223*316acdacSPavithra Barithaya             (unsigned)rc);
224*316acdacSPavithra Barithaya         closePLDM();
225*316acdacSPavithra Barithaya         return rc;
226*316acdacSPavithra Barithaya     }
227*316acdacSPavithra Barithaya     pldmTransport = pldm_transport_af_mctp_core(impl.afMctp);
228*316acdacSPavithra Barithaya     struct pollfd pollfd;
229*316acdacSPavithra Barithaya     rc = pldm_transport_af_mctp_init_pollfd(pldmTransport, &pollfd);
230*316acdacSPavithra Barithaya     if (rc)
231*316acdacSPavithra Barithaya     {
232*316acdacSPavithra Barithaya         trace::err("openAfMctpTransport: Failed to get pollfd. rc = %d",
233*316acdacSPavithra Barithaya                    (unsigned)rc);
234*316acdacSPavithra Barithaya         closePLDM();
235*316acdacSPavithra Barithaya         return rc;
236*316acdacSPavithra Barithaya     }
237*316acdacSPavithra Barithaya     return pollfd.fd;
238*316acdacSPavithra Barithaya }
239*316acdacSPavithra Barithaya 
closePLDM()2409b1a0b6bSPavithra Barithaya void PLDMInstanceManager::closePLDM()
2419b1a0b6bSPavithra Barithaya {
242*316acdacSPavithra Barithaya #if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX)
243*316acdacSPavithra Barithaya     pldm_transport_mctp_demux_destroy(impl.mctpDemux);
244*316acdacSPavithra Barithaya     impl.mctpDemux = nullptr;
245*316acdacSPavithra Barithaya #elif defined(PLDM_TRANSPORT_WITH_AF_MCTP)
246*316acdacSPavithra Barithaya     pldm_transport_af_mctp_destroy(impl.afMctp);
247*316acdacSPavithra Barithaya     impl.afMctp = nullptr;
248*316acdacSPavithra Barithaya #endif
2499b1a0b6bSPavithra Barithaya     pldmTransport = NULL;
2509b1a0b6bSPavithra Barithaya }
2519b1a0b6bSPavithra Barithaya 
252bb90afc7SBen Tyner /** @brief Send PLDM request
253bb90afc7SBen Tyner  *
254bb90afc7SBen Tyner  * @param[in] request - the request data
255bb90afc7SBen Tyner  * @param[in] mcptEid - the mctp endpoint ID
256bb90afc7SBen Tyner  *
257bb90afc7SBen Tyner  * @pre a mctp instance must have been
258bb90afc7SBen Tyner  * @return true if send is successful false otherwise
259bb90afc7SBen Tyner  */
sendPldm(const std::vector<uint8_t> & request,uint8_t mctpEid)2609b1a0b6bSPavithra Barithaya bool PLDMInstanceManager::sendPldm(const std::vector<uint8_t>& request,
2619b1a0b6bSPavithra Barithaya                                    uint8_t mctpEid)
262bb90afc7SBen Tyner {
2639b1a0b6bSPavithra Barithaya     auto rc = openPLDM(mctpEid);
2649b1a0b6bSPavithra Barithaya     if (rc)
265bb90afc7SBen Tyner     {
266bb90afc7SBen Tyner         trace::err("failed to connect to pldm");
267bb90afc7SBen Tyner         return false;
268bb90afc7SBen Tyner     }
269bb90afc7SBen Tyner 
2709b1a0b6bSPavithra Barithaya     pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEid);
271bb90afc7SBen Tyner     // send PLDM request
2729b1a0b6bSPavithra Barithaya     auto pldmRc = pldm_transport_send_msg(pldmTransport, pldmTID,
2739b1a0b6bSPavithra Barithaya                                           request.data(), request.size());
274bb90afc7SBen Tyner 
275bb90afc7SBen Tyner     trace::inf("sent pldm request");
276bb90afc7SBen Tyner 
277bb90afc7SBen Tyner     return pldmRc == PLDM_REQUESTER_SUCCESS ? true : false;
278bb90afc7SBen Tyner }
279bb90afc7SBen Tyner 
280bb90afc7SBen Tyner /** @brief Prepare a request for SetStateEffecterStates
281bb90afc7SBen Tyner  *
282bb90afc7SBen Tyner  *  @param[in] effecterId - the effecter ID
283bb90afc7SBen Tyner  *  @param[in] effecterCount - composite effecter count
284bb90afc7SBen Tyner  *  @param[in] stateIdPos - position of the state set
285bb90afc7SBen Tyner  *  @param[in] stateSetValue - the value to set the state
286bb90afc7SBen Tyner  *  @param[in] mcptEid - the MCTP endpoint ID
287bb90afc7SBen Tyner  *
288bb90afc7SBen Tyner  *  @return PLDM request message to be sent to host, empty message on error
289bb90afc7SBen Tyner  */
prepareSetEffecterReq(uint16_t effecterId,uint8_t effecterCount,uint8_t stateIdPos,uint8_t stateSetValue,uint8_t mctpEid)290a0c724d3SPatrick Williams std::vector<uint8_t> prepareSetEffecterReq(
291a0c724d3SPatrick Williams     uint16_t effecterId, uint8_t effecterCount, uint8_t stateIdPos,
292a0c724d3SPatrick Williams     uint8_t stateSetValue, uint8_t mctpEid)
293bb90afc7SBen Tyner {
29436b043e9SPavithra Barithaya     PLDMInstanceManager& manager = PLDMInstanceManager::getInstance();
29536b043e9SPavithra Barithaya 
29608f25b21SPavithra Barithaya     // get pldm instance associated with the endpoint ID
29708f25b21SPavithra Barithaya     uint8_t pldmInstanceID;
29836b043e9SPavithra Barithaya     if (!manager.getPldmInstanceID(pldmInstanceID, mctpEid))
299bb90afc7SBen Tyner     {
300bb90afc7SBen Tyner         return std::vector<uint8_t>();
301bb90afc7SBen Tyner     }
302bb90afc7SBen Tyner 
303bb90afc7SBen Tyner     // form the request message
304bb90afc7SBen Tyner     std::vector<uint8_t> request(
305bb90afc7SBen Tyner         sizeof(pldm_msg_hdr) + sizeof(effecterId) + sizeof(effecterCount) +
306bb90afc7SBen Tyner         (effecterCount * sizeof(set_effecter_state_field)));
307bb90afc7SBen Tyner 
308bb90afc7SBen Tyner     // encode the state data with the change we want to elicit
309bb90afc7SBen Tyner     std::vector<set_effecter_state_field> stateField;
310bb90afc7SBen Tyner     for (uint8_t effecterPos = 0; effecterPos < effecterCount; effecterPos++)
311bb90afc7SBen Tyner     {
312bb90afc7SBen Tyner         if (effecterPos == stateIdPos)
313bb90afc7SBen Tyner         {
314bb90afc7SBen Tyner             stateField.emplace_back(
315bb90afc7SBen Tyner                 set_effecter_state_field{PLDM_REQUEST_SET, stateSetValue});
316bb90afc7SBen Tyner         }
317bb90afc7SBen Tyner         else
318bb90afc7SBen Tyner         {
319bb90afc7SBen Tyner             stateField.emplace_back(
320bb90afc7SBen Tyner                 set_effecter_state_field{PLDM_NO_CHANGE, 0});
321bb90afc7SBen Tyner         }
322bb90afc7SBen Tyner     }
323bb90afc7SBen Tyner 
324bb90afc7SBen Tyner     // encode the message with state data
325bb90afc7SBen Tyner     auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
326bb90afc7SBen Tyner     auto rc = encode_set_state_effecter_states_req(
32708f25b21SPavithra Barithaya         pldmInstanceID, effecterId, effecterCount, stateField.data(),
32808f25b21SPavithra Barithaya         requestMsg);
329bb90afc7SBen Tyner 
330bb90afc7SBen Tyner     if (rc != PLDM_SUCCESS)
331bb90afc7SBen Tyner     {
332bb90afc7SBen Tyner         trace::err("encode set effecter states request failed");
33336b043e9SPavithra Barithaya         manager.freePLDMInstanceID(pldmInstanceID, mctpEid);
334bb90afc7SBen Tyner         request.clear();
335bb90afc7SBen Tyner     }
336bb90afc7SBen Tyner 
337bb90afc7SBen Tyner     return request;
338bb90afc7SBen Tyner }
339bb90afc7SBen Tyner 
340bb90afc7SBen Tyner /** @brief Return map of sensor ID to SBE instance
341bb90afc7SBen Tyner  *
342bb90afc7SBen Tyner  *  @param[in] stateSetId - the state set ID of interest
343bb90afc7SBen Tyner  *  @param[out] sensorInstanceMap - map of sensor to SBE instance
344bb90afc7SBen Tyner  *  @param[out] sensorOffset - position of sensor with state set ID within map
345bb90afc7SBen Tyner  *
346bb90afc7SBen Tyner  *  @return true if sensor info is available false otherwise
347bb90afc7SBen Tyner  */
fetchSensorInfo(uint16_t stateSetId,std::map<uint16_t,unsigned int> & sensorInstanceMap,uint8_t & sensorOffset)348bb90afc7SBen Tyner bool fetchSensorInfo(uint16_t stateSetId,
349bb90afc7SBen Tyner                      std::map<uint16_t, unsigned int>& sensorInstanceMap,
350bb90afc7SBen Tyner                      uint8_t& sensorOffset)
351bb90afc7SBen Tyner {
352bb90afc7SBen Tyner     // get state sensor PDRs
353bb90afc7SBen Tyner     std::vector<std::vector<uint8_t>> pdrs{};
354bb90afc7SBen Tyner     if (!util::dbus::getStateSensorPdrs(pdrs, stateSetId))
355bb90afc7SBen Tyner     {
356bb90afc7SBen Tyner         return false;
357bb90afc7SBen Tyner     }
358bb90afc7SBen Tyner 
359bb90afc7SBen Tyner     // check for any PDRs available
360bb90afc7SBen Tyner     if (!pdrs.size())
361bb90afc7SBen Tyner     {
362bb90afc7SBen Tyner         trace::err("state sensor PDRs not present");
363bb90afc7SBen Tyner         return false;
364bb90afc7SBen Tyner     }
365bb90afc7SBen Tyner 
366bb90afc7SBen Tyner     // find the offset of specified sensor withing PDRs
367bb90afc7SBen Tyner     bool offsetFound = false;
368bb90afc7SBen Tyner     auto stateSensorPDR =
369bb90afc7SBen Tyner         reinterpret_cast<const pldm_state_sensor_pdr*>(pdrs.front().data());
370bb90afc7SBen Tyner     auto possibleStatesPtr = stateSensorPDR->possible_states;
371bb90afc7SBen Tyner 
372bb90afc7SBen Tyner     for (auto offset = 0; offset < stateSensorPDR->composite_sensor_count;
373bb90afc7SBen Tyner          offset++)
374bb90afc7SBen Tyner     {
375bb90afc7SBen Tyner         auto possibleStates =
376bb90afc7SBen Tyner             reinterpret_cast<const state_sensor_possible_states*>(
377bb90afc7SBen Tyner                 possibleStatesPtr);
378bb90afc7SBen Tyner 
379bb90afc7SBen Tyner         if (possibleStates->state_set_id == stateSetId)
380bb90afc7SBen Tyner         {
381bb90afc7SBen Tyner             sensorOffset = offset;
382bb90afc7SBen Tyner             offsetFound = true;
383bb90afc7SBen Tyner             break;
384bb90afc7SBen Tyner         }
385bb90afc7SBen Tyner         possibleStatesPtr += sizeof(possibleStates->state_set_id) +
386bb90afc7SBen Tyner                              sizeof(possibleStates->possible_states_size) +
387bb90afc7SBen Tyner                              possibleStates->possible_states_size;
388bb90afc7SBen Tyner     }
389bb90afc7SBen Tyner 
390bb90afc7SBen Tyner     if (!offsetFound)
391bb90afc7SBen Tyner     {
392bb90afc7SBen Tyner         trace::err("state sensor not found");
393bb90afc7SBen Tyner         return false;
394bb90afc7SBen Tyner     }
395bb90afc7SBen Tyner 
396bb90afc7SBen Tyner     // map sensor ID to equivelent 16 bit value
397bb90afc7SBen Tyner     std::map<uint32_t, uint16_t> entityInstMap{};
398bb90afc7SBen Tyner     for (auto& pdr : pdrs)
399bb90afc7SBen Tyner     {
400bb90afc7SBen Tyner         auto pdrPtr =
401bb90afc7SBen Tyner             reinterpret_cast<const pldm_state_sensor_pdr*>(pdr.data());
402bb90afc7SBen Tyner         uint32_t key = pdrPtr->sensor_id;
403bb90afc7SBen Tyner         entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->sensor_id));
404bb90afc7SBen Tyner     }
405bb90afc7SBen Tyner 
406bb90afc7SBen Tyner     // map sensor ID to zero based SBE instance
407bb90afc7SBen Tyner     unsigned int position = 0;
40827dd6368SPatrick Williams     for (const auto& pair : entityInstMap)
409bb90afc7SBen Tyner     {
410bb90afc7SBen Tyner         sensorInstanceMap.emplace(pair.second, position);
411bb90afc7SBen Tyner         position++;
412bb90afc7SBen Tyner     }
413bb90afc7SBen Tyner 
414bb90afc7SBen Tyner     return true;
415bb90afc7SBen Tyner }
416bb90afc7SBen Tyner 
417bb90afc7SBen Tyner /** @brief Return map of SBE instance to effecter ID
418bb90afc7SBen Tyner  *
419bb90afc7SBen Tyner  *  @param[in] stateSetId - the state set ID of interest
420bb90afc7SBen Tyner  *  @param[out] instanceToEffecterMap - map of sbe instance to effecter ID
421bb90afc7SBen Tyner  *  @param[out] effecterCount - composite effecter count
422bb90afc7SBen Tyner  *  @param[out] stateIdPos - position of effecter with state set ID within map
423bb90afc7SBen Tyner  *
424bb90afc7SBen Tyner  *  @return true if effector info is available false otherwise
425bb90afc7SBen Tyner  */
fetchEffecterInfo(uint16_t stateSetId,std::map<unsigned int,uint16_t> & instanceToEffecterMap,uint8_t & effecterCount,uint8_t & stateIdPos)426bb90afc7SBen Tyner bool fetchEffecterInfo(uint16_t stateSetId,
427bb90afc7SBen Tyner                        std::map<unsigned int, uint16_t>& instanceToEffecterMap,
428bb90afc7SBen Tyner                        uint8_t& effecterCount, uint8_t& stateIdPos)
429bb90afc7SBen Tyner {
430bb90afc7SBen Tyner     // get state effecter PDRs
431bb90afc7SBen Tyner     std::vector<std::vector<uint8_t>> pdrs{};
432bb90afc7SBen Tyner     if (!util::dbus::getStateEffecterPdrs(pdrs, stateSetId))
433bb90afc7SBen Tyner     {
434bb90afc7SBen Tyner         return false;
435bb90afc7SBen Tyner     }
436bb90afc7SBen Tyner 
437bb90afc7SBen Tyner     // check for any PDRs available
438bb90afc7SBen Tyner     if (!pdrs.size())
439bb90afc7SBen Tyner     {
440bb90afc7SBen Tyner         trace::err("state effecter PDRs not present");
441bb90afc7SBen Tyner         return false;
442bb90afc7SBen Tyner     }
443bb90afc7SBen Tyner 
444bb90afc7SBen Tyner     // find the offset of specified effector within PDRs
445bb90afc7SBen Tyner     bool offsetFound = false;
446bb90afc7SBen Tyner     auto stateEffecterPDR =
447bb90afc7SBen Tyner         reinterpret_cast<const pldm_state_effecter_pdr*>(pdrs.front().data());
448bb90afc7SBen Tyner     auto possibleStatesPtr = stateEffecterPDR->possible_states;
449bb90afc7SBen Tyner 
450bb90afc7SBen Tyner     for (auto offset = 0; offset < stateEffecterPDR->composite_effecter_count;
451bb90afc7SBen Tyner          offset++)
452bb90afc7SBen Tyner     {
453bb90afc7SBen Tyner         auto possibleStates =
454bb90afc7SBen Tyner             reinterpret_cast<const state_effecter_possible_states*>(
455bb90afc7SBen Tyner                 possibleStatesPtr);
456bb90afc7SBen Tyner 
457bb90afc7SBen Tyner         if (possibleStates->state_set_id == stateSetId)
458bb90afc7SBen Tyner         {
459bb90afc7SBen Tyner             stateIdPos = offset;
460bb90afc7SBen Tyner             effecterCount = stateEffecterPDR->composite_effecter_count;
461bb90afc7SBen Tyner             offsetFound = true;
462bb90afc7SBen Tyner             break;
463bb90afc7SBen Tyner         }
464bb90afc7SBen Tyner         possibleStatesPtr += sizeof(possibleStates->state_set_id) +
465bb90afc7SBen Tyner                              sizeof(possibleStates->possible_states_size) +
466bb90afc7SBen Tyner                              possibleStates->possible_states_size;
467bb90afc7SBen Tyner     }
468bb90afc7SBen Tyner 
469bb90afc7SBen Tyner     if (!offsetFound)
470bb90afc7SBen Tyner     {
471bb90afc7SBen Tyner         trace::err("state set effecter not found");
472bb90afc7SBen Tyner         return false;
473bb90afc7SBen Tyner     }
474bb90afc7SBen Tyner 
475bb90afc7SBen Tyner     // map effecter ID to equivelent 16 bit value
476bb90afc7SBen Tyner     std::map<uint32_t, uint16_t> entityInstMap{};
477bb90afc7SBen Tyner     for (auto& pdr : pdrs)
478bb90afc7SBen Tyner     {
479bb90afc7SBen Tyner         auto pdrPtr =
480bb90afc7SBen Tyner             reinterpret_cast<const pldm_state_effecter_pdr*>(pdr.data());
481bb90afc7SBen Tyner         uint32_t key = pdrPtr->effecter_id;
482bb90afc7SBen Tyner         entityInstMap.emplace(key, static_cast<uint16_t>(pdrPtr->effecter_id));
483bb90afc7SBen Tyner     }
484bb90afc7SBen Tyner 
485bb90afc7SBen Tyner     // map zero based SBE instance to effecter ID
486bb90afc7SBen Tyner     unsigned int position = 0;
48727dd6368SPatrick Williams     for (const auto& pair : entityInstMap)
488bb90afc7SBen Tyner     {
489bb90afc7SBen Tyner         instanceToEffecterMap.emplace(position, pair.second);
490bb90afc7SBen Tyner         position++;
491bb90afc7SBen Tyner     }
492bb90afc7SBen Tyner 
493bb90afc7SBen Tyner     return true;
494bb90afc7SBen Tyner }
495bb90afc7SBen Tyner 
496bb90afc7SBen Tyner /**  @brief Reset SBE using HBRT PLDM interface */
hresetSbe(unsigned int sbeInstance)497bb90afc7SBen Tyner bool hresetSbe(unsigned int sbeInstance)
498bb90afc7SBen Tyner {
499bb90afc7SBen Tyner     trace::inf("requesting sbe hreset");
500bb90afc7SBen Tyner 
501bb90afc7SBen Tyner     // get effecter info
502bb90afc7SBen Tyner     std::map<unsigned int, uint16_t> sbeInstanceToEffecter;
503bb90afc7SBen Tyner     uint8_t SBEEffecterCount = 0;
504bb90afc7SBen Tyner     uint8_t sbeMaintenanceStatePosition = 0;
505bb90afc7SBen Tyner 
506bb90afc7SBen Tyner     if (!fetchEffecterInfo(PLDM_OEM_IBM_SBE_MAINTENANCE_STATE,
507bb90afc7SBen Tyner                            sbeInstanceToEffecter, SBEEffecterCount,
508bb90afc7SBen Tyner                            sbeMaintenanceStatePosition))
509bb90afc7SBen Tyner     {
510bb90afc7SBen Tyner         return false;
511bb90afc7SBen Tyner     }
512bb90afc7SBen Tyner 
513bb90afc7SBen Tyner     // find the state effecter ID for the given SBE instance
514bb90afc7SBen Tyner     auto effecterEntry = sbeInstanceToEffecter.find(sbeInstance);
515bb90afc7SBen Tyner     if (effecterEntry == sbeInstanceToEffecter.end())
516bb90afc7SBen Tyner     {
517bb90afc7SBen Tyner         trace::err("failed to find effecter for SBE");
518bb90afc7SBen Tyner         return false;
519bb90afc7SBen Tyner     }
520bb90afc7SBen Tyner 
521bb90afc7SBen Tyner     // create request to HRESET the SBE
522bb90afc7SBen Tyner     constexpr uint8_t hbrtMctpEid = 10; // HBRT MCTP EID
523bb90afc7SBen Tyner 
524bb90afc7SBen Tyner     auto request = prepareSetEffecterReq(
525bb90afc7SBen Tyner         effecterEntry->second, SBEEffecterCount, sbeMaintenanceStatePosition,
526bb90afc7SBen Tyner         SBE_RETRY_REQUIRED, hbrtMctpEid);
527bb90afc7SBen Tyner 
528bb90afc7SBen Tyner     if (request.empty())
529bb90afc7SBen Tyner     {
530bb90afc7SBen Tyner         trace::err("HRESET effecter request empty");
531bb90afc7SBen Tyner         return false;
532bb90afc7SBen Tyner     }
533bb90afc7SBen Tyner 
534bb90afc7SBen Tyner     // get sensor info for validating sensor change
535bb90afc7SBen Tyner     std::map<uint16_t, unsigned int> sensorToSbeInstance;
536bb90afc7SBen Tyner     uint8_t sbeSensorOffset = 0;
537bb90afc7SBen Tyner     if (!fetchSensorInfo(PLDM_OEM_IBM_SBE_HRESET_STATE, sensorToSbeInstance,
538bb90afc7SBen Tyner                          sbeSensorOffset))
539bb90afc7SBen Tyner     {
54036b043e9SPavithra Barithaya         PLDMInstanceManager& manager = PLDMInstanceManager::getInstance();
54136b043e9SPavithra Barithaya         auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&request);
54236b043e9SPavithra Barithaya         manager.freePLDMInstanceID(reqhdr->instance_id, hbrtMctpEid);
543bb90afc7SBen Tyner         return false;
544bb90afc7SBen Tyner     }
545bb90afc7SBen Tyner 
546bb90afc7SBen Tyner     // register signal change listener
547bb90afc7SBen Tyner     std::string hresetStatus = "requested";
548bb90afc7SBen Tyner     constexpr auto interface = "xyz.openbmc_project.PLDM.Event";
549bb90afc7SBen Tyner     constexpr auto path = "/xyz/openbmc_project/pldm";
550bb90afc7SBen Tyner     constexpr auto member = "StateSensorEvent";
551bb90afc7SBen Tyner 
552bb90afc7SBen Tyner     auto bus = sdbusplus::bus::new_default();
553bb90afc7SBen Tyner     std::unique_ptr<sdbusplus::bus::match_t> match =
554bb90afc7SBen Tyner         std::make_unique<sdbusplus::bus::match_t>(
555bb90afc7SBen Tyner             bus,
556bb90afc7SBen Tyner             sdbusplus::bus::match::rules::type::signal() +
557bb90afc7SBen Tyner                 sdbusplus::bus::match::rules::member(member) +
558bb90afc7SBen Tyner                 sdbusplus::bus::match::rules::path(path) +
559bb90afc7SBen Tyner                 sdbusplus::bus::match::rules::interface(interface),
560bb90afc7SBen Tyner             [&](auto& msg) {
561bb90afc7SBen Tyner                 uint8_t sensorTid{};
562bb90afc7SBen Tyner                 uint16_t sensorId{};
563bb90afc7SBen Tyner                 uint8_t msgSensorOffset{};
564bb90afc7SBen Tyner                 uint8_t eventState{};
565bb90afc7SBen Tyner                 uint8_t previousEventState{};
566bb90afc7SBen Tyner 
567bb90afc7SBen Tyner                 // get sensor event details
568bb90afc7SBen Tyner                 msg.read(sensorTid, sensorId, msgSensorOffset, eventState,
569bb90afc7SBen Tyner                          previousEventState);
570bb90afc7SBen Tyner 
571bb90afc7SBen Tyner                 // does sensor offset match?
572bb90afc7SBen Tyner                 if (sbeSensorOffset == msgSensorOffset)
573bb90afc7SBen Tyner                 {
574bb90afc7SBen Tyner                     // does sensor ID match?
575bb90afc7SBen Tyner                     auto sensorEntry = sensorToSbeInstance.find(sensorId);
576bb90afc7SBen Tyner                     if (sensorEntry != sensorToSbeInstance.end())
577bb90afc7SBen Tyner                     {
578bb90afc7SBen Tyner                         const uint8_t instance = sensorEntry->second;
579bb90afc7SBen Tyner 
580bb90afc7SBen Tyner                         // if instances matche check status
581bb90afc7SBen Tyner                         if (instance == sbeInstance)
582bb90afc7SBen Tyner                         {
583a0c724d3SPatrick Williams                             if (eventState ==
584a0c724d3SPatrick Williams                                 static_cast<uint8_t>(SBE_HRESET_READY))
585bb90afc7SBen Tyner                             {
586bb90afc7SBen Tyner                                 hresetStatus = "success";
587bb90afc7SBen Tyner                             }
588bb90afc7SBen Tyner                             else if (eventState ==
589bb90afc7SBen Tyner                                      static_cast<uint8_t>(SBE_HRESET_FAILED))
590bb90afc7SBen Tyner                             {
591bb90afc7SBen Tyner                                 hresetStatus = "fail";
592bb90afc7SBen Tyner                             }
593bb90afc7SBen Tyner                         }
594bb90afc7SBen Tyner                     }
595bb90afc7SBen Tyner                 }
596bb90afc7SBen Tyner             });
597bb90afc7SBen Tyner 
598bb90afc7SBen Tyner     // send request to issue hreset of sbe
5999b1a0b6bSPavithra Barithaya     PLDMInstanceManager& manager = PLDMInstanceManager::getInstance();
6009b1a0b6bSPavithra Barithaya     if (!(manager.sendPldm(request, hbrtMctpEid)))
601bb90afc7SBen Tyner     {
602bb90afc7SBen Tyner         trace::err("send pldm request failed");
60336b043e9SPavithra Barithaya         auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&request);
60436b043e9SPavithra Barithaya         manager.freePLDMInstanceID(reqhdr->instance_id, hbrtMctpEid);
60536b043e9SPavithra Barithaya 
606bb90afc7SBen Tyner         return false;
607bb90afc7SBen Tyner     }
608bb90afc7SBen Tyner 
609bb90afc7SBen Tyner     // keep track of elapsed time
610bb90afc7SBen Tyner     uint64_t timeRemaining = 60000000; // microseconds, 1 minute
611bb90afc7SBen Tyner     std::chrono::steady_clock::time_point begin =
612bb90afc7SBen Tyner         std::chrono::steady_clock::now();
613bb90afc7SBen Tyner 
614bb90afc7SBen Tyner     // wait for status update or timeout
615bb90afc7SBen Tyner     trace::inf("waiting on sbe hreset");
616bb90afc7SBen Tyner     while ("requested" == hresetStatus && 0 != timeRemaining)
617bb90afc7SBen Tyner     {
618bb90afc7SBen Tyner         bus.wait(timeRemaining);
619bb90afc7SBen Tyner         uint64_t timeElapsed =
620bb90afc7SBen Tyner             std::chrono::duration_cast<std::chrono::microseconds>(
621bb90afc7SBen Tyner                 std::chrono::steady_clock::now() - begin)
622bb90afc7SBen Tyner                 .count();
623bb90afc7SBen Tyner 
624bb90afc7SBen Tyner         timeRemaining =
625bb90afc7SBen Tyner             timeElapsed > timeRemaining ? 0 : timeRemaining - timeElapsed;
626bb90afc7SBen Tyner 
627bb90afc7SBen Tyner         bus.process_discard();
628bb90afc7SBen Tyner     }
629bb90afc7SBen Tyner 
630bb90afc7SBen Tyner     if (0 == timeRemaining)
631bb90afc7SBen Tyner     {
632bb90afc7SBen Tyner         trace::err("hreset timed out");
633bb90afc7SBen Tyner     }
634bb90afc7SBen Tyner 
63536b043e9SPavithra Barithaya     auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&request);
63636b043e9SPavithra Barithaya     manager.freePLDMInstanceID(reqhdr->instance_id, hbrtMctpEid);
6379b1a0b6bSPavithra Barithaya     manager.closePLDM();
638bb90afc7SBen Tyner 
639bb90afc7SBen Tyner     return hresetStatus == "success" ? true : false;
640bb90afc7SBen Tyner }
641bb90afc7SBen Tyner 
642bb90afc7SBen Tyner } // namespace pldm
643bb90afc7SBen Tyner } // namespace util
644