xref: /freebsd/contrib/ofed/libibumad/umad.c (revision 76001684)
1d6b92ffaSHans Petter Selasky /*
2d6b92ffaSHans Petter Selasky  * Copyright (c) 2004-2009 Voltaire Inc.  All rights reserved.
3d6b92ffaSHans Petter Selasky  * Copyright (c) 2014 Intel Corporation.  All rights reserved.
4d6b92ffaSHans Petter Selasky  *
5d6b92ffaSHans Petter Selasky  * This software is available to you under a choice of one of two
6d6b92ffaSHans Petter Selasky  * licenses.  You may choose to be licensed under the terms of the GNU
7d6b92ffaSHans Petter Selasky  * General Public License (GPL) Version 2, available from the file
8d6b92ffaSHans Petter Selasky  * COPYING in the main directory of this source tree, or the
9d6b92ffaSHans Petter Selasky  * OpenIB.org BSD license below:
10d6b92ffaSHans Petter Selasky  *
11d6b92ffaSHans Petter Selasky  *     Redistribution and use in source and binary forms, with or
12d6b92ffaSHans Petter Selasky  *     without modification, are permitted provided that the following
13d6b92ffaSHans Petter Selasky  *     conditions are met:
14d6b92ffaSHans Petter Selasky  *
15d6b92ffaSHans Petter Selasky  *      - Redistributions of source code must retain the above
16d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
17d6b92ffaSHans Petter Selasky  *        disclaimer.
18d6b92ffaSHans Petter Selasky  *
19d6b92ffaSHans Petter Selasky  *      - Redistributions in binary form must reproduce the above
20d6b92ffaSHans Petter Selasky  *        copyright notice, this list of conditions and the following
21d6b92ffaSHans Petter Selasky  *        disclaimer in the documentation and/or other materials
22d6b92ffaSHans Petter Selasky  *        provided with the distribution.
23d6b92ffaSHans Petter Selasky  *
24d6b92ffaSHans Petter Selasky  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25d6b92ffaSHans Petter Selasky  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26d6b92ffaSHans Petter Selasky  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27d6b92ffaSHans Petter Selasky  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28d6b92ffaSHans Petter Selasky  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29d6b92ffaSHans Petter Selasky  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30d6b92ffaSHans Petter Selasky  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31d6b92ffaSHans Petter Selasky  * SOFTWARE.
32d6b92ffaSHans Petter Selasky  *
33d6b92ffaSHans Petter Selasky  */
34d6b92ffaSHans Petter Selasky 
35d6b92ffaSHans Petter Selasky #include <config.h>
36d6b92ffaSHans Petter Selasky 
37d6b92ffaSHans Petter Selasky #include <sys/poll.h>
38d6b92ffaSHans Petter Selasky #include <unistd.h>
39d6b92ffaSHans Petter Selasky #include <string.h>
40d6b92ffaSHans Petter Selasky #include <stdio.h>
41d6b92ffaSHans Petter Selasky #include <errno.h>
42d6b92ffaSHans Petter Selasky #include <sys/types.h>
43d6b92ffaSHans Petter Selasky #include <sys/stat.h>
44d6b92ffaSHans Petter Selasky #include <fcntl.h>
45d6b92ffaSHans Petter Selasky #include <sys/ioctl.h>
46d6b92ffaSHans Petter Selasky #include <dirent.h>
47d6b92ffaSHans Petter Selasky #include <ctype.h>
48d6b92ffaSHans Petter Selasky #include <inttypes.h>
497093892cSHans Petter Selasky #include <assert.h>
50d6b92ffaSHans Petter Selasky 
51d6b92ffaSHans Petter Selasky #include <infiniband/umad.h>
52d6b92ffaSHans Petter Selasky 
53d6b92ffaSHans Petter Selasky #define IB_OPENIB_OUI                 (0x001405)
54d6b92ffaSHans Petter Selasky 
55d6b92ffaSHans Petter Selasky #include "sysfs.h"
56d6b92ffaSHans Petter Selasky 
57d6b92ffaSHans Petter Selasky typedef struct ib_user_mad_reg_req {
58d6b92ffaSHans Petter Selasky 	uint32_t id;
59d6b92ffaSHans Petter Selasky 	uint32_t method_mask[4];
60d6b92ffaSHans Petter Selasky 	uint8_t qpn;
61d6b92ffaSHans Petter Selasky 	uint8_t mgmt_class;
62d6b92ffaSHans Petter Selasky 	uint8_t mgmt_class_version;
63d6b92ffaSHans Petter Selasky 	uint8_t oui[3];
64d6b92ffaSHans Petter Selasky 	uint8_t rmpp_version;
65d6b92ffaSHans Petter Selasky } ib_user_mad_reg_req_t;
66d6b92ffaSHans Petter Selasky 
677093892cSHans Petter Selasky static_assert(sizeof(struct ib_user_mad_reg_req) == IOCPARM_LEN(IB_USER_MAD_REGISTER_AGENT),
687093892cSHans Petter Selasky     "Invalid structure size");
697093892cSHans Petter Selasky 
70d6b92ffaSHans Petter Selasky struct ib_user_mad_reg_req2 {
71d6b92ffaSHans Petter Selasky 	uint32_t id;
72d6b92ffaSHans Petter Selasky 	uint32_t qpn;
73d6b92ffaSHans Petter Selasky 	uint8_t  mgmt_class;
74d6b92ffaSHans Petter Selasky 	uint8_t  mgmt_class_version;
75d6b92ffaSHans Petter Selasky 	uint16_t res;
76d6b92ffaSHans Petter Selasky 	uint32_t flags;
77d6b92ffaSHans Petter Selasky 	uint64_t method_mask[2];
78d6b92ffaSHans Petter Selasky 	uint32_t oui;
79d6b92ffaSHans Petter Selasky 	uint8_t  rmpp_version;
80d6b92ffaSHans Petter Selasky 	uint8_t  reserved[3];
81d6b92ffaSHans Petter Selasky };
82d6b92ffaSHans Petter Selasky 
837093892cSHans Petter Selasky static_assert(sizeof(struct ib_user_mad_reg_req2) == IOCPARM_LEN(IB_USER_MAD_REGISTER_AGENT2),
847093892cSHans Petter Selasky     "Invalid structure size");
857093892cSHans Petter Selasky 
86d6b92ffaSHans Petter Selasky #define IBWARN(fmt, args...) fprintf(stderr, "ibwarn: [%d] %s: " fmt "\n", getpid(), __func__, ## args)
87d6b92ffaSHans Petter Selasky 
88d6b92ffaSHans Petter Selasky #define TRACE	if (umaddebug)	IBWARN
89d6b92ffaSHans Petter Selasky #define DEBUG	if (umaddebug)	IBWARN
90d6b92ffaSHans Petter Selasky 
91d6b92ffaSHans Petter Selasky static int umaddebug = 0;
92d6b92ffaSHans Petter Selasky 
93d6b92ffaSHans Petter Selasky #define UMAD_DEV_FILE_SZ	256
94d6b92ffaSHans Petter Selasky 
95d6b92ffaSHans Petter Selasky static const char *def_ca_name = "mthca0";
96d6b92ffaSHans Petter Selasky static int def_ca_port = 1;
97d6b92ffaSHans Petter Selasky 
98d6b92ffaSHans Petter Selasky static unsigned abi_version;
99d6b92ffaSHans Petter Selasky static unsigned new_user_mad_api;
100d6b92ffaSHans Petter Selasky 
101d6b92ffaSHans Petter Selasky /*************************************
102d6b92ffaSHans Petter Selasky  * Port
103d6b92ffaSHans Petter Selasky  */
find_cached_ca(const char * ca_name,umad_ca_t * ca)104d6b92ffaSHans Petter Selasky static int find_cached_ca(const char *ca_name, umad_ca_t * ca)
105d6b92ffaSHans Petter Selasky {
106d6b92ffaSHans Petter Selasky 	return 0;		/* caching not implemented yet */
107d6b92ffaSHans Petter Selasky }
108d6b92ffaSHans Petter Selasky 
put_ca(umad_ca_t * ca)109d6b92ffaSHans Petter Selasky static int put_ca(umad_ca_t * ca)
110d6b92ffaSHans Petter Selasky {
111d6b92ffaSHans Petter Selasky 	return 0;		/* caching not implemented yet */
112d6b92ffaSHans Petter Selasky }
113d6b92ffaSHans Petter Selasky 
release_port(umad_port_t * port)114d6b92ffaSHans Petter Selasky static int release_port(umad_port_t * port)
115d6b92ffaSHans Petter Selasky {
116d6b92ffaSHans Petter Selasky 	free(port->pkeys);
117d6b92ffaSHans Petter Selasky 	port->pkeys = NULL;
118d6b92ffaSHans Petter Selasky 	port->pkeys_size = 0;
119d6b92ffaSHans Petter Selasky 	return 0;
120d6b92ffaSHans Petter Selasky }
121d6b92ffaSHans Petter Selasky 
check_for_digit_name(const struct dirent * dent)122d6b92ffaSHans Petter Selasky static int check_for_digit_name(const struct dirent *dent)
123d6b92ffaSHans Petter Selasky {
124d6b92ffaSHans Petter Selasky 	const char *p = dent->d_name;
125d6b92ffaSHans Petter Selasky 	while (*p && isdigit(*p))
126d6b92ffaSHans Petter Selasky 		p++;
127d6b92ffaSHans Petter Selasky 	return *p ? 0 : 1;
128d6b92ffaSHans Petter Selasky }
129d6b92ffaSHans Petter Selasky 
get_port(const char * ca_name,const char * dir,int portnum,umad_port_t * port)130d6b92ffaSHans Petter Selasky static int get_port(const char *ca_name, const char *dir, int portnum, umad_port_t * port)
131d6b92ffaSHans Petter Selasky {
132d6b92ffaSHans Petter Selasky 	char port_dir[256];
133d6b92ffaSHans Petter Selasky 	union umad_gid gid;
134d6b92ffaSHans Petter Selasky 	struct dirent **namelist = NULL;
135d6b92ffaSHans Petter Selasky 	int i, len, num_pkeys = 0;
136d6b92ffaSHans Petter Selasky 	uint32_t capmask;
137d6b92ffaSHans Petter Selasky 
138d6b92ffaSHans Petter Selasky 	strncpy(port->ca_name, ca_name, sizeof port->ca_name - 1);
139d6b92ffaSHans Petter Selasky 	port->portnum = portnum;
140d6b92ffaSHans Petter Selasky 	port->pkeys = NULL;
14137e576b2SSlava Shwartsman 	port->rate = 0;
142d6b92ffaSHans Petter Selasky 
143d6b92ffaSHans Petter Selasky 	len = snprintf(port_dir, sizeof(port_dir), "%s/%d", dir, portnum);
144d6b92ffaSHans Petter Selasky 	if (len < 0 || len > sizeof(port_dir))
145d6b92ffaSHans Petter Selasky 		goto clean;
146d6b92ffaSHans Petter Selasky 
147d6b92ffaSHans Petter Selasky 	if (sys_read_uint(port_dir, SYS_PORT_LMC, &port->lmc) < 0)
148d6b92ffaSHans Petter Selasky 		goto clean;
149d6b92ffaSHans Petter Selasky 	if (sys_read_uint(port_dir, SYS_PORT_SMLID, &port->sm_lid) < 0)
150d6b92ffaSHans Petter Selasky 		goto clean;
151d6b92ffaSHans Petter Selasky 	if (sys_read_uint(port_dir, SYS_PORT_SMSL, &port->sm_sl) < 0)
152d6b92ffaSHans Petter Selasky 		goto clean;
153d6b92ffaSHans Petter Selasky 	if (sys_read_uint(port_dir, SYS_PORT_LID, &port->base_lid) < 0)
154d6b92ffaSHans Petter Selasky 		goto clean;
155d6b92ffaSHans Petter Selasky 	if (sys_read_uint(port_dir, SYS_PORT_STATE, &port->state) < 0)
156d6b92ffaSHans Petter Selasky 		goto clean;
157d6b92ffaSHans Petter Selasky 	if (sys_read_uint(port_dir, SYS_PORT_PHY_STATE, &port->phys_state) < 0)
158d6b92ffaSHans Petter Selasky 		goto clean;
15937e576b2SSlava Shwartsman 	/*
16037e576b2SSlava Shwartsman 	 * If width was not set properly this read may fail.
16137e576b2SSlava Shwartsman 	 * Instead of failing everything, we will just skip the check
16237e576b2SSlava Shwartsman 	 * and it will be set to 0.
16337e576b2SSlava Shwartsman 	 */
16437e576b2SSlava Shwartsman 	sys_read_uint(port_dir, SYS_PORT_RATE, &port->rate);
165d6b92ffaSHans Petter Selasky 	if (sys_read_uint(port_dir, SYS_PORT_CAPMASK, &capmask) < 0)
166d6b92ffaSHans Petter Selasky 		goto clean;
167d6b92ffaSHans Petter Selasky 
168d6b92ffaSHans Petter Selasky 	if (sys_read_string(port_dir, SYS_PORT_LINK_LAYER,
169d6b92ffaSHans Petter Selasky 	    port->link_layer, UMAD_CA_NAME_LEN) < 0)
170d6b92ffaSHans Petter Selasky 		/* assume IB by default */
171d6b92ffaSHans Petter Selasky 		sprintf(port->link_layer, "IB");
172d6b92ffaSHans Petter Selasky 
173d6b92ffaSHans Petter Selasky 	port->capmask = htobe32(capmask);
174d6b92ffaSHans Petter Selasky 
175d6b92ffaSHans Petter Selasky 	if (sys_read_gid(port_dir, SYS_PORT_GID, &gid) < 0)
176d6b92ffaSHans Petter Selasky 		goto clean;
177d6b92ffaSHans Petter Selasky 
178d6b92ffaSHans Petter Selasky 	port->gid_prefix = gid.global.subnet_prefix;
179d6b92ffaSHans Petter Selasky 	port->port_guid = gid.global.interface_id;
180d6b92ffaSHans Petter Selasky 
181d6b92ffaSHans Petter Selasky 	snprintf(port_dir + len, sizeof(port_dir) - len, "/pkeys");
182d6b92ffaSHans Petter Selasky 	num_pkeys = sys_scandir(port_dir, &namelist, check_for_digit_name, NULL);
183d6b92ffaSHans Petter Selasky 	if (num_pkeys <= 0) {
184d6b92ffaSHans Petter Selasky 		IBWARN("no pkeys found for %s:%u (at dir %s)...",
185d6b92ffaSHans Petter Selasky 		       port->ca_name, port->portnum, port_dir);
186d6b92ffaSHans Petter Selasky 		goto clean;
187d6b92ffaSHans Petter Selasky 	}
188d6b92ffaSHans Petter Selasky 	port->pkeys = calloc(num_pkeys, sizeof(port->pkeys[0]));
189d6b92ffaSHans Petter Selasky 	if (!port->pkeys) {
190d6b92ffaSHans Petter Selasky 		IBWARN("get_port: calloc failed: %s", strerror(errno));
191d6b92ffaSHans Petter Selasky 		goto clean;
192d6b92ffaSHans Petter Selasky 	}
193d6b92ffaSHans Petter Selasky 	for (i = 0; i < num_pkeys; i++) {
194d6b92ffaSHans Petter Selasky 		unsigned idx, val;
195d6b92ffaSHans Petter Selasky 		idx = strtoul(namelist[i]->d_name, NULL, 0);
196d6b92ffaSHans Petter Selasky 		sys_read_uint(port_dir, namelist[i]->d_name, &val);
197d6b92ffaSHans Petter Selasky 		port->pkeys[idx] = val;
198d6b92ffaSHans Petter Selasky 		free(namelist[i]);
199d6b92ffaSHans Petter Selasky 	}
200d6b92ffaSHans Petter Selasky 	port->pkeys_size = num_pkeys;
201d6b92ffaSHans Petter Selasky 	free(namelist);
202d6b92ffaSHans Petter Selasky 	namelist = NULL;
203d6b92ffaSHans Petter Selasky 	port_dir[len] = '\0';
204d6b92ffaSHans Petter Selasky 
205d6b92ffaSHans Petter Selasky 	/* FIXME: handle gids */
206d6b92ffaSHans Petter Selasky 
207d6b92ffaSHans Petter Selasky 	return 0;
208d6b92ffaSHans Petter Selasky 
209d6b92ffaSHans Petter Selasky clean:
210d6b92ffaSHans Petter Selasky 	if (namelist) {
211d6b92ffaSHans Petter Selasky 		for (i = 0; i < num_pkeys; i++)
212d6b92ffaSHans Petter Selasky 			free(namelist[i]);
213d6b92ffaSHans Petter Selasky 		free(namelist);
214d6b92ffaSHans Petter Selasky 	}
215d6b92ffaSHans Petter Selasky 	if (port->pkeys)
216d6b92ffaSHans Petter Selasky 		free(port->pkeys);
217d6b92ffaSHans Petter Selasky 	return -EIO;
218d6b92ffaSHans Petter Selasky }
219d6b92ffaSHans Petter Selasky 
release_ca(umad_ca_t * ca)220d6b92ffaSHans Petter Selasky static int release_ca(umad_ca_t * ca)
221d6b92ffaSHans Petter Selasky {
222d6b92ffaSHans Petter Selasky 	int i;
223d6b92ffaSHans Petter Selasky 
224d6b92ffaSHans Petter Selasky 	for (i = 0; i <= ca->numports; i++) {
225d6b92ffaSHans Petter Selasky 		if (!ca->ports[i])
226d6b92ffaSHans Petter Selasky 			continue;
227d6b92ffaSHans Petter Selasky 		release_port(ca->ports[i]);
228d6b92ffaSHans Petter Selasky 		free(ca->ports[i]);
229d6b92ffaSHans Petter Selasky 		ca->ports[i] = NULL;
230d6b92ffaSHans Petter Selasky 	}
231d6b92ffaSHans Petter Selasky 	return 0;
232d6b92ffaSHans Petter Selasky }
233d6b92ffaSHans Petter Selasky 
234d6b92ffaSHans Petter Selasky /*
235d6b92ffaSHans Petter Selasky  * if *port > 0, check ca[port] state. Otherwise set *port to
236d6b92ffaSHans Petter Selasky  * the first port that is active, and if such is not found, to
237d6b92ffaSHans Petter Selasky  * the first port that is link up and if none are linkup, then
238d6b92ffaSHans Petter Selasky  * the first port that is not disabled.  Otherwise return -1.
239d6b92ffaSHans Petter Selasky  */
resolve_ca_port(const char * ca_name,int * port)240d6b92ffaSHans Petter Selasky static int resolve_ca_port(const char *ca_name, int *port)
241d6b92ffaSHans Petter Selasky {
242d6b92ffaSHans Petter Selasky 	umad_ca_t ca;
243d6b92ffaSHans Petter Selasky 	int active = -1, up = -1;
244d6b92ffaSHans Petter Selasky 	int i, ret = 0;
245d6b92ffaSHans Petter Selasky 
246d6b92ffaSHans Petter Selasky 	TRACE("checking ca '%s'", ca_name);
247d6b92ffaSHans Petter Selasky 
248d6b92ffaSHans Petter Selasky 	if (umad_get_ca(ca_name, &ca) < 0)
249d6b92ffaSHans Petter Selasky 		return -1;
250d6b92ffaSHans Petter Selasky 
251d6b92ffaSHans Petter Selasky 	if (ca.node_type == 2) {
252d6b92ffaSHans Petter Selasky 		*port = 0;	/* switch sma port 0 */
253d6b92ffaSHans Petter Selasky 		ret = 1;
254d6b92ffaSHans Petter Selasky 		goto Exit;
255d6b92ffaSHans Petter Selasky 	}
256d6b92ffaSHans Petter Selasky 
257d6b92ffaSHans Petter Selasky 	if (*port > 0) {	/* check only the port the user wants */
258d6b92ffaSHans Petter Selasky 		if (*port > ca.numports) {
259d6b92ffaSHans Petter Selasky 			ret = -1;
260d6b92ffaSHans Petter Selasky 			goto Exit;
261d6b92ffaSHans Petter Selasky 		}
262d6b92ffaSHans Petter Selasky 		if (!ca.ports[*port]) {
263d6b92ffaSHans Petter Selasky 			ret = -1;
264d6b92ffaSHans Petter Selasky 			goto Exit;
265d6b92ffaSHans Petter Selasky 		}
266d6b92ffaSHans Petter Selasky 		if (strcmp(ca.ports[*port]->link_layer, "InfiniBand") &&
267d6b92ffaSHans Petter Selasky 		    strcmp(ca.ports[*port]->link_layer, "IB")) {
268d6b92ffaSHans Petter Selasky 			ret = -1;
269d6b92ffaSHans Petter Selasky 			goto Exit;
270d6b92ffaSHans Petter Selasky 		}
271d6b92ffaSHans Petter Selasky 		if (ca.ports[*port]->state == 4) {
272d6b92ffaSHans Petter Selasky 			ret = 1;
273d6b92ffaSHans Petter Selasky 			goto Exit;
274d6b92ffaSHans Petter Selasky 		}
275d6b92ffaSHans Petter Selasky 		if (ca.ports[*port]->phys_state != 3)
276d6b92ffaSHans Petter Selasky 			goto Exit;
277d6b92ffaSHans Petter Selasky 		ret = -1;
278d6b92ffaSHans Petter Selasky 		goto Exit;
279d6b92ffaSHans Petter Selasky 	}
280d6b92ffaSHans Petter Selasky 
281d6b92ffaSHans Petter Selasky 	for (i = 0; i <= ca.numports; i++) {
282d6b92ffaSHans Petter Selasky 		DEBUG("checking port %d", i);
283d6b92ffaSHans Petter Selasky 		if (!ca.ports[i])
284d6b92ffaSHans Petter Selasky 			continue;
285d6b92ffaSHans Petter Selasky 		if (strcmp(ca.ports[i]->link_layer, "InfiniBand") &&
286d6b92ffaSHans Petter Selasky 		    strcmp(ca.ports[i]->link_layer, "IB"))
287d6b92ffaSHans Petter Selasky 			continue;
288d6b92ffaSHans Petter Selasky 		if (up < 0 && ca.ports[i]->phys_state == 5)
289d6b92ffaSHans Petter Selasky 			up = *port = i;
290d6b92ffaSHans Petter Selasky 		if (ca.ports[i]->state == 4) {
291d6b92ffaSHans Petter Selasky 			active = *port = i;
292d6b92ffaSHans Petter Selasky 			DEBUG("found active port %d", i);
293d6b92ffaSHans Petter Selasky 			break;
294d6b92ffaSHans Petter Selasky 		}
295d6b92ffaSHans Petter Selasky 	}
296d6b92ffaSHans Petter Selasky 
297d6b92ffaSHans Petter Selasky 	if (active == -1 && up == -1) {	/* no active or linkup port found */
298d6b92ffaSHans Petter Selasky 		for (i = 0; i <= ca.numports; i++) {
299d6b92ffaSHans Petter Selasky 			DEBUG("checking port %d", i);
300d6b92ffaSHans Petter Selasky 			if (!ca.ports[i])
301d6b92ffaSHans Petter Selasky 				continue;
302d6b92ffaSHans Petter Selasky 			if (ca.ports[i]->phys_state != 3) {
303d6b92ffaSHans Petter Selasky 				up = *port = i;
304d6b92ffaSHans Petter Selasky 				break;
305d6b92ffaSHans Petter Selasky 			}
306d6b92ffaSHans Petter Selasky 		}
307d6b92ffaSHans Petter Selasky 	}
308d6b92ffaSHans Petter Selasky 
309d6b92ffaSHans Petter Selasky 	if (active >= 0) {
310d6b92ffaSHans Petter Selasky 		ret = 1;
311d6b92ffaSHans Petter Selasky 		goto Exit;
312d6b92ffaSHans Petter Selasky 	}
313d6b92ffaSHans Petter Selasky 	if (up >= 0) {
314d6b92ffaSHans Petter Selasky 		ret = 0;
315d6b92ffaSHans Petter Selasky 		goto Exit;
316d6b92ffaSHans Petter Selasky 	}
317d6b92ffaSHans Petter Selasky 	ret = -1;
318d6b92ffaSHans Petter Selasky Exit:
319d6b92ffaSHans Petter Selasky 	release_ca(&ca);
320d6b92ffaSHans Petter Selasky 	return ret;
321d6b92ffaSHans Petter Selasky }
322d6b92ffaSHans Petter Selasky 
resolve_ca_name(const char * ca_name,int * best_port)323d6b92ffaSHans Petter Selasky static const char *resolve_ca_name(const char *ca_name, int *best_port)
324d6b92ffaSHans Petter Selasky {
325d6b92ffaSHans Petter Selasky 	static char names[UMAD_MAX_DEVICES][UMAD_CA_NAME_LEN];
326d6b92ffaSHans Petter Selasky 	int phys_found = -1, port_found = 0, port, port_type;
327d6b92ffaSHans Petter Selasky 	int caidx, n;
328d6b92ffaSHans Petter Selasky 
329d6b92ffaSHans Petter Selasky 	if (ca_name && (!best_port || *best_port))
330d6b92ffaSHans Petter Selasky 		return ca_name;
331d6b92ffaSHans Petter Selasky 
332d6b92ffaSHans Petter Selasky 	if (ca_name) {
333d6b92ffaSHans Petter Selasky 		if (resolve_ca_port(ca_name, best_port) < 0)
334d6b92ffaSHans Petter Selasky 			return NULL;
335d6b92ffaSHans Petter Selasky 		return ca_name;
336d6b92ffaSHans Petter Selasky 	}
337d6b92ffaSHans Petter Selasky 
338d6b92ffaSHans Petter Selasky 	/* Get the list of CA names */
339d6b92ffaSHans Petter Selasky 	if ((n = umad_get_cas_names((void *)names, UMAD_MAX_DEVICES)) < 0)
340d6b92ffaSHans Petter Selasky 		return NULL;
341d6b92ffaSHans Petter Selasky 
342d6b92ffaSHans Petter Selasky 	/* Find the first existing CA with an active port */
343d6b92ffaSHans Petter Selasky 	for (caidx = 0; caidx < n; caidx++) {
344d6b92ffaSHans Petter Selasky 		TRACE("checking ca '%s'", names[caidx]);
345d6b92ffaSHans Petter Selasky 
346d6b92ffaSHans Petter Selasky 		port = best_port ? *best_port : 0;
347d6b92ffaSHans Petter Selasky 		if ((port_type = resolve_ca_port(names[caidx], &port)) < 0)
348d6b92ffaSHans Petter Selasky 			continue;
349d6b92ffaSHans Petter Selasky 
350d6b92ffaSHans Petter Selasky 		DEBUG("found ca %s with port %d type %d",
351d6b92ffaSHans Petter Selasky 		      names[caidx], port, port_type);
352d6b92ffaSHans Petter Selasky 
353d6b92ffaSHans Petter Selasky 		if (port_type > 0) {
354d6b92ffaSHans Petter Selasky 			if (best_port)
355d6b92ffaSHans Petter Selasky 				*best_port = port;
356d6b92ffaSHans Petter Selasky 			DEBUG("found ca %s with active port %d",
357d6b92ffaSHans Petter Selasky 			      names[caidx], port);
358d6b92ffaSHans Petter Selasky 			return (char *)(names + caidx);
359d6b92ffaSHans Petter Selasky 		}
360d6b92ffaSHans Petter Selasky 
361d6b92ffaSHans Petter Selasky 		if (phys_found == -1) {
362d6b92ffaSHans Petter Selasky 			phys_found = caidx;
363d6b92ffaSHans Petter Selasky 			port_found = port;
364d6b92ffaSHans Petter Selasky 		}
365d6b92ffaSHans Petter Selasky 	}
366d6b92ffaSHans Petter Selasky 
367d6b92ffaSHans Petter Selasky 	DEBUG("phys found %d on %s port %d",
368d6b92ffaSHans Petter Selasky 	      phys_found, phys_found >= 0 ? names[phys_found] : NULL,
369d6b92ffaSHans Petter Selasky 	      port_found);
370d6b92ffaSHans Petter Selasky 	if (phys_found >= 0) {
371d6b92ffaSHans Petter Selasky 		if (best_port)
372d6b92ffaSHans Petter Selasky 			*best_port = port_found;
373d6b92ffaSHans Petter Selasky 		return names[phys_found];
374d6b92ffaSHans Petter Selasky 	}
375d6b92ffaSHans Petter Selasky 
376d6b92ffaSHans Petter Selasky 	if (best_port)
377d6b92ffaSHans Petter Selasky 		*best_port = def_ca_port;
378d6b92ffaSHans Petter Selasky 	return def_ca_name;
379d6b92ffaSHans Petter Selasky }
380d6b92ffaSHans Petter Selasky 
get_ca(const char * ca_name,umad_ca_t * ca)381d6b92ffaSHans Petter Selasky static int get_ca(const char *ca_name, umad_ca_t * ca)
382d6b92ffaSHans Petter Selasky {
383d6b92ffaSHans Petter Selasky 	char dir_name[256];
384d6b92ffaSHans Petter Selasky 	struct dirent **namelist;
385d6b92ffaSHans Petter Selasky 	int r, i, ret;
386d6b92ffaSHans Petter Selasky 	int portnum;
387d6b92ffaSHans Petter Selasky 
388d6b92ffaSHans Petter Selasky 	ca->numports = 0;
389d6b92ffaSHans Petter Selasky 	memset(ca->ports, 0, sizeof ca->ports);
390d6b92ffaSHans Petter Selasky 	strncpy(ca->ca_name, ca_name, sizeof(ca->ca_name) - 1);
391d6b92ffaSHans Petter Selasky 
392d6b92ffaSHans Petter Selasky 	snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND,
393d6b92ffaSHans Petter Selasky 		 ca->ca_name);
394d6b92ffaSHans Petter Selasky 
395d6b92ffaSHans Petter Selasky 	if ((r = sys_read_uint(dir_name, SYS_NODE_TYPE, &ca->node_type)) < 0)
396d6b92ffaSHans Petter Selasky 		return r;
397d6b92ffaSHans Petter Selasky 	if (sys_read_string(dir_name, SYS_CA_FW_VERS, ca->fw_ver,
398d6b92ffaSHans Petter Selasky 			    sizeof ca->fw_ver) < 0)
399d6b92ffaSHans Petter Selasky 		ca->fw_ver[0] = '\0';
400d6b92ffaSHans Petter Selasky 	if (sys_read_string(dir_name, SYS_CA_HW_VERS, ca->hw_ver,
401d6b92ffaSHans Petter Selasky 			    sizeof ca->hw_ver) < 0)
402d6b92ffaSHans Petter Selasky 		ca->hw_ver[0] = '\0';
403d6b92ffaSHans Petter Selasky 	if ((r = sys_read_string(dir_name, SYS_CA_TYPE, ca->ca_type,
404d6b92ffaSHans Petter Selasky 				 sizeof ca->ca_type)) < 0)
405d6b92ffaSHans Petter Selasky 		ca->ca_type[0] = '\0';
406d6b92ffaSHans Petter Selasky 	if ((r = sys_read_guid(dir_name, SYS_CA_NODE_GUID, &ca->node_guid)) < 0)
407d6b92ffaSHans Petter Selasky 		return r;
408d6b92ffaSHans Petter Selasky 	if ((r =
409d6b92ffaSHans Petter Selasky 	     sys_read_guid(dir_name, SYS_CA_SYS_GUID, &ca->system_guid)) < 0)
410d6b92ffaSHans Petter Selasky 		return r;
411d6b92ffaSHans Petter Selasky 
412d6b92ffaSHans Petter Selasky 	snprintf(dir_name, sizeof(dir_name), "%s/%s/%s",
413d6b92ffaSHans Petter Selasky 		 SYS_INFINIBAND, ca->ca_name, SYS_CA_PORTS_DIR);
414d6b92ffaSHans Petter Selasky 
415d6b92ffaSHans Petter Selasky 	if ((r = sys_scandir(dir_name, &namelist, NULL, alphasort)) < 0) {
416d6b92ffaSHans Petter Selasky 		ret = errno < 0 ? errno : -EIO;
417d6b92ffaSHans Petter Selasky 		goto error;
418d6b92ffaSHans Petter Selasky 	}
419d6b92ffaSHans Petter Selasky 
420d6b92ffaSHans Petter Selasky 	ret = 0;
421d6b92ffaSHans Petter Selasky 	for (i = 0; i < r; i++) {
422d6b92ffaSHans Petter Selasky 		portnum = 0;
423d6b92ffaSHans Petter Selasky 		if (!strcmp(".", namelist[i]->d_name) ||
424d6b92ffaSHans Petter Selasky 		    !strcmp("..", namelist[i]->d_name))
425d6b92ffaSHans Petter Selasky 			continue;
426d6b92ffaSHans Petter Selasky 		if (strcmp("0", namelist[i]->d_name) &&
427d6b92ffaSHans Petter Selasky 		    ((portnum = atoi(namelist[i]->d_name)) <= 0 ||
428d6b92ffaSHans Petter Selasky 		     portnum >= UMAD_CA_MAX_PORTS)) {
429d6b92ffaSHans Petter Selasky 			ret = -EIO;
430d6b92ffaSHans Petter Selasky 			goto clean;
431d6b92ffaSHans Petter Selasky 		}
432d6b92ffaSHans Petter Selasky 		if (!(ca->ports[portnum] =
433d6b92ffaSHans Petter Selasky 		      calloc(1, sizeof(*ca->ports[portnum])))) {
434d6b92ffaSHans Petter Selasky 			ret = -ENOMEM;
435d6b92ffaSHans Petter Selasky 			goto clean;
436d6b92ffaSHans Petter Selasky 		}
437d6b92ffaSHans Petter Selasky 		if (get_port(ca_name, dir_name, portnum, ca->ports[portnum]) <
438d6b92ffaSHans Petter Selasky 		    0) {
439d6b92ffaSHans Petter Selasky 			free(ca->ports[portnum]);
440d6b92ffaSHans Petter Selasky 			ca->ports[portnum] = NULL;
441d6b92ffaSHans Petter Selasky 			ret = -EIO;
442d6b92ffaSHans Petter Selasky 			goto clean;
443d6b92ffaSHans Petter Selasky 		}
444d6b92ffaSHans Petter Selasky 		if (ca->numports < portnum)
445d6b92ffaSHans Petter Selasky 			ca->numports = portnum;
446d6b92ffaSHans Petter Selasky 	}
447d6b92ffaSHans Petter Selasky 
448d6b92ffaSHans Petter Selasky 	for (i = 0; i < r; i++)
449d6b92ffaSHans Petter Selasky 		free(namelist[i]);
450d6b92ffaSHans Petter Selasky 	free(namelist);
451d6b92ffaSHans Petter Selasky 
452d6b92ffaSHans Petter Selasky 	put_ca(ca);
453d6b92ffaSHans Petter Selasky 	return 0;
454d6b92ffaSHans Petter Selasky 
455d6b92ffaSHans Petter Selasky clean:
456d6b92ffaSHans Petter Selasky 	for (i = 0; i < r; i++)
457d6b92ffaSHans Petter Selasky 		free(namelist[i]);
458d6b92ffaSHans Petter Selasky 	free(namelist);
459d6b92ffaSHans Petter Selasky error:
460d6b92ffaSHans Petter Selasky 	release_ca(ca);
461d6b92ffaSHans Petter Selasky 
462d6b92ffaSHans Petter Selasky 	return ret;
463d6b92ffaSHans Petter Selasky }
464d6b92ffaSHans Petter Selasky 
umad_id_to_dev(int umad_id,char * dev,unsigned * port)465d6b92ffaSHans Petter Selasky static int umad_id_to_dev(int umad_id, char *dev, unsigned *port)
466d6b92ffaSHans Petter Selasky {
467d6b92ffaSHans Petter Selasky 	char path[256];
468d6b92ffaSHans Petter Selasky 	int r;
469d6b92ffaSHans Petter Selasky 
470d6b92ffaSHans Petter Selasky 	snprintf(path, sizeof(path), SYS_INFINIBAND_MAD "/umad%d", umad_id);
471d6b92ffaSHans Petter Selasky 
472d6b92ffaSHans Petter Selasky 	if ((r =
473d6b92ffaSHans Petter Selasky 	     sys_read_string(path, SYS_IB_MAD_DEV, dev, UMAD_CA_NAME_LEN)) < 0)
474d6b92ffaSHans Petter Selasky 		return r;
475d6b92ffaSHans Petter Selasky 
476d6b92ffaSHans Petter Selasky 	if ((r = sys_read_uint(path, SYS_IB_MAD_PORT, port)) < 0)
477d6b92ffaSHans Petter Selasky 		return r;
478d6b92ffaSHans Petter Selasky 
479d6b92ffaSHans Petter Selasky 	return 0;
480d6b92ffaSHans Petter Selasky }
481d6b92ffaSHans Petter Selasky 
dev_to_umad_id(const char * dev,unsigned port)482d6b92ffaSHans Petter Selasky static int dev_to_umad_id(const char *dev, unsigned port)
483d6b92ffaSHans Petter Selasky {
484d6b92ffaSHans Petter Selasky 	char umad_dev[UMAD_CA_NAME_LEN];
485d6b92ffaSHans Petter Selasky 	unsigned umad_port;
486d6b92ffaSHans Petter Selasky 	int id;
487d6b92ffaSHans Petter Selasky 
488d6b92ffaSHans Petter Selasky 	for (id = 0; id < UMAD_MAX_PORTS; id++) {
489d6b92ffaSHans Petter Selasky 		if (umad_id_to_dev(id, umad_dev, &umad_port) < 0)
490d6b92ffaSHans Petter Selasky 			continue;
491d6b92ffaSHans Petter Selasky 		if (strncmp(dev, umad_dev, UMAD_CA_NAME_LEN))
492d6b92ffaSHans Petter Selasky 			continue;
493d6b92ffaSHans Petter Selasky 		if (port != umad_port)
494d6b92ffaSHans Petter Selasky 			continue;
495d6b92ffaSHans Petter Selasky 
496d6b92ffaSHans Petter Selasky 		DEBUG("mapped %s %d to %d", dev, port, id);
497d6b92ffaSHans Petter Selasky 		return id;
498d6b92ffaSHans Petter Selasky 	}
499d6b92ffaSHans Petter Selasky 
500d6b92ffaSHans Petter Selasky 	return -1;		/* not found */
501d6b92ffaSHans Petter Selasky }
502d6b92ffaSHans Petter Selasky 
503d6b92ffaSHans Petter Selasky /*******************************
504d6b92ffaSHans Petter Selasky  * Public interface
505d6b92ffaSHans Petter Selasky  */
506d6b92ffaSHans Petter Selasky 
umad_init(void)507d6b92ffaSHans Petter Selasky int umad_init(void)
508d6b92ffaSHans Petter Selasky {
509d6b92ffaSHans Petter Selasky 	TRACE("umad_init");
510d6b92ffaSHans Petter Selasky 	if (sys_read_uint(IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE, &abi_version) < 0) {
511d6b92ffaSHans Petter Selasky 		IBWARN
51276001684SHans Petter Selasky 		    ("can't read ABI version from %s (%m): is ibcore module loaded?",
51376001684SHans Petter Selasky 		     PATH_TO_SYS(IB_UMAD_ABI_DIR "/" IB_UMAD_ABI_FILE));
514d6b92ffaSHans Petter Selasky 		return -1;
515d6b92ffaSHans Petter Selasky 	}
516d6b92ffaSHans Petter Selasky 	if (abi_version < IB_UMAD_ABI_VERSION) {
517d6b92ffaSHans Petter Selasky 		IBWARN
51876001684SHans Petter Selasky 		    ("wrong ABI version: %s is %d but library minimal ABI is %d",
51976001684SHans Petter Selasky 		     PATH_TO_SYS(IB_UMAD_ABI_DIR "/" IB_UMAD_ABI_FILE), abi_version,
520d6b92ffaSHans Petter Selasky 		     IB_UMAD_ABI_VERSION);
521d6b92ffaSHans Petter Selasky 		return -1;
522d6b92ffaSHans Petter Selasky 	}
523d6b92ffaSHans Petter Selasky 	return 0;
524d6b92ffaSHans Petter Selasky }
525d6b92ffaSHans Petter Selasky 
umad_done(void)526d6b92ffaSHans Petter Selasky int umad_done(void)
527d6b92ffaSHans Petter Selasky {
528d6b92ffaSHans Petter Selasky 	TRACE("umad_done");
529d6b92ffaSHans Petter Selasky 	/* FIXME - verify that all ports are closed */
530d6b92ffaSHans Petter Selasky 	return 0;
531d6b92ffaSHans Petter Selasky }
532d6b92ffaSHans Petter Selasky 
is_ib_type(const char * ca_name)533d6b92ffaSHans Petter Selasky static unsigned is_ib_type(const char *ca_name)
534d6b92ffaSHans Petter Selasky {
535d6b92ffaSHans Petter Selasky 	char dir_name[256];
536d6b92ffaSHans Petter Selasky 	unsigned type;
537d6b92ffaSHans Petter Selasky 
538d6b92ffaSHans Petter Selasky 	snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND, ca_name);
539d6b92ffaSHans Petter Selasky 
540d6b92ffaSHans Petter Selasky 	if (sys_read_uint(dir_name, SYS_NODE_TYPE, &type) < 0)
541d6b92ffaSHans Petter Selasky 		return 0;
542d6b92ffaSHans Petter Selasky 
543d6b92ffaSHans Petter Selasky 	return type >= 1 && type <= 3 ? 1 : 0;
544d6b92ffaSHans Petter Selasky }
545d6b92ffaSHans Petter Selasky 
umad_get_cas_names(char cas[][UMAD_CA_NAME_LEN],int max)546d6b92ffaSHans Petter Selasky int umad_get_cas_names(char cas[][UMAD_CA_NAME_LEN], int max)
547d6b92ffaSHans Petter Selasky {
548d6b92ffaSHans Petter Selasky 	struct dirent **namelist;
549d6b92ffaSHans Petter Selasky 	int n, i, j = 0;
550d6b92ffaSHans Petter Selasky 
551d6b92ffaSHans Petter Selasky 	TRACE("max %d", max);
552d6b92ffaSHans Petter Selasky 
553d6b92ffaSHans Petter Selasky 	n = sys_scandir(SYS_INFINIBAND, &namelist, NULL, alphasort);
554d6b92ffaSHans Petter Selasky 	if (n > 0) {
555d6b92ffaSHans Petter Selasky 		for (i = 0; i < n; i++) {
556d6b92ffaSHans Petter Selasky 			if (strcmp(namelist[i]->d_name, ".") &&
557d6b92ffaSHans Petter Selasky 			    strcmp(namelist[i]->d_name, "..")) {
558d6b92ffaSHans Petter Selasky 				if (j < max && is_ib_type(namelist[i]->d_name))
559d6b92ffaSHans Petter Selasky 					strncpy(cas[j++], namelist[i]->d_name,
560d6b92ffaSHans Petter Selasky 						UMAD_CA_NAME_LEN);
561d6b92ffaSHans Petter Selasky 			}
562d6b92ffaSHans Petter Selasky 			free(namelist[i]);
563d6b92ffaSHans Petter Selasky 		}
564d6b92ffaSHans Petter Selasky 		DEBUG("return %d cas", j);
565d6b92ffaSHans Petter Selasky 	} else {
566d6b92ffaSHans Petter Selasky 		/* Is this still needed ? */
567d6b92ffaSHans Petter Selasky 		strncpy((char *)cas, def_ca_name, UMAD_CA_NAME_LEN);
568d6b92ffaSHans Petter Selasky 		DEBUG("return 1 ca");
569d6b92ffaSHans Petter Selasky 		j = 1;
570d6b92ffaSHans Petter Selasky 	}
571d6b92ffaSHans Petter Selasky 	if (n >= 0)
572d6b92ffaSHans Petter Selasky 		free(namelist);
573d6b92ffaSHans Petter Selasky 	return j;
574d6b92ffaSHans Petter Selasky }
575d6b92ffaSHans Petter Selasky 
umad_get_ca_portguids(const char * ca_name,__be64 * portguids,int max)576d6b92ffaSHans Petter Selasky int umad_get_ca_portguids(const char *ca_name, __be64 *portguids, int max)
577d6b92ffaSHans Petter Selasky {
578d6b92ffaSHans Petter Selasky 	umad_ca_t ca;
579d6b92ffaSHans Petter Selasky 	int ports = 0, i;
580d6b92ffaSHans Petter Selasky 
581d6b92ffaSHans Petter Selasky 	TRACE("ca name %s max port guids %d", ca_name, max);
582d6b92ffaSHans Petter Selasky 	if (!(ca_name = resolve_ca_name(ca_name, NULL)))
583d6b92ffaSHans Petter Selasky 		return -ENODEV;
584d6b92ffaSHans Petter Selasky 
585d6b92ffaSHans Petter Selasky 	if (umad_get_ca(ca_name, &ca) < 0)
586d6b92ffaSHans Petter Selasky 		return -1;
587d6b92ffaSHans Petter Selasky 
588d6b92ffaSHans Petter Selasky 	if (portguids) {
589d6b92ffaSHans Petter Selasky 		if (ca.numports + 1 > max) {
590d6b92ffaSHans Petter Selasky 			release_ca(&ca);
591d6b92ffaSHans Petter Selasky 			return -ENOMEM;
592d6b92ffaSHans Petter Selasky 		}
593d6b92ffaSHans Petter Selasky 
594d6b92ffaSHans Petter Selasky 		for (i = 0; i <= ca.numports; i++)
595d6b92ffaSHans Petter Selasky 			portguids[ports++] = ca.ports[i] ?
596d6b92ffaSHans Petter Selasky 				ca.ports[i]->port_guid : htobe64(0);
597d6b92ffaSHans Petter Selasky 	}
598d6b92ffaSHans Petter Selasky 
599d6b92ffaSHans Petter Selasky 	release_ca(&ca);
600d6b92ffaSHans Petter Selasky 	DEBUG("%s: %d ports", ca_name, ports);
601d6b92ffaSHans Petter Selasky 
602d6b92ffaSHans Petter Selasky 	return ports;
603d6b92ffaSHans Petter Selasky }
604d6b92ffaSHans Petter Selasky 
umad_get_issm_path(const char * ca_name,int portnum,char path[],int max)605d6b92ffaSHans Petter Selasky int umad_get_issm_path(const char *ca_name, int portnum, char path[], int max)
606d6b92ffaSHans Petter Selasky {
607d6b92ffaSHans Petter Selasky 	int umad_id;
608d6b92ffaSHans Petter Selasky 
609d6b92ffaSHans Petter Selasky 	TRACE("ca %s port %d", ca_name, portnum);
610d6b92ffaSHans Petter Selasky 
611d6b92ffaSHans Petter Selasky 	if (!(ca_name = resolve_ca_name(ca_name, &portnum)))
612d6b92ffaSHans Petter Selasky 		return -ENODEV;
613d6b92ffaSHans Petter Selasky 
614d6b92ffaSHans Petter Selasky 	if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0)
615d6b92ffaSHans Petter Selasky 		return -EINVAL;
616d6b92ffaSHans Petter Selasky 
617d6b92ffaSHans Petter Selasky 	snprintf(path, max, "%s/issm%u", UMAD_DEV_DIR, umad_id);
618d6b92ffaSHans Petter Selasky 
619d6b92ffaSHans Petter Selasky 	return 0;
620d6b92ffaSHans Petter Selasky }
621d6b92ffaSHans Petter Selasky 
umad_open_port(const char * ca_name,int portnum)622d6b92ffaSHans Petter Selasky int umad_open_port(const char *ca_name, int portnum)
623d6b92ffaSHans Petter Selasky {
624d6b92ffaSHans Petter Selasky 	char dev_file[UMAD_DEV_FILE_SZ];
625d6b92ffaSHans Petter Selasky 	int umad_id, fd;
626d6b92ffaSHans Petter Selasky 
627d6b92ffaSHans Petter Selasky 	TRACE("ca %s port %d", ca_name, portnum);
628d6b92ffaSHans Petter Selasky 
629d6b92ffaSHans Petter Selasky 	if (!(ca_name = resolve_ca_name(ca_name, &portnum)))
630d6b92ffaSHans Petter Selasky 		return -ENODEV;
631d6b92ffaSHans Petter Selasky 
632d6b92ffaSHans Petter Selasky 	DEBUG("opening %s port %d", ca_name, portnum);
633d6b92ffaSHans Petter Selasky 
634d6b92ffaSHans Petter Selasky 	if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0)
635d6b92ffaSHans Petter Selasky 		return -EINVAL;
636d6b92ffaSHans Petter Selasky 
637d6b92ffaSHans Petter Selasky 	snprintf(dev_file, sizeof(dev_file), "%s/umad%d",
638d6b92ffaSHans Petter Selasky 		 UMAD_DEV_DIR, umad_id);
639d6b92ffaSHans Petter Selasky 
640d6b92ffaSHans Petter Selasky 	if ((fd = open(dev_file, O_RDWR | O_NONBLOCK)) < 0) {
641d6b92ffaSHans Petter Selasky 		DEBUG("open %s failed: %s", dev_file, strerror(errno));
642d6b92ffaSHans Petter Selasky 		return -EIO;
643d6b92ffaSHans Petter Selasky 	}
644d6b92ffaSHans Petter Selasky 
645d6b92ffaSHans Petter Selasky 	if (abi_version > 5 || !ioctl(fd, IB_USER_MAD_ENABLE_PKEY, NULL))
646d6b92ffaSHans Petter Selasky 		new_user_mad_api = 1;
647d6b92ffaSHans Petter Selasky 	else
648d6b92ffaSHans Petter Selasky 		new_user_mad_api = 0;
649d6b92ffaSHans Petter Selasky 
650d6b92ffaSHans Petter Selasky 	DEBUG("opened %s fd %d portid %d", dev_file, fd, umad_id);
651d6b92ffaSHans Petter Selasky 	return fd;
652d6b92ffaSHans Petter Selasky }
653d6b92ffaSHans Petter Selasky 
umad_get_ca(const char * ca_name,umad_ca_t * ca)654d6b92ffaSHans Petter Selasky int umad_get_ca(const char *ca_name, umad_ca_t * ca)
655d6b92ffaSHans Petter Selasky {
656d6b92ffaSHans Petter Selasky 	int r;
657d6b92ffaSHans Petter Selasky 
658d6b92ffaSHans Petter Selasky 	TRACE("ca_name %s", ca_name);
659d6b92ffaSHans Petter Selasky 	if (!(ca_name = resolve_ca_name(ca_name, NULL)))
660d6b92ffaSHans Petter Selasky 		return -ENODEV;
661d6b92ffaSHans Petter Selasky 
662d6b92ffaSHans Petter Selasky 	if (find_cached_ca(ca_name, ca) > 0)
663d6b92ffaSHans Petter Selasky 		return 0;
664d6b92ffaSHans Petter Selasky 
665d6b92ffaSHans Petter Selasky 	if ((r = get_ca(ca_name, ca)) < 0)
666d6b92ffaSHans Petter Selasky 		return r;
667d6b92ffaSHans Petter Selasky 
668d6b92ffaSHans Petter Selasky 	DEBUG("opened %s", ca_name);
669d6b92ffaSHans Petter Selasky 	return 0;
670d6b92ffaSHans Petter Selasky }
671d6b92ffaSHans Petter Selasky 
umad_release_ca(umad_ca_t * ca)672d6b92ffaSHans Petter Selasky int umad_release_ca(umad_ca_t * ca)
673d6b92ffaSHans Petter Selasky {
674d6b92ffaSHans Petter Selasky 	int r;
675d6b92ffaSHans Petter Selasky 
676d6b92ffaSHans Petter Selasky 	TRACE("ca_name %s", ca->ca_name);
677d6b92ffaSHans Petter Selasky 	if (!ca)
678d6b92ffaSHans Petter Selasky 		return -ENODEV;
679d6b92ffaSHans Petter Selasky 
680d6b92ffaSHans Petter Selasky 	if ((r = release_ca(ca)) < 0)
681d6b92ffaSHans Petter Selasky 		return r;
682d6b92ffaSHans Petter Selasky 
683d6b92ffaSHans Petter Selasky 	DEBUG("releasing %s", ca->ca_name);
684d6b92ffaSHans Petter Selasky 	return 0;
685d6b92ffaSHans Petter Selasky }
686d6b92ffaSHans Petter Selasky 
umad_get_port(const char * ca_name,int portnum,umad_port_t * port)687d6b92ffaSHans Petter Selasky int umad_get_port(const char *ca_name, int portnum, umad_port_t * port)
688d6b92ffaSHans Petter Selasky {
689d6b92ffaSHans Petter Selasky 	char dir_name[256];
690d6b92ffaSHans Petter Selasky 
691d6b92ffaSHans Petter Selasky 	TRACE("ca_name %s portnum %d", ca_name, portnum);
692d6b92ffaSHans Petter Selasky 
693d6b92ffaSHans Petter Selasky 	if (!(ca_name = resolve_ca_name(ca_name, &portnum)))
694d6b92ffaSHans Petter Selasky 		return -ENODEV;
695d6b92ffaSHans Petter Selasky 
696d6b92ffaSHans Petter Selasky 	snprintf(dir_name, sizeof(dir_name), "%s/%s/%s",
697d6b92ffaSHans Petter Selasky 		 SYS_INFINIBAND, ca_name, SYS_CA_PORTS_DIR);
698d6b92ffaSHans Petter Selasky 
699d6b92ffaSHans Petter Selasky 	return get_port(ca_name, dir_name, portnum, port);
700d6b92ffaSHans Petter Selasky }
701d6b92ffaSHans Petter Selasky 
umad_release_port(umad_port_t * port)702d6b92ffaSHans Petter Selasky int umad_release_port(umad_port_t * port)
703d6b92ffaSHans Petter Selasky {
704d6b92ffaSHans Petter Selasky 	int r;
705d6b92ffaSHans Petter Selasky 
706d6b92ffaSHans Petter Selasky 	TRACE("port %s:%d", port->ca_name, port->portnum);
707d6b92ffaSHans Petter Selasky 	if (!port)
708d6b92ffaSHans Petter Selasky 		return -ENODEV;
709d6b92ffaSHans Petter Selasky 
710d6b92ffaSHans Petter Selasky 	if ((r = release_port(port)) < 0)
711d6b92ffaSHans Petter Selasky 		return r;
712d6b92ffaSHans Petter Selasky 
713d6b92ffaSHans Petter Selasky 	DEBUG("releasing %s:%d", port->ca_name, port->portnum);
714d6b92ffaSHans Petter Selasky 	return 0;
715d6b92ffaSHans Petter Selasky }
716d6b92ffaSHans Petter Selasky 
umad_close_port(int fd)717d6b92ffaSHans Petter Selasky int umad_close_port(int fd)
718d6b92ffaSHans Petter Selasky {
719d6b92ffaSHans Petter Selasky 	close(fd);
720d6b92ffaSHans Petter Selasky 	DEBUG("closed fd %d", fd);
721d6b92ffaSHans Petter Selasky 	return 0;
722d6b92ffaSHans Petter Selasky }
723d6b92ffaSHans Petter Selasky 
umad_get_mad(void * umad)724d6b92ffaSHans Petter Selasky void *umad_get_mad(void *umad)
725d6b92ffaSHans Petter Selasky {
726d6b92ffaSHans Petter Selasky 	return new_user_mad_api ? ((struct ib_user_mad *)umad)->data :
727d6b92ffaSHans Petter Selasky 	    (void *)&((struct ib_user_mad *)umad)->addr.pkey_index;
728d6b92ffaSHans Petter Selasky }
729d6b92ffaSHans Petter Selasky 
umad_size(void)730d6b92ffaSHans Petter Selasky size_t umad_size(void)
731d6b92ffaSHans Petter Selasky {
732d6b92ffaSHans Petter Selasky 	return new_user_mad_api ? sizeof(struct ib_user_mad) :
733d6b92ffaSHans Petter Selasky 	    sizeof(struct ib_user_mad) - 8;
734d6b92ffaSHans Petter Selasky }
735d6b92ffaSHans Petter Selasky 
umad_set_grh(void * umad,void * mad_addr)736d6b92ffaSHans Petter Selasky int umad_set_grh(void *umad, void *mad_addr)
737d6b92ffaSHans Petter Selasky {
738d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
739d6b92ffaSHans Petter Selasky 	struct ib_mad_addr *addr = mad_addr;
740d6b92ffaSHans Petter Selasky 
741d6b92ffaSHans Petter Selasky 	if (mad_addr) {
742d6b92ffaSHans Petter Selasky 		mad->addr.grh_present = 1;
743d6b92ffaSHans Petter Selasky 		mad->addr.ib_gid = addr->ib_gid;
744d6b92ffaSHans Petter Selasky 		/* The definition for umad_set_grh requires that the input be
745d6b92ffaSHans Petter Selasky 		 * in host order */
746d6b92ffaSHans Petter Selasky 		mad->addr.flow_label = htobe32((uint32_t)addr->flow_label);
747d6b92ffaSHans Petter Selasky 		mad->addr.hop_limit = addr->hop_limit;
748d6b92ffaSHans Petter Selasky 		mad->addr.traffic_class = addr->traffic_class;
749d6b92ffaSHans Petter Selasky 	} else
750d6b92ffaSHans Petter Selasky 		mad->addr.grh_present = 0;
751d6b92ffaSHans Petter Selasky 	return 0;
752d6b92ffaSHans Petter Selasky }
753d6b92ffaSHans Petter Selasky 
umad_set_pkey(void * umad,int pkey_index)754d6b92ffaSHans Petter Selasky int umad_set_pkey(void *umad, int pkey_index)
755d6b92ffaSHans Petter Selasky {
756d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
757d6b92ffaSHans Petter Selasky 
758d6b92ffaSHans Petter Selasky 	if (new_user_mad_api)
759d6b92ffaSHans Petter Selasky 		mad->addr.pkey_index = pkey_index;
760d6b92ffaSHans Petter Selasky 
761d6b92ffaSHans Petter Selasky 	return 0;
762d6b92ffaSHans Petter Selasky }
763d6b92ffaSHans Petter Selasky 
umad_get_pkey(void * umad)764d6b92ffaSHans Petter Selasky int umad_get_pkey(void *umad)
765d6b92ffaSHans Petter Selasky {
766d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
767d6b92ffaSHans Petter Selasky 
768d6b92ffaSHans Petter Selasky 	if (new_user_mad_api)
769d6b92ffaSHans Petter Selasky 		return mad->addr.pkey_index;
770d6b92ffaSHans Petter Selasky 
771d6b92ffaSHans Petter Selasky 	return 0;
772d6b92ffaSHans Petter Selasky }
773d6b92ffaSHans Petter Selasky 
umad_set_addr(void * umad,int dlid,int dqp,int sl,int qkey)774d6b92ffaSHans Petter Selasky int umad_set_addr(void *umad, int dlid, int dqp, int sl, int qkey)
775d6b92ffaSHans Petter Selasky {
776d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
777d6b92ffaSHans Petter Selasky 
778d6b92ffaSHans Petter Selasky 	TRACE("umad %p dlid %u dqp %d sl %d, qkey %x",
779d6b92ffaSHans Petter Selasky 	      umad, dlid, dqp, sl, qkey);
780d6b92ffaSHans Petter Selasky 	mad->addr.qpn = htobe32(dqp);
781d6b92ffaSHans Petter Selasky 	mad->addr.lid = htobe16(dlid);
782d6b92ffaSHans Petter Selasky 	mad->addr.qkey = htobe32(qkey);
783d6b92ffaSHans Petter Selasky 	mad->addr.sl = sl;
784d6b92ffaSHans Petter Selasky 
785d6b92ffaSHans Petter Selasky 	return 0;
786d6b92ffaSHans Petter Selasky }
787d6b92ffaSHans Petter Selasky 
umad_set_addr_net(void * umad,__be16 dlid,__be32 dqp,int sl,__be32 qkey)788d6b92ffaSHans Petter Selasky int umad_set_addr_net(void *umad, __be16 dlid, __be32 dqp, int sl, __be32 qkey)
789d6b92ffaSHans Petter Selasky {
790d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
791d6b92ffaSHans Petter Selasky 
792d6b92ffaSHans Petter Selasky 	TRACE("umad %p dlid %u dqp %d sl %d qkey %x",
793d6b92ffaSHans Petter Selasky 	      umad, be16toh(dlid), be32toh(dqp), sl, be32toh(qkey));
794d6b92ffaSHans Petter Selasky 	mad->addr.qpn = dqp;
795d6b92ffaSHans Petter Selasky 	mad->addr.lid = dlid;
796d6b92ffaSHans Petter Selasky 	mad->addr.qkey = qkey;
797d6b92ffaSHans Petter Selasky 	mad->addr.sl = sl;
798d6b92ffaSHans Petter Selasky 
799d6b92ffaSHans Petter Selasky 	return 0;
800d6b92ffaSHans Petter Selasky }
801d6b92ffaSHans Petter Selasky 
umad_send(int fd,int agentid,void * umad,int length,int timeout_ms,int retries)802d6b92ffaSHans Petter Selasky int umad_send(int fd, int agentid, void *umad, int length,
803d6b92ffaSHans Petter Selasky 	      int timeout_ms, int retries)
804d6b92ffaSHans Petter Selasky {
805d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
806d6b92ffaSHans Petter Selasky 	int n;
807d6b92ffaSHans Petter Selasky 
808d6b92ffaSHans Petter Selasky 	TRACE("fd %d agentid %d umad %p timeout %u",
809d6b92ffaSHans Petter Selasky 	      fd, agentid, umad, timeout_ms);
810d6b92ffaSHans Petter Selasky 	errno = 0;
811d6b92ffaSHans Petter Selasky 
812d6b92ffaSHans Petter Selasky 	mad->timeout_ms = timeout_ms;
813d6b92ffaSHans Petter Selasky 	mad->retries = retries;
814d6b92ffaSHans Petter Selasky 	mad->agent_id = agentid;
815d6b92ffaSHans Petter Selasky 
816d6b92ffaSHans Petter Selasky 	if (umaddebug > 1)
817d6b92ffaSHans Petter Selasky 		umad_dump(mad);
818d6b92ffaSHans Petter Selasky 
819d6b92ffaSHans Petter Selasky 	n = write(fd, mad, length + umad_size());
820d6b92ffaSHans Petter Selasky 	if (n == length + umad_size())
821d6b92ffaSHans Petter Selasky 		return 0;
822d6b92ffaSHans Petter Selasky 
823d6b92ffaSHans Petter Selasky 	DEBUG("write returned %d != sizeof umad %zu + length %d (%m)",
824d6b92ffaSHans Petter Selasky 	      n, umad_size(), length);
825d6b92ffaSHans Petter Selasky 	if (!errno)
826d6b92ffaSHans Petter Selasky 		errno = EIO;
827d6b92ffaSHans Petter Selasky 	return -EIO;
828d6b92ffaSHans Petter Selasky }
829d6b92ffaSHans Petter Selasky 
dev_poll(int fd,int timeout_ms)830d6b92ffaSHans Petter Selasky static int dev_poll(int fd, int timeout_ms)
831d6b92ffaSHans Petter Selasky {
832d6b92ffaSHans Petter Selasky 	struct pollfd ufds;
833d6b92ffaSHans Petter Selasky 	int n;
834d6b92ffaSHans Petter Selasky 
835d6b92ffaSHans Petter Selasky 	ufds.fd = fd;
836d6b92ffaSHans Petter Selasky 	ufds.events = POLLIN;
837d6b92ffaSHans Petter Selasky 
838d6b92ffaSHans Petter Selasky 	if ((n = poll(&ufds, 1, timeout_ms)) == 1)
839d6b92ffaSHans Petter Selasky 		return 0;
840d6b92ffaSHans Petter Selasky 
841d6b92ffaSHans Petter Selasky 	if (n == 0)
842d6b92ffaSHans Petter Selasky 		return -ETIMEDOUT;
843d6b92ffaSHans Petter Selasky 
844d6b92ffaSHans Petter Selasky 	return -EIO;
845d6b92ffaSHans Petter Selasky }
846d6b92ffaSHans Petter Selasky 
umad_recv(int fd,void * umad,int * length,int timeout_ms)847d6b92ffaSHans Petter Selasky int umad_recv(int fd, void *umad, int *length, int timeout_ms)
848d6b92ffaSHans Petter Selasky {
849d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
850d6b92ffaSHans Petter Selasky 	int n;
851d6b92ffaSHans Petter Selasky 
852d6b92ffaSHans Petter Selasky 	errno = 0;
853d6b92ffaSHans Petter Selasky 	TRACE("fd %d umad %p timeout %u", fd, umad, timeout_ms);
854d6b92ffaSHans Petter Selasky 
855d6b92ffaSHans Petter Selasky 	if (!umad || !length) {
856d6b92ffaSHans Petter Selasky 		errno = EINVAL;
857d6b92ffaSHans Petter Selasky 		return -EINVAL;
858d6b92ffaSHans Petter Selasky 	}
859d6b92ffaSHans Petter Selasky 
860d6b92ffaSHans Petter Selasky 	if (timeout_ms && (n = dev_poll(fd, timeout_ms)) < 0) {
861d6b92ffaSHans Petter Selasky 		if (!errno)
862d6b92ffaSHans Petter Selasky 			errno = -n;
863d6b92ffaSHans Petter Selasky 		return n;
864d6b92ffaSHans Petter Selasky 	}
865d6b92ffaSHans Petter Selasky 
866d6b92ffaSHans Petter Selasky 	n = read(fd, umad, umad_size() + *length);
867d6b92ffaSHans Petter Selasky 
868d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(umad, umad_size() + *length);
869d6b92ffaSHans Petter Selasky 
870d6b92ffaSHans Petter Selasky 	if ((n >= 0) && (n <= umad_size() + *length)) {
871d6b92ffaSHans Petter Selasky 		DEBUG("mad received by agent %d length %d", mad->agent_id, n);
872d6b92ffaSHans Petter Selasky 		if (n > umad_size())
873d6b92ffaSHans Petter Selasky 			*length = n - umad_size();
874d6b92ffaSHans Petter Selasky 		else
875d6b92ffaSHans Petter Selasky 			*length = 0;
876d6b92ffaSHans Petter Selasky 		return mad->agent_id;
877d6b92ffaSHans Petter Selasky 	}
878d6b92ffaSHans Petter Selasky 
879d6b92ffaSHans Petter Selasky 	if (n == -EWOULDBLOCK) {
880d6b92ffaSHans Petter Selasky 		if (!errno)
881d6b92ffaSHans Petter Selasky 			errno = EWOULDBLOCK;
882d6b92ffaSHans Petter Selasky 		return n;
883d6b92ffaSHans Petter Selasky 	}
884d6b92ffaSHans Petter Selasky 
885d6b92ffaSHans Petter Selasky 	DEBUG("read returned %zu > sizeof umad %zu + length %d (%m)",
886d6b92ffaSHans Petter Selasky 	      mad->length - umad_size(), umad_size(), *length);
887d6b92ffaSHans Petter Selasky 
888d6b92ffaSHans Petter Selasky 	*length = mad->length - umad_size();
889d6b92ffaSHans Petter Selasky 	if (!errno)
890d6b92ffaSHans Petter Selasky 		errno = EIO;
891d6b92ffaSHans Petter Selasky 	return -errno;
892d6b92ffaSHans Petter Selasky }
893d6b92ffaSHans Petter Selasky 
umad_poll(int fd,int timeout_ms)894d6b92ffaSHans Petter Selasky int umad_poll(int fd, int timeout_ms)
895d6b92ffaSHans Petter Selasky {
896d6b92ffaSHans Petter Selasky 	TRACE("fd %d timeout %u", fd, timeout_ms);
897d6b92ffaSHans Petter Selasky 	return dev_poll(fd, timeout_ms);
898d6b92ffaSHans Petter Selasky }
899d6b92ffaSHans Petter Selasky 
umad_get_fd(int fd)900d6b92ffaSHans Petter Selasky int umad_get_fd(int fd)
901d6b92ffaSHans Petter Selasky {
902d6b92ffaSHans Petter Selasky 	TRACE("fd %d", fd);
903d6b92ffaSHans Petter Selasky 	return fd;
904d6b92ffaSHans Petter Selasky }
905d6b92ffaSHans Petter Selasky 
umad_register_oui(int fd,int mgmt_class,uint8_t rmpp_version,uint8_t oui[3],long method_mask[])906d6b92ffaSHans Petter Selasky int umad_register_oui(int fd, int mgmt_class, uint8_t rmpp_version,
907d6b92ffaSHans Petter Selasky 		      uint8_t oui[3], long method_mask[])
908d6b92ffaSHans Petter Selasky {
909d6b92ffaSHans Petter Selasky 	struct ib_user_mad_reg_req req;
910d6b92ffaSHans Petter Selasky 
911d6b92ffaSHans Petter Selasky 	TRACE("fd %d mgmt_class %u rmpp_version %d oui 0x%x%x%x method_mask %p",
912d6b92ffaSHans Petter Selasky 	      fd, mgmt_class, (int)rmpp_version, (int)oui[0], (int)oui[1],
913d6b92ffaSHans Petter Selasky 	      (int)oui[2], method_mask);
914d6b92ffaSHans Petter Selasky 
915d6b92ffaSHans Petter Selasky 	if (mgmt_class < 0x30 || mgmt_class > 0x4f) {
916d6b92ffaSHans Petter Selasky 		DEBUG("mgmt class %d not in vendor range 2", mgmt_class);
917d6b92ffaSHans Petter Selasky 		return -EINVAL;
918d6b92ffaSHans Petter Selasky 	}
919d6b92ffaSHans Petter Selasky 
920d6b92ffaSHans Petter Selasky 	req.qpn = 1;
921d6b92ffaSHans Petter Selasky 	req.mgmt_class = mgmt_class;
922d6b92ffaSHans Petter Selasky 	req.mgmt_class_version = 1;
923d6b92ffaSHans Petter Selasky 	memcpy(req.oui, oui, sizeof req.oui);
924d6b92ffaSHans Petter Selasky 	req.rmpp_version = rmpp_version;
925d6b92ffaSHans Petter Selasky 
926d6b92ffaSHans Petter Selasky 	if (method_mask)
927d6b92ffaSHans Petter Selasky 		memcpy(req.method_mask, method_mask, sizeof req.method_mask);
928d6b92ffaSHans Petter Selasky 	else
929d6b92ffaSHans Petter Selasky 		memset(req.method_mask, 0, sizeof req.method_mask);
930d6b92ffaSHans Petter Selasky 
931d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req);
932d6b92ffaSHans Petter Selasky 
933d6b92ffaSHans Petter Selasky 	if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) {
934d6b92ffaSHans Petter Selasky 		DEBUG
935d6b92ffaSHans Petter Selasky 		    ("fd %d registered to use agent %d qp %d class 0x%x oui %p",
936d6b92ffaSHans Petter Selasky 		     fd, req.id, req.qpn, req.mgmt_class, oui);
937d6b92ffaSHans Petter Selasky 		return req.id;	/* return agentid */
938d6b92ffaSHans Petter Selasky 	}
939d6b92ffaSHans Petter Selasky 
940d6b92ffaSHans Petter Selasky 	DEBUG("fd %d registering qp %d class 0x%x version %d oui %p failed: %m",
941d6b92ffaSHans Petter Selasky 	      fd, req.qpn, req.mgmt_class, req.mgmt_class_version, oui);
942d6b92ffaSHans Petter Selasky 	return -EPERM;
943d6b92ffaSHans Petter Selasky }
944d6b92ffaSHans Petter Selasky 
umad_register(int fd,int mgmt_class,int mgmt_version,uint8_t rmpp_version,long method_mask[])945d6b92ffaSHans Petter Selasky int umad_register(int fd, int mgmt_class, int mgmt_version,
946d6b92ffaSHans Petter Selasky 		  uint8_t rmpp_version, long method_mask[])
947d6b92ffaSHans Petter Selasky {
948d6b92ffaSHans Petter Selasky 	struct ib_user_mad_reg_req req;
949d6b92ffaSHans Petter Selasky 	__be32 oui = htobe32(IB_OPENIB_OUI);
950d6b92ffaSHans Petter Selasky 	int qp;
951d6b92ffaSHans Petter Selasky 
952d6b92ffaSHans Petter Selasky 	TRACE
953d6b92ffaSHans Petter Selasky 	    ("fd %d mgmt_class %u mgmt_version %u rmpp_version %d method_mask %p",
954d6b92ffaSHans Petter Selasky 	     fd, mgmt_class, mgmt_version, rmpp_version, method_mask);
955d6b92ffaSHans Petter Selasky 
956d6b92ffaSHans Petter Selasky 	req.qpn = qp = (mgmt_class == 0x1 || mgmt_class == 0x81) ? 0 : 1;
957d6b92ffaSHans Petter Selasky 	req.mgmt_class = mgmt_class;
958d6b92ffaSHans Petter Selasky 	req.mgmt_class_version = mgmt_version;
959d6b92ffaSHans Petter Selasky 	req.rmpp_version = rmpp_version;
960d6b92ffaSHans Petter Selasky 
961d6b92ffaSHans Petter Selasky 	if (method_mask)
962d6b92ffaSHans Petter Selasky 		memcpy(req.method_mask, method_mask, sizeof req.method_mask);
963d6b92ffaSHans Petter Selasky 	else
964d6b92ffaSHans Petter Selasky 		memset(req.method_mask, 0, sizeof req.method_mask);
965d6b92ffaSHans Petter Selasky 
966d6b92ffaSHans Petter Selasky 	memcpy(&req.oui, (char *)&oui + 1, sizeof req.oui);
967d6b92ffaSHans Petter Selasky 
968d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req);
969d6b92ffaSHans Petter Selasky 
970d6b92ffaSHans Petter Selasky 	if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) {
971d6b92ffaSHans Petter Selasky 		DEBUG("fd %d registered to use agent %d qp %d", fd, req.id, qp);
972d6b92ffaSHans Petter Selasky 		return req.id;	/* return agentid */
973d6b92ffaSHans Petter Selasky 	}
974d6b92ffaSHans Petter Selasky 
975d6b92ffaSHans Petter Selasky 	DEBUG("fd %d registering qp %d class 0x%x version %d failed: %m",
976d6b92ffaSHans Petter Selasky 	      fd, qp, mgmt_class, mgmt_version);
977d6b92ffaSHans Petter Selasky 	return -EPERM;
978d6b92ffaSHans Petter Selasky }
979d6b92ffaSHans Petter Selasky 
umad_register2(int port_fd,struct umad_reg_attr * attr,uint32_t * agent_id)980d6b92ffaSHans Petter Selasky int umad_register2(int port_fd, struct umad_reg_attr *attr, uint32_t *agent_id)
981d6b92ffaSHans Petter Selasky {
982d6b92ffaSHans Petter Selasky 	struct ib_user_mad_reg_req2 req;
983d6b92ffaSHans Petter Selasky 	int rc;
984d6b92ffaSHans Petter Selasky 
985d6b92ffaSHans Petter Selasky 	if (!attr || !agent_id)
986d6b92ffaSHans Petter Selasky 		return EINVAL;
987d6b92ffaSHans Petter Selasky 
988d6b92ffaSHans Petter Selasky 	TRACE("fd %d mgmt_class %u mgmt_class_version %u flags 0x%08x "
989d6b92ffaSHans Petter Selasky 	      "method_mask 0x%016" PRIx64 " %016" PRIx64
990d6b92ffaSHans Petter Selasky 	      "oui 0x%06x rmpp_version %u ",
991d6b92ffaSHans Petter Selasky 	      port_fd, attr->mgmt_class, attr->mgmt_class_version,
992d6b92ffaSHans Petter Selasky 	      attr->flags, attr->method_mask[0], attr->method_mask[1],
993d6b92ffaSHans Petter Selasky 	      attr->oui, attr->rmpp_version);
994d6b92ffaSHans Petter Selasky 
995d6b92ffaSHans Petter Selasky 	if (attr->mgmt_class >= 0x30 && attr->mgmt_class <= 0x4f &&
996d6b92ffaSHans Petter Selasky 	    ((attr->oui & 0x00ffffff) == 0 || (attr->oui & 0xff000000) != 0)) {
997d6b92ffaSHans Petter Selasky 		DEBUG("mgmt class %d is in vendor range 2 but oui (0x%08x) is invalid",
998d6b92ffaSHans Petter Selasky 		      attr->mgmt_class, attr->oui);
999d6b92ffaSHans Petter Selasky 		return EINVAL;
1000d6b92ffaSHans Petter Selasky 	}
1001d6b92ffaSHans Petter Selasky 
1002d6b92ffaSHans Petter Selasky 	memset(&req, 0, sizeof(req));
1003d6b92ffaSHans Petter Selasky 
1004d6b92ffaSHans Petter Selasky 	req.mgmt_class = attr->mgmt_class;
1005d6b92ffaSHans Petter Selasky 	req.mgmt_class_version = attr->mgmt_class_version;
1006d6b92ffaSHans Petter Selasky 	req.qpn = (attr->mgmt_class == 0x1 || attr->mgmt_class == 0x81) ? 0 : 1;
1007d6b92ffaSHans Petter Selasky 	req.flags = attr->flags;
1008d6b92ffaSHans Petter Selasky 	memcpy(req.method_mask, attr->method_mask, sizeof req.method_mask);
1009d6b92ffaSHans Petter Selasky 	req.oui = attr->oui;
1010d6b92ffaSHans Petter Selasky 	req.rmpp_version = attr->rmpp_version;
1011d6b92ffaSHans Petter Selasky 
1012d6b92ffaSHans Petter Selasky 	VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req);
1013d6b92ffaSHans Petter Selasky 
1014d6b92ffaSHans Petter Selasky 	if ((rc = ioctl(port_fd, IB_USER_MAD_REGISTER_AGENT2, (void *)&req)) == 0) {
1015d6b92ffaSHans Petter Selasky 		DEBUG("fd %d registered to use agent %d qp %d class 0x%x oui 0x%06x",
1016d6b92ffaSHans Petter Selasky 		      port_fd, req.id, req.qpn, req.mgmt_class, attr->oui);
1017d6b92ffaSHans Petter Selasky 		*agent_id = req.id;
1018d6b92ffaSHans Petter Selasky 		return 0;
1019d6b92ffaSHans Petter Selasky 	}
1020d6b92ffaSHans Petter Selasky 
1021d6b92ffaSHans Petter Selasky 	if (errno == ENOTTY || errno == EINVAL) {
1022d6b92ffaSHans Petter Selasky 
1023d6b92ffaSHans Petter Selasky 		TRACE("no kernel support for registration flags");
1024d6b92ffaSHans Petter Selasky 		req.flags = 0;
1025d6b92ffaSHans Petter Selasky 
1026d6b92ffaSHans Petter Selasky 		if (attr->flags == 0) {
1027d6b92ffaSHans Petter Selasky 			struct ib_user_mad_reg_req req_v1;
1028d6b92ffaSHans Petter Selasky 
1029d6b92ffaSHans Petter Selasky 			TRACE("attempting original register ioctl");
1030d6b92ffaSHans Petter Selasky 
1031d6b92ffaSHans Petter Selasky 			memset(&req_v1, 0, sizeof(req_v1));
1032d6b92ffaSHans Petter Selasky 			req_v1.mgmt_class = req.mgmt_class;
1033d6b92ffaSHans Petter Selasky 			req_v1.mgmt_class_version = req.mgmt_class_version;
1034d6b92ffaSHans Petter Selasky 			req_v1.qpn = req.qpn;
1035d6b92ffaSHans Petter Selasky 			req_v1.rmpp_version = req.rmpp_version;
1036d6b92ffaSHans Petter Selasky 			req_v1.oui[0] = (req.oui & 0xff0000) >> 16;
1037d6b92ffaSHans Petter Selasky 			req_v1.oui[1] = (req.oui & 0x00ff00) >> 8;
1038d6b92ffaSHans Petter Selasky 			req_v1.oui[2] =  req.oui & 0x0000ff;
1039d6b92ffaSHans Petter Selasky 
1040d6b92ffaSHans Petter Selasky 			memcpy(req_v1.method_mask, req.method_mask, sizeof req_v1.method_mask);
1041d6b92ffaSHans Petter Selasky 
1042d6b92ffaSHans Petter Selasky 			if ((rc = ioctl(port_fd, IB_USER_MAD_REGISTER_AGENT,
1043d6b92ffaSHans Petter Selasky 					(void *)&req_v1)) == 0) {
1044d6b92ffaSHans Petter Selasky 				DEBUG("fd %d registered to use agent %d qp %d class 0x%x oui 0x%06x",
1045d6b92ffaSHans Petter Selasky 				      port_fd, req_v1.id, req_v1.qpn, req_v1.mgmt_class, attr->oui);
1046d6b92ffaSHans Petter Selasky 				*agent_id = req_v1.id;
1047d6b92ffaSHans Petter Selasky 				return 0;
1048d6b92ffaSHans Petter Selasky 			}
1049d6b92ffaSHans Petter Selasky 		}
1050d6b92ffaSHans Petter Selasky 	}
1051d6b92ffaSHans Petter Selasky 
1052d6b92ffaSHans Petter Selasky 	rc = errno;
1053d6b92ffaSHans Petter Selasky 	attr->flags = req.flags;
1054d6b92ffaSHans Petter Selasky 
1055d6b92ffaSHans Petter Selasky 	DEBUG("fd %d registering qp %d class 0x%x version %d "
1056d6b92ffaSHans Petter Selasky 	      "oui 0x%06x failed flags returned 0x%x : %m",
1057d6b92ffaSHans Petter Selasky 	      port_fd, req.qpn, req.mgmt_class, req.mgmt_class_version,
1058d6b92ffaSHans Petter Selasky 	      attr->oui, req.flags);
1059d6b92ffaSHans Petter Selasky 
1060d6b92ffaSHans Petter Selasky 	return rc;
1061d6b92ffaSHans Petter Selasky }
1062d6b92ffaSHans Petter Selasky 
umad_unregister(int fd,int agentid)1063d6b92ffaSHans Petter Selasky int umad_unregister(int fd, int agentid)
1064d6b92ffaSHans Petter Selasky {
1065d6b92ffaSHans Petter Selasky 	TRACE("fd %d unregistering agent %d", fd, agentid);
1066d6b92ffaSHans Petter Selasky 	return ioctl(fd, IB_USER_MAD_UNREGISTER_AGENT, &agentid);
1067d6b92ffaSHans Petter Selasky }
1068d6b92ffaSHans Petter Selasky 
umad_status(void * umad)1069d6b92ffaSHans Petter Selasky int umad_status(void *umad)
1070d6b92ffaSHans Petter Selasky {
1071d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
1072d6b92ffaSHans Petter Selasky 
1073d6b92ffaSHans Petter Selasky 	return mad->status;
1074d6b92ffaSHans Petter Selasky }
1075d6b92ffaSHans Petter Selasky 
umad_get_mad_addr(void * umad)1076d6b92ffaSHans Petter Selasky ib_mad_addr_t *umad_get_mad_addr(void *umad)
1077d6b92ffaSHans Petter Selasky {
1078d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
1079d6b92ffaSHans Petter Selasky 
1080d6b92ffaSHans Petter Selasky 	return &mad->addr;
1081d6b92ffaSHans Petter Selasky }
1082d6b92ffaSHans Petter Selasky 
umad_debug(int level)1083d6b92ffaSHans Petter Selasky int umad_debug(int level)
1084d6b92ffaSHans Petter Selasky {
1085d6b92ffaSHans Petter Selasky 	if (level >= 0)
1086d6b92ffaSHans Petter Selasky 		umaddebug = level;
1087d6b92ffaSHans Petter Selasky 	return umaddebug;
1088d6b92ffaSHans Petter Selasky }
1089d6b92ffaSHans Petter Selasky 
umad_addr_dump(ib_mad_addr_t * addr)1090d6b92ffaSHans Petter Selasky void umad_addr_dump(ib_mad_addr_t * addr)
1091d6b92ffaSHans Petter Selasky {
1092d6b92ffaSHans Petter Selasky #define HEX(x)  ((x) < 10 ? '0' + (x) : 'a' + ((x) -10))
1093d6b92ffaSHans Petter Selasky 	char gid_str[64];
1094d6b92ffaSHans Petter Selasky 	int i;
1095d6b92ffaSHans Petter Selasky 
1096d6b92ffaSHans Petter Selasky 	for (i = 0; i < sizeof addr->gid; i++) {
1097d6b92ffaSHans Petter Selasky 		gid_str[i * 2] = HEX(addr->gid[i] >> 4);
1098d6b92ffaSHans Petter Selasky 		gid_str[i * 2 + 1] = HEX(addr->gid[i] & 0xf);
1099d6b92ffaSHans Petter Selasky 	}
1100d6b92ffaSHans Petter Selasky 	gid_str[i * 2] = 0;
1101d6b92ffaSHans Petter Selasky 	IBWARN("qpn %d qkey 0x%x lid %u sl %d\n"
1102d6b92ffaSHans Petter Selasky 	       "grh_present %d gid_index %d hop_limit %d traffic_class %d flow_label 0x%x pkey_index 0x%x\n"
1103d6b92ffaSHans Petter Selasky 	       "Gid 0x%s",
1104d6b92ffaSHans Petter Selasky 	       be32toh(addr->qpn), be32toh(addr->qkey), be16toh(addr->lid), addr->sl,
1105d6b92ffaSHans Petter Selasky 	       addr->grh_present, (int)addr->gid_index, (int)addr->hop_limit,
1106d6b92ffaSHans Petter Selasky 	       (int)addr->traffic_class, addr->flow_label, addr->pkey_index,
1107d6b92ffaSHans Petter Selasky 	       gid_str);
1108d6b92ffaSHans Petter Selasky }
1109d6b92ffaSHans Petter Selasky 
umad_dump(void * umad)1110d6b92ffaSHans Petter Selasky void umad_dump(void *umad)
1111d6b92ffaSHans Petter Selasky {
1112d6b92ffaSHans Petter Selasky 	struct ib_user_mad *mad = umad;
1113d6b92ffaSHans Petter Selasky 
1114d6b92ffaSHans Petter Selasky 	IBWARN("agent id %d status %x timeout %d",
1115d6b92ffaSHans Petter Selasky 	       mad->agent_id, mad->status, mad->timeout_ms);
1116d6b92ffaSHans Petter Selasky 	umad_addr_dump(&mad->addr);
1117d6b92ffaSHans Petter Selasky }
1118