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