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