1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2006 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 <stdio.h> 39219820Sjeff#include <stdlib.h> 40219820Sjeff#include <unistd.h> 41219820Sjeff#include <pthread.h> 42219820Sjeff#include <sys/time.h> 43219820Sjeff#include <string.h> 44219820Sjeff#include <errno.h> 45219820Sjeff 46219820Sjeff#include <infiniband/umad.h> 47219820Sjeff#include "mad.h" 48219820Sjeff 49219820Sjeff#define MAX_CLASS 256 50219820Sjeff 51219820Sjeffstruct ibmad_port { 52219820Sjeff int port_id; /* file descriptor returned by umad_open() */ 53219820Sjeff int class_agents[MAX_CLASS]; /* class2agent mapper */ 54219820Sjeff}; 55219820Sjeff 56219820Sjeffint ibdebug; 57219820Sjeff 58219820Sjeffstatic int mad_portid = -1; 59219820Sjeffstatic int iberrs; 60219820Sjeff 61219820Sjeffstatic int madrpc_retries = MAD_DEF_RETRIES; 62219820Sjeffstatic int def_madrpc_timeout = MAD_DEF_TIMEOUT_MS; 63219820Sjeffstatic void *save_mad; 64219820Sjeffstatic int save_mad_len = 256; 65219820Sjeff 66219820Sjeff#undef DEBUG 67219820Sjeff#define DEBUG if (ibdebug) IBWARN 68219820Sjeff#define ERRS if (iberrs || ibdebug) IBWARN 69219820Sjeff 70219820Sjeff#define MAD_TID(mad) (*((uint64_t *)((char *)(mad) + 8))) 71219820Sjeff 72219820Sjeffvoid 73219820Sjeffmadrpc_show_errors(int set) 74219820Sjeff{ 75219820Sjeff iberrs = set; 76219820Sjeff} 77219820Sjeff 78219820Sjeffvoid 79219820Sjeffmadrpc_save_mad(void *madbuf, int len) 80219820Sjeff{ 81219820Sjeff save_mad = madbuf; 82219820Sjeff save_mad_len = len; 83219820Sjeff} 84219820Sjeff 85219820Sjeffint 86219820Sjeffmadrpc_set_retries(int retries) 87219820Sjeff{ 88219820Sjeff if (retries > 0) 89219820Sjeff madrpc_retries = retries; 90219820Sjeff return madrpc_retries; 91219820Sjeff} 92219820Sjeff 93219820Sjeffint 94219820Sjeffmadrpc_set_timeout(int timeout) 95219820Sjeff{ 96219820Sjeff def_madrpc_timeout = timeout; 97219820Sjeff return 0; 98219820Sjeff} 99219820Sjeff 100219820Sjeffint 101219820Sjeffmadrpc_def_timeout(void) 102219820Sjeff{ 103219820Sjeff return def_madrpc_timeout; 104219820Sjeff} 105219820Sjeff 106219820Sjeffint 107219820Sjeffmadrpc_portid(void) 108219820Sjeff{ 109219820Sjeff return mad_portid; 110219820Sjeff} 111219820Sjeff 112219820Sjeffstatic int 113219820Sjeff_do_madrpc(int port_id, void *sndbuf, void *rcvbuf, int agentid, int len, 114219820Sjeff int timeout) 115219820Sjeff{ 116219820Sjeff uint32_t trid; /* only low 32 bits */ 117219820Sjeff int retries; 118219820Sjeff int length, status; 119219820Sjeff 120219820Sjeff if (!timeout) 121219820Sjeff timeout = def_madrpc_timeout; 122219820Sjeff 123219820Sjeff if (ibdebug > 1) { 124219820Sjeff IBWARN(">>> sending: len %d pktsz %zu", len, umad_size() + len); 125219820Sjeff xdump(stderr, "send buf\n", sndbuf, umad_size() + len); 126219820Sjeff } 127219820Sjeff 128219820Sjeff if (save_mad) { 129219820Sjeff memcpy(save_mad, umad_get_mad(sndbuf), 130219820Sjeff save_mad_len < len ? save_mad_len : len); 131219820Sjeff save_mad = 0; 132219820Sjeff } 133219820Sjeff 134219820Sjeff trid = mad_get_field64(umad_get_mad(sndbuf), 0, IB_MAD_TRID_F); 135219820Sjeff 136219820Sjeff for (retries = 0; retries < madrpc_retries; retries++) { 137219820Sjeff if (retries) { 138219820Sjeff ERRS("retry %d (timeout %d ms)", retries, timeout); 139219820Sjeff } 140219820Sjeff 141219820Sjeff length = len; 142219820Sjeff if (umad_send(port_id, agentid, sndbuf, length, timeout, 0) < 0) { 143219820Sjeff IBWARN("send failed; %s", strerror(errno)); 144219820Sjeff return -1; 145219820Sjeff } 146219820Sjeff 147219820Sjeff /* Use same timeout on receive side just in case */ 148219820Sjeff /* send packet is lost somewhere. */ 149219820Sjeff do { 150219820Sjeff if (umad_recv(port_id, rcvbuf, &length, timeout) < 0) { 151219820Sjeff IBWARN("recv failed: %s", strerror(errno)); 152219820Sjeff return -1; 153219820Sjeff } 154219820Sjeff 155219820Sjeff if (ibdebug > 1) { 156219820Sjeff IBWARN("rcv buf:"); 157219820Sjeff xdump(stderr, "rcv buf\n", umad_get_mad(rcvbuf), IB_MAD_SIZE); 158219820Sjeff } 159219820Sjeff } while ((uint32_t)mad_get_field64(umad_get_mad(rcvbuf), 0, IB_MAD_TRID_F) != trid); 160219820Sjeff 161219820Sjeff status = umad_status(rcvbuf); 162219820Sjeff if (!status) 163219820Sjeff return length; /* done */ 164219820Sjeff if (status == ENOMEM) 165219820Sjeff return length; 166219820Sjeff } 167219820Sjeff 168219820Sjeff ERRS("timeout after %d retries, %d ms", retries, timeout * retries); 169219820Sjeff return -1; 170219820Sjeff} 171219820Sjeff 172219820Sjeffvoid * 173219820Sjeffmad_rpc(const void *port_id, ib_rpc_t *rpc, ib_portid_t *dport, void *payload, 174219820Sjeff void *rcvdata) 175219820Sjeff{ 176219820Sjeff const struct ibmad_port *p = port_id; 177219820Sjeff int status, len; 178219820Sjeff uint8_t sndbuf[1024], rcvbuf[1024], *mad; 179219820Sjeff 180219820Sjeff len = 0; 181219820Sjeff memset(sndbuf, 0, umad_size() + IB_MAD_SIZE); 182219820Sjeff 183219820Sjeff if ((len = mad_build_pkt(sndbuf, rpc, dport, 0, payload)) < 0) 184219820Sjeff return 0; 185219820Sjeff 186219820Sjeff if ((len = _do_madrpc(p->port_id, sndbuf, rcvbuf, 187219820Sjeff p->class_agents[rpc->mgtclass], 188219820Sjeff len, rpc->timeout)) < 0) { 189219820Sjeff IBWARN("_do_madrpc failed; dport (%s)", portid2str(dport)); 190219820Sjeff return 0; 191219820Sjeff } 192219820Sjeff 193219820Sjeff mad = umad_get_mad(rcvbuf); 194219820Sjeff 195219820Sjeff if ((status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F)) != 0) { 196219820Sjeff ERRS("MAD completed with error status 0x%x; dport (%s)", 197219820Sjeff status, portid2str(dport)); 198219820Sjeff return 0; 199219820Sjeff } 200219820Sjeff 201219820Sjeff if (ibdebug) { 202219820Sjeff IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz); 203219820Sjeff xdump(stderr, "mad data\n", mad + rpc->dataoffs, rpc->datasz); 204219820Sjeff } 205219820Sjeff 206219820Sjeff if (rcvdata) 207219820Sjeff memcpy(rcvdata, mad + rpc->dataoffs, rpc->datasz); 208219820Sjeff 209219820Sjeff return rcvdata; 210219820Sjeff} 211219820Sjeff 212219820Sjeffvoid * 213219820Sjeffmad_rpc_rmpp(const void *port_id, ib_rpc_t *rpc, ib_portid_t *dport, 214219820Sjeff ib_rmpp_hdr_t *rmpp, void *data) 215219820Sjeff{ 216219820Sjeff const struct ibmad_port *p = port_id; 217219820Sjeff int status, len; 218219820Sjeff uint8_t sndbuf[1024], rcvbuf[1024], *mad; 219219820Sjeff 220219820Sjeff memset(sndbuf, 0, umad_size() + IB_MAD_SIZE); 221219820Sjeff 222219820Sjeff DEBUG("rmpp %p data %p", rmpp, data); 223219820Sjeff 224219820Sjeff if ((len = mad_build_pkt(sndbuf, rpc, dport, rmpp, data)) < 0) 225219820Sjeff return 0; 226219820Sjeff 227219820Sjeff if ((len = _do_madrpc(p->port_id, sndbuf, rcvbuf, 228219820Sjeff p->class_agents[rpc->mgtclass], 229219820Sjeff len, rpc->timeout)) < 0) { 230219820Sjeff IBWARN("_do_madrpc failed; dport (%s)", portid2str(dport)); 231219820Sjeff return 0; 232219820Sjeff } 233219820Sjeff 234219820Sjeff mad = umad_get_mad(rcvbuf); 235219820Sjeff 236219820Sjeff if ((status = mad_get_field(mad, 0, IB_MAD_STATUS_F)) != 0) { 237219820Sjeff ERRS("MAD completed with error status 0x%x; dport (%s)", 238219820Sjeff status, portid2str(dport)); 239219820Sjeff return 0; 240219820Sjeff } 241219820Sjeff 242219820Sjeff if (ibdebug) { 243219820Sjeff IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz); 244219820Sjeff xdump(stderr, "rmpp mad data\n", mad + rpc->dataoffs, 245219820Sjeff rpc->datasz); 246219820Sjeff } 247219820Sjeff 248219820Sjeff if (rmpp) { 249219820Sjeff rmpp->flags = mad_get_field(mad, 0, IB_SA_RMPP_FLAGS_F); 250219820Sjeff if ((rmpp->flags & 0x3) && 251219820Sjeff mad_get_field(mad, 0, IB_SA_RMPP_VERS_F) != 1) { 252219820Sjeff IBWARN("bad rmpp version"); 253219820Sjeff return 0; 254219820Sjeff } 255219820Sjeff rmpp->type = mad_get_field(mad, 0, IB_SA_RMPP_TYPE_F); 256219820Sjeff rmpp->status = mad_get_field(mad, 0, IB_SA_RMPP_STATUS_F); 257219820Sjeff DEBUG("rmpp type %d status %d", rmpp->type, rmpp->status); 258219820Sjeff rmpp->d1.u = mad_get_field(mad, 0, IB_SA_RMPP_D1_F); 259219820Sjeff rmpp->d2.u = mad_get_field(mad, 0, IB_SA_RMPP_D2_F); 260219820Sjeff } 261219820Sjeff 262219820Sjeff if (data) 263219820Sjeff memcpy(data, mad + rpc->dataoffs, rpc->datasz); 264219820Sjeff 265219820Sjeff rpc->recsz = mad_get_field(mad, 0, IB_SA_ATTROFFS_F); 266219820Sjeff 267219820Sjeff return data; 268219820Sjeff} 269219820Sjeff 270219820Sjeffvoid * 271219820Sjeffmadrpc(ib_rpc_t *rpc, ib_portid_t *dport, void *payload, void *rcvdata) 272219820Sjeff{ 273219820Sjeff struct ibmad_port port; 274219820Sjeff 275219820Sjeff port.port_id = mad_portid; 276219820Sjeff port.class_agents[rpc->mgtclass] = mad_class_agent(rpc->mgtclass); 277219820Sjeff return mad_rpc(&port, rpc, dport, payload, rcvdata); 278219820Sjeff} 279219820Sjeff 280219820Sjeffvoid * 281219820Sjeffmadrpc_rmpp(ib_rpc_t *rpc, ib_portid_t *dport, ib_rmpp_hdr_t *rmpp, void *data) 282219820Sjeff{ 283219820Sjeff struct ibmad_port port; 284219820Sjeff 285219820Sjeff port.port_id = mad_portid; 286219820Sjeff port.class_agents[rpc->mgtclass] = mad_class_agent(rpc->mgtclass); 287219820Sjeff return mad_rpc_rmpp(&port, rpc, dport, rmpp, data); 288219820Sjeff} 289219820Sjeff 290219820Sjeffstatic pthread_mutex_t rpclock = PTHREAD_MUTEX_INITIALIZER; 291219820Sjeff 292219820Sjeffvoid 293219820Sjeffmadrpc_lock(void) 294219820Sjeff{ 295219820Sjeff pthread_mutex_lock(&rpclock); 296219820Sjeff} 297219820Sjeff 298219820Sjeffvoid 299219820Sjeffmadrpc_unlock(void) 300219820Sjeff{ 301219820Sjeff pthread_mutex_unlock(&rpclock); 302219820Sjeff} 303219820Sjeff 304219820Sjeffvoid 305219820Sjeffmadrpc_init(char *dev_name, int dev_port, int *mgmt_classes, int num_classes) 306219820Sjeff{ 307219820Sjeff if (umad_init() < 0) 308219820Sjeff IBPANIC("can't init UMAD library"); 309219820Sjeff 310219820Sjeff if ((mad_portid = umad_open_port(dev_name, dev_port)) < 0) 311219820Sjeff IBPANIC("can't open UMAD port (%s:%d)", dev_name, dev_port); 312219820Sjeff 313219820Sjeff if (num_classes >= MAX_CLASS) 314219820Sjeff IBPANIC("too many classes %d requested", num_classes); 315219820Sjeff 316219820Sjeff while (num_classes--) { 317219820Sjeff int rmpp_version = 0; 318219820Sjeff int mgmt = *mgmt_classes++; 319219820Sjeff 320219820Sjeff if (mgmt == IB_SA_CLASS) 321219820Sjeff rmpp_version = 1; 322219820Sjeff if (mad_register_client(mgmt, rmpp_version) < 0) 323219820Sjeff IBPANIC("client_register for mgmt class %d failed", mgmt); 324219820Sjeff } 325219820Sjeff} 326219820Sjeff 327219820Sjeffvoid * 328219820Sjeffmad_rpc_open_port(char *dev_name, int dev_port, 329219820Sjeff int *mgmt_classes, int num_classes) 330219820Sjeff{ 331219820Sjeff struct ibmad_port *p; 332219820Sjeff int port_id; 333219820Sjeff 334219820Sjeff if (num_classes >= MAX_CLASS) { 335219820Sjeff IBWARN("too many classes %d requested", num_classes); 336219820Sjeff errno = EINVAL; 337219820Sjeff return NULL; 338219820Sjeff } 339219820Sjeff 340219820Sjeff if (umad_init() < 0) { 341219820Sjeff IBWARN("can't init UMAD library"); 342219820Sjeff errno = ENODEV; 343219820Sjeff return NULL; 344219820Sjeff } 345219820Sjeff 346219820Sjeff p = malloc(sizeof(*p)); 347219820Sjeff if (!p) { 348219820Sjeff errno = ENOMEM; 349219820Sjeff return NULL; 350219820Sjeff } 351219820Sjeff memset(p, 0, sizeof(*p)); 352219820Sjeff 353219820Sjeff if ((port_id = umad_open_port(dev_name, dev_port)) < 0) { 354219820Sjeff IBWARN("can't open UMAD port (%s:%d)", dev_name, dev_port); 355219820Sjeff if (!errno) 356219820Sjeff errno = EIO; 357219820Sjeff free(p); 358219820Sjeff return NULL; 359219820Sjeff } 360219820Sjeff 361219820Sjeff while (num_classes--) { 362219820Sjeff int rmpp_version = 0; 363219820Sjeff int mgmt = *mgmt_classes++; 364219820Sjeff int agent; 365219820Sjeff 366219820Sjeff if (mgmt == IB_SA_CLASS) 367219820Sjeff rmpp_version = 1; 368219820Sjeff if (mgmt < 0 || mgmt >= MAX_CLASS || 369219820Sjeff (agent = mad_register_port_client(port_id, mgmt, 370219820Sjeff rmpp_version)) < 0) { 371219820Sjeff IBWARN("client_register for mgmt %d failed", mgmt); 372219820Sjeff if(!errno) 373219820Sjeff errno = EINVAL; 374219820Sjeff umad_close_port(port_id); 375219820Sjeff free(p); 376219820Sjeff return NULL; 377219820Sjeff } 378219820Sjeff p->class_agents[mgmt] = agent; 379219820Sjeff } 380219820Sjeff 381219820Sjeff p->port_id = port_id; 382219820Sjeff return p; 383219820Sjeff} 384219820Sjeff 385219820Sjeffvoid 386219820Sjeffmad_rpc_close_port(void *port_id) 387219820Sjeff{ 388219820Sjeff struct ibmad_port *p = port_id; 389219820Sjeff 390219820Sjeff umad_close_port(p->port_id); 391219820Sjeff free(p); 392219820Sjeff} 393219820Sjeff 394219820Sjeffuint8_t * 395219820Sjeffsa_call(void *rcvbuf, ib_portid_t *portid, ib_sa_call_t *sa, unsigned timeout) 396219820Sjeff{ 397219820Sjeff struct ibmad_port port; 398219820Sjeff 399219820Sjeff port.port_id = mad_portid; 400219820Sjeff port.class_agents[IB_SA_CLASS] = mad_class_agent(IB_SA_CLASS); 401219820Sjeff return sa_rpc_call(&port, rcvbuf, portid, sa, timeout); 402219820Sjeff} 403