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