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