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