1 #pragma once
2 
3 #include "dbus_types.hpp"
4 #include "dbus_watcher.hpp"
5 
6 #include <filesystem>
7 #include <phosphor-logging/log.hpp>
8 #include <sdbusplus/bus.hpp>
9 #include <sdbusplus/bus/match.hpp>
10 
11 namespace openpower
12 {
13 namespace pels
14 {
15 
16 /**
17  * @class DataInterface
18  *
19  * A base class for gathering data about the system for use
20  * in PELs. Implemented this way to facilitate mocking.
21  */
22 class DataInterfaceBase
23 {
24   public:
25     DataInterfaceBase() = default;
26     virtual ~DataInterfaceBase() = default;
27     DataInterfaceBase(const DataInterfaceBase&) = default;
28     DataInterfaceBase& operator=(const DataInterfaceBase&) = default;
29     DataInterfaceBase(DataInterfaceBase&&) = default;
30     DataInterfaceBase& operator=(DataInterfaceBase&&) = default;
31 
32     /**
33      * @brief Returns the machine Type/Model
34      *
35      * @return string - The machine Type/Model string
36      */
37     virtual std::string getMachineTypeModel() const = 0;
38 
39     /**
40      * @brief Returns the machine serial number
41      *
42      * @return string - The machine serial number
43      */
44     virtual std::string getMachineSerialNumber() const = 0;
45 
46     /**
47      * @brief Says if the system is managed by a hardware
48      *        management console.
49      * @return bool - If the system is HMC managed
50      */
51     virtual bool isHMCManaged() const
52     {
53         return _hmcManaged;
54     }
55 
56     /**
57      * @brief Says if the host is up and running
58      *
59      * @return bool - If the host is running
60      */
61     virtual bool isHostUp() const
62     {
63         return _hostUp;
64     }
65 
66     using HostStateChangeFunc = std::function<void(bool)>;
67 
68     /**
69      * @brief Register a callback function that will get
70      *        called on all host on/off transitions.
71      *
72      * The void(bool) function will get passed the new
73      * value of the host state.
74      *
75      * @param[in] name - The subscription name
76      * @param[in] func - The function to run
77      */
78     void subscribeToHostStateChange(const std::string& name,
79                                     HostStateChangeFunc func)
80     {
81         _hostChangeCallbacks[name] = func;
82     }
83 
84     /**
85      * @brief Unsubscribe from host state changes.
86      *
87      * @param[in] name - The subscription name
88      */
89     void unsubscribeFromHostStateChange(const std::string& name)
90     {
91         _hostChangeCallbacks.erase(name);
92     }
93 
94     /**
95      * @brief Returns the BMC firmware version
96      *
97      * @return std::string - The BMC version
98      */
99     virtual std::string getBMCFWVersion() const
100     {
101         return _bmcFWVersion;
102     }
103 
104     /**
105      * @brief Returns the server firmware version
106      *
107      * @return std::string - The server firmware version
108      */
109     virtual std::string getServerFWVersion() const
110     {
111         return _serverFWVersion;
112     }
113 
114     /**
115      * @brief Returns the BMC FW version ID
116      *
117      * @return std::string - The BMC FW version ID
118      */
119     virtual std::string getBMCFWVersionID() const
120     {
121         return _bmcFWVersionID;
122     }
123 
124     /**
125      * @brief Returns the process name given its PID.
126      *
127      * @param[in] pid - The PID value as a string
128      *
129      * @return std::optional<std::string> - The name, or std::nullopt
130      */
131     std::optional<std::string> getProcessName(const std::string& pid) const
132     {
133         namespace fs = std::filesystem;
134 
135         fs::path path{"/proc"};
136         path /= fs::path{pid} / "exe";
137 
138         if (fs::exists(path))
139         {
140             return fs::read_symlink(path);
141         }
142 
143         return std::nullopt;
144     }
145 
146     /**
147      * @brief Returns the 'send event logs to host' setting.
148      *
149      * @return bool - If sending PELs to the host is enabled.
150      */
151     virtual bool getHostPELEnablement() const
152     {
153         return _sendPELsToHost;
154     }
155 
156     /**
157      * @brief Returns the BMC state
158      *
159      * @return std::string - The BMC state property value
160      */
161     virtual std::string getBMCState() const
162     {
163         return _bmcState;
164     }
165 
166     /**
167      * @brief Returns the Chassis state
168      *
169      * @return std::string - The chassis state property value
170      */
171     virtual std::string getChassisState() const
172     {
173         return _chassisState;
174     }
175 
176     /**
177      * @brief Returns the chassis requested power
178      *        transition value.
179      *
180      * @return std::string - The chassis transition property
181      */
182     virtual std::string getChassisTransition() const
183     {
184         return _chassisTransition;
185     }
186 
187     /**
188      * @brief Returns the Host state
189      *
190      * @return std::string - The Host state property value
191      */
192     virtual std::string getHostState() const
193     {
194         return _hostState;
195     }
196 
197     /**
198      * @brief Returns the Boot state
199      *
200      * @return std::string - The Boot state property value
201      */
202     virtual std::string getBootState() const
203     {
204         return _bootState;
205     }
206 
207     /**
208      * @brief Returns the motherboard CCIN
209      *
210      * @return std::string The motherboard CCIN
211      */
212     virtual std::string getMotherboardCCIN() const = 0;
213 
214     /**
215      * @brief Returns the system IM
216      *
217      * @return std::string The system IM
218      */
219     virtual std::vector<uint8_t> getSystemIMKeyword() const = 0;
220 
221     /**
222      * @brief Get the fields from the inventory necessary for doing
223      *        a callout on an inventory path.
224      *
225      * @param[in] inventoryPath - The item to get the data for
226      * @param[out] fruPartNumber - Filled in with the VINI/FN keyword
227      * @param[out] ccin - Filled in with the VINI/CC keyword
228      * @param[out] serialNumber - Filled in with the VINI/SN keyword
229      */
230     virtual void getHWCalloutFields(const std::string& inventoryPath,
231                                     std::string& fruPartNumber,
232                                     std::string& ccin,
233                                     std::string& serialNumber) const = 0;
234 
235     /**
236      * @brief Get the location code for an inventory item.
237      *
238      * @param[in] inventoryPath - The item to get the data for
239      *
240      * @return std::string - The location code
241      */
242     virtual std::string
243         getLocationCode(const std::string& inventoryPath) const = 0;
244 
245     /**
246      * @brief Get the list of system type names the system is called.
247      *
248      * @return std::vector<std::string> - The list of names
249      */
250     virtual std::vector<std::string> getSystemNames() const = 0;
251 
252     /**
253      * @brief Fills in the placeholder 'Ufcs' in the passed in location
254      *        code with the machine feature code and serial number, which
255      *        is needed to create a valid location code.
256      *
257      * @param[in] locationCode - Location code value starting with Ufcs-, and
258      *                           if that isn't present it will be added first.
259      *
260      * @param[in] node - The node number the location is on.
261      *
262      * @return std::string - The expanded location code
263      */
264     virtual std::string expandLocationCode(const std::string& locationCode,
265                                            uint16_t node) const = 0;
266 
267     /**
268      * @brief Returns the inventory path for the FRU that the location
269      *        code represents.
270      *
271      * @param[in] locationCode - If an expanded location code, then the
272      *                           full location code.
273      *                           If not expanded, a location code value
274      *                           starting with Ufcs-, and if that isn't
275      *                           present it will be added first.
276      *
277      * @param[in] node - The node number the location is on.  Ignored if the
278      *                   expanded location code is passed in.
279      *
280      * @param[in] expanded - If the location code already has the relevent
281      *                       VPD fields embedded in it.
282      *
283      * @return std::string - The inventory D-Bus object
284      */
285     virtual std::string getInventoryFromLocCode(const std::string& LocationCode,
286                                                 uint16_t node,
287                                                 bool expanded) const = 0;
288 
289     /**
290      * @brief Sets the Asserted property on the LED group passed in.
291      *
292      * @param[in] ledGroup - The LED group D-Bus path
293      * @param[in] value - The value to set it to
294      */
295     virtual void assertLEDGroup(const std::string& ledGroup,
296                                 bool value) const = 0;
297 
298     /**
299      * @brief Sets the Functional property on the OperationalStatus
300      *        interface on a D-Bus object.
301      *
302      * @param[in] objectPath - The D-Bus object path
303      * @param[in] functional - The value
304      */
305     virtual void setFunctional(const std::string& objectPath,
306                                bool functional) const = 0;
307 
308     /**
309      * @brief Sets the critical association on the D-Bus object.
310      *
311      * @param[in] objectPath - The D-Bus object path
312      */
313     virtual void
314         setCriticalAssociation(const std::string& objectPath) const = 0;
315 
316     /**
317      * @brief Returns the manufacturing QuiesceOnError property
318      *
319      * @return bool - Manufacturing QuiesceOnError property
320      */
321     virtual bool getQuiesceOnError() const = 0;
322 
323     /**
324      * @brief Split location code into base and connector segments
325      *
326      * A location code that ends in '-Tx', where 'x' is a number,
327      * represents a connector, such as a USB cable connector.
328      *
329      * This function splits the passed in location code into a
330      * base and connector segment.  e.g.:
331      *   P0-T1 -> ['P0', '-T1']
332      *   P0 -> ['P0', '']
333      *
334      * @param[in] locationCode - location code to split
335      * @return pair<string, string> - The base and connector segments
336      */
337     static std::pair<std::string, std::string>
338         extractConnectorFromLocCode(const std::string& locationCode);
339 
340     /**
341      * @brief Returns the dump status
342      *
343      * @return bool dump status
344      */
345     virtual std::vector<bool>
346         checkDumpStatus(const std::vector<std::string>& type) const = 0;
347 
348     /**
349      * @brief Create guard record
350      *
351      *  @param[in] binPath: phal devtree binary path used as key
352      *  @param[in] type: Guard type
353      *  @param[in] logPath: error log entry object path
354      */
355     virtual void createGuardRecord(const std::vector<uint8_t>& binPath,
356                                    const std::string& type,
357                                    const std::string& logPath) const = 0;
358 
359     /**
360      * @brief Create Progress SRC property on the boot progress
361      *        interface on a D-Bus object.
362      *
363      * @param[in] priSRC - Primary SRC value (e.g. BD8D1001)
364      * @param[in] srcStruct - Full SRC base structure
365      */
366     virtual void
367         createProgressSRC(const uint64_t& priSRC,
368                           const std::vector<uint8_t>& srcStruct) const = 0;
369 
370     /**
371      * @brief Get the list of unresolved OpenBMC event log ids that have an
372      * associated hardware isolation entry.
373      *
374      * @return std::vector<uint32_t> - The list of log ids
375      */
376     virtual std::vector<uint32_t> getLogIDWithHwIsolation() const = 0;
377 
378   protected:
379     /**
380      * @brief Sets the host on/off state and runs any
381      *        callback functions (if there was a change).
382      */
383     void setHostUp(bool hostUp)
384     {
385         if (_hostUp != hostUp)
386         {
387             _hostUp = hostUp;
388 
389             for (auto& [name, func] : _hostChangeCallbacks)
390             {
391                 try
392                 {
393                     func(_hostUp);
394                 }
395                 catch (const std::exception& e)
396                 {
397                     using namespace phosphor::logging;
398                     log<level::ERR>("A host state change callback threw "
399                                     "an exception");
400                 }
401             }
402         }
403     }
404 
405     /**
406      * @brief The hardware management console status.  Always kept
407      *        up to date.
408      */
409     bool _hmcManaged = false;
410 
411     /**
412      * @brief The host up status.  Always kept up to date.
413      */
414     bool _hostUp = false;
415 
416     /**
417      * @brief The map of host state change subscriber
418      *        names to callback functions.
419      */
420     std::map<std::string, HostStateChangeFunc> _hostChangeCallbacks;
421 
422     /**
423      * @brief The BMC firmware version string
424      */
425     std::string _bmcFWVersion;
426 
427     /**
428      * @brief The server firmware version string
429      */
430     std::string _serverFWVersion;
431 
432     /**
433      * @brief The BMC firmware version ID string
434      */
435     std::string _bmcFWVersionID;
436 
437     /**
438      * @brief If sending PELs is enabled.
439      *
440      * This is usually set to false in manufacturing test.
441      */
442     bool _sendPELsToHost = true;
443 
444     /**
445      * @brief The BMC state property
446      */
447     std::string _bmcState;
448 
449     /**
450      * @brief The Chassis current power state property
451      */
452     std::string _chassisState;
453 
454     /**
455      * @brief The Chassis requested power transition property
456      */
457     std::string _chassisTransition;
458 
459     /**
460      * @brief The host state property
461      */
462     std::string _hostState;
463 
464     /**
465      * @brief The boot state property
466      */
467     std::string _bootState;
468 };
469 
470 /**
471  * @class DataInterface
472  *
473  * Concrete implementation of DataInterfaceBase.
474  */
475 class DataInterface : public DataInterfaceBase
476 {
477   public:
478     DataInterface() = delete;
479     ~DataInterface() = default;
480     DataInterface(const DataInterface&) = default;
481     DataInterface& operator=(const DataInterface&) = default;
482     DataInterface(DataInterface&&) = default;
483     DataInterface& operator=(DataInterface&&) = default;
484 
485     /**
486      * @brief Constructor
487      *
488      * @param[in] bus - The sdbusplus bus object
489      */
490     explicit DataInterface(sdbusplus::bus::bus& bus);
491 
492     /**
493      * @brief Finds the D-Bus service name that hosts the
494      *        passed in path and interface.
495      *
496      * @param[in] objectPath - The D-Bus object path
497      * @param[in] interface - The D-Bus interface
498      */
499     DBusService getService(const std::string& objectPath,
500                            const std::string& interface) const;
501 
502     /**
503      * @brief Wrapper for the 'GetAll' properties method call
504      *
505      * @param[in] service - The D-Bus service to call it on
506      * @param[in] objectPath - The D-Bus object path
507      * @param[in] interface - The interface to get the props on
508      *
509      * @return DBusPropertyMap - The property results
510      */
511     DBusPropertyMap getAllProperties(const std::string& service,
512                                      const std::string& objectPath,
513                                      const std::string& interface) const;
514     /**
515      * @brief Wrapper for the 'Get' properties method call
516      *
517      * @param[in] service - The D-Bus service to call it on
518      * @param[in] objectPath - The D-Bus object path
519      * @param[in] interface - The interface to get the property on
520      * @param[in] property - The property name
521      * @param[out] value - Filled in with the property value.
522      */
523     void getProperty(const std::string& service, const std::string& objectPath,
524                      const std::string& interface, const std::string& property,
525                      DBusValue& value) const;
526     /**
527      * @brief Returns the machine Type/Model
528      *
529      * @return string - The machine Type/Model string
530      */
531     std::string getMachineTypeModel() const override;
532 
533     /**
534      * @brief Returns the machine serial number
535      *
536      * @return string - The machine serial number
537      */
538     std::string getMachineSerialNumber() const override;
539 
540     /**
541      * @brief Returns the motherboard CCIN
542      *
543      * @return std::string The motherboard CCIN
544      */
545     std::string getMotherboardCCIN() const override;
546 
547     /**
548      * @brief Returns the system IM
549      *
550      * @return std::vector The system IM keyword in 4 byte vector
551      */
552     std::vector<uint8_t> getSystemIMKeyword() const override;
553 
554     /**
555      * @brief Get the fields from the inventory necessary for doing
556      *        a callout on an inventory path.
557      *
558      * @param[in] inventoryPath - The item to get the data for
559      * @param[out] fruPartNumber - Filled in with the VINI/FN keyword
560      * @param[out] ccin - Filled in with the VINI/CC keyword
561      * @param[out] serialNumber - Filled in with the VINI/SN keyword
562      */
563     void getHWCalloutFields(const std::string& inventoryPath,
564                             std::string& fruPartNumber, std::string& ccin,
565                             std::string& serialNumber) const override;
566 
567     /**
568      * @brief Get the location code for an inventory item.
569      *
570      * Throws an exception if the inventory item doesn't have the
571      * location code interface.
572      *
573      * @param[in] inventoryPath - The item to get the data for
574      *
575      * @return std::string - The location code
576      */
577     std::string
578         getLocationCode(const std::string& inventoryPath) const override;
579 
580     /**
581      * @brief Get the list of system type names the system is called.
582      *
583      * @return std::vector<std::string> - The list of names
584      */
585     std::vector<std::string> getSystemNames() const override;
586 
587     /**
588      * @brief Fills in the placeholder 'Ufcs' in the passed in location
589      *        code with the machine feature code and serial number, which
590      *        is needed to create a valid location code.
591      *
592      * @param[in] locationCode - Location code value starting with Ufcs-, and
593      *                           if that isn't present it will be added first.
594      *
595      * @param[in] node - The node number the location is one.
596      *
597      * @return std::string - The expanded location code
598      */
599     std::string expandLocationCode(const std::string& locationCode,
600                                    uint16_t node) const override;
601 
602     /**
603      * @brief Returns the inventory path for the FRU that the location
604      *        code represents.
605      *
606      * @param[in] locationCode - If an expanded location code, then the
607      *                           full location code.
608      *                           If not expanded, a location code value
609      *                           starting with Ufcs-, and if that isn't
610      *                           present it will be added first.
611      *
612      * @param[in] node - The node number the location is on.  Ignored if the
613      *                   expanded location code is passed in.
614      *
615      * @param[in] expanded - If the location code already has the relevent
616      *                       VPD fields embedded in it.
617      *
618      * @return std::string - The inventory D-Bus object
619      */
620     std::string getInventoryFromLocCode(const std::string& locationCode,
621                                         uint16_t node,
622                                         bool expanded) const override;
623 
624     /**
625      * @brief Sets the Asserted property on the LED group passed in.
626      *
627      * @param[in] ledGroup - The LED group D-Bus path
628      * @param[in] value - The value to set it to
629      */
630     void assertLEDGroup(const std::string& ledGroup, bool value) const override;
631 
632     /**
633      * @brief Sets the Functional property on the OperationalStatus
634      *        interface on a D-Bus object.
635      *
636      * @param[in] objectPath - The D-Bus object path
637      * @param[in] functional - The value
638      */
639     void setFunctional(const std::string& objectPath,
640                        bool functional) const override;
641 
642     /**
643      * @brief Sets the critical association on the D-Bus object.
644      *
645      * @param[in] objectPath - The D-Bus object path
646      */
647     void setCriticalAssociation(const std::string& objectPath) const override;
648 
649     /**
650      * @brief Returns the manufacturing QuiesceOnError property
651      *
652      * @return bool - Manufacturing QuiesceOnError property
653      */
654     bool getQuiesceOnError() const override;
655 
656     /**
657      * @brief Returns the dump status
658      *
659      * @param[in] type - The dump type to check for
660      *
661      * @return bool dump status
662      */
663     std::vector<bool>
664         checkDumpStatus(const std::vector<std::string>& type) const override;
665 
666     /**
667      * @brief Create guard record
668      *
669      *  @param[in] binPath: phal devtree binary path used as key
670      *  @param[in] type: Guard type
671      *  @param[in] logPath: error log entry object path
672      */
673     void createGuardRecord(const std::vector<uint8_t>& binPath,
674                            const std::string& type,
675                            const std::string& logPath) const override;
676 
677     /**
678      * @brief Create Progress SRC property on the boot progress
679      *        interface on a D-Bus object.
680      *
681      * @param[in] priSRC - Primary SRC value
682      * @param[in] srcStruct - Full SRC base structure
683      */
684     void
685         createProgressSRC(const uint64_t& priSRC,
686                           const std::vector<uint8_t>& srcStruct) const override;
687 
688     /**
689      * @brief Get the list of unresolved OpenBMC event log ids that have an
690      * associated hardware isolation entry.
691      *
692      * @return std::vector<uint32_t> - The list of log ids
693      */
694     std::vector<uint32_t> getLogIDWithHwIsolation() const override;
695 
696   private:
697     /**
698      * @brief Reads the BMC firmware version string and puts it into
699      *        _bmcFWVersion.
700      */
701     void readBMCFWVersion();
702 
703     /**
704      * @brief Reads the server firmware version string and puts it into
705      *        _serverFWVersion.
706      */
707     void readServerFWVersion();
708 
709     /**
710      * @brief Reads the BMC firmware version ID and puts it into
711      *        _bmcFWVersionID.
712      */
713     void readBMCFWVersionID();
714 
715     /**
716      * @brief Finds all D-Bus paths that contain any of the interfaces
717      *        passed in, by using GetSubTreePaths.
718      *
719      * @param[in] interfaces - The desired interfaces
720      *
721      * @return The D-Bus paths.
722      */
723     DBusPathList getPaths(const DBusInterfaceList& interfaces) const;
724 
725     /**
726      * @brief The interfacesAdded callback used on the inventory to
727      *        find the D-Bus object that has the motherboard interface.
728      *        When the motherboard is found, it then adds a PropertyWatcher
729      *        for the motherboard CCIN.
730      */
731     void motherboardIfaceAdded(sdbusplus::message::message& msg);
732 
733     /**
734      * @brief Adds the Ufcs- prefix to the location code passed in
735      *        if necessary.
736      *
737      * Needed because the location codes that come back from the
738      * message registry and device callout JSON don't have it.
739      *
740      * @param[in] - The location code without a prefix, like P1-C1
741      *
742      * @return std::string - The location code with the prefix
743      */
744     static std::string addLocationCodePrefix(const std::string& locationCode);
745 
746     /**
747      * @brief The D-Bus property or interface watchers that have callbacks
748      *        registered that will set members in this class when
749      *        they change.
750      */
751     std::vector<std::unique_ptr<DBusWatcher>> _properties;
752 
753     /**
754      * @brief The sdbusplus bus object for making D-Bus calls.
755      */
756     sdbusplus::bus::bus& _bus;
757 
758     /**
759      * @brief The interfacesAdded match object used to wait for inventory
760      *        interfaces to show up, so that the object with the motherboard
761      *        interface can be found.  After it is found, this object is
762      *        deleted.
763      */
764     std::unique_ptr<sdbusplus::bus::match_t> _inventoryIfacesAddedMatch;
765 };
766 
767 } // namespace pels
768 } // namespace openpower
769