Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / drivers / infiniband / core / smi.c
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 }