| /* |
| * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. |
| * |
| * This software is available to you under a choice of one of two |
| * licenses. You may choose to be licensed under the terms of the GNU |
| * General Public License (GPL) Version 2, available from the file |
| * COPYING in the main directory of this source tree, or the |
| * OpenIB.org BSD license below: |
| * |
| * Redistribution and use in source and binary forms, with or |
| * without modification, are permitted provided that the following |
| * conditions are met: |
| * |
| * - Redistributions of source code must retain the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials |
| * provided with the distribution. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| #include <infiniband/umad.h> |
| #include <infiniband/mad.h> |
| |
| #include "mad_internal.h" |
| |
| #undef DEBUG |
| #define DEBUG if (ibdebug) IBWARN |
| |
| int mad_send(ib_rpc_t * rpc, ib_portid_t * dport, ib_rmpp_hdr_t * rmpp, |
| void *data) |
| { |
| return mad_send_via(rpc, dport, rmpp, data, ibmp); |
| } |
| |
| int mad_send_via(ib_rpc_t * rpc, ib_portid_t * dport, ib_rmpp_hdr_t * rmpp, |
| void *data, struct ibmad_port *srcport) |
| { |
| uint8_t pktbuf[1024]; |
| void *umad = pktbuf; |
| |
| memset(pktbuf, 0, umad_size() + IB_MAD_SIZE); |
| |
| DEBUG("rmpp %p data %p", rmpp, data); |
| |
| if (mad_build_pkt(umad, rpc, dport, rmpp, data) < 0) |
| return -1; |
| |
| if (ibdebug) { |
| IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz); |
| xdump(stderr, "mad send data\n", |
| (char *)umad_get_mad(umad) + rpc->dataoffs, rpc->datasz); |
| } |
| |
| if (umad_send(srcport->port_id, srcport->class_agents[rpc->mgtclass & 0xff], |
| umad, IB_MAD_SIZE, mad_get_timeout(srcport, rpc->timeout), |
| 0) < 0) { |
| IBWARN("send failed; %s", strerror(errno)); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| int mad_respond(void *umad, ib_portid_t * portid, uint32_t rstatus) |
| { |
| return mad_respond_via(umad, portid, rstatus, ibmp); |
| } |
| |
| int mad_respond_via(void *umad, ib_portid_t * portid, uint32_t rstatus, |
| struct ibmad_port *srcport) |
| { |
| uint8_t *mad = umad_get_mad(umad); |
| ib_mad_addr_t *mad_addr; |
| ib_rpc_t rpc = { 0 }; |
| ib_portid_t rport; |
| int is_smi; |
| |
| if (!portid) { |
| if (!(mad_addr = umad_get_mad_addr(umad))) { |
| errno = EINVAL; |
| return -1; |
| } |
| |
| memset(&rport, 0, sizeof(rport)); |
| |
| rport.lid = ntohs(mad_addr->lid); |
| rport.qp = ntohl(mad_addr->qpn); |
| rport.qkey = ntohl(mad_addr->qkey); |
| rport.sl = mad_addr->sl; |
| |
| portid = &rport; |
| } |
| |
| DEBUG("dest %s", portid2str(portid)); |
| |
| rpc.mgtclass = mad_get_field(mad, 0, IB_MAD_MGMTCLASS_F); |
| |
| rpc.method = mad_get_field(mad, 0, IB_MAD_METHOD_F); |
| if (rpc.method == IB_MAD_METHOD_SET) |
| rpc.method = IB_MAD_METHOD_GET; |
| if (rpc.method != IB_MAD_METHOD_SEND) |
| rpc.method |= IB_MAD_RESPONSE; |
| |
| rpc.attr.id = mad_get_field(mad, 0, IB_MAD_ATTRID_F); |
| rpc.attr.mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); |
| if (rpc.mgtclass == IB_SA_CLASS) |
| rpc.recsz = mad_get_field(mad, 0, IB_SA_ATTROFFS_F); |
| if (mad_is_vendor_range2(rpc.mgtclass)) |
| rpc.oui = mad_get_field(mad, 0, IB_VEND2_OUI_F); |
| |
| rpc.trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); |
| rpc.rstatus = rstatus; |
| |
| /* cleared by default: timeout, datasz, dataoffs, mkey, mask */ |
| |
| is_smi = rpc.mgtclass == IB_SMI_CLASS || |
| rpc.mgtclass == IB_SMI_DIRECT_CLASS; |
| |
| if (is_smi) |
| portid->qp = 0; |
| else if (!portid->qp) |
| portid->qp = 1; |
| |
| if (!portid->qkey && portid->qp == 1) |
| portid->qkey = IB_DEFAULT_QP1_QKEY; |
| |
| DEBUG |
| ("qp 0x%x class 0x%x method %d attr 0x%x mod 0x%x datasz %d off %d qkey %x", |
| portid->qp, rpc.mgtclass, rpc.method, rpc.attr.id, rpc.attr.mod, |
| rpc.datasz, rpc.dataoffs, portid->qkey); |
| |
| if (mad_build_pkt(umad, &rpc, portid, NULL, NULL) < 0) |
| return -1; |
| |
| if (ibdebug > 1) |
| xdump(stderr, "mad respond pkt\n", mad, IB_MAD_SIZE); |
| |
| if (umad_send |
| (srcport->port_id, srcport->class_agents[rpc.mgtclass], umad, |
| IB_MAD_SIZE, mad_get_timeout(srcport, rpc.timeout), 0) < 0) { |
| DEBUG("send failed; %s", strerror(errno)); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| void *mad_receive(void *umad, int timeout) |
| { |
| return mad_receive_via(umad, timeout, ibmp); |
| } |
| |
| void *mad_receive_via(void *umad, int timeout, struct ibmad_port *srcport) |
| { |
| void *mad = umad ? umad : umad_alloc(1, umad_size() + IB_MAD_SIZE); |
| int agent; |
| int length = IB_MAD_SIZE; |
| |
| if ((agent = umad_recv(srcport->port_id, mad, &length, |
| mad_get_timeout(srcport, timeout))) < 0) { |
| if (!umad) |
| umad_free(mad); |
| DEBUG("recv failed: %s", strerror(errno)); |
| return NULL; |
| } |
| |
| return mad; |
| } |
| |
| void *mad_alloc(void) |
| { |
| return umad_alloc(1, umad_size() + IB_MAD_SIZE); |
| } |
| |
| void mad_free(void *umad) |
| { |
| umad_free(umad); |
| } |