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 <nlohmann/json.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 142 dimmPropToHex(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 143 const char* key, 144 const dbus::utility::DBusPropertiesMap::value_type& 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 dbus::utility::DBusPropertiesMap::value_type& 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 (value->ends_with(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 (value->ends_with(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 (value->ends_with(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 (value->ends_with(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 (value->ends_with("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 void getDimmData(std::shared_ptr<bmcweb::AsyncResp> aResp, 820 const std::string& dimmId) 821 { 822 BMCWEB_LOG_DEBUG << "Get available system dimm resources."; 823 crow::connections::systemBus->async_method_call( 824 [dimmId, aResp{std::move(aResp)}]( 825 const boost::system::error_code ec, 826 const dbus::utility::MapperGetSubTreeResponse& subtree) { 827 if (ec) 828 { 829 BMCWEB_LOG_DEBUG << "DBUS response error"; 830 messages::internalError(aResp->res); 831 832 return; 833 } 834 bool found = false; 835 for (const auto& [rawPath, object] : subtree) 836 { 837 sdbusplus::message::object_path path(rawPath); 838 for (const auto& [service, interfaces] : object) 839 { 840 for (const auto& interface : interfaces) 841 { 842 if (interface == 843 "xyz.openbmc_project.Inventory.Item.Dimm" && 844 path.filename() == dimmId) 845 { 846 getDimmDataByService(aResp, dimmId, service, rawPath); 847 found = true; 848 } 849 850 // partitions are separate as there can be multiple 851 // per 852 // device, i.e. 853 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1 854 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2 855 if (interface == 856 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" && 857 path.parent_path().filename() == dimmId) 858 { 859 getDimmPartitionData(aResp, service, rawPath); 860 } 861 } 862 } 863 } 864 // Object not found 865 if (!found) 866 { 867 messages::resourceNotFound(aResp->res, "Memory", dimmId); 868 return; 869 } 870 // Set @odata only if object is found 871 aResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory"; 872 aResp->res.jsonValue["@odata.id"] = 873 "/redfish/v1/Systems/system/Memory/" + dimmId; 874 return; 875 }, 876 "xyz.openbmc_project.ObjectMapper", 877 "/xyz/openbmc_project/object_mapper", 878 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 879 "/xyz/openbmc_project/inventory", 0, 880 std::array<const char*, 2>{ 881 "xyz.openbmc_project.Inventory.Item.Dimm", 882 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"}); 883 } 884 885 inline void requestRoutesMemoryCollection(App& app) 886 { 887 /** 888 * Functions triggers appropriate requests on DBus 889 */ 890 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/") 891 .privileges(redfish::privileges::getMemoryCollection) 892 .methods(boost::beast::http::verb::get)( 893 [&app](const crow::Request& req, 894 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 895 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 896 { 897 return; 898 } 899 asyncResp->res.jsonValue["@odata.type"] = 900 "#MemoryCollection.MemoryCollection"; 901 asyncResp->res.jsonValue["Name"] = "Memory Module Collection"; 902 asyncResp->res.jsonValue["@odata.id"] = 903 "/redfish/v1/Systems/system/Memory"; 904 905 collection_util::getCollectionMembers( 906 asyncResp, "/redfish/v1/Systems/system/Memory", 907 {"xyz.openbmc_project.Inventory.Item.Dimm"}); 908 }); 909 } 910 911 inline void requestRoutesMemory(App& app) 912 { 913 /** 914 * Functions triggers appropriate requests on DBus 915 */ 916 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Memory/<str>/") 917 .privileges(redfish::privileges::getMemory) 918 .methods(boost::beast::http::verb::get)( 919 [&app](const crow::Request& req, 920 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 921 const std::string& dimmId) { 922 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 923 { 924 return; 925 } 926 getDimmData(asyncResp, dimmId); 927 }); 928 } 929 930 } // namespace redfish 931