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