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