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;
timeOutHandler()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
enableSlot(uint16_t effecterId,const AssociatedEntityMap & fruAssociationMap,uint8_t stateFileValue)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
processSlotOperations(const std::string & slotObjectPath,const pldm_entity & entity,uint8_t stateFieldValue)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
callVPDManager(const std::string & adapterObjPath,uint8_t stateFieldValue)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>
getAdapterObjPath(const std::string & slotObjPath)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
createPresenceMatch(const std::string & adapterObjectPath,const pldm_entity & entity,uint8_t stateFieldValue)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_t& 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
processPresentPropertyChange(bool presentValue,uint8_t stateFiledvalue,const pldm_entity & entity)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
getEntityIDfromEffecterID(uint16_t effecterId)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
fetchSlotSensorState(const std::string & slotObjectPath)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
setOemPlatformHandler(pldm::responder::oem_platform::Handler * handler)290 void SlotHandler::setOemPlatformHandler(
291 pldm::responder::oem_platform::Handler* handler)
292 {
293 oemPlatformHandler = handler;
294 }
295
sendStateSensorEvent(uint16_t sensorId,enum sensor_event_class_states sensorEventClass,uint8_t sensorOffset,uint8_t eventState,uint8_t prevEventState)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
fetchSensorStateFromDbus(const std::string & adapterObjectPath)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