xref: /openbmc/linux/drivers/infiniband/core/smi.c (revision 179dd8c0348af75b02c7d72eaaf1cb179f1721ef)
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(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)
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 (node_type != RDMA_NODE_IB_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 (node_type == RDMA_NODE_IB_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 (node_type != RDMA_NODE_IB_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 (node_type == RDMA_NODE_IB_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 				       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 
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 
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)
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 (node_type != RDMA_NODE_IB_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 (node_type == RDMA_NODE_IB_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 (node_type != RDMA_NODE_IB_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 (node_type == RDMA_NODE_IB_SWITCH ?
228 				IB_SMI_HANDLE : IB_SMI_DISCARD);
229 		}
230 
231 		/* C14-13:4 -- hop_ptr = 0 -> give to SM */
232 		/* C14-13:5 -- Check for unreasonable hop pointer */
233 		return (*hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD);
234 	}
235 }
236 
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 
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 
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)
275 {
276 	if (!direction) {
277 		/* C14-9:2 -- intermediate hop */
278 		if (hop_ptr && hop_ptr < hop_cnt)
279 			return IB_SMI_FORWARD;
280 
281 		/* C14-9:3 -- at the end of the DR segment of path */
282 		if (hop_ptr == hop_cnt)
283 			return (dr_dlid_is_permissive ?
284 				IB_SMI_SEND : IB_SMI_LOCAL);
285 
286 		/* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
287 		if (hop_ptr == hop_cnt + 1)
288 			return IB_SMI_SEND;
289 	} else {
290 		/* C14-13:2  -- intermediate hop */
291 		if (2 <= hop_ptr && hop_ptr <= hop_cnt)
292 			return IB_SMI_FORWARD;
293 
294 		/* C14-13:3 -- at the end of the DR segment of path */
295 		if (hop_ptr == 1)
296 			return (!dr_slid_is_permissive ?
297 				IB_SMI_SEND : IB_SMI_LOCAL);
298 	}
299 	return IB_SMI_LOCAL;
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);
309 }
310 
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 
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 }
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 }
340