xref: /openbmc/pldm/libpldmresponder/fru.hpp (revision 28ba36aa9ecc3b4e8f2c2f8b2821dd8ec8c83d78)
1 #pragma once
2 
3 #include "fru_parser.hpp"
4 #include "libpldmresponder/pdr_utils.hpp"
5 #include "oem_handler.hpp"
6 #include "pldmd/handler.hpp"
7 
8 #include <libpldm/fru.h>
9 #include <libpldm/pdr.h>
10 
11 #include <sdbusplus/message.hpp>
12 
13 #include <map>
14 #include <string>
15 #include <variant>
16 #include <vector>
17 
18 namespace pldm
19 {
20 
21 namespace responder
22 {
23 namespace platform
24 {
25 class Handler; // forward declaration
26 }
27 
28 namespace dbus
29 {
30 
31 using Value =
32     std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t,
33                  uint64_t, double, std::string, std::vector<uint8_t>,
34                  std::vector<uint64_t>, std::vector<std::string>>;
35 using PropertyMap = std::map<Property, Value>;
36 using InterfaceMap = std::map<Interface, PropertyMap>;
37 using ObjectValueTree = std::map<sdbusplus::message::object_path, InterfaceMap>;
38 using ObjectPath = std::string;
39 using AssociatedEntityMap = std::map<ObjectPath, pldm_entity>;
40 using ObjectPathToRSIMap = std::map<ObjectPath, uint16_t>;
41 
42 } // namespace dbus
43 
44 /** @class FruImpl
45  *
46  *  @brief Builds the PLDM FRU table containing the FRU records
47  */
48 class FruImpl
49 {
50   public:
51     /* @brief Header size for FRU record, it includes the FRU record set
52      *        identifier, FRU record type, Number of FRU fields, Encoding type
53      *        of FRU fields
54      */
55     static constexpr size_t recHeaderSize =
56         sizeof(struct pldm_fru_record_data_format) -
57         sizeof(struct pldm_fru_record_tlv);
58 
59     /** @brief Constructor for FruImpl, the configPath is consumed to build the
60      *         FruParser object.
61      *
62      *  @param[in] configPath - path to the directory containing config files
63      *                          for PLDM FRU
64      *  @param[in] fruMasterJsonPath - path to the file containing the FRU D-Bus
65      *                                 Lookup Map
66      *  @param[in] pdrRepo - opaque pointer to PDR repository
67      *  @param[in] entityTree - opaque pointer to the entity association tree
68      *  @param[in] bmcEntityTree - opaque pointer to bmc's entity association
69      *                             tree
70      *  @param[in] oemFruHandler - OEM fru handler
71      */
FruImpl(const std::string & configPath,const std::filesystem::path & fruMasterJsonPath,pldm_pdr * pdrRepo,pldm_entity_association_tree * entityTree,pldm_entity_association_tree * bmcEntityTree)72     FruImpl(const std::string& configPath,
73             const std::filesystem::path& fruMasterJsonPath, pldm_pdr* pdrRepo,
74             pldm_entity_association_tree* entityTree,
75             pldm_entity_association_tree* bmcEntityTree) :
76         parser(configPath, fruMasterJsonPath), pdrRepo(pdrRepo),
77         entityTree(entityTree), bmcEntityTree(bmcEntityTree)
78     {}
79 
80     /** @brief Total length of the FRU table in bytes, this includes the pad
81      *         bytes and the checksum.
82      *
83      *  @return size of the FRU table
84      */
size() const85     uint32_t size() const
86     {
87         return table.size();
88     }
89 
90     /** @brief The checksum of the contents of the FRU table
91      *
92      *  @return checksum
93      */
checkSum() const94     uint32_t checkSum() const
95     {
96         return checksum;
97     }
98 
99     /** @brief Number of record set identifiers in the FRU tables
100      *
101      *  @return number of record set identifiers
102      */
numRSI() const103     uint16_t numRSI() const
104     {
105         return rsi;
106     }
107 
108     /** @brief The number of FRU records in the table
109      *
110      *  @return number of FRU records
111      */
numRecords() const112     uint16_t numRecords() const
113     {
114         return numRecs;
115     }
116 
117     /** @brief Get the FRU table
118      *
119      *  @param[out] - Populate response with the FRU table
120      */
121     void getFRUTable(Response& response);
122 
123     /** @brief Get the Fru Table MetaData
124      *
125      */
126     void getFRURecordTableMetadata();
127 
128     /** @brief Get FRU Record Table By Option
129      *  @param[out] response - Populate response with the FRU table got by
130      *                         options
131      *  @param[in] fruTableHandle - The fru table handle
132      *  @param[in] recordSetIdentifer - The record set identifier
133      *  @param[in] recordType - The record type
134      *  @param[in] fieldType - The field type
135      */
136     int getFRURecordByOption(Response& response, uint16_t fruTableHandle,
137                              uint16_t recordSetIdentifer, uint8_t recordType,
138                              uint8_t fieldType);
139 
140     /** @brief FRU table is built by processing the D-Bus inventory namespace
141      *         based on the config files for FRU. The table is populated based
142      *         on the isBuilt flag.
143      */
144     void buildFRUTable();
145 
146     /** @brief Get std::map associated with the entity
147      *         key: object path
148      *         value: pldm_entity
149      *
150      *  @return std::map<ObjectPath, pldm_entity>
151      */
152     inline const pldm::responder::dbus::AssociatedEntityMap&
getAssociateEntityMap() const153         getAssociateEntityMap() const
154     {
155         return associatedEntityMap;
156     }
157 
158     /* @brief Method to set the oem platform handler in FRU handler class
159      *
160      * @param[in] handler - oem platform handler
161      */
setOemPlatformHandler(pldm::responder::oem_platform::Handler * handler)162     inline void setOemPlatformHandler(
163         pldm::responder::oem_platform::Handler* handler)
164     {
165         oemPlatformHandler = handler;
166     }
167 
168     /** @brief Get pldm entity by the object path
169      *
170      *  @param[in] intfMaps - D-Bus interfaces and the associated property
171      *                        values for the FRU
172      *
173      *  @return pldm_entity
174      */
175     std::optional<pldm_entity> getEntityByObjectPath(
176         const dbus::InterfaceMap& intfMaps);
177 
178     /** @brief Update pldm entity to association tree
179      *
180      *  @param[in] objects - std::map The object value tree
181      *  @param[in] path    - Object path
182      *
183      *  Ex: Input path =
184      *  "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0"
185      *
186      *  Get the parent class in turn and store it in a temporary vector
187      *
188      *  Output tmpObjPaths = {
189      *  "/xyz/openbmc_project/inventory/system",
190      *  "/xyz/openbmc_project/inventory/system/chassis/",
191      *  "/xyz/openbmc_project/inventory/system/chassis/motherboard",
192      *  "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0"}
193      *
194      */
195     void updateAssociationTree(const dbus::ObjectValueTree& objects,
196                                const std::string& path);
197 
198     /* @brief Method to populate the firmware version ID
199      *
200      * @return firmware version ID
201      */
202     std::string populatefwVersion();
203 
204     /* @brief Method to resize the table
205      *
206      * @return resized table
207      */
208     std::vector<uint8_t> tableResize();
209 
210     /* @brief set FRU Record Table
211      *
212      * @param[in] fruData - the data of the fru
213      *
214      * @return PLDM completion code
215      */
216     int setFRUTable(const std::vector<uint8_t>& fruData);
217 
218     /* @brief Method to set the oem platform handler in fru handler class
219      *
220      * @param[in] handler - oem fru handler
221      */
setOemFruHandler(pldm::responder::oem_fru::Handler * handler)222     inline void setOemFruHandler(pldm::responder::oem_fru::Handler* handler)
223     {
224         oemFruHandler = handler;
225     }
226 
setPlatformHandler(pldm::responder::platform::Handler * handler)227     inline void setPlatformHandler(pldm::responder::platform::Handler* handler)
228     {
229         platformHandler = handler;
230     }
231 
232   private:
nextRSI()233     uint16_t nextRSI()
234     {
235         return ++rsi;
236     }
237 
nextRecordHandle()238     uint32_t nextRecordHandle()
239     {
240         return ++rh;
241     }
242 
243     uint32_t rh = 0;
244     uint16_t rsi = 0;
245     uint16_t numRecs = 0;
246     uint8_t padBytes = 0;
247     std::vector<uint8_t> table;
248     uint32_t checksum = 0;
249     bool isBuilt = false;
250 
251     fru_parser::FruParser parser;
252     pldm_pdr* pdrRepo;
253     pldm_entity_association_tree* entityTree;
254     pldm_entity_association_tree* bmcEntityTree;
255     pldm::responder::oem_fru::Handler* oemFruHandler = nullptr;
256     dbus::ObjectValueTree objects;
257     pldm::responder::platform::Handler* platformHandler = nullptr;
258 
259     /** @OEM platform handler */
260     pldm::responder::oem_platform::Handler* oemPlatformHandler;
261 
262     std::map<dbus::ObjectPath, pldm_entity_node*> objToEntityNode{};
263 
264     dbus::ObjectPathToRSIMap objectPathToRSIMap{};
265 
266     pdr_utils::DbusObjMaps effecterDbusObjMaps{};
267     pdr_utils::DbusObjMaps sensorDbusObjMaps{};
268 
269     /** @brief populateRecord builds the FRU records for an instance of FRU and
270      *         updates the FRU table with the FRU records.
271      *
272      *  @param[in] interfaces - D-Bus interfaces and the associated property
273      *                          values for the FRU
274      *  @param[in] recordInfos - FRU record info to build the FRU records
275      *  @param[in/out] entity - PLDM entity corresponding to FRU instance
276      */
277     void populateRecords(const dbus::InterfaceMap& interfaces,
278                          const fru_parser::FruRecordInfos& recordInfos,
279                          const pldm_entity& entity);
280 
281     /** @brief Add hotplug record that was modified or added to the PDR entry
282      *  HotPlug is a feature where a FRU can be removed or added when
283      *  the system is running, without needing it to power off.
284      *
285      *  @param[in] pdrEntry - PDR record structure in PDR repository
286      *
287      *  @return record handle of added or modified hotplug record
288      */
289     uint32_t addHotPlugRecord(pldm::responder::pdr_utils::PdrEntry pdrEntry);
290 
291     /** @brief Deletes a FRU record from record set table.
292      *  @param[in] rsi - the FRU Record Set Identifier
293      *
294      *  @return
295      */
296     void deleteFRURecord(uint16_t rsi);
297 
298     /** @brief Deletes a FRU record set PDR and it's associated PDRs after
299      *         a concurrent remove operation.
300      *  @param[in] fruObjectPath - the FRU object path
301      *  @return
302      */
303     void removeIndividualFRU(const std::string& fruObjPath);
304 
305     /** @brief Associate sensor/effecter to FRU entity
306      */
307     dbus::AssociatedEntityMap associatedEntityMap;
308 };
309 
310 namespace fru
311 {
312 
313 class Handler : public CmdHandler
314 {
315   public:
Handler(const std::string & configPath,const std::filesystem::path & fruMasterJsonPath,pldm_pdr * pdrRepo,pldm_entity_association_tree * entityTree,pldm_entity_association_tree * bmcEntityTree)316     Handler(const std::string& configPath,
317             const std::filesystem::path& fruMasterJsonPath, pldm_pdr* pdrRepo,
318             pldm_entity_association_tree* entityTree,
319             pldm_entity_association_tree* bmcEntityTree) :
320         impl(configPath, fruMasterJsonPath, pdrRepo, entityTree, bmcEntityTree)
321     {
322         handlers.emplace(
323             PLDM_GET_FRU_RECORD_TABLE_METADATA,
324             [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
325                 return this->getFRURecordTableMetadata(request, payloadLength);
326             });
327         handlers.emplace(
328             PLDM_GET_FRU_RECORD_TABLE,
329             [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
330                 return this->getFRURecordTable(request, payloadLength);
331             });
332         handlers.emplace(
333             PLDM_GET_FRU_RECORD_BY_OPTION,
334             [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
335                 return this->getFRURecordByOption(request, payloadLength);
336             });
337         handlers.emplace(
338             PLDM_SET_FRU_RECORD_TABLE,
339             [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
340                 return this->setFRURecordTable(request, payloadLength);
341             });
342     }
343 
344     /** @brief Handler for Get FRURecordTableMetadata
345      *
346      *  @param[in] request - Request message payload
347      *  @param[in] payloadLength - Request payload length
348      *
349      *  @return PLDM response message
350      */
351     Response getFRURecordTableMetadata(const pldm_msg* request,
352                                        size_t payloadLength);
353 
354     /** @brief Handler for GetFRURecordTable
355      *
356      *  @param[in] request - Request message payload
357      *  @param[in] payloadLength - Request payload length
358      *
359      *  @return PLDM response message
360      */
361     Response getFRURecordTable(const pldm_msg* request, size_t payloadLength);
362 
363     /** @brief Build FRU table is bnot already built
364      *
365      */
buildFRUTable()366     void buildFRUTable()
367     {
368         impl.buildFRUTable();
369     }
370 
371     /** @brief Get std::map associated with the entity
372      *         key: object path
373      *         value: pldm_entity
374      *
375      *  @return std::map<ObjectPath, pldm_entity>
376      */
getAssociateEntityMap() const377     const pldm::responder::dbus::AssociatedEntityMap& getAssociateEntityMap()
378         const
379     {
380         return impl.getAssociateEntityMap();
381     }
382 
383     /* @brief Method to set the oem platform  handler in host pdr handler class
384      *
385      * @param[in] handler - oem platform handler
386      */
setOemPlatformHandler(pldm::responder::oem_platform::Handler * handler)387     void setOemPlatformHandler(pldm::responder::oem_platform::Handler* handler)
388     {
389         return impl.setOemPlatformHandler(handler);
390     }
391 
392     /** @brief Handler for GetFRURecordByOption
393      *
394      *  @param[in] request - Request message payload
395      *  @param[in] payloadLength - Request payload length
396      *
397      *  @return PLDM response message
398      */
399     Response getFRURecordByOption(const pldm_msg* request,
400                                   size_t payloadLength);
401 
402     /** @brief Handler for SetFRURecordTable
403      *
404      *  @param[in] request - Request message
405      *  @param[in] payloadLength - Request payload length
406      *
407      *  @return PLDM response message
408      */
409     Response setFRURecordTable(const pldm_msg* request, size_t payloadLength);
410 
411     /* @brief Method to set the oem platform handler in fru handler class
412      *
413      * @param[in] handler - oem fru handler
414      */
setOemFruHandler(pldm::responder::oem_fru::Handler * handler)415     void setOemFruHandler(pldm::responder::oem_fru::Handler* handler)
416     {
417         impl.setOemFruHandler(handler);
418     }
419 
setPlatformHandler(pldm::responder::platform::Handler * handler)420     void setPlatformHandler(pldm::responder::platform::Handler* handler)
421     {
422         impl.setPlatformHandler(handler);
423     }
424 
425     using Table = std::vector<uint8_t>;
426 
427   private:
428     FruImpl impl;
429 };
430 
431 } // namespace fru
432 
433 } // namespace responder
434 
435 } // namespace pldm
436