]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / libvendor / osm_vendor_mlx_hca.c
1 /*
2  * Copyright (c) 2004-2006 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 #if HAVE_CONFIG_H
37 #  include <config.h>
38 #endif                          /* HAVE_CONFIG_H */
39
40 #include <stdlib.h>
41 #include <string.h>
42 #if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS)
43 #undef IN
44 #undef OUT
45 #include <vapi_types.h>
46 #include <evapi.h>
47 #include <vendor/osm_vendor_api.h>
48 #include <opensm/osm_log.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51
52 /********************************************************************************
53  *
54  * Provide the functionality for selecting an HCA Port and Obtaining it's guid.
55  *
56  ********************************************************************************/
57
58 typedef struct _osm_ca_info {
59         ib_net64_t guid;
60         size_t attr_size;
61         ib_ca_attr_t *p_attr;
62 } osm_ca_info_t;
63
64 /**********************************************************************
65  * Convert the given GID to GUID by copy of it's upper 8 bytes
66  **********************************************************************/
67 ib_api_status_t
68 __osm_vendor_gid_to_guid(IN u_int8_t * gid, OUT VAPI_gid_t * guid)
69 {
70         memcpy(guid, gid + 8, 8);
71         return (IB_SUCCESS);
72 }
73
74 /**********************************************************************
75  * Returns a pointer to the port attribute of the specified port
76  * owned by this CA.
77  ************************************************************************/
78 static ib_port_attr_t *__osm_ca_info_get_port_attr_ptr(IN const osm_ca_info_t *
79                                                        const p_ca_info,
80                                                        IN const uint8_t index)
81 {
82         return (&p_ca_info->p_attr->p_port_attr[index]);
83 }
84
85 /********************************************************************************
86  * get the CA names available on the system
87  * NOTE: user of this function needs to deallocate p_hca_ids after usage.
88  ********************************************************************************/
89 static ib_api_status_t
90 __osm_vendor_get_ca_ids(IN osm_vendor_t * const p_vend,
91                         IN VAPI_hca_id_t ** const p_hca_ids,
92                         IN uint32_t * const p_num_guids)
93 {
94         ib_api_status_t status;
95         VAPI_ret_t vapi_res;
96
97         OSM_LOG_ENTER(p_vend->p_log);
98
99         CL_ASSERT(p_hca_ids);
100         CL_ASSERT(p_num_guids);
101
102         /* first call is just to get the number */
103         vapi_res = EVAPI_list_hcas(0, p_num_guids, NULL);
104
105         /* fail ? */
106         if (vapi_res == VAPI_EINVAL_PARAM) {
107                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
108                         "__osm_vendor_get_ca_ids: ERR 3D08: : "
109                         "Bad parameter in calling: EVAPI_list_hcas. (%d)\n",
110                         vapi_res);
111                 status = IB_ERROR;
112                 goto Exit;
113         }
114
115         /* NO HCA ? */
116         if (*p_num_guids == 0) {
117                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
118                         "__osm_vendor_get_ca_ids: ERR 3D09: "
119                         "No available channel adapters.\n");
120                 status = IB_INSUFFICIENT_RESOURCES;
121                 goto Exit;
122         }
123
124         /* allocate and really call - user of this function needs to deallocate it */
125         *p_hca_ids =
126             (VAPI_hca_id_t *) malloc(*p_num_guids * sizeof(VAPI_hca_id_t));
127
128         /* now call it really */
129         vapi_res = EVAPI_list_hcas(*p_num_guids, p_num_guids, *p_hca_ids);
130
131         /* too many ? */
132         if (vapi_res == VAPI_EAGAIN) {
133                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
134                         "__osm_vendor_get_ca_ids: ERR 3D10: "
135                         "More CA GUIDs than allocated array (%d).\n",
136                         *p_num_guids);
137                 status = IB_ERROR;
138                 goto Exit;
139         }
140
141         /* fail ? */
142         if (vapi_res != VAPI_OK) {
143                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
144                         "__osm_vendor_get_ca_ids: ERR 3D11: : "
145                         "Bad parameter in calling: EVAPI_list_hcas.\n");
146                 status = IB_ERROR;
147                 goto Exit;
148         }
149
150         if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) {
151                 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
152                         "__osm_vendor_get_ca_ids: "
153                         "Detected %u local channel adapters.\n", *p_num_guids);
154         }
155
156         status = IB_SUCCESS;
157
158 Exit:
159         OSM_LOG_EXIT(p_vend->p_log);
160         return (status);
161 }
162
163 /**********************************************************************
164  * Initialize an Info Struct for the Given HCA by its Id
165  **********************************************************************/
166 static ib_api_status_t
167 __osm_ca_info_init(IN osm_vendor_t * const p_vend,
168                    IN VAPI_hca_id_t ca_id, OUT osm_ca_info_t * const p_ca_info)
169 {
170         ib_api_status_t status = IB_ERROR;
171         VAPI_ret_t vapi_res;
172         VAPI_hca_hndl_t hca_hndl;
173         VAPI_hca_vendor_t hca_vendor;
174         VAPI_hca_cap_t hca_cap;
175         VAPI_hca_port_t hca_port;
176         uint8_t port_num;
177         IB_gid_t *p_port_gid;
178         uint16_t maxNumGids;
179
180         OSM_LOG_ENTER(p_vend->p_log);
181
182         /* get the HCA handle */
183         vapi_res = EVAPI_get_hca_hndl(ca_id, &hca_hndl);
184         if (vapi_res != VAPI_OK) {
185                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
186                         "__osm_ca_info_init: ERR 3D05: "
187                         "Fail to get HCA handle (%u).\n", vapi_res);
188                 goto Exit;
189         }
190
191         if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) {
192                 osm_log(p_vend->p_log, OSM_LOG_DEBUG,
193                         "__osm_ca_info_init: " "Querying CA %s.\n", ca_id);
194         }
195
196         /* query and get the HCA capability */
197         vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap);
198         if (vapi_res != VAPI_OK) {
199                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
200                         "__osm_ca_info_init: ERR 3D06: "
201                         "Fail to get HCA Capabilities (%u).\n", vapi_res);
202                 goto Exit;
203         }
204
205         /* get the guid of the HCA */
206         memcpy(&(p_ca_info->guid), hca_cap.node_guid, 8 * sizeof(u_int8_t));
207         p_ca_info->attr_size = 1;
208         p_ca_info->p_attr = (ib_ca_attr_t *) malloc(sizeof(ib_ca_attr_t));
209         memcpy(&(p_ca_info->p_attr->ca_guid), hca_cap.node_guid,
210                8 * sizeof(u_int8_t));
211
212         /* now obtain the attributes of the ports */
213         p_ca_info->p_attr->num_ports = hca_cap.phys_port_num;
214         p_ca_info->p_attr->p_port_attr =
215             (ib_port_attr_t *) malloc(hca_cap.phys_port_num *
216                                       sizeof(ib_port_attr_t));
217
218         for (port_num = 0; port_num < p_ca_info->p_attr->num_ports; port_num++) {
219
220                 /* query the port attributes */
221                 vapi_res =
222                     VAPI_query_hca_port_prop(hca_hndl, port_num + 1, &hca_port);
223                 if (vapi_res != VAPI_OK) {
224                         osm_log(p_vend->p_log, OSM_LOG_ERROR,
225                                 "__osm_ca_info_init: ERR 3D07: "
226                                 "Fail to get HCA Port Attributes (%d).\n",
227                                 vapi_res);
228                         goto Exit;
229                 }
230
231                 /* first call to know the size of the gid table */
232                 vapi_res =
233                     VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, 0,
234                                            &maxNumGids, NULL);
235                 p_port_gid = (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t));
236
237                 vapi_res =
238                     VAPI_query_hca_gid_tbl(hca_hndl, port_num + 1, maxNumGids,
239                                            &maxNumGids, p_port_gid);
240                 if (vapi_res != VAPI_OK) {
241                         osm_log(p_vend->p_log, OSM_LOG_ERROR,
242                                 "__osm_ca_info_init: ERR 3D12: "
243                                 "Fail to get HCA Port GID (%d).\n", vapi_res);
244                         goto Exit;
245                 }
246
247                 __osm_vendor_gid_to_guid(p_port_gid[0],
248                                          (IB_gid_t *) & p_ca_info->p_attr->
249                                          p_port_attr[port_num].port_guid);
250                 p_ca_info->p_attr->p_port_attr[port_num].lid = hca_port.lid;
251                 p_ca_info->p_attr->p_port_attr[port_num].link_state =
252                     hca_port.state;
253                 p_ca_info->p_attr->p_port_attr[port_num].sm_lid =
254                     hca_port.sm_lid;
255
256                 free(p_port_gid);
257         }
258
259         status = IB_SUCCESS;
260 Exit:
261         OSM_LOG_EXIT(p_vend->p_log);
262         return (status);
263 }
264
265 /**********************************************************************
266  **********************************************************************/
267 void
268 osm_ca_info_destroy(IN osm_vendor_t * const p_vend,
269                     IN osm_ca_info_t * const p_ca_info, IN uint8_t num_ca)
270 {
271         osm_ca_info_t *p_ca;
272         uint8_t i;
273
274         OSM_LOG_ENTER(p_vend->p_log);
275
276         for (i = 0; i < num_ca; i++) {
277                 p_ca = &p_ca_info[i];
278
279                 if (NULL != p_ca->p_attr) {
280                         if (0 != p_ca->p_attr->num_ports) {
281                                 free(p_ca->p_attr->p_port_attr);
282                         }
283
284                         free(p_ca->p_attr);
285                 }
286         }
287
288         free(p_ca_info);
289
290         OSM_LOG_EXIT(p_vend->p_log);
291 }
292
293 /**********************************************************************
294  * Fill in the array of port_attr with all available ports on ALL the
295  * avilable CAs on this machine.
296  * ALSO -
297  * Update the vendor object list of ca_info structs
298  **********************************************************************/
299 ib_api_status_t
300 osm_vendor_get_all_port_attr(IN osm_vendor_t * const p_vend,
301                              IN ib_port_attr_t * const p_attr_array,
302                              IN uint32_t * const p_num_ports)
303 {
304         ib_api_status_t status;
305
306         uint32_t ca;
307         uint32_t ca_count = 0;
308         uint32_t port_count = 0;
309         uint8_t port_num;
310         uint32_t total_ports = 0;
311         VAPI_hca_id_t *p_ca_ids = NULL;
312         osm_ca_info_t *p_ca_infos = NULL;
313         uint32_t attr_array_sz = *p_num_ports;
314
315         OSM_LOG_ENTER(p_vend->p_log);
316
317         CL_ASSERT(p_vend);
318
319         /* determine the number of CA's */
320         status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count);
321         if (status != IB_SUCCESS) {
322                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
323                         "osm_vendor_get_all_port_attr: ERR 3D13: "
324                         "Fail to get CA Ids.\n");
325                 goto Exit;
326         }
327
328         /* Allocate an array big enough to hold the ca info objects */
329         p_ca_infos = malloc(ca_count * sizeof(osm_ca_info_t));
330         if (p_ca_infos == NULL) {
331                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
332                         "osm_vendor_get_all_port_attr: ERR 3D14: "
333                         "Unable to allocate CA information array.\n");
334                 goto Exit;
335         }
336
337         memset(p_ca_infos, 0, ca_count * sizeof(osm_ca_info_t));
338
339         /*
340          * For each CA, retrieve the CA info attributes
341          */
342         for (ca = 0; ca < ca_count; ca++) {
343                 status =
344                     __osm_ca_info_init(p_vend, p_ca_ids[ca], &p_ca_infos[ca]);
345                 if (status != IB_SUCCESS) {
346                         osm_log(p_vend->p_log, OSM_LOG_ERROR,
347                                 "osm_vendor_get_all_port_attr: ERR 3D15: "
348                                 "Unable to initialize CA Info object (%s).\n",
349                                 ib_get_err_str(status));
350                         goto Exit;
351                 }
352                 total_ports += p_ca_infos[ca].p_attr->num_ports;
353         }
354
355         *p_num_ports = total_ports;
356         osm_log(p_vend->p_log, OSM_LOG_DEBUG,
357                 "osm_vendor_get_all_port_attr: total ports:%u \n", total_ports);
358
359         /*
360          * If the user supplied enough storage, return the port guids,
361          * otherwise, return the appropriate error.
362          */
363         if (attr_array_sz >= total_ports) {
364                 for (ca = 0; ca < ca_count; ca++) {
365                         uint32_t num_ports;
366
367                         num_ports = p_ca_infos[ca].p_attr->num_ports;
368
369                         for (port_num = 0; port_num < num_ports; port_num++) {
370                                 p_attr_array[port_count] =
371                                     *__osm_ca_info_get_port_attr_ptr(&p_ca_infos
372                                                                      [ca],
373                                                                      port_num);
374                                 port_count++;
375                         }
376                 }
377         } else {
378                 status = IB_INSUFFICIENT_MEMORY;
379                 goto Exit;
380         }
381
382         status = IB_SUCCESS;
383
384 Exit:
385         if (p_ca_ids)
386                 free(p_ca_ids);
387
388         if (p_ca_infos) {
389                 osm_ca_info_destroy(p_vend, p_ca_infos, ca_count);
390         }
391
392         OSM_LOG_EXIT(p_vend->p_log);
393         return (status);
394 }
395
396 /**********************************************************************
397  * Given the vendor obj and a guid
398  * return the ca id and port number that have that guid
399  **********************************************************************/
400
401 ib_api_status_t
402 osm_vendor_get_guid_ca_and_port(IN osm_vendor_t * const p_vend,
403                                 IN ib_net64_t const guid,
404                                 OUT VAPI_hca_hndl_t * p_hca_hndl,
405                                 OUT VAPI_hca_id_t * p_hca_id,
406                                 OUT uint8_t * p_hca_idx,
407                                 OUT uint32_t * p_port_num)
408 {
409
410         ib_api_status_t status;
411         VAPI_hca_id_t *p_ca_ids = NULL;
412         VAPI_ret_t vapi_res;
413         VAPI_hca_hndl_t hca_hndl;
414         VAPI_hca_vendor_t hca_vendor;
415         VAPI_hca_cap_t hca_cap;
416         IB_gid_t *p_port_gid = NULL;
417         uint16_t maxNumGids;
418         ib_net64_t port_guid;
419         uint32_t ca, portIdx, ca_count;
420
421         OSM_LOG_ENTER(p_vend->p_log);
422
423         CL_ASSERT(p_vend);
424
425         /*
426          * 1) Determine the number of CA's
427          * 2) Allocate an array big enough to hold the ca info objects.
428          * 3) Call again to retrieve the guids.
429          */
430         status = __osm_vendor_get_ca_ids(p_vend, &p_ca_ids, &ca_count);
431         if (status != IB_SUCCESS) {
432                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
433                         "osm_vendor_get_guid_ca_and_port: ERR 3D16: "
434                         "Fail to get CA Ids.\n");
435                 goto Exit;
436         }
437
438         /*
439          * For each CA, retrieve the CA info attributes
440          */
441         for (ca = 0; ca < ca_count; ca++) {
442                 /* get the HCA handle */
443                 vapi_res = EVAPI_get_hca_hndl(p_ca_ids[ca], &hca_hndl);
444                 if (vapi_res != VAPI_OK) {
445                         osm_log(p_vend->p_log, OSM_LOG_ERROR,
446                                 "osm_vendor_get_guid_ca_and_port: ERR 3D17: "
447                                 "Fail to get HCA handle (%u).\n", vapi_res);
448                         goto Exit;
449                 }
450
451                 /* get the CA attributes - to know how many ports it has: */
452                 if (osm_log_is_active(p_vend->p_log, OSM_LOG_DEBUG)) {
453                         osm_log(p_vend->p_log, OSM_LOG_DEBUG,
454                                 "osm_vendor_get_guid_ca_and_port: "
455                                 "Querying CA %s.\n", p_ca_ids[ca]);
456                 }
457
458                 /* query and get the HCA capability */
459                 vapi_res = VAPI_query_hca_cap(hca_hndl, &hca_vendor, &hca_cap);
460                 if (vapi_res != VAPI_OK) {
461                         osm_log(p_vend->p_log, OSM_LOG_ERROR,
462                                 "osm_vendor_get_guid_ca_and_port: ERR 3D18: "
463                                 "Fail to get HCA Capabilities (%u).\n",
464                                 vapi_res);
465                         goto Exit;
466                 }
467
468                 /* go over all ports - to obtail their guids */
469                 for (portIdx = 0; portIdx < hca_cap.phys_port_num; portIdx++) {
470                         vapi_res =
471                             VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1, 0,
472                                                    &maxNumGids, NULL);
473                         p_port_gid =
474                             (IB_gid_t *) malloc(maxNumGids * sizeof(IB_gid_t));
475
476                         /* get the port guid */
477                         vapi_res =
478                             VAPI_query_hca_gid_tbl(hca_hndl, portIdx + 1,
479                                                    maxNumGids, &maxNumGids,
480                                                    p_port_gid);
481                         if (vapi_res != VAPI_OK) {
482                                 osm_log(p_vend->p_log, OSM_LOG_ERROR,
483                                         "osm_vendor_get_guid_ca_and_port: ERR 3D19: "
484                                         "Fail to get HCA Port GID (%d).\n",
485                                         vapi_res);
486                                 goto Exit;
487                         }
488
489                         /* convert to SF style */
490                         __osm_vendor_gid_to_guid(p_port_gid[0],
491                                                  (VAPI_gid_t *) & port_guid);
492
493                         /* finally did we find it ? */
494                         if (port_guid == guid) {
495                                 *p_hca_hndl = hca_hndl;
496                                 memcpy(p_hca_id, p_ca_ids[ca],
497                                        sizeof(VAPI_hca_id_t));
498                                 *p_hca_idx = ca;
499                                 *p_port_num = portIdx + 1;
500                                 status = IB_SUCCESS;
501                                 goto Exit;
502                         }
503
504                         free(p_port_gid);
505                         p_port_gid = NULL;
506                 }               /*  ALL PORTS  */
507         }                       /*  all HCAs */
508
509         osm_log(p_vend->p_log, OSM_LOG_ERROR,
510                 "osm_vendor_get_guid_ca_and_port: ERR 3D20: "
511                 "Fail to find HCA and Port for Port Guid 0x%" PRIx64 "\n",
512                 cl_ntoh64(guid));
513         status = IB_INVALID_GUID;
514
515 Exit:
516         if (p_ca_ids != NULL)
517                 free(p_ca_ids);
518         if (p_port_gid != NULL)
519                 free(p_port_gid);
520         OSM_LOG_EXIT(p_vend->p_log);
521         return (status);
522 }
523
524 #endif