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