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