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