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
69typedef 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
82int umaddebug = 0;
83
84#define UMAD_DEV_FILE_SZ	256
85
86static char *def_ca_name = "mthca0";
87static int def_ca_port = 1;
88
89static unsigned abi_version;
90static unsigned new_user_mad_api;
91
92/*************************************
93 * Port
94 */
95static int
96find_cached_ca(char *ca_name, umad_ca_t *ca)
97{
98	return 0;	/* caching not implemented yet */
99}
100
101static int
102put_ca(umad_ca_t *ca)
103{
104	return 0;	/* caching not implemented yet */
105}
106
107static int
108release_port(umad_port_t *port)
109{
110	free(port->pkeys);
111	port->pkeys = NULL;
112	port->pkeys_size = 0;
113	return 0;
114}
115
116static 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
124static int
125get_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
193clean:
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
204static int
205release_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 */
225static int
226resolve_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
288static char *
289resolve_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
346static int
347get_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
429clean:
430	for (i = 0; i < r; i++)
431		free(namelist[i]);
432	free(namelist);
433error:
434#ifdef __linux__
435	closedir(dir);
436#endif
437	release_ca(ca);
438
439	return ret;
440}
441
442static int
443umad_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
459static int
460dev_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
485int
486umad_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
502int
503umad_done(void)
504{
505	TRACE("umad_done");
506	/* FIXME - verify that all ports are closed */
507	return 0;
508}
509
510static 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
523int
524umad_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
554int
555umad_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
583int
584umad_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
601int
602umad_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
634int
635umad_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
653int
654umad_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
669int
670umad_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
685int
686umad_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
701int
702umad_close_port(int fd)
703{
704	close(fd);
705	DEBUG("closed fd %d", fd);
706	return 0;
707}
708
709void *
710umad_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
716size_t
717umad_size(void)
718{
719	return new_user_mad_api ? sizeof (struct ib_user_mad) :
720		sizeof(struct ib_user_mad) - 8;
721}
722
723int
724umad_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
740int
741umad_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
751int
752umad_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
762int
763umad_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
777int
778umad_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
792int
793umad_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
821static int
822dev_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
839int
840umad_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
887int
888umad_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
894int
895umad_get_fd(int fd)
896{
897	TRACE("fd %d", fd);
898	return fd;
899}
900
901int
902umad_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
940int
941umad_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
976int
977umad_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
983int
984umad_status(void *umad)
985{
986	struct ib_user_mad *mad = umad;
987
988	return mad->status;
989}
990
991ib_mad_addr_t *
992umad_get_mad_addr(void *umad)
993{
994	struct ib_user_mad *mad = umad;
995
996	return &mad->addr;
997}
998
999int
1000umad_debug(int level)
1001{
1002	if (level >= 0)
1003		umaddebug = level;
1004	return umaddebug;
1005}
1006
1007void
1008umad_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
1028void
1029umad_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