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