blob: 004158a5c6089a838b5d91591e61ec7e6841298f [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) {
61 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 of
65 * containerID will include terminus name.
66 **/
67 return (entityAuxiliaryNames &&
68 key.containerId == PLDM_PLATFORM_ENTITY_SYSTEM_CONTAINER_ID &&
69 entityNames.size());
70 });
71
72 if (it != entityAuxiliaryNamesTbl.end())
73 {
74 const auto& [key, entityNames] = **it;
75 if (!entityNames.size())
76 {
77 return std::nullopt;
78 }
79 return entityNames[0].second;
80 }
81
82 return std::nullopt;
83}
84
Thu Nguyen3c5486d2024-08-01 08:03:08 +000085bool Terminus::createInventoryPath(std::string tName)
86{
87 if (tName.empty())
88 {
89 return false;
90 }
91
92 inventoryPath = "/xyz/openbmc_project/inventory/system/board/" + tName;
93 try
94 {
95 inventoryItemBoardInft = std::make_unique<InventoryItemBoardIntf>(
96 utils::DBusHandler::getBus(), inventoryPath.c_str());
97 return true;
98 }
99 catch (const sdbusplus::exception_t& e)
100 {
101 lg2::error(
102 "Failed to create Inventory Board interface for device {PATH}",
103 "PATH", inventoryPath);
104 }
105
106 return false;
107}
108
Gilbert Chende2a1322022-05-24 15:35:21 +0100109void Terminus::parseTerminusPDRs()
110{
111 std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>>
112 numericSensorPdrs{};
113 std::vector<std::shared_ptr<pldm_compact_numeric_sensor_pdr>>
114 compactNumericSensorPdrs{};
115
116 for (auto& pdr : pdrs)
117 {
118 auto pdrHdr = reinterpret_cast<pldm_pdr_hdr*>(pdr.data());
119 switch (pdrHdr->type)
120 {
121 case PLDM_SENSOR_AUXILIARY_NAMES_PDR:
122 {
123 auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr);
124 if (!sensorAuxNames)
125 {
126 lg2::error(
127 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
128 "TYPE", pdrHdr->type, "HANDLE",
129 static_cast<uint32_t>(pdrHdr->record_handle));
130 continue;
131 }
132 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
133 break;
134 }
135 case PLDM_NUMERIC_SENSOR_PDR:
136 {
137 auto parsedPdr = parseNumericSensorPDR(pdr);
138 if (!parsedPdr)
139 {
140 lg2::error(
141 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
142 "TYPE", pdrHdr->type, "HANDLE",
143 static_cast<uint32_t>(pdrHdr->record_handle));
144 continue;
145 }
146 numericSensorPdrs.emplace_back(std::move(parsedPdr));
147 break;
148 }
149 case PLDM_COMPACT_NUMERIC_SENSOR_PDR:
150 {
151 auto parsedPdr = parseCompactNumericSensorPDR(pdr);
152 if (!parsedPdr)
153 {
154 lg2::error(
155 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
156 "TYPE", pdrHdr->type, "HANDLE",
157 static_cast<uint32_t>(pdrHdr->record_handle));
158 continue;
159 }
160 auto sensorAuxNames = parseCompactNumericSensorNames(pdr);
161 if (!sensorAuxNames)
162 {
163 lg2::error(
164 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
165 "TYPE", pdrHdr->type, "HANDLE",
166 static_cast<uint32_t>(pdrHdr->record_handle));
167 continue;
168 }
169 compactNumericSensorPdrs.emplace_back(std::move(parsedPdr));
170 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
171 break;
172 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000173 case PLDM_ENTITY_AUXILIARY_NAMES_PDR:
174 {
175 auto entityNames = parseEntityAuxiliaryNamesPDR(pdr);
176 if (!entityNames)
177 {
178 lg2::error(
179 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
180 "TYPE", pdrHdr->type, "HANDLE",
181 static_cast<uint32_t>(pdrHdr->record_handle));
182 continue;
183 }
184 entityAuxiliaryNamesTbl.emplace_back(std::move(entityNames));
185 break;
186 }
Gilbert Chende2a1322022-05-24 15:35:21 +0100187 default:
188 {
189 lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}",
190 "TYPE", pdrHdr->type, "HANDLE",
191 static_cast<uint32_t>(pdrHdr->record_handle));
192 break;
193 }
194 }
195 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000196
197 auto tName = findTerminusName();
198 if (tName && !tName.value().empty())
199 {
200 lg2::info("Terminus {TID} has Auxiliary Name {NAME}.", "TID", tid,
201 "NAME", tName.value());
202 terminusName = static_cast<std::string>(tName.value());
203 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000204
205 if (terminusName.empty() &&
206 (numericSensorPdrs.size() || compactNumericSensorPdrs.size()))
207 {
208 lg2::error(
209 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
210 "TID", tid);
211 return;
212 }
213
214 if (createInventoryPath(terminusName))
215 {
216 lg2::error("Terminus ID {TID}: Created Inventory path.", "TID", tid);
217 }
218
219 for (auto pdr : numericSensorPdrs)
220 {
221 addNumericSensor(pdr);
222 }
223
224 for (auto pdr : compactNumericSensorPdrs)
225 {
226 addCompactNumericSensor(pdr);
227 }
Gilbert Chende2a1322022-05-24 15:35:21 +0100228}
229
230std::shared_ptr<SensorAuxiliaryNames>
231 Terminus::getSensorAuxiliaryNames(SensorId id)
232{
233 auto it = std::find_if(
234 sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(),
235 [id](
236 const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) {
237 const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames;
238 return sensorId == id;
239 });
240
241 if (it != sensorAuxiliaryNamesTbl.end())
242 {
243 return *it;
244 }
245 return nullptr;
246};
247
248std::shared_ptr<SensorAuxiliaryNames>
249 Terminus::parseSensorAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
250{
251 constexpr uint8_t nullTerminator = 0;
252 auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>(
253 pdrData.data());
254 const uint8_t* ptr = pdr->names;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000255 std::vector<AuxiliaryNames> sensorAuxNames{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100256 char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN];
257 for ([[maybe_unused]] const auto& sensor :
258 std::views::iota(0, static_cast<int>(pdr->sensor_count)))
259 {
260 const uint8_t nameStringCount = static_cast<uint8_t>(*ptr);
261 ptr += sizeof(uint8_t);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000262 AuxiliaryNames nameStrings{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100263 for ([[maybe_unused]] const auto& count :
264 std::views::iota(0, static_cast<int>(nameStringCount)))
265 {
266 std::string_view nameLanguageTag(
267 reinterpret_cast<const char*>(ptr));
268 ptr += nameLanguageTag.size() + sizeof(nullTerminator);
269
270 int u16NameStringLen = 0;
271 for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2)
272 {
273 u16NameStringLen++;
274 }
275 /* include terminator */
276 u16NameStringLen++;
277
278 std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0);
279 if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN)
280 {
281 lg2::error("Sensor name to long.");
282 return nullptr;
283 }
284 memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t));
285 std::u16string u16NameString(alignedBuffer, u16NameStringLen);
tal-yacf1e32c12024-08-12 13:12:30 +0300286 ptr += u16NameString.size() * sizeof(uint16_t);
Gilbert Chende2a1322022-05-24 15:35:21 +0100287 std::transform(u16NameString.cbegin(), u16NameString.cend(),
288 u16NameString.begin(),
289 [](uint16_t utf16) { return be16toh(utf16); });
290 std::string nameString =
291 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
292 char16_t>{}
293 .to_bytes(u16NameString);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000294 nameStrings.emplace_back(std::make_pair(
295 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100296 }
297 sensorAuxNames.emplace_back(std::move(nameStrings));
298 }
299 return std::make_shared<SensorAuxiliaryNames>(
300 pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
301}
302
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000303std::shared_ptr<EntityAuxiliaryNames>
304 Terminus::parseEntityAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
305{
306 auto names_offset = sizeof(struct pldm_pdr_hdr) +
307 PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH;
308 auto names_size = pdrData.size() - names_offset;
309
310 size_t decodedPdrSize = sizeof(struct pldm_entity_auxiliary_names_pdr) +
311 names_size;
312 auto vPdr = std::vector<char>(decodedPdrSize);
313 auto decodedPdr =
314 reinterpret_cast<struct pldm_entity_auxiliary_names_pdr*>(vPdr.data());
315
316 auto rc = decode_entity_auxiliary_names_pdr(pdrData.data(), pdrData.size(),
317 decodedPdr, decodedPdrSize);
318
319 if (rc)
320 {
321 lg2::error(
322 "Failed to decode Entity Auxiliary Name PDR data, error {RC}.",
323 "RC", rc);
324 return nullptr;
325 }
326
327 auto vNames =
328 std::vector<pldm_entity_auxiliary_name>(decodedPdr->name_string_count);
329 decodedPdr->names = vNames.data();
330
331 rc = decode_pldm_entity_auxiliary_names_pdr_index(decodedPdr);
332 if (rc)
333 {
334 lg2::error("Failed to decode Entity Auxiliary Name, error {RC}.", "RC",
335 rc);
336 return nullptr;
337 }
338
339 AuxiliaryNames nameStrings{};
340 for (const auto& count :
341 std::views::iota(0, static_cast<int>(decodedPdr->name_string_count)))
342 {
343 std::string_view nameLanguageTag =
344 static_cast<std::string_view>(decodedPdr->names[count].tag);
345 const size_t u16NameStringLen =
346 std::char_traits<char16_t>::length(decodedPdr->names[count].name);
347 std::u16string u16NameString(decodedPdr->names[count].name,
348 u16NameStringLen);
349 std::transform(u16NameString.cbegin(), u16NameString.cend(),
350 u16NameString.begin(),
351 [](uint16_t utf16) { return be16toh(utf16); });
352 std::string nameString =
353 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
354 .to_bytes(u16NameString);
355 nameStrings.emplace_back(std::make_pair(
356 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
357 }
358
359 EntityKey key{decodedPdr->container.entity_type,
360 decodedPdr->container.entity_instance_num,
361 decodedPdr->container.entity_container_id};
362
363 return std::make_shared<EntityAuxiliaryNames>(key, nameStrings);
364}
365
Gilbert Chende2a1322022-05-24 15:35:21 +0100366std::shared_ptr<pldm_numeric_sensor_value_pdr>
367 Terminus::parseNumericSensorPDR(const std::vector<uint8_t>& pdr)
368{
369 const uint8_t* ptr = pdr.data();
370 auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
371 auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get());
372 if (rc)
373 {
374 return nullptr;
375 }
376 return parsedPdr;
377}
378
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000379void Terminus::addNumericSensor(
380 const std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr)
381{
382 uint16_t sensorId = pdr->sensor_id;
383 if (terminusName.empty())
384 {
385 lg2::error(
386 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
387 "TID", tid);
388 return;
389 }
390 std::string sensorName = terminusName + "_" + "Sensor_" +
391 std::to_string(pdr->sensor_id);
392
393 if (pdr->sensor_auxiliary_names_pdr)
394 {
395 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
396 if (sensorAuxiliaryNames)
397 {
398 const auto& [sensorId, sensorCnt,
399 sensorNames] = *sensorAuxiliaryNames;
400 if (sensorCnt == 1)
401 {
402 for (const auto& [languageTag, name] : sensorNames[0])
403 {
404 if (languageTag == "en" && !name.empty())
405 {
406 sensorName = terminusName + "_" + name;
407 }
408 }
409 }
410 }
411 }
412
413 try
414 {
415 auto sensor = std::make_shared<NumericSensor>(
416 tid, true, pdr, sensorName, inventoryPath);
417 lg2::info("Created NumericSensor {NAME}", "NAME", sensorName);
418 numericSensors.emplace_back(sensor);
419 }
420 catch (const sdbusplus::exception_t& e)
421 {
422 lg2::error(
423 "Failed to create NumericSensor. error - {ERROR} sensorname - {NAME}",
424 "ERROR", e, "NAME", sensorName);
425 }
426}
427
Gilbert Chende2a1322022-05-24 15:35:21 +0100428std::shared_ptr<SensorAuxiliaryNames>
429 Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr)
430{
431 std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
432 sensorAuxNames{};
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000433 AuxiliaryNames nameStrings{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100434 auto pdr =
435 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
436
437 if (sPdr.size() <
438 (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t)))
439 {
440 return nullptr;
441 }
442
443 if (!pdr->sensor_name_length ||
444 (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) -
445 sizeof(uint8_t) + pdr->sensor_name_length)))
446 {
447 return nullptr;
448 }
449
450 std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name),
451 pdr->sensor_name_length);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000452 nameStrings.emplace_back(
453 std::make_pair("en", pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100454 sensorAuxNames.emplace_back(std::move(nameStrings));
455
456 return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,
457 std::move(sensorAuxNames));
458}
459
460std::shared_ptr<pldm_compact_numeric_sensor_pdr>
461 Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr)
462{
463 auto pdr =
464 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
465 if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr))
466 {
467 // Handle error: input data too small to contain valid pdr
468 return nullptr;
469 }
470 auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>();
471
472 parsedPdr->hdr = pdr->hdr;
473 parsedPdr->terminus_handle = pdr->terminus_handle;
474 parsedPdr->sensor_id = pdr->sensor_id;
475 parsedPdr->entity_type = pdr->entity_type;
476 parsedPdr->entity_instance = pdr->entity_instance;
477 parsedPdr->container_id = pdr->container_id;
478 parsedPdr->sensor_name_length = pdr->sensor_name_length;
479 parsedPdr->base_unit = pdr->base_unit;
480 parsedPdr->unit_modifier = pdr->unit_modifier;
481 parsedPdr->occurrence_rate = pdr->occurrence_rate;
482 parsedPdr->range_field_support = pdr->range_field_support;
483 parsedPdr->warning_high = pdr->warning_high;
484 parsedPdr->warning_low = pdr->warning_low;
485 parsedPdr->critical_high = pdr->critical_high;
486 parsedPdr->critical_low = pdr->critical_low;
487 parsedPdr->fatal_high = pdr->fatal_high;
488 parsedPdr->fatal_low = pdr->fatal_low;
489 return parsedPdr;
490}
491
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000492void Terminus::addCompactNumericSensor(
493 const std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr)
494{
495 uint16_t sensorId = pdr->sensor_id;
496 if (terminusName.empty())
497 {
498 lg2::error(
499 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
500 "TID", tid);
501 return;
502 }
503 std::string sensorName = terminusName + "_" + "Sensor_" +
504 std::to_string(pdr->sensor_id);
505
506 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
507 if (sensorAuxiliaryNames)
508 {
509 const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames;
510 if (sensorCnt == 1)
511 {
512 for (const auto& [languageTag, name] : sensorNames[0])
513 {
514 if (languageTag == "en" && !name.empty())
515 {
516 sensorName = terminusName + "_" + name;
517 }
518 }
519 }
520 }
521
522 try
523 {
524 auto sensor = std::make_shared<NumericSensor>(
525 tid, true, pdr, sensorName, inventoryPath);
526 lg2::info("Created Compact NumericSensor {NAME}", "NAME", sensorName);
527 numericSensors.emplace_back(sensor);
528 }
529 catch (const sdbusplus::exception_t& e)
530 {
531 lg2::error(
532 "Failed to create Compact NumericSensor. error - {ERROR} sensorname - {NAME}",
533 "ERROR", e, "NAME", sensorName);
534 }
535}
536
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000537} // namespace platform_mc
538} // namespace pldm