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   protected:
360     /**
361      * @brief Sets the host on/off state and runs any
362      *        callback functions (if there was a change).
363      */
364     void setHostUp(bool hostUp)
365     {
366         if (_hostUp != hostUp)
367         {
368             _hostUp = hostUp;
369 
370             for (auto& [name, func] : _hostChangeCallbacks)
371             {
372                 try
373                 {
374                     func(_hostUp);
375                 }
376                 catch (const std::exception& e)
377                 {
378                     using namespace phosphor::logging;
379                     log<level::ERR>("A host state change callback threw "
380                                     "an exception");
381                 }
382             }
383         }
384     }
385 
386     /**
387      * @brief The hardware management console status.  Always kept
388      *        up to date.
389      */
390     bool _hmcManaged = false;
391 
392     /**
393      * @brief The host up status.  Always kept up to date.
394      */
395     bool _hostUp = false;
396 
397     /**
398      * @brief The map of host state change subscriber
399      *        names to callback functions.
400      */
401     std::map<std::string, HostStateChangeFunc> _hostChangeCallbacks;
402 
403     /**
404      * @brief The BMC firmware version string
405      */
406     std::string _bmcFWVersion;
407 
408     /**
409      * @brief The server firmware version string
410      */
411     std::string _serverFWVersion;
412 
413     /**
414      * @brief The BMC firmware version ID string
415      */
416     std::string _bmcFWVersionID;
417 
418     /**
419      * @brief If sending PELs is enabled.
420      *
421      * This is usually set to false in manufacturing test.
422      */
423     bool _sendPELsToHost = true;
424 
425     /**
426      * @brief The BMC state property
427      */
428     std::string _bmcState;
429 
430     /**
431      * @brief The Chassis current power state property
432      */
433     std::string _chassisState;
434 
435     /**
436      * @brief The Chassis requested power transition property
437      */
438     std::string _chassisTransition;
439 
440     /**
441      * @brief The host state property
442      */
443     std::string _hostState;
444 
445     /**
446      * @brief The boot state property
447      */
448     std::string _bootState;
449 };
450 
451 /**
452  * @class DataInterface
453  *
454  * Concrete implementation of DataInterfaceBase.
455  */
456 class DataInterface : public DataInterfaceBase
457 {
458   public:
459     DataInterface() = delete;
460     ~DataInterface() = default;
461     DataInterface(const DataInterface&) = default;
462     DataInterface& operator=(const DataInterface&) = default;
463     DataInterface(DataInterface&&) = default;
464     DataInterface& operator=(DataInterface&&) = default;
465 
466     /**
467      * @brief Constructor
468      *
469      * @param[in] bus - The sdbusplus bus object
470      */
471     explicit DataInterface(sdbusplus::bus::bus& bus);
472 
473     /**
474      * @brief Finds the D-Bus service name that hosts the
475      *        passed in path and interface.
476      *
477      * @param[in] objectPath - The D-Bus object path
478      * @param[in] interface - The D-Bus interface
479      */
480     DBusService getService(const std::string& objectPath,
481                            const std::string& interface) const;
482 
483     /**
484      * @brief Wrapper for the 'GetAll' properties method call
485      *
486      * @param[in] service - The D-Bus service to call it on
487      * @param[in] objectPath - The D-Bus object path
488      * @param[in] interface - The interface to get the props on
489      *
490      * @return DBusPropertyMap - The property results
491      */
492     DBusPropertyMap getAllProperties(const std::string& service,
493                                      const std::string& objectPath,
494                                      const std::string& interface) const;
495     /**
496      * @brief Wrapper for the 'Get' properties method call
497      *
498      * @param[in] service - The D-Bus service to call it on
499      * @param[in] objectPath - The D-Bus object path
500      * @param[in] interface - The interface to get the property on
501      * @param[in] property - The property name
502      * @param[out] value - Filled in with the property value.
503      */
504     void getProperty(const std::string& service, const std::string& objectPath,
505                      const std::string& interface, const std::string& property,
506                      DBusValue& value) const;
507     /**
508      * @brief Returns the machine Type/Model
509      *
510      * @return string - The machine Type/Model string
511      */
512     std::string getMachineTypeModel() const override;
513 
514     /**
515      * @brief Returns the machine serial number
516      *
517      * @return string - The machine serial number
518      */
519     std::string getMachineSerialNumber() const override;
520 
521     /**
522      * @brief Returns the motherboard CCIN
523      *
524      * @return std::string The motherboard CCIN
525      */
526     std::string getMotherboardCCIN() const override;
527 
528     /**
529      * @brief Returns the system IM
530      *
531      * @return std::vector The system IM keyword in 4 byte vector
532      */
533     std::vector<uint8_t> getSystemIMKeyword() const override;
534 
535     /**
536      * @brief Get the fields from the inventory necessary for doing
537      *        a callout on an inventory path.
538      *
539      * @param[in] inventoryPath - The item to get the data for
540      * @param[out] fruPartNumber - Filled in with the VINI/FN keyword
541      * @param[out] ccin - Filled in with the VINI/CC keyword
542      * @param[out] serialNumber - Filled in with the VINI/SN keyword
543      */
544     void getHWCalloutFields(const std::string& inventoryPath,
545                             std::string& fruPartNumber, std::string& ccin,
546                             std::string& serialNumber) const override;
547 
548     /**
549      * @brief Get the location code for an inventory item.
550      *
551      * Throws an exception if the inventory item doesn't have the
552      * location code interface.
553      *
554      * @param[in] inventoryPath - The item to get the data for
555      *
556      * @return std::string - The location code
557      */
558     std::string
559         getLocationCode(const std::string& inventoryPath) const override;
560 
561     /**
562      * @brief Get the list of system type names the system is called.
563      *
564      * @return std::vector<std::string> - The list of names
565      */
566     std::vector<std::string> getSystemNames() const override;
567 
568     /**
569      * @brief Fills in the placeholder 'Ufcs' in the passed in location
570      *        code with the machine feature code and serial number, which
571      *        is needed to create a valid location code.
572      *
573      * @param[in] locationCode - Location code value starting with Ufcs-, and
574      *                           if that isn't present it will be added first.
575      *
576      * @param[in] node - The node number the location is one.
577      *
578      * @return std::string - The expanded location code
579      */
580     std::string expandLocationCode(const std::string& locationCode,
581                                    uint16_t node) const override;
582 
583     /**
584      * @brief Returns the inventory path for the FRU that the location
585      *        code represents.
586      *
587      * @param[in] locationCode - If an expanded location code, then the
588      *                           full location code.
589      *                           If not expanded, a location code value
590      *                           starting with Ufcs-, and if that isn't
591      *                           present it will be added first.
592      *
593      * @param[in] node - The node number the location is on.  Ignored if the
594      *                   expanded location code is passed in.
595      *
596      * @param[in] expanded - If the location code already has the relevent
597      *                       VPD fields embedded in it.
598      *
599      * @return std::string - The inventory D-Bus object
600      */
601     std::string getInventoryFromLocCode(const std::string& locationCode,
602                                         uint16_t node,
603                                         bool expanded) const override;
604 
605     /**
606      * @brief Sets the Asserted property on the LED group passed in.
607      *
608      * @param[in] ledGroup - The LED group D-Bus path
609      * @param[in] value - The value to set it to
610      */
611     void assertLEDGroup(const std::string& ledGroup, bool value) const override;
612 
613     /**
614      * @brief Sets the Functional property on the OperationalStatus
615      *        interface on a D-Bus object.
616      *
617      * @param[in] objectPath - The D-Bus object path
618      * @param[in] functional - The value
619      */
620     void setFunctional(const std::string& objectPath,
621                        bool functional) const override;
622 
623     /**
624      * @brief Sets the critical association on the D-Bus object.
625      *
626      * @param[in] objectPath - The D-Bus object path
627      */
628     void setCriticalAssociation(const std::string& objectPath) const override;
629 
630     /**
631      * @brief Returns the manufacturing QuiesceOnError property
632      *
633      * @return bool - Manufacturing QuiesceOnError property
634      */
635     bool getQuiesceOnError() const override;
636 
637     /**
638      * @brief Returns the dump status
639      *
640      * @param[in] type - The dump type to check for
641      *
642      * @return bool dump status
643      */
644     std::vector<bool>
645         checkDumpStatus(const std::vector<std::string>& type) const override;
646 
647     /**
648      * @brief Create guard record
649      *
650      *  @param[in] binPath: phal devtree binary path used as key
651      *  @param[in] type: Guard type
652      *  @param[in] logPath: error log entry object path
653      */
654     void createGuardRecord(const std::vector<uint8_t>& binPath,
655                            const std::string& type,
656                            const std::string& logPath) const override;
657 
658   private:
659     /**
660      * @brief Reads the BMC firmware version string and puts it into
661      *        _bmcFWVersion.
662      */
663     void readBMCFWVersion();
664 
665     /**
666      * @brief Reads the server firmware version string and puts it into
667      *        _serverFWVersion.
668      */
669     void readServerFWVersion();
670 
671     /**
672      * @brief Reads the BMC firmware version ID and puts it into
673      *        _bmcFWVersionID.
674      */
675     void readBMCFWVersionID();
676 
677     /**
678      * @brief Finds all D-Bus paths that contain any of the interfaces
679      *        passed in, by using GetSubTreePaths.
680      *
681      * @param[in] interfaces - The desired interfaces
682      *
683      * @return The D-Bus paths.
684      */
685     DBusPathList getPaths(const DBusInterfaceList& interfaces) const;
686 
687     /**
688      * @brief The interfacesAdded callback used on the inventory to
689      *        find the D-Bus object that has the motherboard interface.
690      *        When the motherboard is found, it then adds a PropertyWatcher
691      *        for the motherboard CCIN.
692      */
693     void motherboardIfaceAdded(sdbusplus::message::message& msg);
694 
695     /**
696      * @brief Adds the Ufcs- prefix to the location code passed in
697      *        if necessary.
698      *
699      * Needed because the location codes that come back from the
700      * message registry and device callout JSON don't have it.
701      *
702      * @param[in] - The location code without a prefix, like P1-C1
703      *
704      * @return std::string - The location code with the prefix
705      */
706     static std::string addLocationCodePrefix(const std::string& locationCode);
707 
708     /**
709      * @brief The D-Bus property or interface watchers that have callbacks
710      *        registered that will set members in this class when
711      *        they change.
712      */
713     std::vector<std::unique_ptr<DBusWatcher>> _properties;
714 
715     /**
716      * @brief The sdbusplus bus object for making D-Bus calls.
717      */
718     sdbusplus::bus::bus& _bus;
719 
720     /**
721      * @brief The interfacesAdded match object used to wait for inventory
722      *        interfaces to show up, so that the object with the motherboard
723      *        interface can be found.  After it is found, this object is
724      *        deleted.
725      */
726     std::unique_ptr<sdbusplus::bus::match_t> _inventoryIfacesAddedMatch;
727 };
728 
729 } // namespace pels
730 } // namespace openpower
731