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