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