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