xref: /openbmc/bmcweb/redfish-core/lib/memory.hpp (revision 40e9b92ec19acffb46f83a6e55b18974da5d708e)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation
4 #pragma once
5 
6 #include "bmcweb_config.h"
7 
8 #include "app.hpp"
9 #include "dbus_utility.hpp"
10 #include "generated/enums/memory.hpp"
11 #include "generated/enums/resource.hpp"
12 #include "query.hpp"
13 #include "registries/privilege_registry.hpp"
14 #include "utils/collection.hpp"
15 #include "utils/dbus_utils.hpp"
16 #include "utils/hex_utils.hpp"
17 #include "utils/json_utils.hpp"
18 
19 #include <boost/system/error_code.hpp>
20 #include <boost/url/format.hpp>
21 #include <nlohmann/json.hpp>
22 #include <sdbusplus/asio/property.hpp>
23 #include <sdbusplus/unpack_properties.hpp>
24 
25 #include <array>
26 #include <string_view>
27 
28 namespace redfish
29 {
30 
translateMemoryTypeToRedfish(const std::string & memoryType)31 inline std::string translateMemoryTypeToRedfish(const std::string& memoryType)
32 {
33     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR")
34     {
35         return "DDR";
36     }
37     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2")
38     {
39         return "DDR2";
40     }
41     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR3")
42     {
43         return "DDR3";
44     }
45     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4")
46     {
47         return "DDR4";
48     }
49     if (memoryType ==
50         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4E_SDRAM")
51     {
52         return "DDR4E_SDRAM";
53     }
54     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR5")
55     {
56         return "DDR5";
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 ==
74         "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_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     if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM3")
120     {
121         return "HBM3";
122     }
123     // This is values like Other or Unknown
124     // Also D-Bus values:
125     // DRAM
126     // EDRAM
127     // VRAM
128     // SRAM
129     // RAM
130     // FLASH
131     // EEPROM
132     // FEPROM
133     // EPROM
134     // CDRAM
135     // ThreeDRAM
136     // RDRAM
137     // FBD2
138     // LPDDR_SDRAM
139     // LPDDR2_SDRAM
140     // LPDDR5_SDRAM
141     return "";
142 }
143 
dimmPropToHex(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const char * key,const uint16_t * value,const nlohmann::json::json_pointer & jsonPtr)144 inline void dimmPropToHex(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
145                           const char* key, const uint16_t* value,
146                           const nlohmann::json::json_pointer& jsonPtr)
147 {
148     if (value == nullptr)
149     {
150         return;
151     }
152     asyncResp->res.jsonValue[jsonPtr][key] = "0x" + intToHexString(*value, 4);
153 }
154 
getPersistentMemoryProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const dbus::utility::DBusPropertiesMap & properties,const nlohmann::json::json_pointer & jsonPtr)155 inline void getPersistentMemoryProperties(
156     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
157     const dbus::utility::DBusPropertiesMap& properties,
158     const nlohmann::json::json_pointer& jsonPtr)
159 {
160     const uint16_t* moduleManufacturerID = nullptr;
161     const uint16_t* moduleProductID = nullptr;
162     const uint16_t* subsystemVendorID = nullptr;
163     const uint16_t* subsystemDeviceID = nullptr;
164     const uint64_t* volatileRegionSizeLimitInKiB = nullptr;
165     const uint64_t* pmRegionSizeLimitInKiB = nullptr;
166     const uint64_t* volatileSizeInKiB = nullptr;
167     const uint64_t* pmSizeInKiB = nullptr;
168     const uint64_t* cacheSizeInKB = nullptr;
169     const uint64_t* voltaileRegionMaxSizeInKib = nullptr;
170     const uint64_t* pmRegionMaxSizeInKiB = nullptr;
171     const uint64_t* allocationIncrementInKiB = nullptr;
172     const uint64_t* allocationAlignmentInKiB = nullptr;
173     const uint64_t* volatileRegionNumberLimit = nullptr;
174     const uint64_t* pmRegionNumberLimit = nullptr;
175     const uint64_t* spareDeviceCount = nullptr;
176     const bool* isSpareDeviceInUse = nullptr;
177     const bool* isRankSpareEnabled = nullptr;
178     const std::vector<uint32_t>* maxAveragePowerLimitmW = nullptr;
179     const bool* configurationLocked = nullptr;
180     const std::string* allowedMemoryModes = nullptr;
181     const std::string* memoryMedia = nullptr;
182     const bool* configurationLockCapable = nullptr;
183     const bool* dataLockCapable = nullptr;
184     const bool* passphraseCapable = nullptr;
185     const uint64_t* maxPassphraseCount = nullptr;
186     const uint64_t* passphraseLockLimit = nullptr;
187 
188     const bool success = sdbusplus::unpackPropertiesNoThrow(
189         dbus_utils::UnpackErrorPrinter(), properties, "ModuleManufacturerID",
190         moduleManufacturerID, "ModuleProductID", moduleProductID,
191         "SubsystemVendorID", subsystemVendorID, "SubsystemDeviceID",
192         subsystemDeviceID, "VolatileRegionSizeLimitInKiB",
193         volatileRegionSizeLimitInKiB, "PmRegionSizeLimitInKiB",
194         pmRegionSizeLimitInKiB, "VolatileSizeInKiB", volatileSizeInKiB,
195         "PmSizeInKiB", pmSizeInKiB, "CacheSizeInKB", cacheSizeInKB,
196         "VoltaileRegionMaxSizeInKib", voltaileRegionMaxSizeInKib,
197         "PmRegionMaxSizeInKiB", pmRegionMaxSizeInKiB,
198         "AllocationIncrementInKiB", allocationIncrementInKiB,
199         "AllocationAlignmentInKiB", allocationAlignmentInKiB,
200         "VolatileRegionNumberLimit", volatileRegionNumberLimit,
201         "PmRegionNumberLimit", pmRegionNumberLimit, "SpareDeviceCount",
202         spareDeviceCount, "IsSpareDeviceInUse", isSpareDeviceInUse,
203         "IsRankSpareEnabled", isRankSpareEnabled, "MaxAveragePowerLimitmW",
204         maxAveragePowerLimitmW, "ConfigurationLocked", configurationLocked,
205         "AllowedMemoryModes", allowedMemoryModes, "MemoryMedia", memoryMedia,
206         "ConfigurationLockCapable", configurationLockCapable, "DataLockCapable",
207         dataLockCapable, "PassphraseCapable", passphraseCapable,
208         "MaxPassphraseCount", maxPassphraseCount, "PassphraseLockLimit",
209         passphraseLockLimit);
210 
211     if (!success)
212     {
213         messages::internalError(asyncResp->res);
214         return;
215     }
216 
217     dimmPropToHex(asyncResp, "ModuleManufacturerID", moduleManufacturerID,
218                   jsonPtr);
219     dimmPropToHex(asyncResp, "ModuleProductID", moduleProductID, jsonPtr);
220     dimmPropToHex(asyncResp, "MemorySubsystemControllerManufacturerID",
221                   subsystemVendorID, jsonPtr);
222     dimmPropToHex(asyncResp, "MemorySubsystemControllerProductID",
223                   subsystemDeviceID, jsonPtr);
224 
225     if (volatileRegionSizeLimitInKiB != nullptr)
226     {
227         asyncResp->res.jsonValue[jsonPtr]["VolatileRegionSizeLimitMiB"] =
228             (*volatileRegionSizeLimitInKiB) >> 10;
229     }
230 
231     if (pmRegionSizeLimitInKiB != nullptr)
232     {
233         asyncResp->res.jsonValue[jsonPtr]["PersistentRegionSizeLimitMiB"] =
234             (*pmRegionSizeLimitInKiB) >> 10;
235     }
236 
237     if (volatileSizeInKiB != nullptr)
238     {
239         asyncResp->res.jsonValue[jsonPtr]["VolatileSizeMiB"] =
240             (*volatileSizeInKiB) >> 10;
241     }
242 
243     if (pmSizeInKiB != nullptr)
244     {
245         asyncResp->res.jsonValue[jsonPtr]["NonVolatileSizeMiB"] =
246             (*pmSizeInKiB) >> 10;
247     }
248 
249     if (cacheSizeInKB != nullptr)
250     {
251         asyncResp->res.jsonValue[jsonPtr]["CacheSizeMiB"] =
252             (*cacheSizeInKB >> 10);
253     }
254 
255     if (voltaileRegionMaxSizeInKib != nullptr)
256     {
257         asyncResp->res.jsonValue[jsonPtr]["VolatileRegionSizeMaxMiB"] =
258             (*voltaileRegionMaxSizeInKib) >> 10;
259     }
260 
261     if (pmRegionMaxSizeInKiB != nullptr)
262     {
263         asyncResp->res.jsonValue[jsonPtr]["PersistentRegionSizeMaxMiB"] =
264             (*pmRegionMaxSizeInKiB) >> 10;
265     }
266 
267     if (allocationIncrementInKiB != nullptr)
268     {
269         asyncResp->res.jsonValue[jsonPtr]["AllocationIncrementMiB"] =
270             (*allocationIncrementInKiB) >> 10;
271     }
272 
273     if (allocationAlignmentInKiB != nullptr)
274     {
275         asyncResp->res.jsonValue[jsonPtr]["AllocationAlignmentMiB"] =
276             (*allocationAlignmentInKiB) >> 10;
277     }
278 
279     if (volatileRegionNumberLimit != nullptr)
280     {
281         asyncResp->res.jsonValue[jsonPtr]["VolatileRegionNumberLimit"] =
282             *volatileRegionNumberLimit;
283     }
284 
285     if (pmRegionNumberLimit != nullptr)
286     {
287         asyncResp->res.jsonValue[jsonPtr]["PersistentRegionNumberLimit"] =
288             *pmRegionNumberLimit;
289     }
290 
291     if (spareDeviceCount != nullptr)
292     {
293         asyncResp->res.jsonValue[jsonPtr]["SpareDeviceCount"] =
294             *spareDeviceCount;
295     }
296 
297     if (isSpareDeviceInUse != nullptr)
298     {
299         asyncResp->res.jsonValue[jsonPtr]["IsSpareDeviceEnabled"] =
300             *isSpareDeviceInUse;
301     }
302 
303     if (isRankSpareEnabled != nullptr)
304     {
305         asyncResp->res.jsonValue[jsonPtr]["IsRankSpareEnabled"] =
306             *isRankSpareEnabled;
307     }
308 
309     if (maxAveragePowerLimitmW != nullptr)
310     {
311         asyncResp->res.jsonValue[jsonPtr]["MaxTDPMilliWatts"] =
312             *maxAveragePowerLimitmW;
313     }
314 
315     if (configurationLocked != nullptr)
316     {
317         asyncResp->res.jsonValue[jsonPtr]["ConfigurationLocked"] =
318             *configurationLocked;
319     }
320 
321     if (allowedMemoryModes != nullptr)
322     {
323         constexpr const std::array<const char*, 3> values{"Volatile", "PMEM",
324                                                           "Block"};
325 
326         for (const char* v : values)
327         {
328             if (allowedMemoryModes->ends_with(v))
329             {
330                 asyncResp->res.jsonValue[jsonPtr]["OperatingMemoryModes"]
331                     .push_back(v);
332                 break;
333             }
334         }
335     }
336 
337     if (memoryMedia != nullptr)
338     {
339         constexpr const std::array<const char*, 3> values{"DRAM", "NAND",
340                                                           "Intel3DXPoint"};
341 
342         for (const char* v : values)
343         {
344             if (memoryMedia->ends_with(v))
345             {
346                 asyncResp->res.jsonValue[jsonPtr]["MemoryMedia"].push_back(v);
347                 break;
348             }
349         }
350     }
351 
352     if (configurationLockCapable != nullptr)
353     {
354         asyncResp->res.jsonValue[jsonPtr]["SecurityCapabilities"]
355                                 ["ConfigurationLockCapable"] =
356             *configurationLockCapable;
357     }
358 
359     if (dataLockCapable != nullptr)
360     {
361         asyncResp->res
362             .jsonValue[jsonPtr]["SecurityCapabilities"]["DataLockCapable"] =
363             *dataLockCapable;
364     }
365 
366     if (passphraseCapable != nullptr)
367     {
368         asyncResp->res
369             .jsonValue[jsonPtr]["SecurityCapabilities"]["PassphraseCapable"] =
370             *passphraseCapable;
371     }
372 
373     if (maxPassphraseCount != nullptr)
374     {
375         asyncResp->res
376             .jsonValue[jsonPtr]["SecurityCapabilities"]["MaxPassphraseCount"] =
377             *maxPassphraseCount;
378     }
379 
380     if (passphraseLockLimit != nullptr)
381     {
382         asyncResp->res
383             .jsonValue[jsonPtr]["SecurityCapabilities"]["PassphraseLockLimit"] =
384             *passphraseLockLimit;
385     }
386 }
387 
assembleDimmProperties(std::string_view dimmId,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const dbus::utility::DBusPropertiesMap & properties,const nlohmann::json::json_pointer & jsonPtr)388 inline void assembleDimmProperties(
389     std::string_view dimmId,
390     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
391     const dbus::utility::DBusPropertiesMap& properties,
392     const nlohmann::json::json_pointer& jsonPtr)
393 {
394     asyncResp->res.jsonValue[jsonPtr]["Id"] = dimmId;
395     asyncResp->res.jsonValue[jsonPtr]["Name"] = "DIMM Slot";
396     asyncResp->res.jsonValue[jsonPtr]["Status"]["State"] =
397         resource::State::Enabled;
398     asyncResp->res.jsonValue[jsonPtr]["Status"]["Health"] =
399         resource::Health::OK;
400 
401     const uint16_t* memoryDataWidth = nullptr;
402     const size_t* memorySizeInKB = nullptr;
403     const std::string* partNumber = nullptr;
404     const std::string* serialNumber = nullptr;
405     const std::string* manufacturer = nullptr;
406     const uint16_t* revisionCode = nullptr;
407     const bool* present = nullptr;
408     const uint16_t* memoryTotalWidth = nullptr;
409     const std::string* ecc = nullptr;
410     const std::string* formFactor = nullptr;
411     const std::vector<uint16_t>* allowedSpeedsMT = nullptr;
412     const size_t* memoryAttributes = nullptr;
413     const uint16_t* memoryConfiguredSpeedInMhz = nullptr;
414     const std::string* memoryType = nullptr;
415     const std::uint8_t* channel = nullptr;
416     const std::uint8_t* memoryController = nullptr;
417     const std::uint8_t* slot = nullptr;
418     const std::uint8_t* socket = nullptr;
419     const std::string* sparePartNumber = nullptr;
420     const std::string* model = nullptr;
421     const std::string* locationCode = nullptr;
422 
423     const bool success = sdbusplus::unpackPropertiesNoThrow(
424         dbus_utils::UnpackErrorPrinter(), properties, "MemoryDataWidth",
425         memoryDataWidth, "MemorySizeInKB", memorySizeInKB, "PartNumber",
426         partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
427         "RevisionCode", revisionCode, "Present", present, "MemoryTotalWidth",
428         memoryTotalWidth, "ECC", ecc, "FormFactor", formFactor,
429         "AllowedSpeedsMT", allowedSpeedsMT, "MemoryAttributes",
430         memoryAttributes, "MemoryConfiguredSpeedInMhz",
431         memoryConfiguredSpeedInMhz, "MemoryType", memoryType, "Channel",
432         channel, "MemoryController", memoryController, "Slot", slot, "Socket",
433         socket, "SparePartNumber", sparePartNumber, "Model", model,
434         "LocationCode", locationCode);
435 
436     if (!success)
437     {
438         messages::internalError(asyncResp->res);
439         return;
440     }
441 
442     if (memoryDataWidth != nullptr)
443     {
444         asyncResp->res.jsonValue[jsonPtr]["DataWidthBits"] = *memoryDataWidth;
445     }
446 
447     if (memorySizeInKB != nullptr)
448     {
449         asyncResp->res.jsonValue[jsonPtr]["CapacityMiB"] =
450             (*memorySizeInKB >> 10);
451     }
452 
453     if (partNumber != nullptr)
454     {
455         asyncResp->res.jsonValue[jsonPtr]["PartNumber"] = *partNumber;
456     }
457 
458     if (serialNumber != nullptr)
459     {
460         asyncResp->res.jsonValue[jsonPtr]["SerialNumber"] = *serialNumber;
461     }
462 
463     if (manufacturer != nullptr)
464     {
465         asyncResp->res.jsonValue[jsonPtr]["Manufacturer"] = *manufacturer;
466     }
467 
468     if (revisionCode != nullptr)
469     {
470         asyncResp->res.jsonValue[jsonPtr]["FirmwareRevision"] =
471             std::to_string(*revisionCode);
472     }
473 
474     if (present != nullptr && !*present)
475     {
476         asyncResp->res.jsonValue[jsonPtr]["Status"]["State"] =
477             resource::State::Absent;
478     }
479 
480     if (memoryTotalWidth != nullptr)
481     {
482         asyncResp->res.jsonValue[jsonPtr]["BusWidthBits"] = *memoryTotalWidth;
483     }
484 
485     if (ecc != nullptr)
486     {
487         constexpr const std::array<const char*, 4> values{
488             "NoECC", "SingleBitECC", "MultiBitECC", "AddressParity"};
489 
490         for (const char* v : values)
491         {
492             if (ecc->ends_with(v))
493             {
494                 asyncResp->res.jsonValue[jsonPtr]["ErrorCorrection"] = v;
495                 break;
496             }
497         }
498     }
499 
500     if (formFactor != nullptr)
501     {
502         constexpr const std::array<const char*, 11> values{
503             "RDIMM",       "UDIMM",       "SO_DIMM",      "LRDIMM",
504             "Mini_RDIMM",  "Mini_UDIMM",  "SO_RDIMM_72b", "SO_UDIMM_72b",
505             "SO_DIMM_16b", "SO_DIMM_32b", "Die"};
506 
507         for (const char* v : values)
508         {
509             if (formFactor->ends_with(v))
510             {
511                 asyncResp->res.jsonValue[jsonPtr]["BaseModuleType"] = v;
512                 break;
513             }
514         }
515     }
516 
517     if (allowedSpeedsMT != nullptr)
518     {
519         nlohmann::json& jValue =
520             asyncResp->res.jsonValue[jsonPtr]["AllowedSpeedsMHz"];
521         jValue = nlohmann::json::array();
522         for (uint16_t subVal : *allowedSpeedsMT)
523         {
524             jValue.push_back(subVal);
525         }
526     }
527 
528     if (memoryAttributes != nullptr)
529     {
530         asyncResp->res.jsonValue[jsonPtr]["RankCount"] = *memoryAttributes;
531     }
532 
533     if (memoryConfiguredSpeedInMhz != nullptr)
534     {
535         asyncResp->res.jsonValue[jsonPtr]["OperatingSpeedMhz"] =
536             *memoryConfiguredSpeedInMhz;
537     }
538 
539     if (memoryType != nullptr)
540     {
541         std::string memoryDeviceType =
542             translateMemoryTypeToRedfish(*memoryType);
543         // Values like "Unknown" or "Other" will return empty
544         // so just leave off
545         if (!memoryDeviceType.empty())
546         {
547             asyncResp->res.jsonValue[jsonPtr]["MemoryDeviceType"] =
548                 memoryDeviceType;
549         }
550         if (memoryType->find("DDR") != std::string::npos)
551         {
552             asyncResp->res.jsonValue[jsonPtr]["MemoryType"] =
553                 memory::MemoryType::DRAM;
554         }
555         else if (memoryType->ends_with("Logical"))
556         {
557             asyncResp->res.jsonValue[jsonPtr]["MemoryType"] =
558                 memory::MemoryType::IntelOptane;
559         }
560     }
561 
562     if (channel != nullptr)
563     {
564         asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Channel"] =
565             *channel;
566     }
567 
568     if (memoryController != nullptr)
569     {
570         asyncResp->res
571             .jsonValue[jsonPtr]["MemoryLocation"]["MemoryController"] =
572             *memoryController;
573     }
574 
575     if (slot != nullptr)
576     {
577         asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Slot"] = *slot;
578     }
579 
580     if (socket != nullptr)
581     {
582         asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Socket"] = *socket;
583     }
584 
585     if (sparePartNumber != nullptr)
586     {
587         asyncResp->res.jsonValue[jsonPtr]["SparePartNumber"] = *sparePartNumber;
588     }
589 
590     if (model != nullptr)
591     {
592         asyncResp->res.jsonValue[jsonPtr]["Model"] = *model;
593     }
594 
595     if (locationCode != nullptr)
596     {
597         asyncResp->res
598             .jsonValue[jsonPtr]["Location"]["PartLocation"]["ServiceLabel"] =
599             *locationCode;
600     }
601 
602     getPersistentMemoryProperties(asyncResp, properties, jsonPtr);
603 }
604 
getDimmDataByService(std::shared_ptr<bmcweb::AsyncResp> asyncResp,const std::string & dimmId,const std::string & service,const std::string & objPath)605 inline void getDimmDataByService(
606     std::shared_ptr<bmcweb::AsyncResp> asyncResp, const std::string& dimmId,
607     const std::string& service, const std::string& objPath)
608 {
609     BMCWEB_LOG_DEBUG("Get available system components.");
610     dbus::utility::getAllProperties(
611         service, objPath, "",
612         [dimmId, asyncResp{std::move(asyncResp)}](
613             const boost::system::error_code& ec,
614             const dbus::utility::DBusPropertiesMap& properties) {
615             if (ec)
616             {
617                 BMCWEB_LOG_DEBUG("DBUS response error");
618                 messages::internalError(asyncResp->res);
619                 return;
620             }
621             assembleDimmProperties(dimmId, asyncResp, properties,
622                                    ""_json_pointer);
623         });
624 }
625 
assembleDimmPartitionData(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const dbus::utility::DBusPropertiesMap & properties,const nlohmann::json::json_pointer & regionPtr)626 inline void assembleDimmPartitionData(
627     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
628     const dbus::utility::DBusPropertiesMap& properties,
629     const nlohmann::json::json_pointer& regionPtr)
630 {
631     const std::string* memoryClassification = nullptr;
632     const uint64_t* offsetInKiB = nullptr;
633     const std::string* partitionId = nullptr;
634     const bool* passphraseState = nullptr;
635     const uint64_t* sizeInKiB = nullptr;
636 
637     const bool success = sdbusplus::unpackPropertiesNoThrow(
638         dbus_utils::UnpackErrorPrinter(), properties, "MemoryClassification",
639         memoryClassification, "OffsetInKiB", offsetInKiB, "PartitionId",
640         partitionId, "PassphraseState", passphraseState, "SizeInKiB",
641         sizeInKiB);
642 
643     if (!success)
644     {
645         messages::internalError(asyncResp->res);
646         return;
647     }
648 
649     nlohmann::json::object_t partition;
650 
651     if (memoryClassification != nullptr)
652     {
653         partition["MemoryClassification"] = *memoryClassification;
654     }
655 
656     if (offsetInKiB != nullptr)
657     {
658         partition["OffsetMiB"] = (*offsetInKiB >> 10);
659     }
660 
661     if (partitionId != nullptr)
662     {
663         partition["RegionId"] = *partitionId;
664     }
665 
666     if (passphraseState != nullptr)
667     {
668         partition["PassphraseEnabled"] = *passphraseState;
669     }
670 
671     if (sizeInKiB != nullptr)
672     {
673         partition["SizeMiB"] = (*sizeInKiB >> 10);
674     }
675 
676     asyncResp->res.jsonValue[regionPtr].emplace_back(std::move(partition));
677 }
678 
getDimmPartitionData(std::shared_ptr<bmcweb::AsyncResp> asyncResp,const std::string & service,const std::string & path)679 inline void getDimmPartitionData(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
680                                  const std::string& service,
681                                  const std::string& path)
682 {
683     dbus::utility::getAllProperties(
684         service, path,
685         "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition",
686         [asyncResp{std::move(asyncResp)}](
687             const boost::system::error_code& ec,
688             const dbus::utility::DBusPropertiesMap& properties) {
689             if (ec)
690             {
691                 BMCWEB_LOG_DEBUG("DBUS response error");
692                 messages::internalError(asyncResp->res);
693 
694                 return;
695             }
696             nlohmann::json::json_pointer regionPtr = "/Regions"_json_pointer;
697             assembleDimmPartitionData(asyncResp, properties, regionPtr);
698         }
699 
700     );
701 }
702 
getDimmData(std::shared_ptr<bmcweb::AsyncResp> asyncResp,const std::string & dimmId)703 inline void getDimmData(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
704                         const std::string& dimmId)
705 {
706     BMCWEB_LOG_DEBUG("Get available system dimm resources.");
707     constexpr std::array<std::string_view, 2> dimmInterfaces = {
708         "xyz.openbmc_project.Inventory.Item.Dimm",
709         "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"};
710     dbus::utility::getSubTree(
711         "/xyz/openbmc_project/inventory", 0, dimmInterfaces,
712         [dimmId, asyncResp{std::move(asyncResp)}](
713             const boost::system::error_code& ec,
714             const dbus::utility::MapperGetSubTreeResponse& subtree) {
715             if (ec)
716             {
717                 BMCWEB_LOG_DEBUG("DBUS response error");
718                 messages::internalError(asyncResp->res);
719 
720                 return;
721             }
722             bool found = false;
723             for (const auto& [rawPath, object] : subtree)
724             {
725                 sdbusplus::message::object_path path(rawPath);
726                 for (const auto& [service, interfaces] : object)
727                 {
728                     for (const auto& interface : interfaces)
729                     {
730                         if (interface ==
731                                 "xyz.openbmc_project.Inventory.Item.Dimm" &&
732                             path.filename() == dimmId)
733                         {
734                             getDimmDataByService(asyncResp, dimmId, service,
735                                                  rawPath);
736                             found = true;
737                         }
738 
739                         // partitions are separate as there can be multiple
740                         // per
741                         // device, i.e.
742                         // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1
743                         // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2
744                         if (interface ==
745                                 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" &&
746                             path.parent_path().filename() == dimmId)
747                         {
748                             getDimmPartitionData(asyncResp, service, rawPath);
749                         }
750                     }
751                 }
752             }
753             // Object not found
754             if (!found)
755             {
756                 messages::resourceNotFound(asyncResp->res, "Memory", dimmId);
757                 return;
758             }
759             // Set @odata only if object is found
760             asyncResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory";
761             asyncResp->res.jsonValue["@odata.id"] =
762                 boost::urls::format("/redfish/v1/Systems/{}/Memory/{}",
763                                     BMCWEB_REDFISH_SYSTEM_URI_NAME, dimmId);
764             return;
765         });
766 }
767 
requestRoutesMemoryCollection(App & app)768 inline void requestRoutesMemoryCollection(App& app)
769 {
770     /**
771      * Functions triggers appropriate requests on DBus
772      */
773     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/")
774         .privileges(redfish::privileges::getMemoryCollection)
775         .methods(boost::beast::http::verb::get)(
776             [&app](const crow::Request& req,
777                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
778                    const std::string& systemName) {
779                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
780                 {
781                     return;
782                 }
783                 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
784                 {
785                     // Option currently returns no systems.  TBD
786                     messages::resourceNotFound(asyncResp->res, "ComputerSystem",
787                                                systemName);
788                     return;
789                 }
790                 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
791                 {
792                     messages::resourceNotFound(asyncResp->res, "ComputerSystem",
793                                                systemName);
794                     return;
795                 }
796 
797                 asyncResp->res.jsonValue["@odata.type"] =
798                     "#MemoryCollection.MemoryCollection";
799                 asyncResp->res.jsonValue["Name"] = "Memory Module Collection";
800                 asyncResp->res.jsonValue["@odata.id"] =
801                     boost::urls::format("/redfish/v1/Systems/{}/Memory",
802                                         BMCWEB_REDFISH_SYSTEM_URI_NAME);
803 
804                 constexpr std::array<std::string_view, 1> interfaces{
805                     "xyz.openbmc_project.Inventory.Item.Dimm"};
806                 collection_util::getCollectionMembers(
807                     asyncResp,
808                     boost::urls::format("/redfish/v1/Systems/{}/Memory",
809                                         BMCWEB_REDFISH_SYSTEM_URI_NAME),
810                     interfaces, "/xyz/openbmc_project/inventory");
811             });
812 }
813 
requestRoutesMemory(App & app)814 inline void requestRoutesMemory(App& app)
815 {
816     /**
817      * Functions triggers appropriate requests on DBus
818      */
819     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Memory/<str>/")
820         .privileges(redfish::privileges::getMemory)
821         .methods(boost::beast::http::verb::get)(
822             [&app](const crow::Request& req,
823                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
824                    const std::string& systemName, const std::string& dimmId) {
825                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
826                 {
827                     return;
828                 }
829 
830                 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
831                 {
832                     // Option currently returns no systems.  TBD
833                     messages::resourceNotFound(asyncResp->res, "ComputerSystem",
834                                                systemName);
835                     return;
836                 }
837 
838                 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
839                 {
840                     messages::resourceNotFound(asyncResp->res, "ComputerSystem",
841                                                systemName);
842                     return;
843                 }
844 
845                 getDimmData(asyncResp, dimmId);
846             });
847 }
848 
849 } // namespace redfish
850