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 /** 466 * @brief Returns the latest raw progress SRC from the State.Boot.Raw 467 * D-Bus interface. 468 * 469 * @return std::vector<uint8_t> - The progress SRC bytes 470 */ 471 virtual std::vector<uint8_t> getRawProgressSRC() const = 0; 472 473 protected: 474 /** 475 * @brief Sets the host on/off state and runs any 476 * callback functions (if there was a change). 477 */ 478 void setHostUp(bool hostUp) 479 { 480 if (_hostUp != hostUp) 481 { 482 _hostUp = hostUp; 483 484 for (auto& [name, func] : _hostChangeCallbacks) 485 { 486 try 487 { 488 func(_hostUp); 489 } 490 catch (const std::exception& e) 491 { 492 using namespace phosphor::logging; 493 log<level::ERR>("A host state change callback threw " 494 "an exception"); 495 } 496 } 497 } 498 } 499 500 /** 501 * @brief The hardware management console status. Always kept 502 * up to date. 503 */ 504 bool _hmcManaged = false; 505 506 /** 507 * @brief The host up status. Always kept up to date. 508 */ 509 bool _hostUp = false; 510 511 /** 512 * @brief The map of host state change subscriber 513 * names to callback functions. 514 */ 515 std::map<std::string, HostStateChangeFunc> _hostChangeCallbacks; 516 517 /** 518 * @brief The BMC firmware version string 519 */ 520 std::string _bmcFWVersion; 521 522 /** 523 * @brief The server firmware version string 524 */ 525 std::string _serverFWVersion; 526 527 /** 528 * @brief The BMC firmware version ID string 529 */ 530 std::string _bmcFWVersionID; 531 532 /** 533 * @brief If sending PELs is enabled. 534 * 535 * This is usually set to false in manufacturing test. 536 */ 537 bool _sendPELsToHost = true; 538 539 /** 540 * @brief The BMC state property 541 */ 542 std::string _bmcState; 543 544 /** 545 * @brief The Chassis current power state property 546 */ 547 std::string _chassisState; 548 549 /** 550 * @brief The Chassis requested power transition property 551 */ 552 std::string _chassisTransition; 553 554 /** 555 * @brief The host state property 556 */ 557 std::string _hostState; 558 559 /** 560 * @brief The boot state property 561 */ 562 std::string _bootState; 563 }; 564 565 /** 566 * @class DataInterface 567 * 568 * Concrete implementation of DataInterfaceBase. 569 */ 570 class DataInterface : public DataInterfaceBase 571 { 572 public: 573 DataInterface() = delete; 574 ~DataInterface() = default; 575 DataInterface(const DataInterface&) = default; 576 DataInterface& operator=(const DataInterface&) = default; 577 DataInterface(DataInterface&&) = default; 578 DataInterface& operator=(DataInterface&&) = default; 579 580 /** 581 * @brief Constructor 582 * 583 * @param[in] bus - The sdbusplus bus object 584 */ 585 explicit DataInterface(sdbusplus::bus_t& bus); 586 587 /** 588 * @brief Finds the D-Bus service name that hosts the 589 * passed in path and interface. 590 * 591 * @param[in] objectPath - The D-Bus object path 592 * @param[in] interface - The D-Bus interface 593 */ 594 DBusService getService(const std::string& objectPath, 595 const std::string& interface) const; 596 597 /** 598 * @brief Wrapper for the 'GetAll' properties method call 599 * 600 * @param[in] service - The D-Bus service to call it on 601 * @param[in] objectPath - The D-Bus object path 602 * @param[in] interface - The interface to get the props on 603 * 604 * @return DBusPropertyMap - The property results 605 */ 606 DBusPropertyMap getAllProperties(const std::string& service, 607 const std::string& objectPath, 608 const std::string& interface) const; 609 /** 610 * @brief Wrapper for the 'Get' properties method call 611 * 612 * @param[in] service - The D-Bus service to call it on 613 * @param[in] objectPath - The D-Bus object path 614 * @param[in] interface - The interface to get the property on 615 * @param[in] property - The property name 616 * @param[out] value - Filled in with the property value. 617 */ 618 void getProperty(const std::string& service, const std::string& objectPath, 619 const std::string& interface, const std::string& property, 620 DBusValue& value) const; 621 /** 622 * @brief Returns the machine Type/Model 623 * 624 * @return string - The machine Type/Model string 625 */ 626 std::string getMachineTypeModel() const override; 627 628 /** 629 * @brief Returns the machine serial number 630 * 631 * @return string - The machine serial number 632 */ 633 std::string getMachineSerialNumber() const override; 634 635 /** 636 * @brief Returns the motherboard CCIN 637 * 638 * @return std::string The motherboard CCIN 639 */ 640 std::string getMotherboardCCIN() const override; 641 642 /** 643 * @brief Returns the system IM 644 * 645 * @return std::vector The system IM keyword in 4 byte vector 646 */ 647 std::vector<uint8_t> getSystemIMKeyword() const override; 648 649 /** 650 * @brief Get the fields from the inventory necessary for doing 651 * a callout on an inventory path. 652 * 653 * @param[in] inventoryPath - The item to get the data for 654 * @param[out] fruPartNumber - Filled in with the VINI/FN keyword 655 * @param[out] ccin - Filled in with the VINI/CC keyword 656 * @param[out] serialNumber - Filled in with the VINI/SN keyword 657 */ 658 void getHWCalloutFields(const std::string& inventoryPath, 659 std::string& fruPartNumber, std::string& ccin, 660 std::string& serialNumber) const override; 661 662 /** 663 * @brief Get the location code for an inventory item. 664 * 665 * Throws an exception if the inventory item doesn't have the 666 * location code interface. 667 * 668 * @param[in] inventoryPath - The item to get the data for 669 * 670 * @return std::string - The location code 671 */ 672 std::string 673 getLocationCode(const std::string& inventoryPath) const override; 674 675 /** 676 * @brief Get the list of system type names the system is called. 677 * 678 * @return std::vector<std::string> - The list of names 679 */ 680 std::vector<std::string> getSystemNames() const override; 681 682 /** 683 * @brief Fills in the placeholder 'Ufcs' in the passed in location 684 * code with the machine feature code and serial number, which 685 * is needed to create a valid location code. 686 * 687 * @param[in] locationCode - Location code value starting with Ufcs-, and 688 * if that isn't present it will be added first. 689 * 690 * @param[in] node - The node number the location is one. 691 * 692 * @return std::string - The expanded location code 693 */ 694 std::string expandLocationCode(const std::string& locationCode, 695 uint16_t node) const override; 696 697 /** 698 * @brief Returns the inventory path for the FRU that the location 699 * code represents. 700 * 701 * @param[in] locationCode - If an expanded location code, then the 702 * full location code. 703 * If not expanded, a location code value 704 * starting with Ufcs-, and if that isn't 705 * present it will be added first. 706 * 707 * @param[in] node - The node number the location is on. Ignored if the 708 * expanded location code is passed in. 709 * 710 * @param[in] expanded - If the location code already has the relevent 711 * VPD fields embedded in it. 712 * 713 * @return std::string - The inventory D-Bus object 714 */ 715 std::string getInventoryFromLocCode(const std::string& locationCode, 716 uint16_t node, 717 bool expanded) const override; 718 719 /** 720 * @brief Sets the Asserted property on the LED group passed in. 721 * 722 * @param[in] ledGroup - The LED group D-Bus path 723 * @param[in] value - The value to set it to 724 */ 725 void assertLEDGroup(const std::string& ledGroup, bool value) const override; 726 727 /** 728 * @brief Sets the Functional property on the OperationalStatus 729 * interface on a D-Bus object. 730 * 731 * @param[in] objectPath - The D-Bus object path 732 * @param[in] functional - The value 733 */ 734 void setFunctional(const std::string& objectPath, 735 bool functional) const override; 736 737 /** 738 * @brief Sets the critical association on the D-Bus object. 739 * 740 * @param[in] objectPath - The D-Bus object path 741 */ 742 void setCriticalAssociation(const std::string& objectPath) const override; 743 744 /** 745 * @brief Returns the manufacturing QuiesceOnError property 746 * 747 * @return bool - Manufacturing QuiesceOnError property 748 */ 749 bool getQuiesceOnError() const override; 750 751 /** 752 * @brief Returns the dump status 753 * 754 * @param[in] type - The dump type to check for 755 * 756 * @return bool dump status 757 */ 758 std::vector<bool> 759 checkDumpStatus(const std::vector<std::string>& type) const override; 760 761 /** 762 * @brief Create guard record 763 * 764 * @param[in] binPath: phal devtree binary path used as key 765 * @param[in] type: Guard type 766 * @param[in] logPath: error log entry object path 767 */ 768 void createGuardRecord(const std::vector<uint8_t>& binPath, 769 const std::string& type, 770 const std::string& logPath) const override; 771 772 /** 773 * @brief Create Progress SRC property on the boot progress 774 * interface on a D-Bus object. 775 * 776 * @param[in] priSRC - Primary SRC value 777 * @param[in] srcStruct - Full SRC base structure 778 */ 779 void 780 createProgressSRC(const uint64_t& priSRC, 781 const std::vector<uint8_t>& srcStruct) const override; 782 783 /** 784 * @brief Get the list of unresolved OpenBMC event log ids that have an 785 * associated hardware isolation entry. 786 * 787 * @return std::vector<uint32_t> - The list of log ids 788 */ 789 std::vector<uint32_t> getLogIDWithHwIsolation() const override; 790 791 /** 792 * @brief Returns the latest raw progress SRC from the State.Boot.Raw 793 * D-Bus interface. 794 * 795 * @return std::vector<uint8_t>: The progress SRC bytes 796 */ 797 std::vector<uint8_t> getRawProgressSRC() const override; 798 799 private: 800 /** 801 * @brief Reads the BMC firmware version string and puts it into 802 * _bmcFWVersion. 803 */ 804 void readBMCFWVersion(); 805 806 /** 807 * @brief Reads the server firmware version string and puts it into 808 * _serverFWVersion. 809 */ 810 void readServerFWVersion(); 811 812 /** 813 * @brief Reads the BMC firmware version ID and puts it into 814 * _bmcFWVersionID. 815 */ 816 void readBMCFWVersionID(); 817 818 /** 819 * @brief Finds all D-Bus paths that contain any of the interfaces 820 * passed in, by using GetSubTreePaths. 821 * 822 * @param[in] interfaces - The desired interfaces 823 * 824 * @return The D-Bus paths. 825 */ 826 DBusPathList getPaths(const DBusInterfaceList& interfaces) const; 827 828 /** 829 * @brief The interfacesAdded callback used on the inventory to 830 * find the D-Bus object that has the motherboard interface. 831 * When the motherboard is found, it then adds a PropertyWatcher 832 * for the motherboard CCIN. 833 */ 834 void motherboardIfaceAdded(sdbusplus::message_t& msg); 835 836 /** 837 * @brief Adds the Ufcs- prefix to the location code passed in 838 * if necessary. 839 * 840 * Needed because the location codes that come back from the 841 * message registry and device callout JSON don't have it. 842 * 843 * @param[in] - The location code without a prefix, like P1-C1 844 * 845 * @return std::string - The location code with the prefix 846 */ 847 static std::string addLocationCodePrefix(const std::string& locationCode); 848 849 /** 850 * @brief The D-Bus property or interface watchers that have callbacks 851 * registered that will set members in this class when 852 * they change. 853 */ 854 std::vector<std::unique_ptr<DBusWatcher>> _properties; 855 856 /** 857 * @brief The sdbusplus bus object for making D-Bus calls. 858 */ 859 sdbusplus::bus_t& _bus; 860 861 /** 862 * @brief The interfacesAdded match object used to wait for inventory 863 * interfaces to show up, so that the object with the motherboard 864 * interface can be found. After it is found, this object is 865 * deleted. 866 */ 867 std::unique_ptr<sdbusplus::bus::match_t> _inventoryIfacesAddedMatch; 868 }; 869 870 } // namespace pels 871 } // namespace openpower 872