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 Gets the system type from Entity Manager 239 * 240 * @param[in] std::string - The system type string 241 */ 242 virtual std::string getSystemType() const 243 { 244 // TODO, not implemented by entity manager yet, but adding now 245 // so it can be mocked. 246 return _systemType; 247 } 248 249 protected: 250 /** 251 * @brief Sets the host on/off state and runs any 252 * callback functions (if there was a change). 253 */ 254 void setHostUp(bool hostUp) 255 { 256 if (_hostUp != hostUp) 257 { 258 _hostUp = hostUp; 259 260 for (auto& [name, func] : _hostChangeCallbacks) 261 { 262 try 263 { 264 func(_hostUp); 265 } 266 catch (std::exception& e) 267 { 268 using namespace phosphor::logging; 269 log<level::ERR>("A host state change callback threw " 270 "an exception"); 271 } 272 } 273 } 274 } 275 276 /** 277 * @brief The machine type-model. Always kept up to date 278 */ 279 std::string _machineTypeModel; 280 281 /** 282 * @brief The machine serial number. Always kept up to date 283 */ 284 std::string _machineSerialNumber; 285 286 /** 287 * @brief The hardware management console status. Always kept 288 * up to date. 289 */ 290 bool _hmcManaged = false; 291 292 /** 293 * @brief The host up status. Always kept up to date. 294 */ 295 bool _hostUp = false; 296 297 /** 298 * @brief The map of host state change subscriber 299 * names to callback functions. 300 */ 301 std::map<std::string, HostStateChangeFunc> _hostChangeCallbacks; 302 303 /** 304 * @brief The BMC firmware version string 305 */ 306 std::string _bmcFWVersion; 307 308 /** 309 * @brief The server firmware version string 310 */ 311 std::string _serverFWVersion; 312 313 /** 314 * @brief The BMC firmware version ID string 315 */ 316 std::string _bmcFWVersionID; 317 318 /** 319 * @brief If sending PELs is enabled. 320 * 321 * This is usually set to false in manufacturing test. 322 */ 323 bool _sendPELsToHost = true; 324 325 /** 326 * @brief The BMC state property 327 */ 328 std::string _bmcState; 329 330 /** 331 * @brief The Chassis current power state property 332 */ 333 std::string _chassisState; 334 335 /** 336 * @brief The Chassis requested power transition property 337 */ 338 std::string _chassisTransition; 339 340 /** 341 * @brief The host state property 342 */ 343 std::string _hostState; 344 345 /** 346 * @brief The motherboard CCIN 347 */ 348 std::string _motherboardCCIN; 349 350 /** 351 * @brief The system type 352 */ 353 std::string _systemType; 354 }; 355 356 /** 357 * @class DataInterface 358 * 359 * Concrete implementation of DataInterfaceBase. 360 */ 361 class DataInterface : public DataInterfaceBase 362 { 363 public: 364 DataInterface() = delete; 365 ~DataInterface() = default; 366 DataInterface(const DataInterface&) = default; 367 DataInterface& operator=(const DataInterface&) = default; 368 DataInterface(DataInterface&&) = default; 369 DataInterface& operator=(DataInterface&&) = default; 370 371 /** 372 * @brief Constructor 373 * 374 * @param[in] bus - The sdbusplus bus object 375 */ 376 explicit DataInterface(sdbusplus::bus::bus& bus); 377 378 /** 379 * @brief Finds the D-Bus service name that hosts the 380 * passed in path and interface. 381 * 382 * @param[in] objectPath - The D-Bus object path 383 * @param[in] interface - The D-Bus interface 384 */ 385 DBusService getService(const std::string& objectPath, 386 const std::string& interface) const; 387 388 /** 389 * @brief Wrapper for the 'GetAll' properties method call 390 * 391 * @param[in] service - The D-Bus service to call it on 392 * @param[in] objectPath - The D-Bus object path 393 * @param[in] interface - The interface to get the props on 394 * 395 * @return DBusPropertyMap - The property results 396 */ 397 DBusPropertyMap getAllProperties(const std::string& service, 398 const std::string& objectPath, 399 const std::string& interface) const; 400 /** 401 * @brief Wrapper for the 'Get' properties method call 402 * 403 * @param[in] service - The D-Bus service to call it on 404 * @param[in] objectPath - The D-Bus object path 405 * @param[in] interface - The interface to get the property on 406 * @param[in] property - The property name 407 * @param[out] value - Filled in with the property value. 408 */ 409 void getProperty(const std::string& service, const std::string& objectPath, 410 const std::string& interface, const std::string& property, 411 DBusValue& value) const; 412 413 /** 414 * @brief Get the fields from the inventory necessary for doing 415 * a callout on an inventory path. 416 * 417 * @param[in] inventoryPath - The item to get the data for 418 * @param[out] fruPartNumber - Filled in with the VINI/FN keyword 419 * @param[out] ccin - Filled in with the VINI/CC keyword 420 * @param[out] serialNumber - Filled in with the VINI/SN keyword 421 */ 422 void getHWCalloutFields(const std::string& inventoryPath, 423 std::string& fruPartNumber, std::string& ccin, 424 std::string& serialNumber) const override; 425 426 /** 427 * @brief Get the location code for an inventory item. 428 * 429 * Throws an exception if the inventory item doesn't have the 430 * location code interface. 431 * 432 * @param[in] inventoryPath - The item to get the data for 433 * 434 * @return std::string - The location code 435 */ 436 std::string 437 getLocationCode(const std::string& inventoryPath) const override; 438 439 private: 440 /** 441 * @brief Reads the BMC firmware version string and puts it into 442 * _bmcFWVersion. 443 */ 444 void readBMCFWVersion(); 445 446 /** 447 * @brief Reads the server firmware version string and puts it into 448 * _serverFWVersion. 449 */ 450 void readServerFWVersion(); 451 452 /** 453 * @brief Reads the BMC firmware version ID and puts it into 454 * _bmcFWVersionID. 455 */ 456 void readBMCFWVersionID(); 457 458 /** 459 * @brief Reads the motherboard CCIN and puts it into _motherboardCCIN. 460 * 461 * It finds the motherboard first, possibly having to wait for it to 462 * show up. 463 */ 464 void readMotherboardCCIN(); 465 466 /** 467 * @brief Finds all D-Bus paths that contain any of the interfaces 468 * passed in, by using GetSubTreePaths. 469 * 470 * @param[in] interfaces - The desired interfaces 471 * 472 * @return The D-Bus paths. 473 */ 474 DBusPathList getPaths(const DBusInterfaceList& interfaces) const; 475 476 /** 477 * @brief The interfacesAdded callback used on the inventory to 478 * find the D-Bus object that has the motherboard interface. 479 * When the motherboard is found, it then adds a PropertyWatcher 480 * for the motherboard CCIN. 481 */ 482 void motherboardIfaceAdded(sdbusplus::message::message& msg); 483 484 /** 485 * @brief Set the motherboard CCIN from the DBus variant that 486 * contains it. 487 * 488 * @param[in] ccin - The CCIN variant, a vector<uint8_t>. 489 */ 490 void setMotherboardCCIN(const DBusValue& ccin) 491 { 492 const auto& c = std::get<std::vector<uint8_t>>(ccin); 493 _motherboardCCIN = std::string{c.begin(), c.end()}; 494 } 495 496 /** 497 * @brief The D-Bus property or interface watchers that have callbacks 498 * registered that will set members in this class when 499 * they change. 500 */ 501 std::vector<std::unique_ptr<DBusWatcher>> _properties; 502 503 /** 504 * @brief The sdbusplus bus object for making D-Bus calls. 505 */ 506 sdbusplus::bus::bus& _bus; 507 508 /** 509 * @brief The interfacesAdded match object used to wait for inventory 510 * interfaces to show up, so that the object with the motherboard 511 * interface can be found. After it is found, this object is 512 * deleted. 513 */ 514 std::unique_ptr<sdbusplus::bus::match_t> _inventoryIfacesAddedMatch; 515 }; 516 517 } // namespace pels 518 } // namespace openpower 519