xref: /openbmc/pldm/oem/ibm/libpldmresponder/fru_oem_ibm.cpp (revision 44f8804574581ab063cde67fa5bf2da491e4dd88)
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