blob: aaff47399e5f6d2e31c534a273a542d643948400 [file] [log] [blame]
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +02001/*
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
James Feist35e257a2020-06-05 13:30:51 -070018#include "health.hpp"
19
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +020020#include <boost/container/flat_map.hpp>
James Feistc50e7c62020-07-27 15:39:36 -070021#include <boost/format.hpp>
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +020022#include <node.hpp>
Gunnar Mills116bcc52020-10-14 15:23:42 -050023#include <utils/collection.hpp>
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +020024#include <utils/json_utils.hpp>
25
26namespace redfish
27{
28
James Feistc50e7c62020-07-27 15:39:36 -070029using DimmProperty =
30 std::variant<std::string, std::vector<uint32_t>, std::vector<uint16_t>,
31 uint64_t, uint32_t, uint16_t, uint8_t, bool>;
32
33using DimmProperties = boost::container::flat_map<std::string, DimmProperty>;
34
Gunnar Mills313efb12020-10-26 16:05:08 -050035inline std::string translateMemoryTypeToRedfish(const std::string& memoryType)
36{
37 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR")
38 {
39 return "DDR";
40 }
41 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2")
42 {
43 return "DDR2";
44 }
45 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR3")
46 {
47 return "DDR3";
48 }
49 if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4")
50 {
51 return "DDR4";
52 }
53 if (memoryType ==
54 "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4E_SDRAM")
55 {
56 return "DDR4E_SDRAM";
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 == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_"
74 "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 // This is values like Other or Unknown
120 // Also D-Bus values:
121 // DRAM
122 // EDRAM
123 // VRAM
124 // SRAM
125 // RAM
126 // FLASH
127 // EEPROM
128 // FEPROM
129 // EPROM
130 // CDRAM
131 // ThreeDRAM
132 // RDRAM
133 // FBD2
134 // LPDDR_SDRAM
135 // LPDDR2_SDRAM
136 return "";
137}
138
Ed Tanousb5a76932020-09-29 16:16:58 -0700139inline void dimmPropToHex(const std::shared_ptr<AsyncResp>& aResp,
140 const char* key,
Ed Tanous80789c82020-08-19 09:19:09 -0700141 const std::pair<std::string, DimmProperty>& property)
James Feistc50e7c62020-07-27 15:39:36 -0700142{
143 const uint16_t* value = std::get_if<uint16_t>(&property.second);
144 if (value == nullptr)
145 {
146 messages::internalError(aResp->res);
147 BMCWEB_LOG_DEBUG << "Invalid property type for " << property.first;
148 return;
149 }
150
151 aResp->res.jsonValue[key] = (boost::format("0x%04x") % *value).str();
152}
153
Ed Tanousb5a76932020-09-29 16:16:58 -0700154inline void
155 getPersistentMemoryProperties(const std::shared_ptr<AsyncResp>& aResp,
156 const DimmProperties& properties)
James Feistc50e7c62020-07-27 15:39:36 -0700157{
158 for (const auto& property : properties)
159 {
160 if (property.first == "ModuleManufacturerID")
161 {
162 dimmPropToHex(aResp, "ModuleManufacturerID", property);
163 }
164 else if (property.first == "ModuleProductID")
165 {
166 dimmPropToHex(aResp, "ModuleProductID", property);
167 }
168 else if (property.first == "SubsystemVendorID")
169 {
170 dimmPropToHex(aResp, "MemorySubsystemControllerManufacturerID",
171 property);
172 }
173 else if (property.first == "SubsystemDeviceID")
174 {
175 dimmPropToHex(aResp, "MemorySubsystemControllerProductID",
176 property);
177 }
178 else if (property.first == "VolatileRegionSizeLimitInKiB")
179 {
180 const uint64_t* value = std::get_if<uint64_t>(&property.second);
181
182 if (value == nullptr)
183 {
184 messages::internalError(aResp->res);
185 BMCWEB_LOG_DEBUG << "Invalid property type for "
186 "VolatileRegionSizeLimitKiB";
187 continue;
188 }
189 aResp->res.jsonValue["VolatileRegionSizeLimitMiB"] = (*value) >> 10;
190 }
191 else if (property.first == "PmRegionSizeLimitInKiB")
192 {
193 const uint64_t* value = std::get_if<uint64_t>(&property.second);
194
195 if (value == nullptr)
196 {
197 messages::internalError(aResp->res);
198 BMCWEB_LOG_DEBUG
199 << "Invalid property type for PmRegioSizeLimitKiB";
200 continue;
201 }
202 aResp->res.jsonValue["PersistentRegionSizeLimitMiB"] =
203 (*value) >> 10;
204 }
205 else if (property.first == "VolatileSizeInKiB")
206 {
207 const uint64_t* value = std::get_if<uint64_t>(&property.second);
208
209 if (value == nullptr)
210 {
211 messages::internalError(aResp->res);
212 BMCWEB_LOG_DEBUG
213 << "Invalid property type for VolatileSizeInKiB";
214 continue;
215 }
216 aResp->res.jsonValue["VolatileSizeMiB"] = (*value) >> 10;
217 }
218 else if (property.first == "PmSizeInKiB")
219 {
220 const uint64_t* value = std::get_if<uint64_t>(&property.second);
221 if (value == nullptr)
222 {
223 messages::internalError(aResp->res);
224 BMCWEB_LOG_DEBUG << "Invalid property type for PmSizeInKiB";
225 continue;
226 }
227 aResp->res.jsonValue["NonVolatileSizeMiB"] = (*value) >> 10;
228 }
229 else if (property.first == "CacheSizeInKB")
230 {
231 const uint64_t* value = std::get_if<uint64_t>(&property.second);
232 if (value == nullptr)
233 {
234 messages::internalError(aResp->res);
235 BMCWEB_LOG_DEBUG << "Invalid property type for CacheSizeInKB";
236 continue;
237 }
238 aResp->res.jsonValue["CacheSizeMiB"] = (*value >> 10);
239 }
240
241 else if (property.first == "VoltaileRegionMaxSizeInKib")
242 {
243 const uint64_t* value = std::get_if<uint64_t>(&property.second);
244
245 if (value == nullptr)
246 {
247 messages::internalError(aResp->res);
248 BMCWEB_LOG_DEBUG << "Invalid property type for "
249 "VolatileRegionMaxSizeInKib";
250 continue;
251 }
252 aResp->res.jsonValue["VolatileRegionSizeMaxMiB"] = (*value) >> 10;
253 }
254 else if (property.first == "PmRegionMaxSizeInKiB")
255 {
256 const uint64_t* value = std::get_if<uint64_t>(&property.second);
257
258 if (value == nullptr)
259 {
260 messages::internalError(aResp->res);
261 BMCWEB_LOG_DEBUG
262 << "Invalid property type for PmRegionMaxSizeInKiB";
263 continue;
264 }
265 aResp->res.jsonValue["PersistentRegionSizeMaxMiB"] = (*value) >> 10;
266 }
267 else if (property.first == "AllocationIncrementInKiB")
268 {
269 const uint64_t* value = std::get_if<uint64_t>(&property.second);
270
271 if (value == nullptr)
272 {
273 messages::internalError(aResp->res);
274 BMCWEB_LOG_DEBUG << "Invalid property type for "
275 "AllocationIncrementInKiB";
276 continue;
277 }
278 aResp->res.jsonValue["AllocationIncrementMiB"] = (*value) >> 10;
279 }
280 else if (property.first == "AllocationAlignmentInKiB")
281 {
282 const uint64_t* value = std::get_if<uint64_t>(&property.second);
283
284 if (value == nullptr)
285 {
286 messages::internalError(aResp->res);
287 BMCWEB_LOG_DEBUG << "Invalid property type for "
288 "AllocationAlignmentInKiB";
289 continue;
290 }
291 aResp->res.jsonValue["AllocationAlignmentMiB"] = (*value) >> 10;
292 }
293 else if (property.first == "VolatileRegionNumberLimit")
294 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700295 const uint64_t* value = std::get_if<uint64_t>(&property.second);
296 if (value == nullptr)
297 {
298 messages::internalError(aResp->res);
299 continue;
300 }
301 aResp->res.jsonValue["VolatileRegionNumberLimit"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700302 }
303 else if (property.first == "PmRegionNumberLimit")
304 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700305 const uint64_t* value = std::get_if<uint64_t>(&property.second);
306 if (value == nullptr)
307 {
308 messages::internalError(aResp->res);
309 continue;
310 }
311 aResp->res.jsonValue["PersistentRegionNumberLimit"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700312 }
313 else if (property.first == "SpareDeviceCount")
314 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700315 const uint64_t* value = std::get_if<uint64_t>(&property.second);
316 if (value == nullptr)
317 {
318 messages::internalError(aResp->res);
319 continue;
320 }
321 aResp->res.jsonValue["SpareDeviceCount"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700322 }
323 else if (property.first == "IsSpareDeviceInUse")
324 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700325 const bool* value = std::get_if<bool>(&property.second);
326 if (value == nullptr)
327 {
328 messages::internalError(aResp->res);
329 continue;
330 }
331 aResp->res.jsonValue["IsSpareDeviceEnabled"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700332 }
333 else if (property.first == "IsRankSpareEnabled")
334 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700335 const bool* value = std::get_if<bool>(&property.second);
336 if (value == nullptr)
337 {
338 messages::internalError(aResp->res);
339 continue;
340 }
341 aResp->res.jsonValue["IsRankSpareEnabled"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700342 }
343 else if (property.first == "MaxAveragePowerLimitmW")
344 {
345 const auto* value =
346 std::get_if<std::vector<uint32_t>>(&property.second);
347 if (value == nullptr)
348 {
349 messages::internalError(aResp->res);
350 BMCWEB_LOG_DEBUG << "Invalid property type for "
351 "MaxAveragePowerLimitmW";
352 continue;
353 }
354 aResp->res.jsonValue["MaxTDPMilliWatts"] = *value;
355 }
James Feistc50e7c62020-07-27 15:39:36 -0700356 else if (property.first == "ConfigurationLocked")
357 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700358 const bool* value = std::get_if<bool>(&property.second);
359 if (value == nullptr)
360 {
361 messages::internalError(aResp->res);
362 continue;
363 }
364 aResp->res.jsonValue["ConfigurationLocked"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700365 }
366 else if (property.first == "AllowedMemoryModes")
367 {
368 const std::string* value =
369 std::get_if<std::string>(&property.second);
370 if (value == nullptr)
371 {
372 messages::internalError(aResp->res);
373 BMCWEB_LOG_DEBUG << "Invalid property type for FormFactor";
374 continue;
375 }
376 constexpr const std::array<const char*, 3> values{"Volatile",
377 "PMEM", "Block"};
378
379 for (const char* v : values)
380 {
381 if (boost::ends_with(*value, v))
382 {
383 aResp->res.jsonValue["OperatingMemoryModes "] = v;
384 break;
385 }
386 }
387 }
388 else if (property.first == "MemoryMedia")
389 {
390 const std::string* value =
391 std::get_if<std::string>(&property.second);
392 if (value == nullptr)
393 {
394 messages::internalError(aResp->res);
395 BMCWEB_LOG_DEBUG << "Invalid property type for MemoryMedia";
396 continue;
397 }
398 constexpr const std::array<const char*, 3> values{"DRAM", "NAND",
399 "Intel3DXPoint"};
400
401 for (const char* v : values)
402 {
403 if (boost::ends_with(*value, v))
404 {
405 aResp->res.jsonValue["MemoryMedia"] = v;
406 break;
407 }
408 }
409 }
James Feistc50e7c62020-07-27 15:39:36 -0700410 // PersistantMemory.SecurityCapabilites interface
411 else if (property.first == "ConfigurationLockCapable" ||
412 property.first == "DataLockCapable" ||
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700413 property.first == "PassphraseCapable")
414 {
415 const bool* value = std::get_if<bool>(&property.second);
416 if (value == nullptr)
417 {
418 messages::internalError(aResp->res);
419 continue;
420 }
421 aResp->res.jsonValue["SecurityCapabilities"][property.first] =
422 *value;
423 }
424 else if (property.first == "MaxPassphraseCount" ||
James Feistc50e7c62020-07-27 15:39:36 -0700425 property.first == "PassphraseLockLimit")
426 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700427 const uint64_t* value = std::get_if<uint64_t>(&property.second);
428 if (value == nullptr)
429 {
430 messages::internalError(aResp->res);
431 continue;
432 }
James Feistc50e7c62020-07-27 15:39:36 -0700433 aResp->res.jsonValue["SecurityCapabilities"][property.first] =
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700434 *value;
James Feistc50e7c62020-07-27 15:39:36 -0700435 }
436 }
437}
438
Ed Tanous80789c82020-08-19 09:19:09 -0700439inline void getDimmDataByService(std::shared_ptr<AsyncResp> aResp,
440 const std::string& dimmId,
441 const std::string& service,
442 const std::string& objPath)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200443{
James Feist35e257a2020-06-05 13:30:51 -0700444 auto health = std::make_shared<HealthPopulate>(aResp);
445 health->selfPath = objPath;
446 health->populate();
447
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200448 BMCWEB_LOG_DEBUG << "Get available system components.";
449 crow::connections::systemBus->async_method_call(
James Feistc50e7c62020-07-27 15:39:36 -0700450 [dimmId, aResp{std::move(aResp)}](const boost::system::error_code ec,
451 const DimmProperties& properties) {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200452 if (ec)
453 {
454 BMCWEB_LOG_DEBUG << "DBUS response error";
455 messages::internalError(aResp->res);
456
457 return;
458 }
459 aResp->res.jsonValue["Id"] = dimmId;
460 aResp->res.jsonValue["Name"] = "DIMM Slot";
461
462 const auto memorySizeProperty = properties.find("MemorySizeInKB");
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600463 if (memorySizeProperty != properties.end())
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200464 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500465 const uint32_t* memorySize =
Ed Tanousabf2add2019-01-22 16:40:12 -0800466 std::get_if<uint32_t>(&memorySizeProperty->second);
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600467 if (memorySize == nullptr)
468 {
469 // Important property not in desired type
470 messages::internalError(aResp->res);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200471
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600472 return;
473 }
474 if (*memorySize == 0)
475 {
476 // Slot is not populated, set status end return
477 aResp->res.jsonValue["Status"]["State"] = "Absent";
478 aResp->res.jsonValue["Status"]["Health"] = "OK";
479 // HTTP Code will be set up automatically, just return
480 return;
481 }
482 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200483 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200484 aResp->res.jsonValue["Status"]["State"] = "Enabled";
485 aResp->res.jsonValue["Status"]["Health"] = "OK";
486
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500487 for (const auto& property : properties)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200488 {
489 if (property.first == "MemoryDataWidth")
490 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700491 const uint16_t* value =
492 std::get_if<uint16_t>(&property.second);
493 if (value == nullptr)
494 {
495 continue;
496 }
497 aResp->res.jsonValue["DataWidthBits"] = *value;
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200498 }
Manojkiran Eda7e236ca2019-06-25 23:06:32 +0530499 else if (property.first == "PartNumber")
500 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700501 const std::string* value =
502 std::get_if<std::string>(&property.second);
503 if (value == nullptr)
504 {
505 continue;
506 }
507 aResp->res.jsonValue["PartNumber"] = *value;
Manojkiran Eda7e236ca2019-06-25 23:06:32 +0530508 }
509 else if (property.first == "SerialNumber")
510 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700511 const std::string* value =
512 std::get_if<std::string>(&property.second);
513 if (value == nullptr)
514 {
515 continue;
516 }
517 aResp->res.jsonValue["SerialNumber"] = *value;
Manojkiran Eda7e236ca2019-06-25 23:06:32 +0530518 }
519 else if (property.first == "Manufacturer")
520 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700521 const std::string* value =
522 std::get_if<std::string>(&property.second);
523 if (value == nullptr)
524 {
525 continue;
526 }
527 aResp->res.jsonValue["Manufacturer"] = *value;
Manojkiran Eda7e236ca2019-06-25 23:06:32 +0530528 }
James Feistc50e7c62020-07-27 15:39:36 -0700529 else if (property.first == "RevisionCode")
530 {
531 const uint16_t* value =
532 std::get_if<uint16_t>(&property.second);
533
534 if (value == nullptr)
535 {
536 messages::internalError(aResp->res);
537 BMCWEB_LOG_DEBUG
538 << "Invalid property type for RevisionCode";
539 continue;
540 }
541 aResp->res.jsonValue["FirmwareRevision"] =
542 std::to_string(*value);
543 }
544 else if (property.first == "MemoryTotalWidth")
545 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700546 const uint16_t* value =
547 std::get_if<uint16_t>(&property.second);
548 if (value == nullptr)
549 {
550 continue;
551 }
552 aResp->res.jsonValue["BusWidthBits"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700553 }
554 else if (property.first == "ECC")
555 {
556 const std::string* value =
557 std::get_if<std::string>(&property.second);
558 if (value == nullptr)
559 {
560 messages::internalError(aResp->res);
561 BMCWEB_LOG_DEBUG << "Invalid property type for ECC";
562 continue;
563 }
564 constexpr const std::array<const char*, 4> values{
565 "NoECC", "SingleBitECC", "MultiBitECC",
566 "AddressParity"};
567
568 for (const char* v : values)
569 {
570 if (boost::ends_with(*value, v))
571 {
572 aResp->res.jsonValue["ErrorCorrection"] = v;
573 break;
574 }
575 }
576 }
577 else if (property.first == "FormFactor")
578 {
579 const std::string* value =
580 std::get_if<std::string>(&property.second);
581 if (value == nullptr)
582 {
583 messages::internalError(aResp->res);
584 BMCWEB_LOG_DEBUG
585 << "Invalid property type for FormFactor";
586 continue;
587 }
588 constexpr const std::array<const char*, 11> values{
589 "RDIMM", "UDIMM", "SO_DIMM",
590 "LRDIMM", "Mini_RDIMM", "Mini_UDIMM",
591 "SO_RDIMM_72b", "SO_UDIMM_72b", "SO_DIMM_16b",
592 "SO_DIMM_32b", "Die"};
593
594 for (const char* v : values)
595 {
596 if (boost::ends_with(*value, v))
597 {
598 aResp->res.jsonValue["BaseModuleType"] = v;
599 break;
600 }
601 }
602 }
603 else if (property.first == "AllowedSpeedsMT")
604 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700605 const std::vector<uint16_t>* value =
606 std::get_if<std::vector<uint16_t>>(&property.second);
607 if (value == nullptr)
608 {
609 continue;
610 }
611 nlohmann::json& jValue =
612 aResp->res.jsonValue["AllowedSpeedsMHz"];
613 jValue = nlohmann::json::array();
614 for (uint16_t subVal : *value)
615 {
616 jValue.push_back(subVal);
617 }
James Feistc50e7c62020-07-27 15:39:36 -0700618 }
619 else if (property.first == "MemoryAttributes")
620 {
621 const uint8_t* value =
622 std::get_if<uint8_t>(&property.second);
623
624 if (value == nullptr)
625 {
626 messages::internalError(aResp->res);
627 BMCWEB_LOG_DEBUG
628 << "Invalid property type for MemoryAttributes";
629 continue;
630 }
631 aResp->res.jsonValue["RankCount"] =
632 static_cast<uint64_t>(*value);
633 }
634 else if (property.first == "MemoryConfiguredSpeedInMhz")
635 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700636 const uint16_t* value =
637 std::get_if<uint16_t>(&property.second);
638 if (value == nullptr)
639 {
640 continue;
641 }
642 aResp->res.jsonValue["OperatingSpeedMhz"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700643 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200644 else if (property.first == "MemoryType")
645 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500646 const auto* value =
Ed Tanousabf2add2019-01-22 16:40:12 -0800647 std::get_if<std::string>(&property.second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200648 if (value != nullptr)
649 {
Gunnar Mills313efb12020-10-26 16:05:08 -0500650 std::string memoryDeviceType =
651 translateMemoryTypeToRedfish(*value);
652 // Values like "Unknown" or "Other" will return empty
653 // so just leave off
654 if (!memoryDeviceType.empty())
James Feistc50e7c62020-07-27 15:39:36 -0700655 {
Gunnar Mills313efb12020-10-26 16:05:08 -0500656 aResp->res.jsonValue["MemoryDeviceType"] =
657 memoryDeviceType;
James Feistc50e7c62020-07-27 15:39:36 -0700658 }
James Feistc50e7c62020-07-27 15:39:36 -0700659 if (value->find("DDR") != std::string::npos)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200660 {
661 aResp->res.jsonValue["MemoryType"] = "DRAM";
662 }
James Feistc50e7c62020-07-27 15:39:36 -0700663 else if (boost::ends_with(*value, "Logical"))
664 {
665 aResp->res.jsonValue["MemoryType"] = "IntelOptane";
666 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200667 }
668 }
James Feistc50e7c62020-07-27 15:39:36 -0700669 // memory location interface
670 else if (property.first == "Channel" ||
671 property.first == "MemoryController" ||
672 property.first == "Slot" || property.first == "Socket")
673 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700674 const std::string* value =
675 std::get_if<std::string>(&property.second);
676 if (value == nullptr)
677 {
678 messages::internalError(aResp->res);
679 continue;
680 }
James Feistc50e7c62020-07-27 15:39:36 -0700681 aResp->res.jsonValue["MemoryLocation"][property.first] =
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700682 *value;
James Feistc50e7c62020-07-27 15:39:36 -0700683 }
684 else
685 {
686 getPersistentMemoryProperties(aResp, properties);
687 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200688 }
689 },
690 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
691}
692
Ed Tanous23a21a12020-07-25 04:45:05 +0000693inline void getDimmPartitionData(std::shared_ptr<AsyncResp> aResp,
694 const std::string& service,
695 const std::string& path)
James Feist45094ad2020-04-29 14:02:30 -0700696{
697 crow::connections::systemBus->async_method_call(
698 [aResp{std::move(aResp)}](
699 const boost::system::error_code ec,
700 const boost::container::flat_map<
701 std::string, std::variant<std::string, uint64_t, uint32_t,
702 bool>>& properties) {
703 if (ec)
704 {
705 BMCWEB_LOG_DEBUG << "DBUS response error";
706 messages::internalError(aResp->res);
707
708 return;
709 }
710
711 nlohmann::json& partition =
712 aResp->res.jsonValue["Regions"].emplace_back(
713 nlohmann::json::object());
714 for (const auto& [key, val] : properties)
715 {
716 if (key == "MemoryClassification")
717 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700718 const std::string* value = std::get_if<std::string>(&val);
719 if (value == nullptr)
720 {
721 messages::internalError(aResp->res);
722 continue;
723 }
724 partition[key] = *value;
James Feist45094ad2020-04-29 14:02:30 -0700725 }
726 else if (key == "OffsetInKiB")
727 {
728 const uint64_t* value = std::get_if<uint64_t>(&val);
729 if (value == nullptr)
730 {
731 messages::internalError(aResp->res);
James Feist45094ad2020-04-29 14:02:30 -0700732 continue;
733 }
734
735 partition["OffsetMiB"] = (*value >> 10);
736 }
737 else if (key == "PartitionId")
738 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700739 const std::string* value = std::get_if<std::string>(&val);
740 if (value == nullptr)
741 {
742 messages::internalError(aResp->res);
743 continue;
744 }
745 partition["RegionId"] = *value;
James Feist45094ad2020-04-29 14:02:30 -0700746 }
747
748 else if (key == "PassphraseState")
749 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700750 const bool* value = std::get_if<bool>(&val);
751 if (value == nullptr)
752 {
753 messages::internalError(aResp->res);
754 continue;
755 }
756 partition["PassphraseEnabled"] = *value;
James Feist45094ad2020-04-29 14:02:30 -0700757 }
758 else if (key == "SizeInKiB")
759 {
760 const uint64_t* value = std::get_if<uint64_t>(&val);
761 if (value == nullptr)
762 {
763 messages::internalError(aResp->res);
764 BMCWEB_LOG_DEBUG
765 << "Invalid property type for SizeInKiB";
766 continue;
767 }
768 partition["SizeMiB"] = (*value >> 10);
769 }
770 }
771 },
772
773 service, path, "org.freedesktop.DBus.Properties", "GetAll",
774 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition");
775}
776
Ed Tanous23a21a12020-07-25 04:45:05 +0000777inline void getDimmData(std::shared_ptr<AsyncResp> aResp,
778 const std::string& dimmId)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200779{
780 BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
781 crow::connections::systemBus->async_method_call(
Ed Tanous029573d2019-02-01 10:57:49 -0800782 [dimmId, aResp{std::move(aResp)}](
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200783 const boost::system::error_code ec,
784 const boost::container::flat_map<
785 std::string, boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500786 std::string, std::vector<std::string>>>&
787 subtree) {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200788 if (ec)
789 {
790 BMCWEB_LOG_DEBUG << "DBUS response error";
791 messages::internalError(aResp->res);
792
793 return;
794 }
James Feist45094ad2020-04-29 14:02:30 -0700795 bool found = false;
796 for (const auto& [path, object] : subtree)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200797 {
James Feist45094ad2020-04-29 14:02:30 -0700798 if (path.find(dimmId) != std::string::npos)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200799 {
James Feist45094ad2020-04-29 14:02:30 -0700800 for (const auto& [service, interfaces] : object)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200801 {
James Feist45094ad2020-04-29 14:02:30 -0700802 if (!found &&
803 (std::find(
804 interfaces.begin(), interfaces.end(),
805 "xyz.openbmc_project.Inventory.Item.Dimm") !=
806 interfaces.end()))
807 {
808 getDimmDataByService(aResp, dimmId, service, path);
809 found = true;
810 }
811
812 // partitions are separate as there can be multiple per
813 // device, i.e.
814 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1
815 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2
816 if (std::find(interfaces.begin(), interfaces.end(),
817 "xyz.openbmc_project.Inventory.Item."
818 "PersistentMemory.Partition") !=
819 interfaces.end())
820 {
821 getDimmPartitionData(aResp, service, path);
822 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200823 }
824 }
825 }
826 // Object not found
James Feist45094ad2020-04-29 14:02:30 -0700827 if (!found)
828 {
829 messages::resourceNotFound(aResp->res, "Memory", dimmId);
830 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200831 return;
832 },
833 "xyz.openbmc_project.ObjectMapper",
834 "/xyz/openbmc_project/object_mapper",
835 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Ed Tanous271584a2019-07-09 16:24:22 -0700836 "/xyz/openbmc_project/inventory", 0,
James Feist45094ad2020-04-29 14:02:30 -0700837 std::array<const char*, 2>{
838 "xyz.openbmc_project.Inventory.Item.Dimm",
839 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"});
Ed Tanous271584a2019-07-09 16:24:22 -0700840}
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200841
Ed Tanous029573d2019-02-01 10:57:49 -0800842class MemoryCollection : public Node
843{
844 public:
845 /*
846 * Default Constructor
847 */
Ed Tanous52cc1122020-07-18 13:51:21 -0700848 MemoryCollection(App& app) : Node(app, "/redfish/v1/Systems/system/Memory/")
Ed Tanous029573d2019-02-01 10:57:49 -0800849 {
850 entityPrivileges = {
851 {boost::beast::http::verb::get, {{"Login"}}},
852 {boost::beast::http::verb::head, {{"Login"}}},
853 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
854 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
855 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
856 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
857 }
858
859 private:
860 /**
861 * Functions triggers appropriate requests on DBus
862 */
Ed Tanouscb13a392020-07-25 19:02:03 +0000863 void doGet(crow::Response& res, const crow::Request&,
864 const std::vector<std::string>&) override
Ed Tanous029573d2019-02-01 10:57:49 -0800865 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800866 res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection";
867 res.jsonValue["Name"] = "Memory Module Collection";
James Feistc50e7c62020-07-27 15:39:36 -0700868 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Memory";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200869 auto asyncResp = std::make_shared<AsyncResp>(res);
870
Gunnar Mills05030b82020-10-14 15:51:31 -0500871 collection_util::getCollectionMembers(
872 asyncResp, "/redfish/v1/Systems/system/Memory",
873 {"xyz.openbmc_project.Inventory.Item.Dimm"});
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200874 }
875};
876
877class Memory : public Node
878{
879 public:
880 /*
881 * Default Constructor
882 */
Ed Tanous52cc1122020-07-18 13:51:21 -0700883 Memory(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -0800884 Node(app, "/redfish/v1/Systems/system/Memory/<str>/", std::string())
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200885 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200886 entityPrivileges = {
887 {boost::beast::http::verb::get, {{"Login"}}},
888 {boost::beast::http::verb::head, {{"Login"}}},
889 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
890 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
891 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
892 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
893 }
894
895 private:
896 /**
897 * Functions triggers appropriate requests on DBus
898 */
Ed Tanouscb13a392020-07-25 19:02:03 +0000899 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500900 const std::vector<std::string>& params) override
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200901 {
902 // Check if there is required param, truly entering this shall be
903 // impossible
Ed Tanous029573d2019-02-01 10:57:49 -0800904 if (params.size() != 1)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200905 {
906 messages::internalError(res);
907 res.end();
908 return;
909 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500910 const std::string& dimmId = params[0];
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200911
James Feistc50e7c62020-07-27 15:39:36 -0700912 res.jsonValue["@odata.type"] = "#Memory.v1_7_0.Memory";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200913 res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -0800914 "/redfish/v1/Systems/system/Memory/" + dimmId;
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200915 auto asyncResp = std::make_shared<AsyncResp>(res);
916
Ed Tanous029573d2019-02-01 10:57:49 -0800917 getDimmData(asyncResp, dimmId);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200918 }
919};
920
921} // namespace redfish