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