c75ac2d5162aa7bd0839ea0e891ab57c9f14048d
[mirror/winof/.git] / ulp / ipoib / kernel / ipoib_endpoint.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.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 AND\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  * $Id$\r
30  */\r
31 \r
32 \r
33 \r
34 #include "ipoib_endpoint.h"\r
35 #include "ipoib_port.h"\r
36 #include "ipoib_debug.h"\r
37 #if defined(EVENT_TRACING)\r
38 #ifdef offsetof\r
39 #undef offsetof\r
40 #endif\r
41 #include "ipoib_endpoint.tmh"\r
42 #endif\r
43 #include <complib/cl_atomic.h>\r
44 \r
45 \r
46 static void\r
47 __endpt_destroying(\r
48         IN                              cl_obj_t*                                       p_obj );\r
49 \r
50 static void\r
51 __endpt_cleanup(\r
52         IN                              cl_obj_t*                                       p_obj );\r
53 \r
54 static void\r
55 __endpt_free(\r
56         IN                              cl_obj_t*                                       p_obj );\r
57 \r
58 static ib_api_status_t\r
59 __create_mcast_av(\r
60         IN                              ib_pd_handle_t                          h_pd,\r
61         IN                              uint8_t                                         port_num,\r
62         IN                              ib_member_rec_t* const          p_member_rec,\r
63                 OUT                     ib_av_handle_t* const           ph_av );\r
64 \r
65 static inline ipoib_port_t*\r
66 __endpt_parent(\r
67         IN                              ipoib_endpt_t* const            p_endpt );\r
68 \r
69 static void\r
70 __path_query_cb(\r
71         IN                              ib_query_rec_t                          *p_query_rec );\r
72 \r
73 static void\r
74 __endpt_resolve(\r
75         IN                              ipoib_endpt_t* const            p_endpt );\r
76 \r
77 \r
78 ipoib_endpt_t*\r
79 ipoib_endpt_create(\r
80         IN              const   ib_gid_t* const                         p_dgid,\r
81         IN              const   net16_t                                         dlid,\r
82         IN              const   net32_t                                         qpn )\r
83 {\r
84         ipoib_endpt_t   *p_endpt;\r
85         cl_status_t             status;\r
86 \r
87         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
88 \r
89         p_endpt = cl_zalloc( sizeof(ipoib_endpt_t) );\r
90         if( !p_endpt )\r
91         {\r
92                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
93                         ("Failed to allocate endpoint (%d bytes)\n",\r
94                         sizeof(ipoib_endpt_t)) );\r
95                 return NULL;\r
96         }\r
97 \r
98         cl_obj_construct( &p_endpt->obj, IPOIB_OBJ_ENDPOINT );\r
99 \r
100         status = cl_obj_init( &p_endpt->obj, CL_DESTROY_ASYNC,\r
101                 __endpt_destroying, __endpt_cleanup, __endpt_free );\r
102 \r
103         p_endpt->dgid = *p_dgid;\r
104         p_endpt->dlid = dlid;\r
105         p_endpt->qpn = qpn;\r
106 \r
107         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
108         return p_endpt;\r
109 }\r
110 \r
111 \r
112 static ib_api_status_t\r
113 __create_mcast_av(\r
114         IN                              ib_pd_handle_t                          h_pd,\r
115         IN                              uint8_t                                         port_num,\r
116         IN                              ib_member_rec_t* const          p_member_rec,\r
117                 OUT                     ib_av_handle_t* const           ph_av )\r
118 {\r
119         ib_av_attr_t    av_attr;\r
120         uint32_t                flow_lbl;\r
121         uint8_t                 hop_lmt;\r
122         ib_api_status_t status;\r
123         ipoib_endpt_t   *p_endpt;\r
124 \r
125         IPOIB_ENTER( IPOIB_DBG_MCAST );\r
126 \r
127         p_endpt = PARENT_STRUCT(ph_av, ipoib_endpt_t, h_av );\r
128 \r
129         cl_memclr( &av_attr, sizeof(ib_av_attr_t) );\r
130         av_attr.port_num = port_num;\r
131         ib_member_get_sl_flow_hop( p_member_rec->sl_flow_hop,\r
132                 &av_attr.sl, &flow_lbl, &hop_lmt );\r
133         av_attr.dlid = p_member_rec->mlid;\r
134         av_attr.grh_valid = TRUE;\r
135         av_attr.grh.hop_limit = hop_lmt;\r
136         av_attr.grh.dest_gid = p_member_rec->mgid;\r
137         av_attr.grh.src_gid = p_member_rec->port_gid;\r
138         av_attr.grh.ver_class_flow =\r
139                 ib_grh_set_ver_class_flow( 6, p_member_rec->tclass, flow_lbl );\r
140         av_attr.static_rate = p_member_rec->rate & IB_PATH_REC_BASE_MASK;\r
141         av_attr.path_bits = 0;\r
142         /* port is not attached to endpoint at this point, so use endpt ifc reference */\r
143         status = p_endpt->p_ifc->create_av( h_pd, &av_attr, ph_av );\r
144 \r
145         if( status != IB_SUCCESS )\r
146         {\r
147                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
148                         ("ib_create_av returned %s\n",\r
149                         p_endpt->p_ifc->get_err_str( status )) );\r
150         }\r
151 \r
152         IPOIB_EXIT( IPOIB_DBG_MCAST );\r
153         return status;\r
154 }\r
155 \r
156 \r
157 ib_api_status_t\r
158 ipoib_endpt_set_mcast(\r
159         IN                              ipoib_endpt_t* const            p_endpt,\r
160         IN                              ib_pd_handle_t                          h_pd,\r
161         IN                              uint8_t                                         port_num,\r
162         IN                              ib_mcast_rec_t* const           p_mcast_rec )\r
163 {\r
164         ib_api_status_t status;\r
165 \r
166         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
167 \r
168         IPOIB_PRINT(TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
169                 ("Create av for MAC: %02X-%02X-%02X-%02X-%02X-%02X\n",\r
170                 p_endpt->mac.addr[0], p_endpt->mac.addr[1],\r
171                 p_endpt->mac.addr[2], p_endpt->mac.addr[3],\r
172                 p_endpt->mac.addr[4], p_endpt->mac.addr[5]) );\r
173                 \r
174         status = __create_mcast_av( h_pd, port_num, p_mcast_rec->p_member_rec,\r
175                 &p_endpt->h_av );\r
176         if( status != IB_SUCCESS )\r
177         {\r
178                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
179                         ("__create_mcast_av returned %s\n", \r
180                         p_endpt->p_ifc->get_err_str( status )) );\r
181                 return status;\r
182         }\r
183         p_endpt->h_mcast = p_mcast_rec->h_mcast;\r
184 \r
185         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
186         return IB_SUCCESS;\r
187 }\r
188 \r
189 \r
190 static void\r
191 __endpt_destroying(\r
192         IN                              cl_obj_t*                                       p_obj )\r
193 {\r
194         ipoib_endpt_t   *p_endpt;\r
195         ipoib_port_t    *p_port;\r
196 \r
197         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
198 \r
199         p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
200         p_port = __endpt_parent( p_endpt );\r
201 \r
202         cl_obj_lock( p_obj );\r
203         if( p_endpt->h_query )\r
204         {\r
205                 p_port->p_adapter->p_ifc->cancel_query(\r
206                         p_port->p_adapter->h_al, p_endpt->h_query );\r
207                 p_endpt->h_query = NULL;\r
208         }\r
209         cl_obj_unlock( p_obj );\r
210         \r
211         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
212 }\r
213 \r
214 \r
215 static void\r
216 __endpt_cleanup(\r
217         IN                              cl_obj_t*                                       p_obj )\r
218 {\r
219         ipoib_endpt_t   *p_endpt;\r
220         ipoib_port_t    *p_port;\r
221 \r
222         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
223 \r
224         p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
225         p_port = __endpt_parent( p_endpt );\r
226 \r
227         /* Resume sends so that any pending sends for this endpoint fail. */\r
228         ipoib_port_resume( p_port );\r
229 \r
230         /* Leave the multicast group if it exists. */\r
231         if( p_endpt->h_mcast )\r
232         {\r
233                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
234                         ("Leaving MCast group\n") );\r
235                 p_port->p_adapter->p_ifc->leave_mcast( p_endpt->h_mcast, NULL );\r
236         }\r
237 \r
238         /* Destroy the AV if it exists. */\r
239         if( p_endpt->h_av )\r
240                 p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av );\r
241 \r
242         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
243 }\r
244 \r
245 \r
246 static void\r
247 __endpt_free(\r
248         IN                              cl_obj_t*                                       p_obj )\r
249 {\r
250         ipoib_endpt_t   *p_endpt;\r
251 \r
252         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
253 \r
254         p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
255 \r
256         cl_obj_deinit( p_obj );\r
257         cl_free( p_endpt );\r
258 \r
259         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
260 }\r
261 \r
262 \r
263 static inline ipoib_port_t*\r
264 __endpt_parent(\r
265         IN                              ipoib_endpt_t* const            p_endpt )\r
266 {\r
267         return PARENT_STRUCT( p_endpt->rel.p_parent_obj, ipoib_port_t, obj );\r
268 }\r
269 \r
270 \r
271 /*\r
272  * This function is called with the port object's send lock held and\r
273  * a reference held on the endpoint.  If we fail, we release the reference.\r
274  */\r
275 NDIS_STATUS\r
276 ipoib_endpt_queue(\r
277         IN                              ipoib_endpt_t* const            p_endpt )\r
278 {\r
279         ib_api_status_t status;\r
280         ipoib_port_t    *p_port;\r
281         ib_query_req_t  query;\r
282         ib_user_query_t info;\r
283         ib_path_rec_t   path;\r
284 \r
285         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
286 \r
287         if( p_endpt->h_av )\r
288         {\r
289                 IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
290                 return NDIS_STATUS_SUCCESS;\r
291         }\r
292 \r
293         if( p_endpt->h_query ||\r
294                 p_endpt->qpn == CL_HTON32(0x00FFFFFF) )\r
295         {\r
296                 ipoib_endpt_deref( p_endpt );\r
297                 IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
298                 return NDIS_STATUS_PENDING;\r
299         }\r
300 \r
301         /* This is the first packet for this endpoint.  Query the SA. */\r
302         p_port = __endpt_parent( p_endpt );\r
303 \r
304         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
305 \r
306         info.method = IB_MAD_METHOD_GETTABLE;\r
307         info.attr_id = IB_MAD_ATTR_PATH_RECORD;\r
308         info.attr_size = sizeof(ib_path_rec_t);\r
309         info.comp_mask = IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID |\r
310                 IB_PR_COMPMASK_REVERSIBLE | IB_PR_COMPMASK_NUM_PATH;\r
311         info.p_attr = &path;\r
312 \r
313         cl_memclr( &path, sizeof(ib_path_rec_t) );\r
314         path.dgid = p_endpt->dgid;\r
315         ib_gid_set_default( &path.sgid, p_port->p_adapter->guids.port_guid );\r
316         path.num_path = 0x1;\r
317 \r
318         cl_memclr( &query, sizeof(ib_query_req_t) );\r
319         query.query_type = IB_QUERY_USER_DEFINED;\r
320         query.p_query_input = &info;\r
321         query.port_guid = p_port->p_adapter->guids.port_guid;\r
322         query.timeout_ms = p_port->p_adapter->params.sa_timeout;\r
323         query.retry_cnt = p_port->p_adapter->params.sa_retry_cnt;\r
324 \r
325         query.query_context = p_endpt;\r
326         query.pfn_query_cb = __path_query_cb;\r
327 \r
328         status = p_port->p_adapter->p_ifc->query(\r
329                 p_port->p_adapter->h_al, &query, &p_endpt->h_query );\r
330         if( status != IB_SUCCESS )\r
331         {\r
332                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ENDPT,\r
333                         ("ib_query for path returned %s\n", \r
334                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
335                 ipoib_endpt_deref( p_endpt );\r
336                 /* Flag the adapter as hung. */\r
337                 p_port->p_adapter->hung = TRUE;\r
338         }\r
339 \r
340         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
341         return NDIS_STATUS_PENDING;\r
342 }\r
343 \r
344 \r
345 static void\r
346 __path_query_cb(\r
347         IN                              ib_query_rec_t                          *p_query_rec )\r
348 {\r
349         ib_api_status_t status;\r
350         ipoib_endpt_t   *p_endpt;\r
351         ipoib_port_t    *p_port;\r
352         ib_av_attr_t    av_attr;\r
353         ib_path_rec_t   *p_path;\r
354         net32_t                 flow_lbl;\r
355 \r
356         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
357 \r
358         p_endpt = (ipoib_endpt_t*__ptr64)p_query_rec->query_context;\r
359         p_port = __endpt_parent( p_endpt );\r
360 \r
361         cl_obj_lock( &p_endpt->obj );\r
362         p_endpt->h_query = NULL;\r
363         if( p_endpt->obj.state == CL_DESTROYING )\r
364         {\r
365                 cl_obj_unlock( &p_endpt->obj );\r
366                 ipoib_endpt_deref( p_endpt );\r
367                 if( p_query_rec->p_result_mad )\r
368                         p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
369                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
370                         ("Endpoint destroying, aborting.\n") );\r
371                 return;\r
372         }\r
373         cl_obj_unlock( &p_endpt->obj );\r
374 \r
375         if( p_query_rec->status != IB_SUCCESS || !p_query_rec->result_cnt )\r
376         {\r
377                 p_port->p_adapter->hung = TRUE;\r
378                 ipoib_endpt_deref( p_endpt );\r
379                 if( p_query_rec->p_result_mad )\r
380                         p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
381                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
382                         ("Path query failed with %s\n",\r
383                         p_port->p_adapter->p_ifc->get_err_str( p_query_rec->status )) );\r
384                 return;\r
385         }\r
386 \r
387         p_path = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );\r
388 \r
389         cl_memclr( &av_attr, sizeof(ib_av_attr_t) );\r
390 \r
391         av_attr.port_num = p_port->port_num;\r
392 \r
393         av_attr.sl = ib_path_rec_sl( p_path );\r
394         av_attr.dlid = p_path->dlid;\r
395 \r
396         /*\r
397          * We always send the GRH so that we preferably lookup endpoints\r
398          * by GID rather than by LID.  This allows certain WHQL tests\r
399          * such as the 2c_MediaCheck test to succeed since they don't use\r
400          * IP.  This allows endpoints to be created on the fly for requests\r
401          * for which there is no match, something that doesn't work when\r
402          * using LIDs only.\r
403          */\r
404         flow_lbl = ib_path_rec_flow_lbl( p_path );\r
405         av_attr.grh_valid = TRUE;\r
406         av_attr.grh.ver_class_flow = ib_grh_set_ver_class_flow(\r
407                 6, p_path->tclass, flow_lbl );\r
408         av_attr.grh.resv1 = 0;\r
409         av_attr.grh.resv2 = 0;\r
410         av_attr.grh.hop_limit = ib_path_rec_hop_limit( p_path );\r
411         av_attr.grh.src_gid = p_path->sgid;\r
412         av_attr.grh.dest_gid = p_path->dgid;\r
413         \r
414         if( !p_endpt->dlid )\r
415         {\r
416                 /* This is a subnet local endpoint that does not have its LID set. */\r
417                 p_endpt->dlid = p_path->dlid;\r
418                 /*\r
419                  * Insert the item in the LID map so that locally routed unicast\r
420                  * traffic will resolve it properly.\r
421                  */\r
422                 cl_obj_lock( &p_port->obj );\r
423                 cl_qmap_insert( &p_port->endpt_mgr.lid_endpts,\r
424                         p_endpt->dlid, &p_endpt->lid_item );\r
425                 cl_obj_unlock( &p_port->obj );\r
426         }\r
427         av_attr.static_rate = ib_path_rec_rate( p_path );\r
428         av_attr.path_bits = 0;\r
429 \r
430         /* Done with the path record.  Release the MAD. */\r
431         p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
432 \r
433         /* Create the AV. */\r
434         status = p_port->p_adapter->p_ifc->create_av(\r
435                 p_port->ib_mgr.h_pd, &av_attr, &p_endpt->h_av );\r
436         if( status != IB_SUCCESS )\r
437         {\r
438                 p_port->p_adapter->hung = TRUE;\r
439                 ipoib_endpt_deref( p_endpt );\r
440                 cl_obj_unlock( &p_endpt->obj );\r
441                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
442                         ("ib_create_av failed with %s\n", \r
443                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
444                 return;\r
445         }\r
446 \r
447         /* Try to send all pending sends. */\r
448         ipoib_port_resume( p_port );\r
449 \r
450         /* Release the reference taken for the SA query. */\r
451         ipoib_endpt_deref( p_endpt );\r
452         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
453 }\r