xref: /freebsd/contrib/ofed/infiniband-diags/src/ibdiag_sa.c (revision d8a0fe102c0cfdfcd5b818f850eff09d8536c9bc)
1 /*
2  * Copyright (c) 2006-2007 The Regents of the University of California.
3  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
4  * Copyright (c) 2002-2010 Mellanox Technologies LTD. All rights reserved.
5  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
6  * Copyright (c) 2009 HNR Consulting. All rights reserved.
7  * Copyright (c) 2011 Lawrence Livermore National Security. All rights reserved.
8  *
9  * This software is available to you under a choice of one of two
10  * licenses.  You may choose to be licensed under the terms of the GNU
11  * General Public License (GPL) Version 2, available from the file
12  * COPYING in the main directory of this source tree, or the
13  * OpenIB.org BSD license below:
14  *
15  *     Redistribution and use in source and binary forms, with or
16  *     without modification, are permitted provided that the following
17  *     conditions are met:
18  *
19  *      - Redistributions of source code must retain the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer.
22  *
23  *      - Redistributions in binary form must reproduce the above
24  *        copyright notice, this list of conditions and the following
25  *        disclaimer in the documentation and/or other materials
26  *        provided with the distribution.
27  *
28  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
32  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
33  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35  * SOFTWARE.
36  *
37  */
38 
39 
40 #include <errno.h>
41 #include <infiniband/umad.h>
42 
43 #include "ibdiag_common.h"
44 #include "ibdiag_sa.h"
45 
46 /* define a common SA query structure
47  * This is by no means optimal but it moves the saquery functionality out of
48  * the saquery tool and provides it to other utilities.
49  */
50 
51 struct sa_handle * sa_get_handle(void)
52 {
53 	struct sa_handle * handle;
54 	handle = calloc(1, sizeof(*handle));
55 	if (!handle)
56 		IBPANIC("calloc failed");
57 
58 	resolve_sm_portid(ibd_ca, ibd_ca_port, &handle->dport);
59 	if (!handle->dport.lid) {
60 		IBWARN("No SM/SA found on port %s:%d",
61 			ibd_ca ? "" : ibd_ca,
62 			ibd_ca_port);
63 		free(handle);
64 		return (NULL);
65 	}
66 
67 	handle->dport.qp = 1;
68 	if (!handle->dport.qkey)
69 		handle->dport.qkey = IB_DEFAULT_QP1_QKEY;
70 
71 	handle->fd = umad_open_port(ibd_ca, ibd_ca_port);
72 	handle->agent = umad_register(handle->fd, IB_SA_CLASS, 2, 1, NULL);
73 
74 	return handle;
75 }
76 
77 int sa_set_handle(struct sa_handle * handle, int grh_present, ibmad_gid_t *gid)
78 {
79 	if (grh_present) {
80 		if (gid == NULL) {
81 			return -1;
82 		} else {
83 			handle->dport.grh_present = 1;
84 			memcpy(handle->dport.gid, gid, 16);
85 		}
86 	}
87 	return 0;
88 }
89 
90 void sa_free_handle(struct sa_handle * h)
91 {
92 	umad_unregister(h->fd, h->agent);
93 	umad_close_port(h->fd);
94 	free(h);
95 }
96 
97 int sa_query(struct sa_handle * h, uint8_t method,
98 		    uint16_t attr, uint32_t mod, uint64_t comp_mask,
99 		    uint64_t sm_key, void *data, size_t datasz,
100 		    struct sa_query_result *result)
101 {
102 	ib_rpc_t rpc;
103 	void *umad, *mad;
104 	int ret, offset, len = 256;
105 
106 	memset(&rpc, 0, sizeof(rpc));
107 	rpc.mgtclass = IB_SA_CLASS;
108 	rpc.method = method;
109 	rpc.attr.id = attr;
110 	rpc.attr.mod = mod;
111 	rpc.mask = comp_mask;
112 	rpc.datasz = datasz;
113 	rpc.dataoffs = IB_SA_DATA_OFFS;
114 
115 	umad = calloc(1, len + umad_size());
116 	if (!umad)
117 		IBPANIC("cannot alloc mem for umad: %s\n", strerror(errno));
118 
119 	mad_build_pkt(umad, &rpc, &h->dport, NULL, data);
120 
121 	mad_set_field64(umad_get_mad(umad), 0, IB_SA_MKEY_F, sm_key);
122 
123 	if (ibdebug > 1)
124 		xdump(stdout, "SA Request:\n", umad_get_mad(umad), len);
125 
126 	if (h->dport.grh_present) {
127 		ib_mad_addr_t *p_mad_addr = umad_get_mad_addr(umad);
128 		p_mad_addr->grh_present = 1;
129 		p_mad_addr->gid_index = 0;
130 		p_mad_addr->hop_limit = 0;
131 		p_mad_addr->traffic_class = 0;
132 		memcpy(p_mad_addr->gid, h->dport.gid, 16);
133 	}
134 
135 	ret = umad_send(h->fd, h->agent, umad, len, ibd_timeout, 0);
136 	if (ret < 0) {
137 		IBWARN("umad_send failed: attr 0x%x: %s\n",
138 			attr, strerror(errno));
139 		free(umad);
140 		return (-ret);
141 	}
142 
143 recv_mad:
144 	ret = umad_recv(h->fd, umad, &len, ibd_timeout);
145 	if (ret < 0) {
146 		if (errno == ENOSPC) {
147 			umad = realloc(umad, umad_size() + len);
148 			goto recv_mad;
149 		}
150 		IBWARN("umad_recv failed: attr 0x%x: %s\n", attr,
151 			strerror(errno));
152 		free(umad);
153 		return (-ret);
154 	}
155 
156 	if ((ret = umad_status(umad)))
157 		return ret;
158 
159 	mad = umad_get_mad(umad);
160 
161 	if (ibdebug > 1)
162 		xdump(stdout, "SA Response:\n", mad, len);
163 
164 	method = (uint8_t) mad_get_field(mad, 0, IB_MAD_METHOD_F);
165 	offset = mad_get_field(mad, 0, IB_SA_ATTROFFS_F);
166 	result->status = mad_get_field(mad, 0, IB_MAD_STATUS_F);
167 	result->p_result_madw = mad;
168 	if (result->status != IB_SA_MAD_STATUS_SUCCESS)
169 		result->result_cnt = 0;
170 	else if (method != IB_MAD_METHOD_GET_TABLE)
171 		result->result_cnt = 1;
172 	else if (!offset)
173 		result->result_cnt = 0;
174 	else
175 		result->result_cnt = (len - IB_SA_DATA_OFFS) / (offset << 3);
176 
177 	return 0;
178 }
179 
180 void sa_free_result_mad(struct sa_query_result *result)
181 {
182 	if (result->p_result_madw) {
183 		free((uint8_t *) result->p_result_madw - umad_size());
184 		result->p_result_madw = NULL;
185 	}
186 }
187 
188 void *sa_get_query_rec(void *mad, unsigned i)
189 {
190 	int offset = mad_get_field(mad, 0, IB_SA_ATTROFFS_F);
191 	return (uint8_t *) mad + IB_SA_DATA_OFFS + i * (offset << 3);
192 }
193 
194 static const char *ib_sa_error_str[] = {
195 	"SA_NO_ERROR",
196 	"SA_ERR_NO_RESOURCES",
197 	"SA_ERR_REQ_INVALID",
198 	"SA_ERR_NO_RECORDS",
199 	"SA_ERR_TOO_MANY_RECORDS",
200 	"SA_ERR_REQ_INVALID_GID",
201 	"SA_ERR_REQ_INSUFFICIENT_COMPONENTS",
202 	"SA_ERR_REQ_DENIED",
203 	"SA_ERR_STATUS_PRIO_SUGGESTED",
204 	"SA_ERR_UNKNOWN"
205 };
206 
207 #define ARR_SIZE(a) (sizeof(a)/sizeof((a)[0]))
208 #define SA_ERR_UNKNOWN (ARR_SIZE(ib_sa_error_str) - 1)
209 
210 static inline const char *ib_sa_err_str(IN uint8_t status)
211 {
212 	if (status > SA_ERR_UNKNOWN)
213 		status = SA_ERR_UNKNOWN;
214 	return (ib_sa_error_str[status]);
215 }
216 
217 static const char *ib_mad_inv_field_str[] = {
218 	"MAD No invalid fields",
219 	"MAD Bad version",
220 	"MAD Method specified is not supported",
221 	"MAD Method/Attribute combination is not supported",
222 	"MAD Reserved",
223 	"MAD Reserved",
224 	"MAD Reserved",
225 	"MAD Invalid value in Attribute field(s) or Attribute Modifier"
226 	"MAD UNKNOWN ERROR"
227 };
228 #define MAD_ERR_UNKNOWN (ARR_SIZE(ib_mad_inv_field_str) - 1)
229 
230 static inline const char *ib_mad_inv_field_err_str(IN uint8_t f)
231 {
232 	if (f > MAD_ERR_UNKNOWN)
233 		f = MAD_ERR_UNKNOWN;
234 	return (ib_mad_inv_field_str[f]);
235 }
236 
237 void sa_report_err(int status)
238 {
239 	int st = status & 0xff;
240 	char mad_err_str[64] = { 0 };
241 	char sa_err_str[64] = { 0 };
242 
243 	if (st)
244 		sprintf(mad_err_str, " (%s; %s; %s)",
245 			(st & 0x1) ? "BUSY" : "",
246 			(st & 0x2) ? "Redirection Required" : "",
247 			ib_mad_inv_field_err_str(st>>2));
248 
249 
250 	st = status >> 8;
251 	if (st)
252 		sprintf(sa_err_str, " SA(%s)", ib_sa_err_str((uint8_t) st));
253 
254 	fprintf(stderr, "ERROR: Query result returned 0x%04x, %s%s\n",
255 		status, mad_err_str, sa_err_str);
256 }
257