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