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