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