blob: 5b2ab3ccfa04101be2dbbdd34eb537e89492cd19 [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);
286 ptr += (u16NameString.size() + sizeof(nullTerminator)) *
287 sizeof(uint16_t);
288 std::transform(u16NameString.cbegin(), u16NameString.cend(),
289 u16NameString.begin(),
290 [](uint16_t utf16) { return be16toh(utf16); });
291 std::string nameString =
292 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
293 char16_t>{}
294 .to_bytes(u16NameString);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000295 nameStrings.emplace_back(std::make_pair(
296 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100297 }
298 sensorAuxNames.emplace_back(std::move(nameStrings));
299 }
300 return std::make_shared<SensorAuxiliaryNames>(
301 pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
302}
303
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000304std::shared_ptr<EntityAuxiliaryNames>
305 Terminus::parseEntityAuxiliaryNamesPDR(const std::vector<uint8_t>& pdrData)
306{
307 auto names_offset = sizeof(struct pldm_pdr_hdr) +
308 PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH;
309 auto names_size = pdrData.size() - names_offset;
310
311 size_t decodedPdrSize = sizeof(struct pldm_entity_auxiliary_names_pdr) +
312 names_size;
313 auto vPdr = std::vector<char>(decodedPdrSize);
314 auto decodedPdr =
315 reinterpret_cast<struct pldm_entity_auxiliary_names_pdr*>(vPdr.data());
316
317 auto rc = decode_entity_auxiliary_names_pdr(pdrData.data(), pdrData.size(),
318 decodedPdr, decodedPdrSize);
319
320 if (rc)
321 {
322 lg2::error(
323 "Failed to decode Entity Auxiliary Name PDR data, error {RC}.",
324 "RC", rc);
325 return nullptr;
326 }
327
328 auto vNames =
329 std::vector<pldm_entity_auxiliary_name>(decodedPdr->name_string_count);
330 decodedPdr->names = vNames.data();
331
332 rc = decode_pldm_entity_auxiliary_names_pdr_index(decodedPdr);
333 if (rc)
334 {
335 lg2::error("Failed to decode Entity Auxiliary Name, error {RC}.", "RC",
336 rc);
337 return nullptr;
338 }
339
340 AuxiliaryNames nameStrings{};
341 for (const auto& count :
342 std::views::iota(0, static_cast<int>(decodedPdr->name_string_count)))
343 {
344 std::string_view nameLanguageTag =
345 static_cast<std::string_view>(decodedPdr->names[count].tag);
346 const size_t u16NameStringLen =
347 std::char_traits<char16_t>::length(decodedPdr->names[count].name);
348 std::u16string u16NameString(decodedPdr->names[count].name,
349 u16NameStringLen);
350 std::transform(u16NameString.cbegin(), u16NameString.cend(),
351 u16NameString.begin(),
352 [](uint16_t utf16) { return be16toh(utf16); });
353 std::string nameString =
354 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
355 .to_bytes(u16NameString);
356 nameStrings.emplace_back(std::make_pair(
357 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
358 }
359
360 EntityKey key{decodedPdr->container.entity_type,
361 decodedPdr->container.entity_instance_num,
362 decodedPdr->container.entity_container_id};
363
364 return std::make_shared<EntityAuxiliaryNames>(key, nameStrings);
365}
366
Gilbert Chende2a1322022-05-24 15:35:21 +0100367std::shared_ptr<pldm_numeric_sensor_value_pdr>
368 Terminus::parseNumericSensorPDR(const std::vector<uint8_t>& pdr)
369{
370 const uint8_t* ptr = pdr.data();
371 auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
372 auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get());
373 if (rc)
374 {
375 return nullptr;
376 }
377 return parsedPdr;
378}
379
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000380void Terminus::addNumericSensor(
381 const std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr)
382{
383 uint16_t sensorId = pdr->sensor_id;
384 if (terminusName.empty())
385 {
386 lg2::error(
387 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
388 "TID", tid);
389 return;
390 }
391 std::string sensorName = terminusName + "_" + "Sensor_" +
392 std::to_string(pdr->sensor_id);
393
394 if (pdr->sensor_auxiliary_names_pdr)
395 {
396 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
397 if (sensorAuxiliaryNames)
398 {
399 const auto& [sensorId, sensorCnt,
400 sensorNames] = *sensorAuxiliaryNames;
401 if (sensorCnt == 1)
402 {
403 for (const auto& [languageTag, name] : sensorNames[0])
404 {
405 if (languageTag == "en" && !name.empty())
406 {
407 sensorName = terminusName + "_" + name;
408 }
409 }
410 }
411 }
412 }
413
414 try
415 {
416 auto sensor = std::make_shared<NumericSensor>(
417 tid, true, pdr, sensorName, inventoryPath);
418 lg2::info("Created NumericSensor {NAME}", "NAME", sensorName);
419 numericSensors.emplace_back(sensor);
420 }
421 catch (const sdbusplus::exception_t& e)
422 {
423 lg2::error(
424 "Failed to create NumericSensor. error - {ERROR} sensorname - {NAME}",
425 "ERROR", e, "NAME", sensorName);
426 }
427}
428
Gilbert Chende2a1322022-05-24 15:35:21 +0100429std::shared_ptr<SensorAuxiliaryNames>
430 Terminus::parseCompactNumericSensorNames(const std::vector<uint8_t>& sPdr)
431{
432 std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
433 sensorAuxNames{};
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000434 AuxiliaryNames nameStrings{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100435 auto pdr =
436 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
437
438 if (sPdr.size() <
439 (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t)))
440 {
441 return nullptr;
442 }
443
444 if (!pdr->sensor_name_length ||
445 (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) -
446 sizeof(uint8_t) + pdr->sensor_name_length)))
447 {
448 return nullptr;
449 }
450
451 std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name),
452 pdr->sensor_name_length);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000453 nameStrings.emplace_back(
454 std::make_pair("en", pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100455 sensorAuxNames.emplace_back(std::move(nameStrings));
456
457 return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,
458 std::move(sensorAuxNames));
459}
460
461std::shared_ptr<pldm_compact_numeric_sensor_pdr>
462 Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr)
463{
464 auto pdr =
465 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
466 if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr))
467 {
468 // Handle error: input data too small to contain valid pdr
469 return nullptr;
470 }
471 auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>();
472
473 parsedPdr->hdr = pdr->hdr;
474 parsedPdr->terminus_handle = pdr->terminus_handle;
475 parsedPdr->sensor_id = pdr->sensor_id;
476 parsedPdr->entity_type = pdr->entity_type;
477 parsedPdr->entity_instance = pdr->entity_instance;
478 parsedPdr->container_id = pdr->container_id;
479 parsedPdr->sensor_name_length = pdr->sensor_name_length;
480 parsedPdr->base_unit = pdr->base_unit;
481 parsedPdr->unit_modifier = pdr->unit_modifier;
482 parsedPdr->occurrence_rate = pdr->occurrence_rate;
483 parsedPdr->range_field_support = pdr->range_field_support;
484 parsedPdr->warning_high = pdr->warning_high;
485 parsedPdr->warning_low = pdr->warning_low;
486 parsedPdr->critical_high = pdr->critical_high;
487 parsedPdr->critical_low = pdr->critical_low;
488 parsedPdr->fatal_high = pdr->fatal_high;
489 parsedPdr->fatal_low = pdr->fatal_low;
490 return parsedPdr;
491}
492
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000493void Terminus::addCompactNumericSensor(
494 const std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr)
495{
496 uint16_t sensorId = pdr->sensor_id;
497 if (terminusName.empty())
498 {
499 lg2::error(
500 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
501 "TID", tid);
502 return;
503 }
504 std::string sensorName = terminusName + "_" + "Sensor_" +
505 std::to_string(pdr->sensor_id);
506
507 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
508 if (sensorAuxiliaryNames)
509 {
510 const auto& [sensorId, sensorCnt, sensorNames] = *sensorAuxiliaryNames;
511 if (sensorCnt == 1)
512 {
513 for (const auto& [languageTag, name] : sensorNames[0])
514 {
515 if (languageTag == "en" && !name.empty())
516 {
517 sensorName = terminusName + "_" + name;
518 }
519 }
520 }
521 }
522
523 try
524 {
525 auto sensor = std::make_shared<NumericSensor>(
526 tid, true, pdr, sensorName, inventoryPath);
527 lg2::info("Created Compact NumericSensor {NAME}", "NAME", sensorName);
528 numericSensors.emplace_back(sensor);
529 }
530 catch (const sdbusplus::exception_t& e)
531 {
532 lg2::error(
533 "Failed to create Compact NumericSensor. error - {ERROR} sensorname - {NAME}",
534 "ERROR", e, "NAME", sensorName);
535 }
536}
537
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000538} // namespace platform_mc
539} // namespace pldm