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 <boost/url/format.hpp> 30 #include <nlohmann/json.hpp> 31 #include <sdbusplus/asio/property.hpp> 32 #include <sdbusplus/unpack_properties.hpp> 33 34 #include <array> 35 #include <string_view> 36 37 namespace redfish 38 { 39 40 inline std::string translateMemoryTypeToRedfish(const std::string& memoryType) 41 { 42 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR") 43 { 44 return "DDR"; 45 } 46 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2") 47 { 48 return "DDR2"; 49 } 50 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR3") 51 { 52 return "DDR3"; 53 } 54 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4") 55 { 56 return "DDR4"; 57 } 58 if (memoryType == 59 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4E_SDRAM") 60 { 61 return "DDR4E_SDRAM"; 62 } 63 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR5") 64 { 65 return "DDR5"; 66 } 67 if (memoryType == 68 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR4_SDRAM") 69 { 70 return "LPDDR4_SDRAM"; 71 } 72 if (memoryType == 73 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR3_SDRAM") 74 { 75 return "LPDDR3_SDRAM"; 76 } 77 if (memoryType == 78 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM") 79 { 80 return "DDR2_SDRAM_FB_DIMM"; 81 } 82 if (memoryType == 83 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM_PROB") 84 { 85 return "DDR2_SDRAM_FB_DIMM_PROBE"; 86 } 87 if (memoryType == 88 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR_SGRAM") 89 { 90 return "DDR_SGRAM"; 91 } 92 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.ROM") 93 { 94 return "ROM"; 95 } 96 if (memoryType == 97 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.SDRAM") 98 { 99 return "SDRAM"; 100 } 101 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.EDO") 102 { 103 return "EDO"; 104 } 105 if (memoryType == 106 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.FastPageMode") 107 { 108 return "FastPageMode"; 109 } 110 if (memoryType == 111 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.PipelinedNibble") 112 { 113 return "PipelinedNibble"; 114 } 115 if (memoryType == 116 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.Logical") 117 { 118 return "Logical"; 119 } 120 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM") 121 { 122 return "HBM"; 123 } 124 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM2") 125 { 126 return "HBM2"; 127 } 128 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM3") 129 { 130 return "HBM3"; 131 } 132 // This is values like Other or Unknown 133 // Also D-Bus values: 134 // DRAM 135 // EDRAM 136 // VRAM 137 // SRAM 138 // RAM 139 // FLASH 140 // EEPROM 141 // FEPROM 142 // EPROM 143 // CDRAM 144 // ThreeDRAM 145 // RDRAM 146 // FBD2 147 // LPDDR_SDRAM 148 // LPDDR2_SDRAM 149 // LPDDR5_SDRAM 150 return ""; 151 } 152 153 inline void dimmPropToHex(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 154 const char* key, const uint16_t* value, 155 const nlohmann::json::json_pointer& jsonPtr) 156 { 157 if (value == nullptr) 158 { 159 return; 160 } 161 aResp->res.jsonValue[jsonPtr][key] = "0x" + intToHexString(*value, 4); 162 } 163 164 inline void getPersistentMemoryProperties( 165 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 166 const dbus::utility::DBusPropertiesMap& properties, 167 const nlohmann::json::json_pointer& jsonPtr) 168 { 169 const uint16_t* moduleManufacturerID = nullptr; 170 const uint16_t* moduleProductID = nullptr; 171 const uint16_t* subsystemVendorID = nullptr; 172 const uint16_t* subsystemDeviceID = nullptr; 173 const uint64_t* volatileRegionSizeLimitInKiB = nullptr; 174 const uint64_t* pmRegionSizeLimitInKiB = nullptr; 175 const uint64_t* volatileSizeInKiB = nullptr; 176 const uint64_t* pmSizeInKiB = nullptr; 177 const uint64_t* cacheSizeInKB = nullptr; 178 const uint64_t* voltaileRegionMaxSizeInKib = nullptr; 179 const uint64_t* pmRegionMaxSizeInKiB = nullptr; 180 const uint64_t* allocationIncrementInKiB = nullptr; 181 const uint64_t* allocationAlignmentInKiB = nullptr; 182 const uint64_t* volatileRegionNumberLimit = nullptr; 183 const uint64_t* pmRegionNumberLimit = nullptr; 184 const uint64_t* spareDeviceCount = nullptr; 185 const bool* isSpareDeviceInUse = nullptr; 186 const bool* isRankSpareEnabled = nullptr; 187 const std::vector<uint32_t>* maxAveragePowerLimitmW = nullptr; 188 const bool* configurationLocked = nullptr; 189 const std::string* allowedMemoryModes = nullptr; 190 const std::string* memoryMedia = nullptr; 191 const bool* configurationLockCapable = nullptr; 192 const bool* dataLockCapable = nullptr; 193 const bool* passphraseCapable = nullptr; 194 const uint64_t* maxPassphraseCount = nullptr; 195 const uint64_t* passphraseLockLimit = nullptr; 196 197 const bool success = sdbusplus::unpackPropertiesNoThrow( 198 dbus_utils::UnpackErrorPrinter(), properties, "ModuleManufacturerID", 199 moduleManufacturerID, "ModuleProductID", moduleProductID, 200 "SubsystemVendorID", subsystemVendorID, "SubsystemDeviceID", 201 subsystemDeviceID, "VolatileRegionSizeLimitInKiB", 202 volatileRegionSizeLimitInKiB, "PmRegionSizeLimitInKiB", 203 pmRegionSizeLimitInKiB, "VolatileSizeInKiB", volatileSizeInKiB, 204 "PmSizeInKiB", pmSizeInKiB, "CacheSizeInKB", cacheSizeInKB, 205 "VoltaileRegionMaxSizeInKib", voltaileRegionMaxSizeInKib, 206 "PmRegionMaxSizeInKiB", pmRegionMaxSizeInKiB, 207 "AllocationIncrementInKiB", allocationIncrementInKiB, 208 "AllocationAlignmentInKiB", allocationAlignmentInKiB, 209 "VolatileRegionNumberLimit", volatileRegionNumberLimit, 210 "PmRegionNumberLimit", pmRegionNumberLimit, "SpareDeviceCount", 211 spareDeviceCount, "IsSpareDeviceInUse", isSpareDeviceInUse, 212 "IsRankSpareEnabled", isRankSpareEnabled, "MaxAveragePowerLimitmW", 213 maxAveragePowerLimitmW, "ConfigurationLocked", configurationLocked, 214 "AllowedMemoryModes", allowedMemoryModes, "MemoryMedia", memoryMedia, 215 "ConfigurationLockCapable", configurationLockCapable, "DataLockCapable", 216 dataLockCapable, "PassphraseCapable", passphraseCapable, 217 "MaxPassphraseCount", maxPassphraseCount, "PassphraseLockLimit", 218 passphraseLockLimit); 219 220 if (!success) 221 { 222 messages::internalError(aResp->res); 223 return; 224 } 225 226 dimmPropToHex(aResp, "ModuleManufacturerID", moduleManufacturerID, jsonPtr); 227 dimmPropToHex(aResp, "ModuleProductID", moduleProductID, jsonPtr); 228 dimmPropToHex(aResp, "MemorySubsystemControllerManufacturerID", 229 subsystemVendorID, jsonPtr); 230 dimmPropToHex(aResp, "MemorySubsystemControllerProductID", 231 subsystemDeviceID, jsonPtr); 232 233 if (volatileRegionSizeLimitInKiB != nullptr) 234 { 235 aResp->res.jsonValue[jsonPtr]["VolatileRegionSizeLimitMiB"] = 236 (*volatileRegionSizeLimitInKiB) >> 10; 237 } 238 239 if (pmRegionSizeLimitInKiB != nullptr) 240 { 241 aResp->res.jsonValue[jsonPtr]["PersistentRegionSizeLimitMiB"] = 242 (*pmRegionSizeLimitInKiB) >> 10; 243 } 244 245 if (volatileSizeInKiB != nullptr) 246 { 247 aResp->res.jsonValue[jsonPtr]["VolatileSizeMiB"] = 248 (*volatileSizeInKiB) >> 10; 249 } 250 251 if (pmSizeInKiB != nullptr) 252 { 253 aResp->res.jsonValue[jsonPtr]["NonVolatileSizeMiB"] = (*pmSizeInKiB) >> 254 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.jsonValue[jsonPtr]["SecurityCapabilities"] 368 ["DataLockCapable"] = *dataLockCapable; 369 } 370 371 if (passphraseCapable != nullptr) 372 { 373 aResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 374 ["PassphraseCapable"] = *passphraseCapable; 375 } 376 377 if (maxPassphraseCount != nullptr) 378 { 379 aResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 380 ["MaxPassphraseCount"] = *maxPassphraseCount; 381 } 382 383 if (passphraseLockLimit != nullptr) 384 { 385 aResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] 386 ["PassphraseLockLimit"] = *passphraseLockLimit; 387 } 388 } 389 390 inline void 391 assembleDimmProperties(std::string_view dimmId, 392 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 393 const dbus::utility::DBusPropertiesMap& properties, 394 const nlohmann::json::json_pointer& jsonPtr) 395 { 396 aResp->res.jsonValue[jsonPtr]["Id"] = dimmId; 397 aResp->res.jsonValue[jsonPtr]["Name"] = "DIMM Slot"; 398 aResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Enabled"; 399 aResp->res.jsonValue[jsonPtr]["Status"]["Health"] = "OK"; 400 401 const uint16_t* memoryDataWidth = nullptr; 402 const size_t* memorySizeInKB = nullptr; 403 const std::string* partNumber = nullptr; 404 const std::string* serialNumber = nullptr; 405 const std::string* manufacturer = nullptr; 406 const uint16_t* revisionCode = nullptr; 407 const bool* present = nullptr; 408 const uint16_t* memoryTotalWidth = nullptr; 409 const std::string* ecc = nullptr; 410 const std::string* formFactor = nullptr; 411 const std::vector<uint16_t>* allowedSpeedsMT = nullptr; 412 const uint8_t* memoryAttributes = nullptr; 413 const uint16_t* memoryConfiguredSpeedInMhz = nullptr; 414 const std::string* memoryType = nullptr; 415 const std::string* channel = nullptr; 416 const std::string* memoryController = nullptr; 417 const std::string* slot = nullptr; 418 const std::string* socket = nullptr; 419 const std::string* sparePartNumber = nullptr; 420 const std::string* model = nullptr; 421 const std::string* locationCode = nullptr; 422 423 const bool success = sdbusplus::unpackPropertiesNoThrow( 424 dbus_utils::UnpackErrorPrinter(), properties, "MemoryDataWidth", 425 memoryDataWidth, "MemorySizeInKB", memorySizeInKB, "PartNumber", 426 partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, 427 "RevisionCode", revisionCode, "Present", present, "MemoryTotalWidth", 428 memoryTotalWidth, "ECC", ecc, "FormFactor", formFactor, 429 "AllowedSpeedsMT", allowedSpeedsMT, "MemoryAttributes", 430 memoryAttributes, "MemoryConfiguredSpeedInMhz", 431 memoryConfiguredSpeedInMhz, "MemoryType", memoryType, "Channel", 432 channel, "MemoryController", memoryController, "Slot", slot, "Socket", 433 socket, "SparePartNumber", sparePartNumber, "Model", model, 434 "LocationCode", locationCode); 435 436 if (!success) 437 { 438 messages::internalError(aResp->res); 439 return; 440 } 441 442 if (memoryDataWidth != nullptr) 443 { 444 aResp->res.jsonValue[jsonPtr]["DataWidthBits"] = *memoryDataWidth; 445 } 446 447 if (memorySizeInKB != nullptr) 448 { 449 aResp->res.jsonValue[jsonPtr]["CapacityMiB"] = (*memorySizeInKB >> 10); 450 } 451 452 if (partNumber != nullptr) 453 { 454 aResp->res.jsonValue[jsonPtr]["PartNumber"] = *partNumber; 455 } 456 457 if (serialNumber != nullptr) 458 { 459 aResp->res.jsonValue[jsonPtr]["SerialNumber"] = *serialNumber; 460 } 461 462 if (manufacturer != nullptr) 463 { 464 aResp->res.jsonValue[jsonPtr]["Manufacturer"] = *manufacturer; 465 } 466 467 if (revisionCode != nullptr) 468 { 469 aResp->res.jsonValue[jsonPtr]["FirmwareRevision"] = 470 std::to_string(*revisionCode); 471 } 472 473 if (present != nullptr && !*present) 474 { 475 aResp->res.jsonValue[jsonPtr]["Status"]["State"] = "Absent"; 476 } 477 478 if (memoryTotalWidth != nullptr) 479 { 480 aResp->res.jsonValue[jsonPtr]["BusWidthBits"] = *memoryTotalWidth; 481 } 482 483 if (ecc != nullptr) 484 { 485 constexpr const std::array<const char*, 4> values{ 486 "NoECC", "SingleBitECC", "MultiBitECC", "AddressParity"}; 487 488 for (const char* v : values) 489 { 490 if (ecc->ends_with(v)) 491 { 492 aResp->res.jsonValue[jsonPtr]["ErrorCorrection"] = v; 493 break; 494 } 495 } 496 } 497 498 if (formFactor != nullptr) 499 { 500 constexpr const std::array<const char*, 11> values{ 501 "RDIMM", "UDIMM", "SO_DIMM", "LRDIMM", 502 "Mini_RDIMM", "Mini_UDIMM", "SO_RDIMM_72b", "SO_UDIMM_72b", 503 "SO_DIMM_16b", "SO_DIMM_32b", "Die"}; 504 505 for (const char* v : values) 506 { 507 if (formFactor->ends_with(v)) 508 { 509 aResp->res.jsonValue[jsonPtr]["BaseModuleType"] = v; 510 break; 511 } 512 } 513 } 514 515 if (allowedSpeedsMT != nullptr) 516 { 517 nlohmann::json& jValue = 518 aResp->res.jsonValue[jsonPtr]["AllowedSpeedsMHz"]; 519 jValue = nlohmann::json::array(); 520 for (uint16_t subVal : *allowedSpeedsMT) 521 { 522 jValue.push_back(subVal); 523 } 524 } 525 526 if (memoryAttributes != nullptr) 527 { 528 aResp->res.jsonValue[jsonPtr]["RankCount"] = 529 static_cast<uint64_t>(*memoryAttributes); 530 } 531 532 if (memoryConfiguredSpeedInMhz != nullptr) 533 { 534 aResp->res.jsonValue[jsonPtr]["OperatingSpeedMhz"] = 535 *memoryConfiguredSpeedInMhz; 536 } 537 538 if (memoryType != nullptr) 539 { 540 std::string memoryDeviceType = 541 translateMemoryTypeToRedfish(*memoryType); 542 // Values like "Unknown" or "Other" will return empty 543 // so just leave off 544 if (!memoryDeviceType.empty()) 545 { 546 aResp->res.jsonValue[jsonPtr]["MemoryDeviceType"] = 547 memoryDeviceType; 548 } 549 if (memoryType->find("DDR") != std::string::npos) 550 { 551 aResp->res.jsonValue[jsonPtr]["MemoryType"] = "DRAM"; 552 } 553 else if (memoryType->ends_with("Logical")) 554 { 555 aResp->res.jsonValue[jsonPtr]["MemoryType"] = "IntelOptane"; 556 } 557 } 558 559 if (channel != nullptr) 560 { 561 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Channel"] = *channel; 562 } 563 564 if (memoryController != nullptr) 565 { 566 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["MemoryController"] = 567 *memoryController; 568 } 569 570 if (slot != nullptr) 571 { 572 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Slot"] = *slot; 573 } 574 575 if (socket != nullptr) 576 { 577 aResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Socket"] = *socket; 578 } 579 580 if (sparePartNumber != nullptr) 581 { 582 aResp->res.jsonValue[jsonPtr]["SparePartNumber"] = *sparePartNumber; 583 } 584 585 if (model != nullptr) 586 { 587 aResp->res.jsonValue[jsonPtr]["Model"] = *model; 588 } 589 590 if (locationCode != nullptr) 591 { 592 aResp->res.jsonValue[jsonPtr]["Location"]["PartLocation"] 593 ["ServiceLabel"] = *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 constexpr std::array<std::string_view, 2> dimmInterfaces = { 706 "xyz.openbmc_project.Inventory.Item.Dimm", 707 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"}; 708 dbus::utility::getSubTree( 709 "/xyz/openbmc_project/inventory", 0, dimmInterfaces, 710 [dimmId, aResp{std::move(aResp)}]( 711 const boost::system::error_code& ec, 712 const dbus::utility::MapperGetSubTreeResponse& subtree) { 713 if (ec) 714 { 715 BMCWEB_LOG_DEBUG << "DBUS response error"; 716 messages::internalError(aResp->res); 717 718 return; 719 } 720 bool found = false; 721 for (const auto& [rawPath, object] : subtree) 722 { 723 sdbusplus::message::object_path path(rawPath); 724 for (const auto& [service, interfaces] : object) 725 { 726 for (const auto& interface : interfaces) 727 { 728 if (interface == 729 "xyz.openbmc_project.Inventory.Item.Dimm" && 730 path.filename() == dimmId) 731 { 732 getDimmDataByService(aResp, dimmId, service, rawPath); 733 found = true; 734 } 735 736 // partitions are separate as there can be multiple 737 // per 738 // device, i.e. 739 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1 740 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2 741 if (interface == 742 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" && 743 path.parent_path().filename() == dimmId) 744 { 745 getDimmPartitionData(aResp, service, rawPath); 746 } 747 } 748 } 749 } 750 // Object not found 751 if (!found) 752 { 753 messages::resourceNotFound(aResp->res, "Memory", dimmId); 754 return; 755 } 756 // Set @odata only if object is found 757 aResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory"; 758 aResp->res.jsonValue["@odata.id"] = 759 boost::urls::format("/redfish/v1/Systems/system/Memory/{}", dimmId); 760 return; 761 }); 762 } 763 764 inline void requestRoutesMemoryCollection(App& app) 765 { 766 /** 767 * Functions triggers appropriate requests on DBus 768 */ 769 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/") 770 .privileges(redfish::privileges::getMemoryCollection) 771 .methods(boost::beast::http::verb::get)( 772 [&app](const crow::Request& req, 773 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 774 const std::string& systemName) { 775 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 776 { 777 return; 778 } 779 if (systemName != "system") 780 { 781 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 782 systemName); 783 return; 784 } 785 786 asyncResp->res.jsonValue["@odata.type"] = 787 "#MemoryCollection.MemoryCollection"; 788 asyncResp->res.jsonValue["Name"] = "Memory Module Collection"; 789 asyncResp->res.jsonValue["@odata.id"] = 790 "/redfish/v1/Systems/system/Memory"; 791 792 constexpr std::array<std::string_view, 1> interfaces{ 793 "xyz.openbmc_project.Inventory.Item.Dimm"}; 794 collection_util::getCollectionMembers( 795 asyncResp, boost::urls::url("/redfish/v1/Systems/system/Memory"), 796 interfaces); 797 }); 798 } 799 800 inline void requestRoutesMemory(App& app) 801 { 802 /** 803 * Functions triggers appropriate requests on DBus 804 */ 805 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/<str>/") 806 .privileges(redfish::privileges::getMemory) 807 .methods(boost::beast::http::verb::get)( 808 [&app](const crow::Request& req, 809 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 810 const std::string& systemName, const std::string& dimmId) { 811 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 812 { 813 return; 814 } 815 if (systemName != "system") 816 { 817 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 818 systemName); 819 return; 820 } 821 822 getDimmData(asyncResp, dimmId); 823 }); 824 } 825 826 } // namespace redfish 827