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