1 #include "fru_oem_ibm.hpp"
2
3 #include <com/ibm/VPD/Manager/client.hpp>
4 #include <phosphor-logging/lg2.hpp>
5
6 #include <format>
7 #include <ranges>
8
9 PHOSPHOR_LOG2_USING;
10
11 namespace pldm
12 {
13 namespace responder
14 {
15 namespace oem_ibm_fru
16 {
17
setIBMFruHandler(pldm::responder::fru::Handler * handler)18 void pldm::responder::oem_ibm_fru::Handler::setIBMFruHandler(
19 pldm::responder::fru::Handler* handler)
20 {
21 fruHandler = handler;
22 }
23
processOEMFRUTable(const std::vector<uint8_t> & fruData)24 int pldm::responder::oem_ibm_fru::Handler::processOEMFRUTable(
25 const std::vector<uint8_t>& fruData)
26 {
27 uint8_t dataSize = 0;
28 const uint8_t* data = fruData.data();
29
30 while (dataSize < fruData.size())
31 {
32 auto record =
33 reinterpret_cast<const pldm_fru_record_data_format*>(data);
34 if (!record)
35 {
36 return PLDM_ERROR_INVALID_DATA;
37 }
38
39 auto& entityAssociationMap = getAssociateEntityMap();
40 uint16_t fruRSI = le16toh(record->record_set_id);
41
42 dataSize += sizeof(pldm_fru_record_data_format) -
43 sizeof(pldm_fru_record_tlv);
44
45 data += sizeof(pldm_fru_record_data_format) -
46 sizeof(pldm_fru_record_tlv);
47
48 for ([[maybe_unused]] const auto& i :
49 std::views::iota(0, (int)record->num_fru_fields))
50 {
51 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(data);
52 if (!tlv)
53 {
54 return PLDM_ERROR_INVALID_DATA;
55 }
56
57 if (tlv->type == PLDM_OEM_FRU_FIELD_TYPE_PCIE_CONFIG_SPACE_DATA)
58 {
59 auto pcieData =
60 reinterpret_cast<const PcieConfigSpaceData*>(tlv->value);
61
62 if (!pcieData)
63 {
64 return PLDM_ERROR_INVALID_DATA;
65 }
66
67 auto vendorId =
68 std::format("0x{:04x}", htole16(pcieData->vendorId));
69 auto deviceId =
70 std::format("0x{:04x}", htole16(pcieData->deviceId));
71 auto revisionId =
72 std::format("0x{:02x}", htole16(pcieData->revisionId));
73
74 std::string classCode = "0x";
75 for (const auto& ele : pcieData->classCode)
76 {
77 classCode += std::format("{:02x}", ele);
78 }
79
80 auto subSystemVendorId = std::format(
81 "0x{:04x}", htole16(pcieData->subSystemVendorId));
82 auto subSystemId =
83 std::format("0x{:04x}", htole16(pcieData->subSystemId));
84
85 updateDBusProperty(fruRSI, entityAssociationMap, vendorId,
86 deviceId, revisionId, classCode,
87 subSystemVendorId, subSystemId);
88 }
89
90 if (tlv->type == PLDM_OEM_IBM_FRU_FIELD_TYPE_FIRMWARE_UAK)
91 {
92 std::vector<uint8_t> value(&tlv->value[0],
93 &tlv->value[tlv->length]);
94 setFirmwareUAK(value);
95 }
96
97 dataSize += sizeof(pldm_fru_record_tlv) - sizeof(uint8_t) +
98 tlv->length;
99
100 // Increment data pointer by the size of the current TLV
101 data += sizeof(pldm_fru_record_tlv) - sizeof(uint8_t) + tlv->length;
102 }
103 }
104
105 return PLDM_SUCCESS;
106 }
107
updateDBusProperty(uint16_t fruRSI,const AssociatedEntityMap & fruAssociationMap,const std::string & vendorId,const std::string & deviceId,const std::string & revisionId,const std::string & classCode,const std::string & subSystemVendorId,const std::string & subSystemId)108 void Handler::updateDBusProperty(
109 uint16_t fruRSI, const AssociatedEntityMap& fruAssociationMap,
110 const std::string& vendorId, const std::string& deviceId,
111 const std::string& revisionId, const std::string& classCode,
112 const std::string& subSystemVendorId, const std::string& subSystemId)
113 {
114 uint16_t entityType{};
115 uint16_t entityInstanceNum{};
116 uint16_t containerId{};
117 uint16_t terminusHandle{};
118 const pldm_pdr_record* record{};
119
120 record = pldm_pdr_fru_record_set_find_by_rsi(
121 pdrRepo, fruRSI, &terminusHandle, &entityType, &entityInstanceNum,
122 &containerId);
123
124 if (record)
125 {
126 for (const auto& [key, value] : fruAssociationMap)
127 {
128 if (entityInstanceNum == value.entity_instance_num &&
129 entityType == value.entity_type &&
130 containerId == value.entity_container_id)
131 {
132 if (!(pldm::responder::utils::checkIfIBMFru(key)))
133 {
134 pldm::utils::setFruPresence(key, true);
135 }
136 dbus_map_update(key, "Function0VendorId", vendorId);
137 dbus_map_update(key, "Function0DeviceId", deviceId);
138 dbus_map_update(key, "Function0RevisionId", revisionId);
139 dbus_map_update(key, "Function0ClassCode", classCode);
140 dbus_map_update(key, "Function0SubsystemVendorId",
141 subSystemVendorId);
142 dbus_map_update(key, "Function0SubsystemId", subSystemId);
143 }
144 }
145 }
146 }
147
dbus_map_update(const std::string & adapterObjPath,const std::string & propertyName,const std::string & propValue)148 void Handler::dbus_map_update(const std::string& adapterObjPath,
149 const std::string& propertyName,
150 const std::string& propValue)
151 {
152 pldm::utils::PropertyValue value = propValue;
153 pldm::utils::DBusMapping dbusMapping;
154 dbusMapping.objectPath = adapterObjPath;
155 dbusMapping.interface = "xyz.openbmc_project.Inventory.Item.PCIeDevice";
156 dbusMapping.propertyName = propertyName;
157 dbusMapping.propertyType = "string";
158 try
159 {
160 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
161 }
162 catch (const std::exception& e)
163 {
164 error(
165 "Failed to set property '{PROPERTY} at path '{PATH}' and interface '{INTERFACE}', error - {ERROR}",
166 "PROPERTY", propertyName, "PATH", adapterObjPath, "INTERFACE",
167 dbusMapping.interface, "ERROR", e);
168 }
169 }
170
setFirmwareUAK(const std::vector<uint8_t> & data)171 void Handler::setFirmwareUAK(const std::vector<uint8_t>& data)
172 {
173 using VPDManager = sdbusplus::client::com::ibm::vpd::Manager<>;
174
175 static constexpr auto uakObjPath = "/com/ibm/VPD/Manager";
176 static constexpr auto fruPath =
177 "/xyz/openbmc_project/inventory/system/chassis/motherboard";
178
179 auto& bus = pldm::utils::DBusHandler::getBus();
180 try
181 {
182 auto service = pldm::utils::DBusHandler().getService(
183 uakObjPath, VPDManager::interface);
184 auto method = bus.new_method_call(
185 service.c_str(), uakObjPath, VPDManager::interface, "WriteKeyword");
186 method.append(static_cast<sdbusplus::message::object_path>(fruPath),
187 "UTIL", "D8", data);
188 bus.call_noreply(method, dbusTimeout);
189 }
190 catch (const std::exception& e)
191 {
192 error("Failed to make a DBus call to VPD manager, error - {ERROR}",
193 "ERROR", e);
194 }
195 }
196
197 } // namespace oem_ibm_fru
198 } // namespace responder
199 } // namespace pldm
200