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