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