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 | |
4139032b | 44 | static enum smi_action __smi_handle_dr_smp_send(bool is_switch, int port_num, |
92f15056 IW |
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) { |
4139032b | 67 | if (!is_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)++; | |
4139032b | 80 | return (is_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) { |
4139032b | 99 | if (!is_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 */ |
4139032b | 111 | return (is_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, | |
4139032b | 130 | bool is_switch, int port_num) |
92f15056 | 131 | { |
4139032b | 132 | return __smi_handle_dr_smp_send(is_switch, port_num, |
92f15056 IW |
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 | 141 | enum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp, |
4139032b | 142 | bool is_switch, int port_num) |
f28990bc | 143 | { |
4139032b | 144 | return __smi_handle_dr_smp_send(is_switch, port_num, |
f28990bc IW |
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 | ||
4139032b | 155 | static enum smi_action __smi_handle_dr_smp_recv(bool is_switch, int port_num, |
86f0e67a IW |
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) { |
4139032b | 176 | if (!is_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 | |
4139032b | 191 | return (is_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) { |
4139032b | 211 | if (!is_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 */ |
4139032b | 227 | return (is_switch ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
1da177e4 LT |
228 | } |
229 | ||
230 | /* C14-13:4 -- hop_ptr = 0 -> give to SM */ | |
231 | /* C14-13:5 -- Check for unreasonable hop pointer */ | |
86f0e67a | 232 | return (*hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD); |
1da177e4 LT |
233 | } |
234 | } | |
235 | ||
86f0e67a IW |
236 | /* |
237 | * Adjust information for a received SMP | |
238 | * Return IB_SMI_DISCARD if the SMP should be dropped | |
239 | */ | |
4139032b | 240 | enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, bool is_switch, |
86f0e67a IW |
241 | int port_num, int phys_port_cnt) |
242 | { | |
4139032b | 243 | return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, |
86f0e67a IW |
244 | &smp->hop_ptr, smp->hop_cnt, |
245 | smp->initial_path, | |
246 | smp->return_path, | |
247 | ib_get_smp_direction(smp), | |
248 | smp->dr_dlid == IB_LID_PERMISSIVE, | |
249 | smp->dr_slid == IB_LID_PERMISSIVE); | |
250 | } | |
251 | ||
f28990bc IW |
252 | /* |
253 | * Adjust information for a received SMP | |
254 | * Return IB_SMI_DISCARD if the SMP should be dropped | |
255 | */ | |
4139032b | 256 | enum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, bool is_switch, |
f28990bc IW |
257 | int port_num, int phys_port_cnt) |
258 | { | |
4139032b | 259 | return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, |
f28990bc IW |
260 | &smp->hop_ptr, smp->hop_cnt, |
261 | smp->route.dr.initial_path, | |
262 | smp->route.dr.return_path, | |
263 | opa_get_smp_direction(smp), | |
264 | smp->route.dr.dr_dlid == | |
265 | OPA_LID_PERMISSIVE, | |
266 | smp->route.dr.dr_slid == | |
267 | OPA_LID_PERMISSIVE); | |
268 | } | |
269 | ||
29869eaf IW |
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) | |
1da177e4 | 274 | { |
29869eaf | 275 | if (!direction) { |
1da177e4 LT |
276 | /* C14-9:2 -- intermediate hop */ |
277 | if (hop_ptr && hop_ptr < hop_cnt) | |
1bae4dbf | 278 | return IB_SMI_FORWARD; |
1da177e4 LT |
279 | |
280 | /* C14-9:3 -- at the end of the DR segment of path */ | |
281 | if (hop_ptr == hop_cnt) | |
29869eaf | 282 | return (dr_dlid_is_permissive ? |
de493d47 | 283 | IB_SMI_SEND : IB_SMI_LOCAL); |
1da177e4 LT |
284 | |
285 | /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ | |
286 | if (hop_ptr == hop_cnt + 1) | |
de493d47 | 287 | return IB_SMI_SEND; |
1da177e4 | 288 | } else { |
de493d47 | 289 | /* C14-13:2 -- intermediate hop */ |
1da177e4 | 290 | if (2 <= hop_ptr && hop_ptr <= hop_cnt) |
1bae4dbf | 291 | return IB_SMI_FORWARD; |
1da177e4 LT |
292 | |
293 | /* C14-13:3 -- at the end of the DR segment of path */ | |
294 | if (hop_ptr == 1) | |
29869eaf | 295 | return (!dr_slid_is_permissive ? |
de493d47 | 296 | IB_SMI_SEND : IB_SMI_LOCAL); |
1da177e4 | 297 | } |
de493d47 | 298 | return IB_SMI_LOCAL; |
29869eaf IW |
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(smp->hop_ptr, smp->hop_cnt, | |
305 | ib_get_smp_direction(smp), | |
306 | smp->dr_dlid == IB_LID_PERMISSIVE, | |
307 | smp->dr_slid == IB_LID_PERMISSIVE); | |
1da177e4 | 308 | } |
1bae4dbf | 309 | |
f28990bc IW |
310 | enum smi_forward_action opa_smi_check_forward_dr_smp(struct opa_smp *smp) |
311 | { | |
312 | return __smi_check_forward_dr_smp(smp->hop_ptr, smp->hop_cnt, | |
313 | opa_get_smp_direction(smp), | |
314 | smp->route.dr.dr_dlid == | |
315 | OPA_LID_PERMISSIVE, | |
316 | smp->route.dr.dr_slid == | |
317 | OPA_LID_PERMISSIVE); | |
318 | } | |
319 | ||
1bae4dbf HR |
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 | } | |
f28990bc IW |
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 | } |