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