--- /dev/null
+/*
+ * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under the OpenIB.org BSD license
+ * below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: al_proxy_verbs.c 548 2006-11-27 20:03:51Z leonidk $
+ */
+
+
+#include <complib/comp_lib.h>
+#include <iba/ib_al.h>
+#include <iba/ib_al_ioctl.h>
+#include "al.h"
+#include "al_debug.h"
+
+#if defined(EVENT_TRACING)
+#ifdef offsetof
+#undef offsetof
+#endif
+#include "al_proxy_ndi.tmh"
+#endif
+
+#include "al_dev.h"
+/* Get the internal definitions of apis for the proxy */
+#include "al_ca.h"
+#include "al_pd.h"
+#include "al_cq.h"
+#include "ib_common.h"
+#include "al_proxy_ndi.h"
+
+/*******************************************************************
+ *
+ * Helpers
+ *
+ ******************************************************************/
+
+#pragma warning(disable:4706)
+static inline void __ndi_flush_que(
+ IN ib_cq_handle_t h_cq,
+ IN PIO_CSQ Csq,
+ IN NTSTATUS completion_code
+ )
+{
+ PIRP Irp;
+ while( Irp = IoCsqRemoveNextIrp( Csq, NULL ) )
+ {
+ cl_ioctl_complete( Irp, completion_code, 0 );
+ deref_al_obj( &h_cq->obj );
+ }
+}
+#pragma warning(default:4706)
+
+/*******************************************************************
+ *
+ * Callbacks
+ *
+ ******************************************************************/
+
+static void __ndi_cq_compl_cb(
+ IN const ib_cq_handle_t h_cq,
+ IN void *cq_context )
+{
+ UNUSED_PARAM( cq_context );
+ AL_ENTER( AL_DBG_NDI );
+ __ndi_flush_que( h_cq, (PIO_CSQ)&h_cq->compl, STATUS_SUCCESS );
+ AL_EXIT( AL_DBG_NDI );
+}
+
+static void __ndi_cq_error_cb(
+ IN ib_async_event_rec_t *p_err_rec)
+{
+ ib_cq_handle_t h_cq = p_err_rec->handle.h_cq;
+ AL_ENTER( AL_DBG_NDI );
+ __ndi_flush_que( h_cq, (PIO_CSQ)&h_cq->compl, STATUS_INTERNAL_ERROR );
+ __ndi_flush_que( h_cq, (PIO_CSQ)&h_cq->error, STATUS_INTERNAL_ERROR );
+ AL_EXIT( AL_DBG_NDI );
+}
+
+/*******************************************************************
+ *
+ * Public routines
+ *
+ ******************************************************************/
+
+/* flush a queue of pending requests */
+void
+proxy_ndi_flush_ques(
+ IN ib_cq_handle_t h_cq
+ )
+{
+ AL_ENTER( AL_DBG_NDI );
+ if ( h_cq->pfn_user_comp_cb == __ndi_cq_compl_cb )
+ {
+ __ndi_flush_que( h_cq, (PIO_CSQ)&h_cq->compl, STATUS_CANCELLED );
+ __ndi_flush_que( h_cq, (PIO_CSQ)&h_cq->error, STATUS_CANCELLED );
+ }
+ AL_EXIT( AL_DBG_NDI );
+}
+
+
+/*******************************************************************
+ *
+ * CSQ
+ *
+ ******************************************************************/
+
+static VOID __ndi_insert_irp(
+ IN PIO_CSQ Csq,
+ IN PIRP Irp
+ )
+{
+ ndi_io_csq_t *p_ndi_csq = (ndi_io_csq_t*)Csq;
+
+ AL_ENTER( AL_DBG_NDI );
+ InsertTailList( &p_ndi_csq->que, &Irp->Tail.Overlay.ListEntry );
+ AL_EXIT( AL_DBG_NDI );
+}
+
+static VOID __ndi_remove_irp(
+ IN PIO_CSQ Csq,
+ IN PIRP Irp
+ )
+{
+ UNUSED_PARAM( Csq );
+
+ AL_ENTER( AL_DBG_NDI );
+ RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
+ AL_EXIT( AL_DBG_NDI );
+}
+
+static PIRP __ndi_peek_next_irp(
+ IN PIO_CSQ Csq,
+ IN PIRP Irp,
+ IN PVOID PeekContext
+ )
+{
+ PIRP nextIrp = NULL;
+ PLIST_ENTRY nextEntry;
+ PLIST_ENTRY listHead;
+ ndi_io_csq_t *p_ndi_csq = (ndi_io_csq_t*)Csq;
+
+ AL_ENTER( AL_DBG_NDI );
+
+ listHead = &p_ndi_csq->que;
+
+ //
+ // If the IRP is NULL, we will start peeking from the listhead, else
+ // we will start from that IRP onwards. This is done under the
+ // assumption that new IRPs are always inserted at the tail.
+ //
+
+ if(Irp == NULL)
+ nextEntry = listHead->Flink;
+ else
+ nextEntry = Irp->Tail.Overlay.ListEntry.Flink;
+
+ while(nextEntry != listHead) {
+ nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry);
+
+ //
+ // If context is present, continue until you find a matching one.
+ // Else you break out as you got next one.
+ //
+
+ if(PeekContext)
+ {
+ /* for now PeekContext is not used */
+ }
+ else
+ break;
+
+ nextIrp = NULL;
+ nextEntry = nextEntry->Flink;
+ }
+
+ AL_EXIT( AL_DBG_NDI );
+ return nextIrp;
+}
+
+static VOID __ndi_acquire_lock(
+ IN PIO_CSQ Csq,
+ OUT PKIRQL Irql
+ )
+{
+ ndi_io_csq_t *p_ndi_csq = (ndi_io_csq_t*)Csq;
+ ib_cq_handle_t h_cq = p_ndi_csq->h_cq;
+ UNUSED_PARAM( Irql );
+
+ AL_ENTER( AL_DBG_NDI );
+ cl_spinlock_acquire( &h_cq->obj.lock );
+ AL_EXIT( AL_DBG_NDI );
+}
+
+static VOID __ndi_release_lock(
+ IN PIO_CSQ Csq,
+ IN KIRQL Irql
+ )
+{
+ ndi_io_csq_t *p_ndi_csq = (ndi_io_csq_t*)Csq;
+ ib_cq_handle_t h_cq = p_ndi_csq->h_cq;
+ UNUSED_PARAM( Irql );
+
+ AL_ENTER( AL_DBG_NDI );
+ cl_spinlock_release( &h_cq->obj.lock );
+ AL_EXIT( AL_DBG_NDI );
+}
+
+static VOID __ndi_complete_cancelled_irp(
+ IN PIO_CSQ Csq,
+ IN PIRP Irp
+ )
+{
+ ndi_io_csq_t *p_ndi_csq = (ndi_io_csq_t*)Csq;
+ ib_cq_handle_t h_cq = p_ndi_csq->h_cq;
+
+ AL_ENTER( AL_DBG_NDI );
+ cl_ioctl_complete( Irp, CL_CANCELED, 0 );
+ deref_al_obj( &h_cq->obj );
+ AL_EXIT( AL_DBG_NDI );
+}
+
+static NTSTATUS
+__ndi_init(
+ IN ib_cq_handle_t h_cq )
+{
+
+ NTSTATUS status;
+
+ AL_ENTER( AL_DBG_NDI );
+
+ status = IoCsqInitialize( (PIO_CSQ)&h_cq->compl,
+ __ndi_insert_irp, __ndi_remove_irp,
+ __ndi_peek_next_irp, __ndi_acquire_lock,
+ __ndi_release_lock, __ndi_complete_cancelled_irp );
+ if ( !NT_SUCCESS( status ) )
+ goto exit;
+
+ status = IoCsqInitialize( (PIO_CSQ)&h_cq->error,
+ __ndi_insert_irp, __ndi_remove_irp,
+ __ndi_peek_next_irp, __ndi_acquire_lock,
+ __ndi_release_lock, __ndi_complete_cancelled_irp );
+ if ( !NT_SUCCESS( status ) )
+ goto exit;
+
+ InitializeListHead( &h_cq->compl.que );
+ InitializeListHead( &h_cq->error.que );
+ h_cq->compl.h_cq = h_cq;
+ h_cq->error.h_cq = h_cq;
+ status = STATUS_SUCCESS;
+
+exit:
+ AL_EXIT( AL_DBG_NDI );
+ return status;
+}
+
+
+/*******************************************************************
+ *
+ * IOCTLS
+ *
+ ******************************************************************/
+
+/*
+ * Process the ioctl UAL_CREATE_CQ:
+ */
+static cl_status_t
+__ndi_create_cq(
+ IN void *p_open_context,
+ IN cl_ioctl_handle_t h_ioctl,
+ OUT size_t *p_ret_bytes )
+{
+ ual_create_cq_ioctl_t *p_ioctl =
+ (ual_create_cq_ioctl_t *)cl_ioctl_in_buf( h_ioctl );
+ al_dev_open_context_t *p_context =
+ (al_dev_open_context_t *)p_open_context;
+ ib_ca_handle_t h_ca;
+ ib_cq_handle_t h_cq;
+ ib_cq_create_t cq_create;
+ ci_umv_buf_t *p_umv_buf = NULL;
+ ib_api_status_t status;
+ ib_pfn_event_cb_t pfn_ev;
+
+ AL_ENTER( AL_DBG_CQ );
+
+ /* Validate input buffers. */
+ if( !cl_ioctl_in_buf( h_ioctl ) || !cl_ioctl_out_buf( h_ioctl ) ||
+ cl_ioctl_in_size( h_ioctl ) != sizeof(p_ioctl->in) ||
+ cl_ioctl_out_size( h_ioctl ) != sizeof(p_ioctl->out) )
+ {
+ AL_EXIT( AL_DBG_CQ );
+ return CL_INVALID_PARAMETER;
+ }
+
+ /* Validate CA handle */
+ h_ca = (ib_ca_handle_t)
+ al_hdl_ref( p_context->h_al, p_ioctl->in.h_ca, AL_OBJ_TYPE_H_CA );
+ if( !h_ca )
+ {
+ status = IB_INVALID_CA_HANDLE;
+ goto proxy_create_cq_err1;
+ }
+
+ cq_create.size = p_ioctl->in.size;
+
+ /* Override with proxy's cq callback */
+ cq_create.pfn_comp_cb = __ndi_cq_compl_cb;
+ cq_create.h_wait_obj = NULL;
+ pfn_ev = __ndi_cq_error_cb;
+
+ status = cpyin_umvbuf( &p_ioctl->in.umv_buf, &p_umv_buf );
+ if( status != IB_SUCCESS )
+ goto proxy_create_cq_err2;
+
+ status = create_cq( h_ca, &cq_create, p_ioctl->in.context,
+ pfn_ev, &h_cq, p_umv_buf );
+
+ if( status != IB_SUCCESS )
+ goto proxy_create_cq_err2;
+
+ if( !NT_SUCCESS( __ndi_init( h_cq ) ) )
+ {
+ status = IB_ERROR;
+ goto proxy_create_cq_err3;
+ }
+
+ status = cpyout_umvbuf( &p_ioctl->out.umv_buf, p_umv_buf );
+ if( status == IB_SUCCESS )
+ {
+ p_ioctl->out.size = cq_create.size;
+ p_ioctl->out.h_cq = h_cq->obj.hdl;
+ h_cq->obj.hdl_valid = TRUE;
+ deref_al_obj( &h_cq->obj );
+ }
+ else
+ {
+proxy_create_cq_err3:
+ h_cq->obj.pfn_destroy( &h_cq->obj, NULL );
+
+proxy_create_cq_err2:
+ if( cq_create.h_wait_obj )
+ cl_waitobj_deref( cq_create.h_wait_obj );
+
+proxy_create_cq_err1:
+ p_ioctl->out.umv_buf = p_ioctl->in.umv_buf;
+ p_ioctl->out.h_cq = AL_INVALID_HANDLE;
+ p_ioctl->out.size = 0;
+ }
+ free_umvbuf( p_umv_buf );
+
+ if( h_ca )
+ deref_al_obj( &h_ca->obj );
+
+ p_ioctl->out.status = status;
+ *p_ret_bytes = sizeof(p_ioctl->out);
+
+ AL_EXIT( AL_DBG_CQ );
+ return CL_SUCCESS;
+}
+
+
+static cl_status_t
+__ndi_notify_cq(
+ IN void *p_open_context,
+ IN cl_ioctl_handle_t h_ioctl,
+ OUT size_t *p_ret_bytes )
+{
+ cl_status_t cl_status;
+ ual_ndi_notify_cq_ioctl_cmd_in_t *p_ioctl;
+ al_dev_open_context_t *p_context;
+ ib_cq_handle_t h_cq;
+
+ AL_ENTER( AL_DBG_NDI );
+
+ p_context = (al_dev_open_context_t*)p_open_context;
+ p_ioctl = (ual_ndi_notify_cq_ioctl_cmd_in_t*)cl_ioctl_in_buf( h_ioctl );
+
+ /* Validate user parameters. */
+ if( cl_ioctl_in_size( h_ioctl ) != sizeof(ual_ndi_notify_cq_ioctl_cmd_in_t) )
+ {
+ cl_status = CL_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ /* Validate CQ handle */
+ h_cq = (ib_cq_handle_t)
+ al_hdl_ref( p_context->h_al, p_ioctl->h_cq, AL_OBJ_TYPE_H_CQ );
+ if( !h_cq )
+ {
+ cl_status = CL_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ /* Validate notification type */
+ if ( (unsigned)p_ioctl->notify_type >= (unsigned)NdCqNotifyCount)
+ {
+ cl_status = CL_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ /* enqueue the IRP */
+ ref_al_obj( &h_cq->obj );
+ if (p_ioctl->notify_type == NdCqNotifyErrors)
+ IoCsqInsertIrp( (PIO_CSQ)&h_cq->error, h_ioctl, NULL );
+ else
+ IoCsqInsertIrp( (PIO_CSQ)&h_cq->compl, h_ioctl, NULL );
+
+ *p_ret_bytes = 0;
+ cl_status = CL_PENDING;
+
+exit:
+ AL_EXIT( AL_DBG_NDI );
+ return cl_status;
+}
+
+static cl_status_t
+__ndi_cancel_cq(
+ IN void *p_open_context,
+ IN cl_ioctl_handle_t h_ioctl,
+ OUT size_t *p_ret_bytes )
+{
+ cl_status_t cl_status;
+ ib_cq_handle_t h_cq;
+ al_dev_open_context_t *p_context;
+
+ AL_ENTER( AL_DBG_NDI );
+
+ p_context = (al_dev_open_context_t*)p_open_context;
+
+ /* Validate user parameters. */
+ if( cl_ioctl_in_size( h_ioctl ) != sizeof(uint64_t) )
+ {
+ cl_status = CL_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ /* Validate CQ handle */
+ h_cq = (ib_cq_handle_t)
+ al_hdl_ref( p_context->h_al,
+ *(uint64_t*)cl_ioctl_in_buf( h_ioctl ), AL_OBJ_TYPE_H_CQ );
+ if( !h_cq )
+ {
+ cl_status = CL_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ /* flush IRP queues */
+ proxy_ndi_flush_ques( h_cq );
+
+ *p_ret_bytes = 0;
+ cl_status = CL_SUCCESS;
+
+exit:
+ AL_EXIT( AL_DBG_NDI );
+ return cl_status;
+}
+
+cl_status_t
+ndi_ioctl(
+ IN cl_ioctl_handle_t h_ioctl,
+ OUT size_t *p_ret_bytes )
+{
+ cl_status_t cl_status;
+ IO_STACK_LOCATION *p_io_stack;
+ void *p_context;
+
+ AL_ENTER( AL_DBG_NDI );
+
+ p_io_stack = IoGetCurrentIrpStackLocation( h_ioctl );
+ p_context = p_io_stack->FileObject->FsContext;
+
+ if( !p_context )
+ {
+ AL_EXIT( AL_DBG_DEV );
+ return CL_INVALID_PARAMETER;
+ }
+
+ switch( cl_ioctl_ctl_code( h_ioctl ) )
+ {
+ case UAL_NDI_CREATE_CQ:
+ cl_status = __ndi_create_cq( p_context, h_ioctl, p_ret_bytes );
+ break;
+ case UAL_NDI_NOTIFY_CQ:
+ cl_status = __ndi_notify_cq( p_context, h_ioctl, p_ret_bytes );
+ break;
+ case UAL_NDI_CANCEL_CQ:
+ cl_status = __ndi_cancel_cq( p_context, h_ioctl, p_ret_bytes );
+ break;
+ default:
+ cl_status = CL_INVALID_PARAMETER;
+ break;
+ }
+
+ AL_EXIT( AL_DBG_NDI );
+ return cl_status;
+}
+