1 | /* |
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. |
6 | * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. |
7 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. |
8 | * Copyright (c) 2014 Intel Corporation. All rights reserved. |
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 | * |
38 | */ |
39 | |
40 | #include <rdma/ib_smi.h> |
41 | #include "smi.h" |
42 | #include "opa_smi.h" |
43 | |
44 | static enum smi_action __smi_handle_dr_smp_send(bool is_switch, u32 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) |
51 | { |
52 | /* See section 14.2.2.2, Vol 1 IB spec */ |
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 | |
57 | if (!direction) { |
58 | /* C14-9:1 */ |
59 | if (hop_cnt && *hop_ptr == 0) { |
60 | (*hop_ptr)++; |
61 | return (initial_path[*hop_ptr] == |
62 | port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
63 | } |
64 | |
65 | /* C14-9:2 */ |
66 | if (*hop_ptr && *hop_ptr < hop_cnt) { |
67 | if (!is_switch) |
68 | return IB_SMI_DISCARD; |
69 | |
70 | /* return_path set when received */ |
71 | (*hop_ptr)++; |
72 | return (initial_path[*hop_ptr] == |
73 | port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
74 | } |
75 | |
76 | /* C14-9:3 -- We're at the end of the DR segment of path */ |
77 | if (*hop_ptr == hop_cnt) { |
78 | /* return_path set when received */ |
79 | (*hop_ptr)++; |
80 | return (is_switch || |
81 | dr_dlid_is_permissive ? |
82 | IB_SMI_HANDLE : IB_SMI_DISCARD); |
83 | } |
84 | |
85 | /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ |
86 | /* C14-9:5 -- Fail unreasonable hop pointer */ |
87 | return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
88 | |
89 | } else { |
90 | /* C14-13:1 */ |
91 | if (hop_cnt && *hop_ptr == hop_cnt + 1) { |
92 | (*hop_ptr)--; |
93 | return (return_path[*hop_ptr] == |
94 | port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
95 | } |
96 | |
97 | /* C14-13:2 */ |
98 | if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) { |
99 | if (!is_switch) |
100 | return IB_SMI_DISCARD; |
101 | |
102 | (*hop_ptr)--; |
103 | return (return_path[*hop_ptr] == |
104 | port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
105 | } |
106 | |
107 | /* C14-13:3 -- at the end of the DR segment of path */ |
108 | if (*hop_ptr == 1) { |
109 | (*hop_ptr)--; |
110 | /* C14-13:3 -- SMPs destined for SM shouldn't be here */ |
111 | return (is_switch || |
112 | dr_slid_is_permissive ? |
113 | IB_SMI_HANDLE : IB_SMI_DISCARD); |
114 | } |
115 | |
116 | /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */ |
117 | if (*hop_ptr == 0) |
118 | return IB_SMI_HANDLE; |
119 | |
120 | /* C14-13:5 -- Check for unreasonable hop pointer */ |
121 | return IB_SMI_DISCARD; |
122 | } |
123 | } |
124 | |
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 | bool is_switch, u32 port_num) |
131 | { |
132 | return __smi_handle_dr_smp_send(is_switch, port_num, |
133 | hop_ptr: &smp->hop_ptr, hop_cnt: smp->hop_cnt, |
134 | initial_path: smp->initial_path, |
135 | return_path: smp->return_path, |
136 | direction: ib_get_smp_direction(smp), |
137 | dr_dlid_is_permissive: smp->dr_dlid == IB_LID_PERMISSIVE, |
138 | dr_slid_is_permissive: smp->dr_slid == IB_LID_PERMISSIVE); |
139 | } |
140 | |
141 | enum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp, |
142 | bool is_switch, u32 port_num) |
143 | { |
144 | return __smi_handle_dr_smp_send(is_switch, port_num, |
145 | hop_ptr: &smp->hop_ptr, hop_cnt: smp->hop_cnt, |
146 | initial_path: smp->route.dr.initial_path, |
147 | return_path: smp->route.dr.return_path, |
148 | direction: opa_get_smp_direction(smp), |
149 | dr_dlid_is_permissive: smp->route.dr.dr_dlid == |
150 | OPA_LID_PERMISSIVE, |
151 | dr_slid_is_permissive: smp->route.dr.dr_slid == |
152 | OPA_LID_PERMISSIVE); |
153 | } |
154 | |
155 | static enum smi_action __smi_handle_dr_smp_recv(bool is_switch, u32 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) |
163 | { |
164 | /* See section 14.2.2.2, Vol 1 IB spec */ |
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 | |
169 | if (!direction) { |
170 | /* C14-9:1 -- sender should have incremented hop_ptr */ |
171 | if (hop_cnt && *hop_ptr == 0) |
172 | return IB_SMI_DISCARD; |
173 | |
174 | /* C14-9:2 -- intermediate hop */ |
175 | if (*hop_ptr && *hop_ptr < hop_cnt) { |
176 | if (!is_switch) |
177 | return IB_SMI_DISCARD; |
178 | |
179 | return_path[*hop_ptr] = port_num; |
180 | /* hop_ptr updated when sending */ |
181 | return (initial_path[*hop_ptr+1] <= phys_port_cnt ? |
182 | IB_SMI_HANDLE : IB_SMI_DISCARD); |
183 | } |
184 | |
185 | /* C14-9:3 -- We're at the end of the DR segment of path */ |
186 | if (*hop_ptr == hop_cnt) { |
187 | if (hop_cnt) |
188 | return_path[*hop_ptr] = port_num; |
189 | /* hop_ptr updated when sending */ |
190 | |
191 | return (is_switch || |
192 | dr_dlid_is_permissive ? |
193 | IB_SMI_HANDLE : IB_SMI_DISCARD); |
194 | } |
195 | |
196 | /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ |
197 | /* C14-9:5 -- fail unreasonable hop pointer */ |
198 | return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
199 | |
200 | } else { |
201 | |
202 | /* C14-13:1 */ |
203 | if (hop_cnt && *hop_ptr == hop_cnt + 1) { |
204 | (*hop_ptr)--; |
205 | return (return_path[*hop_ptr] == |
206 | port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
207 | } |
208 | |
209 | /* C14-13:2 */ |
210 | if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) { |
211 | if (!is_switch) |
212 | return IB_SMI_DISCARD; |
213 | |
214 | /* hop_ptr updated when sending */ |
215 | return (return_path[*hop_ptr-1] <= phys_port_cnt ? |
216 | IB_SMI_HANDLE : IB_SMI_DISCARD); |
217 | } |
218 | |
219 | /* C14-13:3 -- We're at the end of the DR segment of path */ |
220 | if (*hop_ptr == 1) { |
221 | if (dr_slid_is_permissive) { |
222 | /* giving SMP to SM - update hop_ptr */ |
223 | (*hop_ptr)--; |
224 | return IB_SMI_HANDLE; |
225 | } |
226 | /* hop_ptr updated when sending */ |
227 | return (is_switch ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
228 | } |
229 | |
230 | /* C14-13:4 -- hop_ptr = 0 -> give to SM */ |
231 | /* C14-13:5 -- Check for unreasonable hop pointer */ |
232 | return (*hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
233 | } |
234 | } |
235 | |
236 | /* |
237 | * Adjust information for a received SMP |
238 | * Return IB_SMI_DISCARD if the SMP should be dropped |
239 | */ |
240 | enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, bool is_switch, |
241 | u32 port_num, int phys_port_cnt) |
242 | { |
243 | return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, |
244 | hop_ptr: &smp->hop_ptr, hop_cnt: smp->hop_cnt, |
245 | initial_path: smp->initial_path, |
246 | return_path: smp->return_path, |
247 | direction: ib_get_smp_direction(smp), |
248 | dr_dlid_is_permissive: smp->dr_dlid == IB_LID_PERMISSIVE, |
249 | dr_slid_is_permissive: smp->dr_slid == IB_LID_PERMISSIVE); |
250 | } |
251 | |
252 | /* |
253 | * Adjust information for a received SMP |
254 | * Return IB_SMI_DISCARD if the SMP should be dropped |
255 | */ |
256 | enum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, bool is_switch, |
257 | u32 port_num, int phys_port_cnt) |
258 | { |
259 | return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, |
260 | hop_ptr: &smp->hop_ptr, hop_cnt: smp->hop_cnt, |
261 | initial_path: smp->route.dr.initial_path, |
262 | return_path: smp->route.dr.return_path, |
263 | direction: opa_get_smp_direction(smp), |
264 | dr_dlid_is_permissive: smp->route.dr.dr_dlid == |
265 | OPA_LID_PERMISSIVE, |
266 | dr_slid_is_permissive: smp->route.dr.dr_slid == |
267 | OPA_LID_PERMISSIVE); |
268 | } |
269 | |
270 | static enum smi_forward_action __smi_check_forward_dr_smp(u8 hop_ptr, u8 hop_cnt, |
271 | u8 direction, |
272 | bool dr_dlid_is_permissive, |
273 | bool dr_slid_is_permissive) |
274 | { |
275 | if (!direction) { |
276 | /* C14-9:2 -- intermediate hop */ |
277 | if (hop_ptr && hop_ptr < hop_cnt) |
278 | return IB_SMI_FORWARD; |
279 | |
280 | /* C14-9:3 -- at the end of the DR segment of path */ |
281 | if (hop_ptr == hop_cnt) |
282 | return (dr_dlid_is_permissive ? |
283 | IB_SMI_SEND : IB_SMI_LOCAL); |
284 | |
285 | /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ |
286 | if (hop_ptr == hop_cnt + 1) |
287 | return IB_SMI_SEND; |
288 | } else { |
289 | /* C14-13:2 -- intermediate hop */ |
290 | if (2 <= hop_ptr && hop_ptr <= hop_cnt) |
291 | return IB_SMI_FORWARD; |
292 | |
293 | /* C14-13:3 -- at the end of the DR segment of path */ |
294 | if (hop_ptr == 1) |
295 | return (!dr_slid_is_permissive ? |
296 | IB_SMI_SEND : IB_SMI_LOCAL); |
297 | } |
298 | return IB_SMI_LOCAL; |
299 | |
300 | } |
301 | |
302 | enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp) |
303 | { |
304 | return __smi_check_forward_dr_smp(hop_ptr: smp->hop_ptr, hop_cnt: smp->hop_cnt, |
305 | direction: ib_get_smp_direction(smp), |
306 | dr_dlid_is_permissive: smp->dr_dlid == IB_LID_PERMISSIVE, |
307 | dr_slid_is_permissive: smp->dr_slid == IB_LID_PERMISSIVE); |
308 | } |
309 | |
310 | enum smi_forward_action opa_smi_check_forward_dr_smp(struct opa_smp *smp) |
311 | { |
312 | return __smi_check_forward_dr_smp(hop_ptr: smp->hop_ptr, hop_cnt: smp->hop_cnt, |
313 | direction: opa_get_smp_direction(smp), |
314 | dr_dlid_is_permissive: smp->route.dr.dr_dlid == |
315 | OPA_LID_PERMISSIVE, |
316 | dr_slid_is_permissive: smp->route.dr.dr_slid == |
317 | OPA_LID_PERMISSIVE); |
318 | } |
319 | |
320 | /* |
321 | * Return the forwarding port number from initial_path for outgoing SMP and |
322 | * from return_path for returning SMP |
323 | */ |
324 | int smi_get_fwd_port(struct ib_smp *smp) |
325 | { |
326 | return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] : |
327 | smp->return_path[smp->hop_ptr-1]); |
328 | } |
329 | |
330 | /* |
331 | * Return the forwarding port number from initial_path for outgoing SMP and |
332 | * from return_path for returning SMP |
333 | */ |
334 | int opa_smi_get_fwd_port(struct opa_smp *smp) |
335 | { |
336 | return !opa_get_smp_direction(smp) ? smp->route.dr.initial_path[smp->hop_ptr+1] : |
337 | smp->route.dr.return_path[smp->hop_ptr-1]; |
338 | } |
339 | |