IB/ehca: Notify consumers of LID/PKEY/SM changes after nondisruptive events
authorJoachim Fenkes <fenkes@de.ibm.com>
Mon, 9 Jul 2007 13:32:22 +0000 (15:32 +0200)
committerRoland Dreier <rolandd@cisco.com>
Tue, 10 Jul 2007 03:12:27 +0000 (20:12 -0700)
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>
drivers/infiniband/hw/ehca/ehca_classes.h
drivers/infiniband/hw/ehca/ehca_hca.c
drivers/infiniband/hw/ehca/ehca_irq.c
drivers/infiniband/hw/ehca/ehca_iverbs.h

index f1e0db2ff16c25423dfd80bafcfe07fbf3f5adca..daf823ea1acedb242caa59e22b35de602570d1b5 100644 (file)
@@ -87,11 +87,17 @@ struct ehca_eq {
        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 ib_cq *ibcq_aqp1;
        struct ib_qp *ibqp_aqp1;
        enum ib_rate  rate;
        enum ib_port_state port_state;
+       struct ehca_sma_attr saved_attr;
 };
 
 struct ehca_shca {
index b310de5c94aeeaa2f6c1c43c03c7a829d33ad442..bbd3c6a5822f1d0b65cc97f536e1a3ee7d33719e 100644 (file)
@@ -193,6 +193,40 @@ query_port1:
        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 ret = 0;
index 02b73c84c49b78fde6a4788ce7ae3740f632e390..96eba383075437e4dfea5deb10e307b693282ed4 100644 (file)
@@ -61,6 +61,7 @@
 #define NEQE_EVENT_CODE        EHCA_BMASK_IBM(2,7)
 #define NEQE_PORT_NUMBER       EHCA_BMASK_IBM(8,15)
 #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_TYPE        EHCA_BMASK_IBM(0,7)
@@ -286,30 +287,61 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe)
        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;
+
+       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 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
 
        switch (ec) {
        case 0x30: /* port availability change */
                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;
-                       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 {
-                       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;
-                       ib_dispatch_event(&event);
+                       dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
+                                           "is inactive");
                }
                break;
        case 0x31:
@@ -317,24 +349,19 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
                 * disruptive change is caused by
                 * LID, PKEY or SM change
                 */
-               ehca_warn(&shca->ib_device,
-                         "disruptive port %x 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;
-               ib_dispatch_event(&event);
-
-               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;
-               ib_dispatch_event(&event);
+               if (EHCA_BMASK_GET(NEQE_DISRUPTIVE, eqe)) {
+                       ehca_warn(&shca->ib_device, "disruptive port "
+                                 "%d configuration change", port);
+
+                       shca->sport[port - 1].port_state = IB_PORT_DOWN;
+                       dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
+                                           "is inactive");
+
+                       shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+                       dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
+                                           "is active");
+               } else
+                       notify_port_conf_change(shca, port);
                break;
        case 0x32: /* adapter malfunction */
                ehca_err(&shca->ib_device, "Adapter malfunction.");
index fd84a804814c87afd3fa0707b7eacfb1d4e255d7..77aeca6a2c2f3e2428dd989b8eabc4afa496fd5d 100644 (file)
@@ -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,
                    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_gid(struct ib_device *ibdev, u8 port, int index,