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