[ipoib,core] Improve support for partitioning.
[mirror/winof/.git] / core / al / kernel / al_proxy.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  * Portions Copyright (c) 2008 Microsoft Corporation.  All rights reserved.\r
5  *\r
6  * This software is available to you under the OpenIB.org BSD license\r
7  * below:\r
8  *\r
9  *     Redistribution and use in source and binary forms, with or\r
10  *     without modification, are permitted provided that the following\r
11  *     conditions are met:\r
12  *\r
13  *      - Redistributions of source code must retain the above\r
14  *        copyright notice, this list of conditions and the following\r
15  *        disclaimer.\r
16  *\r
17  *      - Redistributions in binary form must reproduce the above\r
18  *        copyright notice, this list of conditions and the following\r
19  *        disclaimer in the documentation and/or other materials\r
20  *        provided with the distribution.\r
21  *\r
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
29  * SOFTWARE.\r
30  *\r
31  * $Id$\r
32  */\r
33 \r
34 \r
35 #include <complib/comp_lib.h>\r
36 #include <iba/ib_al.h>\r
37 #include <iba/ib_al_ioctl.h>\r
38 #include "al.h"\r
39 #include "al_mr.h"\r
40 #include "al_debug.h"\r
41 #if defined(EVENT_TRACING)\r
42 #ifdef offsetof\r
43 #undef offsetof\r
44 #endif\r
45 #include "al_proxy.tmh"\r
46 #endif\r
47 #include "al_dev.h"\r
48 #include "al_ci_ca.h"\r
49 #include "al_mgr.h"\r
50 #include "al_pnp.h"\r
51 #include "al_proxy.h"\r
52 #include "ib_common.h"\r
53 \r
54 \r
55 \r
56 /*\r
57  * Acquire an object used to queue callbacks.\r
58  */\r
59 al_proxy_cb_info_t*\r
60 proxy_cb_get(\r
61         IN              al_dev_open_context_t   *p_context )\r
62 {\r
63         al_proxy_cb_info_t              *p_cb_info;\r
64 \r
65         if( !p_context )\r
66                 return NULL;\r
67 \r
68         cl_spinlock_acquire( &p_context->cb_pool_lock );\r
69         p_cb_info = (al_proxy_cb_info_t*)cl_qpool_get( &p_context->cb_pool );\r
70         cl_spinlock_release( &p_context->cb_pool_lock );\r
71 \r
72         if( p_cb_info )\r
73                 p_cb_info->p_context = p_context;\r
74 \r
75         return p_cb_info;\r
76 }\r
77 \r
78 \r
79 \r
80 /*\r
81  * Release an object used to report callbacks.\r
82  */\r
83 void\r
84 proxy_cb_put(\r
85         IN              al_proxy_cb_info_t              *p_cb_info )\r
86 {\r
87         al_dev_open_context_t   *p_context;\r
88 \r
89         if( !p_cb_info )\r
90                 return;\r
91 \r
92         p_context = p_cb_info->p_context;\r
93 \r
94         p_cb_info->reported = FALSE;\r
95         p_cb_info->p_al_obj = NULL;\r
96 \r
97         cl_spinlock_acquire( &p_context->cb_pool_lock );\r
98         cl_qpool_put( &p_context->cb_pool, &p_cb_info->pool_item );\r
99         cl_spinlock_release( &p_context->cb_pool_lock );\r
100 }\r
101 \r
102 \r
103 \r
104 /*\r
105  * Process the ioctl UAL_REG_SHMID:\r
106  */\r
107 static\r
108 cl_status_t\r
109 proxy_reg_shmid(\r
110         IN              void                                    *p_open_context,\r
111         IN              cl_ioctl_handle_t               h_ioctl,\r
112                 OUT     size_t                                  *p_ret_bytes )\r
113 {\r
114         ual_reg_shmid_ioctl_t   *p_ioctl =\r
115                         (ual_reg_shmid_ioctl_t *)cl_ioctl_in_buf( h_ioctl );\r
116         al_dev_open_context_t   *p_context =\r
117                                                         (al_dev_open_context_t *)p_open_context;\r
118         ib_pd_handle_t                  h_pd;\r
119         ib_mr_handle_t                  h_mr;\r
120         uint64_t                                vaddr;\r
121         net32_t                                 lkey, rkey;\r
122 \r
123         AL_ENTER( AL_DBG_DEV );\r
124 \r
125         if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) ||\r
126                 cl_ioctl_in_size( h_ioctl ) < sizeof(ual_reg_shmid_ioctl_t) ||\r
127                 cl_ioctl_out_size( h_ioctl ) < sizeof(ual_reg_shmid_ioctl_t) )\r
128         {\r
129                 AL_EXIT( AL_DBG_DEV );\r
130                 return CL_INVALID_PARAMETER;\r
131         }\r
132 \r
133         /* Validate PD handle */\r
134         h_pd = (ib_pd_handle_t)\r
135                 al_hdl_ref( p_context->h_al, p_ioctl->in.h_pd, AL_OBJ_TYPE_H_PD );\r
136         if( !h_pd )\r
137         {\r
138                 cl_memclr( &p_ioctl->out, sizeof(p_ioctl->out) );\r
139                 p_ioctl->out.status = IB_INVALID_PD_HANDLE;\r
140                 goto done;\r
141         }\r
142 \r
143         /* Validate input region size. */\r
144         if( p_ioctl->in.mr_create.length > ~((size_t)0) )\r
145         {\r
146                 cl_memclr( &p_ioctl->out, sizeof(p_ioctl->out) );\r
147                 p_ioctl->out.status = IB_INVALID_SETTING;\r
148                 goto done;\r
149         }\r
150 \r
151         p_ioctl->out.status = reg_shmid(\r
152                                                         h_pd,\r
153                                                         p_ioctl->in.shmid,\r
154                                                         &p_ioctl->in.mr_create,\r
155                                                         &vaddr,\r
156                                                         &lkey,\r
157                                                         &rkey,\r
158                                                         &h_mr );\r
159 \r
160         if( p_ioctl->out.status == IB_SUCCESS )\r
161         {\r
162                 /* We put the kernel al handle itself in the al_list for the process */\r
163                 p_ioctl->out.vaddr = vaddr;\r
164                 p_ioctl->out.lkey = lkey;\r
165                 p_ioctl->out.rkey = rkey;\r
166                 p_ioctl->out.h_mr = h_mr->obj.hdl;\r
167                 h_mr->obj.hdl_valid = TRUE;\r
168                 deref_al_obj( &h_mr->obj );\r
169         }\r
170         else\r
171         {\r
172                 /* release the memory handle allocated */\r
173                 p_ioctl->out.vaddr = 0;\r
174                 p_ioctl->out.lkey = 0;\r
175                 p_ioctl->out.rkey = 0;\r
176                 p_ioctl->out.h_mr = AL_INVALID_HANDLE;\r
177         }\r
178 \r
179 done:\r
180         *p_ret_bytes = sizeof(p_ioctl->out);\r
181         AL_EXIT( AL_DBG_DEV );\r
182         return CL_SUCCESS;\r
183 }\r
184 \r
185 \r
186 /*\r
187  * Retrieve a callback record from the appropriate callback list\r
188  * and fill the ioctl buffer.\r
189  *\r
190  * If no callback record is available, queue the ioctl buffer.\r
191  * Queued ioctl buffer will put the calling process to sleep and complete\r
192  * when complete when a callback record is available.\r
193  */\r
194 static cl_status_t\r
195 proxy_queue_ioctl_buf(\r
196         IN                              uintn_t                                         cb_type,\r
197         IN                              al_dev_open_context_t           *p_context,\r
198         IN                              cl_ioctl_handle_t                       h_ioctl )\r
199 {\r
200         cl_qlist_t                                      *p_cb_list;\r
201         al_proxy_cb_info_t                      *p_cb_info;\r
202         cl_ioctl_handle_t                       *ph_ioctl;\r
203         uintn_t                                         ioctl_size;\r
204 \r
205         AL_ENTER( AL_DBG_DEV );\r
206 \r
207         /* Set up the appropriate callback list. */\r
208         switch( cb_type )\r
209         {\r
210         case UAL_GET_COMP_CB_INFO:\r
211                 p_cb_list = &p_context->comp_cb_list;\r
212                 ph_ioctl = &p_context->h_comp_ioctl;\r
213                 /* TODO: Use output size only. */\r
214                 ioctl_size = sizeof( comp_cb_ioctl_info_t );\r
215                 break;\r
216 \r
217         case UAL_GET_MISC_CB_INFO:\r
218                 p_cb_list = &p_context->misc_cb_list;\r
219                 ph_ioctl = &p_context->h_misc_ioctl;\r
220                 /* TODO: Use output size only. */\r
221                 ioctl_size = sizeof( misc_cb_ioctl_info_t );\r
222                 break;\r
223 \r
224         default:\r
225                 AL_EXIT( AL_DBG_DEV );\r
226                 return CL_INVALID_PARAMETER;\r
227         }\r
228 \r
229         /* Process queued callbacks. */\r
230         cl_spinlock_acquire( &p_context->cb_lock );\r
231         while( !cl_is_qlist_empty( p_cb_list ) )\r
232         {\r
233                 p_cb_info = (al_proxy_cb_info_t*)cl_qlist_head( p_cb_list );\r
234 \r
235                 /* Check to see if we've already reported the callback. */\r
236                 if( !p_cb_info->reported )\r
237                 {\r
238                         p_cb_info->reported = TRUE;\r
239 \r
240                         /* Return the callback to the user. */\r
241                         CL_ASSERT( cl_ioctl_out_size( h_ioctl ) >= ioctl_size );\r
242                         cl_memcpy(\r
243                                 cl_ioctl_out_buf( h_ioctl ), &p_cb_info->cb_type, ioctl_size );\r
244                         cl_ioctl_complete( h_ioctl, CL_SUCCESS, ioctl_size );\r
245                         cl_spinlock_release( &p_context->cb_lock );\r
246                         AL_EXIT( AL_DBG_DEV );\r
247                         return CL_COMPLETED;\r
248                 }\r
249                 if( p_cb_info->p_al_obj )\r
250                         deref_al_obj( p_cb_info->p_al_obj );\r
251 \r
252                 cl_qlist_remove_head( p_cb_list );\r
253                 proxy_cb_put( p_cb_info );\r
254         }\r
255 \r
256         /* There are no callbacks to report.  Mark this IOCTL as pending. */\r
257         CL_ASSERT( !(*ph_ioctl) );\r
258 \r
259         /* If we're closing down, complete the IOCTL with a canceled status. */\r
260         if( p_context->closing )\r
261         {\r
262                 cl_spinlock_release( &p_context->cb_lock );\r
263                 AL_EXIT( AL_DBG_DEV );\r
264                 return CL_CANCELED;\r
265         }\r
266 \r
267         *ph_ioctl = h_ioctl;\r
268         /* Set the cancel routine for this IRP so the app can abort. */\r
269 #pragma warning(push, 3)\r
270         IoSetCancelRoutine( h_ioctl, al_dev_cancel_io );\r
271 #pragma warning(pop)\r
272         /* If returning pending, the IRP must be marked as such. */\r
273         IoMarkIrpPending( h_ioctl );\r
274 \r
275         /* Ref the context until the IOCTL is either completed or cancelled. */\r
276         proxy_context_ref( p_context );\r
277         cl_spinlock_release( &p_context->cb_lock );\r
278 \r
279         AL_EXIT( AL_DBG_DEV );\r
280         return CL_PENDING;\r
281 }\r
282 \r
283 \r
284 \r
285 /*\r
286  * Process the ioctl UAL_GET_COMP_CB_INFO:\r
287  * Get a completion callback record from the queue of CM callback records\r
288  */\r
289 static cl_status_t\r
290 proxy_get_comp_cb(\r
291         IN              cl_ioctl_handle_t               h_ioctl )\r
292 {\r
293         cl_status_t                             cl_status;\r
294         IO_STACK_LOCATION               *p_io_stack;\r
295         al_dev_open_context_t   *p_context;\r
296 \r
297         AL_ENTER( AL_DBG_DEV );\r
298 \r
299         p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );\r
300         p_context = (al_dev_open_context_t*)p_io_stack->FileObject->FsContext;\r
301         if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_H_CQ )\r
302         {\r
303                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
304                         ("Invalid file object type for request: %016I64x\n",\r
305                         (LONG_PTR)p_io_stack->FileObject->FsContext2) );\r
306                 return CL_INVALID_PARAMETER;\r
307         }\r
308 \r
309         /* Check the size of the ioctl */\r
310         if( !p_context || !cl_ioctl_out_buf( h_ioctl ) ||\r
311                 cl_ioctl_out_size( h_ioctl ) != sizeof(comp_cb_ioctl_info_t) )\r
312         {\r
313                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
314                         ("No output buffer, or buffer too small.\n") );\r
315                 return CL_INVALID_PARAMETER;\r
316         }\r
317 \r
318         cl_status = proxy_queue_ioctl_buf( UAL_GET_COMP_CB_INFO,\r
319                 p_context, h_ioctl );\r
320 \r
321         AL_EXIT( AL_DBG_DEV );\r
322         return cl_status;\r
323 }\r
324 \r
325 \r
326 \r
327 /*\r
328  * Process the ioctl UAL_GET_MISC_CB_INFO:\r
329  * Get a miscellaneous callback record from the queue of CM callback records\r
330  */\r
331 static cl_status_t\r
332 proxy_get_misc_cb(\r
333         IN              cl_ioctl_handle_t               h_ioctl )\r
334 {\r
335         cl_status_t                             cl_status;\r
336         IO_STACK_LOCATION               *p_io_stack;\r
337         al_dev_open_context_t   *p_context;\r
338 \r
339         AL_ENTER( AL_DBG_DEV );\r
340 \r
341         p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );\r
342         p_context = (al_dev_open_context_t*)p_io_stack->FileObject->FsContext;\r
343         if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_AL_MGR )\r
344         {\r
345                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
346                         ("Invalid file object type for request: %016I64x\n",\r
347                         (LONG_PTR)p_io_stack->FileObject->FsContext2) );\r
348                 return CL_INVALID_PARAMETER;\r
349         }\r
350 \r
351         /* Check the size of the ioctl */\r
352         if( !p_context || !cl_ioctl_out_buf( h_ioctl ) ||\r
353                 cl_ioctl_out_size( h_ioctl ) != sizeof(misc_cb_ioctl_info_t) )\r
354         {\r
355                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
356                         ("No output buffer, or buffer too small.\n") );\r
357                 return CL_INVALID_PARAMETER;\r
358         }\r
359 \r
360         cl_status = proxy_queue_ioctl_buf( UAL_GET_MISC_CB_INFO,\r
361                 p_context, h_ioctl );\r
362 \r
363         AL_EXIT( AL_DBG_DEV );\r
364         return cl_status;\r
365 }\r
366 \r
367 \r
368 \r
369 /*\r
370  * Process a PnP callback for a CA.\r
371  */\r
372 ib_api_status_t\r
373 proxy_pnp_ca_cb(\r
374         IN              ib_pnp_rec_t            *p_pnp_rec      )\r
375 {\r
376         misc_cb_ioctl_info_t    misc_cb_info;\r
377         misc_cb_ioctl_rec_t             *p_misc_rec = &misc_cb_info.ioctl_rec;\r
378         al_dev_open_context_t   *p_context;\r
379 \r
380         AL_ENTER( AL_DBG_PROXY_CB );\r
381 \r
382         p_context = p_pnp_rec->pnp_context;\r
383 \r
384         /*\r
385          * If we're already closing the device - do not queue a callback, since\r
386          * we're cleaning up the callback lists.\r
387          */\r
388         if( !proxy_context_ref( p_context ) )\r
389         {\r
390                 proxy_context_deref( p_context );\r
391                 return IB_ERROR;\r
392         }\r
393 \r
394         /* Initialize the PnP callback information to return to user-mode. */\r
395         cl_memclr( &misc_cb_info, sizeof(misc_cb_info) );\r
396         misc_cb_info.rec_type = PNP_REC;\r
397         p_misc_rec->pnp_cb_ioctl_rec.pnp_event = p_pnp_rec->pnp_event;\r
398 \r
399         switch( p_pnp_rec->pnp_event )\r
400         {\r
401         case IB_PNP_CA_ADD:\r
402         case IB_PNP_CA_REMOVE:\r
403                 /* Queue the add/remove pnp record */\r
404                 p_misc_rec->pnp_cb_ioctl_rec.pnp_info.ca.ca_guid = p_pnp_rec->guid;\r
405                 proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &misc_cb_info,\r
406                         NULL );\r
407                 break;\r
408 \r
409         default:\r
410                 /* We only handle CA adds and removals. */\r
411                 break;\r
412         }\r
413 \r
414         proxy_context_deref( p_context );\r
415         AL_EXIT( AL_DBG_PROXY_CB );\r
416         return IB_SUCCESS;\r
417 }\r
418 \r
419 \r
420 \r
421 /*\r
422  * Process a PnP callback for a port.\r
423  */\r
424 ib_api_status_t\r
425 proxy_pnp_port_cb(\r
426         IN              ib_pnp_rec_t            *p_pnp_rec      )\r
427 {\r
428         ib_pnp_port_rec_t               *p_port_rec;\r
429         misc_cb_ioctl_info_t    misc_cb_info;\r
430         misc_cb_ioctl_rec_t             *p_misc_rec = &misc_cb_info.ioctl_rec;\r
431         al_dev_open_context_t   *p_context;\r
432 \r
433         AL_ENTER( AL_DBG_PROXY_CB );\r
434 \r
435         p_context = p_pnp_rec->pnp_context;\r
436 \r
437         /*\r
438          * If we're already closing the device - do not queue a callback, since\r
439          * we're cleaning up the callback lists.\r
440          */\r
441         if( !proxy_context_ref( p_context ) )\r
442         {\r
443                 proxy_context_deref( p_context );\r
444                 return IB_ERROR;\r
445         }\r
446 \r
447         p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec;\r
448 \r
449         /* Initialize the PnP callback information to return to user-mode. */\r
450         cl_memclr( &misc_cb_info, sizeof(misc_cb_info) );\r
451         misc_cb_info.rec_type = PNP_REC;\r
452         p_misc_rec->pnp_cb_ioctl_rec.pnp_event = p_pnp_rec->pnp_event;\r
453 \r
454         switch( p_pnp_rec->pnp_event )\r
455         {\r
456         case IB_PNP_PORT_ADD:\r
457         case IB_PNP_PORT_REMOVE:\r
458                 /* Port add/remove will be generated automatically by uAL. */\r
459                 break;\r
460 \r
461         case IB_PNP_REG_COMPLETE:\r
462                 /*\r
463                  * Once our registration for ports is complete, report this to the\r
464                  * user-mode library.  This indicates to the that the current\r
465                  * system state has been reported.\r
466                  */\r
467                 proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &misc_cb_info,\r
468                         NULL );\r
469                 break;\r
470 \r
471         default:\r
472                 p_misc_rec->pnp_cb_ioctl_rec.pnp_info.ca.ca_guid =\r
473                         p_port_rec->p_ca_attr->ca_guid;\r
474 \r
475                 proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &misc_cb_info,\r
476                         NULL );\r
477                 break;\r
478         }\r
479 \r
480         proxy_context_deref( p_context );\r
481         AL_EXIT( AL_DBG_PROXY_CB );\r
482         return IB_SUCCESS;\r
483 }\r
484 \r
485 \r
486 \r
487 cl_status_t\r
488 proxy_get_ca_attr(\r
489         IN              void                                    *p_open_context,\r
490         IN              cl_ioctl_handle_t               h_ioctl,\r
491                 OUT     size_t                                  *p_ret_bytes )\r
492 {\r
493         al_dev_open_context_t                   *p_context;\r
494         uint64_t                                                *ph_ca_attr;\r
495         ib_ca_attr_t                                    *p_src;\r
496 \r
497         AL_ENTER( AL_DBG_DEV );\r
498 \r
499         UNREFERENCED_PARAMETER( p_ret_bytes );\r
500 \r
501         /* Check the size of the ioctl */\r
502         if( !cl_ioctl_in_buf( h_ioctl ) ||\r
503                 cl_ioctl_in_size( h_ioctl ) < sizeof(uint64_t) )\r
504         {\r
505                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("invalid buffer size\n") );\r
506                 return CL_INVALID_PARAMETER;\r
507         }\r
508         p_context = (al_dev_open_context_t*)p_open_context;\r
509         ph_ca_attr = (uint64_t*)cl_ioctl_in_buf( h_ioctl );\r
510 \r
511         p_src = (ib_ca_attr_t*)al_hdl_get(\r
512                 p_context->h_al, *ph_ca_attr, AL_OBJ_TYPE_H_CA_ATTR );\r
513         if( !p_src )\r
514         {\r
515                 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("invalid attr handle\n") );\r
516                 return CL_INVALID_PARAMETER;\r
517         }\r
518 \r
519         cl_free(p_src);\r
520 \r
521         AL_EXIT( AL_DBG_DEV );\r
522         return CL_SUCCESS;\r
523 }\r
524 \r
525 \r
526 /*\r
527  * Process the ioctl UAL_BIND_SA:\r
528  * Get a completion callback record from the queue of CM callback records\r
529  */\r
530 static cl_status_t\r
531 proxy_bind_file(\r
532         IN                              cl_ioctl_handle_t                       h_ioctl,\r
533         IN              const   uint32_t                                        type )\r
534 {\r
535         NTSTATUS                                status;\r
536         IO_STACK_LOCATION               *p_io_stack;\r
537         al_dev_open_context_t   *p_context;\r
538         ual_bind_file_ioctl_t   *p_ioctl;\r
539         FILE_OBJECT                             *p_file_obj;\r
540 \r
541         AL_ENTER( AL_DBG_DEV );\r
542 \r
543         p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );\r
544         p_context = (al_dev_open_context_t*)p_io_stack->FileObject->FsContext;\r
545 \r
546         /* Check the size of the ioctl */\r
547         if( !p_context ||\r
548                 !cl_ioctl_in_buf( h_ioctl ) || cl_ioctl_out_size( h_ioctl ) ||\r
549                 cl_ioctl_in_size( h_ioctl ) != sizeof(ual_bind_file_ioctl_t) )\r
550         {\r
551                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
552                         ("No input buffer, or buffer too small.\n") );\r
553                 return CL_INVALID_PARAMETER;\r
554         }\r
555 \r
556         p_ioctl = cl_ioctl_in_buf( h_ioctl );\r
557 \r
558         status = ObReferenceObjectByHandle( p_ioctl->h_file,\r
559                 READ_CONTROL, *IoFileObjectType, h_ioctl->RequestorMode,\r
560                 &p_file_obj, NULL );\r
561         if( !NT_SUCCESS(status) )\r
562         {\r
563                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
564                         ("ObReferenceObjectByHandle returned 0x%08X\n", status) );\r
565                 return CL_INVALID_PARAMETER;\r
566         }\r
567 \r
568         p_file_obj->FsContext = p_context;\r
569         p_file_obj->FsContext2 = (void*)(ULONG_PTR)type;\r
570 \r
571         ObDereferenceObject( p_file_obj );\r
572 \r
573         AL_EXIT( AL_DBG_DEV );\r
574         return CL_SUCCESS;\r
575 }\r
576 \r
577 \r
578 \r
579 cl_status_t\r
580 proxy_ioctl(\r
581         IN              cl_ioctl_handle_t               h_ioctl,\r
582                 OUT     size_t                                  *p_ret_bytes )\r
583 {\r
584         cl_status_t                     cl_status;\r
585 \r
586         AL_ENTER( AL_DBG_DEV );\r
587 \r
588         UNUSED_PARAM( p_ret_bytes );\r
589 \r
590         switch( cl_ioctl_ctl_code( h_ioctl ) )\r
591         {\r
592         case UAL_GET_MISC_CB_INFO:\r
593                 cl_status = proxy_get_misc_cb( h_ioctl );\r
594                 break;\r
595         case UAL_GET_COMP_CB_INFO:\r
596                 cl_status = proxy_get_comp_cb( h_ioctl );\r
597                 break;\r
598         case UAL_BIND:\r
599                 cl_status = al_dev_open( h_ioctl );\r
600                 break;\r
601         case UAL_BIND_SA:\r
602                 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_SA_REQ_SVC );\r
603                 break;\r
604         case UAL_BIND_DESTROY:\r
605         case UAL_BIND_PNP:\r
606                 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_PNP_MGR );\r
607                 break;\r
608         case UAL_BIND_CM:\r
609                 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_CM );\r
610                 break;\r
611         case UAL_BIND_CQ:\r
612                 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_H_CQ );\r
613                 break;\r
614         case UAL_BIND_MISC:\r
615                 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_AL_MGR );\r
616                 break;\r
617         case UAL_BIND_ND:\r
618                 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_NDI );\r
619                 break;\r
620         default:\r
621                 cl_status = CL_INVALID_PARAMETER;\r
622                 break;\r
623         }\r
624 \r
625         AL_EXIT( AL_DBG_DEV );\r
626         return cl_status;\r
627 }\r
628 \r
629 \r
630 static ib_api_status_t\r
631 __proxy_pnp_cb(\r
632         IN                              ib_pnp_rec_t                            *p_pnp_rec )\r
633 {\r
634         proxy_pnp_evt_t                         *p_evt;\r
635         uint32_t                                        rec_size;\r
636         proxy_pnp_recs_t                        *p_evt_rec, *p_rec;\r
637         IRP                                                     *p_irp;\r
638         IO_STACK_LOCATION                       *p_io_stack;\r
639         ual_rearm_pnp_ioctl_out_t       *p_ioctl;\r
640         al_dev_open_context_t           *p_context;\r
641         uint64_t                                        hdl;\r
642         cl_status_t                                     cl_status;\r
643         ib_api_status_t                         ret_status;\r
644 \r
645         AL_ENTER( AL_DBG_PNP );\r
646 \r
647         p_rec = (proxy_pnp_recs_t*)p_pnp_rec;\r
648 \r
649         /*\r
650          * If an add event, return error to suppress all further\r
651          * events for this target.\r
652          */\r
653         if( p_pnp_rec->pnp_event & IB_PNP_EVENT_ADD )\r
654                 ret_status = IB_ERROR;\r
655         else\r
656                 ret_status = IB_SUCCESS;\r
657 \r
658         p_context = p_pnp_rec->pnp_context;\r
659         ASSERT( p_context );\r
660 \r
661         /* Must take and release mutex to synchronize with registration. */\r
662         cl_mutex_acquire( &p_context->pnp_mutex );\r
663         cl_mutex_release( &p_context->pnp_mutex );\r
664 \r
665         p_irp = InterlockedExchangePointer( &p_pnp_rec->h_pnp->p_rearm_irp, NULL );\r
666         if( !p_irp )\r
667         {\r
668                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
669                         ("No rearm IRP queued for PnP event.\n") );\r
670                 return ret_status;\r
671         }\r
672 \r
673         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
674 \r
675         p_context = p_io_stack->FileObject->FsContext;\r
676         ASSERT( p_context );\r
677 #pragma warning(push, 3)\r
678         IoSetCancelRoutine( p_irp, NULL );\r
679 #pragma warning(pop)\r
680         switch( pnp_get_class( p_pnp_rec->pnp_event ) )\r
681         {\r
682         case IB_PNP_CA:\r
683                 if( p_pnp_rec->pnp_event == IB_PNP_CA_REMOVE )\r
684                         rec_size = sizeof(ib_pnp_ca_rec_t);\r
685                 else\r
686                         rec_size = sizeof(ib_pnp_ca_rec_t) + p_rec->ca.p_ca_attr->size;\r
687                 break;\r
688         case IB_PNP_PORT:\r
689                 if( p_pnp_rec->pnp_event == IB_PNP_PORT_REMOVE )\r
690                         rec_size = sizeof(ib_pnp_port_rec_t);\r
691                 else\r
692                         rec_size = sizeof(ib_pnp_port_rec_t) + p_rec->port.p_ca_attr->size;\r
693                 break;\r
694         case IB_PNP_IOU:\r
695                 rec_size = sizeof(ib_pnp_iou_rec_t);\r
696                 break;\r
697         case IB_PNP_IOC:\r
698                 switch( p_pnp_rec->pnp_event )\r
699                 {\r
700                 case IB_PNP_IOC_PATH_ADD:\r
701                 case IB_PNP_IOC_PATH_REMOVE:\r
702                         rec_size = sizeof( ib_pnp_ioc_path_rec_t);\r
703                         break;\r
704                 default:\r
705                         rec_size = sizeof( ib_pnp_ioc_rec_t ) + (sizeof(ib_svc_entry_t) *\r
706                                 (p_rec->ioc.info.profile.num_svc_entries - 1));\r
707                 }\r
708                 break;\r
709         default:\r
710                 /* The REG_COMPLETE event is not associated with any class. */\r
711                 rec_size = sizeof( ib_pnp_rec_t );\r
712                 break;\r
713         }\r
714 \r
715         p_evt = cl_zalloc( rec_size + sizeof(proxy_pnp_evt_t) );\r
716         if( !p_evt )\r
717                 return ret_status;\r
718 \r
719         /* Note that cl_event_init cannot fail in kernel-mode. */\r
720         cl_event_init( &p_evt->event, FALSE );\r
721 \r
722         p_evt->rec_size = rec_size;\r
723 \r
724         p_evt_rec = (proxy_pnp_recs_t*)(p_evt + 1);\r
725 \r
726         /* Copy the PnP event data. */\r
727         switch( pnp_get_class( p_pnp_rec->pnp_event ) )\r
728         {\r
729         case IB_PNP_CA:\r
730                 cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_ca_rec_t) );\r
731                 if( p_pnp_rec->pnp_event == IB_PNP_CA_REMOVE )\r
732                 {\r
733                         p_evt_rec->ca.p_ca_attr = NULL;\r
734                 }\r
735                 else\r
736                 {\r
737                         p_evt_rec->ca.p_ca_attr = (ib_ca_attr_t*)(&p_evt_rec->ca + 1);\r
738                         ib_copy_ca_attr( p_evt_rec->ca.p_ca_attr, p_rec->ca.p_ca_attr );\r
739                 }\r
740                 break;\r
741         case IB_PNP_PORT:\r
742                 cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_port_rec_t) );\r
743                 if( p_pnp_rec->pnp_event == IB_PNP_PORT_REMOVE )\r
744                 {\r
745                         p_evt_rec->port.p_ca_attr = NULL;\r
746                         p_evt_rec->port.p_port_attr = NULL;\r
747                 }\r
748                 else\r
749                 {\r
750                         p_evt_rec->port.p_ca_attr = (ib_ca_attr_t*)(&p_evt_rec->port + 1);\r
751                         ib_copy_ca_attr(\r
752                                 p_evt_rec->port.p_ca_attr, p_rec->port.p_ca_attr );\r
753                         p_evt_rec->port.p_port_attr = &p_evt_rec->port.p_ca_attr->\r
754                                 p_port_attr[p_rec->port.p_port_attr->port_num - 1];\r
755                 }\r
756                 break;\r
757         case IB_PNP_IOU:\r
758                 cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_iou_rec_t) );\r
759                 break;\r
760         case IB_PNP_IOC:\r
761                 switch( p_pnp_rec->pnp_event )\r
762                 {\r
763                 case IB_PNP_IOC_PATH_ADD:\r
764                 case IB_PNP_IOC_PATH_REMOVE:\r
765                         cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_ioc_path_rec_t) );\r
766                         break;\r
767                 default:\r
768                         cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_ioc_rec_t) );\r
769                 }\r
770                 break;\r
771         default:\r
772                 p_evt_rec->pnp = *p_pnp_rec;\r
773                 break;\r
774         }\r
775 \r
776         p_evt_rec->pnp.h_pnp_padding = p_pnp_rec->h_pnp->obj.hdl;\r
777         p_pnp_rec->h_pnp->obj.hdl_valid = TRUE;\r
778 \r
779         hdl =\r
780                 al_hdl_lock_insert( p_context->h_al, p_evt, AL_OBJ_TYPE_H_PNP_EVENT );\r
781         if( hdl == AL_INVALID_HANDLE )\r
782         {\r
783                 cl_free( p_evt );\r
784                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
785                         ("Failed to insert PnP event in handle map.\n") );\r
786                 return ret_status;\r
787         }\r
788 \r
789         p_ioctl = cl_ioctl_out_buf( p_irp );\r
790         p_ioctl->evt_hdl = hdl;\r
791         p_ioctl->evt_size = rec_size;\r
792 \r
793         /* Hold callback lock to synchronize with registration. */\r
794         cl_spinlock_acquire( &p_context->cb_lock );\r
795         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
796         p_irp->IoStatus.Information = sizeof(ual_rearm_pnp_ioctl_out_t);\r
797         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
798         cl_spinlock_release( &p_context->cb_lock );\r
799 \r
800         /* Now wait on the event. */\r
801         cl_status = cl_event_wait_on( &p_evt->event, PROXY_PNP_TIMEOUT_US, FALSE );\r
802         if( cl_status == CL_SUCCESS )\r
803         {\r
804                 /* Update the event context with the user's requested value. */\r
805                 p_pnp_rec->context = p_evt->evt_context;\r
806                 /* Forward the user's status. */\r
807                 ret_status = p_evt->evt_status;\r
808         }\r
809         cl_spinlock_acquire( &p_context->h_al->obj.lock );\r
810         al_hdl_free( p_context->h_al, hdl );\r
811         cl_spinlock_release( &p_context->h_al->obj.lock );\r
812         cl_event_destroy( &p_evt->event );\r
813         cl_free( p_evt );\r
814 \r
815         AL_EXIT( AL_DBG_PNP );\r
816         return ret_status;\r
817 }\r
818 \r
819 \r
820 static void\r
821 __cancel_rearm_pnp(\r
822         IN                              DEVICE_OBJECT*                          p_dev_obj,\r
823         IN                              IRP*                                            p_irp )\r
824 {\r
825         al_dev_open_context_t   *p_context;\r
826         PIO_STACK_LOCATION              p_io_stack;\r
827         uint64_t                                hdl;\r
828         al_pnp_t                                *h_pnp;\r
829 \r
830         AL_ENTER( AL_DBG_DEV );\r
831 \r
832         UNUSED_PARAM( p_dev_obj );\r
833 \r
834         /* Get the stack location. */\r
835         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
836 \r
837         p_context = (al_dev_open_context_t *)p_io_stack->FileObject->FsContext;\r
838         ASSERT( p_context );\r
839 \r
840         hdl = (size_t)InterlockedExchangePointer(\r
841                 &p_irp->Tail.Overlay.DriverContext[0], NULL );\r
842         if( hdl != AL_INVALID_HANDLE )\r
843         {\r
844                 h_pnp = (al_pnp_t*)\r
845                         al_hdl_ref( p_context->h_al, hdl, AL_OBJ_TYPE_H_PNP );\r
846                 if( h_pnp )\r
847                 {\r
848                         if( InterlockedExchangePointer( &h_pnp->p_rearm_irp, NULL ) ==\r
849                                 p_irp )\r
850                         {\r
851 #pragma warning(push, 3)\r
852                                 IoSetCancelRoutine( p_irp, NULL );\r
853 #pragma warning(pop)\r
854                                 /* Complete the IRP. */\r
855                                 p_irp->IoStatus.Status = STATUS_CANCELLED;\r
856                                 p_irp->IoStatus.Information = 0;\r
857                                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
858                         }\r
859                         deref_al_obj( &h_pnp->obj );\r
860                 }\r
861         }\r
862 \r
863         IoReleaseCancelSpinLock( p_irp->CancelIrql );\r
864 }\r
865 \r
866 \r
867 /*\r
868  * Process the ioctl UAL_REG_PNP:\r
869  */\r
870 static cl_status_t\r
871 proxy_reg_pnp(\r
872         IN                              void                                            *p_open_context,\r
873         IN                              cl_ioctl_handle_t                       h_ioctl )\r
874 {\r
875         ual_reg_pnp_ioctl_in_t  *p_ioctl;\r
876         al_dev_open_context_t   *p_context;\r
877         IO_STACK_LOCATION               *p_io_stack;\r
878         ib_pnp_req_t                    pnp_req;\r
879         ib_api_status_t                 status, *p_user_status;\r
880         uint64_t                                *p_user_hdl;\r
881         ib_pnp_handle_t                 h_pnp;\r
882         cl_status_t                             cl_status;\r
883         KEVENT                                  *p_sync_event;\r
884         NTSTATUS                                nt_status;\r
885 \r
886         AL_ENTER( AL_DBG_PNP );\r
887 \r
888         p_context = p_open_context;\r
889 \r
890         p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );\r
891         if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_PNP_MGR )\r
892         {\r
893                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
894                         ("Invalid file object type for request: %016I64x\n",\r
895                         (LONG_PTR)p_io_stack->FileObject->FsContext2) );\r
896                 return CL_INVALID_PARAMETER;\r
897         }\r
898 \r
899         if( cl_ioctl_in_size( h_ioctl ) < sizeof(ual_reg_pnp_ioctl_in_t) ||\r
900                 cl_ioctl_out_size( h_ioctl ) < sizeof(ual_rearm_pnp_ioctl_out_t) )\r
901         {\r
902                 AL_EXIT( AL_DBG_PNP );\r
903                 return CL_INVALID_PARAMETER;\r
904         }\r
905 \r
906         p_ioctl = cl_ioctl_in_buf( h_ioctl );\r
907 \r
908         pnp_req.pnp_class = p_ioctl->pnp_class;\r
909         pnp_req.pnp_context = p_open_context;\r
910         pnp_req.pfn_pnp_cb = __proxy_pnp_cb;\r
911 \r
912         p_user_status = (ib_api_status_t*)(ULONG_PTR)p_ioctl->p_status;\r
913         p_user_hdl = (uint64_t*)(ULONG_PTR)p_ioctl->p_hdl;\r
914 \r
915         if( pnp_get_flag( p_ioctl->pnp_class ) & IB_PNP_FLAG_REG_SYNC )\r
916         {\r
917                 nt_status = ObReferenceObjectByHandle( p_ioctl->sync_event,\r
918                         STANDARD_RIGHTS_ALL, *ExEventObjectType, h_ioctl->RequestorMode,\r
919                         (PVOID*)&p_sync_event, NULL );\r
920                 if( !NT_SUCCESS( nt_status ) )\r
921                 {\r
922                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid sync event handle\n") );\r
923                         return CL_INVALID_PARAMETER;\r
924                 }\r
925         }\r
926         else\r
927         {\r
928                 p_sync_event = NULL;\r
929         }\r
930 \r
931         cl_mutex_acquire( &p_context->pnp_mutex );\r
932         status = al_reg_pnp( p_context->h_al, &pnp_req, p_sync_event, &h_pnp );\r
933         if( status == IB_SUCCESS )\r
934         {\r
935                 CL_ASSERT( h_pnp );\r
936                 h_pnp->p_rearm_irp = h_ioctl;\r
937 \r
938                 h_ioctl->Tail.Overlay.DriverContext[0] = (void*)(size_t)h_pnp->obj.hdl;\r
939 #pragma warning(push, 3)\r
940                 IoSetCancelRoutine( h_ioctl, __cancel_rearm_pnp );\r
941 #pragma warning(pop)\r
942                 IoMarkIrpPending( h_ioctl );\r
943 \r
944                 cl_copy_to_user( p_user_hdl, &h_pnp->obj.hdl, sizeof(uint64_t) );\r
945 \r
946                 /* Mark the registration as a user-mode one. */\r
947                 h_pnp->obj.type |= AL_OBJ_SUBTYPE_UM_EXPORT;\r
948                 h_pnp->obj.hdl_valid = TRUE;\r
949                 deref_al_obj( &h_pnp->obj );\r
950 \r
951                 cl_status = CL_PENDING;\r
952         }\r
953         else\r
954         {\r
955                 cl_status = CL_INVALID_PARAMETER;\r
956         }\r
957 \r
958         cl_copy_to_user( p_user_status, &status, sizeof(ib_api_status_t) );\r
959         cl_mutex_release( &p_context->pnp_mutex );\r
960 \r
961         AL_EXIT( AL_DBG_PNP );\r
962         return cl_status;\r
963 }\r
964 \r
965 \r
966 /*\r
967  * Process the ioctl UAL_REG_PNP:\r
968  */\r
969 static cl_status_t\r
970 proxy_poll_pnp(\r
971         IN                              void                                            *p_open_context,\r
972         IN                              cl_ioctl_handle_t                       h_ioctl,\r
973                 OUT                     size_t                                          *p_ret_bytes )\r
974 {\r
975         ual_poll_pnp_ioctl_t    *p_ioctl;\r
976         al_dev_open_context_t   *p_context;\r
977         proxy_pnp_evt_t                 *p_evt;\r
978 \r
979         AL_ENTER( AL_DBG_PNP );\r
980 \r
981         p_context = p_open_context;\r
982 \r
983         if( cl_ioctl_in_size( h_ioctl ) < sizeof(uint64_t) ||\r
984                 cl_ioctl_out_size( h_ioctl ) < sizeof(ib_pnp_rec_t) )\r
985         {\r
986                 AL_EXIT( AL_DBG_PNP );\r
987                 return CL_INVALID_PARAMETER;\r
988         }\r
989 \r
990         p_ioctl = cl_ioctl_in_buf( h_ioctl );\r
991         CL_ASSERT( cl_ioctl_in_buf( h_ioctl ) == cl_ioctl_out_buf( h_ioctl ) );\r
992 \r
993         cl_spinlock_acquire( &p_context->h_al->obj.lock );\r
994         p_evt = al_hdl_chk(\r
995                 p_context->h_al, p_ioctl->in.evt_hdl, AL_OBJ_TYPE_H_PNP_EVENT );\r
996         if( p_evt )\r
997         {\r
998                 if( cl_ioctl_out_size( h_ioctl ) < p_evt->rec_size )\r
999                 {\r
1000                         cl_spinlock_release( &p_context->h_al->obj.lock );\r
1001                         AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Buffer too small!\n") );\r
1002                         return CL_INVALID_PARAMETER;\r
1003                 }\r
1004 \r
1005                 cl_memcpy( &p_ioctl->out.pnp_rec, p_evt + 1, p_evt->rec_size );\r
1006                 *p_ret_bytes = p_evt->rec_size;\r
1007         }\r
1008         cl_spinlock_release( &p_context->h_al->obj.lock );\r
1009 \r
1010         AL_EXIT( AL_DBG_PNP );\r
1011         return CL_SUCCESS;\r
1012 }\r
1013 \r
1014 \r
1015 /*\r
1016  * Process the ioctl UAL_REG_PNP:\r
1017  */\r
1018 static cl_status_t\r
1019 proxy_rearm_pnp(\r
1020         IN                              void                                            *p_open_context,\r
1021         IN                              cl_ioctl_handle_t                       h_ioctl )\r
1022 {\r
1023         ual_rearm_pnp_ioctl_in_t        *p_ioctl;\r
1024         al_dev_open_context_t           *p_context;\r
1025         IO_STACK_LOCATION                       *p_io_stack;\r
1026         proxy_pnp_evt_t                         *p_evt;\r
1027         ib_pnp_handle_t                         h_pnp;\r
1028         IRP                                                     *p_old_irp;\r
1029 \r
1030         AL_ENTER( AL_DBG_PNP );\r
1031 \r
1032         p_context = p_open_context;\r
1033 \r
1034         p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );\r
1035         if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_PNP_MGR )\r
1036         {\r
1037                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1038                         ("Invalid file object type for request: %016I64x\n",\r
1039                         (LONG_PTR)p_io_stack->FileObject->FsContext2) );\r
1040                 return CL_INVALID_PARAMETER;\r
1041         }\r
1042 \r
1043         if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_rearm_pnp_ioctl_in_t) ||\r
1044                 cl_ioctl_out_size( h_ioctl ) != sizeof(ual_rearm_pnp_ioctl_out_t) )\r
1045         {\r
1046                 AL_EXIT( AL_DBG_PNP );\r
1047                 return CL_INVALID_PARAMETER;\r
1048         }\r
1049 \r
1050         p_ioctl = cl_ioctl_in_buf( h_ioctl );\r
1051 \r
1052         h_pnp = (al_pnp_t*)\r
1053                 al_hdl_ref( p_context->h_al, p_ioctl->pnp_hdl, AL_OBJ_TYPE_H_PNP );\r
1054         if( !h_pnp )\r
1055         {\r
1056                 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_PNP,\r
1057                         ("Invalid PNP handle.\n") );\r
1058                 return CL_INVALID_PARAMETER;\r
1059         }\r
1060 #pragma warning(push, 3)\r
1061         IoSetCancelRoutine( h_ioctl, __cancel_rearm_pnp );\r
1062 #pragma warning(pop)\r
1063         IoMarkIrpPending( h_ioctl );\r
1064         h_ioctl->Tail.Overlay.DriverContext[0] = (void*)(size_t)h_pnp->obj.hdl;\r
1065 \r
1066         /*\r
1067          * Update the object context before signalling the event since that value\r
1068          * is returned by the PnP callback.\r
1069          */\r
1070         p_old_irp = InterlockedExchangePointer( &h_pnp->p_rearm_irp, h_ioctl );\r
1071         if( p_old_irp )\r
1072         {\r
1073 #pragma warning(push, 3)\r
1074                 IoSetCancelRoutine( p_old_irp, NULL );\r
1075 #pragma warning(pop)\r
1076                 /* Complete the IRP. */\r
1077                 p_old_irp->IoStatus.Status = STATUS_CANCELLED;\r
1078                 p_old_irp->IoStatus.Information = 0;\r
1079                 IoCompleteRequest( p_old_irp, IO_NO_INCREMENT );\r
1080         }\r
1081 \r
1082         cl_spinlock_acquire( &p_context->h_al->obj.lock );\r
1083         p_evt = al_hdl_chk(\r
1084                 p_context->h_al, p_ioctl->last_evt_hdl, AL_OBJ_TYPE_H_PNP_EVENT );\r
1085         if( p_evt )\r
1086         {\r
1087                 p_evt->evt_context = (void*)(ULONG_PTR)p_ioctl->last_evt_context;\r
1088                 p_evt->evt_status = p_ioctl->last_evt_status;\r
1089                 cl_event_signal( &p_evt->event );\r
1090         }\r
1091         cl_spinlock_release( &p_context->h_al->obj.lock );\r
1092 \r
1093         deref_al_obj( &h_pnp->obj );\r
1094 \r
1095         AL_EXIT( AL_DBG_PNP );\r
1096         return CL_PENDING;\r
1097 }\r
1098 \r
1099 \r
1100 /*\r
1101  * Process the ioctl UAL_DEREG_PNP:\r
1102  */\r
1103 static cl_status_t\r
1104 proxy_dereg_pnp(\r
1105         IN                              void                                            *p_open_context,\r
1106         IN                              cl_ioctl_handle_t                       h_ioctl )\r
1107 {\r
1108         uint64_t                                *p_hdl;\r
1109         al_dev_open_context_t   *p_context;\r
1110         IO_STACK_LOCATION               *p_io_stack;\r
1111         ib_pnp_handle_t                 h_pnp;\r
1112 \r
1113         AL_ENTER( AL_DBG_PNP );\r
1114         p_context = p_open_context;\r
1115 \r
1116         p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );\r
1117         if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_PNP_MGR )\r
1118         {\r
1119                 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,\r
1120                         ("Invalid file object type for request: %016I64x\n",\r
1121                         (LONG_PTR)p_io_stack->FileObject->FsContext2) );\r
1122                 return CL_INVALID_PARAMETER;\r
1123         }\r
1124 \r
1125         if( cl_ioctl_in_size( h_ioctl ) < sizeof(ual_dereg_pnp_ioctl_t) ||\r
1126                 cl_ioctl_out_size( h_ioctl ) )\r
1127         {\r
1128                 AL_EXIT( AL_DBG_DEV );\r
1129                 return CL_INVALID_PARAMETER;\r
1130         }\r
1131 \r
1132         p_hdl = cl_ioctl_in_buf( h_ioctl );\r
1133 \r
1134         h_pnp = (ib_pnp_handle_t)\r
1135                 al_hdl_ref( p_context->h_al, *p_hdl, AL_OBJ_TYPE_H_PNP );\r
1136         if( !h_pnp )\r
1137         {\r
1138                 AL_EXIT( AL_DBG_DEV );\r
1139                 return CL_INVALID_PARAMETER;\r
1140         }\r
1141 \r
1142         h_pnp->p_dereg_irp = h_ioctl;\r
1143 \r
1144         IoMarkIrpPending( h_ioctl );\r
1145 \r
1146         h_pnp->obj.pfn_destroy( &h_pnp->obj, NULL );\r
1147 \r
1148         AL_EXIT( AL_DBG_PNP );\r
1149         return CL_PENDING;\r
1150 }\r
1151 \r
1152 \r
1153 \r
1154 cl_status_t\r
1155 al_ioctl(\r
1156         IN              cl_ioctl_handle_t               h_ioctl,\r
1157                 OUT     size_t                                  *p_ret_bytes )\r
1158 {\r
1159         cl_status_t                             cl_status;\r
1160         IO_STACK_LOCATION               *p_io_stack;\r
1161         void                                    *p_context;\r
1162 \r
1163         AL_ENTER( AL_DBG_DEV );\r
1164 \r
1165         CL_ASSERT( h_ioctl && p_ret_bytes );\r
1166 \r
1167         p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );\r
1168         p_context = p_io_stack->FileObject->FsContext;\r
1169 \r
1170         if( !p_context )\r
1171         {\r
1172                 AL_EXIT( AL_DBG_DEV );\r
1173                 return CL_INVALID_PARAMETER;\r
1174         }\r
1175 \r
1176         switch( cl_ioctl_ctl_code( h_ioctl ) )\r
1177         {\r
1178         case UAL_REG_SHMID:\r
1179                 cl_status = proxy_reg_shmid( p_context, h_ioctl, p_ret_bytes );\r
1180                 break;\r
1181         case UAL_GET_CA_ATTR_INFO:\r
1182                 cl_status = proxy_get_ca_attr( p_context, h_ioctl, p_ret_bytes );\r
1183                 break;\r
1184         case UAL_REG_PNP:\r
1185                 cl_status = proxy_reg_pnp( p_context, h_ioctl );\r
1186                 break;\r
1187         case UAL_POLL_PNP:\r
1188                 cl_status = proxy_poll_pnp( p_context, h_ioctl, p_ret_bytes );\r
1189                 break;\r
1190         case UAL_REARM_PNP:\r
1191                 cl_status = proxy_rearm_pnp( p_context, h_ioctl );\r
1192                 break;\r
1193         case UAL_DEREG_PNP:\r
1194                 cl_status = proxy_dereg_pnp( p_context, h_ioctl );\r
1195                 break;\r
1196         default:\r
1197                 cl_status = CL_INVALID_PARAMETER;\r
1198                 break;\r
1199         }\r
1200 \r
1201         AL_EXIT( AL_DBG_DEV );\r
1202         return cl_status;\r
1203 }\r
1204 \r
1205 \r
1206 NTSTATUS\r
1207 ib_to_ntstatus(\r
1208     IN  ib_api_status_t ib_status )\r
1209 {\r
1210     switch( ib_status )\r
1211     {\r
1212     case IB_SUCCESS:\r
1213         return STATUS_SUCCESS;\r
1214         case IB_INSUFFICIENT_RESOURCES:\r
1215         case IB_MAX_MCAST_QPS_REACHED:\r
1216         return STATUS_INSUFFICIENT_RESOURCES;\r
1217         case IB_INSUFFICIENT_MEMORY:\r
1218         return STATUS_NO_MEMORY;\r
1219         case IB_INVALID_PARAMETER:\r
1220         case IB_INVALID_SETTING:\r
1221         case IB_INVALID_PKEY:\r
1222         case IB_INVALID_LKEY:\r
1223         case IB_INVALID_RKEY:\r
1224         case IB_INVALID_MAX_WRS:\r
1225         case IB_INVALID_MAX_SGE:\r
1226         case IB_INVALID_CQ_SIZE:\r
1227         case IB_INVALID_SRQ_SIZE:\r
1228         case IB_INVALID_SERVICE_TYPE:\r
1229         case IB_INVALID_GID:\r
1230         case IB_INVALID_LID:\r
1231         case IB_INVALID_GUID:\r
1232         case IB_INVALID_WR_TYPE:\r
1233         case IB_INVALID_PORT:\r
1234         case IB_INVALID_INDEX:\r
1235         return STATUS_INVALID_PARAMETER;\r
1236         case IB_NO_MATCH:\r
1237         case IB_NOT_FOUND:\r
1238         return STATUS_NOT_FOUND;\r
1239         case IB_TIMEOUT:\r
1240         return STATUS_TIMEOUT;\r
1241         case IB_CANCELED:\r
1242         return STATUS_CANCELLED;\r
1243         case IB_INTERRUPTED:\r
1244         case IB_NOT_DONE:\r
1245         return STATUS_ABANDONED;\r
1246         case IB_INVALID_PERMISSION:\r
1247         return STATUS_ACCESS_DENIED;\r
1248         case IB_UNSUPPORTED:\r
1249         case IB_QP_IN_TIMEWAIT:\r
1250         case IB_EE_IN_TIMEWAIT:\r
1251         return STATUS_INVALID_DEVICE_REQUEST;\r
1252         case IB_OVERFLOW:\r
1253         return STATUS_BUFFER_OVERFLOW;\r
1254         case IB_INVALID_QP_STATE:\r
1255         case IB_INVALID_APM_STATE:\r
1256         case IB_INVALID_PORT_STATE:\r
1257         case IB_INVALID_STATE:\r
1258         return STATUS_INVALID_DEVICE_STATE;\r
1259         case IB_RESOURCE_BUSY:\r
1260         return STATUS_DEVICE_BUSY;\r
1261         case IB_INVALID_CA_HANDLE:\r
1262         case IB_INVALID_AV_HANDLE:\r
1263         case IB_INVALID_CQ_HANDLE:\r
1264         case IB_INVALID_QP_HANDLE:\r
1265         case IB_INVALID_SRQ_HANDLE:\r
1266         case IB_INVALID_PD_HANDLE:\r
1267         case IB_INVALID_MR_HANDLE:\r
1268         case IB_INVALID_FMR_HANDLE:\r
1269         case IB_INVALID_MW_HANDLE:\r
1270         case IB_INVALID_MCAST_HANDLE:\r
1271         case IB_INVALID_CALLBACK:\r
1272         case IB_INVALID_AL_HANDLE:\r
1273         case IB_INVALID_HANDLE:\r
1274         return STATUS_INVALID_HANDLE;\r
1275         case IB_VERBS_PROCESSING_DONE:\r
1276         return STATUS_EVENT_DONE;\r
1277         case IB_PENDING:\r
1278         return STATUS_PENDING;\r
1279         case IB_ERROR:\r
1280         case IB_REMOTE_ERROR:\r
1281     default:\r
1282         return STATUS_UNSUCCESSFUL;\r
1283     }\r
1284 }\r