Commit 8705ce5b authored by Joachim Fenkes's avatar Joachim Fenkes Committed by Roland Dreier

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: default avatarJoachim Fenkes <fenkes@de.ibm.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent b1cfe43d
...@@ -87,11 +87,17 @@ struct ehca_eq { ...@@ -87,11 +87,17 @@ struct ehca_eq {
struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE]; struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE];
}; };
struct ehca_sma_attr {
u16 lid, lmc, sm_sl, sm_lid;
u16 pkey_tbl_len, pkeys[16];
};
struct ehca_sport { struct ehca_sport {
struct ib_cq *ibcq_aqp1; struct ib_cq *ibcq_aqp1;
struct ib_qp *ibqp_aqp1; struct ib_qp *ibqp_aqp1;
enum ib_rate rate; enum ib_rate rate;
enum ib_port_state port_state; enum ib_port_state port_state;
struct ehca_sma_attr saved_attr;
}; };
struct ehca_shca { struct ehca_shca {
......
...@@ -193,6 +193,40 @@ int ehca_query_port(struct ib_device *ibdev, ...@@ -193,6 +193,40 @@ int ehca_query_port(struct ib_device *ibdev,
return ret; return ret;
} }
int ehca_query_sma_attr(struct ehca_shca *shca,
u8 port, struct ehca_sma_attr *attr)
{
int ret = 0;
struct hipz_query_port *rblock;
rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
if (!rblock) {
ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
return -ENOMEM;
}
if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto query_sma_attr1;
}
memset(attr, 0, sizeof(struct ehca_sma_attr));
attr->lid = rblock->lid;
attr->lmc = rblock->lmc;
attr->sm_sl = rblock->sm_sl;
attr->sm_lid = rblock->sm_lid;
attr->pkey_tbl_len = rblock->pkey_tbl_len;
memcpy(attr->pkeys, rblock->pkey_entries, sizeof(attr->pkeys));
query_sma_attr1:
ehca_free_fw_ctrlblock(rblock);
return ret;
}
int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
{ {
int ret = 0; int ret = 0;
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7) #define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7)
#define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15) #define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15)
#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16) #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
#define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16,16)
#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63) #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63)
#define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7) #define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7)
...@@ -286,30 +287,61 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe) ...@@ -286,30 +287,61 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe)
return; return;
} }
static void parse_ec(struct ehca_shca *shca, u64 eqe) static void dispatch_port_event(struct ehca_shca *shca, int port_num,
enum ib_event_type type, const char *msg)
{ {
struct ib_event event; struct ib_event event;
ehca_info(&shca->ib_device, "port %d %s.", port_num, msg);
event.device = &shca->ib_device;
event.event = type;
event.element.port_num = port_num;
ib_dispatch_event(&event);
}
static void notify_port_conf_change(struct ehca_shca *shca, int port_num)
{
struct ehca_sma_attr new_attr;
struct ehca_sma_attr *old_attr = &shca->sport[port_num - 1].saved_attr;
ehca_query_sma_attr(shca, port_num, &new_attr);
if (new_attr.sm_sl != old_attr->sm_sl ||
new_attr.sm_lid != old_attr->sm_lid)
dispatch_port_event(shca, port_num, IB_EVENT_SM_CHANGE,
"SM changed");
if (new_attr.lid != old_attr->lid ||
new_attr.lmc != old_attr->lmc)
dispatch_port_event(shca, port_num, IB_EVENT_LID_CHANGE,
"LID changed");
if (new_attr.pkey_tbl_len != old_attr->pkey_tbl_len ||
memcmp(new_attr.pkeys, old_attr->pkeys,
sizeof(u16) * new_attr.pkey_tbl_len))
dispatch_port_event(shca, port_num, IB_EVENT_PKEY_CHANGE,
"P_Key changed");
*old_attr = new_attr;
}
static void parse_ec(struct ehca_shca *shca, u64 eqe)
{
u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe); u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe); u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
switch (ec) { switch (ec) {
case 0x30: /* port availability change */ case 0x30: /* port availability change */
if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) { if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
ehca_info(&shca->ib_device,
"port %x is active.", port);
event.device = &shca->ib_device;
event.event = IB_EVENT_PORT_ACTIVE;
event.element.port_num = port;
shca->sport[port - 1].port_state = IB_PORT_ACTIVE; shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
ib_dispatch_event(&event); dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
"is active");
ehca_query_sma_attr(shca, port,
&shca->sport[port - 1].saved_attr);
} else { } else {
ehca_info(&shca->ib_device,
"port %x is inactive.", port);
event.device = &shca->ib_device;
event.event = IB_EVENT_PORT_ERR;
event.element.port_num = port;
shca->sport[port - 1].port_state = IB_PORT_DOWN; shca->sport[port - 1].port_state = IB_PORT_DOWN;
ib_dispatch_event(&event); dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
"is inactive");
} }
break; break;
case 0x31: case 0x31:
...@@ -317,24 +349,19 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) ...@@ -317,24 +349,19 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
* disruptive change is caused by * disruptive change is caused by
* LID, PKEY or SM change * LID, PKEY or SM change
*/ */
ehca_warn(&shca->ib_device, if (EHCA_BMASK_GET(NEQE_DISRUPTIVE, eqe)) {
"disruptive port %x configuration change", port); ehca_warn(&shca->ib_device, "disruptive port "
"%d configuration change", port);
ehca_info(&shca->ib_device,
"port %x is inactive.", port);
event.device = &shca->ib_device;
event.event = IB_EVENT_PORT_ERR;
event.element.port_num = port;
shca->sport[port - 1].port_state = IB_PORT_DOWN; shca->sport[port - 1].port_state = IB_PORT_DOWN;
ib_dispatch_event(&event); dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
"is inactive");
ehca_info(&shca->ib_device,
"port %x is active.", port);
event.device = &shca->ib_device;
event.event = IB_EVENT_PORT_ACTIVE;
event.element.port_num = port;
shca->sport[port - 1].port_state = IB_PORT_ACTIVE; shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
ib_dispatch_event(&event); dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
"is active");
} else
notify_port_conf_change(shca, port);
break; break;
case 0x32: /* adapter malfunction */ case 0x32: /* adapter malfunction */
ehca_err(&shca->ib_device, "Adapter malfunction."); ehca_err(&shca->ib_device, "Adapter malfunction.");
......
...@@ -49,6 +49,9 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props); ...@@ -49,6 +49,9 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props);
int ehca_query_port(struct ib_device *ibdev, u8 port, int ehca_query_port(struct ib_device *ibdev, u8 port,
struct ib_port_attr *props); struct ib_port_attr *props);
int ehca_query_sma_attr(struct ehca_shca *shca, u8 port,
struct ehca_sma_attr *attr);
int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey); int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey);
int ehca_query_gid(struct ib_device *ibdev, u8 port, int index, int ehca_query_gid(struct ib_device *ibdev, u8 port, int index,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment