]> Pileus Git - ~andy/linux/commitdiff
IB/cm: Add interim support for routed paths
authorSean Hefty <sean.hefty@intel.com>
Mon, 10 Dec 2007 23:53:25 +0000 (15:53 -0800)
committerRoland Dreier <rolandd@cisco.com>
Tue, 5 Feb 2008 04:20:42 +0000 (20:20 -0800)
Paths with hop_limit > 1 indicate that the connection will be routed
between IB subnets.  Update the subnet local field in the CM REQ based
on the hop_limit value.  In addition, if the path is routed, then set
the LIDs in the REQ to the permissive LIDs.  This is used to indicate
to the passive side that it should use the LIDs in the received local
route header (LRH) associated with the REQ when programming the QP.

This is a temporary work-around to the IB CM to support IB router
development until the IB router specification is completed.  It is not
anticipated that this work-around will cause any interoperability
issues with existing stacks or future stacks that will properly
support IB routers when defined.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
drivers/infiniband/core/cm.c

index c0150147d3478d5c539d2e3e320e1722c4b408ba..638b727d42e0796ff57de4de2fd3b4881c1839c4 100644 (file)
@@ -974,6 +974,9 @@ static void cm_format_req(struct cm_req_msg *req_msg,
                          struct cm_id_private *cm_id_priv,
                          struct ib_cm_req_param *param)
 {
+       struct ib_sa_path_rec *pri_path = param->primary_path;
+       struct ib_sa_path_rec *alt_path = param->alternate_path;
+
        cm_format_mad_hdr(&req_msg->hdr, CM_REQ_ATTR_ID,
                          cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_REQ));
 
@@ -997,35 +1000,46 @@ static void cm_format_req(struct cm_req_msg *req_msg,
        cm_req_set_max_cm_retries(req_msg, param->max_cm_retries);
        cm_req_set_srq(req_msg, param->srq);
 
-       req_msg->primary_local_lid = param->primary_path->slid;
-       req_msg->primary_remote_lid = param->primary_path->dlid;
-       req_msg->primary_local_gid = param->primary_path->sgid;
-       req_msg->primary_remote_gid = param->primary_path->dgid;
-       cm_req_set_primary_flow_label(req_msg, param->primary_path->flow_label);
-       cm_req_set_primary_packet_rate(req_msg, param->primary_path->rate);
-       req_msg->primary_traffic_class = param->primary_path->traffic_class;
-       req_msg->primary_hop_limit = param->primary_path->hop_limit;
-       cm_req_set_primary_sl(req_msg, param->primary_path->sl);
-       cm_req_set_primary_subnet_local(req_msg, 1); /* local only... */
+       if (pri_path->hop_limit <= 1) {
+               req_msg->primary_local_lid = pri_path->slid;
+               req_msg->primary_remote_lid = pri_path->dlid;
+       } else {
+               /* Work-around until there's a way to obtain remote LID info */
+               req_msg->primary_local_lid = IB_LID_PERMISSIVE;
+               req_msg->primary_remote_lid = IB_LID_PERMISSIVE;
+       }
+       req_msg->primary_local_gid = pri_path->sgid;
+       req_msg->primary_remote_gid = pri_path->dgid;
+       cm_req_set_primary_flow_label(req_msg, pri_path->flow_label);
+       cm_req_set_primary_packet_rate(req_msg, pri_path->rate);
+       req_msg->primary_traffic_class = pri_path->traffic_class;
+       req_msg->primary_hop_limit = pri_path->hop_limit;
+       cm_req_set_primary_sl(req_msg, pri_path->sl);
+       cm_req_set_primary_subnet_local(req_msg, (pri_path->hop_limit <= 1));
        cm_req_set_primary_local_ack_timeout(req_msg,
                cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
-                              param->primary_path->packet_life_time));
+                              pri_path->packet_life_time));
 
-       if (param->alternate_path) {
-               req_msg->alt_local_lid = param->alternate_path->slid;
-               req_msg->alt_remote_lid = param->alternate_path->dlid;
-               req_msg->alt_local_gid = param->alternate_path->sgid;
-               req_msg->alt_remote_gid = param->alternate_path->dgid;
+       if (alt_path) {
+               if (alt_path->hop_limit <= 1) {
+                       req_msg->alt_local_lid = alt_path->slid;
+                       req_msg->alt_remote_lid = alt_path->dlid;
+               } else {
+                       req_msg->alt_local_lid = IB_LID_PERMISSIVE;
+                       req_msg->alt_remote_lid = IB_LID_PERMISSIVE;
+               }
+               req_msg->alt_local_gid = alt_path->sgid;
+               req_msg->alt_remote_gid = alt_path->dgid;
                cm_req_set_alt_flow_label(req_msg,
-                                         param->alternate_path->flow_label);
-               cm_req_set_alt_packet_rate(req_msg, param->alternate_path->rate);
-               req_msg->alt_traffic_class = param->alternate_path->traffic_class;
-               req_msg->alt_hop_limit = param->alternate_path->hop_limit;
-               cm_req_set_alt_sl(req_msg, param->alternate_path->sl);
-               cm_req_set_alt_subnet_local(req_msg, 1); /* local only... */
+                                         alt_path->flow_label);
+               cm_req_set_alt_packet_rate(req_msg, alt_path->rate);
+               req_msg->alt_traffic_class = alt_path->traffic_class;
+               req_msg->alt_hop_limit = alt_path->hop_limit;
+               cm_req_set_alt_sl(req_msg, alt_path->sl);
+               cm_req_set_alt_subnet_local(req_msg, (alt_path->hop_limit <= 1));
                cm_req_set_alt_local_ack_timeout(req_msg,
                        cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
-                                      param->alternate_path->packet_life_time));
+                                      alt_path->packet_life_time));
        }
 
        if (param->private_data && param->private_data_len)
@@ -1441,6 +1455,34 @@ out:
        return listen_cm_id_priv;
 }
 
+/*
+ * Work-around for inter-subnet connections.  If the LIDs are permissive,
+ * we need to override the LID/SL data in the REQ with the LID information
+ * in the work completion.
+ */
+static void cm_process_routed_req(struct cm_req_msg *req_msg, struct ib_wc *wc)
+{
+       if (!cm_req_get_primary_subnet_local(req_msg)) {
+               if (req_msg->primary_local_lid == IB_LID_PERMISSIVE) {
+                       req_msg->primary_local_lid = cpu_to_be16(wc->slid);
+                       cm_req_set_primary_sl(req_msg, wc->sl);
+               }
+
+               if (req_msg->primary_remote_lid == IB_LID_PERMISSIVE)
+                       req_msg->primary_remote_lid = cpu_to_be16(wc->dlid_path_bits);
+       }
+
+       if (!cm_req_get_alt_subnet_local(req_msg)) {
+               if (req_msg->alt_local_lid == IB_LID_PERMISSIVE) {
+                       req_msg->alt_local_lid = cpu_to_be16(wc->slid);
+                       cm_req_set_alt_sl(req_msg, wc->sl);
+               }
+
+               if (req_msg->alt_remote_lid == IB_LID_PERMISSIVE)
+                       req_msg->alt_remote_lid = cpu_to_be16(wc->dlid_path_bits);
+       }
+}
+
 static int cm_req_handler(struct cm_work *work)
 {
        struct ib_cm_id *cm_id;
@@ -1481,6 +1523,7 @@ static int cm_req_handler(struct cm_work *work)
        cm_id_priv->id.service_id = req_msg->service_id;
        cm_id_priv->id.service_mask = __constant_cpu_to_be64(~0ULL);
 
+       cm_process_routed_req(req_msg, work->mad_recv_wc->wc);
        cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
        ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
        if (ret) {