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