Merge with /home/shaggy/git/linus-clean/
[linux-2.6] / drivers / infiniband / core / smi.c
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 }