xref: /openbmc/openpower-vpd-parser/vpd-manager/include/worker.hpp (revision 63a822a0a7d20225224a7a868ae35fde41eb62f0)
1 #pragma once
2 
3 #include "constants.hpp"
4 #include "types.hpp"
5 
6 #include <nlohmann/json.hpp>
7 
8 #include <mutex>
9 #include <optional>
10 #include <semaphore>
11 #include <tuple>
12 
13 namespace vpd
14 {
15 /**
16  * @brief A class to process and publish VPD data.
17  *
18  * The class works on VPD and is mainly responsible for following tasks:
19  * 1) Select appropriate device tree and JSON. Reboot if required.
20  * 2) Get desired parser using parser factory.
21  * 3) Calling respective parser class to get parsed VPD.
22  * 4) Arranging VPD data under required interfaces.
23  * 5) Calling PIM to publish VPD.
24  *
25  * The class may also implement helper functions required for VPD handling.
26  */
27 class Worker
28 {
29   public:
30     /**
31      * List of deleted functions.
32      */
33     Worker(const Worker&) = delete;
34     Worker& operator=(const Worker&) = delete;
35     Worker(Worker&&) = delete;
36     Worker& operator=(const Worker&&) = delete;
37 
38     /**
39      * @brief Constructor.
40      *
41      * In case the processing is not JSON based, no argument needs to be passed.
42      * Constructor will also, based on symlink pick the correct JSON and
43      * initialize the parsed JSON variable.
44      *
45      * @param[in] pathToConfigJSON - Path to the config JSON, if applicable.
46      * @param[in] i_maxThreadCount - Maximum thread while collecting FRUs VPD.
47      * @param[in] i_vpdCollectionMode - Mode in which VPD collection should take
48      * place.
49      *
50      * Note: Throws std::exception in case of construction failure. Caller needs
51      * to handle to detect successful object creation.
52      */
53     Worker(std::string pathToConfigJson = std::string(),
54            uint8_t i_maxThreadCount = constants::MAX_THREADS,
55            types::VpdCollectionMode i_vpdCollectionMode =
56                types::VpdCollectionMode::DEFAULT_MODE);
57 
58     /**
59      * @brief Destructor
60      */
61     ~Worker() = default;
62 
63     /**
64      * @brief API to process all FRUs presnt in config JSON file.
65      *
66      * This API based on config JSON passed/selected for the system, will
67      * trigger parser for all the FRUs and publish it on DBus.
68      *
69      * Note: Config JSON file path should be passed to worker class constructor
70      * to make use of this API.
71      *
72      */
73     void collectFrusFromJson();
74 
75     /**
76      * @brief API to parse VPD data
77      *
78      * @param[in] i_vpdFilePath - Path to the VPD file.
79      */
80     types::VPDMapVariant parseVpdFile(const std::string& i_vpdFilePath);
81 
82     /**
83      * @brief An API to populate DBus interfaces for a FRU.
84      *
85      * Note: Call this API to populate D-Bus. Also caller should handle empty
86      * objectInterfaceMap.
87      *
88      * @param[in] parsedVpdMap - Parsed VPD as a map.
89      * @param[out] objectInterfaceMap - Object and its interfaces map.
90      * @param[in] vpdFilePath - EEPROM path of FRU.
91      */
92     void populateDbus(const types::VPDMapVariant& parsedVpdMap,
93                       types::ObjectMap& objectInterfaceMap,
94                       const std::string& vpdFilePath);
95 
96     /**
97      * @brief An API to delete FRU VPD over DBus.
98      *
99      * @param[in] i_dbusObjPath - Dbus object path of the FRU.
100      *
101      * @throw std::runtime_error if given input path is empty.
102      */
103     void deleteFruVpd(const std::string& i_dbusObjPath);
104 
105     /**
106      * @brief API to get status of VPD collection process.
107      *
108      * @return - True when done, false otherwise.
109      */
isAllFruCollectionDone() const110     inline bool isAllFruCollectionDone() const
111     {
112         return m_isAllFruCollected;
113     }
114 
115     /**
116      * @brief API to get system config JSON object
117      *
118      * @return System config JSON object.
119      */
getSysCfgJsonObj() const120     inline nlohmann::json getSysCfgJsonObj() const
121     {
122         return m_parsedJson;
123     }
124 
125     /**
126      * @brief API to get active thread count.
127      *
128      * Each FRU is collected in a separate thread. This API gives the active
129      * thread collecting FRU's VPD at any given time.
130      *
131      * @return Count of active threads.
132      */
getActiveThreadCount() const133     size_t getActiveThreadCount() const
134     {
135         return m_activeCollectionThreadCount;
136     }
137 
138     /**
139      * @brief API to get list of EEPROMs for which thread creation failed.
140      *
141      * This API returns reference to list of EEPROM paths for which VPD
142      * collection thread creation has failed. Manager needs to process this list
143      * of EEPROMs and take appropriate action.
144      *
145      * @return reference to list of EEPROM paths for which VPD collection thread
146      * creation has failed
147      */
getFailedEepromPaths()148     inline std::forward_list<std::string>& getFailedEepromPaths() noexcept
149     {
150         return m_failedEepromPaths;
151     }
152 
153     /**
154      * @brief API to get VPD collection mode
155      *
156      * @return VPD collection mode enum value
157      */
getVpdCollectionMode() const158     inline types::VpdCollectionMode getVpdCollectionMode() const
159     {
160         return m_vpdCollectionMode;
161     }
162 
163     /**
164      * @brief Collect single FRU VPD
165      * API can be used to perform VPD collection for the given FRU, only if the
166      * current state of the system matches with the state at which the FRU is
167      * allowed for VPD recollection.
168      *
169      * @param[in] i_dbusObjPath - D-bus object path
170      */
171     void collectSingleFruVpd(
172         const sdbusplus::message::object_path& i_dbusObjPath);
173 
174     /**
175      * @brief  Perform VPD recollection
176      * This api will trigger parser to perform VPD recollection for FRUs that
177      * can be replaced at standby.
178      */
179     void performVpdRecollection();
180 
181     /**
182      * @brief API to set CollectionStatus property.
183      *
184      * This API updates the CollectionStatus property of the given FRU with the
185      * given value.
186      *
187      * @param[in] i_vpdPath - EEPROM or inventory path.
188      * @param[in] i_value - Value to be set.
189      */
190     void setCollectionStatusProperty(const std::string& i_fruPath,
191                                      const std::string& i_value) const noexcept;
192 
193   private:
194     /**
195      * @brief An API to parse and publish a FRU VPD over D-Bus.
196      *
197      * Note: This API will handle all the exceptions internally and will only
198      * return status of parsing and publishing of VPD over D-Bus.
199      *
200      * @param[in] i_vpdFilePath - Path of file containing VPD.
201      * @return Tuple of status and file path. Status, true if successfull else
202      * false.
203      */
204     std::tuple<bool, std::string> parseAndPublishVPD(
205         const std::string& i_vpdFilePath);
206 
207     /**
208      * @brief An API to process extrainterfaces w.r.t a FRU.
209      *
210      * @param[in] singleFru - JSON block for a single FRU.
211      * @param[out] interfaces - Map to hold interface along with its properties.
212      * @param[in] parsedVpdMap - Parsed VPD as a map.
213      */
214     void processExtraInterfaces(const nlohmann::json& singleFru,
215                                 types::InterfaceMap& interfaces,
216                                 const types::VPDMapVariant& parsedVpdMap);
217 
218     /**
219      * @brief An API to process embedded and synthesized FRUs.
220      *
221      * @param[in] singleFru - FRU to be processed.
222      * @param[out] interfaces - Map to hold interface along with its properties.
223      */
224     void processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru,
225                                            types::InterfaceMap& interfaces);
226 
227     /**
228      * @brief An API to read process FRU based in CCIN.
229      *
230      * For some FRUs VPD can be processed only if the FRU has some specific
231      * value for CCIN. In case the value is not from that set, VPD for those
232      * FRUs can't be processed.
233      *
234      * @param[in] singleFru - Fru whose CCIN value needs to be matched.
235      * @param[in] parsedVpdMap - Parsed VPD map.
236      */
237     bool processFruWithCCIN(const nlohmann::json& singleFru,
238                             const types::VPDMapVariant& parsedVpdMap);
239 
240     /**
241      * @brief API to process json's inherit flag.
242      *
243      * Inherit flag denotes that some property in the child FRU needs to be
244      * inherited from parent FRU.
245      *
246      * @param[in] parsedVpdMap - Parsed VPD as a map.
247      * @param[out] interfaces - Map to hold interface along with its properties.
248      */
249     void processInheritFlag(const types::VPDMapVariant& parsedVpdMap,
250                             types::InterfaceMap& interfaces);
251 
252     /**
253      * @brief API to process json's "copyRecord" flag.
254      *
255      * copyRecord flag denotes if some record data needs to be copies in the
256      * given FRU.
257      *
258      * @param[in] singleFru - FRU being processed.
259      * @param[in] parsedVpdMap - Parsed VPD as a map.
260      * @param[out] interfaces - Map to hold interface along with its properties.
261      */
262     void processCopyRecordFlag(const nlohmann::json& singleFru,
263                                const types::VPDMapVariant& parsedVpdMap,
264                                types::InterfaceMap& interfaces);
265 
266     /**
267      * @brief An API to populate IPZ VPD property map.
268      *
269      * @param[out] interfacePropMap - Map of interface and properties under it.
270      * @param[in] keyordValueMap - Keyword value map of IPZ VPD.
271      * @param[in] interfaceName - Name of the interface.
272      */
273     void populateIPZVPDpropertyMap(types::InterfaceMap& interfacePropMap,
274                                    const types::IPZKwdValueMap& keyordValueMap,
275                                    const std::string& interfaceName);
276 
277     /**
278      * @brief An API to populate Kwd VPD property map.
279      *
280      * @param[in] keyordValueMap - Keyword value map of Kwd VPD.
281      * @param[out] interfaceMap - interface and property,value under it.
282      */
283     void populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap,
284                                    types::InterfaceMap& interfaceMap);
285 
286     /**
287      * @brief API to populate all required interface for a FRU.
288      *
289      * @param[in] interfaceJson - JSON containing interfaces to be populated.
290      * @param[out] interfaceMap - Map to hold populated interfaces.
291      * @param[in] parsedVpdMap - Parsed VPD as a map.
292      */
293     void populateInterfaces(const nlohmann::json& interfaceJson,
294                             types::InterfaceMap& interfaceMap,
295                             const types::VPDMapVariant& parsedVpdMap);
296 
297     /**
298      * @brief Check if the given CPU is an IO only chip.
299      *
300      * The CPU is termed as IO, whose all of the cores are bad and can never be
301      * used. Those CPU chips can be used for IO purpose like connecting PCIe
302      * devices etc., The CPU whose every cores are bad, can be identified from
303      * the CP00 record's PG keyword, only if all of the 8 EQs' value equals
304      * 0xE7F9FF. (1EQ has 4 cores grouped together by sharing its cache memory.)
305      *
306      * @param [in] pgKeyword - PG Keyword of CPU.
307      * @return true if the given cpu is an IO, false otherwise.
308      */
309     bool isCPUIOGoodOnly(const std::string& pgKeyword);
310 
311     /**
312      * @brief API to process preAction(base_action) defined in config JSON.
313      *
314      * @note sequence of tags under any given flag of preAction is EXTREMELY
315      * important to ensure proper processing. The API will process all the
316      * nested items under the base action sequentially. Also if any of the tag
317      * processing fails, the code will not process remaining tags under the
318      * flag.
319      * ******** sample format **************
320      * fru EEPROM path: {
321      *     base_action: {
322      *         flag1: {
323      *           tag1: {
324      *            },
325      *           tag2: {
326      *            }
327      *         }
328      *         flag2: {
329      *           tags: {
330      *            }
331      *         }
332      *     }
333      * }
334      * *************************************
335      *
336      * @param[in] i_vpdFilePath - Path to the EEPROM file.
337      * @param[in] i_flagToProcess - To identify which flag(s) needs to be
338      * processed under PreAction tag of config JSON.
339      * @param[out] o_errCode - To set error code in case of error.
340      * @return Execution status.
341      */
342     bool processPreAction(const std::string& i_vpdFilePath,
343                           const std::string& i_flagToProcess,
344                           uint16_t& o_errCode);
345 
346     /**
347      * @brief API to process postAction(base_action) defined in config JSON.
348      *
349      * @note Sequence of tags under any given flag of postAction is EXTREMELY
350      * important to ensure proper processing. The API will process all the
351      * nested items under the base action sequentially. Also if any of the tag
352      * processing fails, the code will not process remaining tags under the
353      * flag.
354      * ******** sample format **************
355      * fru EEPROM path: {
356      *     base_action: {
357      *         flag1: {
358      *           tag1: {
359      *            },
360      *           tag2: {
361      *            }
362      *         }
363      *         flag2: {
364      *           tags: {
365      *            }
366      *         }
367      *     }
368      * }
369      * *************************************
370      * Also, if post action is required to be processed only for FRUs with
371      * certain CCIN then CCIN list can be provided under flag.
372      *
373      * @param[in] i_vpdFruPath - Path to the EEPROM file.
374      * @param[in] i_flagToProcess - To identify which flag(s) needs to be
375      * processed under postAction tag of config JSON.
376      * @param[in] i_parsedVpd - Optional Parsed VPD map. If CCIN match is
377      * required.
378      * @return Execution status.
379      */
380     bool processPostAction(
381         const std::string& i_vpdFruPath, const std::string& i_flagToProcess,
382         const std::optional<types::VPDMapVariant> i_parsedVpd = std::nullopt);
383 
384     /**
385      * @brief API to update "Functional" property.
386      *
387      * The API sets the default value for "Functional" property once if the
388      * property is not yet populated over DBus. As the property value is not
389      * controlled by the VPD-Collection process, if it is found already
390      * populated, the functions skips re-populating the property so that already
391      * existing value can be retained.
392      *
393      * @param[in] i_inventoryObjPath - Inventory path as read from config JSON.
394      * @param[in] io_interfaces - Map to hold all the interfaces for the FRU.
395      */
396     void processFunctionalProperty(const std::string& i_inventoryObjPath,
397                                    types::InterfaceMap& io_interfaces);
398 
399     /**
400      * @brief API to update "enabled" property.
401      *
402      * The API sets the default value for "enabled" property once if the
403      * property is not yet populated over DBus. As the property value is not
404      * controlled by the VPD-Collection process, if it is found already
405      * populated, the functions skips re-populating the property so that already
406      * existing value can be retained.
407      *
408      * @param[in] i_inventoryObjPath - Inventory path as read from config JSON.
409      * @param[in] io_interfaces - Map to hold all the interfaces for the FRU.
410      */
411     void processEnabledProperty(const std::string& i_inventoryObjPath,
412                                 types::InterfaceMap& io_interfaces);
413 
414     /**
415      * @brief API to set present property.
416      *
417      * This API updates the present property of the given FRU with the given
418      * value. Note: It is the responsibility of the caller to determine whether
419      * the present property for the FRU should be updated or not.
420      *
421      * @param[in] i_vpdPath - EEPROM or inventory path.
422      * @param[in] i_value - value to be set.
423      */
424     void setPresentProperty(const std::string& i_fruPath, const bool& i_value);
425 
426     /**
427      * @brief API to check if the path needs to be skipped for collection.
428      *
429      * Some FRUs, under some given scenarios should not be collected and
430      * skipped.
431      *
432      * @param[in] i_vpdFilePath - EEPROM path.
433      *
434      * @return True - if path is empty or should be skipped, false otherwise.
435      */
436     bool skipPathForCollection(const std::string& i_vpdFilePath);
437 
438     /**
439      * @brief API to check if present property should be handled for given FRU.
440      *
441      * vpd-manager should update present property for a FRU if and only if it's
442      * not synthesized and vpd-manager handles present property for the FRU.
443      * This API assumes "handlePresence" tag is a subset of "synthesized" tag.
444      *
445      * @param[in] i_fru -  JSON block for a single FRU.
446      *
447      * @return true if present property should be handled, false otherwise.
448      */
isPresentPropertyHandlingRequired(const nlohmann::json & i_fru) const449     inline bool isPresentPropertyHandlingRequired(
450         const nlohmann::json& i_fru) const noexcept
451     {
452         // TODO: revisit this to see if this logic can be optimized.
453         return !i_fru.value("synthesized", false) &&
454                i_fru.value("handlePresence", true);
455     }
456 
457     // Parsed JSON file.
458     nlohmann::json m_parsedJson{};
459 
460     // Path to config JSON if applicable.
461     std::string& m_configJsonPath;
462 
463     // Keeps track of active thread(s) doing VPD collection.
464     size_t m_activeCollectionThreadCount = 0;
465 
466     // Holds status, if VPD collection has been done or not.
467     // Note: This variable does not give information about successfull or failed
468     // collection. It just states, if the VPD collection process is over or not.
469     bool m_isAllFruCollected = false;
470 
471     // Mutex to guard critical resource m_activeCollectionThreadCount.
472     std::mutex m_mutex;
473 
474     // Counting semaphore to limit the number of threads.
475     std::counting_semaphore<constants::MAX_THREADS> m_semaphore;
476 
477     // List of EEPROM paths for which VPD collection thread creation has failed.
478     std::forward_list<std::string> m_failedEepromPaths;
479 
480     // VPD collection mode
481     types::VpdCollectionMode m_vpdCollectionMode{
482         types::VpdCollectionMode::DEFAULT_MODE};
483 };
484 } // namespace vpd
485