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