xref: /openbmc/openpower-vpd-parser/vpd-manager/include/worker.hpp (revision fa47e6c0c7f9ac505aa54fd5b33a3c10853579bc)
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 Check if the given CPU is an IO only chip.
332       *
333       * The CPU is termed as IO, whose all of the cores are bad and can never be
334       * used. Those CPU chips can be used for IO purpose like connecting PCIe
335       * devices etc., The CPU whose every cores are bad, can be identified from
336       * the CP00 record's PG keyword, only if all of the 8 EQs' value equals
337       * 0xE7F9FF. (1EQ has 4 cores grouped together by sharing its cache memory.)
338       *
339       * @param [in] pgKeyword - PG Keyword of CPU.
340       * @return true if the given cpu is an IO, false otherwise.
341       */
342      bool isCPUIOGoodOnly(const std::string& pgKeyword);
343  
344      /**
345       * @brief API to prime inventory Objects.
346       *
347       * @param[in] i_vpdFilePath - EEPROM file path.
348       * @return true if the prime inventory is success, false otherwise.
349       */
350      bool primeInventory(const std::string& i_vpdFilePath);
351  
352      /**
353       * @brief API to process preAction(base_action) defined in config JSON.
354       *
355       * @note sequence of tags under any given flag of preAction is EXTREMELY
356       * important to ensure proper processing. The API will process all the
357       * nested items under the base action sequentially. Also if any of the tag
358       * processing fails, the code will not process remaining tags under the
359       * flag.
360       * ******** sample format **************
361       * fru EEPROM path: {
362       *     base_action: {
363       *         flag1: {
364       *           tag1: {
365       *            },
366       *           tag2: {
367       *            }
368       *         }
369       *         flag2: {
370       *           tags: {
371       *            }
372       *         }
373       *     }
374       * }
375       * *************************************
376       *
377       * @param[in] i_vpdFilePath - Path to the EEPROM file.
378       * @param[in] i_flagToProcess - To identify which flag(s) needs to be
379       * processed under PreAction tag of config JSON.
380       * @return Execution status.
381       */
382      bool processPreAction(const std::string& i_vpdFilePath,
383                            const std::string& i_flagToProcess);
384  
385      /**
386       * @brief API to process postAction(base_action) defined in config JSON.
387       *
388       * @note Sequence of tags under any given flag of postAction is EXTREMELY
389       * important to ensure proper processing. The API will process all the
390       * nested items under the base action sequentially. Also if any of the tag
391       * processing fails, the code will not process remaining tags under the
392       * flag.
393       * ******** sample format **************
394       * fru EEPROM path: {
395       *     base_action: {
396       *         flag1: {
397       *           tag1: {
398       *            },
399       *           tag2: {
400       *            }
401       *         }
402       *         flag2: {
403       *           tags: {
404       *            }
405       *         }
406       *     }
407       * }
408       * *************************************
409       * Also, if post action is required to be processed only for FRUs with
410       * certain CCIN then CCIN list can be provided under flag.
411       *
412       * @param[in] i_vpdFruPath - Path to the EEPROM file.
413       * @param[in] i_flagToProcess - To identify which flag(s) needs to be
414       * processed under postAction tag of config JSON.
415       * @param[in] i_parsedVpd - Optional Parsed VPD map. If CCIN match is
416       * required.
417       * @return Execution status.
418       */
419      bool processPostAction(
420          const std::string& i_vpdFruPath, const std::string& i_flagToProcess,
421          const std::optional<types::VPDMapVariant> i_parsedVpd = std::nullopt);
422  
423      /**
424       * @brief Function to enable and bring MUX out of idle state.
425       *
426       * This finds all the MUX defined in the system json and enables them by
427       * setting the holdidle parameter to 0.
428       *
429       * @throw std::runtime_error
430       */
431      void enableMuxChips();
432  
433      /**
434       * @brief An API to perform backup or restore of VPD.
435       *
436       * @param[in,out] io_srcVpdMap - Source VPD map.
437       */
438      void performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap);
439  
440      /**
441       * @brief API to update "Functional" property.
442       *
443       * The API sets the default value for "Functional" property once if the
444       * property is not yet populated over DBus. As the property value is not
445       * controlled by the VPD-Collection process, if it is found already
446       * populated, the functions skips re-populating the property so that already
447       * existing value can be retained.
448       *
449       * @param[in] i_inventoryObjPath - Inventory path as read from config JSON.
450       * @param[in] io_interfaces - Map to hold all the interfaces for the FRU.
451       */
452      void processFunctionalProperty(const std::string& i_inventoryObjPath,
453                                     types::InterfaceMap& io_interfaces);
454  
455      /**
456       * @brief API to update "enabled" property.
457       *
458       * The API sets the default value for "enabled" property once if the
459       * property is not yet populated over DBus. As the property value is not
460       * controlled by the VPD-Collection process, if it is found already
461       * populated, the functions skips re-populating the property so that already
462       * existing value can be retained.
463       *
464       * @param[in] i_inventoryObjPath - Inventory path as read from config JSON.
465       * @param[in] io_interfaces - Map to hold all the interfaces for the FRU.
466       */
467      void processEnabledProperty(const std::string& i_inventoryObjPath,
468                                  types::InterfaceMap& io_interfaces);
469  
470      /**
471       * @brief API to form asset tag string for the system.
472       *
473       * @param[in] i_parsedVpdMap - Parsed VPD map.
474       *
475       * @throw std::runtime_error
476       *
477       * @return - Formed asset tag string.
478       */
479      std::string createAssetTagString(
480          const types::VPDMapVariant& i_parsedVpdMap);
481  
482      /**
483       * @brief API to prime system blueprint.
484       *
485       * The API will traverse the system config JSON and will prime all the FRU
486       * paths which qualifies for priming.
487       */
488      void primeSystemBlueprint();
489  
490      /**
491       * @brief API to set symbolic link for system config JSON.
492       *
493       * Once correct device tree is set, symbolic link to the correct sytsem
494       * config JSON is set to be used in subsequent BMC boot.
495       *
496       * @param[in] i_systemJson - system config JSON.
497       */
498      void setJsonSymbolicLink(const std::string& i_systemJson);
499  
500      /**
501       * @brief API to set present property.
502       *
503       * This API updates the present property of the given FRU with the given
504       * value. Note: It is the responsibility of the caller to determine whether
505       * the present property for the FRU should be updated or not.
506       *
507       * @param[in] i_vpdPath - EEPROM or inventory path.
508       * @param[in] i_value - value to be set.
509       */
510      void setPresentProperty(const std::string& i_fruPath, const bool& i_value);
511  
512      /**
513       * @brief API to check if the path needs to be skipped for collection.
514       *
515       * Some FRUs, under some given scenarios should not be collected and
516       * skipped.
517       *
518       * @param[in] i_vpdFilePath - EEPROM path.
519       *
520       * @return True - if path is empty or should be skipped, false otherwise.
521       */
522      bool skipPathForCollection(const std::string& i_vpdFilePath);
523  
524      /**
525       * @brief API to check if present property should be handled for given FRU.
526       *
527       * vpd-manager should update present property for a FRU if and only if it's
528       * not synthesized and vpd-manager handles present property for the FRU.
529       * This API assumes "handlePresence" tag is a subset of "synthesized" tag.
530       *
531       * @param[in] i_fru -  JSON block for a single FRU.
532       *
533       * @return true if present property should be handled, false otherwise.
534       */
isPresentPropertyHandlingRequired(const nlohmann::json & i_fru) const535      inline bool isPresentPropertyHandlingRequired(
536          const nlohmann::json& i_fru) const noexcept
537      {
538          // TODO: revisit this to see if this logic can be optimized.
539          return !i_fru.value("synthesized", false) &&
540                 i_fru.value("handlePresence", true);
541      }
542  
543      // Parsed JSON file.
544      nlohmann::json m_parsedJson{};
545  
546      // Hold if symlink is present or not.
547      bool m_isSymlinkPresent = false;
548  
549      // Path to config JSON if applicable.
550      std::string& m_configJsonPath;
551  
552      // Keeps track of active thread(s) doing VPD collection.
553      size_t m_activeCollectionThreadCount = 0;
554  
555      // Holds status, if VPD collection has been done or not.
556      // Note: This variable does not give information about successfull or failed
557      // collection. It just states, if the VPD collection process is over or not.
558      bool m_isAllFruCollected = false;
559  
560      // To distinguish the factory reset path.
561      bool m_isFactoryResetDone = false;
562  
563      // Mutex to guard critical resource m_activeCollectionThreadCount.
564      std::mutex m_mutex;
565  
566      // Counting semaphore to limit the number of threads.
567      std::counting_semaphore<constants::MAX_THREADS> m_semaphore;
568  
569      // List of EEPROM paths for which VPD collection thread creation has failed.
570      std::forward_list<std::string> m_failedEepromPaths;
571  };
572  } // namespace vpd
573