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