1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004,2005 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 <netinet/in.h>
45219820Sjeff
46219820Sjeff#include <infiniband/common.h>
47219820Sjeff#include <infiniband/umad.h>
48219820Sjeff#include <mad.h>
49219820Sjeff
50219820Sjeff#undef DEBUG
51219820Sjeff#define DEBUG	if (ibdebug)	IBWARN
52219820Sjeff
53219820Sjeffint
54219820Sjeffmad_send(ib_rpc_t *rpc, ib_portid_t *dport, ib_rmpp_hdr_t *rmpp, void *data)
55219820Sjeff{
56219820Sjeff	uint8_t pktbuf[1024];
57219820Sjeff	void *umad = pktbuf;
58219820Sjeff
59219820Sjeff	memset(pktbuf, 0, umad_size());
60219820Sjeff
61219820Sjeff	DEBUG("rmpp %p data %p", rmpp, data);
62219820Sjeff
63219820Sjeff	if (mad_build_pkt(umad, rpc, dport, rmpp, data) < 0)
64219820Sjeff		return 0;
65219820Sjeff
66219820Sjeff	if (ibdebug) {
67219820Sjeff		IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz);
68219820Sjeff		xdump(stderr, "mad send data\n",
69219820Sjeff			(char *)umad_get_mad(umad) + rpc->dataoffs, rpc->datasz);
70219820Sjeff	}
71219820Sjeff
72219820Sjeff	if (umad_send(madrpc_portid(), mad_class_agent(rpc->mgtclass),
73219820Sjeff		      umad, IB_MAD_SIZE, rpc->timeout, 0) < 0) {
74219820Sjeff		IBWARN("send failed; %m");
75219820Sjeff		return -1;
76219820Sjeff	}
77219820Sjeff
78219820Sjeff	return 0;
79219820Sjeff}
80219820Sjeff
81219820Sjeffint
82219820Sjeffmad_respond(void *umad, ib_portid_t *portid, uint32_t rstatus)
83219820Sjeff{
84219820Sjeff	uint8_t *mad = umad_get_mad(umad);
85219820Sjeff	ib_mad_addr_t *mad_addr;
86219820Sjeff	ib_rpc_t rpc = {0};
87219820Sjeff	ib_portid_t rport;
88219820Sjeff	int is_smi;
89219820Sjeff
90219820Sjeff	if (!portid) {
91219820Sjeff		if (!(mad_addr = umad_get_mad_addr(umad)))
92219820Sjeff			return -1;
93219820Sjeff
94219820Sjeff		memset(&rport, 0, sizeof(rport));
95219820Sjeff
96219820Sjeff		rport.lid = ntohs(mad_addr->lid);
97219820Sjeff		rport.qp = ntohl(mad_addr->qpn);
98219820Sjeff		rport.qkey = ntohl(mad_addr->qkey);
99219820Sjeff		rport.sl = mad_addr->sl;
100219820Sjeff
101219820Sjeff		portid = &rport;
102219820Sjeff	}
103219820Sjeff
104219820Sjeff	DEBUG("dest %s", portid2str(portid));
105219820Sjeff
106219820Sjeff	rpc.mgtclass = mad_get_field(mad, 0, IB_MAD_MGMTCLASS_F);
107219820Sjeff
108219820Sjeff	rpc.method = mad_get_field(mad, 0, IB_MAD_METHOD_F);
109219820Sjeff	if (rpc.method == IB_MAD_METHOD_SET)
110219820Sjeff		rpc.method = IB_MAD_METHOD_GET;
111219820Sjeff	if (rpc.method != IB_MAD_METHOD_SEND)
112219820Sjeff		rpc.method |= IB_MAD_RESPONSE;
113219820Sjeff
114219820Sjeff	rpc.attr.id = mad_get_field(mad, 0, IB_MAD_ATTRID_F);
115219820Sjeff	rpc.attr.mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F);
116219820Sjeff	if (rpc.mgtclass == IB_SA_CLASS)
117219820Sjeff		rpc.recsz = mad_get_field(mad, 0, IB_SA_ATTROFFS_F);
118219820Sjeff	if (mad_is_vendor_range2(rpc.mgtclass))
119219820Sjeff		rpc.oui = mad_get_field(mad, 0, IB_VEND2_OUI_F);
120219820Sjeff
121219820Sjeff	rpc.trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);
122219820Sjeff
123219820Sjeff	/* cleared by default: timeout, datasz, dataoffs, mkey, mask */
124219820Sjeff
125219820Sjeff	is_smi = rpc.mgtclass == IB_SMI_CLASS ||
126219820Sjeff		 rpc.mgtclass == IB_SMI_DIRECT_CLASS;
127219820Sjeff
128219820Sjeff	if (is_smi)
129219820Sjeff		portid->qp = 0;
130219820Sjeff	else if (!portid->qp)
131219820Sjeff		 portid->qp = 1;
132219820Sjeff
133219820Sjeff	if (!portid->qkey && portid->qp == 1)
134219820Sjeff		portid->qkey = IB_DEFAULT_QP1_QKEY;
135219820Sjeff
136219820Sjeff	DEBUG("qp 0x%x class 0x%x method %d attr 0x%x mod 0x%x datasz %d off %d qkey %x",
137219820Sjeff		portid->qp, rpc.mgtclass, rpc.method, rpc.attr.id, rpc.attr.mod,
138219820Sjeff		rpc.datasz, rpc.dataoffs, portid->qkey);
139219820Sjeff
140219820Sjeff	if (mad_build_pkt(umad, &rpc, portid, 0, 0) < 0)
141219820Sjeff		return -1;
142219820Sjeff
143219820Sjeff	if (ibdebug > 1)
144219820Sjeff		xdump(stderr, "mad respond pkt\n", mad, IB_MAD_SIZE);
145219820Sjeff
146219820Sjeff	if (umad_send(madrpc_portid(), mad_class_agent(rpc.mgtclass), umad,
147219820Sjeff		      IB_MAD_SIZE, rpc.timeout, 0) < 0) {
148219820Sjeff		DEBUG("send failed; %m");
149219820Sjeff		return -1;
150219820Sjeff	}
151219820Sjeff
152219820Sjeff	return 0;
153219820Sjeff}
154219820Sjeff
155219820Sjeffvoid *
156219820Sjeffmad_receive(void *umad, int timeout)
157219820Sjeff{
158219820Sjeff	void *mad = umad ? umad : umad_alloc(1, umad_size() + IB_MAD_SIZE);
159219820Sjeff	int agent;
160219820Sjeff	int length = IB_MAD_SIZE;
161219820Sjeff
162219820Sjeff	if ((agent = umad_recv(madrpc_portid(), mad,
163219820Sjeff			       &length, timeout)) < 0) {
164219820Sjeff		if (!umad)
165219820Sjeff			umad_free(mad);
166219820Sjeff		DEBUG("recv failed: %m");
167219820Sjeff		return 0;
168219820Sjeff	}
169219820Sjeff
170219820Sjeff	return mad;
171219820Sjeff}
172219820Sjeff
173219820Sjeffvoid *
174219820Sjeffmad_alloc(void)
175219820Sjeff{
176219820Sjeff	return umad_alloc(1, umad_size() + IB_MAD_SIZE);
177219820Sjeff}
178219820Sjeff
179219820Sjeffvoid
180219820Sjeffmad_free(void *umad)
181219820Sjeff{
182219820Sjeff	umad_free(umad);
183219820Sjeff}
184