xref: /openbmc/linux/drivers/infiniband/core/smi.c (revision 1da177e4)
1 /*
2  * Copyright (c) 2004 Mellanox Technologies Ltd.  All rights reserved.
3  * Copyright (c) 2004 Infinicon Corporation.  All rights reserved.
4  * Copyright (c) 2004 Intel Corporation.  All rights reserved.
5  * Copyright (c) 2004 Topspin Corporation.  All rights reserved.
6  * Copyright (c) 2004 Voltaire Corporation.  All rights reserved.
7  *
8  * This software is available to you under a choice of one of two
9  * licenses.  You may choose to be licensed under the terms of the GNU
10  * General Public License (GPL) Version 2, available from the file
11  * COPYING in the main directory of this source tree, or the
12  * OpenIB.org BSD license below:
13  *
14  *     Redistribution and use in source and binary forms, with or
15  *     without modification, are permitted provided that the following
16  *     conditions are met:
17  *
18  *      - Redistributions of source code must retain the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer.
21  *
22  *      - Redistributions in binary form must reproduce the above
23  *        copyright notice, this list of conditions and the following
24  *        disclaimer in the documentation and/or other materials
25  *        provided with the distribution.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34  * SOFTWARE.
35  *
36  * $Id: smi.c 1389 2004-12-27 22:56:47Z roland $
37  */
38 
39 #include <ib_smi.h>
40 #include "smi.h"
41 
42 /*
43  * Fixup a directed route SMP for sending
44  * Return 0 if the SMP should be discarded
45  */
46 int smi_handle_dr_smp_send(struct ib_smp *smp,
47 			   u8 node_type,
48 			   int port_num)
49 {
50 	u8 hop_ptr, hop_cnt;
51 
52 	hop_ptr = smp->hop_ptr;
53 	hop_cnt = smp->hop_cnt;
54 
55 	/* See section 14.2.2.2, Vol 1 IB spec */
56 	if (!ib_get_smp_direction(smp)) {
57 		/* C14-9:1 */
58 		if (hop_cnt && hop_ptr == 0) {
59 			smp->hop_ptr++;
60 			return (smp->initial_path[smp->hop_ptr] ==
61 				port_num);
62 		}
63 
64 		/* C14-9:2 */
65 		if (hop_ptr && hop_ptr < hop_cnt) {
66 			if (node_type != IB_NODE_SWITCH)
67 				return 0;
68 
69 			/* smp->return_path set when received */
70 			smp->hop_ptr++;
71 			return (smp->initial_path[smp->hop_ptr] ==
72 				port_num);
73 		}
74 
75 		/* C14-9:3 -- We're at the end of the DR segment of path */
76 		if (hop_ptr == hop_cnt) {
77 			/* smp->return_path set when received */
78 			smp->hop_ptr++;
79 			return (node_type == IB_NODE_SWITCH ||
80 				smp->dr_dlid == IB_LID_PERMISSIVE);
81 		}
82 
83 		/* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
84 		/* C14-9:5 -- Fail unreasonable hop pointer */
85 		return (hop_ptr == hop_cnt + 1);
86 
87 	} else {
88 		/* C14-13:1 */
89 		if (hop_cnt && hop_ptr == hop_cnt + 1) {
90 			smp->hop_ptr--;
91 			return (smp->return_path[smp->hop_ptr] ==
92 				port_num);
93 		}
94 
95 		/* C14-13:2 */
96 		if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
97 			if (node_type != IB_NODE_SWITCH)
98 				return 0;
99 
100 			smp->hop_ptr--;
101 			return (smp->return_path[smp->hop_ptr] ==
102 				port_num);
103 		}
104 
105 		/* C14-13:3 -- at the end of the DR segment of path */
106 		if (hop_ptr == 1) {
107 			smp->hop_ptr--;
108 			/* C14-13:3 -- SMPs destined for SM shouldn't be here */
109 			return (node_type == IB_NODE_SWITCH ||
110 				smp->dr_slid == IB_LID_PERMISSIVE);
111 		}
112 
113 		/* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */
114 		if (hop_ptr == 0)
115 			return 1;
116 
117 		/* C14-13:5 -- Check for unreasonable hop pointer */
118 		return 0;
119 	}
120 }
121 
122 /*
123  * Adjust information for a received SMP
124  * Return 0 if the SMP should be dropped
125  */
126 int smi_handle_dr_smp_recv(struct ib_smp *smp,
127 			   u8 node_type,
128 			   int port_num,
129 			   int phys_port_cnt)
130 {
131 	u8 hop_ptr, hop_cnt;
132 
133 	hop_ptr = smp->hop_ptr;
134 	hop_cnt = smp->hop_cnt;
135 
136 	/* See section 14.2.2.2, Vol 1 IB spec */
137 	if (!ib_get_smp_direction(smp)) {
138 		/* C14-9:1 -- sender should have incremented hop_ptr */
139 		if (hop_cnt && hop_ptr == 0)
140 			return 0;
141 
142 		/* C14-9:2 -- intermediate hop */
143 		if (hop_ptr && hop_ptr < hop_cnt) {
144 			if (node_type != IB_NODE_SWITCH)
145 				return 0;
146 
147 			smp->return_path[hop_ptr] = port_num;
148 			/* smp->hop_ptr updated when sending */
149 			return (smp->initial_path[hop_ptr+1] <= phys_port_cnt);
150 		}
151 
152 		/* C14-9:3 -- We're at the end of the DR segment of path */
153 		if (hop_ptr == hop_cnt) {
154 			if (hop_cnt)
155 				smp->return_path[hop_ptr] = port_num;
156 			/* smp->hop_ptr updated when sending */
157 
158 			return (node_type == IB_NODE_SWITCH ||
159 				smp->dr_dlid == IB_LID_PERMISSIVE);
160 		}
161 
162 		/* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
163 		/* C14-9:5 -- fail unreasonable hop pointer */
164 		return (hop_ptr == hop_cnt + 1);
165 
166 	} else {
167 
168 		/* C14-13:1 */
169 		if (hop_cnt && hop_ptr == hop_cnt + 1) {
170 			smp->hop_ptr--;
171 			return (smp->return_path[smp->hop_ptr] ==
172 				port_num);
173 		}
174 
175 		/* C14-13:2 */
176 		if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
177 			if (node_type != IB_NODE_SWITCH)
178 				return 0;
179 
180 			/* smp->hop_ptr updated when sending */
181 			return (smp->return_path[hop_ptr-1] <= phys_port_cnt);
182 		}
183 
184 		/* C14-13:3 -- We're at the end of the DR segment of path */
185 		if (hop_ptr == 1) {
186 			if (smp->dr_slid == IB_LID_PERMISSIVE) {
187 				/* giving SMP to SM - update hop_ptr */
188 				smp->hop_ptr--;
189 				return 1;
190 			}
191 			/* smp->hop_ptr updated when sending */
192 			return (node_type == IB_NODE_SWITCH);
193 		}
194 
195 		/* C14-13:4 -- hop_ptr = 0 -> give to SM */
196 		/* C14-13:5 -- Check for unreasonable hop pointer */
197 		return (hop_ptr == 0);
198 	}
199 }
200 
201 /*
202  * Return 1 if the received DR SMP should be forwarded to the send queue
203  * Return 0 if the SMP should be completed up the stack
204  */
205 int smi_check_forward_dr_smp(struct ib_smp *smp)
206 {
207 	u8 hop_ptr, hop_cnt;
208 
209 	hop_ptr = smp->hop_ptr;
210 	hop_cnt = smp->hop_cnt;
211 
212 	if (!ib_get_smp_direction(smp)) {
213 		/* C14-9:2 -- intermediate hop */
214 		if (hop_ptr && hop_ptr < hop_cnt)
215 			return 1;
216 
217 		/* C14-9:3 -- at the end of the DR segment of path */
218 		if (hop_ptr == hop_cnt)
219 			return (smp->dr_dlid == IB_LID_PERMISSIVE);
220 
221 		/* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */
222 		if (hop_ptr == hop_cnt + 1)
223 			return 1;
224 	} else {
225 		/* C14-13:2 */
226 		if (2 <= hop_ptr && hop_ptr <= hop_cnt)
227 			return 1;
228 
229 		/* C14-13:3 -- at the end of the DR segment of path */
230 		if (hop_ptr == 1)
231 			return (smp->dr_slid != IB_LID_PERMISSIVE);
232 	}
233 	return 0;
234 }
235