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