libibmad: updated based on merge feedback
[mirror/winof/.git] / ulp / libibmad / src / rpc.c
1 /*
2  * Copyright (c) 2004-2006 Voltaire Inc.  All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  *
32  */
33
34 #if HAVE_CONFIG_H
35 #  include <config.h>
36 #endif /* HAVE_CONFIG_H */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <errno.h>
42
43 #include <infiniband/umad.h>
44 #include "mad.h"
45
46 #define MAX_CLASS 256
47
48 struct ibmad_port {
49         int port_id;  /* file descriptor returned by umad_open() */
50         int class_agents[MAX_CLASS]; /* class2agent mapper */
51 };
52
53 int ibdebug;
54
55 static int mad_portid = -1;
56 static int iberrs;
57
58 static int madrpc_retries = MAD_DEF_RETRIES;
59 static int def_madrpc_timeout = MAD_DEF_TIMEOUT_MS;
60 static void *save_mad;
61 static int save_mad_len = 256;
62
63 #undef DEBUG
64 #define DEBUG   if (ibdebug)    IBWARN
65 #define ERRS    if (iberrs || ibdebug)  IBWARN
66
67 #define MAD_TID(mad)    (*((uint64_t *)((char *)(mad) + 8)))
68
69 void
70 madrpc_show_errors(int set)
71 {
72         iberrs = set;
73 }
74
75 void
76 madrpc_save_mad(void *madbuf, int len)
77 {
78         save_mad = madbuf;
79         save_mad_len = len;
80 }
81
82 int
83 madrpc_set_retries(int retries)
84 {
85         if (retries > 0)
86                 madrpc_retries = retries;
87         return madrpc_retries;
88 }
89
90 int
91 madrpc_set_timeout(int timeout)
92 {
93         def_madrpc_timeout = timeout;
94         return 0;
95 }
96
97 int
98 madrpc_def_timeout(void)
99 {
100         return def_madrpc_timeout;
101 }
102
103 int
104 madrpc_portid(void)
105 {
106         return mad_portid;
107 }
108
109 static int
110 _do_madrpc(int port_id, void *sndbuf, void *rcvbuf, int agentid, int len,
111            int timeout)
112 {
113         uint32_t trid; /* only low 32 bits */
114         int retries;
115         int length, status;
116
117         if (!timeout)
118                 timeout = def_madrpc_timeout;
119
120         if (ibdebug > 1) {
121                 IBWARN(">>> sending: len %d pktsz %zu", len, umad_size() + len);
122                 xdump(stderr, "send buf\n", sndbuf, umad_size() + len);
123         }
124
125         if (save_mad) {
126                 memcpy(save_mad, umad_get_mad(sndbuf),
127                        save_mad_len < len ? save_mad_len : len);
128                 save_mad = 0;
129         }
130
131         trid = (uint32_t)mad_get_field64(umad_get_mad(sndbuf), 0, IB_MAD_TRID_F);
132
133         for (retries = 0; retries < madrpc_retries; retries++) {
134                 if (retries) {
135                         ERRS("retry %d (timeout %d ms)", retries, timeout);
136                 }
137
138                 length = len;
139                 if (umad_send(port_id, agentid, sndbuf, length, timeout, 0) < 0) {
140                         IBWARN("send failed; %m");
141                         return -1;
142                 }
143
144                 /* Use same timeout on receive side just in case */
145                 /* send packet is lost somewhere. */
146                 do {
147                         if (umad_recv(port_id, rcvbuf, &length, timeout) < 0) {
148                                 IBWARN("recv failed: %m");
149                                 return -1;
150                         }
151
152                         if (ibdebug > 1) {
153                                 IBWARN("rcv buf:");
154                                 xdump(stderr, "rcv buf\n", umad_get_mad(rcvbuf), IB_MAD_SIZE);
155                         }
156                 } while ((uint32_t)mad_get_field64(umad_get_mad(rcvbuf), 0, IB_MAD_TRID_F) != trid);
157
158                 status = umad_status(rcvbuf);
159                 if (!status)
160                         return length;          /* done */
161                 if (status == ENOMEM)
162                         return length;
163         }
164
165         ERRS("timeout after %d retries, %d ms", retries, timeout * retries);
166         return -1;
167 }
168
169 void *
170 mad_rpc(const void *port_id, ib_rpc_t *rpc, ib_portid_t *dport, void *payload,
171         void *rcvdata)
172 {
173         const struct ibmad_port *p = port_id;
174         int status, len;
175         uint8_t sndbuf[1024], rcvbuf[1024], *mad;
176
177         len = 0;
178         memset(sndbuf, 0, umad_size() + IB_MAD_SIZE);
179
180         if ((len = mad_build_pkt(sndbuf, rpc, dport, 0, payload)) < 0)
181                 return 0;
182
183         if ((len = _do_madrpc(p->port_id, sndbuf, rcvbuf,
184                               p->class_agents[rpc->mgtclass],
185                               len, rpc->timeout)) < 0) {
186                 IBWARN("_do_madrpc failed; dport (%s)", portid2str(dport));
187                 return 0;
188         }
189
190         mad = umad_get_mad(rcvbuf);
191
192         if ((status = mad_get_field(mad, 0, IB_DRSMP_STATUS_F)) != 0) {
193                 ERRS("MAD completed with error status 0x%x; dport (%s)",
194                         status, portid2str(dport));
195                 return 0;
196         }
197
198         if (ibdebug) {
199                 IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz);
200                 xdump(stderr, "mad data\n", mad + rpc->dataoffs, rpc->datasz);
201         }
202
203         if (rcvdata)
204                 memcpy(rcvdata, mad + rpc->dataoffs, rpc->datasz);
205
206         return rcvdata;
207 }
208
209 void *
210 mad_rpc_rmpp(const void *port_id, ib_rpc_t *rpc, ib_portid_t *dport,
211              ib_rmpp_hdr_t *rmpp, void *data)
212 {
213         const struct ibmad_port *p = port_id;
214         int status, len;
215         uint8_t sndbuf[1024], rcvbuf[1024], *mad;
216
217         memset(sndbuf, 0, umad_size() + IB_MAD_SIZE);
218
219         DEBUG("rmpp %p data %p", rmpp, data);
220
221         if ((len = mad_build_pkt(sndbuf, rpc, dport, rmpp, data)) < 0)
222                 return 0;
223
224         if ((len = _do_madrpc(p->port_id, sndbuf, rcvbuf,
225                               p->class_agents[rpc->mgtclass],
226                               len, rpc->timeout)) < 0) {
227                 IBWARN("_do_madrpc failed; dport (%s)", portid2str(dport));
228                 return 0;
229         }
230
231         mad = umad_get_mad(rcvbuf);
232
233         if ((status = mad_get_field(mad, 0, IB_MAD_STATUS_F)) != 0) {
234                 ERRS("MAD completed with error status 0x%x; dport (%s)",
235                         status, portid2str(dport));
236                 return 0;
237         }
238
239         if (ibdebug) {
240                 IBWARN("data offs %d sz %d", rpc->dataoffs, rpc->datasz);
241                 xdump(stderr, "rmpp mad data\n", mad + rpc->dataoffs,
242                       rpc->datasz);
243         }
244
245         if (rmpp) {
246                 rmpp->flags = mad_get_field(mad, 0, IB_SA_RMPP_FLAGS_F);
247                 if ((rmpp->flags & 0x3) &&
248                     mad_get_field(mad, 0, IB_SA_RMPP_VERS_F) != 1) {
249                         IBWARN("bad rmpp version");
250                         return 0;
251                 }
252                 rmpp->type = mad_get_field(mad, 0, IB_SA_RMPP_TYPE_F);
253                 rmpp->status = mad_get_field(mad, 0, IB_SA_RMPP_STATUS_F);
254                 DEBUG("rmpp type %d status %d", rmpp->type, rmpp->status);
255                 rmpp->d1.u = mad_get_field(mad, 0, IB_SA_RMPP_D1_F);
256                 rmpp->d2.u = mad_get_field(mad, 0, IB_SA_RMPP_D2_F);
257         }
258
259         if (data)
260                 memcpy(data, mad + rpc->dataoffs, rpc->datasz);
261
262         rpc->recsz = mad_get_field(mad, 0, IB_SA_ATTROFFS_F);
263
264         return data;
265 }
266
267 void *
268 madrpc(ib_rpc_t *rpc, ib_portid_t *dport, void *payload, void *rcvdata)
269 {
270         struct ibmad_port port;
271
272         port.port_id = mad_portid;
273         port.class_agents[rpc->mgtclass] = mad_class_agent(rpc->mgtclass);
274         return mad_rpc(&port, rpc, dport, payload, rcvdata);
275 }
276
277 void *
278 madrpc_rmpp(ib_rpc_t *rpc, ib_portid_t *dport, ib_rmpp_hdr_t *rmpp, void *data)
279 {
280         struct ibmad_port port;
281
282         port.port_id = mad_portid;
283         port.class_agents[rpc->mgtclass] = mad_class_agent(rpc->mgtclass);
284         return mad_rpc_rmpp(&port, rpc, dport, rmpp, data);
285 }
286
287 void
288 madrpc_init(char *dev_name, int dev_port, int *mgmt_classes, int num_classes)
289 {
290         if (umad_init() < 0)
291                 IBPANIC("can't init UMAD library");
292
293         if ((mad_portid = umad_open_port(dev_name, dev_port)) < 0)
294                 IBPANIC("can't open UMAD port (%s:%d)", dev_name, dev_port);
295
296         if (num_classes >= MAX_CLASS)
297                 IBPANIC("too many classes %d requested", num_classes);
298
299         while (num_classes--) {
300                 uint8_t rmpp_version = 0;
301                 int mgmt = *mgmt_classes++;
302
303                 if (mgmt == IB_SA_CLASS)
304                         rmpp_version = 1;
305                 if (mad_register_client(mgmt, rmpp_version) < 0)
306                         IBPANIC("client_register for mgmt class %d failed", mgmt);
307         }
308 }
309
310 void *
311 mad_rpc_open_port(char *dev_name, int dev_port,
312                   int *mgmt_classes, int num_classes)
313 {
314         struct ibmad_port *p;
315         int port_id;
316
317         if (num_classes >= MAX_CLASS) {
318                 IBWARN("too many classes %d requested", num_classes);
319                 errno = EINVAL;
320                 return NULL;
321         }
322
323         if (umad_init() < 0) {
324                 IBWARN("can't init UMAD library");
325                 errno = ENODEV;
326                 return NULL;
327         }
328
329         p = malloc(sizeof(*p));
330         if (!p) {
331                 errno = ENOMEM;
332                 return NULL;
333         }
334         memset(p, 0, sizeof(*p));
335
336         if ((port_id = umad_open_port(dev_name, dev_port)) < 0) {
337                 IBWARN("can't open UMAD port (%s:%d)", dev_name, dev_port);
338                 if (!errno)
339                         errno = EIO;
340                 free(p);
341                 return NULL;
342         }
343
344         while (num_classes--) {
345                 uint8_t rmpp_version = 0;
346                 int mgmt = *mgmt_classes++;
347                 int agent;
348
349                 if (mgmt == IB_SA_CLASS)
350                         rmpp_version = 1;
351                 if (mgmt < 0 || mgmt >= MAX_CLASS ||
352                     (agent = mad_register_port_client(port_id, mgmt,
353                                                       rmpp_version)) < 0) {
354                         IBWARN("client_register for mgmt %d failed", mgmt);
355                         if(!errno)
356                                 errno = EINVAL;
357                         umad_close_port(port_id);
358                         free(p);
359                         return NULL;
360                 }
361                 p->class_agents[mgmt] = agent;
362         }
363
364         p->port_id = port_id;
365         return p;
366 }
367
368 void
369 mad_rpc_close_port(void *port_id)
370 {
371         struct ibmad_port *p = port_id;
372
373         umad_close_port(p->port_id);
374         free(p);
375 }
376
377 uint8_t *
378 sa_call(void *rcvbuf, ib_portid_t *portid, ib_sa_call_t *sa, unsigned timeout)
379 {
380         struct ibmad_port port;
381
382         port.port_id = mad_portid;
383         port.class_agents[IB_SA_CLASS] = mad_class_agent(IB_SA_CLASS);
384         return sa_rpc_call(&port, rcvbuf, portid, sa, timeout);
385 }