1 #include "collect_slot_vpd.hpp" 2 3 #include "oem_ibm_handler.hpp" 4 5 #include <phosphor-logging/lg2.hpp> 6 7 PHOSPHOR_LOG2_USING; 8 9 namespace pldm 10 { 11 namespace responder 12 { 13 using namespace oem_ibm_platform; 14 void SlotHandler::timeOutHandler() 15 { 16 info( 17 "Timer expired waiting for Event from Inventory on following pldm_entity: [ {ENTITY_TYP}, {ENTITY_NUM}, {ENTITY_ID} ]", 18 "ENTITY_TYP", 19 static_cast<unsigned>(currentOnGoingSlotEntity.entity_type), 20 "ENTITY_NUM", 21 static_cast<unsigned>(currentOnGoingSlotEntity.entity_instance_num), 22 "ENTITY_ID", 23 static_cast<unsigned>(currentOnGoingSlotEntity.entity_container_id)); 24 // Disable the timer 25 timer.setEnabled(false); 26 27 // obtain the sensor Id 28 auto sensorId = pldm::utils::findStateSensorId( 29 pdrRepo, 0, PLDM_ENTITY_SLOT, 30 currentOnGoingSlotEntity.entity_instance_num, 31 currentOnGoingSlotEntity.entity_container_id, 32 PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE); 33 34 // send the sensor event to host with error state 35 sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, 36 PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_ERROR, 37 PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN); 38 } 39 40 void SlotHandler::enableSlot(uint16_t effecterId, 41 const AssociatedEntityMap& fruAssociationMap, 42 uint8_t stateFileValue) 43 44 { 45 info("CM: slot enable effecter id: {EFFECTER_ID}", "EFFECTER_ID", 46 effecterId); 47 const pldm_entity entity = getEntityIDfromEffecterID(effecterId); 48 49 for (const auto& [key, value] : fruAssociationMap) 50 { 51 if (entity.entity_instance_num == value.entity_instance_num && 52 entity.entity_type == value.entity_type && 53 entity.entity_container_id == value.entity_container_id) 54 { 55 this->currentOnGoingSlotEntity.entity_type = value.entity_type; 56 this->currentOnGoingSlotEntity.entity_instance_num = 57 value.entity_instance_num; 58 this->currentOnGoingSlotEntity.entity_container_id = 59 value.entity_container_id; 60 processSlotOperations(key, value, stateFileValue); 61 } 62 } 63 } 64 65 void SlotHandler::processSlotOperations(const std::string& slotObjectPath, 66 const pldm_entity& entity, 67 uint8_t stateFieldValue) 68 { 69 info("CM: processing the slot operations, SlotObject: {SLOT_OBJ}", 70 "SLOT_OBJ", slotObjectPath); 71 72 std::string adapterObjPath; 73 try 74 { 75 // get the adapter dbus object path from the slot dbus object path 76 adapterObjPath = getAdapterObjPath(slotObjectPath).value(); 77 } 78 catch (const std::bad_optional_access& e) 79 { 80 error("Failed to get the adapter dbus object ERROR={ERROR}", "ERROR", 81 e); 82 return; 83 } 84 85 info( 86 "CM: Found an adapter under the slot, adapter object:{ADAPTER_OBJ_PATH}", 87 "ADAPTER_OBJ_PATH", adapterObjPath); 88 // create a presence match for the adpter present property 89 createPresenceMatch(adapterObjPath, entity, stateFieldValue); 90 91 // call the VPD Manager to collect/remove VPD objects 92 callVPDManager(adapterObjPath, stateFieldValue); 93 94 // start the 1 min timer 95 timer.restart(std::chrono::seconds(60)); 96 } 97 98 void SlotHandler::callVPDManager(const std::string& adapterObjPath, 99 uint8_t stateFieldValue) 100 { 101 static constexpr auto VPDObjPath = "/com/ibm/VPD/Manager"; 102 static constexpr auto VPDInterface = "com.ibm.VPD.Manager"; 103 auto& bus = pldm::utils::DBusHandler::getBus(); 104 try 105 { 106 auto service = 107 pldm::utils::DBusHandler().getService(VPDObjPath, VPDInterface); 108 if (stateFieldValue == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_ADD) 109 { 110 auto method = bus.new_method_call(service.c_str(), VPDObjPath, 111 VPDInterface, "CollectFRUVPD"); 112 method.append( 113 static_cast<sdbusplus::message::object_path>(adapterObjPath)); 114 bus.call_noreply(method, dbusTimeout); 115 } 116 else if (stateFieldValue == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_REMOVE || 117 stateFieldValue == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_REPLACE) 118 { 119 auto method = bus.new_method_call(service.c_str(), VPDObjPath, 120 VPDInterface, "deleteFRUVPD"); 121 method.append( 122 static_cast<sdbusplus::message::object_path>(adapterObjPath)); 123 bus.call_noreply(method, dbusTimeout); 124 } 125 } 126 catch (const std::exception& e) 127 { 128 error( 129 "failed to make a d-bus call to VPD Manager , Operation = {STATE_FILED_VAL}, ERROR={ERROR}", 130 "STATE_FILED_VAL", (unsigned)stateFieldValue, "ERROR", e); 131 } 132 } 133 134 std::optional<std::string> 135 SlotHandler::getAdapterObjPath(const std::string& slotObjPath) 136 { 137 static constexpr auto searchpath = "/xyz/openbmc_project/inventory"; 138 int depth = 0; 139 std::vector<std::string> pcieAdapterInterface = { 140 "xyz.openbmc_project.Inventory.Item.PCIeDevice"}; 141 pldm::utils::GetSubTreeResponse response = 142 pldm::utils::DBusHandler().getSubtree(searchpath, depth, 143 pcieAdapterInterface); 144 for (const auto& [objPath, serviceMap] : response) 145 { 146 // An adapter is a child of a PCIe Slot Object 147 if (objPath.contains(slotObjPath)) 148 { 149 // Found the Adapter under the slot 150 return objPath; 151 } 152 } 153 return std::nullopt; 154 } 155 156 void SlotHandler::createPresenceMatch(const std::string& adapterObjectPath, 157 const pldm_entity& entity, 158 uint8_t stateFieldValue) 159 { 160 fruPresenceMatch = std::make_unique<sdbusplus::bus::match_t>( 161 pldm::utils::DBusHandler::getBus(), 162 propertiesChanged(adapterObjectPath, 163 "xyz.openbmc_project.Inventory.Item"), 164 [this, adapterObjectPath, stateFieldValue, 165 entity](sdbusplus::message::message& msg) { 166 pldm::utils::DbusChangedProps props{}; 167 std::string intf; 168 msg.read(intf, props); 169 const auto itr = props.find("Present"); 170 if (itr != props.end()) 171 { 172 bool value = std::get<bool>(itr->second); 173 // Present Property is found 174 this->processPresentPropertyChange(value, stateFieldValue, 175 entity); 176 } 177 }); 178 } 179 180 void SlotHandler::processPresentPropertyChange( 181 bool presentValue, uint8_t stateFiledvalue, const pldm_entity& entity) 182 { 183 // irrespective of true->false or false->true change, we should stop the 184 // timer 185 timer.setEnabled(false); 186 187 // remove the prence match so that it does not monitor the change 188 // even after we captured the property changed signal 189 fruPresenceMatch = nullptr; 190 191 // obtain the sensor id attached with this slot 192 auto sensorId = pldm::utils::findStateSensorId( 193 pdrRepo, 0, PLDM_ENTITY_SLOT, entity.entity_instance_num, 194 entity.entity_container_id, PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE); 195 196 uint8_t sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN; 197 if (presentValue) 198 { 199 sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_ENABLED; 200 } 201 else 202 { 203 if (stateFiledvalue == PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_REPLACE) 204 { 205 sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN; 206 } 207 else 208 { 209 sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_DISABLED; 210 } 211 } 212 info( 213 "CM: processing the property change from VPD Present value and sensor opState: {CURR_VAL} and {SENSOR_OP_STATE}", 214 "CURR_VAL", presentValue, "SENSOR_OP_STATE", (unsigned)sensorOpState); 215 // set the sensor state based on the stateFieldValue 216 this->sendStateSensorEvent(sensorId, PLDM_STATE_SENSOR_STATE, 0, 217 sensorOpState, 218 PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN); 219 } 220 221 pldm_entity SlotHandler::getEntityIDfromEffecterID(uint16_t effecterId) 222 { 223 pldm_entity parentFruEntity{}; 224 uint8_t* pdrData = nullptr; 225 uint32_t pdrSize{}; 226 const pldm_pdr_record* record{}; 227 do 228 { 229 record = pldm_pdr_find_record_by_type(pdrRepo, PLDM_STATE_EFFECTER_PDR, 230 record, &pdrData, &pdrSize); 231 if (record && !pldm_pdr_record_is_remote(record)) 232 { 233 auto pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrData); 234 auto compositeEffecterCount = pdr->composite_effecter_count; 235 auto possible_states_start = pdr->possible_states; 236 237 for (auto effecters = 0x00; effecters < compositeEffecterCount; 238 effecters++) 239 { 240 auto possibleStates = 241 reinterpret_cast<state_effecter_possible_states*>( 242 possible_states_start); 243 244 if (possibleStates->state_set_id == 245 PLDM_OEM_IBM_PCIE_SLOT_EFFECTER_STATE && 246 effecterId == pdr->effecter_id) 247 { 248 parentFruEntity.entity_type = pdr->entity_type; 249 parentFruEntity.entity_instance_num = pdr->entity_instance; 250 parentFruEntity.entity_container_id = pdr->container_id; 251 252 return parentFruEntity; 253 } 254 } 255 } 256 } while (record); 257 258 return parentFruEntity; 259 } 260 261 uint8_t SlotHandler::fetchSlotSensorState(const std::string& slotObjectPath) 262 { 263 std::string adapterObjPath; 264 uint8_t sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN; 265 266 try 267 { 268 // get the adapter dbus object path from the slot dbus object path 269 adapterObjPath = getAdapterObjPath(slotObjectPath).value(); 270 } 271 catch (const std::bad_optional_access& e) 272 { 273 error( 274 "Failed to get the adapterObjectPath from slotObjectPath : {SLOT_OBJ_PATH} with error ERROR={ERROR}", 275 "SLOT_OBJ_PATH", slotObjectPath, "ERROR", e); 276 return PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_UNKOWN; 277 } 278 279 if (fetchSensorStateFromDbus(adapterObjPath)) 280 { 281 sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_ENABLED; 282 } 283 else 284 { 285 sensorOpState = PLDM_OEM_IBM_PCIE_SLOT_SENSOR_STATE_DISABLED; 286 } 287 return sensorOpState; 288 } 289 290 void SlotHandler::setOemPlatformHandler( 291 pldm::responder::oem_platform::Handler* handler) 292 { 293 oemPlatformHandler = handler; 294 } 295 296 void SlotHandler::sendStateSensorEvent( 297 uint16_t sensorId, enum sensor_event_class_states sensorEventClass, 298 uint8_t sensorOffset, uint8_t eventState, uint8_t prevEventState) 299 { 300 pldm::responder::oem_ibm_platform::Handler* oemIbmPlatformHandler = 301 dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>( 302 oemPlatformHandler); 303 if (oemIbmPlatformHandler) 304 { 305 oemIbmPlatformHandler->sendStateSensorEvent( 306 sensorId, sensorEventClass, sensorOffset, eventState, 307 prevEventState); 308 } 309 } 310 311 bool SlotHandler::fetchSensorStateFromDbus(const std::string& adapterObjectPath) 312 { 313 static constexpr auto ItemInterface = "xyz.openbmc_project.Inventory.Item"; 314 315 try 316 { 317 auto presentProperty = 318 pldm::utils::DBusHandler().getDbusPropertyVariant( 319 adapterObjectPath.c_str(), "Present", ItemInterface); 320 return std::get<bool>(presentProperty); 321 } 322 catch (const std::exception& e) 323 { 324 error( 325 "failed to make a d-bus call to Inventory manager from adapterObjectPath : {ADAPTER_OBJ_PATH} with error ERROR={ERROR}", 326 "ADAPTER_OBJ_PATH", adapterObjectPath, "ERROR", e); 327 } 328 329 return false; 330 } 331 332 } // namespace responder 333 } // namespace pldm 334