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