[IPoIB] Fix locking around endpoint LID checks.
[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         /* Leave the multicast group if it exists. */\r
228         if( p_endpt->h_mcast )\r
229         {\r
230                 IPOIB_PRINT( TRACE_LEVEL_INFORMATION, IPOIB_DBG_ENDPT,\r
231                         ("Leaving MCast group\n") );\r
232                 p_port->p_adapter->p_ifc->leave_mcast( p_endpt->h_mcast, NULL );\r
233         }\r
234 \r
235         /* Destroy the AV if it exists. */\r
236         if( p_endpt->h_av )\r
237                 p_port->p_adapter->p_ifc->destroy_av( p_endpt->h_av );\r
238 \r
239         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
240 }\r
241 \r
242 \r
243 static void\r
244 __endpt_free(\r
245         IN                              cl_obj_t*                                       p_obj )\r
246 {\r
247         ipoib_endpt_t   *p_endpt;\r
248 \r
249         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
250 \r
251         p_endpt = PARENT_STRUCT( p_obj, ipoib_endpt_t, obj );\r
252 \r
253         cl_obj_deinit( p_obj );\r
254         cl_free( p_endpt );\r
255 \r
256         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
257 }\r
258 \r
259 \r
260 static inline ipoib_port_t*\r
261 __endpt_parent(\r
262         IN                              ipoib_endpt_t* const            p_endpt )\r
263 {\r
264         return PARENT_STRUCT( p_endpt->rel.p_parent_obj, ipoib_port_t, obj );\r
265 }\r
266 \r
267 \r
268 /*\r
269  * This function is called with the port object's send lock held and\r
270  * a reference held on the endpoint.  If we fail, we release the reference.\r
271  */\r
272 NDIS_STATUS\r
273 ipoib_endpt_queue(\r
274         IN                              ipoib_endpt_t* const            p_endpt )\r
275 {\r
276         ib_api_status_t status;\r
277         ipoib_port_t    *p_port;\r
278         ib_query_req_t  query;\r
279         ib_user_query_t info;\r
280         ib_path_rec_t   path;\r
281 \r
282         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
283 \r
284         if( p_endpt->h_av )\r
285         {\r
286                 IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
287                 return NDIS_STATUS_SUCCESS;\r
288         }\r
289 \r
290         if( p_endpt->h_query ||\r
291                 p_endpt->qpn == CL_HTON32(0x00FFFFFF) )\r
292         {\r
293                 ipoib_endpt_deref( p_endpt );\r
294                 IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
295                 return NDIS_STATUS_PENDING;\r
296         }\r
297 \r
298         /* This is the first packet for this endpoint.  Query the SA. */\r
299         p_port = __endpt_parent( p_endpt );\r
300 \r
301         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
302 \r
303         info.method = IB_MAD_METHOD_GETTABLE;\r
304         info.attr_id = IB_MAD_ATTR_PATH_RECORD;\r
305         info.attr_size = sizeof(ib_path_rec_t);\r
306         info.comp_mask = IB_PR_COMPMASK_DGID | IB_PR_COMPMASK_SGID |\r
307                 IB_PR_COMPMASK_REVERSIBLE | IB_PR_COMPMASK_NUM_PATH;\r
308         info.p_attr = &path;\r
309 \r
310         cl_memclr( &path, sizeof(ib_path_rec_t) );\r
311         path.dgid = p_endpt->dgid;\r
312         ib_gid_set_default( &path.sgid, p_port->p_adapter->guids.port_guid );\r
313         path.num_path = 0x1;\r
314 \r
315         cl_memclr( &query, sizeof(ib_query_req_t) );\r
316         query.query_type = IB_QUERY_USER_DEFINED;\r
317         query.p_query_input = &info;\r
318         query.port_guid = p_port->p_adapter->guids.port_guid;\r
319         query.timeout_ms = p_port->p_adapter->params.sa_timeout;\r
320         query.retry_cnt = p_port->p_adapter->params.sa_retry_cnt;\r
321 \r
322         query.query_context = p_endpt;\r
323         query.pfn_query_cb = __path_query_cb;\r
324 \r
325         status = p_port->p_adapter->p_ifc->query(\r
326                 p_port->p_adapter->h_al, &query, &p_endpt->h_query );\r
327         if( status != IB_SUCCESS )\r
328         {\r
329                 IPOIB_PRINT( TRACE_LEVEL_ERROR, IPOIB_DBG_ENDPT,\r
330                         ("ib_query for path returned %s\n", \r
331                         p_port->p_adapter->p_ifc->get_err_str( status )) );\r
332                 ipoib_endpt_deref( p_endpt );\r
333                 /* Flag the adapter as hung. */\r
334                 p_port->p_adapter->hung = TRUE;\r
335         }\r
336 \r
337         IPOIB_EXIT( IPOIB_DBG_ENDPT );\r
338         return NDIS_STATUS_PENDING;\r
339 }\r
340 \r
341 \r
342 static void\r
343 __path_query_cb(\r
344         IN                              ib_query_rec_t                          *p_query_rec )\r
345 {\r
346         ib_api_status_t status;\r
347         ipoib_endpt_t   *p_endpt;\r
348         ipoib_port_t    *p_port;\r
349         ib_av_attr_t    av_attr;\r
350         ib_path_rec_t   *p_path;\r
351         net32_t                 flow_lbl;\r
352 \r
353         IPOIB_ENTER( IPOIB_DBG_ENDPT );\r
354 \r
355         p_endpt = (ipoib_endpt_t*__ptr64)p_query_rec->query_context;\r
356         p_port = __endpt_parent( p_endpt );\r
357 \r
358         cl_obj_lock( &p_endpt->obj );\r
359         p_endpt->h_query = NULL;\r
360         if( p_endpt->obj.state == CL_DESTROYING )\r
361         {\r
362                 cl_obj_unlock( &p_endpt->obj );\r
363                 ipoib_endpt_deref( p_endpt );\r
364                 if( p_query_rec->p_result_mad )\r
365                         p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
366                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
367                         ("Endpoint destroying, aborting.\n") );\r
368                 return;\r
369         }\r
370         cl_obj_unlock( &p_endpt->obj );\r
371 \r
372         if( p_query_rec->status != IB_SUCCESS || !p_query_rec->result_cnt )\r
373         {\r
374                 p_port->p_adapter->hung = TRUE;\r
375                 ipoib_endpt_deref( p_endpt );\r
376                 if( p_query_rec->p_result_mad )\r
377                         p_port->p_adapter->p_ifc->put_mad( p_query_rec->p_result_mad );\r
378                 IPOIB_PRINT_EXIT( TRACE_LEVEL_ERROR, IPOIB_DBG_ERROR,\r
379                         ("Path query failed with %s\n",\r
380                         p_port->p_adapter->p_ifc->get_err_str( p_query_rec->status )) );\r
381                 return;\r
382         }\r
383 \r
384         p_path = ib_get_query_path_rec( p_query_rec->p_result_mad, 0 );\r
385 \r
386         cl_memclr( &av_attr, sizeof(ib_av_attr_t) );\r
387 \r
388         av_attr.port_num = p_port->port_num;\r
389 \r
390         av_attr.sl = ib_path_rec_sl( p_path );\r
391         av_attr.dlid = p_path->dlid;\r
392 \r
393         /*\r
394          * We always send the GRH so that we preferably lookup endpoints\r
395          * by GID rather than by LID.  This allows certain WHQL tests\r
396          * such as the 2c_MediaCheck test to succeed since they don't use\r
397          * IP.  This allows endpoints to be created on the fly for requests\r
398          * for which there is no match, something that doesn't work when\r
399          * using LIDs only.\r
400          */\r
401         flow_lbl = ib_path_rec_flow_lbl( p_path );\r
402         av_attr.grh_valid = TRUE;\r
403         av_attr.grh.ver_class_flow = ib_grh_set_ver_class_flow(\r
404                 6, p_path->tclass, flow_lbl );\r
405         av_attr.grh.resv1 = 0;\r
406         av_attr.grh.resv2 = 0;\r
407         av_attr.grh.hop_limit = ib_path_rec_hop_limit( p_path );\r
408         av_attr.grh.src_gid = p_path->sgid;\r
409         av_attr.grh.dest_gid = p_path->dgid;\r
410         \r
411         cl_obj_lock( &p_port->obj );\r
412         if( !p_endpt->dlid )\r
413         {\r
414                 cl_map_item_t   *p_qitem;\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                 p_qitem = cl_qmap_insert( &p_port->endpt_mgr.lid_endpts,\r
423                         p_endpt->dlid, &p_endpt->lid_item );\r
424                 CL_ASSERT( p_qitem == &p_endpt->lid_item );\r
425         }\r
426         cl_obj_unlock( &p_port->obj );\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