1 /*
2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2015 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_file_ids.h>
50 #define FILE_ID OSM_FILE_NODE_C
51 #include <opensm/osm_node.h>
52 #include <opensm/osm_madw.h>
53
osm_node_init_physp(IN osm_node_t * p_node,uint8_t port_num,IN const osm_madw_t * p_madw)54 void osm_node_init_physp(IN osm_node_t * p_node, uint8_t port_num,
55 IN const osm_madw_t * p_madw)
56 {
57 ib_net64_t port_guid;
58 ib_smp_t *p_smp;
59 ib_node_info_t *p_ni;
60
61 p_smp = osm_madw_get_smp_ptr(p_madw);
62
63 p_ni = ib_smp_get_payload_ptr(p_smp);
64 port_guid = p_ni->port_guid;
65
66 CL_ASSERT(port_num < p_node->physp_tbl_size);
67
68 osm_physp_init(&p_node->physp_table[port_num],
69 port_guid, port_num, p_node,
70 osm_madw_get_bind_handle(p_madw),
71 p_smp->hop_count, p_smp->initial_path);
72 }
73
osm_node_new(IN const osm_madw_t * p_madw)74 osm_node_t *osm_node_new(IN const osm_madw_t * p_madw)
75 {
76 osm_node_t *p_node;
77 ib_smp_t *p_smp;
78 ib_node_info_t *p_ni;
79 uint8_t i;
80 uint32_t size;
81
82 p_smp = osm_madw_get_smp_ptr(p_madw);
83 p_ni = ib_smp_get_payload_ptr(p_smp);
84
85 /*
86 The node object already contains one physical port object.
87 Therefore, subtract 1 from the number of physical ports
88 used by the switch. This is not done for CA's since they
89 need to occupy 1 more physp than they physically have since
90 we still reserve room for a "port 0".
91 */
92 size = p_ni->num_ports;
93
94 p_node = malloc(sizeof(*p_node) + sizeof(osm_physp_t) * size);
95 if (!p_node)
96 return NULL;
97
98 memset(p_node, 0, sizeof(*p_node) + sizeof(osm_physp_t) * size);
99 p_node->node_info = *p_ni;
100 p_node->physp_tbl_size = size + 1;
101
102 p_node->physp_discovered = malloc(sizeof(uint8_t) * p_node->physp_tbl_size);
103 if (!p_node->physp_discovered) {
104 free(p_node);
105 return NULL;
106 }
107 memset(p_node->physp_discovered, 0, sizeof(uint8_t) * p_node->physp_tbl_size);
108 /*
109 Construct Physical Port objects owned by this Node.
110 Then, initialize the Physical Port through with we
111 discovered this port.
112 For switches, all ports have the same GUID.
113 For CAs and routers, each port has a different GUID, so we only
114 know the GUID for the port that responded to our
115 Get(NodeInfo).
116 */
117 for (i = 0; i < p_node->physp_tbl_size; i++)
118 osm_physp_construct(&p_node->physp_table[i]);
119
120 if (p_ni->node_type == IB_NODE_TYPE_SWITCH)
121 for (i = 0; i <= p_ni->num_ports; i++)
122 osm_node_init_physp(p_node, i, p_madw);
123 else
124 osm_node_init_physp(p_node,
125 ib_node_info_get_local_port_num(p_ni),
126 p_madw);
127 p_node->print_desc = strdup(OSM_NODE_DESC_UNKNOWN);
128
129 return p_node;
130 }
131
node_destroy(IN osm_node_t * p_node)132 static void node_destroy(IN osm_node_t * p_node)
133 {
134 uint16_t i;
135
136 /*
137 Cleanup all physports
138 */
139 for (i = 0; i < p_node->physp_tbl_size; i++)
140 osm_physp_destroy(&p_node->physp_table[i]);
141
142 /* cleanup printable node_desc field */
143 if (p_node->print_desc)
144 free(p_node->print_desc);
145
146 /* cleanup physp_discovered array */
147 free(p_node->physp_discovered);
148 }
149
osm_node_delete(IN OUT osm_node_t ** p_node)150 void osm_node_delete(IN OUT osm_node_t ** p_node)
151 {
152 CL_ASSERT(p_node && *p_node);
153 node_destroy(*p_node);
154 free(*p_node);
155 *p_node = NULL;
156 }
157
osm_node_link(IN osm_node_t * p_node,IN uint8_t port_num,IN osm_node_t * p_remote_node,IN uint8_t remote_port_num)158 void osm_node_link(IN osm_node_t * p_node, IN uint8_t port_num,
159 IN osm_node_t * p_remote_node, IN uint8_t remote_port_num)
160 {
161 osm_physp_t *p_physp;
162 osm_physp_t *p_remote_physp;
163
164 p_physp = osm_node_get_physp_ptr(p_node, port_num);
165 p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
166
167 if (p_physp->p_remote_physp)
168 p_physp->p_remote_physp->p_remote_physp = NULL;
169 if (p_remote_physp->p_remote_physp)
170 p_remote_physp->p_remote_physp->p_remote_physp = NULL;
171
172 osm_physp_link(p_physp, p_remote_physp);
173 }
174
osm_node_unlink(IN osm_node_t * p_node,IN uint8_t port_num,IN osm_node_t * p_remote_node,IN uint8_t remote_port_num)175 void osm_node_unlink(IN osm_node_t * p_node, IN uint8_t port_num,
176 IN osm_node_t * p_remote_node, IN uint8_t remote_port_num)
177 {
178 osm_physp_t *p_physp;
179 osm_physp_t *p_remote_physp;
180
181 CL_ASSERT(port_num < p_node->physp_tbl_size);
182 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
183
184 if (osm_node_link_exists(p_node, port_num,
185 p_remote_node, remote_port_num)) {
186
187 p_physp = osm_node_get_physp_ptr(p_node, port_num);
188 p_remote_physp =
189 osm_node_get_physp_ptr(p_remote_node, remote_port_num);
190
191 osm_physp_unlink(p_physp, p_remote_physp);
192 }
193 }
194
osm_node_link_exists(IN osm_node_t * p_node,IN uint8_t port_num,IN osm_node_t * p_remote_node,IN uint8_t remote_port_num)195 boolean_t osm_node_link_exists(IN osm_node_t * p_node, IN uint8_t port_num,
196 IN osm_node_t * p_remote_node,
197 IN uint8_t remote_port_num)
198 {
199 osm_physp_t *p_physp;
200 osm_physp_t *p_remote_physp;
201
202 CL_ASSERT(port_num < p_node->physp_tbl_size);
203 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
204
205 p_physp = osm_node_get_physp_ptr(p_node, port_num);
206 p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
207
208 return osm_physp_link_exists(p_physp, p_remote_physp);
209 }
210
osm_node_link_has_valid_ports(IN osm_node_t * p_node,IN uint8_t port_num,IN osm_node_t * p_remote_node,IN uint8_t remote_port_num)211 boolean_t osm_node_link_has_valid_ports(IN osm_node_t * p_node,
212 IN uint8_t port_num,
213 IN osm_node_t * p_remote_node,
214 IN uint8_t remote_port_num)
215 {
216 osm_physp_t *p_physp;
217 osm_physp_t *p_remote_physp;
218
219 CL_ASSERT(port_num < p_node->physp_tbl_size);
220 CL_ASSERT(remote_port_num < p_remote_node->physp_tbl_size);
221
222 p_physp = osm_node_get_physp_ptr(p_node, port_num);
223 p_remote_physp = osm_node_get_physp_ptr(p_remote_node, remote_port_num);
224
225 return (p_physp && p_remote_physp);
226 }
227
osm_node_has_any_link(IN osm_node_t * p_node,IN uint8_t port_num)228 boolean_t osm_node_has_any_link(IN osm_node_t * p_node, IN uint8_t port_num)
229 {
230 osm_physp_t *p_physp;
231 CL_ASSERT(port_num < p_node->physp_tbl_size);
232 p_physp = osm_node_get_physp_ptr(p_node, port_num);
233 return osm_physp_has_any_link(p_physp);
234 }
235
osm_node_get_remote_node(IN osm_node_t * p_node,IN uint8_t port_num,OUT uint8_t * p_remote_port_num)236 osm_node_t *osm_node_get_remote_node(IN osm_node_t * p_node,
237 IN uint8_t port_num,
238 OUT uint8_t * p_remote_port_num)
239 {
240 osm_physp_t *p_physp;
241 osm_physp_t *p_remote_physp;
242
243 p_physp = osm_node_get_physp_ptr(p_node, port_num);
244
245 if (!p_physp || !osm_physp_has_any_link(p_physp))
246 return NULL;
247
248 p_remote_physp = osm_physp_get_remote(p_physp);
249 if (p_remote_port_num)
250 *p_remote_port_num = osm_physp_get_port_num(p_remote_physp);
251
252 return osm_physp_get_node_ptr(p_remote_physp);
253 }
254
255 /**********************************************************************
256 The lock must be held before calling this function.
257 **********************************************************************/
osm_node_get_remote_base_lid(IN osm_node_t * p_node,IN uint32_t port_num)258 ib_net16_t osm_node_get_remote_base_lid(IN osm_node_t * p_node,
259 IN uint32_t port_num)
260 {
261 osm_physp_t *p_physp;
262 osm_physp_t *p_remote_physp;
263 CL_ASSERT(port_num < p_node->physp_tbl_size);
264
265 p_physp = osm_node_get_physp_ptr(p_node, port_num);
266 if (p_physp) {
267 p_remote_physp = osm_physp_get_remote(p_physp);
268 return osm_physp_get_base_lid(p_remote_physp);
269 }
270
271 return 0;
272 }
273