| /* | |
| * 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; | |
| /* | |
| * The received pkey_index is resolved against our local P_Key | |
| * table, so echoing it sends the reply on the same partition | |
| * the request arrived on. | |
| */ | |
| rport.pkey_idx = umad_get_pkey(umad); | |
| 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); | |
| } |