1 /*
2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 *
34 */
35
36 /*
37 * Abstract:
38 * Implementation of osm_node_t.
39 * This object represents an Infiniband Node.
40 * This object is part of the opensm family of objects.
41 */
42
43 #if HAVE_CONFIG_H
44 # include <config.h>
45 #endif /* HAVE_CONFIG_H */
46
47 #include <stdlib.h>
48 #include <iba/ib_types.h>
49 #include <opensm/osm_node.h>
50 #include <opensm/osm_madw.h>
51
52 /**********************************************************************
53 **********************************************************************/
54 void
osm_node_init_physp(IN osm_node_t * const p_node,IN const osm_madw_t * const p_madw)55 osm_node_init_physp(IN osm_node_t * const p_node,
56 IN const osm_madw_t * const p_madw)
57 {
58 ib_net64_t port_guid;
59 ib_smp_t *p_smp;
60 ib_node_info_t *p_ni;
61 uint8_t port_num;
62
63 p_smp = osm_madw_get_smp_ptr(p_madw);
64
65 p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp);
66 port_guid = p_ni->port_guid;
67 port_num = ib_node_info_get_local_port_num(p_ni);
68
69 CL_ASSERT(port_num < p_node->physp_tbl_size);
70
71 osm_physp_init(&p_node->physp_table[port_num],
72 port_guid, port_num, p_node,
73 osm_madw_get_bind_handle(p_madw),
74 p_smp->hop_count, p_smp->initial_path);
75 }
76
77 /**********************************************************************
78 **********************************************************************/
node_init_physp0(IN osm_node_t * const p_node,IN const osm_madw_t * const p_madw)79 static void node_init_physp0(IN osm_node_t * const p_node,
80 IN const osm_madw_t * const p_madw)
81 {
82 ib_smp_t *p_smp;
83 ib_node_info_t *p_ni;
84
85 p_smp = osm_madw_get_smp_ptr(p_madw);
86 p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp);
87
88 osm_physp_init(&p_node->physp_table[0],
89 p_ni->port_guid, 0, p_node,
90 osm_madw_get_bind_handle(p_madw),
91 p_smp->hop_count, p_smp->initial_path);
92 }
93
94 /**********************************************************************
95 **********************************************************************/
osm_node_new(IN const osm_madw_t * const p_madw)96 osm_node_t *osm_node_new(IN const osm_madw_t * const p_madw)
97 {
98 osm_node_t *p_node;
99 ib_smp_t *p_smp;
100 ib_node_info_t *p_ni;
101 uint8_t i;
102 uint32_t size;
103
104 p_smp = osm_madw_get_smp_ptr(p_madw);
105 p_ni = (ib_node_info_t *) ib_smp_get_payload_ptr(p_smp);
106
107 /*
108 The node object already contains one physical port object.
109 Therefore, subtract 1 from the number of physical ports
110 used by the switch. This is not done for CA's since they
111 need to occupy 1 more physp than they physically have since
112 we still reserve room for a "port 0".
113 */
114 size = p_ni->num_ports;
115
116 p_node = malloc(sizeof(*p_node) + sizeof(osm_physp_t) * size);
117 if (!p_node)
118 return NULL;
119
120 memset(p_node, 0, sizeof(*p_node) + sizeof(osm_physp_t) * size);
121 p_node->node_info = *p_ni;
122 p_node->physp_tbl_size = size + 1;
123
124 /*
125 Construct Physical Port objects owned by this Node.
126 Then, initialize the Physical Port through with we
127 discovered this port.
128 For switches, all ports have the same GUID.
129 For CAs and routers, each port has a different GUID, so we only
130 know the GUID for the port that responded to our
131 Get(NodeInfo).
132 */
133 for (i = 0; i < p_node->physp_tbl_size; i++)
134 osm_physp_construct(&p_node->physp_table[i]);
135
136 osm_node_init_physp(p_node, p_madw);
137 if (p_ni->node_type == IB_NODE_TYPE_SWITCH)
138 node_init_physp0(p_node, p_madw);
139 p_node->print_desc = strdup(OSM_NODE_DESC_UNKNOWN);
140
141 return (p_node);
142 }
143
144 /**********************************************************************
145 **********************************************************************/
osm_node_destroy(IN osm_node_t * p_node)146 static void osm_node_destroy(IN osm_node_t * p_node)
147 {
148 uint16_t i;
149
150 /*
151 Cleanup all physports
152 */
153 for (i = 0; i < p_node->physp_tbl_size; i++)
154 osm_physp_destroy(&p_node->physp_table[i]);
155
156 /* cleanup printable node_desc field */
157 if (p_node->print_desc) {
158 free(p_node->print_desc);
159 }
160 }
161
162 /**********************************************************************
163 **********************************************************************/
osm_node_delete(IN OUT osm_node_t ** const p_node)164 void osm_node_delete(IN OUT osm_node_t ** const p_node)
165 {
166 CL_ASSERT(p_node && *p_node);
167 osm_node_destroy(*p_node);
168 free(*p_node);
169 *p_node = NULL;
170 }
171
172 /**********************************************************************
173 **********************************************************************/
174 void
osm_node_link(IN osm_node_t * const p_node,IN const uint8_t port_num,IN osm_node_t * const p_remote_node,IN const uint8_t remote_port_num)175 osm_node_link(IN osm_node_t * const p_node,
176 IN const uint8_t port_num,
177 IN osm_node_t * const p_remote_node,
178 IN const uint8_t remote_port_num)
179 {
180 osm_physp_t *p_physp;
181 osm_physp_t *p_remote_physp;
182
183 CL_ASSERT(port_num < p_node->physp_tbl_size);
184 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
185
186 p_physp = osm_node_get_physp_ptr(p_node, port_num);
187 p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
188
189 if (p_physp->p_remote_physp)
190 p_physp->p_remote_physp->p_remote_physp = NULL;
191 if (p_remote_physp->p_remote_physp)
192 p_remote_physp->p_remote_physp->p_remote_physp = NULL;
193
194 osm_physp_link(p_physp, p_remote_physp);
195 }
196
197 /**********************************************************************
198 **********************************************************************/
199 void
osm_node_unlink(IN osm_node_t * const p_node,IN const uint8_t port_num,IN osm_node_t * const p_remote_node,IN const uint8_t remote_port_num)200 osm_node_unlink(IN osm_node_t * const p_node,
201 IN const uint8_t port_num,
202 IN osm_node_t * const p_remote_node,
203 IN const uint8_t remote_port_num)
204 {
205 osm_physp_t *p_physp;
206 osm_physp_t *p_remote_physp;
207
208 CL_ASSERT(port_num < p_node->physp_tbl_size);
209 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
210
211 if (osm_node_link_exists(p_node, port_num,
212 p_remote_node, remote_port_num)) {
213
214 p_physp = osm_node_get_physp_ptr(p_node, port_num);
215 p_remote_physp =
216 osm_node_get_physp_ptr(p_remote_node, remote_port_num);
217
218 osm_physp_unlink(p_physp, p_remote_physp);
219 }
220 }
221
222 /**********************************************************************
223 **********************************************************************/
224 boolean_t
osm_node_link_exists(IN osm_node_t * const p_node,IN const uint8_t port_num,IN osm_node_t * const p_remote_node,IN const uint8_t remote_port_num)225 osm_node_link_exists(IN osm_node_t * const p_node,
226 IN const uint8_t port_num,
227 IN osm_node_t * const p_remote_node,
228 IN const uint8_t remote_port_num)
229 {
230 osm_physp_t *p_physp;
231 osm_physp_t *p_remote_physp;
232
233 CL_ASSERT(port_num < p_node->physp_tbl_size);
234 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
235
236 p_physp = osm_node_get_physp_ptr(p_node, port_num);
237 p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
238
239 return (osm_physp_link_exists(p_physp, p_remote_physp));
240 }
241
242 /**********************************************************************
243 **********************************************************************/
244 boolean_t
osm_node_link_has_valid_ports(IN osm_node_t * const p_node,IN const uint8_t port_num,IN osm_node_t * const p_remote_node,IN const uint8_t remote_port_num)245 osm_node_link_has_valid_ports(IN osm_node_t * const p_node,
246 IN const uint8_t port_num,
247 IN osm_node_t * const p_remote_node,
248 IN const uint8_t remote_port_num)
249 {
250 osm_physp_t *p_physp;
251 osm_physp_t *p_remote_physp;
252
253 CL_ASSERT(port_num < p_node->physp_tbl_size);
254 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
255
256 p_physp = osm_node_get_physp_ptr(p_node, port_num);
257 p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
258
259 return (p_physp && p_remote_physp);
260 }
261
262 /**********************************************************************
263 **********************************************************************/
264 boolean_t
osm_node_has_any_link(IN osm_node_t * const p_node,IN const uint8_t port_num)265 osm_node_has_any_link(IN osm_node_t * const p_node, IN const uint8_t port_num)
266 {
267 osm_physp_t *p_physp;
268 CL_ASSERT(port_num < p_node->physp_tbl_size);
269 p_physp = osm_node_get_physp_ptr(p_node, port_num);
270 return (osm_physp_has_any_link(p_physp));
271 }
272
273 /**********************************************************************
274 **********************************************************************/
osm_node_get_remote_node(IN osm_node_t * const p_node,IN const uint8_t port_num,OUT uint8_t * p_remote_port_num)275 osm_node_t *osm_node_get_remote_node(IN osm_node_t * const p_node,
276 IN const uint8_t port_num,
277 OUT uint8_t * p_remote_port_num)
278 {
279 osm_physp_t *p_physp;
280 osm_physp_t *p_remote_physp;
281
282 p_physp = osm_node_get_physp_ptr(p_node, port_num);
283
284 if (!p_physp || !osm_physp_has_any_link(p_physp))
285 return (NULL);
286
287 p_remote_physp = osm_physp_get_remote(p_physp);
288 if (p_remote_port_num)
289 *p_remote_port_num = osm_physp_get_port_num(p_remote_physp);
290
291 return (osm_physp_get_node_ptr(p_remote_physp));
292 }
293
294 /**********************************************************************
295 The lock must be held before calling this function.
296 **********************************************************************/
297 ib_net16_t
osm_node_get_remote_base_lid(IN osm_node_t * const p_node,IN const uint32_t port_num)298 osm_node_get_remote_base_lid(IN osm_node_t * const p_node,
299 IN const uint32_t port_num)
300 {
301 osm_physp_t *p_physp;
302 osm_physp_t *p_remote_physp;
303 CL_ASSERT(port_num < p_node->physp_tbl_size);
304
305 p_physp = osm_node_get_physp_ptr(p_node, port_num);
306 if (p_physp) {
307 p_remote_physp = osm_physp_get_remote(p_physp);
308 return (osm_physp_get_base_lid(p_remote_physp));
309 }
310
311 return (0);
312 }
313