blob: 7fe1b7c1c8ac9fd419498f2e5a0ccfa9d4e9847f [file] [log] [blame]
Deepak Kodihalli70e8db02019-10-21 00:59:46 -05001#include "fru.hpp"
2
Deepak Kodihallid130e1a2020-06-17 05:55:32 -05003#include "common/utils.hpp"
Deepak Kodihalli70e8db02019-10-21 00:59:46 -05004
George Liuc453e162022-12-21 17:16:23 +08005#include <libpldm/entity.h>
6#include <libpldm/utils.h>
Deepak Kodihalli70e8db02019-10-21 00:59:46 -05007#include <systemd/sd-journal.h>
8
Riya Dixit49cfb132023-03-02 04:26:53 -06009#include <phosphor-logging/lg2.hpp>
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050010#include <sdbusplus/bus.hpp>
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050011
George Liu5bfb0dc2021-05-01 14:28:41 +080012#include <optional>
George Liu6492f522020-06-16 10:34:05 +080013#include <set>
George Liu5bfb0dc2021-05-01 14:28:41 +080014#include <stack>
George Liu077fea22020-04-08 16:47:14 +080015
Riya Dixit49cfb132023-03-02 04:26:53 -060016PHOSPHOR_LOG2_USING;
17
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050018namespace pldm
19{
Deepak Kodihalli70e8db02019-10-21 00:59:46 -050020namespace responder
21{
George Liu5bfb0dc2021-05-01 14:28:41 +080022
23constexpr auto root = "/xyz/openbmc_project/inventory/";
24
Patrick Williams366507c2025-02-03 14:28:01 -050025std::optional<pldm_entity> FruImpl::getEntityByObjectPath(
26 const dbus::InterfaceMap& intfMaps)
George Liu5bfb0dc2021-05-01 14:28:41 +080027{
28 for (const auto& intfMap : intfMaps)
29 {
30 try
31 {
32 pldm_entity entity{};
33 entity.entity_type = parser.getEntityType(intfMap.first);
34 return entity;
35 }
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -050036 catch (const std::exception&)
George Liu5bfb0dc2021-05-01 14:28:41 +080037 {
38 continue;
39 }
40 }
41
42 return std::nullopt;
43}
44
45void FruImpl::updateAssociationTree(const dbus::ObjectValueTree& objects,
46 const std::string& path)
47{
48 if (path.find(root) == std::string::npos)
49 {
50 return;
51 }
52
53 std::stack<std::string> tmpObjPaths{};
54 tmpObjPaths.emplace(path);
55
56 auto obj = pldm::utils::findParent(path);
57 while ((obj + '/') != root)
58 {
59 tmpObjPaths.emplace(obj);
60 obj = pldm::utils::findParent(obj);
61 }
62
63 std::stack<std::string> tmpObj = tmpObjPaths;
64 while (!tmpObj.empty())
65 {
66 std::string s = tmpObj.top();
George Liu5bfb0dc2021-05-01 14:28:41 +080067 tmpObj.pop();
68 }
Manojkiran Eda2576aec2024-06-17 12:05:17 +053069 // Update pldm entity to association tree
George Liu5bfb0dc2021-05-01 14:28:41 +080070 std::string prePath = tmpObjPaths.top();
71 while (!tmpObjPaths.empty())
72 {
73 std::string currPath = tmpObjPaths.top();
74 tmpObjPaths.pop();
75
76 do
77 {
78 if (objToEntityNode.contains(currPath))
79 {
80 pldm_entity node =
81 pldm_entity_extract(objToEntityNode.at(currPath));
Manojkiran Eda8e715ae2021-07-04 21:46:43 +053082 if (pldm_entity_association_tree_find_with_locality(
83 entityTree, &node, false))
George Liu5bfb0dc2021-05-01 14:28:41 +080084 {
85 break;
86 }
87 }
88 else
89 {
90 if (!objects.contains(currPath))
91 {
92 break;
93 }
94
95 auto entityPtr = getEntityByObjectPath(objects.at(currPath));
96 if (!entityPtr)
97 {
98 break;
99 }
100
101 pldm_entity entity = *entityPtr;
102
Pavithra Barithaya15b94112024-04-10 02:42:12 -0500103 for (const auto& it : objToEntityNode)
George Liu5bfb0dc2021-05-01 14:28:41 +0800104 {
105 pldm_entity node = pldm_entity_extract(it.second);
106 if (node.entity_type == entity.entity_type)
107 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400108 entity.entity_instance_num =
109 node.entity_instance_num + 1;
George Liu5bfb0dc2021-05-01 14:28:41 +0800110 break;
111 }
112 }
113
114 if (currPath == prePath)
115 {
Manojkiran Eda8e715ae2021-07-04 21:46:43 +0530116 auto node = pldm_entity_association_tree_add_entity(
George Liu5bfb0dc2021-05-01 14:28:41 +0800117 entityTree, &entity, 0xFFFF, nullptr,
Manojkiran Eda8e715ae2021-07-04 21:46:43 +0530118 PLDM_ENTITY_ASSOCIAION_PHYSICAL, false, true, 0xFFFF);
George Liu5bfb0dc2021-05-01 14:28:41 +0800119 objToEntityNode[currPath] = node;
120 }
121 else
122 {
123 if (objToEntityNode.contains(prePath))
124 {
Manojkiran Eda8e715ae2021-07-04 21:46:43 +0530125 auto node = pldm_entity_association_tree_add_entity(
George Liu5bfb0dc2021-05-01 14:28:41 +0800126 entityTree, &entity, 0xFFFF,
127 objToEntityNode[prePath],
Manojkiran Eda8e715ae2021-07-04 21:46:43 +0530128 PLDM_ENTITY_ASSOCIAION_PHYSICAL, false, true,
129 0xFFFF);
George Liu5bfb0dc2021-05-01 14:28:41 +0800130 objToEntityNode[currPath] = node;
131 }
132 }
133 }
134 } while (0);
135
136 prePath = currPath;
137 }
138}
139
Tom Joseph33e9c7e2020-06-11 22:09:52 +0530140void FruImpl::buildFRUTable()
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500141{
Tom Joseph33e9c7e2020-06-11 22:09:52 +0530142 if (isBuilt)
143 {
144 return;
145 }
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500146
Tom Josephf0076332020-02-06 10:18:50 +0530147 fru_parser::DBusLookupInfo dbusInfo;
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500148
149 try
150 {
Tom Joseph33e9c7e2020-06-11 22:09:52 +0530151 dbusInfo = parser.inventoryLookup();
Riya Dixit754041d2024-02-20 06:15:49 -0600152 objects = pldm::utils::DBusHandler::getInventoryObjects<
153 pldm::utils::DBusHandler>();
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500154 }
155 catch (const std::exception& e)
156 {
Riya Dixit89644442024-03-31 05:39:59 -0500157 error(
158 "Failed to build FRU table due to inventory lookup, error - {ERROR}",
159 "ERROR", e);
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500160 return;
161 }
162
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500163 auto itemIntfsLookup = std::get<2>(dbusInfo);
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500164
165 for (const auto& object : objects)
166 {
167 const auto& interfaces = object.second;
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500168 for (const auto& interface : interfaces)
169 {
Sagar Srinivas06f9b292024-03-31 11:35:28 -0500170 if (itemIntfsLookup.contains(interface.first))
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500171 {
Kamalkumar Patel2a103ef2024-02-14 02:58:08 -0600172 // checking fru present property is available or not.
173 if (!pldm::utils::checkForFruPresence(object.first.str))
174 {
175 continue;
176 }
177
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500178 // An exception will be thrown by getRecordInfo, if the item
179 // D-Bus interface name specified in FRU_Master.json does
180 // not have corresponding config jsons
181 try
182 {
George Liu5bfb0dc2021-05-01 14:28:41 +0800183 updateAssociationTree(objects, object.first.str);
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500184 pldm_entity entity{};
George Liu5bfb0dc2021-05-01 14:28:41 +0800185 if (objToEntityNode.contains(object.first.str))
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500186 {
George Liu5bfb0dc2021-05-01 14:28:41 +0800187 pldm_entity_node* node =
188 objToEntityNode.at(object.first.str);
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500189
George Liu5bfb0dc2021-05-01 14:28:41 +0800190 entity = pldm_entity_extract(node);
191 }
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500192
Tom Joseph33e9c7e2020-06-11 22:09:52 +0530193 auto recordInfos = parser.getRecordInfo(interface.first);
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500194 populateRecords(interfaces, recordInfos, entity);
George Liuc4ea6a92020-07-14 15:48:44 +0800195
196 associatedEntityMap.emplace(object.first, entity);
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500197 break;
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500198 }
199 catch (const std::exception& e)
200 {
Riya Dixit797f3382023-08-22 22:27:51 -0500201 error(
Riya Dixit89644442024-03-31 05:39:59 -0500202 "Config JSONs missing for the item '{INTERFACE}', error - {ERROR}",
203 "INTERFACE", interface.first, "ERROR", e);
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500204 break;
205 }
206 }
207 }
208 }
209
Andrew Jefferybc2955f2024-08-01 13:15:36 +0000210 int rc = pldm_entity_association_pdr_add(entityTree, pdrRepo, false,
211 TERMINUS_HANDLE);
Andrew Jefferyb0ba34d2023-07-17 17:47:16 +0930212 if (rc < 0)
213 {
214 // pldm_entity_assocation_pdr_add() assert()ed on failure
Riya Dixit89644442024-03-31 05:39:59 -0500215 error("Failed to add PLDM entity association PDR, response code '{RC}'",
216 "RC", rc);
Andrew Jefferyb0ba34d2023-07-17 17:47:16 +0930217 throw std::runtime_error("Failed to add PLDM entity association PDR");
218 }
219
Sampa Misrac073a202021-05-08 10:56:05 -0500220 // save a copy of bmc's entity association tree
221 pldm_entity_association_tree_copy_root(entityTree, bmcEntityTree);
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500222
Tom Joseph33e9c7e2020-06-11 22:09:52 +0530223 isBuilt = true;
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500224}
Pavithra Barithaya47180ac2020-10-28 02:12:05 -0500225std::string FruImpl::populatefwVersion()
226{
227 static constexpr auto fwFunctionalObjPath =
228 "/xyz/openbmc_project/software/functional";
229 auto& bus = pldm::utils::DBusHandler::getBus();
230 std::string currentBmcVersion;
231 try
232 {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400233 auto method =
234 bus.new_method_call(pldm::utils::mapperService, fwFunctionalObjPath,
235 pldm::utils::dbusProperties, "Get");
Pavithra Barithaya47180ac2020-10-28 02:12:05 -0500236 method.append("xyz.openbmc_project.Association", "endpoints");
237 std::variant<std::vector<std::string>> paths;
vkaverap@in.ibm.com91a092f2023-09-18 23:39:44 -0500238 auto reply = bus.call(method, dbusTimeout);
Pavithra Barithaya47180ac2020-10-28 02:12:05 -0500239 reply.read(paths);
240 auto fwRunningVersion = std::get<std::vector<std::string>>(paths)[0];
241 constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
242 auto version = pldm::utils::DBusHandler().getDbusPropertyVariant(
243 fwRunningVersion.c_str(), "Version", versionIntf);
244 currentBmcVersion = std::get<std::string>(version);
245 }
246 catch (const std::exception& e)
247 {
Manojkiran Eda2576aec2024-06-17 12:05:17 +0530248 error("Failed to make a d-bus call Association, error - {ERROR}",
Riya Dixit89644442024-03-31 05:39:59 -0500249 "ERROR", e);
Pavithra Barithaya47180ac2020-10-28 02:12:05 -0500250 return {};
251 }
252 return currentBmcVersion;
253}
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500254void FruImpl::populateRecords(
255 const pldm::responder::dbus::InterfaceMap& interfaces,
Deepak Kodihalli3cd61812020-03-10 06:38:45 -0500256 const fru_parser::FruRecordInfos& recordInfos, const pldm_entity& entity)
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500257{
258 // recordSetIdentifier for the FRU will be set when the first record gets
259 // added for the FRU
260 uint16_t recordSetIdentifier = 0;
261 auto numRecsCount = numRecs;
Pavithra Barithaya4f2538a2021-03-05 07:32:15 -0600262 static uint32_t bmc_record_handle = 0;
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500263
Patrick Williams6da4f912023-05-10 07:50:53 -0500264 for (const auto& [recType, encType, fieldInfos] : recordInfos)
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500265 {
266 std::vector<uint8_t> tlvs;
267 uint8_t numFRUFields = 0;
Patrick Williams6da4f912023-05-10 07:50:53 -0500268 for (const auto& [intf, prop, propType, fieldTypeNum] : fieldInfos)
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500269 {
270 try
271 {
Pavithra Barithaya47180ac2020-10-28 02:12:05 -0500272 pldm::responder::dbus::Value propValue;
Manojkiran Eda2b7c1bf2021-09-09 12:26:00 +0530273
274 // Assuming that 0 container Id is assigned to the System (as
275 // that should be the top most container as per dbus hierarchy)
276 if (entity.entity_container_id == 0 && prop == "Version")
Pavithra Barithaya47180ac2020-10-28 02:12:05 -0500277 {
278 propValue = populatefwVersion();
279 }
280 else
281 {
282 propValue = interfaces.at(intf).at(prop);
283 }
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500284 if (propType == "bytearray")
285 {
286 auto byteArray = std::get<std::vector<uint8_t>>(propValue);
287 if (!byteArray.size())
288 {
289 continue;
290 }
291
292 numFRUFields++;
293 tlvs.emplace_back(fieldTypeNum);
294 tlvs.emplace_back(byteArray.size());
295 std::move(std::begin(byteArray), std::end(byteArray),
296 std::back_inserter(tlvs));
297 }
298 else if (propType == "string")
299 {
300 auto str = std::get<std::string>(propValue);
301 if (!str.size())
302 {
303 continue;
304 }
305
306 numFRUFields++;
307 tlvs.emplace_back(fieldTypeNum);
308 tlvs.emplace_back(str.size());
309 std::move(std::begin(str), std::end(str),
310 std::back_inserter(tlvs));
311 }
312 }
Kamalkumar Patel58cbcaf2023-10-06 03:48:25 -0500313 catch (const std::out_of_range&)
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500314 {
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500315 continue;
316 }
317 }
318
319 if (tlvs.size())
320 {
321 if (numRecs == numRecsCount)
322 {
323 recordSetIdentifier = nextRSI();
Pavithra Barithaya4f2538a2021-03-05 07:32:15 -0600324 bmc_record_handle = nextRecordHandle();
Andrew Jeffery17d32902024-08-01 13:15:36 +0000325 int rc = pldm_pdr_add_fru_record_set(
Manojkiran Edacc5f1582021-09-29 17:03:06 +0530326 pdrRepo, TERMINUS_HANDLE, recordSetIdentifier,
327 entity.entity_type, entity.entity_instance_num,
Andrew Jeffery2e248e82023-07-03 17:23:24 +0930328 entity.entity_container_id, &bmc_record_handle);
329 if (rc)
330 {
331 // pldm_pdr_add_fru_record_set() assert()ed on failure
332 throw std::runtime_error(
333 "Failed to add PDR FRU record set");
334 }
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500335 }
336 auto curSize = table.size();
337 table.resize(curSize + recHeaderSize + tlvs.size());
338 encode_fru_record(table.data(), table.size(), &curSize,
339 recordSetIdentifier, recType, numFRUFields,
340 encType, tlvs.data(), tlvs.size());
341 numRecs++;
342 }
343 }
344}
345
Pavithra Barithaya129dab12025-04-24 16:13:03 +0530346void FruImpl::deleteFRURecord(uint16_t rsi)
347{
348 std::vector<uint8_t> updatedFruTbl;
349 size_t pos = 0;
350
351 while (pos < table.size())
352 {
353 // Ensure enough space for the record header
354 if ((table.size() - pos) < sizeof(struct pldm_fru_record_data_format))
355 {
356 // Log or handle corrupt/truncated record
357 error("Error: Incomplete FRU record header");
358 return;
359 }
360
361 auto recordSetSrc =
362 reinterpret_cast<const struct pldm_fru_record_data_format*>(
363 &table[pos]);
364
365 size_t recordLen = sizeof(struct pldm_fru_record_data_format) -
366 sizeof(struct pldm_fru_record_tlv);
367
368 const struct pldm_fru_record_tlv* tlv = recordSetSrc->tlvs;
369
370 for (uint8_t i = 0; i < recordSetSrc->num_fru_fields; ++i)
371 {
372 if ((table.size() - pos) < (recordLen + sizeof(*tlv)))
373 {
374 error("Error: Incomplete TLV header");
375 return;
376 }
377
378 size_t len = sizeof(*tlv) - 1 + tlv->length;
379
380 if ((table.size() - pos) < (recordLen + len))
381 {
382 error("Error: Incomplete TLV data");
383 return;
384 }
385
386 recordLen += len;
387
388 // Advance to next tlv
389 tlv = reinterpret_cast<const struct pldm_fru_record_tlv*>(
390 reinterpret_cast<const uint8_t*>(tlv) + len);
391 }
392
393 if ((le16toh(recordSetSrc->record_set_id) != rsi && rsi != 0))
394 {
395 std::copy(table.begin() + pos, table.begin() + pos + recordLen,
396 std::back_inserter(updatedFruTbl));
397 }
398 else
399 {
400 // Deleted record
401 numRecs--;
402 }
403
404 pos += recordLen;
405 }
406 // Replace the old table with the updated one
407 table = std::move(updatedFruTbl);
408}
409
Pavithra Barithaya9e6631e2024-01-22 00:46:32 -0600410std::vector<uint8_t> FruImpl::tableResize()
411{
412 std::vector<uint8_t> tempTable;
413
414 if (table.size())
415 {
416 std::copy(table.begin(), table.end(), std::back_inserter(tempTable));
417 padBytes = pldm::utils::getNumPadBytes(table.size());
418 tempTable.resize(tempTable.size() + padBytes, 0);
419 }
420 return tempTable;
421}
422
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500423void FruImpl::getFRUTable(Response& response)
424{
425 auto hdrSize = response.size();
Pavithra Barithaya9e6631e2024-01-22 00:46:32 -0600426 std::vector<uint8_t> tempTable;
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500427
Pavithra Barithaya9e6631e2024-01-22 00:46:32 -0600428 if (table.size())
429 {
430 tempTable = tableResize();
Andrew Jeffery2cb36eb2025-04-05 21:35:48 +1030431 checksum = pldm_edac_crc32(tempTable.data(), tempTable.size());
Pavithra Barithaya9e6631e2024-01-22 00:46:32 -0600432 }
433 response.resize(hdrSize + tempTable.size() + sizeof(checksum), 0);
434 std::copy(tempTable.begin(), tempTable.end(), response.begin() + hdrSize);
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500435
436 // Copy the checksum to response data
Pavithra Barithaya9e6631e2024-01-22 00:46:32 -0600437 auto iter = response.begin() + hdrSize + tempTable.size();
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500438 std::copy_n(reinterpret_cast<const uint8_t*>(&checksum), sizeof(checksum),
439 iter);
440}
441
Pavithra Barithaya9e6631e2024-01-22 00:46:32 -0600442void FruImpl::getFRURecordTableMetadata()
443{
444 std::vector<uint8_t> tempTable;
445 if (table.size())
446 {
447 tempTable = tableResize();
Andrew Jeffery2cb36eb2025-04-05 21:35:48 +1030448 checksum = pldm_edac_crc32(tempTable.data(), tempTable.size());
Pavithra Barithaya9e6631e2024-01-22 00:46:32 -0600449 }
450}
451
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400452int FruImpl::getFRURecordByOption(
453 std::vector<uint8_t>& fruData, uint16_t /* fruTableHandle */,
454 uint16_t recordSetIdentifer, uint8_t recordType, uint8_t fieldType)
John Wang9e82ad12020-06-12 10:53:32 +0800455{
Manojkiran Eda31a78442021-09-12 15:18:25 +0530456 using sum = uint32_t;
457
John Wang9e82ad12020-06-12 10:53:32 +0800458 // FRU table is built lazily, build if not done.
459 buildFRUTable();
460
461 /* 7 is sizeof(checksum,4) + padBytesMax(3)
462 * We can not know size of the record table got by options in advance, but
463 * it must be less than the source table. So it's safe to use sizeof the
464 * source table + 7 as the buffer length
465 */
466 size_t recordTableSize = table.size() - padBytes + 7;
467 fruData.resize(recordTableSize, 0);
468
Andrew Jeffery40d43872024-09-07 11:00:07 +0000469 int rc = get_fru_record_by_option(
Andrew Jeffery663783b2023-07-03 12:58:14 +0930470 table.data(), table.size() - padBytes, fruData.data(), &recordTableSize,
471 recordSetIdentifer, recordType, fieldType);
John Wang9e82ad12020-06-12 10:53:32 +0800472
Andrew Jeffery663783b2023-07-03 12:58:14 +0930473 if (rc != PLDM_SUCCESS || recordTableSize == 0)
John Wang9e82ad12020-06-12 10:53:32 +0800474 {
475 return PLDM_FRU_DATA_STRUCTURE_TABLE_UNAVAILABLE;
476 }
477
Sridevi Ramesheefe49b2022-06-27 11:51:02 -0500478 auto pads = pldm::utils::getNumPadBytes(recordTableSize);
Andrew Jeffery2cb36eb2025-04-05 21:35:48 +1030479 pldm_edac_crc32(fruData.data(), recordTableSize + pads);
John Wang9e82ad12020-06-12 10:53:32 +0800480
481 auto iter = fruData.begin() + recordTableSize + pads;
482 std::copy_n(reinterpret_cast<const uint8_t*>(&checksum), sizeof(checksum),
483 iter);
484 fruData.resize(recordTableSize + pads + sizeof(sum));
485
486 return PLDM_SUCCESS;
487}
488
Pavithra Barithayaa410c652021-07-22 01:32:47 -0500489int FruImpl::setFRUTable(const std::vector<uint8_t>& fruData)
490{
491 auto record =
492 reinterpret_cast<const pldm_fru_record_data_format*>(fruData.data());
493 if (record)
494 {
495 if (oemFruHandler && record->record_type == PLDM_FRU_RECORD_TYPE_OEM)
496 {
497 auto rc = oemFruHandler->processOEMFRUTable(fruData);
498 if (!rc)
499 {
500 return PLDM_SUCCESS;
501 }
502 }
503 }
504 return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
505}
506
Pavithra Barithayaaac7db32025-10-16 11:47:09 +0530507uint32_t FruImpl::addHotPlugRecord(
508 pldm::responder::pdr_utils::PdrEntry pdrEntry)
509{
510 uint32_t lastHandle = 0;
511 uint32_t recordHandle = 0;
512
513 if (oemPlatformHandler)
514 {
515 auto lastLocalRecord = oemPlatformHandler->fetchLastBMCRecord(pdrRepo);
516 lastHandle = pldm_pdr_get_record_handle(pdrRepo, lastLocalRecord);
517 }
518
519 pdrEntry.handle.recordHandle = lastHandle + 1;
520 pldm_pdr_add(pdrRepo, pdrEntry.data, pdrEntry.size, false,
521 pdrEntry.handle.recordHandle, &recordHandle);
522
523 return recordHandle;
524}
525
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500526namespace fru
527{
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500528Response Handler::getFRURecordTableMetadata(const pldm_msg* request,
529 size_t /*payloadLength*/)
530{
Tom Joseph33e9c7e2020-06-11 22:09:52 +0530531 // FRU table is built lazily, build if not done.
532 buildFRUTable();
533
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500534 constexpr uint8_t major = 0x01;
535 constexpr uint8_t minor = 0x00;
536 constexpr uint32_t maxSize = 0xFFFFFFFF;
537
538 Response response(sizeof(pldm_msg_hdr) +
539 PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES,
540 0);
Pavithra Barithaya677a4552025-01-31 10:33:39 +0530541 auto responsePtr = new (response.data()) pldm_msg;
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500542
Pavithra Barithaya9e6631e2024-01-22 00:46:32 -0600543 impl.getFRURecordTableMetadata();
544
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500545 auto rc = encode_get_fru_record_table_metadata_resp(
546 request->hdr.instance_id, PLDM_SUCCESS, major, minor, maxSize,
547 impl.size(), impl.numRSI(), impl.numRecords(), impl.checkSum(),
548 responsePtr);
549 if (rc != PLDM_SUCCESS)
550 {
551 return ccOnlyResponse(request, rc);
552 }
553
554 return response;
555}
556
557Response Handler::getFRURecordTable(const pldm_msg* request,
558 size_t payloadLength)
559{
Tom Joseph33e9c7e2020-06-11 22:09:52 +0530560 // FRU table is built lazily, build if not done.
561 buildFRUTable();
562
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500563 if (payloadLength != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES)
564 {
565 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
566 }
567
568 Response response(
569 sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES, 0);
Pavithra Barithaya677a4552025-01-31 10:33:39 +0530570 auto responsePtr = new (response.data()) pldm_msg;
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500571
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400572 auto rc =
573 encode_get_fru_record_table_resp(request->hdr.instance_id, PLDM_SUCCESS,
574 0, PLDM_START_AND_END, responsePtr);
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500575 if (rc != PLDM_SUCCESS)
576 {
577 return ccOnlyResponse(request, rc);
578 }
579
580 impl.getFRUTable(response);
581
582 return response;
583}
584
John Wang9e82ad12020-06-12 10:53:32 +0800585Response Handler::getFRURecordByOption(const pldm_msg* request,
586 size_t payloadLength)
587{
588 if (payloadLength != sizeof(pldm_get_fru_record_by_option_req))
589 {
590 return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
591 }
592
593 uint32_t retDataTransferHandle{};
594 uint16_t retFruTableHandle{};
595 uint16_t retRecordSetIdentifier{};
596 uint8_t retRecordType{};
597 uint8_t retFieldType{};
598 uint8_t retTransferOpFlag{};
599
600 auto rc = decode_get_fru_record_by_option_req(
601 request, payloadLength, &retDataTransferHandle, &retFruTableHandle,
602 &retRecordSetIdentifier, &retRecordType, &retFieldType,
603 &retTransferOpFlag);
604
605 if (rc != PLDM_SUCCESS)
606 {
607 return ccOnlyResponse(request, rc);
608 }
609
610 std::vector<uint8_t> fruData;
611 rc = impl.getFRURecordByOption(fruData, retFruTableHandle,
612 retRecordSetIdentifier, retRecordType,
613 retFieldType);
614 if (rc != PLDM_SUCCESS)
615 {
616 return ccOnlyResponse(request, rc);
617 }
618
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400619 auto respPayloadLength =
620 PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES + fruData.size();
John Wang9e82ad12020-06-12 10:53:32 +0800621 Response response(sizeof(pldm_msg_hdr) + respPayloadLength, 0);
Pavithra Barithaya677a4552025-01-31 10:33:39 +0530622 auto responsePtr = new (response.data()) pldm_msg;
John Wang9e82ad12020-06-12 10:53:32 +0800623
624 rc = encode_get_fru_record_by_option_resp(
625 request->hdr.instance_id, PLDM_SUCCESS, 0, PLDM_START_AND_END,
626 fruData.data(), fruData.size(), responsePtr, respPayloadLength);
627
628 if (rc != PLDM_SUCCESS)
629 {
630 return ccOnlyResponse(request, rc);
631 }
632
633 return response;
634}
635
Pavithra Barithayaa410c652021-07-22 01:32:47 -0500636Response Handler::setFRURecordTable(const pldm_msg* request,
637 size_t payloadLength)
638{
639 uint32_t transferHandle{};
640 uint8_t transferOpFlag{};
641 struct variable_field fruData;
642
643 auto rc = decode_set_fru_record_table_req(
644 request, payloadLength, &transferHandle, &transferOpFlag, &fruData);
645
646 if (rc != PLDM_SUCCESS)
647 {
648 return ccOnlyResponse(request, rc);
649 }
650
651 Table table(fruData.ptr, fruData.ptr + fruData.length);
652 rc = impl.setFRUTable(table);
653 if (rc != PLDM_SUCCESS)
654 {
655 return ccOnlyResponse(request, rc);
656 }
657
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400658 Response response(
659 sizeof(pldm_msg_hdr) + PLDM_SET_FRU_RECORD_TABLE_RESP_BYTES);
Pavithra Barithaya677a4552025-01-31 10:33:39 +0530660 struct pldm_msg* responsePtr = new (response.data()) pldm_msg;
Pavithra Barithayaa410c652021-07-22 01:32:47 -0500661
662 rc = encode_set_fru_record_table_resp(
663 request->hdr.instance_id, PLDM_SUCCESS, 0 /* nextDataTransferHandle */,
664 response.size() - sizeof(pldm_msg_hdr), responsePtr);
665
666 if (rc != PLDM_SUCCESS)
667 {
668 return ccOnlyResponse(request, rc);
669 }
670
671 return response;
672}
673
Deepak Kodihallie60c5822019-10-23 03:26:15 -0500674} // namespace fru
675
Deepak Kodihalli70e8db02019-10-21 00:59:46 -0500676} // namespace responder
677
678} // namespace pldm