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