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