aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorJoachim Fenkes <fenkes@de.ibm.com>2007-07-09 09:32:22 -0400
committerRoland Dreier <rolandd@cisco.com>2007-07-09 23:12:27 -0400
commit8705ce5b90118be93eb8b0ed6f49ca5ff377df24 (patch)
treea7d273e77e01a4be09882aae2a8285e31e02aebf /drivers/infiniband
parentb1cfe43d4b24144596d277133e0e5b715eea1347 (diff)
IB/ehca: Notify consumers of LID/PKEY/SM changes after nondisruptive events
When firmware reports a nondisruptive port configuration change event, previous versions of the eHCA driver didn't forward the event to consumers like IPoIB. Add code that determines the type of configuration change by comparing old and new port attributes and reports it. Signed-off-by: Joachim Fenkes <fenkes@de.ibm.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h6
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c34
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c89
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h3
4 files changed, 101 insertions, 31 deletions
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index f1e0db2ff16c..daf823ea1ace 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -87,11 +87,17 @@ struct ehca_eq {
87 struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE]; 87 struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE];
88}; 88};
89 89
90struct ehca_sma_attr {
91 u16 lid, lmc, sm_sl, sm_lid;
92 u16 pkey_tbl_len, pkeys[16];
93};
94
90struct ehca_sport { 95struct ehca_sport {
91 struct ib_cq *ibcq_aqp1; 96 struct ib_cq *ibcq_aqp1;
92 struct ib_qp *ibqp_aqp1; 97 struct ib_qp *ibqp_aqp1;
93 enum ib_rate rate; 98 enum ib_rate rate;
94 enum ib_port_state port_state; 99 enum ib_port_state port_state;
100 struct ehca_sma_attr saved_attr;
95}; 101};
96 102
97struct ehca_shca { 103struct ehca_shca {
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index b310de5c94ae..bbd3c6a5822f 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -193,6 +193,40 @@ query_port1:
193 return ret; 193 return ret;
194} 194}
195 195
196int ehca_query_sma_attr(struct ehca_shca *shca,
197 u8 port, struct ehca_sma_attr *attr)
198{
199 int ret = 0;
200 struct hipz_query_port *rblock;
201
202 rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
203 if (!rblock) {
204 ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
205 return -ENOMEM;
206 }
207
208 if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
209 ehca_err(&shca->ib_device, "Can't query port properties");
210 ret = -EINVAL;
211 goto query_sma_attr1;
212 }
213
214 memset(attr, 0, sizeof(struct ehca_sma_attr));
215
216 attr->lid = rblock->lid;
217 attr->lmc = rblock->lmc;
218 attr->sm_sl = rblock->sm_sl;
219 attr->sm_lid = rblock->sm_lid;
220
221 attr->pkey_tbl_len = rblock->pkey_tbl_len;
222 memcpy(attr->pkeys, rblock->pkey_entries, sizeof(attr->pkeys));
223
224query_sma_attr1:
225 ehca_free_fw_ctrlblock(rblock);
226
227 return ret;
228}
229
196int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) 230int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
197{ 231{
198 int ret = 0; 232 int ret = 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 02b73c84c49b..96eba3830754 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -61,6 +61,7 @@
61#define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7) 61#define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7)
62#define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15) 62#define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15)
63#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16) 63#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
64#define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16,16)
64 65
65#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63) 66#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63)
66#define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7) 67#define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7)
@@ -286,30 +287,61 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe)
286 return; 287 return;
287} 288}
288 289
289static void parse_ec(struct ehca_shca *shca, u64 eqe) 290static void dispatch_port_event(struct ehca_shca *shca, int port_num,
291 enum ib_event_type type, const char *msg)
290{ 292{
291 struct ib_event event; 293 struct ib_event event;
294
295 ehca_info(&shca->ib_device, "port %d %s.", port_num, msg);
296 event.device = &shca->ib_device;
297 event.event = type;
298 event.element.port_num = port_num;
299 ib_dispatch_event(&event);
300}
301
302static void notify_port_conf_change(struct ehca_shca *shca, int port_num)
303{
304 struct ehca_sma_attr new_attr;
305 struct ehca_sma_attr *old_attr = &shca->sport[port_num - 1].saved_attr;
306
307 ehca_query_sma_attr(shca, port_num, &new_attr);
308
309 if (new_attr.sm_sl != old_attr->sm_sl ||
310 new_attr.sm_lid != old_attr->sm_lid)
311 dispatch_port_event(shca, port_num, IB_EVENT_SM_CHANGE,
312 "SM changed");
313
314 if (new_attr.lid != old_attr->lid ||
315 new_attr.lmc != old_attr->lmc)
316 dispatch_port_event(shca, port_num, IB_EVENT_LID_CHANGE,
317 "LID changed");
318
319 if (new_attr.pkey_tbl_len != old_attr->pkey_tbl_len ||
320 memcmp(new_attr.pkeys, old_attr->pkeys,
321 sizeof(u16) * new_attr.pkey_tbl_len))
322 dispatch_port_event(shca, port_num, IB_EVENT_PKEY_CHANGE,
323 "P_Key changed");
324
325 *old_attr = new_attr;
326}
327
328static void parse_ec(struct ehca_shca *shca, u64 eqe)
329{
292 u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe); 330 u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
293 u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe); 331 u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
294 332
295 switch (ec) { 333 switch (ec) {
296 case 0x30: /* port availability change */ 334 case 0x30: /* port availability change */
297 if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) { 335 if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
298 ehca_info(&shca->ib_device,
299 "port %x is active.", port);
300 event.device = &shca->ib_device;
301 event.event = IB_EVENT_PORT_ACTIVE;
302 event.element.port_num = port;
303 shca->sport[port - 1].port_state = IB_PORT_ACTIVE; 336 shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
304 ib_dispatch_event(&event); 337 dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
338 "is active");
339 ehca_query_sma_attr(shca, port,
340 &shca->sport[port - 1].saved_attr);
305 } else { 341 } else {
306 ehca_info(&shca->ib_device,
307 "port %x is inactive.", port);
308 event.device = &shca->ib_device;
309 event.event = IB_EVENT_PORT_ERR;
310 event.element.port_num = port;
311 shca->sport[port - 1].port_state = IB_PORT_DOWN; 342 shca->sport[port - 1].port_state = IB_PORT_DOWN;
312 ib_dispatch_event(&event); 343 dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
344 "is inactive");
313 } 345 }
314 break; 346 break;
315 case 0x31: 347 case 0x31:
@@ -317,24 +349,19 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
317 * disruptive change is caused by 349 * disruptive change is caused by
318 * LID, PKEY or SM change 350 * LID, PKEY or SM change
319 */ 351 */
320 ehca_warn(&shca->ib_device, 352 if (EHCA_BMASK_GET(NEQE_DISRUPTIVE, eqe)) {
321 "disruptive port %x configuration change", port); 353 ehca_warn(&shca->ib_device, "disruptive port "
322 354 "%d configuration change", port);
323 ehca_info(&shca->ib_device, 355
324 "port %x is inactive.", port); 356 shca->sport[port - 1].port_state = IB_PORT_DOWN;
325 event.device = &shca->ib_device; 357 dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
326 event.event = IB_EVENT_PORT_ERR; 358 "is inactive");
327 event.element.port_num = port; 359
328 shca->sport[port - 1].port_state = IB_PORT_DOWN; 360 shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
329 ib_dispatch_event(&event); 361 dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
330 362 "is active");
331 ehca_info(&shca->ib_device, 363 } else
332 "port %x is active.", port); 364 notify_port_conf_change(shca, port);
333 event.device = &shca->ib_device;
334 event.event = IB_EVENT_PORT_ACTIVE;
335 event.element.port_num = port;
336 shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
337 ib_dispatch_event(&event);
338 break; 365 break;
339 case 0x32: /* adapter malfunction */ 366 case 0x32: /* adapter malfunction */
340 ehca_err(&shca->ib_device, "Adapter malfunction."); 367 ehca_err(&shca->ib_device, "Adapter malfunction.");
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index fd84a804814c..77aeca6a2c2f 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -49,6 +49,9 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props);
49int ehca_query_port(struct ib_device *ibdev, u8 port, 49int ehca_query_port(struct ib_device *ibdev, u8 port,
50 struct ib_port_attr *props); 50 struct ib_port_attr *props);
51 51
52int ehca_query_sma_attr(struct ehca_shca *shca, u8 port,
53 struct ehca_sma_attr *attr);
54
52int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey); 55int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey);
53 56
54int ehca_query_gid(struct ib_device *ibdev, u8 port, int index, 57int ehca_query_gid(struct ib_device *ibdev, u8 port, int index,