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