]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/infiniband/core/smi.c
IB/mad: Create a generic helper for DR SMP Send processing
[mirror_ubuntu-artful-kernel.git] / drivers / infiniband / core / smi.c
CommitLineData
1da177e4 1/*
2a1d9b7f
RD
2 * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved.
3 * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved.
4 * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved.
5 * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved.
de493d47 6 * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved.
2a1d9b7f 7 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
1da177e4
LT
8 *
9 * This software is available to you under a choice of one of two
10 * licenses. You may choose to be licensed under the terms of the GNU
11 * General Public License (GPL) Version 2, available from the file
12 * COPYING in the main directory of this source tree, or the
13 * OpenIB.org BSD license below:
14 *
15 * Redistribution and use in source and binary forms, with or
16 * without modification, are permitted provided that the following
17 * conditions are met:
18 *
19 * - Redistributions of source code must retain the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer.
22 *
23 * - Redistributions in binary form must reproduce the above
24 * copyright notice, this list of conditions and the following
25 * disclaimer in the documentation and/or other materials
26 * provided with the distribution.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
32 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
33 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35 * SOFTWARE.
36 *
1da177e4
LT
37 */
38
a4d61e84 39#include <rdma/ib_smi.h>
1da177e4
LT
40#include "smi.h"
41
92f15056
IW
42static enum smi_action __smi_handle_dr_smp_send(u8 node_type, int port_num,
43 u8 *hop_ptr, u8 hop_cnt,
44 const u8 *initial_path,
45 const u8 *return_path,
46 u8 direction,
47 bool dr_dlid_is_permissive,
48 bool dr_slid_is_permissive)
1da177e4 49{
1da177e4 50 /* See section 14.2.2.2, Vol 1 IB spec */
60f2b652
RD
51 /* C14-6 -- valid hop_cnt values are from 0 to 63 */
52 if (hop_cnt >= IB_SMP_MAX_PATH_HOPS)
53 return IB_SMI_DISCARD;
54
92f15056 55 if (!direction) {
1da177e4 56 /* C14-9:1 */
92f15056
IW
57 if (hop_cnt && *hop_ptr == 0) {
58 (*hop_ptr)++;
59 return (initial_path[*hop_ptr] ==
de493d47 60 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
61 }
62
63 /* C14-9:2 */
92f15056 64 if (*hop_ptr && *hop_ptr < hop_cnt) {
07ebafba 65 if (node_type != RDMA_NODE_IB_SWITCH)
de493d47 66 return IB_SMI_DISCARD;
1da177e4 67
92f15056
IW
68 /* return_path set when received */
69 (*hop_ptr)++;
70 return (initial_path[*hop_ptr] ==
de493d47 71 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
72 }
73
74 /* C14-9:3 -- We're at the end of the DR segment of path */
92f15056
IW
75 if (*hop_ptr == hop_cnt) {
76 /* return_path set when received */
77 (*hop_ptr)++;
07ebafba 78 return (node_type == RDMA_NODE_IB_SWITCH ||
92f15056 79 dr_dlid_is_permissive ?
de493d47 80 IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
81 }
82
83 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
84 /* C14-9:5 -- Fail unreasonable hop pointer */
92f15056 85 return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
86
87 } else {
88 /* C14-13:1 */
92f15056
IW
89 if (hop_cnt && *hop_ptr == hop_cnt + 1) {
90 (*hop_ptr)--;
91 return (return_path[*hop_ptr] ==
de493d47 92 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
93 }
94
95 /* C14-13:2 */
92f15056 96 if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) {
07ebafba 97 if (node_type != RDMA_NODE_IB_SWITCH)
de493d47 98 return IB_SMI_DISCARD;
1da177e4 99
92f15056
IW
100 (*hop_ptr)--;
101 return (return_path[*hop_ptr] ==
de493d47 102 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
103 }
104
105 /* C14-13:3 -- at the end of the DR segment of path */
92f15056
IW
106 if (*hop_ptr == 1) {
107 (*hop_ptr)--;
1da177e4 108 /* C14-13:3 -- SMPs destined for SM shouldn't be here */
07ebafba 109 return (node_type == RDMA_NODE_IB_SWITCH ||
92f15056 110 dr_slid_is_permissive ?
de493d47 111 IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
112 }
113
114 /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */
92f15056 115 if (*hop_ptr == 0)
de493d47 116 return IB_SMI_HANDLE;
1da177e4
LT
117
118 /* C14-13:5 -- Check for unreasonable hop pointer */
de493d47 119 return IB_SMI_DISCARD;
1da177e4
LT
120 }
121}
122
92f15056
IW
123/*
124 * Fixup a directed route SMP for sending
125 * Return IB_SMI_DISCARD if the SMP should be discarded
126 */
127enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
128 u8 node_type, int port_num)
129{
130 return __smi_handle_dr_smp_send(node_type, port_num,
131 &smp->hop_ptr, smp->hop_cnt,
132 smp->initial_path,
133 smp->return_path,
134 ib_get_smp_direction(smp),
135 smp->dr_dlid == IB_LID_PERMISSIVE,
136 smp->dr_slid == IB_LID_PERMISSIVE);
137}
138
1da177e4
LT
139/*
140 * Adjust information for a received SMP
b78d28a2 141 * Return IB_SMI_DISCARD if the SMP should be dropped
1da177e4 142 */
de493d47
HR
143enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
144 int port_num, int phys_port_cnt)
1da177e4
LT
145{
146 u8 hop_ptr, hop_cnt;
147
148 hop_ptr = smp->hop_ptr;
149 hop_cnt = smp->hop_cnt;
150
151 /* See section 14.2.2.2, Vol 1 IB spec */
60f2b652
RD
152 /* C14-6 -- valid hop_cnt values are from 0 to 63 */
153 if (hop_cnt >= IB_SMP_MAX_PATH_HOPS)
154 return IB_SMI_DISCARD;
155
1da177e4
LT
156 if (!ib_get_smp_direction(smp)) {
157 /* C14-9:1 -- sender should have incremented hop_ptr */
158 if (hop_cnt && hop_ptr == 0)
de493d47 159 return IB_SMI_DISCARD;
1da177e4
LT
160
161 /* C14-9:2 -- intermediate hop */
162 if (hop_ptr && hop_ptr < hop_cnt) {
07ebafba 163 if (node_type != RDMA_NODE_IB_SWITCH)
de493d47 164 return IB_SMI_DISCARD;
1da177e4
LT
165
166 smp->return_path[hop_ptr] = port_num;
167 /* smp->hop_ptr updated when sending */
de493d47
HR
168 return (smp->initial_path[hop_ptr+1] <= phys_port_cnt ?
169 IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
170 }
171
172 /* C14-9:3 -- We're at the end of the DR segment of path */
173 if (hop_ptr == hop_cnt) {
174 if (hop_cnt)
175 smp->return_path[hop_ptr] = port_num;
176 /* smp->hop_ptr updated when sending */
177
07ebafba 178 return (node_type == RDMA_NODE_IB_SWITCH ||
de493d47
HR
179 smp->dr_dlid == IB_LID_PERMISSIVE ?
180 IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
181 }
182
183 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
184 /* C14-9:5 -- fail unreasonable hop pointer */
de493d47 185 return (hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
186
187 } else {
188
189 /* C14-13:1 */
190 if (hop_cnt && hop_ptr == hop_cnt + 1) {
191 smp->hop_ptr--;
192 return (smp->return_path[smp->hop_ptr] ==
de493d47 193 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
194 }
195
196 /* C14-13:2 */
197 if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
07ebafba 198 if (node_type != RDMA_NODE_IB_SWITCH)
de493d47 199 return IB_SMI_DISCARD;
1da177e4
LT
200
201 /* smp->hop_ptr updated when sending */
de493d47
HR
202 return (smp->return_path[hop_ptr-1] <= phys_port_cnt ?
203 IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
204 }
205
206 /* C14-13:3 -- We're at the end of the DR segment of path */
207 if (hop_ptr == 1) {
208 if (smp->dr_slid == IB_LID_PERMISSIVE) {
209 /* giving SMP to SM - update hop_ptr */
210 smp->hop_ptr--;
de493d47 211 return IB_SMI_HANDLE;
1da177e4
LT
212 }
213 /* smp->hop_ptr updated when sending */
de493d47 214 return (node_type == RDMA_NODE_IB_SWITCH ?
1bae4dbf 215 IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
216 }
217
218 /* C14-13:4 -- hop_ptr = 0 -> give to SM */
219 /* C14-13:5 -- Check for unreasonable hop pointer */
de493d47 220 return (hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
1da177e4
LT
221 }
222}
223
de493d47 224enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp)
1da177e4
LT
225{
226 u8 hop_ptr, hop_cnt;
227
228 hop_ptr = smp->hop_ptr;
229 hop_cnt = smp->hop_cnt;
230
231 if (!ib_get_smp_direction(smp)) {
232 /* C14-9:2 -- intermediate hop */
233 if (hop_ptr && hop_ptr < hop_cnt)
1bae4dbf 234 return IB_SMI_FORWARD;
1da177e4
LT
235
236 /* C14-9:3 -- at the end of the DR segment of path */
237 if (hop_ptr == hop_cnt)
de493d47
HR
238 return (smp->dr_dlid == IB_LID_PERMISSIVE ?
239 IB_SMI_SEND : IB_SMI_LOCAL);
1da177e4
LT
240
241 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
242 if (hop_ptr == hop_cnt + 1)
de493d47 243 return IB_SMI_SEND;
1da177e4 244 } else {
de493d47 245 /* C14-13:2 -- intermediate hop */
1da177e4 246 if (2 <= hop_ptr && hop_ptr <= hop_cnt)
1bae4dbf 247 return IB_SMI_FORWARD;
1da177e4
LT
248
249 /* C14-13:3 -- at the end of the DR segment of path */
250 if (hop_ptr == 1)
de493d47
HR
251 return (smp->dr_slid != IB_LID_PERMISSIVE ?
252 IB_SMI_SEND : IB_SMI_LOCAL);
1da177e4 253 }
de493d47 254 return IB_SMI_LOCAL;
1da177e4 255}
1bae4dbf
HR
256
257/*
258 * Return the forwarding port number from initial_path for outgoing SMP and
259 * from return_path for returning SMP
260 */
261int smi_get_fwd_port(struct ib_smp *smp)
262{
263 return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] :
264 smp->return_path[smp->hop_ptr-1]);
265}