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 <boost/system/error_code.hpp> 29 #include <nlohmann/json.hpp> 30 #include <sdbusplus/asio/property.hpp> 31 #include <sdbusplus/unpack_properties.hpp> 32 33 #include <array> 34 #include <string_view> 35 36 namespace redfish 37 { 38 39 inline std::string translateMemoryTypeToRedfish(const std::string& memoryType) 40 { 41 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR") 42 { 43 return "DDR"; 44 } 45 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2") 46 { 47 return "DDR2"; 48 } 49 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR3") 50 { 51 return "DDR3"; 52 } 53 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4") 54 { 55 return "DDR4"; 56 } 57 if (memoryType == 58 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4E_SDRAM") 59 { 60 return "DDR4E_SDRAM"; 61 } 62 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR5") 63 { 64 return "DDR5"; 65 } 66 if (memoryType == 67 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR4_SDRAM") 68 { 69 return "LPDDR4_SDRAM"; 70 } 71 if (memoryType == 72 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR3_SDRAM") 73 { 74 return "LPDDR3_SDRAM"; 75 } 76 if (memoryType == 77 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM") 78 { 79 return "DDR2_SDRAM_FB_DIMM"; 80 } 81 if (memoryType == 82 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM_PROB") 83 { 84 return "DDR2_SDRAM_FB_DIMM_PROBE"; 85 } 86 if (memoryType == 87 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR_SGRAM") 88 { 89 return "DDR_SGRAM"; 90 } 91 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.ROM") 92 { 93 return "ROM"; 94 } 95 if (memoryType == 96 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.SDRAM") 97 { 98 return "SDRAM"; 99 } 100 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.EDO") 101 { 102 return "EDO"; 103 } 104 if (memoryType == 105 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.FastPageMode") 106 { 107 return "FastPageMode"; 108 } 109 if (memoryType == 110 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.PipelinedNibble") 111 { 112 return "PipelinedNibble"; 113 } 114 if (memoryType == 115 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.Logical") 116 { 117 return "Logical"; 118 } 119 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM") 120 { 121 return "HBM"; 122 } 123 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM2") 124 { 125 return "HBM2"; 126 } 127 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM3") 128 { 129 return "HBM3"; 130 } 131 // This is values like Other or Unknown 132 // Also D-Bus values: 133 // DRAM 134 // EDRAM 135 // VRAM 136 // SRAM 137 // RAM 138 // FLASH 139 // EEPROM 140 // FEPROM 141 // EPROM 142 // CDRAM 143 // ThreeDRAM 144 // RDRAM 145 // FBD2 146 // LPDDR_SDRAM 147 // LPDDR2_SDRAM 148 // LPDDR5_SDRAM 149 return ""; 150 } 151 152 inline void dimmPropToHex(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 153 const char* key, const uint16_t* value, 154 const nlohmann::json::json_pointer& jsonPtr) 155 { 156 if (value == nullptr) 157 { 158 return; 159 } 160 aResp->res.jsonValue[jsonPtr][key] = "0x" + intToHexString(*value, 4); 161 } 162 163 inline void getPersistentMemoryProperties( 164 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 165 const dbus::utility::DBusPropertiesMap& properties, 166 const nlohmann::json::json_pointer& jsonPtr) 167 { 168 const uint16_t* moduleManufacturerID = nullptr; 169 const uint16_t* moduleProductID = nullptr; 170 const uint16_t* subsystemVendorID = nullptr; 171 const uint16_t* subsystemDeviceID = nullptr; 172 const uint64_t* volatileRegionSizeLimitInKiB = nullptr; 173 const uint64_t* pmRegionSizeLimitInKiB = nullptr; 174 const uint64_t* volatileSizeInKiB = nullptr; 175 const uint64_t* pmSizeInKiB = nullptr; 176 const uint64_t* cacheSizeInKB = nullptr; 177 const uint64_t* voltaileRegionMaxSizeInKib = nullptr; 178 const uint64_t* pmRegionMaxSizeInKiB = nullptr; 179 const uint64_t* allocationIncrementInKiB = nullptr; 180 const uint64_t* allocationAlignmentInKiB = nullptr; 181 const uint64_t* volatileRegionNumberLimit = nullptr; 182 const uint64_t* pmRegionNumberLimit = nullptr; 183 const uint64_t* spareDeviceCount = nullptr; 184 const bool* isSpareDeviceInUse = nullptr; 185 const bool* isRankSpareEnabled = nullptr; 186 const std::vector<uint32_t>* maxAveragePowerLimitmW = nullptr; 187 const bool* configurationLocked = nullptr; 188 const std::string* allowedMemoryModes = nullptr; 189 const std::string* memoryMedia = nullptr; 190 const bool* configurationLockCapable = nullptr; 191 const bool* dataLockCapable = nullptr; 192 const bool* passphraseCapable = nullptr; 193 const uint64_t* maxPassphraseCount = nullptr; 194 const uint64_t* passphraseLockLimit = nullptr; 195 196 const bool success = sdbusplus::unpackPropertiesNoThrow( 197 dbus_utils::UnpackErrorPrinter(), properties, "ModuleManufacturerID", 198 moduleManufacturerID, "ModuleProductID", moduleProductID, 199 "SubsystemVendorID", subsystemVendorID, "SubsystemDeviceID", 200 subsystemDeviceID, "VolatileRegionSizeLimitInKiB", 201 volatileRegionSizeLimitInKiB, "PmRegionSizeLimitInKiB", 202 pmRegionSizeLimitInKiB, "VolatileSizeInKiB", volatileSizeInKiB, 203 "PmSizeInKiB", pmSizeInKiB, "CacheSizeInKB", cacheSizeInKB, 204 "VoltaileRegionMaxSizeInKib", voltaileRegionMaxSizeInKib, 205 "PmRegionMaxSizeInKiB", pmRegionMaxSizeInKiB, 206 "AllocationIncrementInKiB", allocationIncrementInKiB, 207 "AllocationAlignmentInKiB", allocationAlignmentInKiB, 208 "VolatileRegionNumberLimit", volatileRegionNumberLimit, 209 "PmRegionNumberLimit", pmRegionNumberLimit, "SpareDeviceCount", 210 spareDeviceCount, "IsSpareDeviceInUse", isSpareDeviceInUse, 211 "IsRankSpareEnabled", isRankSpareEnabled, "MaxAveragePowerLimitmW", 212 maxAveragePowerLimitmW, "ConfigurationLocked", configurationLocked, 213 "AllowedMemoryModes", allowedMemoryModes, "MemoryMedia", memoryMedia, 214 "ConfigurationLockCapable", configurationLockCapable, "DataLockCapable", 215 dataLockCapable, "PassphraseCapable", passphraseCapable, 216 "MaxPassphraseCount", maxPassphraseCount, "PassphraseLockLimit", 217 passphraseLockLimit); 218 219 if (!success) 220 { 221 messages::internalError(aResp->res); 222 return; 223 } 224 225 dimmPropToHex(aResp, "ModuleManufacturerID", moduleManufacturerID, jsonPtr); 226 dimmPropToHex(aResp, "ModuleProductID", moduleProductID, jsonPtr); 227 dimmPropToHex(aResp, "MemorySubsystemControllerManufacturerID", 228 subsystemVendorID, jsonPtr); 229 dimmPropToHex(aResp, "MemorySubsystemControllerProductID", 230 subsystemDeviceID, jsonPtr); 231 232 if (volatileRegionSizeLimitInKiB != nullptr) 233 { 234 aResp->res.jsonValue[jsonPtr]["VolatileRegionSizeLimitMiB"] = 235 (*volatileRegionSizeLimitInKiB) >> 10; 236 } 237 238 if (pmRegionSizeLimitInKiB != nullptr) 239 { 240 aResp->res.jsonValue[jsonPtr]["PersistentRegionSizeLimitMiB"] = 241 (*pmRegionSizeLimitInKiB) >> 10; 242 } 243 244 if (volatileSizeInKiB != nullptr) 245 { 246 aResp->res.jsonValue[jsonPtr]["VolatileSizeMiB"] = 247 (*volatileSizeInKiB) >> 10; 248 } 249 250 if (pmSizeInKiB != nullptr) 251 { 252 aResp->res.jsonValue[jsonPtr]["NonVolatileSizeMiB"] = (*pmSizeInKiB) >> 253 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.jsonValue[jsonPtr]["SecurityCapabilities"] 367 ["DataLockCapable"] = *dataLockCapable; 368 } 369 370 if (passphraseCapable != nullptr) 371 { 372 aResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 373 ["PassphraseCapable"] = *passphraseCapable; 374 } 375 376 if (maxPassphraseCount != nullptr) 377 { 378 aResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 379 ["MaxPassphraseCount"] = *maxPassphraseCount; 380 } 381 382 if (passphraseLockLimit != nullptr) 383 { 384 aResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 385 ["PassphraseLockLimit"] = *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, "Manufacturer", manufacturer, 426 "RevisionCode", revisionCode, "Present", present, "MemoryTotalWidth", 427 memoryTotalWidth, "ECC", ecc, "FormFactor", formFactor, 428 "AllowedSpeedsMT", allowedSpeedsMT, "MemoryAttributes", 429 memoryAttributes, "MemoryConfiguredSpeedInMhz", 430 memoryConfiguredSpeedInMhz, "MemoryType", memoryType, "Channel", 431 channel, "MemoryController", memoryController, "Slot", slot, "Socket", 432 socket, "SparePartNumber", sparePartNumber, "Model", model, 433 "LocationCode", locationCode); 434 435 if (!success) 436 { 437 messages::internalError(aResp->res); 438 return; 439 } 440 441 if (memoryDataWidth != nullptr) 442 { 443 aResp->res.jsonValue[jsonPtr]["DataWidthBits"] = *memoryDataWidth; 444 } 445 446 if (memorySizeInKB != nullptr) 447 { 448 aResp->res.jsonValue[jsonPtr]["CapacityMiB"] = (*memorySizeInKB >> 10); 449 } 450 451 if (partNumber != nullptr) 452 { 453 aResp->res.jsonValue[jsonPtr]["PartNumber"] = *partNumber; 454 } 455 456 if (serialNumber != nullptr) 457 { 458 aResp->res.jsonValue[jsonPtr]["SerialNumber"] = *serialNumber; 459 } 460 461 if (manufacturer != nullptr) 462 { 463 aResp->res.jsonValue[jsonPtr]["Manufacturer"] = *manufacturer; 464 } 465 466 if (revisionCode != nullptr) 467 { 468 aResp->res.jsonValue[jsonPtr]["FirmwareRevision"] = 469 std::to_string(*revisionCode); 470 } 471 472 if (present != nullptr && !*present) 473 { 474 aResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Absent"; 475 } 476 477 if (memoryTotalWidth != nullptr) 478 { 479 aResp->res.jsonValue[jsonPtr]["BusWidthBits"] = *memoryTotalWidth; 480 } 481 482 if (ecc != nullptr) 483 { 484 constexpr const std::array<const char*, 4> values{ 485 "NoECC", "SingleBitECC", "MultiBitECC", "AddressParity"}; 486 487 for (const char* v : values) 488 { 489 if (ecc->ends_with(v)) 490 { 491 aResp->res.jsonValue[jsonPtr]["ErrorCorrection"] = v; 492 break; 493 } 494 } 495 } 496 497 if (formFactor != nullptr) 498 { 499 constexpr const std::array<const char*, 11> values{ 500 "RDIMM", "UDIMM", "SO_DIMM", "LRDIMM", 501 "Mini_RDIMM", "Mini_UDIMM", "SO_RDIMM_72b", "SO_UDIMM_72b", 502 "SO_DIMM_16b", "SO_DIMM_32b", "Die"}; 503 504 for (const char* v : values) 505 { 506 if (formFactor->ends_with(v)) 507 { 508 aResp->res.jsonValue[jsonPtr]["BaseModuleType"] = v; 509 break; 510 } 511 } 512 } 513 514 if (allowedSpeedsMT != nullptr) 515 { 516 nlohmann::json& jValue = 517 aResp->res.jsonValue[jsonPtr]["AllowedSpeedsMHz"]; 518 jValue = nlohmann::json::array(); 519 for (uint16_t subVal : *allowedSpeedsMT) 520 { 521 jValue.push_back(subVal); 522 } 523 } 524 525 if (memoryAttributes != nullptr) 526 { 527 aResp->res.jsonValue[jsonPtr]["RankCount"] = 528 static_cast<uint64_t>(*memoryAttributes); 529 } 530 531 if (memoryConfiguredSpeedInMhz != nullptr) 532 { 533 aResp->res.jsonValue[jsonPtr]["OperatingSpeedMhz"] = 534 *memoryConfiguredSpeedInMhz; 535 } 536 537 if (memoryType != nullptr) 538 { 539 std::string memoryDeviceType = 540 translateMemoryTypeToRedfish(*memoryType); 541 // Values like "Unknown" or "Other" will return empty 542 // so just leave off 543 if (!memoryDeviceType.empty()) 544 { 545 aResp->res.jsonValue[jsonPtr]["MemoryDeviceType"] = 546 memoryDeviceType; 547 } 548 if (memoryType->find("DDR") != std::string::npos) 549 { 550 aResp->res.jsonValue[jsonPtr]["MemoryType"] = "DRAM"; 551 } 552 else if (memoryType->ends_with("Logical")) 553 { 554 aResp->res.jsonValue[jsonPtr]["MemoryType"] = "IntelOptane"; 555 } 556 } 557 558 if (channel != nullptr) 559 { 560 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Channel"] = *channel; 561 } 562 563 if (memoryController != nullptr) 564 { 565 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["MemoryController"] = 566 *memoryController; 567 } 568 569 if (slot != nullptr) 570 { 571 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Slot"] = *slot; 572 } 573 574 if (socket != nullptr) 575 { 576 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Socket"] = *socket; 577 } 578 579 if (sparePartNumber != nullptr) 580 { 581 aResp->res.jsonValue[jsonPtr]["SparePartNumber"] = *sparePartNumber; 582 } 583 584 if (model != nullptr) 585 { 586 aResp->res.jsonValue[jsonPtr]["Model"] = *model; 587 } 588 589 if (locationCode != nullptr) 590 { 591 aResp->res.jsonValue[jsonPtr]["Location"]["PartLocation"] 592 ["ServiceLabel"] = *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 constexpr std::array<std::string_view, 2> dimmInterfaces = { 705 "xyz.openbmc_project.Inventory.Item.Dimm", 706 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"}; 707 dbus::utility::getSubTree( 708 "/xyz/openbmc_project/inventory", 0, dimmInterfaces, 709 [dimmId, aResp{std::move(aResp)}]( 710 const boost::system::error_code& ec, 711 const dbus::utility::MapperGetSubTreeResponse& subtree) { 712 if (ec) 713 { 714 BMCWEB_LOG_DEBUG << "DBUS response error"; 715 messages::internalError(aResp->res); 716 717 return; 718 } 719 bool found = false; 720 for (const auto& [rawPath, object] : subtree) 721 { 722 sdbusplus::message::object_path path(rawPath); 723 for (const auto& [service, interfaces] : object) 724 { 725 for (const auto& interface : interfaces) 726 { 727 if (interface == 728 "xyz.openbmc_project.Inventory.Item.Dimm" && 729 path.filename() == dimmId) 730 { 731 getDimmDataByService(aResp, dimmId, service, rawPath); 732 found = true; 733 } 734 735 // partitions are separate as there can be multiple 736 // per 737 // device, i.e. 738 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1 739 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2 740 if (interface == 741 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" && 742 path.parent_path().filename() == dimmId) 743 { 744 getDimmPartitionData(aResp, service, rawPath); 745 } 746 } 747 } 748 } 749 // Object not found 750 if (!found) 751 { 752 messages::resourceNotFound(aResp->res, "Memory", dimmId); 753 return; 754 } 755 // Set @odata only if object is found 756 aResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory"; 757 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 758 "redfish", "v1", "Systems", "system", "Memory", dimmId); 759 return; 760 }); 761 } 762 763 inline void requestRoutesMemoryCollection(App& app) 764 { 765 /** 766 * Functions triggers appropriate requests on DBus 767 */ 768 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/") 769 .privileges(redfish::privileges::getMemoryCollection) 770 .methods(boost::beast::http::verb::get)( 771 [&app](const crow::Request& req, 772 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 773 const std::string& systemName) { 774 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 775 { 776 return; 777 } 778 if (systemName != "system") 779 { 780 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 781 systemName); 782 return; 783 } 784 785 asyncResp->res.jsonValue["@odata.type"] = 786 "#MemoryCollection.MemoryCollection"; 787 asyncResp->res.jsonValue["Name"] = "Memory Module Collection"; 788 asyncResp->res.jsonValue["@odata.id"] = 789 "/redfish/v1/Systems/system/Memory"; 790 791 constexpr std::array<std::string_view, 1> interfaces{ 792 "xyz.openbmc_project.Inventory.Item.Dimm"}; 793 collection_util::getCollectionMembers( 794 asyncResp, boost::urls::url("/redfish/v1/Systems/system/Memory"), 795 interfaces); 796 }); 797 } 798 799 inline void requestRoutesMemory(App& app) 800 { 801 /** 802 * Functions triggers appropriate requests on DBus 803 */ 804 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/<str>/") 805 .privileges(redfish::privileges::getMemory) 806 .methods(boost::beast::http::verb::get)( 807 [&app](const crow::Request& req, 808 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 809 const std::string& systemName, const std::string& dimmId) { 810 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 811 { 812 return; 813 } 814 if (systemName != "system") 815 { 816 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 817 systemName); 818 return; 819 } 820 821 getDimmData(asyncResp, dimmId); 822 }); 823 } 824 825 } // namespace redfish 826