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 motherboard CCIN 199 * 200 * @return std::string The motherboard CCIN 201 */ 202 virtual std::string getMotherboardCCIN() const = 0; 203 204 /** 205 * @brief Returns the system IM 206 * 207 * @return std::string The system IM 208 */ 209 virtual std::vector<uint8_t> getSystemIMKeyword() const = 0; 210 211 /** 212 * @brief Get the fields from the inventory necessary for doing 213 * a callout on an inventory path. 214 * 215 * @param[in] inventoryPath - The item to get the data for 216 * @param[out] fruPartNumber - Filled in with the VINI/FN keyword 217 * @param[out] ccin - Filled in with the VINI/CC keyword 218 * @param[out] serialNumber - Filled in with the VINI/SN keyword 219 */ 220 virtual void getHWCalloutFields(const std::string& inventoryPath, 221 std::string& fruPartNumber, 222 std::string& ccin, 223 std::string& serialNumber) const = 0; 224 225 /** 226 * @brief Get the location code for an inventory item. 227 * 228 * @param[in] inventoryPath - The item to get the data for 229 * 230 * @return std::string - The location code 231 */ 232 virtual std::string 233 getLocationCode(const std::string& inventoryPath) const = 0; 234 235 /** 236 * @brief Get the list of system type names the system is called. 237 * 238 * @return std::vector<std::string> - The list of names 239 */ 240 virtual std::vector<std::string> getSystemNames() const = 0; 241 242 /** 243 * @brief Fills in the placeholder 'Ufcs' in the passed in location 244 * code with the machine feature code and serial number, which 245 * is needed to create a valid location code. 246 * 247 * @param[in] locationCode - Location code value starting with Ufcs-, and 248 * if that isn't present it will be added first. 249 * 250 * @param[in] node - The node number the location is on. 251 * 252 * @return std::string - The expanded location code 253 */ 254 virtual std::string expandLocationCode(const std::string& locationCode, 255 uint16_t node) const = 0; 256 257 /** 258 * @brief Returns the inventory path for the FRU that the location 259 * code represents. 260 * 261 * @param[in] locationCode - If an expanded location code, then the 262 * full location code. 263 * If not expanded, a location code value 264 * starting with Ufcs-, and if that isn't 265 * present it will be added first. 266 * 267 * @param[in] node - The node number the location is on. Ignored if the 268 * expanded location code is passed in. 269 * 270 * @param[in] expanded - If the location code already has the relevent 271 * VPD fields embedded in it. 272 * 273 * @return std::string - The inventory D-Bus object 274 */ 275 virtual std::string getInventoryFromLocCode(const std::string& LocationCode, 276 uint16_t node, 277 bool expanded) const = 0; 278 279 /** 280 * @brief Sets the Asserted property on the LED group passed in. 281 * 282 * @param[in] ledGroup - The LED group D-Bus path 283 * @param[in] value - The value to set it to 284 */ 285 virtual void assertLEDGroup(const std::string& ledGroup, 286 bool value) const = 0; 287 288 /** 289 * @brief Sets the Functional property on the OperationalStatus 290 * interface on a D-Bus object. 291 * 292 * @param[in] objectPath - The D-Bus object path 293 * @param[in] functional - The value 294 */ 295 virtual void setFunctional(const std::string& objectPath, 296 bool functional) const = 0; 297 298 /** 299 * @brief Sets the critical association on the D-Bus object. 300 * 301 * @param[in] objectPath - The D-Bus object path 302 */ 303 virtual void 304 setCriticalAssociation(const std::string& objectPath) const = 0; 305 306 /** 307 * @brief Returns the manufacturing QuiesceOnError property 308 * 309 * @return bool - Manufacturing QuiesceOnError property 310 */ 311 virtual bool getQuiesceOnError() const = 0; 312 313 /** 314 * @brief Split location code into base and connector segments 315 * 316 * A location code that ends in '-Tx', where 'x' is a number, 317 * represents a connector, such as a USB cable connector. 318 * 319 * This function splits the passed in location code into a 320 * base and connector segment. e.g.: 321 * P0-T1 -> ['P0', '-T1'] 322 * P0 -> ['P0', ''] 323 * 324 * @param[in] locationCode - location code to split 325 * @return pair<string, string> - The base and connector segments 326 */ 327 static std::pair<std::string, std::string> 328 extractConnectorFromLocCode(const std::string& locationCode); 329 330 protected: 331 /** 332 * @brief Sets the host on/off state and runs any 333 * callback functions (if there was a change). 334 */ 335 void setHostUp(bool hostUp) 336 { 337 if (_hostUp != hostUp) 338 { 339 _hostUp = hostUp; 340 341 for (auto& [name, func] : _hostChangeCallbacks) 342 { 343 try 344 { 345 func(_hostUp); 346 } 347 catch (std::exception& e) 348 { 349 using namespace phosphor::logging; 350 log<level::ERR>("A host state change callback threw " 351 "an exception"); 352 } 353 } 354 } 355 } 356 357 /** 358 * @brief The hardware management console status. Always kept 359 * up to date. 360 */ 361 bool _hmcManaged = false; 362 363 /** 364 * @brief The host up status. Always kept up to date. 365 */ 366 bool _hostUp = false; 367 368 /** 369 * @brief The map of host state change subscriber 370 * names to callback functions. 371 */ 372 std::map<std::string, HostStateChangeFunc> _hostChangeCallbacks; 373 374 /** 375 * @brief The BMC firmware version string 376 */ 377 std::string _bmcFWVersion; 378 379 /** 380 * @brief The server firmware version string 381 */ 382 std::string _serverFWVersion; 383 384 /** 385 * @brief The BMC firmware version ID string 386 */ 387 std::string _bmcFWVersionID; 388 389 /** 390 * @brief If sending PELs is enabled. 391 * 392 * This is usually set to false in manufacturing test. 393 */ 394 bool _sendPELsToHost = true; 395 396 /** 397 * @brief The BMC state property 398 */ 399 std::string _bmcState; 400 401 /** 402 * @brief The Chassis current power state property 403 */ 404 std::string _chassisState; 405 406 /** 407 * @brief The Chassis requested power transition property 408 */ 409 std::string _chassisTransition; 410 411 /** 412 * @brief The host state property 413 */ 414 std::string _hostState; 415 }; 416 417 /** 418 * @class DataInterface 419 * 420 * Concrete implementation of DataInterfaceBase. 421 */ 422 class DataInterface : public DataInterfaceBase 423 { 424 public: 425 DataInterface() = delete; 426 ~DataInterface() = default; 427 DataInterface(const DataInterface&) = default; 428 DataInterface& operator=(const DataInterface&) = default; 429 DataInterface(DataInterface&&) = default; 430 DataInterface& operator=(DataInterface&&) = default; 431 432 /** 433 * @brief Constructor 434 * 435 * @param[in] bus - The sdbusplus bus object 436 */ 437 explicit DataInterface(sdbusplus::bus::bus& bus); 438 439 /** 440 * @brief Finds the D-Bus service name that hosts the 441 * passed in path and interface. 442 * 443 * @param[in] objectPath - The D-Bus object path 444 * @param[in] interface - The D-Bus interface 445 */ 446 DBusService getService(const std::string& objectPath, 447 const std::string& interface) const; 448 449 /** 450 * @brief Wrapper for the 'GetAll' properties method call 451 * 452 * @param[in] service - The D-Bus service to call it on 453 * @param[in] objectPath - The D-Bus object path 454 * @param[in] interface - The interface to get the props on 455 * 456 * @return DBusPropertyMap - The property results 457 */ 458 DBusPropertyMap getAllProperties(const std::string& service, 459 const std::string& objectPath, 460 const std::string& interface) const; 461 /** 462 * @brief Wrapper for the 'Get' properties method call 463 * 464 * @param[in] service - The D-Bus service to call it on 465 * @param[in] objectPath - The D-Bus object path 466 * @param[in] interface - The interface to get the property on 467 * @param[in] property - The property name 468 * @param[out] value - Filled in with the property value. 469 */ 470 void getProperty(const std::string& service, const std::string& objectPath, 471 const std::string& interface, const std::string& property, 472 DBusValue& value) const; 473 /** 474 * @brief Returns the machine Type/Model 475 * 476 * @return string - The machine Type/Model string 477 */ 478 std::string getMachineTypeModel() const override; 479 480 /** 481 * @brief Returns the machine serial number 482 * 483 * @return string - The machine serial number 484 */ 485 std::string getMachineSerialNumber() const override; 486 487 /** 488 * @brief Returns the motherboard CCIN 489 * 490 * @return std::string The motherboard CCIN 491 */ 492 std::string getMotherboardCCIN() const override; 493 494 /** 495 * @brief Returns the system IM 496 * 497 * @return std::vector The system IM keyword in 4 byte vector 498 */ 499 std::vector<uint8_t> getSystemIMKeyword() const override; 500 501 /** 502 * @brief Get the fields from the inventory necessary for doing 503 * a callout on an inventory path. 504 * 505 * @param[in] inventoryPath - The item to get the data for 506 * @param[out] fruPartNumber - Filled in with the VINI/FN keyword 507 * @param[out] ccin - Filled in with the VINI/CC keyword 508 * @param[out] serialNumber - Filled in with the VINI/SN keyword 509 */ 510 void getHWCalloutFields(const std::string& inventoryPath, 511 std::string& fruPartNumber, std::string& ccin, 512 std::string& serialNumber) const override; 513 514 /** 515 * @brief Get the location code for an inventory item. 516 * 517 * Throws an exception if the inventory item doesn't have the 518 * location code interface. 519 * 520 * @param[in] inventoryPath - The item to get the data for 521 * 522 * @return std::string - The location code 523 */ 524 std::string 525 getLocationCode(const std::string& inventoryPath) const override; 526 527 /** 528 * @brief Get the list of system type names the system is called. 529 * 530 * @return std::vector<std::string> - The list of names 531 */ 532 std::vector<std::string> getSystemNames() const override; 533 534 /** 535 * @brief Fills in the placeholder 'Ufcs' in the passed in location 536 * code with the machine feature code and serial number, which 537 * is needed to create a valid location code. 538 * 539 * @param[in] locationCode - Location code value starting with Ufcs-, and 540 * if that isn't present it will be added first. 541 * 542 * @param[in] node - The node number the location is one. 543 * 544 * @return std::string - The expanded location code 545 */ 546 std::string expandLocationCode(const std::string& locationCode, 547 uint16_t node) const override; 548 549 /** 550 * @brief Returns the inventory path for the FRU that the location 551 * code represents. 552 * 553 * @param[in] locationCode - If an expanded location code, then the 554 * full location code. 555 * If not expanded, a location code value 556 * starting with Ufcs-, and if that isn't 557 * present it will be added first. 558 * 559 * @param[in] node - The node number the location is on. Ignored if the 560 * expanded location code is passed in. 561 * 562 * @param[in] expanded - If the location code already has the relevent 563 * VPD fields embedded in it. 564 * 565 * @return std::string - The inventory D-Bus object 566 */ 567 std::string getInventoryFromLocCode(const std::string& locationCode, 568 uint16_t node, 569 bool expanded) const override; 570 571 /** 572 * @brief Sets the Asserted property on the LED group passed in. 573 * 574 * @param[in] ledGroup - The LED group D-Bus path 575 * @param[in] value - The value to set it to 576 */ 577 void assertLEDGroup(const std::string& ledGroup, bool value) const override; 578 579 /** 580 * @brief Sets the Functional property on the OperationalStatus 581 * interface on a D-Bus object. 582 * 583 * @param[in] objectPath - The D-Bus object path 584 * @param[in] functional - The value 585 */ 586 void setFunctional(const std::string& objectPath, 587 bool functional) const override; 588 589 /** 590 * @brief Sets the critical association on the D-Bus object. 591 * 592 * @param[in] objectPath - The D-Bus object path 593 */ 594 void setCriticalAssociation(const std::string& objectPath) const override; 595 596 /** 597 * @brief Returns the manufacturing QuiesceOnError property 598 * 599 * @return bool - Manufacturing QuiesceOnError property 600 */ 601 bool getQuiesceOnError() const override; 602 603 private: 604 /** 605 * @brief Reads the BMC firmware version string and puts it into 606 * _bmcFWVersion. 607 */ 608 void readBMCFWVersion(); 609 610 /** 611 * @brief Reads the server firmware version string and puts it into 612 * _serverFWVersion. 613 */ 614 void readServerFWVersion(); 615 616 /** 617 * @brief Reads the BMC firmware version ID and puts it into 618 * _bmcFWVersionID. 619 */ 620 void readBMCFWVersionID(); 621 622 /** 623 * @brief Finds all D-Bus paths that contain any of the interfaces 624 * passed in, by using GetSubTreePaths. 625 * 626 * @param[in] interfaces - The desired interfaces 627 * 628 * @return The D-Bus paths. 629 */ 630 DBusPathList getPaths(const DBusInterfaceList& interfaces) const; 631 632 /** 633 * @brief The interfacesAdded callback used on the inventory to 634 * find the D-Bus object that has the motherboard interface. 635 * When the motherboard is found, it then adds a PropertyWatcher 636 * for the motherboard CCIN. 637 */ 638 void motherboardIfaceAdded(sdbusplus::message::message& msg); 639 640 /** 641 * @brief Adds the Ufcs- prefix to the location code passed in 642 * if necessary. 643 * 644 * Needed because the location codes that come back from the 645 * message registry and device callout JSON don't have it. 646 * 647 * @param[in] - The location code without a prefix, like P1-C1 648 * 649 * @return std::string - The location code with the prefix 650 */ 651 static std::string addLocationCodePrefix(const std::string& locationCode); 652 653 /** 654 * @brief The D-Bus property or interface watchers that have callbacks 655 * registered that will set members in this class when 656 * they change. 657 */ 658 std::vector<std::unique_ptr<DBusWatcher>> _properties; 659 660 /** 661 * @brief The sdbusplus bus object for making D-Bus calls. 662 */ 663 sdbusplus::bus::bus& _bus; 664 665 /** 666 * @brief The interfacesAdded match object used to wait for inventory 667 * interfaces to show up, so that the object with the motherboard 668 * interface can be found. After it is found, this object is 669 * deleted. 670 */ 671 std::unique_ptr<sdbusplus::bus::match_t> _inventoryIfacesAddedMatch; 672 }; 673 674 } // namespace pels 675 } // namespace openpower 676