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
6 * This software is available to you under the OpenIB.org BSD license
\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
13 * - Redistributions of source code must retain the above
\r
14 * copyright notice, this list of conditions and the following
\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
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
35 #include <complib/comp_lib.h>
\r
36 #include <iba/ib_al.h>
\r
37 #include <iba/ib_al_ioctl.h>
\r
40 #include "al_debug.h"
\r
41 #if defined(EVENT_TRACING)
\r
45 #include "al_proxy.tmh"
\r
48 #include "al_ci_ca.h"
\r
51 #include "al_proxy.h"
\r
52 #include "ib_common.h"
\r
57 * Acquire an object used to queue callbacks.
\r
61 IN al_dev_open_context_t *p_context )
\r
63 al_proxy_cb_info_t *p_cb_info;
\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
73 p_cb_info->p_context = p_context;
\r
81 * Release an object used to report callbacks.
\r
85 IN al_proxy_cb_info_t *p_cb_info )
\r
87 al_dev_open_context_t *p_context;
\r
92 p_context = p_cb_info->p_context;
\r
94 p_cb_info->reported = FALSE;
\r
95 p_cb_info->p_al_obj = NULL;
\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
105 * Process the ioctl UAL_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
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
121 net32_t lkey, rkey;
\r
123 AL_ENTER( AL_DBG_DEV );
\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
129 AL_EXIT( AL_DBG_DEV );
\r
130 return CL_INVALID_PARAMETER;
\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
138 cl_memclr( &p_ioctl->out, sizeof(p_ioctl->out) );
\r
139 p_ioctl->out.status = IB_INVALID_PD_HANDLE;
\r
143 /* Validate input region size. */
\r
144 if( p_ioctl->in.mr_create.length > ~((size_t)0) )
\r
146 cl_memclr( &p_ioctl->out, sizeof(p_ioctl->out) );
\r
147 p_ioctl->out.status = IB_INVALID_SETTING;
\r
151 p_ioctl->out.status = reg_shmid(
\r
154 &p_ioctl->in.mr_create,
\r
160 if( p_ioctl->out.status == IB_SUCCESS )
\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
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
180 *p_ret_bytes = sizeof(p_ioctl->out);
\r
181 AL_EXIT( AL_DBG_DEV );
\r
187 * Retrieve a callback record from the appropriate callback list
\r
188 * and fill the ioctl buffer.
\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
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
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
205 AL_ENTER( AL_DBG_DEV );
\r
207 /* Set up the appropriate callback list. */
\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
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
225 AL_EXIT( AL_DBG_DEV );
\r
226 return CL_INVALID_PARAMETER;
\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
233 p_cb_info = (al_proxy_cb_info_t*)cl_qlist_head( p_cb_list );
\r
235 /* Check to see if we've already reported the callback. */
\r
236 if( !p_cb_info->reported )
\r
238 p_cb_info->reported = TRUE;
\r
240 /* Return the callback to the user. */
\r
241 CL_ASSERT( cl_ioctl_out_size( h_ioctl ) >= ioctl_size );
\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
249 if( p_cb_info->p_al_obj )
\r
250 deref_al_obj( p_cb_info->p_al_obj );
\r
252 cl_qlist_remove_head( p_cb_list );
\r
253 proxy_cb_put( p_cb_info );
\r
256 /* There are no callbacks to report. Mark this IOCTL as pending. */
\r
257 CL_ASSERT( !(*ph_ioctl) );
\r
259 /* If we're closing down, complete the IOCTL with a canceled status. */
\r
260 if( p_context->closing )
\r
262 cl_spinlock_release( &p_context->cb_lock );
\r
263 AL_EXIT( AL_DBG_DEV );
\r
264 return CL_CANCELED;
\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
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
279 AL_EXIT( AL_DBG_DEV );
\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
291 IN cl_ioctl_handle_t h_ioctl )
\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
297 AL_ENTER( AL_DBG_DEV );
\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
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
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
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
318 cl_status = proxy_queue_ioctl_buf( UAL_GET_COMP_CB_INFO,
\r
319 p_context, h_ioctl );
\r
321 AL_EXIT( AL_DBG_DEV );
\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
333 IN cl_ioctl_handle_t h_ioctl )
\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
339 AL_ENTER( AL_DBG_DEV );
\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
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
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
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
360 cl_status = proxy_queue_ioctl_buf( UAL_GET_MISC_CB_INFO,
\r
361 p_context, h_ioctl );
\r
363 AL_EXIT( AL_DBG_DEV );
\r
370 * Process a PnP callback for a CA.
\r
374 IN ib_pnp_rec_t *p_pnp_rec )
\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
380 AL_ENTER( AL_DBG_PROXY_CB );
\r
382 p_context = p_pnp_rec->pnp_context;
\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
388 if( !proxy_context_ref( p_context ) )
\r
390 proxy_context_deref( p_context );
\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
399 switch( p_pnp_rec->pnp_event )
\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
410 /* We only handle CA adds and removals. */
\r
414 proxy_context_deref( p_context );
\r
415 AL_EXIT( AL_DBG_PROXY_CB );
\r
422 * Process a PnP callback for a port.
\r
426 IN ib_pnp_rec_t *p_pnp_rec )
\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
433 AL_ENTER( AL_DBG_PROXY_CB );
\r
435 p_context = p_pnp_rec->pnp_context;
\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
441 if( !proxy_context_ref( p_context ) )
\r
443 proxy_context_deref( p_context );
\r
447 p_port_rec = (ib_pnp_port_rec_t*)p_pnp_rec;
\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
454 switch( p_pnp_rec->pnp_event )
\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
461 case IB_PNP_REG_COMPLETE:
\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
467 proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &misc_cb_info,
\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
475 proxy_queue_cb_buf( UAL_GET_MISC_CB_INFO, p_context, &misc_cb_info,
\r
480 proxy_context_deref( p_context );
\r
481 AL_EXIT( AL_DBG_PROXY_CB );
\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
493 al_dev_open_context_t *p_context;
\r
494 uint64_t *ph_ca_attr;
\r
495 ib_ca_attr_t *p_src;
\r
497 AL_ENTER( AL_DBG_DEV );
\r
499 UNREFERENCED_PARAMETER( p_ret_bytes );
\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
505 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("invalid buffer size\n") );
\r
506 return CL_INVALID_PARAMETER;
\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
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
515 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("invalid attr handle\n") );
\r
516 return CL_INVALID_PARAMETER;
\r
521 AL_EXIT( AL_DBG_DEV );
\r
527 * Process the ioctl UAL_BIND_SA:
\r
528 * Get a completion callback record from the queue of CM callback records
\r
532 IN cl_ioctl_handle_t h_ioctl,
\r
533 IN const uint32_t type )
\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
541 AL_ENTER( AL_DBG_DEV );
\r
543 p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );
\r
544 p_context = (al_dev_open_context_t*)p_io_stack->FileObject->FsContext;
\r
546 /* Check the size of the ioctl */
\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
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
556 p_ioctl = cl_ioctl_in_buf( h_ioctl );
\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
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
568 p_file_obj->FsContext = p_context;
\r
569 p_file_obj->FsContext2 = (void*)(ULONG_PTR)type;
\r
571 ObDereferenceObject( p_file_obj );
\r
573 AL_EXIT( AL_DBG_DEV );
\r
581 IN cl_ioctl_handle_t h_ioctl,
\r
582 OUT size_t *p_ret_bytes )
\r
584 cl_status_t cl_status;
\r
586 AL_ENTER( AL_DBG_DEV );
\r
588 UNUSED_PARAM( p_ret_bytes );
\r
590 switch( cl_ioctl_ctl_code( h_ioctl ) )
\r
592 case UAL_GET_MISC_CB_INFO:
\r
593 cl_status = proxy_get_misc_cb( h_ioctl );
\r
595 case UAL_GET_COMP_CB_INFO:
\r
596 cl_status = proxy_get_comp_cb( h_ioctl );
\r
599 cl_status = al_dev_open( h_ioctl );
\r
602 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_SA_REQ_SVC );
\r
604 case UAL_BIND_DESTROY:
\r
606 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_PNP_MGR );
\r
609 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_CM );
\r
612 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_H_CQ );
\r
614 case UAL_BIND_MISC:
\r
615 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_AL_MGR );
\r
618 cl_status = proxy_bind_file( h_ioctl, AL_OBJ_TYPE_NDI );
\r
621 cl_status = CL_INVALID_PARAMETER;
\r
625 AL_EXIT( AL_DBG_DEV );
\r
630 static ib_api_status_t
\r
632 IN ib_pnp_rec_t *p_pnp_rec )
\r
634 proxy_pnp_evt_t *p_evt;
\r
636 proxy_pnp_recs_t *p_evt_rec, *p_rec;
\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
642 cl_status_t cl_status;
\r
643 ib_api_status_t ret_status;
\r
645 AL_ENTER( AL_DBG_PNP );
\r
647 p_rec = (proxy_pnp_recs_t*)p_pnp_rec;
\r
650 * If an add event, return error to suppress all further
\r
651 * events for this target.
\r
653 if( p_pnp_rec->pnp_event & IB_PNP_EVENT_ADD )
\r
654 ret_status = IB_ERROR;
\r
656 ret_status = IB_SUCCESS;
\r
658 p_context = p_pnp_rec->pnp_context;
\r
659 ASSERT( p_context );
\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
665 p_irp = InterlockedExchangePointer( &p_pnp_rec->h_pnp->p_rearm_irp, NULL );
\r
668 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
669 ("No rearm IRP queued for PnP event.\n") );
\r
673 p_io_stack = IoGetCurrentIrpStackLocation( p_irp );
\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
683 if( p_pnp_rec->pnp_event == IB_PNP_CA_REMOVE )
\r
684 rec_size = sizeof(ib_pnp_ca_rec_t);
\r
686 rec_size = sizeof(ib_pnp_ca_rec_t) + p_rec->ca.p_ca_attr->size;
\r
689 if( p_pnp_rec->pnp_event == IB_PNP_PORT_REMOVE )
\r
690 rec_size = sizeof(ib_pnp_port_rec_t);
\r
692 rec_size = sizeof(ib_pnp_port_rec_t) + p_rec->port.p_ca_attr->size;
\r
695 rec_size = sizeof(ib_pnp_iou_rec_t);
\r
698 switch( p_pnp_rec->pnp_event )
\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
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
710 /* The REG_COMPLETE event is not associated with any class. */
\r
711 rec_size = sizeof( ib_pnp_rec_t );
\r
715 p_evt = cl_zalloc( rec_size + sizeof(proxy_pnp_evt_t) );
\r
719 /* Note that cl_event_init cannot fail in kernel-mode. */
\r
720 cl_event_init( &p_evt->event, FALSE );
\r
722 p_evt->rec_size = rec_size;
\r
724 p_evt_rec = (proxy_pnp_recs_t*)(p_evt + 1);
\r
726 /* Copy the PnP event data. */
\r
727 switch( pnp_get_class( p_pnp_rec->pnp_event ) )
\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
733 p_evt_rec->ca.p_ca_attr = NULL;
\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
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
745 p_evt_rec->port.p_ca_attr = NULL;
\r
746 p_evt_rec->port.p_port_attr = NULL;
\r
750 p_evt_rec->port.p_ca_attr = (ib_ca_attr_t*)(&p_evt_rec->port + 1);
\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
758 cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_iou_rec_t) );
\r
761 switch( p_pnp_rec->pnp_event )
\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
768 cl_memcpy( p_evt_rec, p_pnp_rec, sizeof(ib_pnp_ioc_rec_t) );
\r
772 p_evt_rec->pnp = *p_pnp_rec;
\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
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
784 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
785 ("Failed to insert PnP event in handle map.\n") );
\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
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
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
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
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
815 AL_EXIT( AL_DBG_PNP );
\r
821 __cancel_rearm_pnp(
\r
822 IN DEVICE_OBJECT* p_dev_obj,
\r
825 al_dev_open_context_t *p_context;
\r
826 PIO_STACK_LOCATION p_io_stack;
\r
830 AL_ENTER( AL_DBG_DEV );
\r
832 UNUSED_PARAM( p_dev_obj );
\r
834 /* Get the stack location. */
\r
835 p_io_stack = IoGetCurrentIrpStackLocation( p_irp );
\r
837 p_context = (al_dev_open_context_t *)p_io_stack->FileObject->FsContext;
\r
838 ASSERT( p_context );
\r
840 hdl = (size_t)InterlockedExchangePointer(
\r
841 &p_irp->Tail.Overlay.DriverContext[0], NULL );
\r
842 if( hdl != AL_INVALID_HANDLE )
\r
844 h_pnp = (al_pnp_t*)
\r
845 al_hdl_ref( p_context->h_al, hdl, AL_OBJ_TYPE_H_PNP );
\r
848 if( InterlockedExchangePointer( &h_pnp->p_rearm_irp, NULL ) ==
\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
859 deref_al_obj( &h_pnp->obj );
\r
863 IoReleaseCancelSpinLock( p_irp->CancelIrql );
\r
868 * Process the ioctl UAL_REG_PNP:
\r
872 IN void *p_open_context,
\r
873 IN cl_ioctl_handle_t h_ioctl )
\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
886 AL_ENTER( AL_DBG_PNP );
\r
888 p_context = p_open_context;
\r
890 p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );
\r
891 if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_PNP_MGR )
\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
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
902 AL_EXIT( AL_DBG_PNP );
\r
903 return CL_INVALID_PARAMETER;
\r
906 p_ioctl = cl_ioctl_in_buf( h_ioctl );
\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
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
915 if( pnp_get_flag( p_ioctl->pnp_class ) & IB_PNP_FLAG_REG_SYNC )
\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
922 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("Invalid sync event handle\n") );
\r
923 return CL_INVALID_PARAMETER;
\r
928 p_sync_event = NULL;
\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
935 CL_ASSERT( h_pnp );
\r
936 h_pnp->p_rearm_irp = h_ioctl;
\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
944 cl_copy_to_user( p_user_hdl, &h_pnp->obj.hdl, sizeof(uint64_t) );
\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
951 cl_status = CL_PENDING;
\r
955 cl_status = CL_INVALID_PARAMETER;
\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
961 AL_EXIT( AL_DBG_PNP );
\r
967 * Process the ioctl UAL_REG_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
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
979 AL_ENTER( AL_DBG_PNP );
\r
981 p_context = p_open_context;
\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
986 AL_EXIT( AL_DBG_PNP );
\r
987 return CL_INVALID_PARAMETER;
\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
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
998 if( cl_ioctl_out_size( h_ioctl ) < p_evt->rec_size )
\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
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
1008 cl_spinlock_release( &p_context->h_al->obj.lock );
\r
1010 AL_EXIT( AL_DBG_PNP );
\r
1011 return CL_SUCCESS;
\r
1016 * Process the ioctl UAL_REG_PNP:
\r
1018 static cl_status_t
\r
1020 IN void *p_open_context,
\r
1021 IN cl_ioctl_handle_t h_ioctl )
\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
1030 AL_ENTER( AL_DBG_PNP );
\r
1032 p_context = p_open_context;
\r
1034 p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );
\r
1035 if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_PNP_MGR )
\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
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
1046 AL_EXIT( AL_DBG_PNP );
\r
1047 return CL_INVALID_PARAMETER;
\r
1050 p_ioctl = cl_ioctl_in_buf( h_ioctl );
\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
1056 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_PNP,
\r
1057 ("Invalid PNP handle.\n") );
\r
1058 return CL_INVALID_PARAMETER;
\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
1067 * Update the object context before signalling the event since that value
\r
1068 * is returned by the PnP callback.
\r
1070 p_old_irp = InterlockedExchangePointer( &h_pnp->p_rearm_irp, h_ioctl );
\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
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
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
1091 cl_spinlock_release( &p_context->h_al->obj.lock );
\r
1093 deref_al_obj( &h_pnp->obj );
\r
1095 AL_EXIT( AL_DBG_PNP );
\r
1096 return CL_PENDING;
\r
1101 * Process the ioctl UAL_DEREG_PNP:
\r
1103 static cl_status_t
\r
1105 IN void *p_open_context,
\r
1106 IN cl_ioctl_handle_t h_ioctl )
\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
1113 AL_ENTER( AL_DBG_PNP );
\r
1114 p_context = p_open_context;
\r
1116 p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );
\r
1117 if( (uintn_t)p_io_stack->FileObject->FsContext2 != AL_OBJ_TYPE_PNP_MGR )
\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
1125 if( cl_ioctl_in_size( h_ioctl ) < sizeof(ual_dereg_pnp_ioctl_t) ||
\r
1126 cl_ioctl_out_size( h_ioctl ) )
\r
1128 AL_EXIT( AL_DBG_DEV );
\r
1129 return CL_INVALID_PARAMETER;
\r
1132 p_hdl = cl_ioctl_in_buf( h_ioctl );
\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
1138 AL_EXIT( AL_DBG_DEV );
\r
1139 return CL_INVALID_PARAMETER;
\r
1142 h_pnp->p_dereg_irp = h_ioctl;
\r
1144 IoMarkIrpPending( h_ioctl );
\r
1146 h_pnp->obj.pfn_destroy( &h_pnp->obj, NULL );
\r
1148 AL_EXIT( AL_DBG_PNP );
\r
1149 return CL_PENDING;
\r
1156 IN cl_ioctl_handle_t h_ioctl,
\r
1157 OUT size_t *p_ret_bytes )
\r
1159 cl_status_t cl_status;
\r
1160 IO_STACK_LOCATION *p_io_stack;
\r
1163 AL_ENTER( AL_DBG_DEV );
\r
1165 CL_ASSERT( h_ioctl && p_ret_bytes );
\r
1167 p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );
\r
1168 p_context = p_io_stack->FileObject->FsContext;
\r
1172 AL_EXIT( AL_DBG_DEV );
\r
1173 return CL_INVALID_PARAMETER;
\r
1176 switch( cl_ioctl_ctl_code( h_ioctl ) )
\r
1178 case UAL_REG_SHMID:
\r
1179 cl_status = proxy_reg_shmid( p_context, h_ioctl, p_ret_bytes );
\r
1181 case UAL_GET_CA_ATTR_INFO:
\r
1182 cl_status = proxy_get_ca_attr( p_context, h_ioctl, p_ret_bytes );
\r
1185 cl_status = proxy_reg_pnp( p_context, h_ioctl );
\r
1187 case UAL_POLL_PNP:
\r
1188 cl_status = proxy_poll_pnp( p_context, h_ioctl, p_ret_bytes );
\r
1190 case UAL_REARM_PNP:
\r
1191 cl_status = proxy_rearm_pnp( p_context, h_ioctl );
\r
1193 case UAL_DEREG_PNP:
\r
1194 cl_status = proxy_dereg_pnp( p_context, h_ioctl );
\r
1197 cl_status = CL_INVALID_PARAMETER;
\r
1201 AL_EXIT( AL_DBG_DEV );
\r
1208 IN ib_api_status_t ib_status )
\r
1210 switch( ib_status )
\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
1237 case IB_NOT_FOUND:
\r
1238 return STATUS_NOT_FOUND;
\r
1240 return STATUS_TIMEOUT;
\r
1242 return STATUS_CANCELLED;
\r
1243 case IB_INTERRUPTED:
\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
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
1278 return STATUS_PENDING;
\r
1280 case IB_REMOTE_ERROR:
\r
1282 return STATUS_UNSUCCESSFUL;
\r