Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Hal Rosenstock and committed by
Roland Dreier
1bae4dbf 71780f59

+72 -15
+16 -3
drivers/infiniband/core/agent.c
··· 3 3 * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. 4 4 * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. 5 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 7 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 8 8 * 9 9 * This software is available to you under a choice of one of two ··· 34 34 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35 35 * SOFTWARE. 36 36 * 37 - * $Id: agent.c 1389 2004-12-27 22:56:47Z roland $ 38 37 */ 39 38 40 39 #include <linux/slab.h> ··· 41 42 42 43 #include "agent.h" 43 44 #include "smi.h" 45 + #include "mad_priv.h" 44 46 45 47 #define SPFX "ib_agent: " 46 48 ··· 87 87 struct ib_mad_send_buf *send_buf; 88 88 struct ib_ah *ah; 89 89 int ret; 90 + struct ib_mad_send_wr_private *mad_send_wr; 90 91 91 - port_priv = ib_get_agent_port(device, port_num); 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); 96 + 92 97 if (!port_priv) { 93 98 printk(KERN_ERR SPFX "Unable to find port agent\n"); 94 99 return -ENODEV; ··· 118 113 119 114 memcpy(send_buf->mad, mad, sizeof *mad); 120 115 send_buf->ah = ah; 116 + 117 + if (device->node_type == RDMA_NODE_IB_SWITCH) { 118 + mad_send_wr = container_of(send_buf, 119 + struct ib_mad_send_wr_private, 120 + send_buf); 121 + mad_send_wr->send_wr.wr.ud.port_num = port_num; 122 + } 123 + 121 124 if ((ret = ib_post_send_mad(send_buf, NULL))) { 122 125 printk(KERN_ERR SPFX "ib_post_send_mad error:%d\n", ret); 123 126 goto err2;
+41 -9
drivers/infiniband/core/mad.c
··· 675 675 struct ib_mad_port_private *port_priv; 676 676 struct ib_mad_agent_private *recv_mad_agent = NULL; 677 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 679 struct ib_wc mad_wc; 680 680 struct ib_send_wr *send_wr = &mad_send_wr->send_wr; 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; 681 687 682 688 /* 683 689 * Directed route handling starts if the initial LID routed part of ··· 1845 1839 struct ib_mad_private *recv, *response; 1846 1840 struct ib_mad_list_head *mad_list; 1847 1841 struct ib_mad_agent_private *mad_agent; 1842 + int port_num; 1848 1843 1849 1844 response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL); 1850 1845 if (!response) ··· 1879 1872 if (!validate_mad(&recv->mad.mad, qp_info->qp->qp_num)) 1880 1873 goto out; 1881 1874 1875 + if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH) 1876 + port_num = wc->port_num; 1877 + else 1878 + port_num = port_priv->port_num; 1879 + 1882 1880 if (recv->mad.mad.mad_hdr.mgmt_class == 1883 1881 IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 1882 + enum smi_forward_action retsmi; 1883 + 1884 1884 if (smi_handle_dr_smp_recv(&recv->mad.smp, 1885 1885 port_priv->device->node_type, 1886 - port_priv->port_num, 1886 + port_num, 1887 1887 port_priv->device->phys_port_cnt) == 1888 1888 IB_SMI_DISCARD) 1889 1889 goto out; 1890 1890 1891 - if (smi_check_forward_dr_smp(&recv->mad.smp) == IB_SMI_LOCAL) 1891 + retsmi = smi_check_forward_dr_smp(&recv->mad.smp); 1892 + if (retsmi == IB_SMI_LOCAL) 1892 1893 goto local; 1893 1894 1894 - if (smi_handle_dr_smp_send(&recv->mad.smp, 1895 - port_priv->device->node_type, 1896 - port_priv->port_num) == IB_SMI_DISCARD) 1897 - goto out; 1895 + if (retsmi == IB_SMI_SEND) { /* don't forward */ 1896 + if (smi_handle_dr_smp_send(&recv->mad.smp, 1897 + port_priv->device->node_type, 1898 + port_num) == IB_SMI_DISCARD) 1899 + goto out; 1898 1900 1899 - if (smi_check_local_smp(&recv->mad.smp, port_priv->device) == IB_SMI_DISCARD) 1901 + if (smi_check_local_smp(&recv->mad.smp, port_priv->device) == IB_SMI_DISCARD) 1902 + goto out; 1903 + } else if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH) { 1904 + /* forward case for switches */ 1905 + memcpy(response, recv, sizeof(*response)); 1906 + response->header.recv_wc.wc = &response->header.wc; 1907 + response->header.recv_wc.recv_buf.mad = &response->mad.mad; 1908 + response->header.recv_wc.recv_buf.grh = &response->grh; 1909 + 1910 + if (!agent_send_response(&response->mad.mad, 1911 + &response->grh, wc, 1912 + port_priv->device, 1913 + smi_get_fwd_port(&recv->mad.smp), 1914 + qp_info->qp->qp_num)) 1915 + response = NULL; 1916 + 1900 1917 goto out; 1918 + } 1901 1919 } 1902 1920 1903 1921 local: ··· 1951 1919 agent_send_response(&response->mad.mad, 1952 1920 &recv->grh, wc, 1953 1921 port_priv->device, 1954 - port_priv->port_num, 1922 + port_num, 1955 1923 qp_info->qp->qp_num); 1956 1924 goto out; 1957 1925 }
+13 -3
drivers/infiniband/core/smi.c
··· 192 192 } 193 193 /* smp->hop_ptr updated when sending */ 194 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 198 /* C14-13:4 -- hop_ptr = 0 -> give to SM */ ··· 211 211 if (!ib_get_smp_direction(smp)) { 212 212 /* C14-9:2 -- intermediate hop */ 213 213 if (hop_ptr && hop_ptr < hop_cnt) 214 - return IB_SMI_SEND; 214 + return IB_SMI_FORWARD; 215 215 216 216 /* C14-9:3 -- at the end of the DR segment of path */ 217 217 if (hop_ptr == hop_cnt) ··· 224 224 } else { 225 225 /* C14-13:2 -- intermediate hop */ 226 226 if (2 <= hop_ptr && hop_ptr <= hop_cnt) 227 - return IB_SMI_SEND; 227 + return IB_SMI_FORWARD; 228 228 229 229 /* C14-13:3 -- at the end of the DR segment of path */ 230 230 if (hop_ptr == 1) ··· 232 232 IB_SMI_SEND : IB_SMI_LOCAL); 233 233 } 234 234 return IB_SMI_LOCAL; 235 + } 236 + 237 + /* 238 + * Return the forwarding port number from initial_path for outgoing SMP and 239 + * from return_path for returning SMP 240 + */ 241 + int 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]); 235 245 }
+2
drivers/infiniband/core/smi.h
··· 48 48 enum smi_forward_action { 49 49 IB_SMI_LOCAL, /* SMP should be completed up the stack */ 50 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 53 54 enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, 54 55 int port_num, int phys_port_cnt); 56 + int smi_get_fwd_port(struct ib_smp *smp); 55 57 extern enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp); 56 58 extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, 57 59 u8 node_type, int port_num);