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