xref: /openbmc/linux/drivers/infiniband/core/smi.c (revision 20e2fc42)
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, 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)
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, int port_num)
131 {
132 	return __smi_handle_dr_smp_send(is_switch, 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 
141 enum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp,
142 				       bool is_switch, int port_num)
143 {
144 	return __smi_handle_dr_smp_send(is_switch, 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 
155 static enum smi_action __smi_handle_dr_smp_recv(bool is_switch, 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)
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 				       int port_num, int phys_port_cnt)
242 {
243 	return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt,
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 
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 					   int port_num, int phys_port_cnt)
258 {
259 	return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt,
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 
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(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);
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(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 
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