]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ofed/management/opensm/opensm/osm_sa_guidinfo_record.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ofed / management / opensm / opensm / osm_sa_guidinfo_record.c
1 /*
2  * Copyright (c) 2006-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_gir_rcv_t.
39  * This object represents the GUIDInfoRecord Receiver object.
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 <string.h>
48 #include <iba/ib_types.h>
49 #include <complib/cl_qmap.h>
50 #include <complib/cl_passivelock.h>
51 #include <complib/cl_debug.h>
52 #include <complib/cl_qlist.h>
53 #include <vendor/osm_vendor_api.h>
54 #include <opensm/osm_port.h>
55 #include <opensm/osm_node.h>
56 #include <opensm/osm_helper.h>
57 #include <opensm/osm_pkey.h>
58 #include <opensm/osm_sa.h>
59
60 typedef struct osm_gir_item {
61         cl_list_item_t list_item;
62         ib_guidinfo_record_t rec;
63 } osm_gir_item_t;
64
65 typedef struct osm_gir_search_ctxt {
66         const ib_guidinfo_record_t *p_rcvd_rec;
67         ib_net64_t comp_mask;
68         cl_qlist_t *p_list;
69         osm_sa_t *sa;
70         const osm_physp_t *p_req_physp;
71 } osm_gir_search_ctxt_t;
72
73 /**********************************************************************
74  **********************************************************************/
75 static ib_api_status_t
76 __osm_gir_rcv_new_gir(IN osm_sa_t * sa,
77                       IN const osm_node_t * const p_node,
78                       IN cl_qlist_t * const p_list,
79                       IN ib_net64_t const match_port_guid,
80                       IN ib_net16_t const match_lid,
81                       IN const osm_physp_t * const p_req_physp,
82                       IN uint8_t const block_num)
83 {
84         osm_gir_item_t *p_rec_item;
85         ib_api_status_t status = IB_SUCCESS;
86
87         OSM_LOG_ENTER(sa->p_log);
88
89         p_rec_item = malloc(sizeof(*p_rec_item));
90         if (p_rec_item == NULL) {
91                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5102: "
92                         "rec_item alloc failed\n");
93                 status = IB_INSUFFICIENT_RESOURCES;
94                 goto Exit;
95         }
96
97         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
98                 "New GUIDInfoRecord: lid %u, block num %d\n",
99                 cl_ntoh16(match_lid), block_num);
100
101         memset(p_rec_item, 0, sizeof(*p_rec_item));
102
103         p_rec_item->rec.lid = match_lid;
104         p_rec_item->rec.block_num = block_num;
105         if (!block_num)
106                 p_rec_item->rec.guid_info.guid[0] =
107                     osm_physp_get_port_guid(p_req_physp);
108
109         cl_qlist_insert_tail(p_list, &p_rec_item->list_item);
110
111 Exit:
112         OSM_LOG_EXIT(sa->p_log);
113         return (status);
114 }
115
116 /**********************************************************************
117  **********************************************************************/
118 static void
119 __osm_sa_gir_create_gir(IN osm_sa_t * sa,
120                         IN osm_node_t * const p_node,
121                         IN cl_qlist_t * const p_list,
122                         IN ib_net64_t const match_port_guid,
123                         IN ib_net16_t const match_lid,
124                         IN const osm_physp_t * const p_req_physp,
125                         IN uint8_t const match_block_num)
126 {
127         const osm_physp_t *p_physp;
128         uint8_t port_num;
129         uint8_t num_ports;
130         uint16_t match_lid_ho;
131         ib_net16_t base_lid_ho;
132         ib_net16_t max_lid_ho;
133         uint8_t lmc;
134         ib_net64_t port_guid;
135         uint8_t block_num, start_block_num, end_block_num, num_blocks;
136
137         OSM_LOG_ENTER(sa->p_log);
138
139         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
140                 "Looking for GUIDRecord with LID: %u GUID:0x%016"
141                 PRIx64 "\n", cl_ntoh16(match_lid), cl_ntoh64(match_port_guid));
142
143         /*
144            For switches, do not return the GUIDInfo record(s)
145            for each port on the switch, just for port 0.
146          */
147         if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH)
148                 num_ports = 1;
149         else
150                 num_ports = osm_node_get_num_physp(p_node);
151
152         for (port_num = 0; port_num < num_ports; port_num++) {
153                 p_physp = osm_node_get_physp_ptr(p_node, port_num);
154                 if (!p_physp)
155                         continue;
156
157                 /* Check to see if the found p_physp and the requester physp
158                    share a pkey. If not, continue */
159                 if (!osm_physp_share_pkey(sa->p_log, p_physp, p_req_physp))
160                         continue;
161
162                 port_guid = osm_physp_get_port_guid(p_physp);
163
164                 if (match_port_guid && (port_guid != match_port_guid))
165                         continue;
166
167                 /*
168                    Note: the following check is a temporary workaround
169                    Since 1. GUIDCap should never be 0 on ports where this applies
170                    and   2. GUIDCap should not be used on ports where it doesn't apply
171                    So this should really be a check for whether the port is a
172                    switch external port or not!
173                  */
174                 if (p_physp->port_info.guid_cap == 0)
175                         continue;
176
177                 num_blocks = p_physp->port_info.guid_cap / 8;
178                 if (p_physp->port_info.guid_cap % 8)
179                         num_blocks++;
180                 if (match_block_num == 255) {
181                         start_block_num = 0;
182                         end_block_num = num_blocks - 1;
183                 } else {
184                         if (match_block_num >= num_blocks)
185                                 continue;
186                         end_block_num = start_block_num = match_block_num;
187                 }
188
189                 base_lid_ho = cl_ntoh16(osm_physp_get_base_lid(p_physp));
190                 match_lid_ho = cl_ntoh16(match_lid);
191                 if (match_lid_ho) {
192                         lmc = osm_physp_get_lmc(p_physp);
193                         max_lid_ho = (uint16_t) (base_lid_ho + (1 << lmc) - 1);
194
195                         /*
196                            We validate that the lid belongs to this node.
197                          */
198                         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
199                                 "Comparing LID: %u <= %u <= %u\n",
200                                 base_lid_ho, match_lid_ho, max_lid_ho);
201
202                         if (match_lid_ho < base_lid_ho
203                             || match_lid_ho > max_lid_ho)
204                                 continue;
205                 }
206
207                 for (block_num = start_block_num; block_num <= end_block_num;
208                      block_num++)
209                         __osm_gir_rcv_new_gir(sa, p_node, p_list, port_guid,
210                                               cl_ntoh16(base_lid_ho), p_physp,
211                                               block_num);
212
213         }
214
215         OSM_LOG_EXIT(sa->p_log);
216 }
217
218 /**********************************************************************
219  **********************************************************************/
220 static void
221 __osm_sa_gir_by_comp_mask_cb(IN cl_map_item_t * const p_map_item,
222                              IN void *context)
223 {
224         const osm_gir_search_ctxt_t *const p_ctxt =
225             (osm_gir_search_ctxt_t *) context;
226         osm_node_t *const p_node = (osm_node_t *) p_map_item;
227         const ib_guidinfo_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec;
228         const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp;
229         osm_sa_t *sa = p_ctxt->sa;
230         const ib_guid_info_t *p_comp_gi;
231         ib_net64_t const comp_mask = p_ctxt->comp_mask;
232         ib_net64_t match_port_guid = 0;
233         ib_net16_t match_lid = 0;
234         uint8_t match_block_num = 255;
235
236         OSM_LOG_ENTER(p_ctxt->sa->p_log);
237
238         if (comp_mask & IB_GIR_COMPMASK_LID)
239                 match_lid = p_rcvd_rec->lid;
240
241         if (comp_mask & IB_GIR_COMPMASK_BLOCKNUM)
242                 match_block_num = p_rcvd_rec->block_num;
243
244         p_comp_gi = &p_rcvd_rec->guid_info;
245         /* Different rule for block 0 v. other blocks */
246         if (comp_mask & IB_GIR_COMPMASK_GID0) {
247                 if (!p_rcvd_rec->block_num)
248                         match_port_guid = osm_physp_get_port_guid(p_req_physp);
249                 if (p_comp_gi->guid[0] != match_port_guid)
250                         goto Exit;
251         }
252
253         if (comp_mask & IB_GIR_COMPMASK_GID1) {
254                 if (p_comp_gi->guid[1] != 0)
255                         goto Exit;
256         }
257
258         if (comp_mask & IB_GIR_COMPMASK_GID2) {
259                 if (p_comp_gi->guid[2] != 0)
260                         goto Exit;
261         }
262
263         if (comp_mask & IB_GIR_COMPMASK_GID3) {
264                 if (p_comp_gi->guid[3] != 0)
265                         goto Exit;
266         }
267
268         if (comp_mask & IB_GIR_COMPMASK_GID4) {
269                 if (p_comp_gi->guid[4] != 0)
270                         goto Exit;
271         }
272
273         if (comp_mask & IB_GIR_COMPMASK_GID5) {
274                 if (p_comp_gi->guid[5] != 0)
275                         goto Exit;
276         }
277
278         if (comp_mask & IB_GIR_COMPMASK_GID6) {
279                 if (p_comp_gi->guid[6] != 0)
280                         goto Exit;
281         }
282
283         if (comp_mask & IB_GIR_COMPMASK_GID7) {
284                 if (p_comp_gi->guid[7] != 0)
285                         goto Exit;
286         }
287
288         __osm_sa_gir_create_gir(sa, p_node, p_ctxt->p_list,
289                                 match_port_guid, match_lid, p_req_physp,
290                                 match_block_num);
291
292 Exit:
293         OSM_LOG_EXIT(p_ctxt->sa->p_log);
294 }
295
296 /**********************************************************************
297  **********************************************************************/
298 void osm_gir_rcv_process(IN void *ctx, IN void *data)
299 {
300         osm_sa_t *sa = ctx;
301         osm_madw_t *p_madw = data;
302         const ib_sa_mad_t *p_rcvd_mad;
303         const ib_guidinfo_record_t *p_rcvd_rec;
304         cl_qlist_t rec_list;
305         osm_gir_search_ctxt_t context;
306         osm_physp_t *p_req_physp;
307
308         CL_ASSERT(sa);
309
310         OSM_LOG_ENTER(sa->p_log);
311
312         CL_ASSERT(p_madw);
313
314         p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw);
315         p_rcvd_rec =
316             (ib_guidinfo_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad);
317
318         CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_GUIDINFO_RECORD);
319
320         /* we only support SubnAdmGet and SubnAdmGetTable methods */
321         if (p_rcvd_mad->method != IB_MAD_METHOD_GET &&
322             p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) {
323                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5105: "
324                         "Unsupported Method (%s)\n",
325                         ib_get_sa_method_str(p_rcvd_mad->method));
326                 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
327                 goto Exit;
328         }
329
330         /* update the requester physical port. */
331         p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
332                                                 osm_madw_get_mad_addr_ptr
333                                                 (p_madw));
334         if (p_req_physp == NULL) {
335                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 5104: "
336                         "Cannot find requester physical port\n");
337                 goto Exit;
338         }
339
340         if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG))
341                 osm_dump_guidinfo_record(sa->p_log, p_rcvd_rec, OSM_LOG_DEBUG);
342
343         cl_qlist_init(&rec_list);
344
345         context.p_rcvd_rec = p_rcvd_rec;
346         context.p_list = &rec_list;
347         context.comp_mask = p_rcvd_mad->comp_mask;
348         context.sa = sa;
349         context.p_req_physp = p_req_physp;
350
351         cl_plock_acquire(sa->p_lock);
352
353         cl_qmap_apply_func(&sa->p_subn->node_guid_tbl,
354                            __osm_sa_gir_by_comp_mask_cb, &context);
355
356         cl_plock_release(sa->p_lock);
357
358         osm_sa_respond(sa, p_madw, sizeof(ib_guidinfo_record_t), &rec_list);
359
360 Exit:
361         OSM_LOG_EXIT(sa->p_log);
362 }