1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.
3219820Sjeff *
4219820Sjeff * This software is available to you under a choice of one of two
5219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
6219820Sjeff * General Public License (GPL) Version 2, available from the file
7219820Sjeff * COPYING in the main directory of this source tree, or the
8219820Sjeff * OpenIB.org BSD license below:
9219820Sjeff *
10219820Sjeff *     Redistribution and use in source and binary forms, with or
11219820Sjeff *     without modification, are permitted provided that the following
12219820Sjeff *     conditions are met:
13219820Sjeff *
14219820Sjeff *      - Redistributions of source code must retain the above
15219820Sjeff *        copyright notice, this list of conditions and the following
16219820Sjeff *        disclaimer.
17219820Sjeff *
18219820Sjeff *      - Redistributions in binary form must reproduce the above
19219820Sjeff *        copyright notice, this list of conditions and the following
20219820Sjeff *        disclaimer in the documentation and/or other materials
21219820Sjeff *        provided with the distribution.
22219820Sjeff *
23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30219820Sjeff * SOFTWARE.
31219820Sjeff *
32219820Sjeff */
33219820Sjeff
34219820Sjeff#if HAVE_CONFIG_H
35219820Sjeff#  include <config.h>
36219820Sjeff#endif /* HAVE_CONFIG_H */
37219820Sjeff
38219820Sjeff#include <sys/poll.h>
39219820Sjeff#include <unistd.h>
40219820Sjeff#include <string.h>
41219820Sjeff#include <errno.h>
42219820Sjeff#include <sys/types.h>
43219820Sjeff#include <sys/stat.h>
44219820Sjeff#include <fcntl.h>
45219820Sjeff#include <sys/ioctl.h>
46219820Sjeff#include <netinet/in.h>
47219820Sjeff#include <dirent.h>
48219820Sjeff#include <stdlib.h>
49219820Sjeff#include <ctype.h>
50219820Sjeff
51219820Sjeff#include "umad.h"
52219820Sjeff
53219820Sjeff#define IB_OPENIB_OUI                 (0x001405)
54219820Sjeff
55219820Sjeff#ifdef HAVE_VALGRIND_MEMCHECK_H
56219820Sjeff
57219820Sjeff#  include <valgrind/memcheck.h>
58219820Sjeff
59219820Sjeff#  ifndef VALGRIND_MAKE_MEM_DEFINED
60219820Sjeff#    warning "Valgrind support requested, but VALGRIND_MAKE_MEM_DEFINED not available"
61219820Sjeff#  endif
62219820Sjeff
63219820Sjeff#endif /* HAVE_VALGRIND_MEMCHECK_H */
64219820Sjeff
65219820Sjeff#ifndef VALGRIND_MAKE_MEM_DEFINED
66219820Sjeff#  define VALGRIND_MAKE_MEM_DEFINED(addr,len)
67219820Sjeff#endif
68219820Sjeff
69219820Sjefftypedef struct ib_user_mad_reg_req {
70219820Sjeff	uint32_t id;
71219820Sjeff	uint32_t method_mask[4];
72219820Sjeff	uint8_t  qpn;
73219820Sjeff	uint8_t  mgmt_class;
74219820Sjeff	uint8_t  mgmt_class_version;
75219820Sjeff	uint8_t  oui[3];
76219820Sjeff	uint8_t  rmpp_version;
77219820Sjeff} ib_user_mad_reg_req_t;
78219820Sjeff
79219820Sjeff#define TRACE	if (umaddebug)	IBWARN
80219820Sjeff#define DEBUG	if (umaddebug)	IBWARN
81219820Sjeff
82219820Sjeffint umaddebug = 0;
83219820Sjeff
84219820Sjeff#define UMAD_DEV_FILE_SZ	256
85219820Sjeff
86219820Sjeffstatic char *def_ca_name = "mthca0";
87219820Sjeffstatic int def_ca_port = 1;
88219820Sjeff
89219820Sjeffstatic unsigned abi_version;
90219820Sjeffstatic unsigned new_user_mad_api;
91219820Sjeff
92219820Sjeff/*************************************
93219820Sjeff * Port
94219820Sjeff */
95219820Sjeffstatic int
96219820Sjefffind_cached_ca(char *ca_name, umad_ca_t *ca)
97219820Sjeff{
98219820Sjeff	return 0;	/* caching not implemented yet */
99219820Sjeff}
100219820Sjeff
101219820Sjeffstatic int
102219820Sjeffput_ca(umad_ca_t *ca)
103219820Sjeff{
104219820Sjeff	return 0;	/* caching not implemented yet */
105219820Sjeff}
106219820Sjeff
107219820Sjeffstatic int
108219820Sjeffrelease_port(umad_port_t *port)
109219820Sjeff{
110219820Sjeff	free(port->pkeys);
111219820Sjeff	port->pkeys = NULL;
112219820Sjeff	port->pkeys_size = 0;
113219820Sjeff	return 0;
114219820Sjeff}
115219820Sjeff
116219820Sjeffstatic int check_for_digit_name(const struct dirent *dent)
117219820Sjeff{
118219820Sjeff	const char *p = dent->d_name;
119219820Sjeff	while (*p && isdigit(*p))
120219820Sjeff		p++;
121219820Sjeff	return *p ? 0 : 1;
122219820Sjeff}
123219820Sjeff
124219820Sjeffstatic int
125219820Sjeffget_port(char *ca_name, char *dir, int portnum, umad_port_t *port)
126219820Sjeff{
127219820Sjeff	char port_dir[256];
128219820Sjeff	uint8_t gid[16];
129219820Sjeff	struct dirent **namelist = NULL;
130219820Sjeff	int i, len, ret = 0;
131219820Sjeff
132219820Sjeff	strncpy(port->ca_name, ca_name, sizeof port->ca_name - 1);
133219820Sjeff	port->portnum = portnum;
134219820Sjeff	port->pkeys = NULL;
135219820Sjeff
136219820Sjeff	len = snprintf(port_dir, sizeof(port_dir), "%s/%d", dir, portnum);
137219820Sjeff	if (len < 0 || len > sizeof(port_dir))
138219820Sjeff		goto clean;
139219820Sjeff
140219820Sjeff	if (sys_read_uint(port_dir, SYS_PORT_LMC, &port->lmc) < 0)
141219820Sjeff		goto clean;
142219820Sjeff	if (sys_read_uint(port_dir, SYS_PORT_SMLID, &port->sm_lid) < 0)
143219820Sjeff		goto clean;
144219820Sjeff	if (sys_read_uint(port_dir, SYS_PORT_SMSL, &port->sm_sl) < 0)
145219820Sjeff		goto clean;
146219820Sjeff	if (sys_read_uint(port_dir, SYS_PORT_LID, &port->base_lid) < 0)
147219820Sjeff		goto clean;
148219820Sjeff	if (sys_read_uint(port_dir, SYS_PORT_STATE, &port->state) < 0)
149219820Sjeff		goto clean;
150219820Sjeff	if (sys_read_uint(port_dir, SYS_PORT_PHY_STATE, &port->phys_state) < 0)
151219820Sjeff		goto clean;
152219820Sjeff	if (sys_read_uint(port_dir, SYS_PORT_RATE, &port->rate) < 0)
153219820Sjeff		goto clean;
154219820Sjeff	if (sys_read_uint64(port_dir, SYS_PORT_CAPMASK, &port->capmask) < 0)
155219820Sjeff		goto clean;
156219820Sjeff
157219820Sjeff	port->capmask = htonl(port->capmask);
158219820Sjeff
159219820Sjeff	if (sys_read_gid(port_dir, SYS_PORT_GID, gid) < 0)
160219820Sjeff		goto clean;
161219820Sjeff
162219820Sjeff	memcpy(&port->gid_prefix, gid, sizeof port->gid_prefix);
163219820Sjeff	memcpy(&port->port_guid, gid + 8, sizeof port->port_guid);
164219820Sjeff
165219820Sjeff	snprintf(port_dir + len, sizeof(port_dir) - len, "/pkeys");
166219820Sjeff	ret = sys_scandir(port_dir, &namelist, check_for_digit_name, NULL);
167219820Sjeff	if (ret <= 0) {
168219820Sjeff		IBWARN("no pkeys found for %s:%u (at dir %s)...",
169219820Sjeff		       port->ca_name, port->portnum, port_dir);
170219820Sjeff		goto clean;
171219820Sjeff	}
172219820Sjeff	port->pkeys = calloc(ret, sizeof(port->pkeys[0]));
173219820Sjeff	if (!port->pkeys) {
174219820Sjeff		IBWARN("get_port: calloc failed: %s", strerror(errno));
175219820Sjeff		goto clean;
176219820Sjeff	}
177219820Sjeff	for (i = 0; i < ret ; i++) {
178219820Sjeff		unsigned idx, val;
179219820Sjeff		idx = strtoul(namelist[i]->d_name, NULL, 0);
180219820Sjeff		sys_read_uint(port_dir, namelist[i]->d_name, &val);
181219820Sjeff		port->pkeys[idx] = val;
182219820Sjeff		free(namelist[i]);
183219820Sjeff	}
184219820Sjeff	port->pkeys_size = ret;
185219820Sjeff	free(namelist);
186219820Sjeff	namelist = NULL;
187219820Sjeff	port_dir[len] = '\0';
188219820Sjeff
189219820Sjeff	/* FIXME: handle gids */
190219820Sjeff
191219820Sjeff	return 0;
192219820Sjeff
193219820Sjeffclean:
194219820Sjeff	if (namelist) {
195219820Sjeff		for (i = 0; i < ret ; i++)
196219820Sjeff			free(namelist[i]);
197219820Sjeff		free(namelist);
198219820Sjeff	}
199219820Sjeff	if (port->pkeys)
200219820Sjeff		free(port->pkeys);
201219820Sjeff	return -EIO;
202219820Sjeff}
203219820Sjeff
204219820Sjeffstatic int
205219820Sjeffrelease_ca(umad_ca_t *ca)
206219820Sjeff{
207219820Sjeff	int i;
208219820Sjeff
209219820Sjeff	for (i = 0; i <= ca->numports; i++) {
210219820Sjeff		if (!ca->ports[i])
211219820Sjeff			continue;
212219820Sjeff		release_port(ca->ports[i]);
213219820Sjeff		free(ca->ports[i]);
214219820Sjeff		ca->ports[i] = 0;
215219820Sjeff	}
216219820Sjeff	return 0;
217219820Sjeff}
218219820Sjeff
219219820Sjeff/*
220219820Sjeff * if *port > 0, check ca[port] state. Otherwise set *port to
221219820Sjeff * the first port that is active, and if such is not found, to
222219820Sjeff * the first port that is link up and if none are linkup, then
223219820Sjeff * the first port that is not disabled.  Otherwise return -1.
224219820Sjeff */
225219820Sjeffstatic int
226219820Sjeffresolve_ca_port(char *ca_name, int *port)
227219820Sjeff{
228219820Sjeff	umad_ca_t ca;
229219820Sjeff	int active = -1, up = -1;
230219820Sjeff	int i;
231219820Sjeff
232219820Sjeff	TRACE("checking ca '%s'", ca_name);
233219820Sjeff
234219820Sjeff	if (umad_get_ca(ca_name, &ca) < 0)
235219820Sjeff		return -1;
236219820Sjeff
237219820Sjeff	if (ca.node_type == 2) {
238219820Sjeff		*port = 0;	/* switch sma port 0 */
239219820Sjeff		return 1;
240219820Sjeff	}
241219820Sjeff
242219820Sjeff	if (*port > 0) {	/* check only the port the user wants */
243219820Sjeff		if (*port > ca.numports)
244219820Sjeff			return -1;
245219820Sjeff		if (!ca.ports[*port])
246219820Sjeff			return -1;
247219820Sjeff		if (ca.ports[*port]->state == 4)
248219820Sjeff			return 1;
249219820Sjeff		if (ca.ports[*port]->phys_state != 3)
250219820Sjeff			return 0;
251219820Sjeff		return -1;
252219820Sjeff	}
253219820Sjeff
254219820Sjeff	for (i = 0; i <= ca.numports; i++) {
255219820Sjeff		DEBUG("checking port %d", i);
256219820Sjeff		if (!ca.ports[i])
257219820Sjeff			continue;
258219820Sjeff		if (up < 0 && ca.ports[i]->phys_state == 5)
259219820Sjeff			up = *port = i;
260219820Sjeff		if (ca.ports[i]->state == 4) {
261219820Sjeff			active = *port = i;
262219820Sjeff			DEBUG("found active port %d", i);
263219820Sjeff			break;
264219820Sjeff		}
265219820Sjeff	}
266219820Sjeff
267219820Sjeff	if (active == -1 && up == -1) { /* no active or linkup port found */
268219820Sjeff		for (i = 0; i <= ca.numports; i++) {
269219820Sjeff			DEBUG("checking port %d", i);
270219820Sjeff			if (!ca.ports[i])
271219820Sjeff				continue;
272219820Sjeff			if (ca.ports[i]->phys_state != 3) {
273219820Sjeff				up = *port = i;
274219820Sjeff				break;
275219820Sjeff			}
276219820Sjeff		}
277219820Sjeff	}
278219820Sjeff
279219820Sjeff	release_ca(&ca);
280219820Sjeff
281219820Sjeff	if (active >= 0)
282219820Sjeff		return 1;
283219820Sjeff	if (up >= 0)
284219820Sjeff		return 0;
285219820Sjeff	return -1;
286219820Sjeff}
287219820Sjeff
288219820Sjeffstatic char *
289219820Sjeffresolve_ca_name(char *ca_name, int *best_port)
290219820Sjeff{
291219820Sjeff	static char names[UMAD_MAX_DEVICES][UMAD_CA_NAME_LEN];
292219820Sjeff	int phys_found = -1, port_found = 0, port, port_type;
293219820Sjeff	int caidx, n;
294219820Sjeff
295219820Sjeff	if (ca_name && (!best_port || *best_port))
296219820Sjeff		return ca_name;
297219820Sjeff
298219820Sjeff	if (ca_name) {
299219820Sjeff		if (resolve_ca_port(ca_name, best_port) < 0)
300219820Sjeff			return 0;
301219820Sjeff		return ca_name;
302219820Sjeff	}
303219820Sjeff
304219820Sjeff	/* Get the list of CA names */
305219820Sjeff	if ((n = umad_get_cas_names((void *)names, 20)) < 0)
306219820Sjeff		return 0;
307219820Sjeff
308219820Sjeff	/* Find the first existing CA with an active port */
309219820Sjeff	for (caidx = 0; caidx < n; caidx++) {
310219820Sjeff		TRACE("checking ca '%s'", names[caidx]);
311219820Sjeff
312219820Sjeff		port = best_port ? *best_port : 0;
313219820Sjeff		if ((port_type = resolve_ca_port(names[caidx], &port)) < 0)
314219820Sjeff			continue;
315219820Sjeff
316219820Sjeff		DEBUG("found ca %s with port %d type %d",
317219820Sjeff			names[caidx], port, port_type);
318219820Sjeff
319219820Sjeff		if (port_type > 0) {
320219820Sjeff			if (best_port)
321219820Sjeff				*best_port = port;
322219820Sjeff			DEBUG("found ca %s with active port %d",
323219820Sjeff			      names[caidx], port);
324219820Sjeff			return (char *)(names + caidx);
325219820Sjeff		}
326219820Sjeff
327219820Sjeff		if (phys_found == -1) {
328219820Sjeff			phys_found = caidx;
329219820Sjeff			port_found = port;
330219820Sjeff		}
331219820Sjeff	}
332219820Sjeff
333219820Sjeff	DEBUG("phys found %d on %s port %d",
334219820Sjeff		phys_found, phys_found >=0 ? names[phys_found] : 0, port_found);
335219820Sjeff	if (phys_found >= 0) {
336219820Sjeff		if (best_port)
337219820Sjeff			*best_port = port_found;
338219820Sjeff		return names[phys_found];
339219820Sjeff	}
340219820Sjeff
341219820Sjeff	if (best_port)
342219820Sjeff		*best_port = def_ca_port;
343219820Sjeff	return def_ca_name;
344219820Sjeff}
345219820Sjeff
346219820Sjeffstatic int
347219820Sjeffget_ca(char *ca_name, umad_ca_t *ca)
348219820Sjeff{
349219820Sjeff#ifdef __linux__
350219820Sjeff	DIR *dir;
351219820Sjeff#endif
352219820Sjeff	char dir_name[256];
353219820Sjeff	struct dirent **namelist;
354219820Sjeff	int r, i, ret;
355219820Sjeff	int portnum;
356219820Sjeff
357219820Sjeff	strncpy(ca->ca_name, ca_name, sizeof ca->ca_name);
358219820Sjeff
359219820Sjeff	snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND,
360219820Sjeff		 ca->ca_name);
361219820Sjeff
362219820Sjeff	if ((r = sys_read_uint(dir_name, SYS_NODE_TYPE, &ca->node_type)) < 0)
363219820Sjeff		return r;
364219820Sjeff	if (sys_read_string(dir_name, SYS_CA_FW_VERS, ca->fw_ver,
365219820Sjeff			    sizeof ca->fw_ver) < 0)
366219820Sjeff		ca->fw_ver[0] = '\0';
367219820Sjeff	if (sys_read_string(dir_name, SYS_CA_HW_VERS, ca->hw_ver,
368219820Sjeff			    sizeof ca->hw_ver) < 0)
369219820Sjeff		ca->hw_ver[0] = '\0';
370219820Sjeff	if ((r = sys_read_string(dir_name, SYS_CA_TYPE, ca->ca_type,
371219820Sjeff				 sizeof ca->ca_type)) < 0)
372219820Sjeff		ca->ca_type[0] = '\0';
373219820Sjeff	if ((r = sys_read_guid(dir_name, SYS_CA_NODE_GUID, &ca->node_guid)) < 0)
374219820Sjeff		return r;
375219820Sjeff	if ((r = sys_read_guid(dir_name, SYS_CA_SYS_GUID, &ca->system_guid)) < 0)
376219820Sjeff		return r;
377219820Sjeff
378219820Sjeff	snprintf(dir_name, sizeof(dir_name), "%s/%s/%s",
379219820Sjeff		SYS_INFINIBAND, ca->ca_name, SYS_CA_PORTS_DIR);
380219820Sjeff
381219820Sjeff#ifdef __linux__
382219820Sjeff	if (!(dir = opendir(dir_name)))
383219820Sjeff		return -ENOENT;
384219820Sjeff#endif
385219820Sjeff
386219820Sjeff	if ((r = sys_scandir(dir_name, &namelist, 0, alphasort)) < 0) {
387219820Sjeff		ret = errno < 0 ? errno : -EIO;
388219820Sjeff		goto error;
389219820Sjeff	}
390219820Sjeff
391219820Sjeff	ret = 0;
392219820Sjeff	ca->numports = 0;
393219820Sjeff	memset(ca->ports, 0, sizeof ca->ports);
394219820Sjeff	for (i = 0; i < r; i++) {
395219820Sjeff		portnum = 0;
396219820Sjeff		if (!strcmp(".", namelist[i]->d_name) ||
397219820Sjeff		    !strcmp("..", namelist[i]->d_name))
398219820Sjeff			continue;
399219820Sjeff		if (strcmp("0", namelist[i]->d_name) &&
400219820Sjeff		    ((portnum = atoi(namelist[i]->d_name)) <= 0 ||
401219820Sjeff		     portnum >= UMAD_CA_MAX_PORTS)) {
402219820Sjeff			ret = -EIO;
403219820Sjeff			goto clean;
404219820Sjeff		}
405219820Sjeff		if (!(ca->ports[portnum] = calloc(1, sizeof(*ca->ports[portnum])))) {
406219820Sjeff			ret = -ENOMEM;
407219820Sjeff			goto clean;
408219820Sjeff		}
409219820Sjeff		if (get_port(ca_name, dir_name, portnum, ca->ports[portnum]) < 0) {
410219820Sjeff			free(ca->ports[portnum]);
411219820Sjeff			ca->ports[portnum] = NULL;
412219820Sjeff			ret = -EIO;
413219820Sjeff			goto clean;
414219820Sjeff		}
415219820Sjeff		if (ca->numports < portnum)
416219820Sjeff			ca->numports = portnum;
417219820Sjeff	}
418219820Sjeff
419219820Sjeff	for (i = 0; i < r; i++)
420219820Sjeff		free(namelist[i]);
421219820Sjeff	free(namelist);
422219820Sjeff
423219820Sjeff#ifdef __linux__
424219820Sjeff	closedir(dir);
425219820Sjeff#endif
426219820Sjeff	put_ca(ca);
427219820Sjeff	return 0;
428219820Sjeff
429219820Sjeffclean:
430219820Sjeff	for (i = 0; i < r; i++)
431219820Sjeff		free(namelist[i]);
432219820Sjeff	free(namelist);
433219820Sjefferror:
434219820Sjeff#ifdef __linux__
435219820Sjeff	closedir(dir);
436219820Sjeff#endif
437219820Sjeff	release_ca(ca);
438219820Sjeff
439219820Sjeff	return ret;
440219820Sjeff}
441219820Sjeff
442219820Sjeffstatic int
443219820Sjeffumad_id_to_dev(int umad_id, char *dev, unsigned *port)
444219820Sjeff{
445219820Sjeff	char path[256];
446219820Sjeff	int r;
447219820Sjeff
448219820Sjeff	snprintf(path, sizeof(path), SYS_INFINIBAND_MAD "/umad%d", umad_id);
449219820Sjeff
450219820Sjeff	if ((r = sys_read_string(path, SYS_IB_MAD_DEV, dev, UMAD_CA_NAME_LEN)) < 0)
451219820Sjeff		return r;
452219820Sjeff
453219820Sjeff	if ((r = sys_read_uint(path, SYS_IB_MAD_PORT, port)) < 0)
454219820Sjeff		return r;
455219820Sjeff
456219820Sjeff	return 0;
457219820Sjeff}
458219820Sjeff
459219820Sjeffstatic int
460219820Sjeffdev_to_umad_id(char *dev, unsigned port)
461219820Sjeff{
462219820Sjeff	char umad_dev[UMAD_CA_NAME_LEN];
463219820Sjeff	unsigned umad_port;
464219820Sjeff	int id;
465219820Sjeff
466219820Sjeff	for (id = 0; id < UMAD_MAX_PORTS; id++) {
467219820Sjeff		if (umad_id_to_dev(id, umad_dev, &umad_port) < 0)
468219820Sjeff			continue;
469219820Sjeff		if (strncmp(dev, umad_dev, UMAD_CA_NAME_LEN))
470219820Sjeff			continue;
471219820Sjeff		if (port != umad_port)
472219820Sjeff			continue;
473219820Sjeff
474219820Sjeff		DEBUG("mapped %s %d to %d", dev, port, id);
475219820Sjeff		return id;
476219820Sjeff	}
477219820Sjeff
478219820Sjeff	return -1;	/* not found */
479219820Sjeff}
480219820Sjeff
481219820Sjeff/*******************************
482219820Sjeff * Public interface
483219820Sjeff */
484219820Sjeff
485219820Sjeffint
486219820Sjeffumad_init(void)
487219820Sjeff{
488219820Sjeff	TRACE("umad_init");
489219820Sjeff	if (sys_read_uint(IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE, &abi_version) < 0) {
490219820Sjeff		IBWARN("can't read ABI version from %s/%s (%m): is ib_umad module loaded?",
491219820Sjeff			IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE);
492219820Sjeff		return -1;
493219820Sjeff	}
494219820Sjeff	if (abi_version < IB_UMAD_ABI_VERSION) {
495219820Sjeff		IBWARN("wrong ABI version: %s/%s is %d but library minimal ABI is %d",
496219820Sjeff			IB_UMAD_ABI_DIR, IB_UMAD_ABI_FILE, abi_version, IB_UMAD_ABI_VERSION);
497219820Sjeff		return -1;
498219820Sjeff	}
499219820Sjeff	return 0;
500219820Sjeff}
501219820Sjeff
502219820Sjeffint
503219820Sjeffumad_done(void)
504219820Sjeff{
505219820Sjeff	TRACE("umad_done");
506219820Sjeff	/* FIXME - verify that all ports are closed */
507219820Sjeff	return 0;
508219820Sjeff}
509219820Sjeff
510219820Sjeffstatic unsigned is_ib_type(char *ca_name)
511219820Sjeff{
512219820Sjeff	char dir_name[256];
513219820Sjeff	unsigned type;
514219820Sjeff
515219820Sjeff	snprintf(dir_name, sizeof(dir_name), "%s/%s", SYS_INFINIBAND, ca_name);
516219820Sjeff
517219820Sjeff	if (sys_read_uint(dir_name, SYS_NODE_TYPE, &type) < 0)
518219820Sjeff		return 0;
519219820Sjeff
520219820Sjeff	return type >= 1 && type <= 3 ? 1 : 0;
521219820Sjeff}
522219820Sjeff
523219820Sjeffint
524219820Sjeffumad_get_cas_names(char cas[][UMAD_CA_NAME_LEN], int max)
525219820Sjeff{
526219820Sjeff	struct dirent **namelist;
527219820Sjeff	int n, i, j = 0;
528219820Sjeff
529219820Sjeff	TRACE("max %d", max);
530219820Sjeff
531219820Sjeff	n = sys_scandir(SYS_INFINIBAND, &namelist, NULL, alphasort);
532219820Sjeff	if (n > 0) {
533219820Sjeff		for (i = 0; i < n; i++) {
534219820Sjeff			if (strcmp(namelist[i]->d_name, ".") &&
535219820Sjeff			    strcmp(namelist[i]->d_name, "..")) {
536219820Sjeff				if (j < max && is_ib_type(namelist[i]->d_name))
537219820Sjeff					strncpy(cas[j++], namelist[i]->d_name,
538219820Sjeff						UMAD_CA_NAME_LEN);
539219820Sjeff			}
540219820Sjeff			free(namelist[i]);
541219820Sjeff		}
542219820Sjeff		DEBUG("return %d cas", j);
543219820Sjeff	} else {
544219820Sjeff		/* Is this still needed ? */
545219820Sjeff		strncpy((char *)cas, def_ca_name, UMAD_CA_NAME_LEN);
546219820Sjeff		DEBUG("return 1 ca");
547219820Sjeff		j = 1;
548219820Sjeff	}
549219820Sjeff	if (n >= 0)
550219820Sjeff		free(namelist);
551219820Sjeff	return j;
552219820Sjeff}
553219820Sjeff
554219820Sjeffint
555219820Sjeffumad_get_ca_portguids(char *ca_name, uint64_t *portguids, int max)
556219820Sjeff{
557219820Sjeff	umad_ca_t ca;
558219820Sjeff	int ports = 0, i;
559219820Sjeff
560219820Sjeff	TRACE("ca name %s max port guids %d", ca_name, max);
561219820Sjeff	if (!(ca_name = resolve_ca_name(ca_name, 0)))
562219820Sjeff		return -ENODEV;
563219820Sjeff
564219820Sjeff	if (umad_get_ca(ca_name, &ca) < 0)
565219820Sjeff		return -1;
566219820Sjeff
567219820Sjeff	if (portguids) {
568219820Sjeff		if (ca.numports + 1 > max) {
569219820Sjeff			release_ca(&ca);
570219820Sjeff			return -ENOMEM;
571219820Sjeff		}
572219820Sjeff
573219820Sjeff		for (i = 0; i <= ca.numports; i++)
574219820Sjeff			portguids[ports++] = ca.ports[i] ? ca.ports[i]->port_guid : 0;
575219820Sjeff	}
576219820Sjeff
577219820Sjeff	release_ca(&ca);
578219820Sjeff	DEBUG("%s: %d ports", ca_name, ports);
579219820Sjeff
580219820Sjeff	return ports;
581219820Sjeff}
582219820Sjeff
583219820Sjeffint
584219820Sjeffumad_get_issm_path(char *ca_name, int portnum, char path[], int max)
585219820Sjeff{
586219820Sjeff	int umad_id;
587219820Sjeff
588219820Sjeff	TRACE("ca %s port %d", ca_name, portnum);
589219820Sjeff
590219820Sjeff	if (!(ca_name = resolve_ca_name(ca_name, &portnum)))
591219820Sjeff		return -ENODEV;
592219820Sjeff
593219820Sjeff	if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0)
594219820Sjeff		return -EINVAL;
595219820Sjeff
596219820Sjeff	snprintf(path, max, "%s/issm%u", UMAD_DEV_DIR , umad_id);
597219820Sjeff
598219820Sjeff	return 0;
599219820Sjeff}
600219820Sjeff
601219820Sjeffint
602219820Sjeffumad_open_port(char *ca_name, int portnum)
603219820Sjeff{
604219820Sjeff	char dev_file[UMAD_DEV_FILE_SZ];
605219820Sjeff	int umad_id, fd;
606219820Sjeff
607219820Sjeff	TRACE("ca %s port %d", ca_name, portnum);
608219820Sjeff
609219820Sjeff	if (!(ca_name = resolve_ca_name(ca_name, &portnum)))
610219820Sjeff		return -ENODEV;
611219820Sjeff
612219820Sjeff	DEBUG("opening %s port %d", ca_name, portnum);
613219820Sjeff
614219820Sjeff	if ((umad_id = dev_to_umad_id(ca_name, portnum)) < 0)
615219820Sjeff		return -EINVAL;
616219820Sjeff
617219820Sjeff	snprintf(dev_file, sizeof(dev_file), "%s/umad%d",
618219820Sjeff		 UMAD_DEV_DIR , umad_id);
619219820Sjeff
620219820Sjeff	if ((fd = open(dev_file, O_RDWR|O_NONBLOCK)) < 0) {
621219820Sjeff		DEBUG("open %s failed: %s", dev_file, strerror(errno));
622219820Sjeff		return -EIO;
623219820Sjeff	}
624219820Sjeff
625219820Sjeff	if (abi_version > 5 || !ioctl(fd, IB_USER_MAD_ENABLE_PKEY, NULL))
626219820Sjeff		new_user_mad_api = 1;
627219820Sjeff	else
628219820Sjeff		new_user_mad_api = 0;
629219820Sjeff
630219820Sjeff	DEBUG("opened %s fd %d portid %d", dev_file, fd, umad_id);
631219820Sjeff	return fd;
632219820Sjeff}
633219820Sjeff
634219820Sjeffint
635219820Sjeffumad_get_ca(char *ca_name, umad_ca_t *ca)
636219820Sjeff{
637219820Sjeff	int r;
638219820Sjeff
639219820Sjeff	TRACE("ca_name %s", ca_name);
640219820Sjeff	if (!(ca_name = resolve_ca_name(ca_name, 0)))
641219820Sjeff		return -ENODEV;
642219820Sjeff
643219820Sjeff	if (find_cached_ca(ca_name, ca) > 0)
644219820Sjeff		return 0;
645219820Sjeff
646219820Sjeff	if ((r = get_ca(ca_name, ca)) < 0)
647219820Sjeff		return r;
648219820Sjeff
649219820Sjeff	DEBUG("opened %s", ca_name);
650219820Sjeff	return 0;
651219820Sjeff}
652219820Sjeff
653219820Sjeffint
654219820Sjeffumad_release_ca(umad_ca_t *ca)
655219820Sjeff{
656219820Sjeff	int r;
657219820Sjeff
658219820Sjeff	TRACE("ca_name %s", ca->ca_name);
659219820Sjeff	if (!ca)
660219820Sjeff		return -ENODEV;
661219820Sjeff
662219820Sjeff	if ((r = release_ca(ca)) < 0)
663219820Sjeff		return r;
664219820Sjeff
665219820Sjeff	DEBUG("releasing %s", ca->ca_name);
666219820Sjeff	return 0;
667219820Sjeff}
668219820Sjeff
669219820Sjeffint
670219820Sjeffumad_get_port(char *ca_name, int portnum, umad_port_t *port)
671219820Sjeff{
672219820Sjeff	char dir_name[256];
673219820Sjeff
674219820Sjeff	TRACE("ca_name %s portnum %d", ca_name, portnum);
675219820Sjeff
676219820Sjeff	if (!(ca_name = resolve_ca_name(ca_name, &portnum)))
677219820Sjeff		return -ENODEV;
678219820Sjeff
679219820Sjeff	snprintf(dir_name, sizeof(dir_name), "%s/%s/%s",
680219820Sjeff		SYS_INFINIBAND, ca_name, SYS_CA_PORTS_DIR);
681219820Sjeff
682219820Sjeff	return get_port(ca_name, dir_name, portnum, port);
683219820Sjeff}
684219820Sjeff
685219820Sjeffint
686219820Sjeffumad_release_port(umad_port_t *port)
687219820Sjeff{
688219820Sjeff	int r;
689219820Sjeff
690219820Sjeff	TRACE("port %s:%d", port->ca_name, port->portnum);
691219820Sjeff	if (!port)
692219820Sjeff		return -ENODEV;
693219820Sjeff
694219820Sjeff	if ((r = release_port(port)) < 0)
695219820Sjeff		return r;
696219820Sjeff
697219820Sjeff	DEBUG("releasing %s:%d", port->ca_name, port->portnum);
698219820Sjeff	return 0;
699219820Sjeff}
700219820Sjeff
701219820Sjeffint
702219820Sjeffumad_close_port(int fd)
703219820Sjeff{
704219820Sjeff	close(fd);
705219820Sjeff	DEBUG("closed fd %d", fd);
706219820Sjeff	return 0;
707219820Sjeff}
708219820Sjeff
709219820Sjeffvoid *
710219820Sjeffumad_get_mad(void *umad)
711219820Sjeff{
712219820Sjeff	return new_user_mad_api ? ((struct ib_user_mad *)umad)->data :
713219820Sjeff		(void *)&((struct ib_user_mad *)umad)->addr.pkey_index;
714219820Sjeff}
715219820Sjeff
716219820Sjeffsize_t
717219820Sjeffumad_size(void)
718219820Sjeff{
719219820Sjeff	return new_user_mad_api ? sizeof (struct ib_user_mad) :
720219820Sjeff		sizeof(struct ib_user_mad) - 8;
721219820Sjeff}
722219820Sjeff
723219820Sjeffint
724219820Sjeffumad_set_grh(void *umad, void *mad_addr)
725219820Sjeff{
726219820Sjeff	struct ib_user_mad *mad = umad;
727219820Sjeff	struct ib_mad_addr *addr = mad_addr;
728219820Sjeff
729219820Sjeff	if (mad_addr) {
730219820Sjeff		mad->addr.grh_present = 1;
731219820Sjeff		memcpy(mad->addr.gid, addr->gid, 16);
732219820Sjeff		mad->addr.flow_label = htonl(addr->flow_label);
733219820Sjeff		mad->addr.hop_limit = addr->hop_limit;
734219820Sjeff		mad->addr.traffic_class = addr->traffic_class;
735219820Sjeff	} else
736219820Sjeff		mad->addr.grh_present = 0;
737219820Sjeff	return 0;
738219820Sjeff}
739219820Sjeff
740219820Sjeffint
741219820Sjeffumad_set_pkey(void *umad, int pkey_index)
742219820Sjeff{
743219820Sjeff	struct ib_user_mad *mad = umad;
744219820Sjeff
745219820Sjeff	if (new_user_mad_api)
746219820Sjeff		mad->addr.pkey_index = pkey_index;
747219820Sjeff
748219820Sjeff	return 0;
749219820Sjeff}
750219820Sjeff
751219820Sjeffint
752219820Sjeffumad_get_pkey(void *umad)
753219820Sjeff{
754219820Sjeff	struct ib_user_mad *mad = umad;
755219820Sjeff
756219820Sjeff	if (new_user_mad_api)
757219820Sjeff		return mad->addr.pkey_index;
758219820Sjeff
759219820Sjeff	return 0;
760219820Sjeff}
761219820Sjeff
762219820Sjeffint
763219820Sjeffumad_set_addr(void *umad, int dlid, int dqp, int sl, int qkey)
764219820Sjeff{
765219820Sjeff	struct ib_user_mad *mad = umad;
766219820Sjeff
767219820Sjeff	TRACE("umad %p dlid %d dqp %d sl %d, qkey %x",
768219820Sjeff	      umad, dlid, dqp, sl, qkey);
769219820Sjeff	mad->addr.qpn = htonl(dqp);
770219820Sjeff	mad->addr.lid = htons(dlid);
771219820Sjeff	mad->addr.qkey = htonl(qkey);
772219820Sjeff	mad->addr.sl = sl;
773219820Sjeff
774219820Sjeff	return 0;
775219820Sjeff}
776219820Sjeff
777219820Sjeffint
778219820Sjeffumad_set_addr_net(void *umad, int dlid, int dqp, int sl, int qkey)
779219820Sjeff{
780219820Sjeff	struct ib_user_mad *mad = umad;
781219820Sjeff
782219820Sjeff	TRACE("umad %p dlid %d dqp %d sl %d qkey %x",
783219820Sjeff	      umad, ntohs(dlid), ntohl(dqp), sl, ntohl(qkey));
784219820Sjeff	mad->addr.qpn = dqp;
785219820Sjeff	mad->addr.lid = dlid;
786219820Sjeff	mad->addr.qkey = qkey;
787219820Sjeff	mad->addr.sl = sl;
788219820Sjeff
789219820Sjeff	return 0;
790219820Sjeff}
791219820Sjeff
792219820Sjeffint
793219820Sjeffumad_send(int fd, int agentid, void *umad, int length,
794219820Sjeff	  int timeout_ms, int retries)
795219820Sjeff{
796219820Sjeff	struct ib_user_mad *mad = umad;
797219820Sjeff	int n;
798219820Sjeff
799219820Sjeff	TRACE("fd %d agentid %d umad %p timeout %u",
800219820Sjeff	      fd, agentid, umad, timeout_ms);
801219820Sjeff	errno = 0;
802219820Sjeff
803219820Sjeff	mad->timeout_ms = timeout_ms;
804219820Sjeff	mad->retries = retries;
805219820Sjeff	mad->agent_id = agentid;
806219820Sjeff
807219820Sjeff	if (umaddebug > 1)
808219820Sjeff		umad_dump(mad);
809219820Sjeff
810219820Sjeff	n = write(fd, mad, length + umad_size());
811219820Sjeff	if (n == length + umad_size())
812219820Sjeff		return 0;
813219820Sjeff
814219820Sjeff	DEBUG("write returned %d != sizeof umad %zu + length %d (%m)",
815219820Sjeff	      n, umad_size(), length);
816219820Sjeff	if (!errno)
817219820Sjeff		errno = EIO;
818219820Sjeff	return -EIO;
819219820Sjeff}
820219820Sjeff
821219820Sjeffstatic int
822219820Sjeffdev_poll(int fd, int timeout_ms)
823219820Sjeff{
824219820Sjeff	struct pollfd ufds;
825219820Sjeff	int n;
826219820Sjeff
827219820Sjeff	ufds.fd     = fd;
828219820Sjeff	ufds.events = POLLIN;
829219820Sjeff
830219820Sjeff	if ((n = poll(&ufds, 1, timeout_ms)) == 1)
831219820Sjeff		return 0;
832219820Sjeff
833219820Sjeff	if (n == 0)
834219820Sjeff		return -ETIMEDOUT;
835219820Sjeff
836219820Sjeff	return -EIO;
837219820Sjeff}
838219820Sjeff
839219820Sjeffint
840219820Sjeffumad_recv(int fd, void *umad, int *length, int timeout_ms)
841219820Sjeff{
842219820Sjeff	struct ib_user_mad *mad = umad;
843219820Sjeff	int n;
844219820Sjeff
845219820Sjeff	errno = 0;
846219820Sjeff	TRACE("fd %d umad %p timeout %u", fd, umad, timeout_ms);
847219820Sjeff
848219820Sjeff	if (!umad || !length) {
849219820Sjeff		errno = EINVAL;
850219820Sjeff		return -EINVAL;
851219820Sjeff	}
852219820Sjeff
853219820Sjeff	if (timeout_ms && (n = dev_poll(fd, timeout_ms)) < 0) {
854219820Sjeff		if (!errno)
855219820Sjeff			errno = -n;
856219820Sjeff		return n;
857219820Sjeff	}
858219820Sjeff
859219820Sjeff	n = read(fd, umad, umad_size() + *length);
860219820Sjeff
861219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(umad, umad_size() + *length);
862219820Sjeff
863219820Sjeff	if ((n >= 0) && (n <= umad_size() + *length)) {
864219820Sjeff		DEBUG("mad received by agent %d length %d", mad->agent_id, n);
865219820Sjeff		if (n > umad_size())
866219820Sjeff			*length = n - umad_size();
867219820Sjeff		else
868219820Sjeff			*length = 0;
869219820Sjeff		return mad->agent_id;
870219820Sjeff	}
871219820Sjeff
872219820Sjeff	if (n == -EWOULDBLOCK) {
873219820Sjeff		if (!errno)
874219820Sjeff			errno = EWOULDBLOCK;
875219820Sjeff		return n;
876219820Sjeff	}
877219820Sjeff
878219820Sjeff	DEBUG("read returned %zu > sizeof umad %zu + length %d (%m)",
879219820Sjeff	      mad->length - umad_size(), umad_size(), *length);
880219820Sjeff
881219820Sjeff	*length = mad->length - umad_size();
882219820Sjeff	if (!errno)
883219820Sjeff		errno = EIO;
884219820Sjeff	return -errno;
885219820Sjeff}
886219820Sjeff
887219820Sjeffint
888219820Sjeffumad_poll(int fd, int timeout_ms)
889219820Sjeff{
890219820Sjeff	TRACE("fd %d timeout %u", fd, timeout_ms);
891219820Sjeff	return dev_poll(fd, timeout_ms);
892219820Sjeff}
893219820Sjeff
894219820Sjeffint
895219820Sjeffumad_get_fd(int fd)
896219820Sjeff{
897219820Sjeff	TRACE("fd %d", fd);
898219820Sjeff	return fd;
899219820Sjeff}
900219820Sjeff
901219820Sjeffint
902219820Sjeffumad_register_oui(int fd, int mgmt_class, uint8_t rmpp_version,
903219820Sjeff		  uint8_t oui[3], long method_mask[])
904219820Sjeff{
905219820Sjeff	struct ib_user_mad_reg_req req;
906219820Sjeff
907219820Sjeff	TRACE("fd %d mgmt_class %u rmpp_version %d oui 0x%x%x%x method_mask %p",
908219820Sjeff		fd, mgmt_class, (int)rmpp_version, (int)oui[0], (int)oui[1],
909219820Sjeff		(int)oui[2], method_mask);
910219820Sjeff
911219820Sjeff	if (mgmt_class < 0x30 || mgmt_class > 0x4f) {
912219820Sjeff		DEBUG("mgmt class %d not in vendor range 2", mgmt_class);
913219820Sjeff		return -EINVAL;
914219820Sjeff	}
915219820Sjeff
916219820Sjeff	req.qpn = 1;
917219820Sjeff	req.mgmt_class = mgmt_class;
918219820Sjeff	req.mgmt_class_version = 1;
919219820Sjeff	memcpy(req.oui, oui, sizeof req.oui);
920219820Sjeff	req.rmpp_version = rmpp_version;
921219820Sjeff
922219820Sjeff	if (method_mask)
923219820Sjeff		memcpy(req.method_mask, method_mask, sizeof req.method_mask);
924219820Sjeff	else
925219820Sjeff		memset(req.method_mask, 0, sizeof req.method_mask);
926219820Sjeff
927219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req);
928219820Sjeff
929219820Sjeff	if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) {
930219820Sjeff		DEBUG("fd %d registered to use agent %d qp %d class 0x%x oui %p",
931219820Sjeff			fd, req.id, req.qpn, req.mgmt_class, oui);
932219820Sjeff		return req.id; 		/* return agentid */
933219820Sjeff	}
934219820Sjeff
935219820Sjeff	DEBUG("fd %d registering qp %d class 0x%x version %d oui %p failed: %m",
936219820Sjeff		fd, req.qpn, req.mgmt_class, req.mgmt_class_version, oui);
937219820Sjeff	return -EPERM;
938219820Sjeff}
939219820Sjeff
940219820Sjeffint
941219820Sjeffumad_register(int fd, int mgmt_class, int mgmt_version,
942219820Sjeff	      uint8_t rmpp_version, long method_mask[])
943219820Sjeff{
944219820Sjeff	struct ib_user_mad_reg_req req;
945219820Sjeff	uint32_t oui = htonl(IB_OPENIB_OUI);
946219820Sjeff	int qp;
947219820Sjeff
948219820Sjeff	TRACE("fd %d mgmt_class %u mgmt_version %u rmpp_version %d method_mask %p",
949219820Sjeff		fd, mgmt_class, mgmt_version, rmpp_version, method_mask);
950219820Sjeff
951219820Sjeff	req.qpn = qp = (mgmt_class == 0x1 || mgmt_class == 0x81) ? 0 : 1;
952219820Sjeff	req.mgmt_class = mgmt_class;
953219820Sjeff	req.mgmt_class_version = mgmt_version;
954219820Sjeff	req.rmpp_version = rmpp_version;
955219820Sjeff
956219820Sjeff	if (method_mask)
957219820Sjeff		memcpy(req.method_mask, method_mask, sizeof req.method_mask);
958219820Sjeff	else
959219820Sjeff		memset(req.method_mask, 0, sizeof req.method_mask);
960219820Sjeff
961219820Sjeff	memcpy(&req.oui, (char *)&oui + 1, sizeof req.oui);
962219820Sjeff
963219820Sjeff	VALGRIND_MAKE_MEM_DEFINED(&req, sizeof req);
964219820Sjeff
965219820Sjeff	if (!ioctl(fd, IB_USER_MAD_REGISTER_AGENT, (void *)&req)) {
966219820Sjeff		DEBUG("fd %d registered to use agent %d qp %d",
967219820Sjeff		      fd, req.id, qp);
968219820Sjeff		return req.id; 		/* return agentid */
969219820Sjeff	}
970219820Sjeff
971219820Sjeff	DEBUG("fd %d registering qp %d class 0x%x version %d failed: %m",
972219820Sjeff		fd, qp, mgmt_class, mgmt_version);
973219820Sjeff	return -EPERM;
974219820Sjeff}
975219820Sjeff
976219820Sjeffint
977219820Sjeffumad_unregister(int fd, int agentid)
978219820Sjeff{
979219820Sjeff	TRACE("fd %d unregistering agent %d", fd, agentid);
980219820Sjeff	return ioctl(fd, IB_USER_MAD_UNREGISTER_AGENT, &agentid);
981219820Sjeff}
982219820Sjeff
983219820Sjeffint
984219820Sjeffumad_status(void *umad)
985219820Sjeff{
986219820Sjeff	struct ib_user_mad *mad = umad;
987219820Sjeff
988219820Sjeff	return mad->status;
989219820Sjeff}
990219820Sjeff
991219820Sjeffib_mad_addr_t *
992219820Sjeffumad_get_mad_addr(void *umad)
993219820Sjeff{
994219820Sjeff	struct ib_user_mad *mad = umad;
995219820Sjeff
996219820Sjeff	return &mad->addr;
997219820Sjeff}
998219820Sjeff
999219820Sjeffint
1000219820Sjeffumad_debug(int level)
1001219820Sjeff{
1002219820Sjeff	if (level >= 0)
1003219820Sjeff		umaddebug = level;
1004219820Sjeff	return umaddebug;
1005219820Sjeff}
1006219820Sjeff
1007219820Sjeffvoid
1008219820Sjeffumad_addr_dump(ib_mad_addr_t *addr)
1009219820Sjeff{
1010219820Sjeff#define HEX(x)  ((x) < 10 ? '0' + (x) : 'a' + ((x) -10))
1011219820Sjeff	char gid_str[64];
1012219820Sjeff	int i;
1013219820Sjeff
1014219820Sjeff	for (i = 0; i < sizeof addr->gid; i++) {
1015219820Sjeff		gid_str[i*2] = HEX(addr->gid[i] >> 4);
1016219820Sjeff		gid_str[i*2+1] = HEX(addr->gid[i] & 0xf);
1017219820Sjeff	}
1018219820Sjeff	gid_str[i*2] = 0;
1019219820Sjeff	IBWARN("qpn %d qkey 0x%x lid 0x%x sl %d\n"
1020219820Sjeff		"grh_present %d gid_index %d hop_limit %d traffic_class %d flow_label 0x%x pkey_index 0x%x\n"
1021219820Sjeff		"Gid 0x%s",
1022219820Sjeff		ntohl(addr->qpn), ntohl(addr->qkey), ntohs(addr->lid), addr->sl,
1023219820Sjeff		addr->grh_present, (int)addr->gid_index, (int)addr->hop_limit,
1024219820Sjeff		(int)addr->traffic_class, addr->flow_label, addr->pkey_index,
1025219820Sjeff		gid_str);
1026219820Sjeff}
1027219820Sjeff
1028219820Sjeffvoid
1029219820Sjeffumad_dump(void *umad)
1030219820Sjeff{
1031219820Sjeff	struct ib_user_mad * mad = umad;
1032219820Sjeff
1033219820Sjeff	IBWARN("agent id %d status %x timeout %d",
1034219820Sjeff	     mad->agent_id, mad->status, mad->timeout_ms);
1035219820Sjeff	umad_addr_dump(&mad->addr);
1036219820Sjeff}
1037