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