blob: 4101624e6a023b6f8e8a0ba906dfa11695f3fd34 [file] [log] [blame]
Tom Joseph75356c12021-06-20 03:52:40 -07001#include "inventory_manager.hpp"
2
Tom Joseph75356c12021-06-20 03:52:40 -07003#include "common/utils.hpp"
4#include "xyz/openbmc_project/Software/Version/server.hpp"
5
George Liuc453e162022-12-21 17:16:23 +08006#include <libpldm/firmware_update.h>
7
Riya Dixit49cfb132023-03-02 04:26:53 -06008#include <phosphor-logging/lg2.hpp>
9
Tom Joseph75356c12021-06-20 03:52:40 -070010#include <functional>
11
Riya Dixit49cfb132023-03-02 04:26:53 -060012PHOSPHOR_LOG2_USING;
13
Tom Joseph75356c12021-06-20 03:52:40 -070014namespace pldm
15{
Tom Joseph75356c12021-06-20 03:52:40 -070016namespace fw_update
17{
Tom Joseph75356c12021-06-20 03:52:40 -070018void InventoryManager::discoverFDs(const std::vector<mctp_eid_t>& eids)
19{
20 for (const auto& eid : eids)
21 {
Unive Tieneaf79da2024-11-25 09:34:39 +080022 try
Tom Joseph75356c12021-06-20 03:52:40 -070023 {
Unive Tieneaf79da2024-11-25 09:34:39 +080024 sendQueryDownstreamDevicesRequest(eid);
Tom Joseph75356c12021-06-20 03:52:40 -070025 }
Unive Tieneaf79da2024-11-25 09:34:39 +080026 catch (const std::exception& e)
27 {
28 error("Failed to discover FDs, EID={EID}, Error={ERROR}", "EID",
29 eid, "ERROR", e.what());
30 }
31 }
32}
Tom Joseph75356c12021-06-20 03:52:40 -070033
Unive Tieneaf79da2024-11-25 09:34:39 +080034void InventoryManager::sendQueryDeviceIdentifiersRequest(mctp_eid_t eid)
35{
36 auto instanceId = instanceIdDb.next(eid);
37 Request requestMsg(
38 sizeof(pldm_msg_hdr) + PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES);
39 auto request = new (requestMsg.data()) pldm_msg;
40 auto rc = encode_query_device_identifiers_req(
41 instanceId, PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES, request);
42 if (rc)
43 {
44 instanceIdDb.free(eid, instanceId);
45 error(
46 "Failed to encode query device identifiers request, EID={EID}, RC = {RC}",
47 "EID", eid, "RC", rc);
48 throw std::runtime_error(
49 "Failed to encode QueryDeviceIdentifiers request");
50 }
51
52 rc = handler.registerRequest(
53 eid, instanceId, PLDM_FWUP, PLDM_QUERY_DEVICE_IDENTIFIERS,
54 std::move(requestMsg),
55 std::bind_front(&InventoryManager::queryDeviceIdentifiers, this));
56 if (rc)
57 {
58 error(
59 "Failed to send query device identifiers request for endpoint ID '{EID}', response code '{RC}'",
60 "EID", eid, "RC", rc);
61 throw std::runtime_error(
62 "Failed to send QueryDeviceIdentifiers request");
Tom Joseph75356c12021-06-20 03:52:40 -070063 }
64}
65
Patrick Williams16c2a0a2024-08-16 15:20:59 -040066void InventoryManager::queryDeviceIdentifiers(
67 mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
Tom Joseph75356c12021-06-20 03:52:40 -070068{
69 if (response == nullptr || !respMsgLen)
70 {
Riya Dixit76f2c602024-03-28 07:34:12 -050071 error(
72 "No response received for query device identifiers for endpoint ID '{EID}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -050073 "EID", eid);
Tom Joseph75356c12021-06-20 03:52:40 -070074 return;
75 }
76
77 uint8_t completionCode = PLDM_SUCCESS;
78 uint32_t deviceIdentifiersLen = 0;
79 uint8_t descriptorCount = 0;
80 uint8_t* descriptorPtr = nullptr;
81
82 auto rc = decode_query_device_identifiers_resp(
83 response, respMsgLen, &completionCode, &deviceIdentifiersLen,
84 &descriptorCount, &descriptorPtr);
85 if (rc)
86 {
Riya Dixit49cfb132023-03-02 04:26:53 -060087 error(
Riya Dixit76f2c602024-03-28 07:34:12 -050088 "Failed to decode query device identifiers response for endpoint ID '{EID}' and descriptor count '{DESCRIPTOR_COUNT}', response code '{RC}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -050089 "EID", eid, "DESCRIPTOR_COUNT", descriptorCount, "RC", rc);
Tom Joseph75356c12021-06-20 03:52:40 -070090 return;
91 }
92
93 if (completionCode)
94 {
Riya Dixit49cfb132023-03-02 04:26:53 -060095 error(
Riya Dixit76f2c602024-03-28 07:34:12 -050096 "Failed to query device identifiers response for endpoint ID '{EID}', completion code '{CC}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -050097 "EID", eid, "CC", completionCode);
Tom Joseph75356c12021-06-20 03:52:40 -070098 return;
99 }
100
101 Descriptors descriptors{};
102 while (descriptorCount-- && (deviceIdentifiersLen > 0))
103 {
104 uint16_t descriptorType = 0;
105 variable_field descriptorData{};
106
107 rc = decode_descriptor_type_length_value(
108 descriptorPtr, deviceIdentifiersLen, &descriptorType,
109 &descriptorData);
110 if (rc)
111 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600112 error(
Riya Dixit76f2c602024-03-28 07:34:12 -0500113 "Failed to decode descriptor type {TYPE}, length {LENGTH} and value for endpoint ID '{EID}', response code '{RC}'",
114 "TYPE", descriptorType, "LENGTH", deviceIdentifiersLen, "EID",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500115 eid, "RC", rc);
Tom Joseph75356c12021-06-20 03:52:40 -0700116 return;
117 }
118
119 if (descriptorType != PLDM_FWUP_VENDOR_DEFINED)
120 {
121 std::vector<uint8_t> descData(
122 descriptorData.ptr, descriptorData.ptr + descriptorData.length);
123 descriptors.emplace(descriptorType, std::move(descData));
124 }
125 else
126 {
127 uint8_t descriptorTitleStrType = 0;
128 variable_field descriptorTitleStr{};
129 variable_field vendorDefinedDescriptorData{};
130
131 rc = decode_vendor_defined_descriptor_value(
132 descriptorData.ptr, descriptorData.length,
133 &descriptorTitleStrType, &descriptorTitleStr,
134 &vendorDefinedDescriptorData);
135 if (rc)
136 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600137 error(
Riya Dixit76f2c602024-03-28 07:34:12 -0500138 "Failed to decode vendor-defined descriptor value for endpoint ID '{EID}', response code '{RC}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500139 "EID", eid, "RC", rc);
Tom Joseph75356c12021-06-20 03:52:40 -0700140 return;
141 }
142
143 auto vendorDefinedDescriptorTitleStr =
144 utils::toString(descriptorTitleStr);
145 std::vector<uint8_t> vendorDescData(
146 vendorDefinedDescriptorData.ptr,
147 vendorDefinedDescriptorData.ptr +
148 vendorDefinedDescriptorData.length);
149 descriptors.emplace(descriptorType,
150 std::make_tuple(vendorDefinedDescriptorTitleStr,
151 vendorDescData));
152 }
153 auto nextDescriptorOffset =
154 sizeof(pldm_descriptor_tlv().descriptor_type) +
155 sizeof(pldm_descriptor_tlv().descriptor_length) +
156 descriptorData.length;
157 descriptorPtr += nextDescriptorOffset;
158 deviceIdentifiersLen -= nextDescriptorOffset;
159 }
160
161 descriptorMap.emplace(eid, std::move(descriptors));
162
163 // Send GetFirmwareParameters request
164 sendGetFirmwareParametersRequest(eid);
165}
166
Unive Tieneaf79da2024-11-25 09:34:39 +0800167void InventoryManager::sendQueryDownstreamDevicesRequest(mctp_eid_t eid)
168{
169 Request requestMsg(sizeof(pldm_msg_hdr));
170 auto instanceId = instanceIdDb.next(eid);
171 auto request = new (requestMsg.data()) pldm_msg;
172 auto rc = encode_query_downstream_devices_req(instanceId, request);
173 if (rc)
174 {
175 instanceIdDb.free(eid, instanceId);
176 error(
177 "Failed to encode query downstream devices request, EID={EID}, RC = {RC}",
178 "EID", eid, "RC", rc);
179 throw std::runtime_error(
180 "Failed to encode query downstream devices request");
181 }
182
183 rc = handler.registerRequest(
184 eid, instanceId, PLDM_FWUP, PLDM_QUERY_DOWNSTREAM_DEVICES,
185 std::move(requestMsg),
186 std::bind_front(&InventoryManager::queryDownstreamDevices, this));
187 if (rc)
188 {
189 error(
190 "Failed to send QueryDownstreamDevices request, EID={EID}, RC = {RC}",
191 "EID", eid, "RC", rc);
192 }
193}
194
195void InventoryManager::queryDownstreamDevices(
196 mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
197{
198 if (!response || !respMsgLen)
199 {
200 error("No response received for QueryDownstreamDevices, EID={EID}",
201 "EID", eid);
202 return;
203 }
204
205 pldm_query_downstream_devices_resp downstreamDevicesResp{};
206 auto rc = decode_query_downstream_devices_resp(response, respMsgLen,
207 &downstreamDevicesResp);
208 if (rc)
209 {
210 error(
211 "Decoding QueryDownstreamDevices response failed, EID={EID}, RC = {RC}",
212 "EID", eid, "RC", rc);
213 return;
214 }
215
216 switch (downstreamDevicesResp.completion_code)
217 {
218 case PLDM_SUCCESS:
219 break;
220 case PLDM_ERROR_UNSUPPORTED_PLDM_CMD:
221 /* QueryDownstreamDevices is optional, consider the device does not
222 * support Downstream Devices.
223 */
224 return;
225 default:
226 error(
227 "QueryDownstreamDevices response failed with error completion code, EID={EID}, CC = {CC}",
228 "EID", eid, "CC", downstreamDevicesResp.completion_code);
229 return;
230 }
231
232 switch (downstreamDevicesResp.downstream_device_update_supported)
233 {
234 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_SUPPORTED:
235 /** DataTransferHandle will be skipped when TransferOperationFlag is
236 * `GetFirstPart`. Use 0x0 as default by following example in
237 * Figure 9 in DSP0267 1.1.0
238 */
239 try
240 {
241 sendQueryDownstreamIdentifiersRequest(eid, 0x0,
242 PLDM_GET_FIRSTPART);
243 }
244 catch (const std::exception& e)
245 {
246 error(
247 "Failed to send QueryDownstreamIdentifiers request, EID={EID}, Error={ERROR}",
248 "EID", eid, "ERROR", e.what());
249 }
250 break;
251 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_NOT_SUPPORTED:
252 /* The FDP does not support firmware updates but may report
253 * inventory information on downstream devices.
254 * In this scenario, sends only GetDownstreamFirmwareParameters
255 * to the FDP.
256 * The definition can be found at Table 15 of DSP0267_1.1.0
257 */
258 break;
259 default:
260 error(
261 "Unknown response of DownstreamDeviceUpdateSupported from EID={EID}, Value = {VALUE}",
262 "EID", eid, "VALUE",
263 downstreamDevicesResp.downstream_device_update_supported);
264 return;
265 }
266}
267
268void InventoryManager::sendQueryDownstreamIdentifiersRequest(
269 mctp_eid_t eid, uint32_t dataTransferHandle,
270 enum transfer_op_flag transferOperationFlag)
271{
272 auto instanceId = instanceIdDb.next(eid);
273 Request requestMsg(
274 sizeof(pldm_msg_hdr) + PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES);
275 auto request = new (requestMsg.data()) pldm_msg;
276 pldm_query_downstream_identifiers_req requestParameters{
277 dataTransferHandle, static_cast<uint8_t>(transferOperationFlag)};
278
279 auto rc = encode_query_downstream_identifiers_req(
280 instanceId, &requestParameters, request,
281 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES);
282 if (rc)
283 {
284 instanceIdDb.free(eid, instanceId);
285 error(
286 "Failed to encode query downstream identifiers request, EID={EID}, RC = {RC}",
287 "EID", eid, "RC", rc);
288 throw std::runtime_error(
289 "Failed to encode query downstream identifiers request");
290 }
291
292 rc = handler.registerRequest(
293 eid, instanceId, PLDM_FWUP, PLDM_QUERY_DOWNSTREAM_IDENTIFIERS,
294 std::move(requestMsg),
295 std::bind_front(&InventoryManager::queryDownstreamIdentifiers, this));
296 if (rc)
297 {
298 error(
299 "Failed to send QueryDownstreamIdentifiers request, EID={EID}, RC = {RC}",
300 "EID", eid, "RC", rc);
301 }
302}
303
304void InventoryManager::queryDownstreamIdentifiers(
305 mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
306{
307 if (!response || !respMsgLen)
308 {
309 error("No response received for QueryDownstreamIdentifiers, EID={EID}",
310 "EID", eid);
311 descriptorMap.erase(eid);
312 return;
313 }
314
315 pldm_query_downstream_identifiers_resp downstreamIds{};
316 pldm_downstream_device_iter devs{};
317
318 auto rc = decode_query_downstream_identifiers_resp(response, respMsgLen,
319 &downstreamIds, &devs);
320 if (rc)
321 {
322 error(
323 "Decoding QueryDownstreamIdentifiers response failed, EID={EID}, RC = {RC}",
324 "EID", eid, "RC", rc);
325 return;
326 }
327
328 if (downstreamIds.completion_code)
329 {
330 error(
331 "QueryDownstreamIdentifiers response failed with error completion code, EID={EID}, CC = {CC}",
332 "EID", eid, "CC", unsigned(downstreamIds.completion_code));
333 return;
334 }
335
336 DownstreamDevices initialDownstreamDevices{};
337 DownstreamDevices* downstreamDevices;
338 switch (downstreamIds.transfer_flag)
339 {
340 case PLDM_MIDDLE:
341 case PLDM_END:
342 downstreamDevices = &downstreamDescriptorMap.at(eid);
343 break;
344 default:
345 downstreamDevices = &initialDownstreamDevices;
346 break;
347 }
348
349 pldm_downstream_device dev;
350 foreach_pldm_downstream_device(devs, dev, rc)
351 {
352 pldm_descriptor desc;
353 Descriptors descriptors{};
354 foreach_pldm_downstream_device_descriptor(devs, dev, desc, rc)
355 {
356 const auto descriptorData =
357 new (const_cast<void*>(desc.descriptor_data))
358 uint8_t[desc.descriptor_length];
359 if (desc.descriptor_type != PLDM_FWUP_VENDOR_DEFINED)
360 {
361 std::vector<uint8_t> descData(
362 descriptorData, descriptorData + desc.descriptor_length);
363 descriptors.emplace(desc.descriptor_type, std::move(descData));
364 }
365 else
366 {
367 uint8_t descriptorTitleStrType = 0;
368 variable_field descriptorTitleStr{};
369 variable_field vendorDefinedDescriptorData{};
370
371 rc = decode_vendor_defined_descriptor_value(
372 descriptorData, desc.descriptor_length,
373 &descriptorTitleStrType, &descriptorTitleStr,
374 &vendorDefinedDescriptorData);
375
376 if (rc)
377 {
378 error(
379 "Decoding Vendor-defined descriptor value failed, EID={EID}, RC = {RC}",
380 "EID", eid, "RC", rc);
381 return;
382 }
383
384 auto vendorDefinedDescriptorTitleStr =
385 utils::toString(descriptorTitleStr);
386 std::vector<uint8_t> vendorDescData(
387 vendorDefinedDescriptorData.ptr,
388 vendorDefinedDescriptorData.ptr +
389 vendorDefinedDescriptorData.length);
390 descriptors.emplace(
391 desc.descriptor_type,
392 std::make_tuple(vendorDefinedDescriptorTitleStr,
393 vendorDescData));
394 }
395 }
396 if (rc)
397 {
398 error(
399 "Failed to decode downstream descriptors from iterator, EID={EID}, RC = {RC}",
400 "EID", eid, "RC", rc);
401 return;
402 }
403 downstreamDevices->emplace_back(
404 DownstreamDeviceInfo{dev.downstream_device_index, descriptors});
405 }
406 if (rc)
407 {
408 error(
409 "Failed to decode downstream devices from iterator, EID={EID}, RC = {RC}",
410 "EID", eid, "RC", rc);
411 return;
412 }
413
414 switch (downstreamIds.transfer_flag)
415 {
416 case PLDM_START:
417 downstreamDescriptorMap.emplace(
418 eid, std::move(initialDownstreamDevices));
419 [[fallthrough]];
420 case PLDM_MIDDLE:
421 sendQueryDownstreamIdentifiersRequest(
422 eid, downstreamIds.next_data_transfer_handle,
423 PLDM_GET_NEXTPART);
424 break;
425 case PLDM_START_AND_END:
426 downstreamDescriptorMap.emplace(
427 eid, std::move(initialDownstreamDevices));
428 /** DataTransferHandle will be skipped when TransferOperationFlag is
429 * `GetFirstPart`. Use 0x0 as default by following example in
430 * Figure 9 in DSP0267 1.1.0
431 */
432 [[fallthrough]];
433 case PLDM_END:
434 sendQueryDeviceIdentifiersRequest(eid);
435 break;
436 }
437}
438
Tom Joseph75356c12021-06-20 03:52:40 -0700439void InventoryManager::sendGetFirmwareParametersRequest(mctp_eid_t eid)
440{
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930441 auto instanceId = instanceIdDb.next(eid);
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400442 Request requestMsg(
443 sizeof(pldm_msg_hdr) + PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES);
Tom Joseph75356c12021-06-20 03:52:40 -0700444 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
445 auto rc = encode_get_firmware_parameters_req(
446 instanceId, PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES, request);
447 if (rc)
448 {
Andrew Jefferya330b2f2023-05-04 14:55:37 +0930449 instanceIdDb.free(eid, instanceId);
Riya Dixit76f2c602024-03-28 07:34:12 -0500450 error(
451 "Failed to encode get firmware parameters req for endpoint ID '{EID}', response code '{RC}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500452 "EID", eid, "RC", rc);
Tom Joseph75356c12021-06-20 03:52:40 -0700453 return;
454 }
455
456 rc = handler.registerRequest(
457 eid, instanceId, PLDM_FWUP, PLDM_GET_FIRMWARE_PARAMETERS,
458 std::move(requestMsg),
Andrew Jefferyc14fb4b2024-07-25 22:13:09 +0930459 std::bind_front(&InventoryManager::getFirmwareParameters, this));
Tom Joseph75356c12021-06-20 03:52:40 -0700460 if (rc)
461 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600462 error(
Riya Dixit76f2c602024-03-28 07:34:12 -0500463 "Failed to send get firmware parameters request for endpoint ID '{EID}', response code '{RC}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500464 "EID", eid, "RC", rc);
Tom Joseph75356c12021-06-20 03:52:40 -0700465 }
466}
467
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400468void InventoryManager::getFirmwareParameters(
469 mctp_eid_t eid, const pldm_msg* response, size_t respMsgLen)
Tom Joseph75356c12021-06-20 03:52:40 -0700470{
471 if (response == nullptr || !respMsgLen)
472 {
Riya Dixit76f2c602024-03-28 07:34:12 -0500473 error(
474 "No response received for get firmware parameters for endpoint ID '{EID}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500475 "EID", eid);
Tom Joseph75356c12021-06-20 03:52:40 -0700476 descriptorMap.erase(eid);
477 return;
478 }
479
480 pldm_get_firmware_parameters_resp fwParams{};
481 variable_field activeCompImageSetVerStr{};
482 variable_field pendingCompImageSetVerStr{};
483 variable_field compParamTable{};
484
485 auto rc = decode_get_firmware_parameters_resp(
486 response, respMsgLen, &fwParams, &activeCompImageSetVerStr,
487 &pendingCompImageSetVerStr, &compParamTable);
488 if (rc)
489 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600490 error(
Riya Dixit76f2c602024-03-28 07:34:12 -0500491 "Failed to decode get firmware parameters response for endpoint ID '{EID}', response code '{RC}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500492 "EID", eid, "RC", rc);
Tom Joseph75356c12021-06-20 03:52:40 -0700493 return;
494 }
495
496 if (fwParams.completion_code)
497 {
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500498 auto fw_param_cc = fwParams.completion_code;
Riya Dixit49cfb132023-03-02 04:26:53 -0600499 error(
Riya Dixit76f2c602024-03-28 07:34:12 -0500500 "Failed to get firmware parameters response for endpoint ID '{EID}', completion code '{CC}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500501 "EID", eid, "CC", fw_param_cc);
Tom Joseph75356c12021-06-20 03:52:40 -0700502 return;
503 }
504
505 auto compParamPtr = compParamTable.ptr;
506 auto compParamTableLen = compParamTable.length;
507 pldm_component_parameter_entry compEntry{};
508 variable_field activeCompVerStr{};
509 variable_field pendingCompVerStr{};
510
511 ComponentInfo componentInfo{};
512 while (fwParams.comp_count-- && (compParamTableLen > 0))
513 {
514 auto rc = decode_get_firmware_parameters_resp_comp_entry(
515 compParamPtr, compParamTableLen, &compEntry, &activeCompVerStr,
516 &pendingCompVerStr);
517 if (rc)
518 {
Riya Dixit49cfb132023-03-02 04:26:53 -0600519 error(
Riya Dixit76f2c602024-03-28 07:34:12 -0500520 "Failed to decode component parameter table entry for endpoint ID '{EID}', response code '{RC}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500521 "EID", eid, "RC", rc);
Tom Joseph75356c12021-06-20 03:52:40 -0700522 return;
523 }
524
525 auto compClassification = compEntry.comp_classification;
526 auto compIdentifier = compEntry.comp_identifier;
527 componentInfo.emplace(
528 std::make_pair(compClassification, compIdentifier),
529 compEntry.comp_classification_index);
530 compParamPtr += sizeof(pldm_component_parameter_entry) +
531 activeCompVerStr.length + pendingCompVerStr.length;
532 compParamTableLen -= sizeof(pldm_component_parameter_entry) +
533 activeCompVerStr.length + pendingCompVerStr.length;
534 }
535 componentInfoMap.emplace(eid, std::move(componentInfo));
536}
537
538} // namespace fw_update
539
Riya Dixit49cfb132023-03-02 04:26:53 -0600540} // namespace pldm