1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 18 #include "bmcweb_config.h" 19 20 #include "app.hpp" 21 #include "dbus_utility.hpp" 22 #include "health.hpp" 23 #include "query.hpp" 24 #include "registries/privilege_registry.hpp" 25 #include "utils/collection.hpp" 26 #include "utils/dbus_utils.hpp" 27 #include "utils/hex_utils.hpp" 28 #include "utils/json_utils.hpp" 29 30 #include <boost/system/error_code.hpp> 31 #include <boost/url/format.hpp> 32 #include <nlohmann/json.hpp> 33 #include <sdbusplus/asio/property.hpp> 34 #include <sdbusplus/unpack_properties.hpp> 35 36 #include <array> 37 #include <string_view> 38 39 namespace redfish 40 { 41 42 inline std::string translateMemoryTypeToRedfish(const std::string& memoryType) 43 { 44 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR") 45 { 46 return "DDR"; 47 } 48 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2") 49 { 50 return "DDR2"; 51 } 52 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR3") 53 { 54 return "DDR3"; 55 } 56 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4") 57 { 58 return "DDR4"; 59 } 60 if (memoryType == 61 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4E_SDRAM") 62 { 63 return "DDR4E_SDRAM"; 64 } 65 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR5") 66 { 67 return "DDR5"; 68 } 69 if (memoryType == 70 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR4_SDRAM") 71 { 72 return "LPDDR4_SDRAM"; 73 } 74 if (memoryType == 75 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR3_SDRAM") 76 { 77 return "LPDDR3_SDRAM"; 78 } 79 if (memoryType == 80 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM") 81 { 82 return "DDR2_SDRAM_FB_DIMM"; 83 } 84 if (memoryType == 85 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM_PROB") 86 { 87 return "DDR2_SDRAM_FB_DIMM_PROBE"; 88 } 89 if (memoryType == 90 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR_SGRAM") 91 { 92 return "DDR_SGRAM"; 93 } 94 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.ROM") 95 { 96 return "ROM"; 97 } 98 if (memoryType == 99 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.SDRAM") 100 { 101 return "SDRAM"; 102 } 103 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.EDO") 104 { 105 return "EDO"; 106 } 107 if (memoryType == 108 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.FastPageMode") 109 { 110 return "FastPageMode"; 111 } 112 if (memoryType == 113 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.PipelinedNibble") 114 { 115 return "PipelinedNibble"; 116 } 117 if (memoryType == 118 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.Logical") 119 { 120 return "Logical"; 121 } 122 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM") 123 { 124 return "HBM"; 125 } 126 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM2") 127 { 128 return "HBM2"; 129 } 130 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM3") 131 { 132 return "HBM3"; 133 } 134 // This is values like Other or Unknown 135 // Also D-Bus values: 136 // DRAM 137 // EDRAM 138 // VRAM 139 // SRAM 140 // RAM 141 // FLASH 142 // EEPROM 143 // FEPROM 144 // EPROM 145 // CDRAM 146 // ThreeDRAM 147 // RDRAM 148 // FBD2 149 // LPDDR_SDRAM 150 // LPDDR2_SDRAM 151 // LPDDR5_SDRAM 152 return ""; 153 } 154 155 inline void dimmPropToHex(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 156 const char* key, const uint16_t* value, 157 const nlohmann::json::json_pointer& jsonPtr) 158 { 159 if (value == nullptr) 160 { 161 return; 162 } 163 asyncResp->res.jsonValue[jsonPtr][key] = "0x" + intToHexString(*value, 4); 164 } 165 166 inline void getPersistentMemoryProperties( 167 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 168 const dbus::utility::DBusPropertiesMap& properties, 169 const nlohmann::json::json_pointer& jsonPtr) 170 { 171 const uint16_t* moduleManufacturerID = nullptr; 172 const uint16_t* moduleProductID = nullptr; 173 const uint16_t* subsystemVendorID = nullptr; 174 const uint16_t* subsystemDeviceID = nullptr; 175 const uint64_t* volatileRegionSizeLimitInKiB = nullptr; 176 const uint64_t* pmRegionSizeLimitInKiB = nullptr; 177 const uint64_t* volatileSizeInKiB = nullptr; 178 const uint64_t* pmSizeInKiB = nullptr; 179 const uint64_t* cacheSizeInKB = nullptr; 180 const uint64_t* voltaileRegionMaxSizeInKib = nullptr; 181 const uint64_t* pmRegionMaxSizeInKiB = nullptr; 182 const uint64_t* allocationIncrementInKiB = nullptr; 183 const uint64_t* allocationAlignmentInKiB = nullptr; 184 const uint64_t* volatileRegionNumberLimit = nullptr; 185 const uint64_t* pmRegionNumberLimit = nullptr; 186 const uint64_t* spareDeviceCount = nullptr; 187 const bool* isSpareDeviceInUse = nullptr; 188 const bool* isRankSpareEnabled = nullptr; 189 const std::vector<uint32_t>* maxAveragePowerLimitmW = nullptr; 190 const bool* configurationLocked = nullptr; 191 const std::string* allowedMemoryModes = nullptr; 192 const std::string* memoryMedia = nullptr; 193 const bool* configurationLockCapable = nullptr; 194 const bool* dataLockCapable = nullptr; 195 const bool* passphraseCapable = nullptr; 196 const uint64_t* maxPassphraseCount = nullptr; 197 const uint64_t* passphraseLockLimit = nullptr; 198 199 const bool success = sdbusplus::unpackPropertiesNoThrow( 200 dbus_utils::UnpackErrorPrinter(), properties, "ModuleManufacturerID", 201 moduleManufacturerID, "ModuleProductID", moduleProductID, 202 "SubsystemVendorID", subsystemVendorID, "SubsystemDeviceID", 203 subsystemDeviceID, "VolatileRegionSizeLimitInKiB", 204 volatileRegionSizeLimitInKiB, "PmRegionSizeLimitInKiB", 205 pmRegionSizeLimitInKiB, "VolatileSizeInKiB", volatileSizeInKiB, 206 "PmSizeInKiB", pmSizeInKiB, "CacheSizeInKB", cacheSizeInKB, 207 "VoltaileRegionMaxSizeInKib", voltaileRegionMaxSizeInKib, 208 "PmRegionMaxSizeInKiB", pmRegionMaxSizeInKiB, 209 "AllocationIncrementInKiB", allocationIncrementInKiB, 210 "AllocationAlignmentInKiB", allocationAlignmentInKiB, 211 "VolatileRegionNumberLimit", volatileRegionNumberLimit, 212 "PmRegionNumberLimit", pmRegionNumberLimit, "SpareDeviceCount", 213 spareDeviceCount, "IsSpareDeviceInUse", isSpareDeviceInUse, 214 "IsRankSpareEnabled", isRankSpareEnabled, "MaxAveragePowerLimitmW", 215 maxAveragePowerLimitmW, "ConfigurationLocked", configurationLocked, 216 "AllowedMemoryModes", allowedMemoryModes, "MemoryMedia", memoryMedia, 217 "ConfigurationLockCapable", configurationLockCapable, "DataLockCapable", 218 dataLockCapable, "PassphraseCapable", passphraseCapable, 219 "MaxPassphraseCount", maxPassphraseCount, "PassphraseLockLimit", 220 passphraseLockLimit); 221 222 if (!success) 223 { 224 messages::internalError(asyncResp->res); 225 return; 226 } 227 228 dimmPropToHex(asyncResp, "ModuleManufacturerID", moduleManufacturerID, 229 jsonPtr); 230 dimmPropToHex(asyncResp, "ModuleProductID", moduleProductID, jsonPtr); 231 dimmPropToHex(asyncResp, "MemorySubsystemControllerManufacturerID", 232 subsystemVendorID, jsonPtr); 233 dimmPropToHex(asyncResp, "MemorySubsystemControllerProductID", 234 subsystemDeviceID, jsonPtr); 235 236 if (volatileRegionSizeLimitInKiB != nullptr) 237 { 238 asyncResp->res.jsonValue[jsonPtr]["VolatileRegionSizeLimitMiB"] = 239 (*volatileRegionSizeLimitInKiB) >> 10; 240 } 241 242 if (pmRegionSizeLimitInKiB != nullptr) 243 { 244 asyncResp->res.jsonValue[jsonPtr]["PersistentRegionSizeLimitMiB"] = 245 (*pmRegionSizeLimitInKiB) >> 10; 246 } 247 248 if (volatileSizeInKiB != nullptr) 249 { 250 asyncResp->res.jsonValue[jsonPtr]["VolatileSizeMiB"] = 251 (*volatileSizeInKiB) >> 10; 252 } 253 254 if (pmSizeInKiB != nullptr) 255 { 256 asyncResp->res.jsonValue[jsonPtr]["NonVolatileSizeMiB"] = 257 (*pmSizeInKiB) >> 10; 258 } 259 260 if (cacheSizeInKB != nullptr) 261 { 262 asyncResp->res.jsonValue[jsonPtr]["CacheSizeMiB"] = 263 (*cacheSizeInKB >> 10); 264 } 265 266 if (voltaileRegionMaxSizeInKib != nullptr) 267 { 268 asyncResp->res.jsonValue[jsonPtr]["VolatileRegionSizeMaxMiB"] = 269 (*voltaileRegionMaxSizeInKib) >> 10; 270 } 271 272 if (pmRegionMaxSizeInKiB != nullptr) 273 { 274 asyncResp->res.jsonValue[jsonPtr]["PersistentRegionSizeMaxMiB"] = 275 (*pmRegionMaxSizeInKiB) >> 10; 276 } 277 278 if (allocationIncrementInKiB != nullptr) 279 { 280 asyncResp->res.jsonValue[jsonPtr]["AllocationIncrementMiB"] = 281 (*allocationIncrementInKiB) >> 10; 282 } 283 284 if (allocationAlignmentInKiB != nullptr) 285 { 286 asyncResp->res.jsonValue[jsonPtr]["AllocationAlignmentMiB"] = 287 (*allocationAlignmentInKiB) >> 10; 288 } 289 290 if (volatileRegionNumberLimit != nullptr) 291 { 292 asyncResp->res.jsonValue[jsonPtr]["VolatileRegionNumberLimit"] = 293 *volatileRegionNumberLimit; 294 } 295 296 if (pmRegionNumberLimit != nullptr) 297 { 298 asyncResp->res.jsonValue[jsonPtr]["PersistentRegionNumberLimit"] = 299 *pmRegionNumberLimit; 300 } 301 302 if (spareDeviceCount != nullptr) 303 { 304 asyncResp->res.jsonValue[jsonPtr]["SpareDeviceCount"] = 305 *spareDeviceCount; 306 } 307 308 if (isSpareDeviceInUse != nullptr) 309 { 310 asyncResp->res.jsonValue[jsonPtr]["IsSpareDeviceEnabled"] = 311 *isSpareDeviceInUse; 312 } 313 314 if (isRankSpareEnabled != nullptr) 315 { 316 asyncResp->res.jsonValue[jsonPtr]["IsRankSpareEnabled"] = 317 *isRankSpareEnabled; 318 } 319 320 if (maxAveragePowerLimitmW != nullptr) 321 { 322 asyncResp->res.jsonValue[jsonPtr]["MaxTDPMilliWatts"] = 323 *maxAveragePowerLimitmW; 324 } 325 326 if (configurationLocked != nullptr) 327 { 328 asyncResp->res.jsonValue[jsonPtr]["ConfigurationLocked"] = 329 *configurationLocked; 330 } 331 332 if (allowedMemoryModes != nullptr) 333 { 334 constexpr const std::array<const char*, 3> values{"Volatile", "PMEM", 335 "Block"}; 336 337 for (const char* v : values) 338 { 339 if (allowedMemoryModes->ends_with(v)) 340 { 341 asyncResp->res.jsonValue[jsonPtr]["OperatingMemoryModes"] 342 .push_back(v); 343 break; 344 } 345 } 346 } 347 348 if (memoryMedia != nullptr) 349 { 350 constexpr const std::array<const char*, 3> values{"DRAM", "NAND", 351 "Intel3DXPoint"}; 352 353 for (const char* v : values) 354 { 355 if (memoryMedia->ends_with(v)) 356 { 357 asyncResp->res.jsonValue[jsonPtr]["MemoryMedia"].push_back(v); 358 break; 359 } 360 } 361 } 362 363 if (configurationLockCapable != nullptr) 364 { 365 asyncResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 366 ["ConfigurationLockCapable"] = 367 *configurationLockCapable; 368 } 369 370 if (dataLockCapable != nullptr) 371 { 372 asyncResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 373 ["DataLockCapable"] = *dataLockCapable; 374 } 375 376 if (passphraseCapable != nullptr) 377 { 378 asyncResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 379 ["PassphraseCapable"] = *passphraseCapable; 380 } 381 382 if (maxPassphraseCount != nullptr) 383 { 384 asyncResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 385 ["MaxPassphraseCount"] = *maxPassphraseCount; 386 } 387 388 if (passphraseLockLimit != nullptr) 389 { 390 asyncResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 391 ["PassphraseLockLimit"] = *passphraseLockLimit; 392 } 393 } 394 395 inline void 396 assembleDimmProperties(std::string_view dimmId, 397 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 398 const dbus::utility::DBusPropertiesMap& properties, 399 const nlohmann::json::json_pointer& jsonPtr) 400 { 401 asyncResp->res.jsonValue[jsonPtr]["Id"] = dimmId; 402 asyncResp->res.jsonValue[jsonPtr]["Name"] = "DIMM Slot"; 403 asyncResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Enabled"; 404 asyncResp->res.jsonValue[jsonPtr]["Status"]["Health"] = "OK"; 405 406 const uint16_t* memoryDataWidth = nullptr; 407 const size_t* memorySizeInKB = nullptr; 408 const std::string* partNumber = nullptr; 409 const std::string* serialNumber = nullptr; 410 const std::string* manufacturer = nullptr; 411 const uint16_t* revisionCode = nullptr; 412 const bool* present = nullptr; 413 const uint16_t* memoryTotalWidth = nullptr; 414 const std::string* ecc = nullptr; 415 const std::string* formFactor = nullptr; 416 const std::vector<uint16_t>* allowedSpeedsMT = nullptr; 417 const uint8_t* memoryAttributes = nullptr; 418 const uint16_t* memoryConfiguredSpeedInMhz = nullptr; 419 const std::string* memoryType = nullptr; 420 const std::uint8_t* channel = nullptr; 421 const std::uint8_t* memoryController = nullptr; 422 const std::uint8_t* slot = nullptr; 423 const std::uint8_t* socket = nullptr; 424 const std::string* sparePartNumber = nullptr; 425 const std::string* model = nullptr; 426 const std::string* locationCode = nullptr; 427 428 const bool success = sdbusplus::unpackPropertiesNoThrow( 429 dbus_utils::UnpackErrorPrinter(), properties, "MemoryDataWidth", 430 memoryDataWidth, "MemorySizeInKB", memorySizeInKB, "PartNumber", 431 partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 432 "RevisionCode", revisionCode, "Present", present, "MemoryTotalWidth", 433 memoryTotalWidth, "ECC", ecc, "FormFactor", formFactor, 434 "AllowedSpeedsMT", allowedSpeedsMT, "MemoryAttributes", 435 memoryAttributes, "MemoryConfiguredSpeedInMhz", 436 memoryConfiguredSpeedInMhz, "MemoryType", memoryType, "Channel", 437 channel, "MemoryController", memoryController, "Slot", slot, "Socket", 438 socket, "SparePartNumber", sparePartNumber, "Model", model, 439 "LocationCode", locationCode); 440 441 if (!success) 442 { 443 messages::internalError(asyncResp->res); 444 return; 445 } 446 447 if (memoryDataWidth != nullptr) 448 { 449 asyncResp->res.jsonValue[jsonPtr]["DataWidthBits"] = *memoryDataWidth; 450 } 451 452 if (memorySizeInKB != nullptr) 453 { 454 asyncResp->res.jsonValue[jsonPtr]["CapacityMiB"] = 455 (*memorySizeInKB >> 10); 456 } 457 458 if (partNumber != nullptr) 459 { 460 asyncResp->res.jsonValue[jsonPtr]["PartNumber"] = *partNumber; 461 } 462 463 if (serialNumber != nullptr) 464 { 465 asyncResp->res.jsonValue[jsonPtr]["SerialNumber"] = *serialNumber; 466 } 467 468 if (manufacturer != nullptr) 469 { 470 asyncResp->res.jsonValue[jsonPtr]["Manufacturer"] = *manufacturer; 471 } 472 473 if (revisionCode != nullptr) 474 { 475 asyncResp->res.jsonValue[jsonPtr]["FirmwareRevision"] = 476 std::to_string(*revisionCode); 477 } 478 479 if (present != nullptr && !*present) 480 { 481 asyncResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Absent"; 482 } 483 484 if (memoryTotalWidth != nullptr) 485 { 486 asyncResp->res.jsonValue[jsonPtr]["BusWidthBits"] = *memoryTotalWidth; 487 } 488 489 if (ecc != nullptr) 490 { 491 constexpr const std::array<const char*, 4> values{ 492 "NoECC", "SingleBitECC", "MultiBitECC", "AddressParity"}; 493 494 for (const char* v : values) 495 { 496 if (ecc->ends_with(v)) 497 { 498 asyncResp->res.jsonValue[jsonPtr]["ErrorCorrection"] = v; 499 break; 500 } 501 } 502 } 503 504 if (formFactor != nullptr) 505 { 506 constexpr const std::array<const char*, 11> values{ 507 "RDIMM", "UDIMM", "SO_DIMM", "LRDIMM", 508 "Mini_RDIMM", "Mini_UDIMM", "SO_RDIMM_72b", "SO_UDIMM_72b", 509 "SO_DIMM_16b", "SO_DIMM_32b", "Die"}; 510 511 for (const char* v : values) 512 { 513 if (formFactor->ends_with(v)) 514 { 515 asyncResp->res.jsonValue[jsonPtr]["BaseModuleType"] = v; 516 break; 517 } 518 } 519 } 520 521 if (allowedSpeedsMT != nullptr) 522 { 523 nlohmann::json& jValue = 524 asyncResp->res.jsonValue[jsonPtr]["AllowedSpeedsMHz"]; 525 jValue = nlohmann::json::array(); 526 for (uint16_t subVal : *allowedSpeedsMT) 527 { 528 jValue.push_back(subVal); 529 } 530 } 531 532 if (memoryAttributes != nullptr) 533 { 534 asyncResp->res.jsonValue[jsonPtr]["RankCount"] = 535 static_cast<uint64_t>(*memoryAttributes); 536 } 537 538 if (memoryConfiguredSpeedInMhz != nullptr) 539 { 540 asyncResp->res.jsonValue[jsonPtr]["OperatingSpeedMhz"] = 541 *memoryConfiguredSpeedInMhz; 542 } 543 544 if (memoryType != nullptr) 545 { 546 std::string memoryDeviceType = 547 translateMemoryTypeToRedfish(*memoryType); 548 // Values like "Unknown" or "Other" will return empty 549 // so just leave off 550 if (!memoryDeviceType.empty()) 551 { 552 asyncResp->res.jsonValue[jsonPtr]["MemoryDeviceType"] = 553 memoryDeviceType; 554 } 555 if (memoryType->find("DDR") != std::string::npos) 556 { 557 asyncResp->res.jsonValue[jsonPtr]["MemoryType"] = "DRAM"; 558 } 559 else if (memoryType->ends_with("Logical")) 560 { 561 asyncResp->res.jsonValue[jsonPtr]["MemoryType"] = "IntelOptane"; 562 } 563 } 564 565 if (channel != nullptr) 566 { 567 asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Channel"] = 568 *channel; 569 } 570 571 if (memoryController != nullptr) 572 { 573 asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"] 574 ["MemoryController"] = *memoryController; 575 } 576 577 if (slot != nullptr) 578 { 579 asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Slot"] = *slot; 580 } 581 582 if (socket != nullptr) 583 { 584 asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Socket"] = *socket; 585 } 586 587 if (sparePartNumber != nullptr) 588 { 589 asyncResp->res.jsonValue[jsonPtr]["SparePartNumber"] = *sparePartNumber; 590 } 591 592 if (model != nullptr) 593 { 594 asyncResp->res.jsonValue[jsonPtr]["Model"] = *model; 595 } 596 597 if (locationCode != nullptr) 598 { 599 asyncResp->res.jsonValue[jsonPtr]["Location"]["PartLocation"] 600 ["ServiceLabel"] = *locationCode; 601 } 602 603 getPersistentMemoryProperties(asyncResp, properties, jsonPtr); 604 } 605 606 inline void getDimmDataByService(std::shared_ptr<bmcweb::AsyncResp> asyncResp, 607 const std::string& dimmId, 608 const std::string& service, 609 const std::string& objPath) 610 { 611 if constexpr (bmcwebEnableHealthPopulate) 612 { 613 auto health = std::make_shared<HealthPopulate>(asyncResp); 614 health->selfPath = objPath; 615 health->populate(); 616 } 617 618 BMCWEB_LOG_DEBUG << "Get available system components."; 619 sdbusplus::asio::getAllProperties( 620 *crow::connections::systemBus, service, objPath, "", 621 [dimmId, asyncResp{std::move(asyncResp)}]( 622 const boost::system::error_code& ec, 623 const dbus::utility::DBusPropertiesMap& properties) { 624 if (ec) 625 { 626 BMCWEB_LOG_DEBUG << "DBUS response error"; 627 messages::internalError(asyncResp->res); 628 return; 629 } 630 assembleDimmProperties(dimmId, asyncResp, properties, ""_json_pointer); 631 }); 632 } 633 634 inline void assembleDimmPartitionData( 635 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 636 const dbus::utility::DBusPropertiesMap& properties, 637 const nlohmann::json::json_pointer& regionPtr) 638 { 639 const std::string* memoryClassification = nullptr; 640 const uint64_t* offsetInKiB = nullptr; 641 const std::string* partitionId = nullptr; 642 const bool* passphraseState = nullptr; 643 const uint64_t* sizeInKiB = nullptr; 644 645 const bool success = sdbusplus::unpackPropertiesNoThrow( 646 dbus_utils::UnpackErrorPrinter(), properties, "MemoryClassification", 647 memoryClassification, "OffsetInKiB", offsetInKiB, "PartitionId", 648 partitionId, "PassphraseState", passphraseState, "SizeInKiB", 649 sizeInKiB); 650 651 if (!success) 652 { 653 messages::internalError(asyncResp->res); 654 return; 655 } 656 657 nlohmann::json::object_t partition; 658 659 if (memoryClassification != nullptr) 660 { 661 partition["MemoryClassification"] = *memoryClassification; 662 } 663 664 if (offsetInKiB != nullptr) 665 { 666 partition["OffsetMiB"] = (*offsetInKiB >> 10); 667 } 668 669 if (partitionId != nullptr) 670 { 671 partition["RegionId"] = *partitionId; 672 } 673 674 if (passphraseState != nullptr) 675 { 676 partition["PassphraseEnabled"] = *passphraseState; 677 } 678 679 if (sizeInKiB != nullptr) 680 { 681 partition["SizeMiB"] = (*sizeInKiB >> 10); 682 } 683 684 asyncResp->res.jsonValue[regionPtr].emplace_back(std::move(partition)); 685 } 686 687 inline void getDimmPartitionData(std::shared_ptr<bmcweb::AsyncResp> asyncResp, 688 const std::string& service, 689 const std::string& path) 690 { 691 sdbusplus::asio::getAllProperties( 692 *crow::connections::systemBus, service, path, 693 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition", 694 [asyncResp{std::move(asyncResp)}]( 695 const boost::system::error_code& ec, 696 const dbus::utility::DBusPropertiesMap& properties) { 697 if (ec) 698 { 699 BMCWEB_LOG_DEBUG << "DBUS response error"; 700 messages::internalError(asyncResp->res); 701 702 return; 703 } 704 nlohmann::json::json_pointer regionPtr = "/Regions"_json_pointer; 705 assembleDimmPartitionData(asyncResp, properties, regionPtr); 706 } 707 708 ); 709 } 710 711 inline void getDimmData(std::shared_ptr<bmcweb::AsyncResp> asyncResp, 712 const std::string& dimmId) 713 { 714 BMCWEB_LOG_DEBUG << "Get available system dimm resources."; 715 constexpr std::array<std::string_view, 2> dimmInterfaces = { 716 "xyz.openbmc_project.Inventory.Item.Dimm", 717 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"}; 718 dbus::utility::getSubTree( 719 "/xyz/openbmc_project/inventory", 0, dimmInterfaces, 720 [dimmId, asyncResp{std::move(asyncResp)}]( 721 const boost::system::error_code& ec, 722 const dbus::utility::MapperGetSubTreeResponse& subtree) { 723 if (ec) 724 { 725 BMCWEB_LOG_DEBUG << "DBUS response error"; 726 messages::internalError(asyncResp->res); 727 728 return; 729 } 730 bool found = false; 731 for (const auto& [rawPath, object] : subtree) 732 { 733 sdbusplus::message::object_path path(rawPath); 734 for (const auto& [service, interfaces] : object) 735 { 736 for (const auto& interface : interfaces) 737 { 738 if (interface == 739 "xyz.openbmc_project.Inventory.Item.Dimm" && 740 path.filename() == dimmId) 741 { 742 getDimmDataByService(asyncResp, dimmId, service, 743 rawPath); 744 found = true; 745 } 746 747 // partitions are separate as there can be multiple 748 // per 749 // device, i.e. 750 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1 751 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2 752 if (interface == 753 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" && 754 path.parent_path().filename() == dimmId) 755 { 756 getDimmPartitionData(asyncResp, service, rawPath); 757 } 758 } 759 } 760 } 761 // Object not found 762 if (!found) 763 { 764 messages::resourceNotFound(asyncResp->res, "Memory", dimmId); 765 return; 766 } 767 // Set @odata only if object is found 768 asyncResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory"; 769 asyncResp->res.jsonValue["@odata.id"] = 770 boost::urls::format("/redfish/v1/Systems/system/Memory/{}", dimmId); 771 return; 772 }); 773 } 774 775 inline void requestRoutesMemoryCollection(App& app) 776 { 777 /** 778 * Functions triggers appropriate requests on DBus 779 */ 780 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/") 781 .privileges(redfish::privileges::getMemoryCollection) 782 .methods(boost::beast::http::verb::get)( 783 [&app](const crow::Request& req, 784 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 785 const std::string& systemName) { 786 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 787 { 788 return; 789 } 790 if (systemName != "system") 791 { 792 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 793 systemName); 794 return; 795 } 796 797 asyncResp->res.jsonValue["@odata.type"] = 798 "#MemoryCollection.MemoryCollection"; 799 asyncResp->res.jsonValue["Name"] = "Memory Module Collection"; 800 asyncResp->res.jsonValue["@odata.id"] = 801 "/redfish/v1/Systems/system/Memory"; 802 803 constexpr std::array<std::string_view, 1> interfaces{ 804 "xyz.openbmc_project.Inventory.Item.Dimm"}; 805 collection_util::getCollectionMembers( 806 asyncResp, boost::urls::url("/redfish/v1/Systems/system/Memory"), 807 interfaces); 808 }); 809 } 810 811 inline void requestRoutesMemory(App& app) 812 { 813 /** 814 * Functions triggers appropriate requests on DBus 815 */ 816 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/<str>/") 817 .privileges(redfish::privileges::getMemory) 818 .methods(boost::beast::http::verb::get)( 819 [&app](const crow::Request& req, 820 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 821 const std::string& systemName, const std::string& dimmId) { 822 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 823 { 824 return; 825 } 826 if (systemName != "system") 827 { 828 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 829 systemName); 830 return; 831 } 832 833 getDimmData(asyncResp, dimmId); 834 }); 835 } 836 837 } // namespace redfish 838