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