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