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