Blame src/ibdiag_sa.c

Packit db064d
/*
Packit db064d
 * Copyright (c) 2006-2007 The Regents of the University of California.
Packit db064d
 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
Packit db064d
 * Copyright (c) 2002-2010 Mellanox Technologies LTD. All rights reserved.
Packit db064d
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit db064d
 * Copyright (c) 2009 HNR Consulting. All rights reserved.
Packit db064d
 * Copyright (c) 2011 Lawrence Livermore National Security. All rights reserved.
Packit db064d
 *
Packit db064d
 * This software is available to you under a choice of one of two
Packit db064d
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit db064d
 * General Public License (GPL) Version 2, available from the file
Packit db064d
 * COPYING in the main directory of this source tree, or the
Packit db064d
 * OpenIB.org BSD license below:
Packit db064d
 *
Packit db064d
 *     Redistribution and use in source and binary forms, with or
Packit db064d
 *     without modification, are permitted provided that the following
Packit db064d
 *     conditions are met:
Packit db064d
 *
Packit db064d
 *      - Redistributions of source code must retain the above
Packit db064d
 *        copyright notice, this list of conditions and the following
Packit db064d
 *        disclaimer.
Packit db064d
 *
Packit db064d
 *      - Redistributions in binary form must reproduce the above
Packit db064d
 *        copyright notice, this list of conditions and the following
Packit db064d
 *        disclaimer in the documentation and/or other materials
Packit db064d
 *        provided with the distribution.
Packit db064d
 *
Packit db064d
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit db064d
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit db064d
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit db064d
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit db064d
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit db064d
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit db064d
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit db064d
 * SOFTWARE.
Packit db064d
 *
Packit db064d
 */
Packit db064d
Packit db064d
Packit db064d
#include <errno.h>
Packit db064d
#include <infiniband/umad.h>
Packit db064d
Packit db064d
#include "ibdiag_common.h"
Packit db064d
#include "ibdiag_sa.h"
Packit db064d
Packit db064d
/* define a common SA query structure
Packit db064d
 * This is by no means optimal but it moves the saquery functionality out of
Packit db064d
 * the saquery tool and provides it to other utilities.
Packit db064d
 */
Packit db064d
Packit db064d
struct sa_handle * sa_get_handle(void)
Packit db064d
{
Packit db064d
	struct sa_handle * handle;
Packit db064d
	handle = calloc(1, sizeof(*handle));
Packit db064d
	if (!handle)
Packit db064d
		IBPANIC("calloc failed");
Packit db064d
Packit db064d
	resolve_sm_portid(ibd_ca, ibd_ca_port, &handle->dport);
Packit db064d
	if (!handle->dport.lid) {
Packit db064d
		IBWARN("No SM/SA found on port %s:%d",
Packit db064d
			ibd_ca ? "" : ibd_ca,
Packit db064d
			ibd_ca_port);
Packit db064d
		goto err;
Packit db064d
	}
Packit db064d
Packit db064d
	handle->dport.qp = 1;
Packit db064d
	if (!handle->dport.qkey)
Packit db064d
		handle->dport.qkey = IB_DEFAULT_QP1_QKEY;
Packit db064d
Packit db064d
	if ((handle->fd = umad_open_port(ibd_ca, ibd_ca_port)) < 0) {
Packit db064d
		IBWARN("umad_open_port on port %s:%d failed",
Packit db064d
			ibd_ca ? "" : ibd_ca,
Packit db064d
			ibd_ca_port);
Packit db064d
		goto err;
Packit db064d
	}
Packit db064d
	if ((handle->agent = umad_register(handle->fd, IB_SA_CLASS, 2, 1, NULL)) < 0) {
Packit db064d
		umad_close_port(handle->fd);
Packit db064d
		IBWARN("umad_register for SA class failed on port %s:%d",
Packit db064d
		       ibd_ca ? "" : ibd_ca,
Packit db064d
		       ibd_ca_port);
Packit db064d
		goto err;
Packit db064d
	}
Packit db064d
Packit db064d
	return handle;
Packit db064d
Packit db064d
err:
Packit db064d
	free(handle);
Packit db064d
	return (NULL);
Packit db064d
}
Packit db064d
Packit db064d
void sa_free_handle(struct sa_handle * h)
Packit db064d
{
Packit db064d
	umad_unregister(h->fd, h->agent);
Packit db064d
	umad_close_port(h->fd);
Packit db064d
	free(h);
Packit db064d
}
Packit db064d
Packit db064d
int sa_query(struct sa_handle * h, uint8_t method,
Packit db064d
		    uint16_t attr, uint32_t mod, uint64_t comp_mask,
Packit db064d
		    uint64_t sm_key, void *data, size_t datasz,
Packit db064d
		    struct sa_query_result *result)
Packit db064d
{
Packit db064d
	ib_rpc_t rpc;
Packit db064d
	void *umad, *mad;
Packit db064d
	int ret, offset, len = 256;
Packit db064d
Packit db064d
	memset(&rpc, 0, sizeof(rpc));
Packit db064d
	rpc.mgtclass = IB_SA_CLASS;
Packit db064d
	rpc.method = method;
Packit db064d
	rpc.attr.id = attr;
Packit db064d
	rpc.attr.mod = mod;
Packit db064d
	rpc.mask = comp_mask;
Packit db064d
	rpc.datasz = datasz;
Packit db064d
	rpc.dataoffs = IB_SA_DATA_OFFS;
Packit db064d
Packit db064d
	umad = calloc(1, len + umad_size());
Packit db064d
	if (!umad)
Packit db064d
		IBPANIC("cannot alloc mem for umad: %s\n", strerror(errno));
Packit db064d
Packit db064d
	mad_build_pkt(umad, &rpc, &h->dport, NULL, data);
Packit db064d
Packit db064d
	mad_set_field64(umad_get_mad(umad), 0, IB_SA_MKEY_F, sm_key);
Packit db064d
Packit db064d
	if (ibdebug > 1)
Packit db064d
		xdump(stdout, "SA Request:\n", umad_get_mad(umad), len);
Packit db064d
Packit db064d
	ret = umad_send(h->fd, h->agent, umad, len, ibd_timeout, 0);
Packit db064d
	if (ret < 0) {
Packit db064d
		IBWARN("umad_send failed: attr 0x%x: %s\n",
Packit db064d
			attr, strerror(errno));
Packit db064d
		free(umad);
Packit db064d
		return (-ret);
Packit db064d
	}
Packit db064d
Packit db064d
recv_mad:
Packit db064d
	ret = umad_recv(h->fd, umad, &len, ibd_timeout);
Packit db064d
	if (ret < 0) {
Packit db064d
		if (errno == ENOSPC) {
Packit db064d
			umad = realloc(umad, umad_size() + len);
Packit db064d
			goto recv_mad;
Packit db064d
		}
Packit db064d
		IBWARN("umad_recv failed: attr 0x%x: %s\n", attr,
Packit db064d
			strerror(errno));
Packit db064d
		free(umad);
Packit db064d
		return (-ret);
Packit db064d
	}
Packit db064d
Packit db064d
	if ((ret = umad_status(umad)))
Packit db064d
		return ret;
Packit db064d
Packit db064d
	mad = umad_get_mad(umad);
Packit db064d
Packit db064d
	if (ibdebug > 1)
Packit db064d
		xdump(stdout, "SA Response:\n", mad, len);
Packit db064d
Packit db064d
	method = (uint8_t) mad_get_field(mad, 0, IB_MAD_METHOD_F);
Packit db064d
	offset = mad_get_field(mad, 0, IB_SA_ATTROFFS_F);
Packit db064d
	result->status = mad_get_field(mad, 0, IB_MAD_STATUS_F);
Packit db064d
	result->p_result_madw = mad;
Packit db064d
	if (result->status != IB_SA_MAD_STATUS_SUCCESS)
Packit db064d
		result->result_cnt = 0;
Packit db064d
	else if (method != IB_MAD_METHOD_GET_TABLE)
Packit db064d
		result->result_cnt = 1;
Packit db064d
	else if (!offset)
Packit db064d
		result->result_cnt = 0;
Packit db064d
	else
Packit db064d
		result->result_cnt = (len - IB_SA_DATA_OFFS) / (offset << 3);
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
void sa_free_result_mad(struct sa_query_result *result)
Packit db064d
{
Packit db064d
	if (result->p_result_madw) {
Packit db064d
		free((uint8_t *) result->p_result_madw - umad_size());
Packit db064d
		result->p_result_madw = NULL;
Packit db064d
	}
Packit db064d
}
Packit db064d
Packit db064d
void *sa_get_query_rec(void *mad, unsigned i)
Packit db064d
{
Packit db064d
	int offset = mad_get_field(mad, 0, IB_SA_ATTROFFS_F);
Packit db064d
	return (uint8_t *) mad + IB_SA_DATA_OFFS + i * (offset << 3);
Packit db064d
}
Packit db064d
Packit db064d
static const char *ib_sa_error_str[] = {
Packit db064d
	"SA_NO_ERROR",
Packit db064d
	"SA_ERR_NO_RESOURCES",
Packit db064d
	"SA_ERR_REQ_INVALID",
Packit db064d
	"SA_ERR_NO_RECORDS",
Packit db064d
	"SA_ERR_TOO_MANY_RECORDS",
Packit db064d
	"SA_ERR_REQ_INVALID_GID",
Packit db064d
	"SA_ERR_REQ_INSUFFICIENT_COMPONENTS",
Packit db064d
	"SA_ERR_REQ_DENIED",
Packit db064d
	"SA_ERR_STATUS_PRIO_SUGGESTED",
Packit db064d
	"SA_ERR_UNKNOWN"
Packit db064d
};
Packit db064d
Packit db064d
#define ARR_SIZE(a) (sizeof(a)/sizeof((a)[0]))
Packit db064d
#define SA_ERR_UNKNOWN (ARR_SIZE(ib_sa_error_str) - 1)
Packit db064d
Packit db064d
static inline const char *ib_sa_err_str(uint8_t status)
Packit db064d
{
Packit db064d
	if (status > SA_ERR_UNKNOWN)
Packit db064d
		status = SA_ERR_UNKNOWN;
Packit db064d
	return (ib_sa_error_str[status]);
Packit db064d
}
Packit db064d
Packit db064d
static const char *ib_mad_inv_field_str[] = {
Packit db064d
	"MAD No invalid fields",
Packit db064d
	"MAD Bad version",
Packit db064d
	"MAD Method specified is not supported",
Packit db064d
	"MAD Method/Attribute combination is not supported",
Packit db064d
	"MAD Reserved",
Packit db064d
	"MAD Reserved",
Packit db064d
	"MAD Reserved",
Packit db064d
	"MAD Invalid value in Attribute field(s) or Attribute Modifier",
Packit db064d
	"MAD UNKNOWN ERROR"
Packit db064d
};
Packit db064d
#define MAD_ERR_UNKNOWN (ARR_SIZE(ib_mad_inv_field_str) - 1)
Packit db064d
Packit db064d
static inline const char *ib_mad_inv_field_err_str(uint8_t f)
Packit db064d
{
Packit db064d
	if (f > MAD_ERR_UNKNOWN)
Packit db064d
		f = MAD_ERR_UNKNOWN;
Packit db064d
	return (ib_mad_inv_field_str[f]);
Packit db064d
}
Packit db064d
Packit db064d
void sa_report_err(int status)
Packit db064d
{
Packit db064d
	int st = status & 0xff;
Packit db064d
	char mad_err_str[128] = { 0 };
Packit db064d
	char sa_err_str[64] = { 0 };
Packit db064d
	int rc;
Packit db064d
Packit db064d
	if (st) {
Packit db064d
		rc = snprintf(mad_err_str, sizeof(mad_err_str), " (%s; %s; %s)",
Packit db064d
			(st & 0x1) ? "BUSY" : "",
Packit db064d
			(st & 0x2) ? "Redirection Required" : "",
Packit db064d
			ib_mad_inv_field_err_str(st>>2));
Packit db064d
		if (rc > sizeof(mad_err_str))
Packit db064d
			fprintf(stderr, "WARN: string buffer overflow\n");
Packit db064d
	}
Packit db064d
Packit db064d
	st = status >> 8;
Packit db064d
	if (st) {
Packit db064d
		rc = snprintf(sa_err_str, sizeof(sa_err_str), " SA(%s)",
Packit db064d
			ib_sa_err_str((uint8_t) st));
Packit db064d
		if (rc > sizeof(sa_err_str))
Packit db064d
			fprintf(stderr, "WARN: string buffer overflow\n");
Packit db064d
	}
Packit db064d
Packit db064d
	fprintf(stderr, "ERROR: Query result returned 0x%04x, %s%s\n",
Packit db064d
		status, mad_err_str, sa_err_str);
Packit db064d
}