blob: f6be846d9b57f989516165a50872fc1c0dead738 [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);
Gunnar Millsaceb7fc2018-12-10 15:17:20 -0600471 return;
472 }
473 aResp->res.jsonValue["CapacityMiB"] = (*memorySize >> 10);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200474 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200475 aResp->res.jsonValue["Status"]["State"] = "Enabled";
476 aResp->res.jsonValue["Status"]["Health"] = "OK";
477
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500478 for (const auto& property : properties)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200479 {
480 if (property.first == "MemoryDataWidth")
481 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700482 const uint16_t* value =
483 std::get_if<uint16_t>(&property.second);
484 if (value == nullptr)
485 {
486 continue;
487 }
488 aResp->res.jsonValue["DataWidthBits"] = *value;
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200489 }
Manojkiran Eda7e236ca2019-06-25 23:06:32 +0530490 else if (property.first == "PartNumber")
491 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700492 const std::string* value =
493 std::get_if<std::string>(&property.second);
494 if (value == nullptr)
495 {
496 continue;
497 }
498 aResp->res.jsonValue["PartNumber"] = *value;
Manojkiran Eda7e236ca2019-06-25 23:06:32 +0530499 }
500 else if (property.first == "SerialNumber")
501 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700502 const std::string* value =
503 std::get_if<std::string>(&property.second);
504 if (value == nullptr)
505 {
506 continue;
507 }
508 aResp->res.jsonValue["SerialNumber"] = *value;
Manojkiran Eda7e236ca2019-06-25 23:06:32 +0530509 }
510 else if (property.first == "Manufacturer")
511 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700512 const std::string* value =
513 std::get_if<std::string>(&property.second);
514 if (value == nullptr)
515 {
516 continue;
517 }
518 aResp->res.jsonValue["Manufacturer"] = *value;
Manojkiran Eda7e236ca2019-06-25 23:06:32 +0530519 }
James Feistc50e7c62020-07-27 15:39:36 -0700520 else if (property.first == "RevisionCode")
521 {
522 const uint16_t* value =
523 std::get_if<uint16_t>(&property.second);
524
525 if (value == nullptr)
526 {
527 messages::internalError(aResp->res);
528 BMCWEB_LOG_DEBUG
529 << "Invalid property type for RevisionCode";
530 continue;
531 }
532 aResp->res.jsonValue["FirmwareRevision"] =
533 std::to_string(*value);
534 }
535 else if (property.first == "MemoryTotalWidth")
536 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700537 const uint16_t* value =
538 std::get_if<uint16_t>(&property.second);
539 if (value == nullptr)
540 {
541 continue;
542 }
543 aResp->res.jsonValue["BusWidthBits"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700544 }
545 else if (property.first == "ECC")
546 {
547 const std::string* value =
548 std::get_if<std::string>(&property.second);
549 if (value == nullptr)
550 {
551 messages::internalError(aResp->res);
552 BMCWEB_LOG_DEBUG << "Invalid property type for ECC";
553 continue;
554 }
555 constexpr const std::array<const char*, 4> values{
556 "NoECC", "SingleBitECC", "MultiBitECC",
557 "AddressParity"};
558
559 for (const char* v : values)
560 {
561 if (boost::ends_with(*value, v))
562 {
563 aResp->res.jsonValue["ErrorCorrection"] = v;
564 break;
565 }
566 }
567 }
568 else if (property.first == "FormFactor")
569 {
570 const std::string* value =
571 std::get_if<std::string>(&property.second);
572 if (value == nullptr)
573 {
574 messages::internalError(aResp->res);
575 BMCWEB_LOG_DEBUG
576 << "Invalid property type for FormFactor";
577 continue;
578 }
579 constexpr const std::array<const char*, 11> values{
580 "RDIMM", "UDIMM", "SO_DIMM",
581 "LRDIMM", "Mini_RDIMM", "Mini_UDIMM",
582 "SO_RDIMM_72b", "SO_UDIMM_72b", "SO_DIMM_16b",
583 "SO_DIMM_32b", "Die"};
584
585 for (const char* v : values)
586 {
587 if (boost::ends_with(*value, v))
588 {
589 aResp->res.jsonValue["BaseModuleType"] = v;
590 break;
591 }
592 }
593 }
594 else if (property.first == "AllowedSpeedsMT")
595 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700596 const std::vector<uint16_t>* value =
597 std::get_if<std::vector<uint16_t>>(&property.second);
598 if (value == nullptr)
599 {
600 continue;
601 }
602 nlohmann::json& jValue =
603 aResp->res.jsonValue["AllowedSpeedsMHz"];
604 jValue = nlohmann::json::array();
605 for (uint16_t subVal : *value)
606 {
607 jValue.push_back(subVal);
608 }
James Feistc50e7c62020-07-27 15:39:36 -0700609 }
610 else if (property.first == "MemoryAttributes")
611 {
612 const uint8_t* value =
613 std::get_if<uint8_t>(&property.second);
614
615 if (value == nullptr)
616 {
617 messages::internalError(aResp->res);
618 BMCWEB_LOG_DEBUG
619 << "Invalid property type for MemoryAttributes";
620 continue;
621 }
622 aResp->res.jsonValue["RankCount"] =
623 static_cast<uint64_t>(*value);
624 }
625 else if (property.first == "MemoryConfiguredSpeedInMhz")
626 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700627 const uint16_t* value =
628 std::get_if<uint16_t>(&property.second);
629 if (value == nullptr)
630 {
631 continue;
632 }
633 aResp->res.jsonValue["OperatingSpeedMhz"] = *value;
James Feistc50e7c62020-07-27 15:39:36 -0700634 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200635 else if (property.first == "MemoryType")
636 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500637 const auto* value =
Ed Tanousabf2add2019-01-22 16:40:12 -0800638 std::get_if<std::string>(&property.second);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200639 if (value != nullptr)
640 {
Gunnar Mills313efb12020-10-26 16:05:08 -0500641 std::string memoryDeviceType =
642 translateMemoryTypeToRedfish(*value);
643 // Values like "Unknown" or "Other" will return empty
644 // so just leave off
645 if (!memoryDeviceType.empty())
James Feistc50e7c62020-07-27 15:39:36 -0700646 {
Gunnar Mills313efb12020-10-26 16:05:08 -0500647 aResp->res.jsonValue["MemoryDeviceType"] =
648 memoryDeviceType;
James Feistc50e7c62020-07-27 15:39:36 -0700649 }
James Feistc50e7c62020-07-27 15:39:36 -0700650 if (value->find("DDR") != std::string::npos)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200651 {
652 aResp->res.jsonValue["MemoryType"] = "DRAM";
653 }
James Feistc50e7c62020-07-27 15:39:36 -0700654 else if (boost::ends_with(*value, "Logical"))
655 {
656 aResp->res.jsonValue["MemoryType"] = "IntelOptane";
657 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200658 }
659 }
James Feistc50e7c62020-07-27 15:39:36 -0700660 // memory location interface
661 else if (property.first == "Channel" ||
662 property.first == "MemoryController" ||
663 property.first == "Slot" || property.first == "Socket")
664 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700665 const std::string* value =
666 std::get_if<std::string>(&property.second);
667 if (value == nullptr)
668 {
669 messages::internalError(aResp->res);
670 continue;
671 }
James Feistc50e7c62020-07-27 15:39:36 -0700672 aResp->res.jsonValue["MemoryLocation"][property.first] =
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700673 *value;
James Feistc50e7c62020-07-27 15:39:36 -0700674 }
SunnySrivastava1984ee135e22020-12-15 12:42:19 -0600675 else if (property.first == "SparePartNumber")
676 {
677 const std::string* value =
678 std::get_if<std::string>(&property.second);
679 if (value == nullptr)
680 {
681 messages::internalError(aResp->res);
682 continue;
683 }
684 aResp->res.jsonValue["SparePartNumber"] = *value;
685 }
686 else if (property.first == "Model")
687 {
688 const std::string* value =
689 std::get_if<std::string>(&property.second);
690 if (value == nullptr)
691 {
692 messages::internalError(aResp->res);
693 continue;
694 }
695 aResp->res.jsonValue["Model"] = *value;
696 }
697 else if (property.first == "LocationCode")
698 {
699 const std::string* value =
700 std::get_if<std::string>(&property.second);
701 if (value == nullptr)
702 {
703 messages::internalError(aResp->res);
704 continue;
705 }
706 aResp->res
707 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
708 *value;
709 }
James Feistc50e7c62020-07-27 15:39:36 -0700710 else
711 {
712 getPersistentMemoryProperties(aResp, properties);
713 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200714 }
715 },
716 service, objPath, "org.freedesktop.DBus.Properties", "GetAll", "");
717}
718
Ed Tanous23a21a12020-07-25 04:45:05 +0000719inline void getDimmPartitionData(std::shared_ptr<AsyncResp> aResp,
720 const std::string& service,
721 const std::string& path)
James Feist45094ad2020-04-29 14:02:30 -0700722{
723 crow::connections::systemBus->async_method_call(
724 [aResp{std::move(aResp)}](
725 const boost::system::error_code ec,
726 const boost::container::flat_map<
727 std::string, std::variant<std::string, uint64_t, uint32_t,
728 bool>>& properties) {
729 if (ec)
730 {
731 BMCWEB_LOG_DEBUG << "DBUS response error";
732 messages::internalError(aResp->res);
733
734 return;
735 }
736
737 nlohmann::json& partition =
738 aResp->res.jsonValue["Regions"].emplace_back(
739 nlohmann::json::object());
740 for (const auto& [key, val] : properties)
741 {
742 if (key == "MemoryClassification")
743 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700744 const std::string* value = std::get_if<std::string>(&val);
745 if (value == nullptr)
746 {
747 messages::internalError(aResp->res);
748 continue;
749 }
750 partition[key] = *value;
James Feist45094ad2020-04-29 14:02:30 -0700751 }
752 else if (key == "OffsetInKiB")
753 {
754 const uint64_t* value = std::get_if<uint64_t>(&val);
755 if (value == nullptr)
756 {
757 messages::internalError(aResp->res);
James Feist45094ad2020-04-29 14:02:30 -0700758 continue;
759 }
760
761 partition["OffsetMiB"] = (*value >> 10);
762 }
763 else if (key == "PartitionId")
764 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700765 const std::string* value = std::get_if<std::string>(&val);
766 if (value == nullptr)
767 {
768 messages::internalError(aResp->res);
769 continue;
770 }
771 partition["RegionId"] = *value;
James Feist45094ad2020-04-29 14:02:30 -0700772 }
773
774 else if (key == "PassphraseState")
775 {
Ed Tanous5fb91ba2020-09-28 15:41:28 -0700776 const bool* value = std::get_if<bool>(&val);
777 if (value == nullptr)
778 {
779 messages::internalError(aResp->res);
780 continue;
781 }
782 partition["PassphraseEnabled"] = *value;
James Feist45094ad2020-04-29 14:02:30 -0700783 }
784 else if (key == "SizeInKiB")
785 {
786 const uint64_t* value = std::get_if<uint64_t>(&val);
787 if (value == nullptr)
788 {
789 messages::internalError(aResp->res);
790 BMCWEB_LOG_DEBUG
791 << "Invalid property type for SizeInKiB";
792 continue;
793 }
794 partition["SizeMiB"] = (*value >> 10);
795 }
796 }
797 },
798
799 service, path, "org.freedesktop.DBus.Properties", "GetAll",
800 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition");
801}
802
Ed Tanous23a21a12020-07-25 04:45:05 +0000803inline void getDimmData(std::shared_ptr<AsyncResp> aResp,
804 const std::string& dimmId)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200805{
806 BMCWEB_LOG_DEBUG << "Get available system dimm resources.";
807 crow::connections::systemBus->async_method_call(
Ed Tanous029573d2019-02-01 10:57:49 -0800808 [dimmId, aResp{std::move(aResp)}](
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200809 const boost::system::error_code ec,
810 const boost::container::flat_map<
811 std::string, boost::container::flat_map<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500812 std::string, std::vector<std::string>>>&
813 subtree) {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200814 if (ec)
815 {
816 BMCWEB_LOG_DEBUG << "DBUS response error";
817 messages::internalError(aResp->res);
818
819 return;
820 }
James Feist45094ad2020-04-29 14:02:30 -0700821 bool found = false;
822 for (const auto& [path, object] : subtree)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200823 {
James Feist45094ad2020-04-29 14:02:30 -0700824 if (path.find(dimmId) != std::string::npos)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200825 {
James Feist45094ad2020-04-29 14:02:30 -0700826 for (const auto& [service, interfaces] : object)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200827 {
James Feist45094ad2020-04-29 14:02:30 -0700828 if (!found &&
829 (std::find(
830 interfaces.begin(), interfaces.end(),
831 "xyz.openbmc_project.Inventory.Item.Dimm") !=
832 interfaces.end()))
833 {
834 getDimmDataByService(aResp, dimmId, service, path);
835 found = true;
836 }
837
838 // partitions are separate as there can be multiple per
839 // device, i.e.
840 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1
841 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2
842 if (std::find(interfaces.begin(), interfaces.end(),
843 "xyz.openbmc_project.Inventory.Item."
844 "PersistentMemory.Partition") !=
845 interfaces.end())
846 {
847 getDimmPartitionData(aResp, service, path);
848 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200849 }
850 }
851 }
852 // Object not found
James Feist45094ad2020-04-29 14:02:30 -0700853 if (!found)
854 {
855 messages::resourceNotFound(aResp->res, "Memory", dimmId);
856 }
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200857 return;
858 },
859 "xyz.openbmc_project.ObjectMapper",
860 "/xyz/openbmc_project/object_mapper",
861 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Ed Tanous271584a2019-07-09 16:24:22 -0700862 "/xyz/openbmc_project/inventory", 0,
James Feist45094ad2020-04-29 14:02:30 -0700863 std::array<const char*, 2>{
864 "xyz.openbmc_project.Inventory.Item.Dimm",
865 "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"});
Ed Tanous271584a2019-07-09 16:24:22 -0700866}
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200867
Ed Tanous029573d2019-02-01 10:57:49 -0800868class MemoryCollection : public Node
869{
870 public:
871 /*
872 * Default Constructor
873 */
Ed Tanous52cc1122020-07-18 13:51:21 -0700874 MemoryCollection(App& app) : Node(app, "/redfish/v1/Systems/system/Memory/")
Ed Tanous029573d2019-02-01 10:57:49 -0800875 {
876 entityPrivileges = {
877 {boost::beast::http::verb::get, {{"Login"}}},
878 {boost::beast::http::verb::head, {{"Login"}}},
879 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
880 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
881 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
882 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
883 }
884
885 private:
886 /**
887 * Functions triggers appropriate requests on DBus
888 */
Ed Tanouscb13a392020-07-25 19:02:03 +0000889 void doGet(crow::Response& res, const crow::Request&,
890 const std::vector<std::string>&) override
Ed Tanous029573d2019-02-01 10:57:49 -0800891 {
Ed Tanous0f74e642018-11-12 15:17:05 -0800892 res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection";
893 res.jsonValue["Name"] = "Memory Module Collection";
James Feistc50e7c62020-07-27 15:39:36 -0700894 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Memory";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200895 auto asyncResp = std::make_shared<AsyncResp>(res);
896
Gunnar Mills05030b82020-10-14 15:51:31 -0500897 collection_util::getCollectionMembers(
898 asyncResp, "/redfish/v1/Systems/system/Memory",
899 {"xyz.openbmc_project.Inventory.Item.Dimm"});
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200900 }
901};
902
903class Memory : public Node
904{
905 public:
906 /*
907 * Default Constructor
908 */
Ed Tanous52cc1122020-07-18 13:51:21 -0700909 Memory(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -0800910 Node(app, "/redfish/v1/Systems/system/Memory/<str>/", std::string())
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200911 {
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200912 entityPrivileges = {
913 {boost::beast::http::verb::get, {{"Login"}}},
914 {boost::beast::http::verb::head, {{"Login"}}},
915 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
916 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
917 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
918 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
919 }
920
921 private:
922 /**
923 * Functions triggers appropriate requests on DBus
924 */
Ed Tanouscb13a392020-07-25 19:02:03 +0000925 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500926 const std::vector<std::string>& params) override
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200927 {
928 // Check if there is required param, truly entering this shall be
929 // impossible
Ed Tanous029573d2019-02-01 10:57:49 -0800930 if (params.size() != 1)
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200931 {
932 messages::internalError(res);
933 res.end();
934 return;
935 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500936 const std::string& dimmId = params[0];
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200937
SunnySrivastava1984ee135e22020-12-15 12:42:19 -0600938 res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory";
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200939 res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -0800940 "/redfish/v1/Systems/system/Memory/" + dimmId;
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200941 auto asyncResp = std::make_shared<AsyncResp>(res);
942
Ed Tanous029573d2019-02-01 10:57:49 -0800943 getDimmData(asyncResp, dimmId);
Rapkiewicz, Pawel443c2932018-10-22 15:08:49 +0200944 }
945};
946
947} // namespace redfish