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