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 38 { 39 return _machineTypeModel; 40 } 41 42 /** 43 * @brief Returns the machine serial number 44 * 45 * @return string - The machine serial number 46 */ 47 virtual std::string getMachineSerialNumber() const 48 { 49 return _machineSerialNumber; 50 } 51 52 /** 53 * @brief Says if the system is managed by a hardware 54 * management console. 55 * @return bool - If the system is HMC managed 56 */ 57 virtual bool isHMCManaged() const 58 { 59 return _hmcManaged; 60 } 61 62 /** 63 * @brief Says if the host is up and running 64 * 65 * @return bool - If the host is running 66 */ 67 virtual bool isHostUp() const 68 { 69 return _hostUp; 70 } 71 72 using HostStateChangeFunc = std::function<void(bool)>; 73 74 /** 75 * @brief Register a callback function that will get 76 * called on all host on/off transitions. 77 * 78 * The void(bool) function will get passed the new 79 * value of the host state. 80 * 81 * @param[in] name - The subscription name 82 * @param[in] func - The function to run 83 */ 84 void subscribeToHostStateChange(const std::string& name, 85 HostStateChangeFunc func) 86 { 87 _hostChangeCallbacks[name] = func; 88 } 89 90 /** 91 * @brief Unsubscribe from host state changes. 92 * 93 * @param[in] name - The subscription name 94 */ 95 void unsubscribeFromHostStateChange(const std::string& name) 96 { 97 _hostChangeCallbacks.erase(name); 98 } 99 100 /** 101 * @brief Returns the BMC firmware version 102 * 103 * @return std::string - The BMC version 104 */ 105 virtual std::string getBMCFWVersion() const 106 { 107 return _bmcFWVersion; 108 } 109 110 /** 111 * @brief Returns the server firmware version 112 * 113 * @return std::string - The server firmware version 114 */ 115 virtual std::string getServerFWVersion() const 116 { 117 return _serverFWVersion; 118 } 119 120 /** 121 * @brief Returns the BMC FW version ID 122 * 123 * @return std::string - The BMC FW version ID 124 */ 125 virtual std::string getBMCFWVersionID() const 126 { 127 return _bmcFWVersionID; 128 } 129 130 /** 131 * @brief Returns the process name given its PID. 132 * 133 * @param[in] pid - The PID value as a string 134 * 135 * @return std::optional<std::string> - The name, or std::nullopt 136 */ 137 std::optional<std::string> getProcessName(const std::string& pid) const 138 { 139 namespace fs = std::filesystem; 140 141 fs::path path{"/proc"}; 142 path /= fs::path{pid} / "exe"; 143 144 if (fs::exists(path)) 145 { 146 return fs::read_symlink(path); 147 } 148 149 return std::nullopt; 150 } 151 152 /** 153 * @brief Returns the 'send event logs to host' setting. 154 * 155 * @return bool - If sending PELs to the host is enabled. 156 */ 157 virtual bool getHostPELEnablement() const 158 { 159 return _sendPELsToHost; 160 } 161 162 /** 163 * @brief Returns the BMC state 164 * 165 * @return std::string - The BMC state property value 166 */ 167 virtual std::string getBMCState() const 168 { 169 return _bmcState; 170 } 171 172 /** 173 * @brief Returns the Chassis state 174 * 175 * @return std::string - The chassis state property value 176 */ 177 virtual std::string getChassisState() const 178 { 179 return _chassisState; 180 } 181 182 /** 183 * @brief Returns the chassis requested power 184 * transition value. 185 * 186 * @return std::string - The chassis transition property 187 */ 188 virtual std::string getChassisTransition() const 189 { 190 return _chassisTransition; 191 } 192 193 /** 194 * @brief Returns the Host state 195 * 196 * @return std::string - The Host state property value 197 */ 198 virtual std::string getHostState() const 199 { 200 return _hostState; 201 } 202 203 /** 204 * @brief Returns the motherboard CCIN 205 * 206 * @return std::string The motherboard CCIN 207 */ 208 virtual std::string getMotherboardCCIN() const 209 { 210 return _motherboardCCIN; 211 } 212 213 /** 214 * @brief Get the fields from the inventory necessary for doing 215 * a callout on an inventory path. 216 * 217 * @param[in] inventoryPath - The item to get the data for 218 * @param[out] fruPartNumber - Filled in with the VINI/FN keyword 219 * @param[out] ccin - Filled in with the VINI/CC keyword 220 * @param[out] serialNumber - Filled in with the VINI/SN keyword 221 */ 222 virtual void getHWCalloutFields(const std::string& inventoryPath, 223 std::string& fruPartNumber, 224 std::string& ccin, 225 std::string& serialNumber) const = 0; 226 227 /** 228 * @brief Get the location code for an inventory item. 229 * 230 * @param[in] inventoryPath - The item to get the data for 231 * 232 * @return std::string - The location code 233 */ 234 virtual std::string 235 getLocationCode(const std::string& inventoryPath) const = 0; 236 237 /** 238 * @brief Get the list of system type names the system is called. 239 * 240 * @return std::vector<std::string> - The list of names 241 */ 242 virtual std::vector<std::string> getSystemNames() const = 0; 243 244 /** 245 * @brief Fills in the placeholder 'Ufcs' in the passed in location 246 * code with the machine feature code and serial number, which 247 * is needed to create a valid location code. 248 * 249 * @param[in] locationCode - Location code value starting with Ufcs-, and 250 * if that isn't present it will be added first. 251 * 252 * @param[in] node - The node number the location is on. 253 * 254 * @return std::string - The expanded location code 255 */ 256 virtual std::string expandLocationCode(const std::string& locationCode, 257 uint16_t node) const = 0; 258 259 /** 260 * @brief Returns the inventory path for the FRU that the location 261 * code represents. 262 * 263 * @param[in] locationCode - If an expanded location code, then the 264 * full location code. 265 * If not expanded, a location code value 266 * starting with Ufcs-, and if that isn't 267 * present it will be added first. 268 * 269 * @param[in] node - The node number the location is on. Ignored if the 270 * expanded location code is passed in. 271 * 272 * @param[in] expanded - If the location code already has the relevent 273 * VPD fields embedded in it. 274 * 275 * @return std::string - The inventory D-Bus object 276 */ 277 virtual std::string getInventoryFromLocCode(const std::string& LocationCode, 278 uint16_t node, 279 bool expanded) const = 0; 280 281 /** 282 * @brief Returns the fault LED group D-Bus path for the inventory 283 * D-Bus path passed in. 284 * 285 * @param[in] inventoryPath - The inventory D-Bus path 286 * 287 * @return std::string - The fault LED group D-Bus path 288 */ 289 virtual std::string 290 getFaultLEDGroup(const std::string& inventoryPath) const = 0; 291 292 /** 293 * @brief Sets the Asserted property on the LED group passed in. 294 * 295 * @param[in] ledGroup - The LED group D-Bus path 296 * @param[in] value - The value to set it to 297 */ 298 virtual void assertLEDGroup(const std::string& ledGroup, 299 bool value) const = 0; 300 301 protected: 302 /** 303 * @brief Sets the host on/off state and runs any 304 * callback functions (if there was a change). 305 */ 306 void setHostUp(bool hostUp) 307 { 308 if (_hostUp != hostUp) 309 { 310 _hostUp = hostUp; 311 312 for (auto& [name, func] : _hostChangeCallbacks) 313 { 314 try 315 { 316 func(_hostUp); 317 } 318 catch (std::exception& e) 319 { 320 using namespace phosphor::logging; 321 log<level::ERR>("A host state change callback threw " 322 "an exception"); 323 } 324 } 325 } 326 } 327 328 /** 329 * @brief The machine type-model. Always kept up to date 330 */ 331 std::string _machineTypeModel; 332 333 /** 334 * @brief The machine serial number. Always kept up to date 335 */ 336 std::string _machineSerialNumber; 337 338 /** 339 * @brief The hardware management console status. Always kept 340 * up to date. 341 */ 342 bool _hmcManaged = false; 343 344 /** 345 * @brief The host up status. Always kept up to date. 346 */ 347 bool _hostUp = false; 348 349 /** 350 * @brief The map of host state change subscriber 351 * names to callback functions. 352 */ 353 std::map<std::string, HostStateChangeFunc> _hostChangeCallbacks; 354 355 /** 356 * @brief The BMC firmware version string 357 */ 358 std::string _bmcFWVersion; 359 360 /** 361 * @brief The server firmware version string 362 */ 363 std::string _serverFWVersion; 364 365 /** 366 * @brief The BMC firmware version ID string 367 */ 368 std::string _bmcFWVersionID; 369 370 /** 371 * @brief If sending PELs is enabled. 372 * 373 * This is usually set to false in manufacturing test. 374 */ 375 bool _sendPELsToHost = true; 376 377 /** 378 * @brief The BMC state property 379 */ 380 std::string _bmcState; 381 382 /** 383 * @brief The Chassis current power state property 384 */ 385 std::string _chassisState; 386 387 /** 388 * @brief The Chassis requested power transition property 389 */ 390 std::string _chassisTransition; 391 392 /** 393 * @brief The host state property 394 */ 395 std::string _hostState; 396 397 /** 398 * @brief The motherboard CCIN 399 */ 400 std::string _motherboardCCIN; 401 }; 402 403 /** 404 * @class DataInterface 405 * 406 * Concrete implementation of DataInterfaceBase. 407 */ 408 class DataInterface : public DataInterfaceBase 409 { 410 public: 411 DataInterface() = delete; 412 ~DataInterface() = default; 413 DataInterface(const DataInterface&) = default; 414 DataInterface& operator=(const DataInterface&) = default; 415 DataInterface(DataInterface&&) = default; 416 DataInterface& operator=(DataInterface&&) = default; 417 418 /** 419 * @brief Constructor 420 * 421 * @param[in] bus - The sdbusplus bus object 422 */ 423 explicit DataInterface(sdbusplus::bus::bus& bus); 424 425 /** 426 * @brief Finds the D-Bus service name that hosts the 427 * passed in path and interface. 428 * 429 * @param[in] objectPath - The D-Bus object path 430 * @param[in] interface - The D-Bus interface 431 */ 432 DBusService getService(const std::string& objectPath, 433 const std::string& interface) const; 434 435 /** 436 * @brief Wrapper for the 'GetAll' properties method call 437 * 438 * @param[in] service - The D-Bus service to call it on 439 * @param[in] objectPath - The D-Bus object path 440 * @param[in] interface - The interface to get the props on 441 * 442 * @return DBusPropertyMap - The property results 443 */ 444 DBusPropertyMap getAllProperties(const std::string& service, 445 const std::string& objectPath, 446 const std::string& interface) const; 447 /** 448 * @brief Wrapper for the 'Get' properties method call 449 * 450 * @param[in] service - The D-Bus service to call it on 451 * @param[in] objectPath - The D-Bus object path 452 * @param[in] interface - The interface to get the property on 453 * @param[in] property - The property name 454 * @param[out] value - Filled in with the property value. 455 */ 456 void getProperty(const std::string& service, const std::string& objectPath, 457 const std::string& interface, const std::string& property, 458 DBusValue& value) const; 459 460 /** 461 * @brief Get the fields from the inventory necessary for doing 462 * a callout on an inventory path. 463 * 464 * @param[in] inventoryPath - The item to get the data for 465 * @param[out] fruPartNumber - Filled in with the VINI/FN keyword 466 * @param[out] ccin - Filled in with the VINI/CC keyword 467 * @param[out] serialNumber - Filled in with the VINI/SN keyword 468 */ 469 void getHWCalloutFields(const std::string& inventoryPath, 470 std::string& fruPartNumber, std::string& ccin, 471 std::string& serialNumber) const override; 472 473 /** 474 * @brief Get the location code for an inventory item. 475 * 476 * Throws an exception if the inventory item doesn't have the 477 * location code interface. 478 * 479 * @param[in] inventoryPath - The item to get the data for 480 * 481 * @return std::string - The location code 482 */ 483 std::string 484 getLocationCode(const std::string& inventoryPath) const override; 485 486 /** 487 * @brief Get the list of system type names the system is called. 488 * 489 * @return std::vector<std::string> - The list of names 490 */ 491 std::vector<std::string> getSystemNames() const override; 492 493 /** 494 * @brief Fills in the placeholder 'Ufcs' in the passed in location 495 * code with the machine feature code and serial number, which 496 * is needed to create a valid location code. 497 * 498 * @param[in] locationCode - Location code value starting with Ufcs-, and 499 * if that isn't present it will be added first. 500 * 501 * @param[in] node - The node number the location is one. 502 * 503 * @return std::string - The expanded location code 504 */ 505 std::string expandLocationCode(const std::string& locationCode, 506 uint16_t node) const override; 507 508 /** 509 * @brief Returns the inventory path for the FRU that the location 510 * code represents. 511 * 512 * @param[in] locationCode - If an expanded location code, then the 513 * full location code. 514 * If not expanded, a location code value 515 * starting with Ufcs-, and if that isn't 516 * present it will be added first. 517 * 518 * @param[in] node - The node number the location is on. Ignored if the 519 * expanded location code is passed in. 520 * 521 * @param[in] expanded - If the location code already has the relevent 522 * VPD fields embedded in it. 523 * 524 * @return std::string - The inventory D-Bus object 525 */ 526 std::string getInventoryFromLocCode(const std::string& locationCode, 527 uint16_t node, 528 bool expanded) const override; 529 530 /** 531 * @brief Returns the fault LED group D-Bus path for the inventory 532 * D-Bus path passed in. 533 * 534 * @param[in] inventoryPath - The inventory D-Bus path 535 * 536 * @return std::string - The fault LED group D-Bus path 537 */ 538 std::string 539 getFaultLEDGroup(const std::string& inventoryPath) const override; 540 541 /** 542 * @brief Sets the Asserted property on the LED group passed in. 543 * 544 * @param[in] ledGroup - The LED group D-Bus path 545 * @param[in] value - The value to set it to 546 */ 547 void assertLEDGroup(const std::string& ledGroup, bool value) const override; 548 549 private: 550 /** 551 * @brief Reads the BMC firmware version string and puts it into 552 * _bmcFWVersion. 553 */ 554 void readBMCFWVersion(); 555 556 /** 557 * @brief Reads the server firmware version string and puts it into 558 * _serverFWVersion. 559 */ 560 void readServerFWVersion(); 561 562 /** 563 * @brief Reads the BMC firmware version ID and puts it into 564 * _bmcFWVersionID. 565 */ 566 void readBMCFWVersionID(); 567 568 /** 569 * @brief Reads the motherboard CCIN and puts it into _motherboardCCIN. 570 * 571 * It finds the motherboard first, possibly having to wait for it to 572 * show up. 573 */ 574 void readMotherboardCCIN(); 575 576 /** 577 * @brief Finds all D-Bus paths that contain any of the interfaces 578 * passed in, by using GetSubTreePaths. 579 * 580 * @param[in] interfaces - The desired interfaces 581 * 582 * @return The D-Bus paths. 583 */ 584 DBusPathList getPaths(const DBusInterfaceList& interfaces) const; 585 586 /** 587 * @brief The interfacesAdded callback used on the inventory to 588 * find the D-Bus object that has the motherboard interface. 589 * When the motherboard is found, it then adds a PropertyWatcher 590 * for the motherboard CCIN. 591 */ 592 void motherboardIfaceAdded(sdbusplus::message::message& msg); 593 594 /** 595 * @brief Set the motherboard CCIN from the DBus variant that 596 * contains it. 597 * 598 * @param[in] ccin - The CCIN variant, a vector<uint8_t>. 599 */ 600 void setMotherboardCCIN(const DBusValue& ccin) 601 { 602 const auto& c = std::get<std::vector<uint8_t>>(ccin); 603 _motherboardCCIN = std::string{c.begin(), c.end()}; 604 } 605 606 /** 607 * @brief Adds the Ufcs- prefix to the location code passed in 608 * if necessary. 609 * 610 * Needed because the location codes that come back from the 611 * message registry and device callout JSON don't have it. 612 * 613 * @param[in] - The location code without a prefix, like P1-C1 614 * 615 * @return std::string - The location code with the prefix 616 */ 617 static std::string addLocationCodePrefix(const std::string& locationCode); 618 619 /** 620 * @brief The D-Bus property or interface watchers that have callbacks 621 * registered that will set members in this class when 622 * they change. 623 */ 624 std::vector<std::unique_ptr<DBusWatcher>> _properties; 625 626 /** 627 * @brief The sdbusplus bus object for making D-Bus calls. 628 */ 629 sdbusplus::bus::bus& _bus; 630 631 /** 632 * @brief The interfacesAdded match object used to wait for inventory 633 * interfaces to show up, so that the object with the motherboard 634 * interface can be found. After it is found, this object is 635 * deleted. 636 */ 637 std::unique_ptr<sdbusplus::bus::match_t> _inventoryIfacesAddedMatch; 638 }; 639 640 } // namespace pels 641 } // namespace openpower 642