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