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