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