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