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