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