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