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