1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2009 HNR Consulting. All rights reserved. 4321936Shselasky * Copyright (c) 2011 Mellanox Technologies LTD. All rights reserved. 5321936Shselasky * 6321936Shselasky * This software is available to you under a choice of one of two 7321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 8321936Shselasky * General Public License (GPL) Version 2, available from the file 9321936Shselasky * COPYING in the main directory of this source tree, or the 10321936Shselasky * OpenIB.org BSD license below: 11321936Shselasky * 12321936Shselasky * Redistribution and use in source and binary forms, with or 13321936Shselasky * without modification, are permitted provided that the following 14321936Shselasky * conditions are met: 15321936Shselasky * 16321936Shselasky * - Redistributions of source code must retain the above 17321936Shselasky * copyright notice, this list of conditions and the following 18321936Shselasky * disclaimer. 19321936Shselasky * 20321936Shselasky * - Redistributions in binary form must reproduce the above 21321936Shselasky * copyright notice, this list of conditions and the following 22321936Shselasky * disclaimer in the documentation and/or other materials 23321936Shselasky * provided with the distribution. 24321936Shselasky * 25321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32321936Shselasky * SOFTWARE. 33321936Shselasky * 34321936Shselasky */ 35321936Shselasky 36321936Shselasky#if HAVE_CONFIG_H 37321936Shselasky# include <config.h> 38321936Shselasky#endif /* HAVE_CONFIG_H */ 39321936Shselasky 40321936Shselasky#include <stdio.h> 41321936Shselasky#include <stdlib.h> 42321936Shselasky#include <string.h> 43321936Shselasky#include <time.h> 44321936Shselasky#include <errno.h> 45321936Shselasky 46321936Shselasky#include <infiniband/umad.h> 47321936Shselasky#include <infiniband/mad.h> 48321936Shselasky 49321936Shselasky#include "mad_internal.h" 50321936Shselasky 51321936Shselasky#undef DEBUG 52321936Shselasky#define DEBUG if (ibdebug) IBWARN 53321936Shselasky 54321936Shselasky#define GET_IB_USERLAND_TID(tid) (tid & 0x00000000ffffffff) 55321936Shselasky/* 56321936Shselasky * Generate the 64 bit MAD transaction ID. The upper 32 bits are reserved for 57321936Shselasky * use by the kernel. We clear the upper 32 bits here, but MADs received from 58321936Shselasky * the kernel may contain kernel specific data in these bits, consequently 59321936Shselasky * userland TID matching should only be done on the lower 32 bits. 60321936Shselasky */ 61321936Shselaskyuint64_t mad_trid(void) 62321936Shselasky{ 63321936Shselasky static uint64_t trid; 64321936Shselasky uint64_t next; 65321936Shselasky 66321936Shselasky if (!trid) { 67321936Shselasky srandom((int)time(0) * getpid()); 68321936Shselasky trid = random(); 69321936Shselasky } 70321936Shselasky next = ++trid; 71321936Shselasky next = GET_IB_USERLAND_TID(next); 72321936Shselasky return next; 73321936Shselasky} 74321936Shselasky 75321936Shselaskyint mad_get_timeout(const struct ibmad_port *srcport, int override_ms) 76321936Shselasky{ 77321936Shselasky return (override_ms ? override_ms : 78321936Shselasky srcport->timeout ? srcport->timeout : madrpc_timeout); 79321936Shselasky} 80321936Shselasky 81321936Shselaskyint mad_get_retries(const struct ibmad_port *srcport) 82321936Shselasky{ 83321936Shselasky return (srcport->retries ? srcport->retries : madrpc_retries); 84321936Shselasky} 85321936Shselasky 86321936Shselaskyvoid *mad_encode(void *buf, ib_rpc_t * rpc, ib_dr_path_t * drpath, void *data) 87321936Shselasky{ 88321936Shselasky int is_resp = rpc->method & IB_MAD_RESPONSE; 89321936Shselasky int mgtclass; 90321936Shselasky 91321936Shselasky /* first word */ 92321936Shselasky mad_set_field(buf, 0, IB_MAD_METHOD_F, rpc->method); 93321936Shselasky mad_set_field(buf, 0, IB_MAD_RESPONSE_F, is_resp ? 1 : 0); 94321936Shselasky mgtclass = rpc->mgtclass & 0xff; 95321936Shselasky if (mgtclass == IB_SA_CLASS || mgtclass == IB_CC_CLASS) 96321936Shselasky mad_set_field(buf, 0, IB_MAD_CLASSVER_F, 2); 97321936Shselasky else 98321936Shselasky mad_set_field(buf, 0, IB_MAD_CLASSVER_F, 1); 99321936Shselasky mad_set_field(buf, 0, IB_MAD_MGMTCLASS_F, rpc->mgtclass & 0xff); 100321936Shselasky mad_set_field(buf, 0, IB_MAD_BASEVER_F, 1); 101321936Shselasky 102321936Shselasky /* second word */ 103321936Shselasky if ((rpc->mgtclass & 0xff) == IB_SMI_DIRECT_CLASS) { 104321936Shselasky if (!drpath) { 105321936Shselasky IBWARN("encoding dr mad without drpath (null)"); 106321936Shselasky errno = EINVAL; 107321936Shselasky return NULL; 108321936Shselasky } 109321936Shselasky if (drpath->cnt >= IB_SUBNET_PATH_HOPS_MAX) { 110321936Shselasky IBWARN("dr path with hop count %d", drpath->cnt); 111321936Shselasky errno = EINVAL; 112321936Shselasky return NULL; 113321936Shselasky } 114321936Shselasky mad_set_field(buf, 0, IB_DRSMP_HOPCNT_F, drpath->cnt); 115321936Shselasky mad_set_field(buf, 0, IB_DRSMP_HOPPTR_F, 116321936Shselasky is_resp ? drpath->cnt + 1 : 0x0); 117321936Shselasky mad_set_field(buf, 0, IB_DRSMP_STATUS_F, rpc->rstatus); 118321936Shselasky mad_set_field(buf, 0, IB_DRSMP_DIRECTION_F, is_resp ? 1 : 0); /* out */ 119321936Shselasky } else 120321936Shselasky mad_set_field(buf, 0, IB_MAD_STATUS_F, rpc->rstatus); 121321936Shselasky 122321936Shselasky /* words 3,4,5,6 */ 123321936Shselasky if (!rpc->trid) 124321936Shselasky rpc->trid = mad_trid(); 125321936Shselasky 126321936Shselasky mad_set_field64(buf, 0, IB_MAD_TRID_F, rpc->trid); 127321936Shselasky mad_set_field(buf, 0, IB_MAD_ATTRID_F, rpc->attr.id); 128321936Shselasky mad_set_field(buf, 0, IB_MAD_ATTRMOD_F, rpc->attr.mod); 129321936Shselasky 130321936Shselasky /* words 7,8 */ 131321936Shselasky mad_set_field64(buf, 0, IB_MAD_MKEY_F, rpc->mkey); 132321936Shselasky 133321936Shselasky if ((rpc->mgtclass & 0xff) == IB_SMI_DIRECT_CLASS) { 134321936Shselasky /* word 9 */ 135321936Shselasky mad_set_field(buf, 0, IB_DRSMP_DRDLID_F, 136321936Shselasky drpath->drdlid ? drpath->drdlid : 0xffff); 137321936Shselasky mad_set_field(buf, 0, IB_DRSMP_DRSLID_F, 138321936Shselasky drpath->drslid ? drpath->drslid : 0xffff); 139321936Shselasky 140321936Shselasky /* bytes 128 - 256 - by default should be zero due to memset */ 141321936Shselasky if (is_resp) 142321936Shselasky mad_set_array(buf, 0, IB_DRSMP_RPATH_F, drpath->p); 143321936Shselasky else 144321936Shselasky mad_set_array(buf, 0, IB_DRSMP_PATH_F, drpath->p); 145321936Shselasky } 146321936Shselasky 147321936Shselasky if ((rpc->mgtclass & 0xff) == IB_SA_CLASS) 148321936Shselasky mad_set_field64(buf, 0, IB_SA_COMPMASK_F, rpc->mask); 149321936Shselasky 150321936Shselasky if ((rpc->mgtclass & 0xff) == IB_CC_CLASS) { 151321936Shselasky ib_rpc_cc_t *rpccc = (ib_rpc_cc_t *)rpc; 152321936Shselasky mad_set_field64(buf, 0, IB_CC_CCKEY_F, rpccc->cckey); 153321936Shselasky } 154321936Shselasky 155321936Shselasky if (data) 156321936Shselasky memcpy((char *)buf + rpc->dataoffs, data, rpc->datasz); 157321936Shselasky 158321936Shselasky /* vendor mads range 2 */ 159321936Shselasky if (mad_is_vendor_range2(rpc->mgtclass & 0xff)) 160321936Shselasky mad_set_field(buf, 0, IB_VEND2_OUI_F, rpc->oui); 161321936Shselasky 162321936Shselasky return (uint8_t *) buf + IB_MAD_SIZE; 163321936Shselasky} 164321936Shselasky 165321936Shselaskyint mad_build_pkt(void *umad, ib_rpc_t * rpc, ib_portid_t * dport, 166321936Shselasky ib_rmpp_hdr_t * rmpp, void *data) 167321936Shselasky{ 168321936Shselasky uint8_t *p, *mad; 169321936Shselasky int lid_routed = (rpc->mgtclass & 0xff) != IB_SMI_DIRECT_CLASS; 170321936Shselasky int is_smi = ((rpc->mgtclass & 0xff) == IB_SMI_CLASS || 171321936Shselasky (rpc->mgtclass & 0xff) == IB_SMI_DIRECT_CLASS); 172321936Shselasky struct ib_mad_addr addr; 173321936Shselasky 174321936Shselasky if (!is_smi) 175321936Shselasky umad_set_addr(umad, dport->lid, dport->qp, dport->sl, 176321936Shselasky dport->qkey); 177321936Shselasky else if (lid_routed) 178321936Shselasky umad_set_addr(umad, dport->lid, dport->qp, 0, 0); 179321936Shselasky else if ((dport->drpath.drslid != 0xffff) && (dport->lid > 0)) 180321936Shselasky umad_set_addr(umad, dport->lid, 0, 0, 0); 181321936Shselasky else 182321936Shselasky umad_set_addr(umad, 0xffff, 0, 0, 0); 183321936Shselasky 184321936Shselasky if (dport->grh_present && !is_smi) { 185321936Shselasky addr.grh_present = 1; 186321936Shselasky memcpy(addr.gid, dport->gid, 16); 187321936Shselasky addr.hop_limit = 0xff; 188321936Shselasky addr.traffic_class = 0; 189321936Shselasky addr.flow_label = 0; 190321936Shselasky umad_set_grh(umad, &addr); 191321936Shselasky } else 192321936Shselasky umad_set_grh(umad, 0); 193321936Shselasky umad_set_pkey(umad, is_smi ? 0 : dport->pkey_idx); 194321936Shselasky 195321936Shselasky mad = umad_get_mad(umad); 196321936Shselasky p = mad_encode(mad, rpc, lid_routed ? 0 : &dport->drpath, data); 197321936Shselasky if (!p) 198321936Shselasky return -1; 199321936Shselasky 200321936Shselasky if (!is_smi && rmpp) { 201321936Shselasky mad_set_field(mad, 0, IB_SA_RMPP_VERS_F, 1); 202321936Shselasky mad_set_field(mad, 0, IB_SA_RMPP_TYPE_F, rmpp->type); 203321936Shselasky mad_set_field(mad, 0, IB_SA_RMPP_RESP_F, 0x3f); 204321936Shselasky mad_set_field(mad, 0, IB_SA_RMPP_FLAGS_F, rmpp->flags); 205321936Shselasky mad_set_field(mad, 0, IB_SA_RMPP_STATUS_F, rmpp->status); 206321936Shselasky mad_set_field(mad, 0, IB_SA_RMPP_D1_F, rmpp->d1.u); 207321936Shselasky mad_set_field(mad, 0, IB_SA_RMPP_D2_F, rmpp->d2.u); 208321936Shselasky } 209321936Shselasky 210321936Shselasky return ((int)(p - mad)); 211321936Shselasky} 212