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