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