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