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