blob: 575741aee4507a31e205a34bcf2f77b1d2889716 [file] [log] [blame]
Gilbert Chen6c7fed42022-02-22 15:40:17 +00001#include "terminus.hpp"
2
3#include "libpldm/platform.h"
4
5#include "terminus_manager.hpp"
6
Thu Nguyenb8cf46b2024-06-15 02:44:35 +00007#include <common/utils.hpp>
8
Gilbert Chende2a1322022-05-24 15:35:21 +01009#include <ranges>
10
Gilbert Chen6c7fed42022-02-22 15:40:17 +000011namespace pldm
12{
13namespace platform_mc
14{
15
16Terminus::Terminus(pldm_tid_t tid, uint64_t supportedTypes) :
Thu Nguyen51d66b52024-08-06 09:15:55 +000017 initialized(false), synchronyConfigurationSupported(0), tid(tid),
18 supportedTypes(supportedTypes)
Gilbert Chen6c7fed42022-02-22 15:40:17 +000019{}
20
21bool Terminus::doesSupportType(uint8_t type)
22{
23 return supportedTypes.test(type);
24}
25
26bool Terminus::doesSupportCommand(uint8_t type, uint8_t command)
27{
28 if (!doesSupportType(type))
29 {
30 return false;
31 }
32
33 try
34 {
35 const size_t idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (command / 8);
36 if (idx >= supportedCmds.size())
37 {
38 return false;
39 }
40
41 if (supportedCmds[idx] & (1 << (command % 8)))
42 {
43 lg2::info(
44 "PLDM type {TYPE} command {CMD} is supported by terminus {TID}",
45 "TYPE", type, "CMD", command, "TID", getTid());
46 return true;
47 }
48 }
49 catch (const std::exception& e)
50 {
51 return false;
52 }
53
54 return false;
55}
56
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000057std::optional<std::string_view> Terminus::findTerminusName()
58{
59 auto it = std::find_if(
60 entityAuxiliaryNamesTbl.begin(), entityAuxiliaryNamesTbl.end(),
61 [](const std::shared_ptr<EntityAuxiliaryNames>& entityAuxiliaryNames) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040062 const auto& [key, entityNames] = *entityAuxiliaryNames;
63 /**
64 * There is only one Overal system container entity in one terminus.
65 * The entity auxiliary name PDR of that terminus with the that type
66 *of containerID will include terminus name.
67 **/
68 return (
69 entityAuxiliaryNames &&
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000070 key.containerId == PLDM_PLATFORM_ENTITY_SYSTEM_CONTAINER_ID &&
71 entityNames.size());
Patrick Williams16c2a0a2024-08-16 15:20:59 -040072 });
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000073
74 if (it != entityAuxiliaryNamesTbl.end())
75 {
76 const auto& [key, entityNames] = **it;
77 if (!entityNames.size())
78 {
79 return std::nullopt;
80 }
81 return entityNames[0].second;
82 }
83
84 return std::nullopt;
85}
86
Thu Nguyen3c5486d2024-08-01 08:03:08 +000087bool Terminus::createInventoryPath(std::string tName)
88{
89 if (tName.empty())
90 {
91 return false;
92 }
93
94 inventoryPath = "/xyz/openbmc_project/inventory/system/board/" + tName;
95 try
96 {
97 inventoryItemBoardInft = std::make_unique<InventoryItemBoardIntf>(
98 utils::DBusHandler::getBus(), inventoryPath.c_str());
99 return true;
100 }
101 catch (const sdbusplus::exception_t& e)
102 {
103 lg2::error(
104 "Failed to create Inventory Board interface for device {PATH}",
105 "PATH", inventoryPath);
106 }
107
108 return false;
109}
110
Gilbert Chende2a1322022-05-24 15:35:21 +0100111void Terminus::parseTerminusPDRs()
112{
113 std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>>
114 numericSensorPdrs{};
115 std::vector<std::shared_ptr<pldm_compact_numeric_sensor_pdr>>
116 compactNumericSensorPdrs{};
117
118 for (auto& pdr : pdrs)
119 {
120 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
121 switch (pdrHdr->type)
122 {
123 case PLDM_SENSOR_AUXILIARY_NAMES_PDR:
124 {
125 auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr);
126 if (!sensorAuxNames)
127 {
128 lg2::error(
129 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
130 "TYPE", pdrHdr->type, "HANDLE",
131 static_cast<uint32_t>(pdrHdr->record_handle));
132 continue;
133 }
134 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
135 break;
136 }
137 case PLDM_NUMERIC_SENSOR_PDR:
138 {
139 auto parsedPdr = parseNumericSensorPDR(pdr);
140 if (!parsedPdr)
141 {
142 lg2::error(
143 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
144 "TYPE", pdrHdr->type, "HANDLE",
145 static_cast<uint32_t>(pdrHdr->record_handle));
146 continue;
147 }
148 numericSensorPdrs.emplace_back(std::move(parsedPdr));
149 break;
150 }
151 case PLDM_COMPACT_NUMERIC_SENSOR_PDR:
152 {
153 auto parsedPdr = parseCompactNumericSensorPDR(pdr);
154 if (!parsedPdr)
155 {
156 lg2::error(
157 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
158 "TYPE", pdrHdr->type, "HANDLE",
159 static_cast<uint32_t>(pdrHdr->record_handle));
160 continue;
161 }
162 auto sensorAuxNames = parseCompactNumericSensorNames(pdr);
163 if (!sensorAuxNames)
164 {
165 lg2::error(
166 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
167 "TYPE", pdrHdr->type, "HANDLE",
168 static_cast<uint32_t>(pdrHdr->record_handle));
169 continue;
170 }
171 compactNumericSensorPdrs.emplace_back(std::move(parsedPdr));
172 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
173 break;
174 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000175 case PLDM_ENTITY_AUXILIARY_NAMES_PDR:
176 {
177 auto entityNames = parseEntityAuxiliaryNamesPDR(pdr);
178 if (!entityNames)
179 {
180 lg2::error(
181 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
182 "TYPE", pdrHdr->type, "HANDLE",
183 static_cast<uint32_t>(pdrHdr->record_handle));
184 continue;
185 }
186 entityAuxiliaryNamesTbl.emplace_back(std::move(entityNames));
187 break;
188 }
Gilbert Chende2a1322022-05-24 15:35:21 +0100189 default:
190 {
191 lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}",
192 "TYPE", pdrHdr->type, "HANDLE",
193 static_cast<uint32_t>(pdrHdr->record_handle));
194 break;
195 }
196 }
197 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000198
199 auto tName = findTerminusName();
200 if (tName && !tName.value().empty())
201 {
202 lg2::info("Terminus {TID} has Auxiliary Name {NAME}.", "TID", tid,
203 "NAME", tName.value());
204 terminusName = static_cast<std::string>(tName.value());
205 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000206
207 if (terminusName.empty() &&
208 (numericSensorPdrs.size() || compactNumericSensorPdrs.size()))
209 {
210 lg2::error(
211 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
212 "TID", tid);
213 return;
214 }
215
216 if (createInventoryPath(terminusName))
217 {
218 lg2::error("Terminus ID {TID}: Created Inventory path.", "TID", tid);
219 }
220
221 for (auto pdr : numericSensorPdrs)
222 {
223 addNumericSensor(pdr);
224 }
225
226 for (auto pdr : compactNumericSensorPdrs)
227 {
228 addCompactNumericSensor(pdr);
229 }
Gilbert Chende2a1322022-05-24 15:35:21 +0100230}
231
232std::shared_ptr<SensorAuxiliaryNames>
233 Terminus::getSensorAuxiliaryNames(SensorId id)
234{
235 auto it = std::find_if(
236 sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(),
237 [id](
238 const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400239 const auto& [sensorId, sensorCnt, sensorNames] =
240 *sensorAuxiliaryNames;
241 return sensorId == id;
242 });
Gilbert Chende2a1322022-05-24 15:35:21 +0100243
244 if (it != sensorAuxiliaryNamesTbl.end())
245 {
246 return *it;
247 }
248 return nullptr;
249};
250
251std::shared_ptr<SensorAuxiliaryNames>
252 Terminus::parseSensorAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
253{
254 constexpr uint8_t nullTerminator = 0;
255 auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>(
256 pdrData.data());
257 const uint8_t* ptr = pdr->names;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000258 std::vector<AuxiliaryNames> sensorAuxNames{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100259 char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN];
260 for ([[maybe_unused]] const auto& sensor :
261 std::views::iota(0, static_cast<int>(pdr->sensor_count)))
262 {
263 const uint8_t nameStringCount = static_cast<uint8_t>(*ptr);
264 ptr += sizeof(uint8_t);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000265 AuxiliaryNames nameStrings{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100266 for ([[maybe_unused]] const auto& count :
267 std::views::iota(0, static_cast<int>(nameStringCount)))
268 {
269 std::string_view nameLanguageTag(
270 reinterpret_cast<const char*>(ptr));
271 ptr += nameLanguageTag.size() + sizeof(nullTerminator);
272
273 int u16NameStringLen = 0;
274 for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2)
275 {
276 u16NameStringLen++;
277 }
278 /* include terminator */
279 u16NameStringLen++;
280
281 std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0);
282 if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN)
283 {
284 lg2::error("Sensor name to long.");
285 return nullptr;
286 }
287 memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t));
288 std::u16string u16NameString(alignedBuffer, u16NameStringLen);
tal-yacf1e32c12024-08-12 13:12:30 +0300289 ptr += u16NameString.size() * sizeof(uint16_t);
Gilbert Chende2a1322022-05-24 15:35:21 +0100290 std::transform(u16NameString.cbegin(), u16NameString.cend(),
291 u16NameString.begin(),
292 [](uint16_t utf16) { return be16toh(utf16); });
293 std::string nameString =
294 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
295 char16_t>{}
296 .to_bytes(u16NameString);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000297 nameStrings.emplace_back(std::make_pair(
298 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100299 }
300 sensorAuxNames.emplace_back(std::move(nameStrings));
301 }
302 return std::make_shared<SensorAuxiliaryNames>(
303 pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
304}
305
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000306std::shared_ptr<EntityAuxiliaryNames>
307 Terminus::parseEntityAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
308{
309 auto names_offset = sizeof(struct pldm_pdr_hdr) +
310 PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH;
311 auto names_size = pdrData.size() - names_offset;
312
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400313 size_t decodedPdrSize =
314 sizeof(struct pldm_entity_auxiliary_names_pdr) + names_size;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000315 auto vPdr = std::vector<char>(decodedPdrSize);
316 auto decodedPdr =
317 reinterpret_cast<struct pldm_entity_auxiliary_names_pdr*>(vPdr.data());
318
319 auto rc = decode_entity_auxiliary_names_pdr(pdrData.data(), pdrData.size(),
320 decodedPdr, decodedPdrSize);
321
322 if (rc)
323 {
324 lg2::error(
325 "Failed to decode Entity Auxiliary Name PDR data, error {RC}.",
326 "RC", rc);
327 return nullptr;
328 }
329
330 auto vNames =
331 std::vector<pldm_entity_auxiliary_name>(decodedPdr->name_string_count);
332 decodedPdr->names = vNames.data();
333
334 rc = decode_pldm_entity_auxiliary_names_pdr_index(decodedPdr);
335 if (rc)
336 {
337 lg2::error("Failed to decode Entity Auxiliary Name, error {RC}.", "RC",
338 rc);
339 return nullptr;
340 }
341
342 AuxiliaryNames nameStrings{};
343 for (const auto& count :
344 std::views::iota(0, static_cast<int>(decodedPdr->name_string_count)))
345 {
346 std::string_view nameLanguageTag =
347 static_cast<std::string_view>(decodedPdr->names[count].tag);
348 const size_t u16NameStringLen =
349 std::char_traits<char16_t>::length(decodedPdr->names[count].name);
350 std::u16string u16NameString(decodedPdr->names[count].name,
351 u16NameStringLen);
352 std::transform(u16NameString.cbegin(), u16NameString.cend(),
353 u16NameString.begin(),
354 [](uint16_t utf16) { return be16toh(utf16); });
355 std::string nameString =
356 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
357 .to_bytes(u16NameString);
358 nameStrings.emplace_back(std::make_pair(
359 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
360 }
361
362 EntityKey key{decodedPdr->container.entity_type,
363 decodedPdr->container.entity_instance_num,
364 decodedPdr->container.entity_container_id};
365
366 return std::make_shared<EntityAuxiliaryNames>(key, nameStrings);
367}
368
Gilbert Chende2a1322022-05-24 15:35:21 +0100369std::shared_ptr<pldm_numeric_sensor_value_pdr>
370 Terminus::parseNumericSensorPDR(const std::vector<uint8_t>& pdr)
371{
372 const uint8_t* ptr = pdr.data();
373 auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
374 auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get());
375 if (rc)
376 {
377 return nullptr;
378 }
379 return parsedPdr;
380}
381
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000382void Terminus::addNumericSensor(
383 const std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr)
384{
385 uint16_t sensorId = pdr->sensor_id;
386 if (terminusName.empty())
387 {
388 lg2::error(
389 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
390 "TID", tid);
391 return;
392 }
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400393 std::string sensorName =
394 terminusName + "_" + "Sensor_" + std::to_string(pdr->sensor_id);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000395
396 if (pdr->sensor_auxiliary_names_pdr)
397 {
398 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
399 if (sensorAuxiliaryNames)
400 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400401 const auto& [sensorId, sensorCnt, sensorNames] =
402 *sensorAuxiliaryNames;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000403 if (sensorCnt == 1)
404 {
405 for (const auto& [languageTag, name] : sensorNames[0])
406 {
407 if (languageTag == "en" && !name.empty())
408 {
409 sensorName = terminusName + "_" + name;
410 }
411 }
412 }
413 }
414 }
415
416 try
417 {
418 auto sensor = std::make_shared<NumericSensor>(
419 tid, true, pdr, sensorName, inventoryPath);
420 lg2::info("Created NumericSensor {NAME}", "NAME", sensorName);
421 numericSensors.emplace_back(sensor);
422 }
423 catch (const sdbusplus::exception_t& e)
424 {
425 lg2::error(
426 "Failed to create NumericSensor. error - {ERROR} sensorname - {NAME}",
427 "ERROR", e, "NAME", sensorName);
428 }
429}
430
Gilbert Chende2a1322022-05-24 15:35:21 +0100431std::shared_ptr<SensorAuxiliaryNames>
432 Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr)
433{
434 std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
435 sensorAuxNames{};
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000436 AuxiliaryNames nameStrings{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100437 auto pdr =
438 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
439
440 if (sPdr.size() <
441 (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t)))
442 {
443 return nullptr;
444 }
445
446 if (!pdr->sensor_name_length ||
447 (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) -
448 sizeof(uint8_t) + pdr->sensor_name_length)))
449 {
450 return nullptr;
451 }
452
453 std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name),
454 pdr->sensor_name_length);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000455 nameStrings.emplace_back(
456 std::make_pair("en", pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100457 sensorAuxNames.emplace_back(std::move(nameStrings));
458
459 return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,
460 std::move(sensorAuxNames));
461}
462
463std::shared_ptr<pldm_compact_numeric_sensor_pdr>
464 Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr)
465{
466 auto pdr =
467 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
468 if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr))
469 {
470 // Handle error: input data too small to contain valid pdr
471 return nullptr;
472 }
473 auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>();
474
475 parsedPdr->hdr = pdr->hdr;
476 parsedPdr->terminus_handle = pdr->terminus_handle;
477 parsedPdr->sensor_id = pdr->sensor_id;
478 parsedPdr->entity_type = pdr->entity_type;
479 parsedPdr->entity_instance = pdr->entity_instance;
480 parsedPdr->container_id = pdr->container_id;
481 parsedPdr->sensor_name_length = pdr->sensor_name_length;
482 parsedPdr->base_unit = pdr->base_unit;
483 parsedPdr->unit_modifier = pdr->unit_modifier;
484 parsedPdr->occurrence_rate = pdr->occurrence_rate;
485 parsedPdr->range_field_support = pdr->range_field_support;
486 parsedPdr->warning_high = pdr->warning_high;
487 parsedPdr->warning_low = pdr->warning_low;
488 parsedPdr->critical_high = pdr->critical_high;
489 parsedPdr->critical_low = pdr->critical_low;
490 parsedPdr->fatal_high = pdr->fatal_high;
491 parsedPdr->fatal_low = pdr->fatal_low;
492 return parsedPdr;
493}
494
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000495void Terminus::addCompactNumericSensor(
496 const std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr)
497{
498 uint16_t sensorId = pdr->sensor_id;
499 if (terminusName.empty())
500 {
501 lg2::error(
502 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
503 "TID", tid);
504 return;
505 }
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400506 std::string sensorName =
507 terminusName + "_" + "Sensor_" + std::to_string(pdr->sensor_id);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000508
509 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
510 if (sensorAuxiliaryNames)
511 {
512 const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames;
513 if (sensorCnt == 1)
514 {
515 for (const auto& [languageTag, name] : sensorNames[0])
516 {
517 if (languageTag == "en" && !name.empty())
518 {
519 sensorName = terminusName + "_" + name;
520 }
521 }
522 }
523 }
524
525 try
526 {
527 auto sensor = std::make_shared<NumericSensor>(
528 tid, true, pdr, sensorName, inventoryPath);
529 lg2::info("Created Compact NumericSensor {NAME}", "NAME", sensorName);
530 numericSensors.emplace_back(sensor);
531 }
532 catch (const sdbusplus::exception_t& e)
533 {
534 lg2::error(
535 "Failed to create Compact NumericSensor. error - {ERROR} sensorname - {NAME}",
536 "ERROR", e, "NAME", sensorName);
537 }
538}
539
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000540} // namespace platform_mc
541} // namespace pldm