aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHal Rosenstock <halr@voltaire.com>2007-05-14 17:21:52 -0400
committerRoland Dreier <rolandd@cisco.com>2007-07-09 19:17:32 -0400
commit1bae4dbf9576e563da23927e4078fffbbce67a75 (patch)
tree3728d91be2f42c1a4a73e41c92857769738d1b83
parent71780f59e127bb281a9302d430495ca9586c14e7 (diff)
IB/mad: Enhance SMI for switch support
Extend the SMI with switch (intermediate hop) support. Care has been taken to ensure that the CA (and router) code paths are changed as little as possible. Signed-off-by: Suresh Shelvapille <suri@baymicrosystems.com> Signed-off-by: Hal Rosenstock <halr@voltaire.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r--drivers/infiniband/core/agent.c19
-rw-r--r--drivers/infiniband/core/mad.c50
-rw-r--r--drivers/infiniband/core/smi.c16
-rw-r--r--drivers/infiniband/core/smi.h2
4 files changed, 72 insertions, 15 deletions
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c
index ecd1a3057c61..db2633e4aae6 100644
--- a/drivers/infiniband/core/agent.c
+++ b/drivers/infiniband/core/agent.c
@@ -3,7 +3,7 @@
3 * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. 3 * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved.
4 * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. 4 * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved.
5 * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. 5 * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved.
6 * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. 6 * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved.
7 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 7 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
8 * 8 *
9 * This software is available to you under a choice of one of two 9 * This software is available to you under a choice of one of two
@@ -34,7 +34,6 @@
34 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 34 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35 * SOFTWARE. 35 * SOFTWARE.
36 * 36 *
37 * $Id: agent.c 1389 2004-12-27 22:56:47Z roland $
38 */ 37 */
39 38
40#include <linux/slab.h> 39#include <linux/slab.h>
@@ -42,6 +41,7 @@
42 41
43#include "agent.h" 42#include "agent.h"
44#include "smi.h" 43#include "smi.h"
44#include "mad_priv.h"
45 45
46#define SPFX "ib_agent: " 46#define SPFX "ib_agent: "
47 47
@@ -87,8 +87,13 @@ int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
87 struct ib_mad_send_buf *send_buf; 87 struct ib_mad_send_buf *send_buf;
88 struct ib_ah *ah; 88 struct ib_ah *ah;
89 int ret; 89 int ret;
90 struct ib_mad_send_wr_private *mad_send_wr;
91
92 if (device->node_type == RDMA_NODE_IB_SWITCH)
93 port_priv = ib_get_agent_port(device, 0);
94 else
95 port_priv = ib_get_agent_port(device, port_num);
90 96
91 port_priv = ib_get_agent_port(device, port_num);
92 if (!port_priv) { 97 if (!port_priv) {
93 printk(KERN_ERR SPFX "Unable to find port agent\n"); 98 printk(KERN_ERR SPFX "Unable to find port agent\n");
94 return -ENODEV; 99 return -ENODEV;
@@ -113,6 +118,14 @@ int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
113 118
114 memcpy(send_buf->mad, mad, sizeof *mad); 119 memcpy(send_buf->mad, mad, sizeof *mad);
115 send_buf->ah = ah; 120 send_buf->ah = ah;
121
122 if (device->node_type == RDMA_NODE_IB_SWITCH) {
123 mad_send_wr = container_of(send_buf,
124 struct ib_mad_send_wr_private,
125 send_buf);
126 mad_send_wr->send_wr.wr.ud.port_num = port_num;
127 }
128
116 if ((ret = ib_post_send_mad(send_buf, NULL))) { 129 if ((ret = ib_post_send_mad(send_buf, NULL))) {
117 printk(KERN_ERR SPFX "ib_post_send_mad error:%d\n", ret); 130 printk(KERN_ERR SPFX "ib_post_send_mad error:%d\n", ret);
118 goto err2; 131 goto err2;
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 85ccf13b8041..6b8faca02f8a 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -675,10 +675,16 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
675 struct ib_mad_port_private *port_priv; 675 struct ib_mad_port_private *port_priv;
676 struct ib_mad_agent_private *recv_mad_agent = NULL; 676 struct ib_mad_agent_private *recv_mad_agent = NULL;
677 struct ib_device *device = mad_agent_priv->agent.device; 677 struct ib_device *device = mad_agent_priv->agent.device;
678 u8 port_num = mad_agent_priv->agent.port_num; 678 u8 port_num;
679 struct ib_wc mad_wc; 679 struct ib_wc mad_wc;
680 struct ib_send_wr *send_wr = &mad_send_wr->send_wr; 680 struct ib_send_wr *send_wr = &mad_send_wr->send_wr;
681 681
682 if (device->node_type == RDMA_NODE_IB_SWITCH &&
683 smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
684 port_num = send_wr->wr.ud.port_num;
685 else
686 port_num = mad_agent_priv->agent.port_num;
687
682 /* 688 /*
683 * Directed route handling starts if the initial LID routed part of 689 * Directed route handling starts if the initial LID routed part of
684 * a request or the ending LID routed part of a response is empty. 690 * a request or the ending LID routed part of a response is empty.
@@ -1839,6 +1845,7 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
1839 struct ib_mad_private *recv, *response; 1845 struct ib_mad_private *recv, *response;
1840 struct ib_mad_list_head *mad_list; 1846 struct ib_mad_list_head *mad_list;
1841 struct ib_mad_agent_private *mad_agent; 1847 struct ib_mad_agent_private *mad_agent;
1848 int port_num;
1842 1849
1843 response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL); 1850 response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL);
1844 if (!response) 1851 if (!response)
@@ -1872,25 +1879,50 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
1872 if (!validate_mad(&recv->mad.mad, qp_info->qp->qp_num)) 1879 if (!validate_mad(&recv->mad.mad, qp_info->qp->qp_num))
1873 goto out; 1880 goto out;
1874 1881
1882 if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH)
1883 port_num = wc->port_num;
1884 else
1885 port_num = port_priv->port_num;
1886
1875 if (recv->mad.mad.mad_hdr.mgmt_class == 1887 if (recv->mad.mad.mad_hdr.mgmt_class ==
1876 IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 1888 IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
1889 enum smi_forward_action retsmi;
1890
1877 if (smi_handle_dr_smp_recv(&recv->mad.smp, 1891 if (smi_handle_dr_smp_recv(&recv->mad.smp,
1878 port_priv->device->node_type, 1892 port_priv->device->node_type,
1879 port_priv->port_num, 1893 port_num,
1880 port_priv->device->phys_port_cnt) == 1894 port_priv->device->phys_port_cnt) ==
1881 IB_SMI_DISCARD) 1895 IB_SMI_DISCARD)
1882 goto out; 1896 goto out;
1883 1897
1884 if (smi_check_forward_dr_smp(&recv->mad.smp) == IB_SMI_LOCAL) 1898 retsmi = smi_check_forward_dr_smp(&recv->mad.smp);
1899 if (retsmi == IB_SMI_LOCAL)
1885 goto local; 1900 goto local;
1886 1901
1887 if (smi_handle_dr_smp_send(&recv->mad.smp, 1902 if (retsmi == IB_SMI_SEND) { /* don't forward */
1888 port_priv->device->node_type, 1903 if (smi_handle_dr_smp_send(&recv->mad.smp,
1889 port_priv->port_num) == IB_SMI_DISCARD) 1904 port_priv->device->node_type,
1890 goto out; 1905 port_num) == IB_SMI_DISCARD)
1906 goto out;
1907
1908 if (smi_check_local_smp(&recv->mad.smp, port_priv->device) == IB_SMI_DISCARD)
1909 goto out;
1910 } else if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH) {
1911 /* forward case for switches */
1912 memcpy(response, recv, sizeof(*response));
1913 response->header.recv_wc.wc = &response->header.wc;
1914 response->header.recv_wc.recv_buf.mad = &response->mad.mad;
1915 response->header.recv_wc.recv_buf.grh = &response->grh;
1916
1917 if (!agent_send_response(&response->mad.mad,
1918 &response->grh, wc,
1919 port_priv->device,
1920 smi_get_fwd_port(&recv->mad.smp),
1921 qp_info->qp->qp_num))
1922 response = NULL;
1891 1923
1892 if (smi_check_local_smp(&recv->mad.smp, port_priv->device) == IB_SMI_DISCARD)
1893 goto out; 1924 goto out;
1925 }
1894 } 1926 }
1895 1927
1896local: 1928local:
@@ -1919,7 +1951,7 @@ local:
1919 agent_send_response(&response->mad.mad, 1951 agent_send_response(&response->mad.mad,
1920 &recv->grh, wc, 1952 &recv->grh, wc,
1921 port_priv->device, 1953 port_priv->device,
1922 port_priv->port_num, 1954 port_num,
1923 qp_info->qp->qp_num); 1955 qp_info->qp->qp_num);
1924 goto out; 1956 goto out;
1925 } 1957 }
diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c
index 2bca753eb622..87236753bce9 100644
--- a/drivers/infiniband/core/smi.c
+++ b/drivers/infiniband/core/smi.c
@@ -192,7 +192,7 @@ enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
192 } 192 }
193 /* smp->hop_ptr updated when sending */ 193 /* smp->hop_ptr updated when sending */
194 return (node_type == RDMA_NODE_IB_SWITCH ? 194 return (node_type == RDMA_NODE_IB_SWITCH ?
195 IB_SMI_HANDLE: IB_SMI_DISCARD); 195 IB_SMI_HANDLE : IB_SMI_DISCARD);
196 } 196 }
197 197
198 /* C14-13:4 -- hop_ptr = 0 -> give to SM */ 198 /* C14-13:4 -- hop_ptr = 0 -> give to SM */
@@ -211,7 +211,7 @@ enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp)
211 if (!ib_get_smp_direction(smp)) { 211 if (!ib_get_smp_direction(smp)) {
212 /* C14-9:2 -- intermediate hop */ 212 /* C14-9:2 -- intermediate hop */
213 if (hop_ptr && hop_ptr < hop_cnt) 213 if (hop_ptr && hop_ptr < hop_cnt)
214 return IB_SMI_SEND; 214 return IB_SMI_FORWARD;
215 215
216 /* C14-9:3 -- at the end of the DR segment of path */ 216 /* C14-9:3 -- at the end of the DR segment of path */
217 if (hop_ptr == hop_cnt) 217 if (hop_ptr == hop_cnt)
@@ -224,7 +224,7 @@ enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp)
224 } else { 224 } else {
225 /* C14-13:2 -- intermediate hop */ 225 /* C14-13:2 -- intermediate hop */
226 if (2 <= hop_ptr && hop_ptr <= hop_cnt) 226 if (2 <= hop_ptr && hop_ptr <= hop_cnt)
227 return IB_SMI_SEND; 227 return IB_SMI_FORWARD;
228 228
229 /* C14-13:3 -- at the end of the DR segment of path */ 229 /* C14-13:3 -- at the end of the DR segment of path */
230 if (hop_ptr == 1) 230 if (hop_ptr == 1)
@@ -233,3 +233,13 @@ enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp)
233 } 233 }
234 return IB_SMI_LOCAL; 234 return IB_SMI_LOCAL;
235} 235}
236
237/*
238 * Return the forwarding port number from initial_path for outgoing SMP and
239 * from return_path for returning SMP
240 */
241int smi_get_fwd_port(struct ib_smp *smp)
242{
243 return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] :
244 smp->return_path[smp->hop_ptr-1]);
245}
diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h
index 9a4b349efc30..1cfc2984434f 100644
--- a/drivers/infiniband/core/smi.h
+++ b/drivers/infiniband/core/smi.h
@@ -48,10 +48,12 @@ enum smi_action {
48enum smi_forward_action { 48enum smi_forward_action {
49 IB_SMI_LOCAL, /* SMP should be completed up the stack */ 49 IB_SMI_LOCAL, /* SMP should be completed up the stack */
50 IB_SMI_SEND, /* received DR SMP should be forwarded to the send queue */ 50 IB_SMI_SEND, /* received DR SMP should be forwarded to the send queue */
51 IB_SMI_FORWARD /* SMP should be forwarded (for switches only) */
51}; 52};
52 53
53enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, 54enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
54 int port_num, int phys_port_cnt); 55 int port_num, int phys_port_cnt);
56int smi_get_fwd_port(struct ib_smp *smp);
55extern enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp); 57extern enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp);
56extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, 58extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
57 u8 node_type, int port_num); 59 u8 node_type, int port_num);