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