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 247 aResp->res.jsonValue[jsonPtr]["VolatileSizeMiB"] = 248 (*volatileSizeInKiB) >> 10; 249 } 250 251 if (pmSizeInKiB != nullptr) 252 { 253 aResp->res.jsonValue[jsonPtr]["NonVolatileSizeMiB"] = 254 (*pmSizeInKiB) >> 10; 255 } 256 257 if (cacheSizeInKB != nullptr) 258 { 259 aResp->res.jsonValue[jsonPtr]["CacheSizeMiB"] = (*cacheSizeInKB >> 10); 260 } 261 262 if (voltaileRegionMaxSizeInKib != nullptr) 263 { 264 aResp->res.jsonValue[jsonPtr]["VolatileRegionSizeMaxMiB"] = 265 (*voltaileRegionMaxSizeInKib) >> 10; 266 } 267 268 if (pmRegionMaxSizeInKiB != nullptr) 269 { 270 aResp->res.jsonValue[jsonPtr]["PersistentRegionSizeMaxMiB"] = 271 (*pmRegionMaxSizeInKiB) >> 10; 272 } 273 274 if (allocationIncrementInKiB != nullptr) 275 { 276 aResp->res.jsonValue[jsonPtr]["AllocationIncrementMiB"] = 277 (*allocationIncrementInKiB) >> 10; 278 } 279 280 if (allocationAlignmentInKiB != nullptr) 281 { 282 aResp->res.jsonValue[jsonPtr]["AllocationAlignmentMiB"] = 283 (*allocationAlignmentInKiB) >> 10; 284 } 285 286 if (volatileRegionNumberLimit != nullptr) 287 { 288 aResp->res.jsonValue[jsonPtr]["VolatileRegionNumberLimit"] = 289 *volatileRegionNumberLimit; 290 } 291 292 if (pmRegionNumberLimit != nullptr) 293 { 294 aResp->res.jsonValue[jsonPtr]["PersistentRegionNumberLimit"] = 295 *pmRegionNumberLimit; 296 } 297 298 if (spareDeviceCount != nullptr) 299 { 300 aResp->res.jsonValue[jsonPtr]["SpareDeviceCount"] = *spareDeviceCount; 301 } 302 303 if (isSpareDeviceInUse != nullptr) 304 { 305 aResp->res.jsonValue[jsonPtr]["IsSpareDeviceEnabled"] = 306 *isSpareDeviceInUse; 307 } 308 309 if (isRankSpareEnabled != nullptr) 310 { 311 aResp->res.jsonValue[jsonPtr]["IsRankSpareEnabled"] = 312 *isRankSpareEnabled; 313 } 314 315 if (maxAveragePowerLimitmW != nullptr) 316 { 317 aResp->res.jsonValue[jsonPtr]["MaxTDPMilliWatts"] = 318 *maxAveragePowerLimitmW; 319 } 320 321 if (configurationLocked != nullptr) 322 { 323 aResp->res.jsonValue[jsonPtr]["ConfigurationLocked"] = 324 *configurationLocked; 325 } 326 327 if (allowedMemoryModes != nullptr) 328 { 329 constexpr const std::array<const char*, 3> values{"Volatile", "PMEM", 330 "Block"}; 331 332 for (const char* v : values) 333 { 334 if (allowedMemoryModes->ends_with(v)) 335 { 336 aResp->res.jsonValue[jsonPtr]["OperatingMemoryModes"].push_back( 337 v); 338 break; 339 } 340 } 341 } 342 343 if (memoryMedia != nullptr) 344 { 345 constexpr const std::array<const char*, 3> values{"DRAM", "NAND", 346 "Intel3DXPoint"}; 347 348 for (const char* v : values) 349 { 350 if (memoryMedia->ends_with(v)) 351 { 352 aResp->res.jsonValue[jsonPtr]["MemoryMedia"].push_back(v); 353 break; 354 } 355 } 356 } 357 358 if (configurationLockCapable != nullptr) 359 { 360 aResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 361 ["ConfigurationLockCapable"] = 362 *configurationLockCapable; 363 } 364 365 if (dataLockCapable != nullptr) 366 { 367 aResp->res 368 .jsonValue[jsonPtr]["SecurityCapabilities"]["DataLockCapable"] = 369 *dataLockCapable; 370 } 371 372 if (passphraseCapable != nullptr) 373 { 374 aResp->res 375 .jsonValue[jsonPtr]["SecurityCapabilities"]["PassphraseCapable"] = 376 *passphraseCapable; 377 } 378 379 if (maxPassphraseCount != nullptr) 380 { 381 aResp->res 382 .jsonValue[jsonPtr]["SecurityCapabilities"]["MaxPassphraseCount"] = 383 *maxPassphraseCount; 384 } 385 386 if (passphraseLockLimit != nullptr) 387 { 388 aResp->res 389 .jsonValue[jsonPtr]["SecurityCapabilities"]["PassphraseLockLimit"] = 390 *passphraseLockLimit; 391 } 392 } 393 394 inline void 395 assembleDimmProperties(std::string_view dimmId, 396 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 397 const dbus::utility::DBusPropertiesMap& properties, 398 const nlohmann::json::json_pointer& jsonPtr) 399 { 400 aResp->res.jsonValue[jsonPtr]["Id"] = dimmId; 401 aResp->res.jsonValue[jsonPtr]["Name"] = "DIMM Slot"; 402 aResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Enabled"; 403 aResp->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 uint8_t* memoryAttributes = nullptr; 417 const uint16_t* memoryConfiguredSpeedInMhz = nullptr; 418 const std::string* memoryType = nullptr; 419 const std::string* channel = nullptr; 420 const std::string* memoryController = nullptr; 421 const std::string* slot = nullptr; 422 const std::string* 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(aResp->res); 443 return; 444 } 445 446 if (memoryDataWidth != nullptr) 447 { 448 aResp->res.jsonValue[jsonPtr]["DataWidthBits"] = *memoryDataWidth; 449 } 450 451 if (memorySizeInKB != nullptr) 452 { 453 aResp->res.jsonValue[jsonPtr]["CapacityMiB"] = (*memorySizeInKB >> 10); 454 } 455 456 if (partNumber != nullptr) 457 { 458 aResp->res.jsonValue[jsonPtr]["PartNumber"] = *partNumber; 459 } 460 461 if (serialNumber != nullptr) 462 { 463 aResp->res.jsonValue[jsonPtr]["SerialNumber"] = *serialNumber; 464 } 465 466 if (manufacturer != nullptr) 467 { 468 aResp->res.jsonValue[jsonPtr]["Manufacturer"] = *manufacturer; 469 } 470 471 if (revisionCode != nullptr) 472 { 473 aResp->res.jsonValue[jsonPtr]["FirmwareRevision"] = 474 std::to_string(*revisionCode); 475 } 476 477 if (present != nullptr && !*present) 478 { 479 aResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Absent"; 480 } 481 482 if (memoryTotalWidth != nullptr) 483 { 484 aResp->res.jsonValue[jsonPtr]["BusWidthBits"] = *memoryTotalWidth; 485 } 486 487 if (ecc != nullptr) 488 { 489 constexpr const std::array<const char*, 4> values{ 490 "NoECC", "SingleBitECC", "MultiBitECC", "AddressParity"}; 491 492 for (const char* v : values) 493 { 494 if (ecc->ends_with(v)) 495 { 496 aResp->res.jsonValue[jsonPtr]["ErrorCorrection"] = v; 497 break; 498 } 499 } 500 } 501 502 if (formFactor != nullptr) 503 { 504 constexpr const std::array<const char*, 11> values{ 505 "RDIMM", "UDIMM", "SO_DIMM", "LRDIMM", 506 "Mini_RDIMM", "Mini_UDIMM", "SO_RDIMM_72b", "SO_UDIMM_72b", 507 "SO_DIMM_16b", "SO_DIMM_32b", "Die"}; 508 509 for (const char* v : values) 510 { 511 if (formFactor->ends_with(v)) 512 { 513 aResp->res.jsonValue[jsonPtr]["BaseModuleType"] = v; 514 break; 515 } 516 } 517 } 518 519 if (allowedSpeedsMT != nullptr) 520 { 521 nlohmann::json& jValue = 522 aResp->res.jsonValue[jsonPtr]["AllowedSpeedsMHz"]; 523 jValue = nlohmann::json::array(); 524 for (uint16_t subVal : *allowedSpeedsMT) 525 { 526 jValue.push_back(subVal); 527 } 528 } 529 530 if (memoryAttributes != nullptr) 531 { 532 aResp->res.jsonValue[jsonPtr]["RankCount"] = 533 static_cast<uint64_t>(*memoryAttributes); 534 } 535 536 if (memoryConfiguredSpeedInMhz != nullptr) 537 { 538 aResp->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 aResp->res.jsonValue[jsonPtr]["MemoryDeviceType"] = 551 memoryDeviceType; 552 } 553 if (memoryType->find("DDR") != std::string::npos) 554 { 555 aResp->res.jsonValue[jsonPtr]["MemoryType"] = "DRAM"; 556 } 557 else if (memoryType->ends_with("Logical")) 558 { 559 aResp->res.jsonValue[jsonPtr]["MemoryType"] = "IntelOptane"; 560 } 561 } 562 563 if (channel != nullptr) 564 { 565 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Channel"] = *channel; 566 } 567 568 if (memoryController != nullptr) 569 { 570 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["MemoryController"] = 571 *memoryController; 572 } 573 574 if (slot != nullptr) 575 { 576 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Slot"] = *slot; 577 } 578 579 if (socket != nullptr) 580 { 581 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Socket"] = *socket; 582 } 583 584 if (sparePartNumber != nullptr) 585 { 586 aResp->res.jsonValue[jsonPtr]["SparePartNumber"] = *sparePartNumber; 587 } 588 589 if (model != nullptr) 590 { 591 aResp->res.jsonValue[jsonPtr]["Model"] = *model; 592 } 593 594 if (locationCode != nullptr) 595 { 596 aResp->res 597 .jsonValue[jsonPtr]["Location"]["PartLocation"]["ServiceLabel"] = 598 *locationCode; 599 } 600 601 getPersistentMemoryProperties(aResp, properties, jsonPtr); 602 } 603 604 inline void getDimmDataByService(std::shared_ptr<bmcweb::AsyncResp> aResp, 605 const std::string& dimmId, 606 const std::string& service, 607 const std::string& objPath) 608 { 609 auto health = std::make_shared<HealthPopulate>(aResp); 610 health->selfPath = objPath; 611 health->populate(); 612 613 BMCWEB_LOG_DEBUG << "Get available system components."; 614 sdbusplus::asio::getAllProperties( 615 *crow::connections::systemBus, service, objPath, "", 616 [dimmId, aResp{std::move(aResp)}]( 617 const boost::system::error_code ec, 618 const dbus::utility::DBusPropertiesMap& properties) { 619 if (ec) 620 { 621 BMCWEB_LOG_DEBUG << "DBUS response error"; 622 messages::internalError(aResp->res); 623 return; 624 } 625 assembleDimmProperties(dimmId, aResp, properties, ""_json_pointer); 626 }); 627 } 628 629 inline void assembleDimmPartitionData( 630 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 631 const dbus::utility::DBusPropertiesMap& properties, 632 const nlohmann::json::json_pointer& regionPtr) 633 { 634 const std::string* memoryClassification = nullptr; 635 const uint64_t* offsetInKiB = nullptr; 636 const std::string* partitionId = nullptr; 637 const bool* passphraseState = nullptr; 638 const uint64_t* sizeInKiB = nullptr; 639 640 const bool success = sdbusplus::unpackPropertiesNoThrow( 641 dbus_utils::UnpackErrorPrinter(), properties, "MemoryClassification", 642 memoryClassification, "OffsetInKiB", offsetInKiB, "PartitionId", 643 partitionId, "PassphraseState", passphraseState, "SizeInKiB", 644 sizeInKiB); 645 646 if (!success) 647 { 648 messages::internalError(aResp->res); 649 return; 650 } 651 652 nlohmann::json::object_t partition; 653 654 if (memoryClassification != nullptr) 655 { 656 partition["MemoryClassification"] = *memoryClassification; 657 } 658 659 if (offsetInKiB != nullptr) 660 { 661 partition["OffsetMiB"] = (*offsetInKiB >> 10); 662 } 663 664 if (partitionId != nullptr) 665 { 666 partition["RegionId"] = *partitionId; 667 } 668 669 if (passphraseState != nullptr) 670 { 671 partition["PassphraseEnabled"] = *passphraseState; 672 } 673 674 if (sizeInKiB != nullptr) 675 { 676 partition["SizeMiB"] = (*sizeInKiB >> 10); 677 } 678 679 aResp->res.jsonValue[regionPtr].emplace_back(std::move(partition)); 680 } 681 682 inline void getDimmPartitionData(std::shared_ptr<bmcweb::AsyncResp> aResp, 683 const std::string& service, 684 const std::string& path) 685 { 686 sdbusplus::asio::getAllProperties( 687 *crow::connections::systemBus, service, path, 688 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition", 689 [aResp{std::move(aResp)}]( 690 const boost::system::error_code ec, 691 const dbus::utility::DBusPropertiesMap& properties) { 692 if (ec) 693 { 694 BMCWEB_LOG_DEBUG << "DBUS response error"; 695 messages::internalError(aResp->res); 696 697 return; 698 } 699 nlohmann::json::json_pointer regionPtr = "/Regions"_json_pointer; 700 assembleDimmPartitionData(aResp, properties, regionPtr); 701 } 702 703 ); 704 } 705 706 inline void getDimmData(std::shared_ptr<bmcweb::AsyncResp> aResp, 707 const std::string& dimmId) 708 { 709 BMCWEB_LOG_DEBUG << "Get available system dimm resources."; 710 constexpr std::array<std::string_view, 2> dimmInterfaces = { 711 "xyz.openbmc_project.Inventory.Item.Dimm", 712 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"}; 713 dbus::utility::getSubTree( 714 "/xyz/openbmc_project/inventory", 0, dimmInterfaces, 715 [dimmId, aResp{std::move(aResp)}]( 716 const boost::system::error_code& ec, 717 const dbus::utility::MapperGetSubTreeResponse& subtree) { 718 if (ec) 719 { 720 BMCWEB_LOG_DEBUG << "DBUS response error"; 721 messages::internalError(aResp->res); 722 723 return; 724 } 725 bool found = false; 726 for (const auto& [rawPath, object] : subtree) 727 { 728 sdbusplus::message::object_path path(rawPath); 729 for (const auto& [service, interfaces] : object) 730 { 731 for (const auto& interface : interfaces) 732 { 733 if (interface == 734 "xyz.openbmc_project.Inventory.Item.Dimm" && 735 path.filename() == dimmId) 736 { 737 getDimmDataByService(aResp, dimmId, service, rawPath); 738 found = true; 739 } 740 741 // partitions are separate as there can be multiple 742 // per 743 // device, i.e. 744 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1 745 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2 746 if (interface == 747 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" && 748 path.parent_path().filename() == dimmId) 749 { 750 getDimmPartitionData(aResp, service, rawPath); 751 } 752 } 753 } 754 } 755 // Object not found 756 if (!found) 757 { 758 messages::resourceNotFound(aResp->res, "Memory", dimmId); 759 return; 760 } 761 // Set @odata only if object is found 762 aResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory"; 763 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 764 "redfish", "v1", "Systems", "system", "Memory", dimmId); 765 return; 766 }); 767 } 768 769 inline void requestRoutesMemoryCollection(App& app) 770 { 771 /** 772 * Functions triggers appropriate requests on DBus 773 */ 774 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/") 775 .privileges(redfish::privileges::getMemoryCollection) 776 .methods(boost::beast::http::verb::get)( 777 [&app](const crow::Request& req, 778 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 779 const std::string& systemName) { 780 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 781 { 782 return; 783 } 784 if (systemName != "system") 785 { 786 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 787 systemName); 788 return; 789 } 790 791 asyncResp->res.jsonValue["@odata.type"] = 792 "#MemoryCollection.MemoryCollection"; 793 asyncResp->res.jsonValue["Name"] = "Memory Module Collection"; 794 asyncResp->res.jsonValue["@odata.id"] = 795 "/redfish/v1/Systems/system/Memory"; 796 797 constexpr std::array<std::string_view, 1> interfaces{ 798 "xyz.openbmc_project.Inventory.Item.Dimm"}; 799 collection_util::getCollectionMembers( 800 asyncResp, boost::urls::url("/redfish/v1/Systems/system/Memory"), 801 interfaces); 802 }); 803 } 804 805 inline void requestRoutesMemory(App& app) 806 { 807 /** 808 * Functions triggers appropriate requests on DBus 809 */ 810 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/<str>/") 811 .privileges(redfish::privileges::getMemory) 812 .methods(boost::beast::http::verb::get)( 813 [&app](const crow::Request& req, 814 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 815 const std::string& systemName, const std::string& dimmId) { 816 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 817 { 818 return; 819 } 820 if (systemName != "system") 821 { 822 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 823 systemName); 824 return; 825 } 826 827 getDimmData(asyncResp, dimmId); 828 }); 829 } 830 831 } // namespace redfish 832