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 472 return; 473 } 474 if (*memorySize == 0) 475 { 476 // Slot is not populated, set status end return 477 aResp->res.jsonValue["Status"]["State"] = "Absent"; 478 aResp->res.jsonValue["Status"]["Health"] = "OK"; 479 // HTTP Code will be set up automatically, just return 480 return; 481 } 482 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10); 483 } 484 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 485 aResp->res.jsonValue["Status"]["Health"] = "OK"; 486 487 for (const auto& property : properties) 488 { 489 if (property.first == "MemoryDataWidth") 490 { 491 const uint16_t* value = 492 std::get_if<uint16_t>(&property.second); 493 if (value == nullptr) 494 { 495 continue; 496 } 497 aResp->res.jsonValue["DataWidthBits"] = *value; 498 } 499 else if (property.first == "PartNumber") 500 { 501 const std::string* value = 502 std::get_if<std::string>(&property.second); 503 if (value == nullptr) 504 { 505 continue; 506 } 507 aResp->res.jsonValue["PartNumber"] = *value; 508 } 509 else if (property.first == "SerialNumber") 510 { 511 const std::string* value = 512 std::get_if<std::string>(&property.second); 513 if (value == nullptr) 514 { 515 continue; 516 } 517 aResp->res.jsonValue["SerialNumber"] = *value; 518 } 519 else if (property.first == "Manufacturer") 520 { 521 const std::string* value = 522 std::get_if<std::string>(&property.second); 523 if (value == nullptr) 524 { 525 continue; 526 } 527 aResp->res.jsonValue["Manufacturer"] = *value; 528 } 529 else if (property.first == "RevisionCode") 530 { 531 const uint16_t* value = 532 std::get_if<uint16_t>(&property.second); 533 534 if (value == nullptr) 535 { 536 messages::internalError(aResp->res); 537 BMCWEB_LOG_DEBUG 538 << "Invalid property type for RevisionCode"; 539 continue; 540 } 541 aResp->res.jsonValue["FirmwareRevision"] = 542 std::to_string(*value); 543 } 544 else if (property.first == "MemoryTotalWidth") 545 { 546 const uint16_t* value = 547 std::get_if<uint16_t>(&property.second); 548 if (value == nullptr) 549 { 550 continue; 551 } 552 aResp->res.jsonValue["BusWidthBits"] = *value; 553 } 554 else if (property.first == "ECC") 555 { 556 const std::string* value = 557 std::get_if<std::string>(&property.second); 558 if (value == nullptr) 559 { 560 messages::internalError(aResp->res); 561 BMCWEB_LOG_DEBUG << "Invalid property type for ECC"; 562 continue; 563 } 564 constexpr const std::array<const char*, 4> values{ 565 "NoECC", "SingleBitECC", "MultiBitECC", 566 "AddressParity"}; 567 568 for (const char* v : values) 569 { 570 if (boost::ends_with(*value, v)) 571 { 572 aResp->res.jsonValue["ErrorCorrection"] = v; 573 break; 574 } 575 } 576 } 577 else if (property.first == "FormFactor") 578 { 579 const std::string* value = 580 std::get_if<std::string>(&property.second); 581 if (value == nullptr) 582 { 583 messages::internalError(aResp->res); 584 BMCWEB_LOG_DEBUG 585 << "Invalid property type for FormFactor"; 586 continue; 587 } 588 constexpr const std::array<const char*, 11> values{ 589 "RDIMM", "UDIMM", "SO_DIMM", 590 "LRDIMM", "Mini_RDIMM", "Mini_UDIMM", 591 "SO_RDIMM_72b", "SO_UDIMM_72b", "SO_DIMM_16b", 592 "SO_DIMM_32b", "Die"}; 593 594 for (const char* v : values) 595 { 596 if (boost::ends_with(*value, v)) 597 { 598 aResp->res.jsonValue["BaseModuleType"] = v; 599 break; 600 } 601 } 602 } 603 else if (property.first == "AllowedSpeedsMT") 604 { 605 const std::vector<uint16_t>* value = 606 std::get_if<std::vector<uint16_t>>(&property.second); 607 if (value == nullptr) 608 { 609 continue; 610 } 611 nlohmann::json& jValue = 612 aResp->res.jsonValue["AllowedSpeedsMHz"]; 613 jValue = nlohmann::json::array(); 614 for (uint16_t subVal : *value) 615 { 616 jValue.push_back(subVal); 617 } 618 } 619 else if (property.first == "MemoryAttributes") 620 { 621 const uint8_t* value = 622 std::get_if<uint8_t>(&property.second); 623 624 if (value == nullptr) 625 { 626 messages::internalError(aResp->res); 627 BMCWEB_LOG_DEBUG 628 << "Invalid property type for MemoryAttributes"; 629 continue; 630 } 631 aResp->res.jsonValue["RankCount"] = 632 static_cast<uint64_t>(*value); 633 } 634 else if (property.first == "MemoryConfiguredSpeedInMhz") 635 { 636 const uint16_t* value = 637 std::get_if<uint16_t>(&property.second); 638 if (value == nullptr) 639 { 640 continue; 641 } 642 aResp->res.jsonValue["OperatingSpeedMhz"] = *value; 643 } 644 else if (property.first == "MemoryType") 645 { 646 const auto* value = 647 std::get_if<std::string>(&property.second); 648 if (value != nullptr) 649 { 650 std::string memoryDeviceType = 651 translateMemoryTypeToRedfish(*value); 652 // Values like "Unknown" or "Other" will return empty 653 // so just leave off 654 if (!memoryDeviceType.empty()) 655 { 656 aResp->res.jsonValue["MemoryDeviceType"] = 657 memoryDeviceType; 658 } 659 if (value->find("DDR") != std::string::npos) 660 { 661 aResp->res.jsonValue["MemoryType"] = "DRAM"; 662 } 663 else if (boost::ends_with(*value, "Logical")) 664 { 665 aResp->res.jsonValue["MemoryType"] = "IntelOptane"; 666 } 667 } 668 } 669 // memory location interface 670 else if (property.first == "Channel" || 671 property.first == "MemoryController" || 672 property.first == "Slot" || property.first == "Socket") 673 { 674 const std::string* value = 675 std::get_if<std::string>(&property.second); 676 if (value == nullptr) 677 { 678 messages::internalError(aResp->res); 679 continue; 680 } 681 aResp->res.jsonValue["MemoryLocation"][property.first] = 682 *value; 683 } 684 else 685 { 686 getPersistentMemoryProperties(aResp, properties); 687 } 688 } 689 }, 690 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", ""); 691 } 692 693 inline void getDimmPartitionData(std::shared_ptr<AsyncResp> aResp, 694 const std::string& service, 695 const std::string& path) 696 { 697 crow::connections::systemBus->async_method_call( 698 [aResp{std::move(aResp)}]( 699 const boost::system::error_code ec, 700 const boost::container::flat_map< 701 std::string, std::variant<std::string, uint64_t, uint32_t, 702 bool>>& properties) { 703 if (ec) 704 { 705 BMCWEB_LOG_DEBUG << "DBUS response error"; 706 messages::internalError(aResp->res); 707 708 return; 709 } 710 711 nlohmann::json& partition = 712 aResp->res.jsonValue["Regions"].emplace_back( 713 nlohmann::json::object()); 714 for (const auto& [key, val] : properties) 715 { 716 if (key == "MemoryClassification") 717 { 718 const std::string* value = std::get_if<std::string>(&val); 719 if (value == nullptr) 720 { 721 messages::internalError(aResp->res); 722 continue; 723 } 724 partition[key] = *value; 725 } 726 else if (key == "OffsetInKiB") 727 { 728 const uint64_t* value = std::get_if<uint64_t>(&val); 729 if (value == nullptr) 730 { 731 messages::internalError(aResp->res); 732 continue; 733 } 734 735 partition["OffsetMiB"] = (*value >> 10); 736 } 737 else if (key == "PartitionId") 738 { 739 const std::string* value = std::get_if<std::string>(&val); 740 if (value == nullptr) 741 { 742 messages::internalError(aResp->res); 743 continue; 744 } 745 partition["RegionId"] = *value; 746 } 747 748 else if (key == "PassphraseState") 749 { 750 const bool* value = std::get_if<bool>(&val); 751 if (value == nullptr) 752 { 753 messages::internalError(aResp->res); 754 continue; 755 } 756 partition["PassphraseEnabled"] = *value; 757 } 758 else if (key == "SizeInKiB") 759 { 760 const uint64_t* value = std::get_if<uint64_t>(&val); 761 if (value == nullptr) 762 { 763 messages::internalError(aResp->res); 764 BMCWEB_LOG_DEBUG 765 << "Invalid property type for SizeInKiB"; 766 continue; 767 } 768 partition["SizeMiB"] = (*value >> 10); 769 } 770 } 771 }, 772 773 service, path, "org.freedesktop.DBus.Properties", "GetAll", 774 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"); 775 } 776 777 inline void getDimmData(std::shared_ptr<AsyncResp> aResp, 778 const std::string& dimmId) 779 { 780 BMCWEB_LOG_DEBUG << "Get available system dimm resources."; 781 crow::connections::systemBus->async_method_call( 782 [dimmId, aResp{std::move(aResp)}]( 783 const boost::system::error_code ec, 784 const boost::container::flat_map< 785 std::string, boost::container::flat_map< 786 std::string, std::vector<std::string>>>& 787 subtree) { 788 if (ec) 789 { 790 BMCWEB_LOG_DEBUG << "DBUS response error"; 791 messages::internalError(aResp->res); 792 793 return; 794 } 795 bool found = false; 796 for (const auto& [path, object] : subtree) 797 { 798 if (path.find(dimmId) != std::string::npos) 799 { 800 for (const auto& [service, interfaces] : object) 801 { 802 if (!found && 803 (std::find( 804 interfaces.begin(), interfaces.end(), 805 "xyz.openbmc_project.Inventory.Item.Dimm") != 806 interfaces.end())) 807 { 808 getDimmDataByService(aResp, dimmId, service, path); 809 found = true; 810 } 811 812 // partitions are separate as there can be multiple per 813 // device, i.e. 814 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1 815 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2 816 if (std::find(interfaces.begin(), interfaces.end(), 817 "xyz.openbmc_project.Inventory.Item." 818 "PersistentMemory.Partition") != 819 interfaces.end()) 820 { 821 getDimmPartitionData(aResp, service, path); 822 } 823 } 824 } 825 } 826 // Object not found 827 if (!found) 828 { 829 messages::resourceNotFound(aResp->res, "Memory", dimmId); 830 } 831 return; 832 }, 833 "xyz.openbmc_project.ObjectMapper", 834 "/xyz/openbmc_project/object_mapper", 835 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 836 "/xyz/openbmc_project/inventory", 0, 837 std::array<const char*, 2>{ 838 "xyz.openbmc_project.Inventory.Item.Dimm", 839 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"}); 840 } 841 842 class MemoryCollection : public Node 843 { 844 public: 845 /* 846 * Default Constructor 847 */ 848 MemoryCollection(App& app) : Node(app, "/redfish/v1/Systems/system/Memory/") 849 { 850 entityPrivileges = { 851 {boost::beast::http::verb::get, {{"Login"}}}, 852 {boost::beast::http::verb::head, {{"Login"}}}, 853 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 854 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 855 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 856 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 857 } 858 859 private: 860 /** 861 * Functions triggers appropriate requests on DBus 862 */ 863 void doGet(crow::Response& res, const crow::Request&, 864 const std::vector<std::string>&) override 865 { 866 res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection"; 867 res.jsonValue["Name"] = "Memory Module Collection"; 868 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Memory"; 869 auto asyncResp = std::make_shared<AsyncResp>(res); 870 871 collection_util::getCollectionMembers( 872 asyncResp, "/redfish/v1/Systems/system/Memory", 873 {"xyz.openbmc_project.Inventory.Item.Dimm"}); 874 } 875 }; 876 877 class Memory : public Node 878 { 879 public: 880 /* 881 * Default Constructor 882 */ 883 Memory(App& app) : 884 Node(app, "/redfish/v1/Systems/system/Memory/<str>/", std::string()) 885 { 886 entityPrivileges = { 887 {boost::beast::http::verb::get, {{"Login"}}}, 888 {boost::beast::http::verb::head, {{"Login"}}}, 889 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 890 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 891 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 892 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 893 } 894 895 private: 896 /** 897 * Functions triggers appropriate requests on DBus 898 */ 899 void doGet(crow::Response& res, const crow::Request&, 900 const std::vector<std::string>& params) override 901 { 902 // Check if there is required param, truly entering this shall be 903 // impossible 904 if (params.size() != 1) 905 { 906 messages::internalError(res); 907 res.end(); 908 return; 909 } 910 const std::string& dimmId = params[0]; 911 912 res.jsonValue["@odata.type"] = "#Memory.v1_7_0.Memory"; 913 res.jsonValue["@odata.id"] = 914 "/redfish/v1/Systems/system/Memory/" + dimmId; 915 auto asyncResp = std::make_shared<AsyncResp>(res); 916 917 getDimmData(asyncResp, dimmId); 918 } 919 }; 920 921 } // namespace redfish 922