[WSD] Use correct CQ thread info structure when cleaning up.
[mirror/winof/.git] / ulp / wsd / user / ibsp_pnp.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 /* TODO: right now, hotplug is not supported. */\r
33 \r
34 #include "ibspdll.h"\r
35 \r
36 \r
37 static void pnp_port_remove(\r
38         IN                              struct ibsp_port* const         port );\r
39 \r
40 \r
41 /* Find a HCA in the list based on its GUID */\r
42 static struct ibsp_hca *\r
43 lookup_hca(\r
44                                         ib_net64_t                                      ca_guid )\r
45 {\r
46         cl_list_item_t *item;\r
47 \r
48         cl_spinlock_acquire( &g_ibsp.hca_mutex );\r
49 \r
50         for( item = cl_qlist_head( &g_ibsp.hca_list );\r
51                 item != cl_qlist_end( &g_ibsp.hca_list );\r
52                 item = cl_qlist_next( item ) )\r
53         {\r
54                 struct ibsp_hca *hca = PARENT_STRUCT(item, struct ibsp_hca, item);\r
55                 if( hca->guid == ca_guid )\r
56                 {\r
57                         /* Found */\r
58                         cl_spinlock_release( &g_ibsp.hca_mutex );\r
59                         return hca;\r
60                 }\r
61         }\r
62 \r
63         cl_spinlock_release( &g_ibsp.hca_mutex );\r
64 \r
65         return NULL;\r
66 }\r
67 \r
68 \r
69 /* Add a new adapter */\r
70 ib_api_status_t\r
71 pnp_ca_add(\r
72         IN                              ib_pnp_ca_rec_t* const          p_ca_rec )\r
73 {\r
74         struct ibsp_hca *hca;\r
75         ib_api_status_t status;\r
76 \r
77         IBSP_ENTER( IBSP_DBG_HW );\r
78 \r
79         hca = HeapAlloc( g_ibsp.heap, HEAP_ZERO_MEMORY, sizeof(struct ibsp_hca) );\r
80         if( hca == NULL )\r
81         {\r
82                 IBSP_ERROR(\r
83                         ("can't get enough memory (%d)\n", sizeof(struct ibsp_hca)) );\r
84                 status = IB_INSUFFICIENT_MEMORY;\r
85                 goto pnp_ca_add_err1;\r
86         }\r
87 \r
88         hca->guid = p_ca_rec->p_ca_attr->ca_guid;\r
89         hca->dev_id = p_ca_rec->p_ca_attr->dev_id;\r
90         cl_qlist_init( &hca->port_list );\r
91         cl_spinlock_init( &hca->port_lock );\r
92         cl_qlist_init( &hca->rdma_mem_list.list );\r
93         cl_spinlock_init( &hca->rdma_mem_list.mutex );\r
94         cl_spinlock_init( &hca->cq_lock );\r
95 \r
96         /* HCA handle */\r
97         IBSP_TRACE( IBSP_DBG_HW,\r
98                          ("handle is %p %016I64x\n", g_ibsp.al_handle, hca->guid) );\r
99         status =\r
100                 ib_open_ca( g_ibsp.al_handle, hca->guid, NULL, hca, &hca->hca_handle );\r
101 \r
102         if( status != IB_SUCCESS )\r
103         {\r
104                 IBSP_ERROR( ("ib_open_ca failed (%d)\n", status) );\r
105                 goto pnp_ca_add_err2;\r
106         }\r
107 \r
108         STAT_INC( ca_num );\r
109 \r
110         /* Protection domain for the HCA */\r
111         status = ib_alloc_pd( hca->hca_handle, IB_PDT_NORMAL, hca, &hca->pd );\r
112         if( status == IB_SUCCESS )\r
113         {\r
114                 STAT_INC( pd_num );\r
115 \r
116                 IBSP_TRACE( IBSP_DBG_EP, ("allocated PD %p for HCA\n", hca->pd) );\r
117 \r
118                 /* Success */\r
119                 cl_spinlock_acquire( &g_ibsp.hca_mutex );\r
120                 cl_qlist_insert_tail( &g_ibsp.hca_list, &hca->item );\r
121                 cl_spinlock_release( &g_ibsp.hca_mutex );\r
122 \r
123                 p_ca_rec->pnp_rec.context = hca;\r
124         }\r
125         else\r
126         {\r
127                 IBSP_ERROR( ("ib_alloc_pd failed (%d)\n", status) );\r
128                 if( ib_close_ca( hca->hca_handle, NULL ) == IB_SUCCESS )\r
129                         STAT_DEC( ca_num );\r
130 \r
131 pnp_ca_add_err2:\r
132                 HeapFree( g_ibsp.heap, 0, hca );\r
133 \r
134         }\r
135 pnp_ca_add_err1:\r
136 \r
137         IBSP_EXIT( IBSP_DBG_HW );\r
138         return status;\r
139 }\r
140 \r
141 \r
142 /* Remove an adapter and its ports. */\r
143 void\r
144 pnp_ca_remove(\r
145                                         struct ibsp_hca                         *hca )\r
146 {\r
147         ib_api_status_t                 status;\r
148         cl_list_item_t                  *p_item;\r
149         struct cq_thread_info   *p_cq_tinfo;\r
150 \r
151         IBSP_ENTER( IBSP_DBG_HW );\r
152 \r
153         /*\r
154          * Remove all the ports\r
155          */\r
156         cl_spinlock_acquire( &hca->port_lock );\r
157         while( cl_qlist_count( &hca->port_list ) )\r
158         {\r
159                 p_item = cl_qlist_remove_head( &hca->port_list );\r
160 \r
161                 HeapFree( g_ibsp.heap, 0,\r
162                         PARENT_STRUCT(p_item, struct ibsp_port, item) );\r
163         }\r
164         cl_spinlock_release( &hca->port_lock );\r
165 \r
166         cl_spinlock_acquire( &hca->cq_lock );\r
167         while( hca->cq_tinfo )\r
168         {\r
169                 p_cq_tinfo = hca->cq_tinfo;\r
170 \r
171                 hca->cq_tinfo = PARENT_STRUCT(\r
172                         cl_qlist_next( &hca->cq_tinfo->list_item ),\r
173                 struct cq_thread_info, list_item );\r
174 \r
175                 __cl_primitive_remove( &p_cq_tinfo->list_item );\r
176 \r
177                 if( hca->cq_tinfo == p_cq_tinfo )\r
178                         break;\r
179 \r
180                 cl_spinlock_release( &hca->cq_lock );\r
181                 ib_destroy_cq_tinfo( p_cq_tinfo );\r
182                 cl_spinlock_acquire( &hca->cq_lock );\r
183         }\r
184         cl_spinlock_release( &hca->cq_lock );\r
185 \r
186         if( hca->pd )\r
187         {\r
188                 ibsp_dereg_hca( &hca->rdma_mem_list );\r
189 \r
190                 /*\r
191                  * No need to wait for PD destruction - CA destruction will block\r
192                  * until all child resources are released.\r
193                  */\r
194                 status = ib_dealloc_pd( hca->pd, NULL );\r
195                 if( status )\r
196                         IBSP_ERROR( ("ib_dealloc_pd failed (%d)\n", status) );\r
197                 else\r
198                         STAT_DEC( pd_num );\r
199 \r
200                 hca->pd = NULL;\r
201         }\r
202 \r
203         if( hca->hca_handle )\r
204         {\r
205                 status = ib_close_ca( hca->hca_handle, ib_sync_destroy );\r
206                 if( status != IB_SUCCESS )\r
207                         IBSP_ERROR( ("ib_close_ca failed (%d)\n", status) );\r
208 \r
209                 hca->hca_handle = NULL;\r
210         }\r
211 \r
212         /* Remove the HCA from the HCA list and free it. */\r
213         cl_spinlock_acquire( &g_ibsp.hca_mutex );\r
214         cl_qlist_remove_item( &g_ibsp.hca_list, &hca->item );\r
215         cl_spinlock_release( &g_ibsp.hca_mutex );\r
216 \r
217         cl_spinlock_destroy( &hca->port_lock );\r
218         cl_spinlock_destroy( &hca->rdma_mem_list.mutex );\r
219 \r
220         cl_spinlock_destroy( &hca->cq_lock );\r
221 \r
222         HeapFree( g_ibsp.heap, 0, hca );\r
223 \r
224         IBSP_EXIT( IBSP_DBG_HW );\r
225 }\r
226 \r
227 \r
228 /* Add a new port to an adapter */\r
229 static ib_api_status_t\r
230 pnp_port_add(\r
231         IN      OUT                     ib_pnp_port_rec_t* const        p_port_rec )\r
232 {\r
233         struct ibsp_hca *hca;\r
234         struct ibsp_port *port;\r
235 \r
236         IBSP_ENTER( IBSP_DBG_HW );\r
237 \r
238         hca = lookup_hca( p_port_rec->p_ca_attr->ca_guid );\r
239         if( !hca )\r
240         {\r
241                 IBSP_ERROR(\r
242                         ("Failed to lookup HCA (%016I64x) for new port (%016I64x)\n",\r
243                         p_port_rec->p_ca_attr->ca_guid, p_port_rec->p_port_attr->port_guid) );\r
244                 IBSP_EXIT( IBSP_DBG_HW );\r
245                 return IB_INVALID_GUID;\r
246         }\r
247 \r
248         port = HeapAlloc( g_ibsp.heap, HEAP_ZERO_MEMORY, sizeof(struct ibsp_port) );\r
249         if( port == NULL )\r
250         {\r
251                 IBSP_ERROR(\r
252                                  ("HeapAlloc failed (%d)\n", sizeof(struct ibsp_port)) );\r
253                 IBSP_EXIT( IBSP_DBG_HW );\r
254                 return IB_INSUFFICIENT_MEMORY;\r
255         }\r
256 \r
257         port->guid = p_port_rec->p_port_attr->port_guid;\r
258         port->port_num = p_port_rec->p_port_attr->port_num;\r
259         port->hca = hca;\r
260 \r
261         cl_spinlock_acquire( &hca->port_lock );\r
262         cl_qlist_insert_tail( &hca->port_list, &port->item );\r
263         cl_spinlock_release( &hca->port_lock );\r
264         p_port_rec->pnp_rec.context = port;\r
265 \r
266         IBSP_EXIT( IBSP_DBG_HW );\r
267         return IB_SUCCESS;\r
268 }\r
269 \r
270 \r
271 /* Remove a port. The IP addresses should have already been removed. */\r
272 static void\r
273 pnp_port_remove(\r
274         IN                              struct ibsp_port* const         port )\r
275 {\r
276         IBSP_ENTER( IBSP_DBG_HW );\r
277 \r
278         if( !port )\r
279                 goto done;\r
280 \r
281         CL_ASSERT( port->hca );\r
282 \r
283         /* Remove the port from the HCA list */\r
284         cl_spinlock_acquire( &port->hca->port_lock );\r
285         cl_qlist_remove_item( &port->hca->port_list, &port->item );\r
286         cl_spinlock_release( &port->hca->port_lock );\r
287 \r
288         HeapFree( g_ibsp.heap, 0, port );\r
289 \r
290 done:\r
291         IBSP_EXIT( IBSP_DBG_HW );\r
292 }\r
293 \r
294 \r
295 static ib_api_status_t AL_API\r
296 pnp_callback(\r
297         IN                              ib_pnp_rec_t                            *pnp_rec )\r
298 {\r
299         ib_api_status_t                 status = IB_SUCCESS;\r
300         ib_pnp_port_rec_t*              p_port_rec = (ib_pnp_port_rec_t*)pnp_rec;\r
301 \r
302         IBSP_ENTER( IBSP_DBG_HW );\r
303         IBSP_TRACE( IBSP_DBG_HW, ("event is %x\n", pnp_rec->pnp_event) );\r
304 \r
305         switch( pnp_rec->pnp_event )\r
306         {\r
307                 /* CA events */\r
308         case IB_PNP_CA_ADD:\r
309                 status = pnp_ca_add( (ib_pnp_ca_rec_t*)pnp_rec );\r
310                 break;\r
311 \r
312         case IB_PNP_CA_REMOVE:\r
313                 pnp_ca_remove( (struct ibsp_hca* __ptr64)pnp_rec->context );\r
314                 break;\r
315 \r
316                 /* Port events */\r
317         case IB_PNP_PORT_ADD:\r
318                 status = pnp_port_add( p_port_rec );\r
319                 break;\r
320 \r
321         case IB_PNP_PORT_INIT:\r
322         case IB_PNP_PORT_ARMED:\r
323         case IB_PNP_PORT_ACTIVE:\r
324         case IB_PNP_PORT_DOWN:\r
325                 /* Nothing to do. */\r
326                 break;\r
327 \r
328         case IB_PNP_PORT_REMOVE:\r
329                 pnp_port_remove( (struct ibsp_port* __ptr64)pnp_rec->context );\r
330                 break;\r
331 \r
332         case IB_PNP_PKEY_CHANGE:\r
333         case IB_PNP_SM_CHANGE:\r
334         case IB_PNP_GID_CHANGE:\r
335         case IB_PNP_LID_CHANGE:\r
336         case IB_PNP_SUBNET_TIMEOUT_CHANGE:\r
337                 IBSP_ERROR(\r
338                         ("pnp_callback: unsupported event %x\n", pnp_rec->pnp_event) );\r
339                 break;\r
340 \r
341                 /* Discovery complete event */\r
342         case IB_PNP_REG_COMPLETE:\r
343                 break;\r
344 \r
345         default:\r
346                 IBSP_ERROR(\r
347                         ("pnp_callback: unsupported event %x\n", pnp_rec->pnp_event) );\r
348                 break;\r
349         }\r
350 \r
351         IBSP_EXIT( IBSP_DBG_HW );\r
352 \r
353         return status;\r
354 }\r
355 \r
356 \r
357 \r
358 \r
359 /* Registers for PNP events and starts the hardware discovery */\r
360 ib_api_status_t\r
361 register_pnp(void)\r
362 {\r
363         ib_api_status_t status;\r
364         ib_pnp_req_t pnp_req;\r
365 \r
366         IBSP_ENTER( IBSP_DBG_HW );\r
367 \r
368         pnp_req.pnp_class = IB_PNP_CA;\r
369         pnp_req.pnp_context = NULL;\r
370         pnp_req.pfn_pnp_cb = pnp_callback;\r
371         status = ib_reg_pnp( g_ibsp.al_handle, &pnp_req, &g_ibsp.pnp_handle_port );\r
372         if( status != IB_SUCCESS )\r
373         {\r
374                 IBSP_ERROR(\r
375                         ("register_pnp: ib_reg_pnp for PORT failed (%d)\n", status) );\r
376                 goto done;\r
377         }\r
378 \r
379         pnp_req.pnp_class = IB_PNP_PORT | IB_PNP_FLAG_REG_SYNC;\r
380         pnp_req.pnp_context = NULL;\r
381         pnp_req.pfn_pnp_cb = pnp_callback;\r
382         status = ib_reg_pnp( g_ibsp.al_handle, &pnp_req, &g_ibsp.pnp_handle_port );\r
383         if( status != IB_SUCCESS )\r
384         {\r
385                 IBSP_ERROR(\r
386                         ("register_pnp: ib_reg_pnp for PORT failed (%d)\n", status) );\r
387                 goto done;\r
388         }\r
389 \r
390         STAT_INC( pnp_num );\r
391 \r
392 done:\r
393         if( status != IB_SUCCESS )\r
394         {\r
395                 unregister_pnp();\r
396         }\r
397 \r
398         IBSP_EXIT( IBSP_DBG_HW );\r
399 \r
400         return status;\r
401 }\r
402 \r
403 \r
404 /* Unregisters the PNP events */\r
405 void\r
406 unregister_pnp(void)\r
407 {\r
408         ib_api_status_t status;\r
409 \r
410         IBSP_ENTER( IBSP_DBG_HW );\r
411 \r
412         if( g_ibsp.pnp_handle_port )\r
413         {\r
414                 status = ib_dereg_pnp( g_ibsp.pnp_handle_port, ib_sync_destroy );\r
415                 if( status != IB_SUCCESS )\r
416                 {\r
417                         IBSP_ERROR(\r
418                                 ("unregister_pnp: ib_dereg_pnp for PORT failed (%d)\n", status) );\r
419                 }\r
420 \r
421                 g_ibsp.pnp_handle_port = NULL;\r
422         }\r
423 \r
424         if( g_ibsp.pnp_handle_ca )\r
425         {\r
426                 status = ib_dereg_pnp( g_ibsp.pnp_handle_ca, ib_sync_destroy );\r
427                 if( status != IB_SUCCESS )\r
428                 {\r
429                         IBSP_ERROR(\r
430                                 ("unregister_pnp: ib_dereg_pnp for PORT failed (%d)\n", status) );\r
431                 }\r
432 \r
433                 g_ibsp.pnp_handle_ca = NULL;\r
434         }\r
435 \r
436         IBSP_EXIT( IBSP_DBG_HW );\r
437 }\r