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 const bool* functional = nullptr; 433 434 const bool success = sdbusplus::unpackPropertiesNoThrow( 435 dbus_utils::UnpackErrorPrinter(), properties, "MemoryDataWidth", 436 memoryDataWidth, "MemorySizeInKB", memorySizeInKB, "PartNumber", 437 partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 438 "RevisionCode", revisionCode, "Present", present, "MemoryTotalWidth", 439 memoryTotalWidth, "ECC", ecc, "FormFactor", formFactor, 440 "AllowedSpeedsMT", allowedSpeedsMT, "MemoryAttributes", 441 memoryAttributes, "MemoryConfiguredSpeedInMhz", 442 memoryConfiguredSpeedInMhz, "MemoryType", memoryType, "Channel", 443 channel, "MemoryController", memoryController, "Slot", slot, "Socket", 444 socket, "SparePartNumber", sparePartNumber, "Model", model, 445 "LocationCode", locationCode, "Functional", functional); 446 447 if (!success) 448 { 449 messages::internalError(asyncResp->res); 450 return; 451 } 452 453 if (memoryDataWidth != nullptr) 454 { 455 asyncResp->res.jsonValue[jsonPtr]["DataWidthBits"] = *memoryDataWidth; 456 } 457 458 if (memorySizeInKB != nullptr) 459 { 460 asyncResp->res.jsonValue[jsonPtr]["CapacityMiB"] = 461 (*memorySizeInKB >> 10); 462 } 463 464 if (partNumber != nullptr) 465 { 466 asyncResp->res.jsonValue[jsonPtr]["PartNumber"] = *partNumber; 467 } 468 469 if (serialNumber != nullptr) 470 { 471 asyncResp->res.jsonValue[jsonPtr]["SerialNumber"] = *serialNumber; 472 } 473 474 if (manufacturer != nullptr) 475 { 476 asyncResp->res.jsonValue[jsonPtr]["Manufacturer"] = *manufacturer; 477 } 478 479 if (revisionCode != nullptr) 480 { 481 asyncResp->res.jsonValue[jsonPtr]["FirmwareRevision"] = 482 std::to_string(*revisionCode); 483 } 484 485 if (present != nullptr && !*present) 486 { 487 asyncResp->res.jsonValue[jsonPtr]["Status"]["State"] = 488 resource::State::Absent; 489 } 490 491 if (functional != nullptr) 492 { 493 if (!*functional) 494 { 495 asyncResp->res.jsonValue[jsonPtr]["Status"]["Health"] = 496 resource::Health::Critical; 497 } 498 } 499 500 if (memoryTotalWidth != nullptr) 501 { 502 asyncResp->res.jsonValue[jsonPtr]["BusWidthBits"] = *memoryTotalWidth; 503 } 504 505 if (ecc != nullptr) 506 { 507 constexpr const std::array<const char*, 4> values{ 508 "NoECC", "SingleBitECC", "MultiBitECC", "AddressParity"}; 509 510 for (const char* v : values) 511 { 512 if (ecc->ends_with(v)) 513 { 514 asyncResp->res.jsonValue[jsonPtr]["ErrorCorrection"] = v; 515 break; 516 } 517 } 518 } 519 520 if (formFactor != nullptr) 521 { 522 constexpr const std::array<const char*, 11> values{ 523 "RDIMM", "UDIMM", "SO_DIMM", "LRDIMM", 524 "Mini_RDIMM", "Mini_UDIMM", "SO_RDIMM_72b", "SO_UDIMM_72b", 525 "SO_DIMM_16b", "SO_DIMM_32b", "Die"}; 526 527 for (const char* v : values) 528 { 529 if (formFactor->ends_with(v)) 530 { 531 asyncResp->res.jsonValue[jsonPtr]["BaseModuleType"] = v; 532 break; 533 } 534 } 535 } 536 537 if (allowedSpeedsMT != nullptr) 538 { 539 nlohmann::json& jValue = 540 asyncResp->res.jsonValue[jsonPtr]["AllowedSpeedsMHz"]; 541 jValue = nlohmann::json::array(); 542 for (uint16_t subVal : *allowedSpeedsMT) 543 { 544 jValue.push_back(subVal); 545 } 546 } 547 548 if (memoryAttributes != nullptr) 549 { 550 asyncResp->res.jsonValue[jsonPtr]["RankCount"] = *memoryAttributes; 551 } 552 553 if (memoryConfiguredSpeedInMhz != nullptr) 554 { 555 asyncResp->res.jsonValue[jsonPtr]["OperatingSpeedMhz"] = 556 *memoryConfiguredSpeedInMhz; 557 } 558 559 if (memoryType != nullptr) 560 { 561 std::string memoryDeviceType = 562 translateMemoryTypeToRedfish(*memoryType); 563 // Values like "Unknown" or "Other" will return empty 564 // so just leave off 565 if (!memoryDeviceType.empty()) 566 { 567 asyncResp->res.jsonValue[jsonPtr]["MemoryDeviceType"] = 568 memoryDeviceType; 569 } 570 if (memoryType->find("DDR") != std::string::npos) 571 { 572 asyncResp->res.jsonValue[jsonPtr]["MemoryType"] = 573 memory::MemoryType::DRAM; 574 } 575 else if (memoryType->ends_with("Logical")) 576 { 577 asyncResp->res.jsonValue[jsonPtr]["MemoryType"] = 578 memory::MemoryType::IntelOptane; 579 } 580 } 581 582 if (channel != nullptr) 583 { 584 asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Channel"] = 585 *channel; 586 } 587 588 if (memoryController != nullptr) 589 { 590 asyncResp->res 591 .jsonValue[jsonPtr]["MemoryLocation"]["MemoryController"] = 592 *memoryController; 593 } 594 595 if (slot != nullptr) 596 { 597 asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Slot"] = *slot; 598 } 599 600 if (socket != nullptr) 601 { 602 asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Socket"] = *socket; 603 } 604 605 if (sparePartNumber != nullptr) 606 { 607 asyncResp->res.jsonValue[jsonPtr]["SparePartNumber"] = *sparePartNumber; 608 } 609 610 if (model != nullptr) 611 { 612 asyncResp->res.jsonValue[jsonPtr]["Model"] = *model; 613 } 614 615 if (locationCode != nullptr) 616 { 617 asyncResp->res 618 .jsonValue[jsonPtr]["Location"]["PartLocation"]["ServiceLabel"] = 619 *locationCode; 620 } 621 622 getPersistentMemoryProperties(asyncResp, properties, jsonPtr); 623 } 624 625 inline void getDimmDataByService( 626 std::shared_ptr<bmcweb::AsyncResp> asyncResp, const std::string& dimmId, 627 const std::string& service, const std::string& objPath) 628 { 629 BMCWEB_LOG_DEBUG("Get available system components."); 630 dbus::utility::getAllProperties( 631 service, objPath, "", 632 [dimmId, asyncResp{std::move(asyncResp)}]( 633 const boost::system::error_code& ec, 634 const dbus::utility::DBusPropertiesMap& properties) { 635 if (ec) 636 { 637 BMCWEB_LOG_DEBUG("DBUS response error"); 638 messages::internalError(asyncResp->res); 639 return; 640 } 641 assembleDimmProperties(dimmId, asyncResp, properties, 642 ""_json_pointer); 643 }); 644 } 645 646 inline void assembleDimmPartitionData( 647 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 648 const dbus::utility::DBusPropertiesMap& properties, 649 const nlohmann::json::json_pointer& regionPtr) 650 { 651 const std::string* memoryClassification = nullptr; 652 const uint64_t* offsetInKiB = nullptr; 653 const std::string* partitionId = nullptr; 654 const bool* passphraseState = nullptr; 655 const uint64_t* sizeInKiB = nullptr; 656 657 const bool success = sdbusplus::unpackPropertiesNoThrow( 658 dbus_utils::UnpackErrorPrinter(), properties, "MemoryClassification", 659 memoryClassification, "OffsetInKiB", offsetInKiB, "PartitionId", 660 partitionId, "PassphraseState", passphraseState, "SizeInKiB", 661 sizeInKiB); 662 663 if (!success) 664 { 665 messages::internalError(asyncResp->res); 666 return; 667 } 668 669 nlohmann::json::object_t partition; 670 671 if (memoryClassification != nullptr) 672 { 673 partition["MemoryClassification"] = *memoryClassification; 674 } 675 676 if (offsetInKiB != nullptr) 677 { 678 partition["OffsetMiB"] = (*offsetInKiB >> 10); 679 } 680 681 if (partitionId != nullptr) 682 { 683 partition["RegionId"] = *partitionId; 684 } 685 686 if (passphraseState != nullptr) 687 { 688 partition["PassphraseEnabled"] = *passphraseState; 689 } 690 691 if (sizeInKiB != nullptr) 692 { 693 partition["SizeMiB"] = (*sizeInKiB >> 10); 694 } 695 696 asyncResp->res.jsonValue[regionPtr].emplace_back(std::move(partition)); 697 } 698 699 inline void getDimmPartitionData(std::shared_ptr<bmcweb::AsyncResp> asyncResp, 700 const std::string& service, 701 const std::string& path) 702 { 703 dbus::utility::getAllProperties( 704 service, path, 705 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition", 706 [asyncResp{std::move(asyncResp)}]( 707 const boost::system::error_code& ec, 708 const dbus::utility::DBusPropertiesMap& properties) { 709 if (ec) 710 { 711 BMCWEB_LOG_DEBUG("DBUS response error"); 712 messages::internalError(asyncResp->res); 713 714 return; 715 } 716 nlohmann::json::json_pointer regionPtr = "/Regions"_json_pointer; 717 assembleDimmPartitionData(asyncResp, properties, regionPtr); 718 } 719 720 ); 721 } 722 723 inline void getDimmData(std::shared_ptr<bmcweb::AsyncResp> asyncResp, 724 const std::string& dimmId) 725 { 726 BMCWEB_LOG_DEBUG("Get available system dimm resources."); 727 constexpr std::array<std::string_view, 2> dimmInterfaces = { 728 "xyz.openbmc_project.Inventory.Item.Dimm", 729 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"}; 730 dbus::utility::getSubTree( 731 "/xyz/openbmc_project/inventory", 0, dimmInterfaces, 732 [dimmId, asyncResp{std::move(asyncResp)}]( 733 const boost::system::error_code& ec, 734 const dbus::utility::MapperGetSubTreeResponse& subtree) { 735 if (ec) 736 { 737 BMCWEB_LOG_DEBUG("DBUS response error"); 738 messages::internalError(asyncResp->res); 739 740 return; 741 } 742 bool found = false; 743 for (const auto& [rawPath, object] : subtree) 744 { 745 sdbusplus::message::object_path path(rawPath); 746 for (const auto& [service, interfaces] : object) 747 { 748 for (const auto& interface : interfaces) 749 { 750 if (interface == 751 "xyz.openbmc_project.Inventory.Item.Dimm" && 752 path.filename() == dimmId) 753 { 754 getDimmDataByService(asyncResp, dimmId, service, 755 rawPath); 756 found = true; 757 } 758 759 // partitions are separate as there can be multiple 760 // per 761 // device, i.e. 762 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1 763 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2 764 if (interface == 765 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" && 766 path.parent_path().filename() == dimmId) 767 { 768 getDimmPartitionData(asyncResp, service, rawPath); 769 } 770 } 771 } 772 } 773 // Object not found 774 if (!found) 775 { 776 messages::resourceNotFound(asyncResp->res, "Memory", dimmId); 777 return; 778 } 779 // Set @odata only if object is found 780 asyncResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory"; 781 asyncResp->res.jsonValue["@odata.id"] = 782 boost::urls::format("/redfish/v1/Systems/{}/Memory/{}", 783 BMCWEB_REDFISH_SYSTEM_URI_NAME, dimmId); 784 return; 785 }); 786 } 787 788 inline void requestRoutesMemoryCollection(App& app) 789 { 790 /** 791 * Functions triggers appropriate requests on DBus 792 */ 793 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/") 794 .privileges(redfish::privileges::getMemoryCollection) 795 .methods(boost::beast::http::verb::get)( 796 [&app](const crow::Request& req, 797 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 798 const std::string& systemName) { 799 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 800 { 801 return; 802 } 803 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 804 { 805 // Option currently returns no systems. TBD 806 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 807 systemName); 808 return; 809 } 810 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 811 { 812 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 813 systemName); 814 return; 815 } 816 817 asyncResp->res.jsonValue["@odata.type"] = 818 "#MemoryCollection.MemoryCollection"; 819 asyncResp->res.jsonValue["Name"] = "Memory Module Collection"; 820 asyncResp->res.jsonValue["@odata.id"] = 821 boost::urls::format("/redfish/v1/Systems/{}/Memory", 822 BMCWEB_REDFISH_SYSTEM_URI_NAME); 823 824 constexpr std::array<std::string_view, 1> interfaces{ 825 "xyz.openbmc_project.Inventory.Item.Dimm"}; 826 collection_util::getCollectionMembers( 827 asyncResp, 828 boost::urls::format("/redfish/v1/Systems/{}/Memory", 829 BMCWEB_REDFISH_SYSTEM_URI_NAME), 830 interfaces, "/xyz/openbmc_project/inventory"); 831 }); 832 } 833 834 inline void requestRoutesMemory(App& app) 835 { 836 /** 837 * Functions triggers appropriate requests on DBus 838 */ 839 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/<str>/") 840 .privileges(redfish::privileges::getMemory) 841 .methods(boost::beast::http::verb::get)( 842 [&app](const crow::Request& req, 843 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 844 const std::string& systemName, const std::string& dimmId) { 845 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 846 { 847 return; 848 } 849 850 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 851 { 852 // Option currently returns no systems. TBD 853 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 854 systemName); 855 return; 856 } 857 858 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 859 { 860 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 861 systemName); 862 return; 863 } 864 865 getDimmData(asyncResp, dimmId); 866 }); 867 } 868 869 } // namespace redfish 870