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