
/*++
 ****************************************************************************
 * Copyright (c) 1999-2002 Digi International Inc., All Rights Reserved
 *
 * This software contains proprietary and confidential information of Digi
 * International Inc.  By accepting transfer of this copy, Recipient agrees
 * to retain this software in confidence, to prevent disclosure to others,
 * and to make no use of this software other than that for which it was
 * delivered.  This is an unpublished copyrighted work of Digi International
 * Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 * prohibited.
 *
 * Restricted Rights Legend
 *
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 * Technical Data and Computer Software clause at DFARS 252.227-7031 or
 * subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 * Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 ****************************************************************************

Module Name:

   DxbQDump.c
   
--*/
#include "digidxb.h"
#include "dxbqdump.h"

STATIC VOID dxbInitQueueTrace(
    PDXB_DEVICE_EXTENSION   pExt,
    DXB_QUEUE_TYPE          DxbQType
)
{
    if ( DxbQType == DXB_CMD_QUEUE )
    {    
        pExt->Trace[DxbQType].pLock = &pExt->DxbCmdQ.Lock;
        pExt->Trace[DxbQType].cbTotal = pExt->DxbCmdQ.cbTotal;
        pExt->Trace[DxbQType].pQueue = &pExt->DxbCmdQ;
        
    }        
    else 
    {
        pExt->Trace[DxbQType].pLock = &pExt->DxbEventQ.Lock;                
        pExt->Trace[DxbQType].cbTotal = pExt->DxbEventQ.cbTotal;
        pExt->Trace[DxbQType].pQueue = &pExt->DxbEventQ;
    }
    pExt->Trace[DxbQType].fInit = TRUE;        
}   
 
STATIC 
ULONG QueueTrace(
    PDXB_DEVICE_EXTENSION   pExt,
    DXB_QUEUE_TYPE          DxbQType,
    PUCHAR                  pDest,
    ULONG                   cbBufSize,
    BOOLEAN                 fReStart,
    PULONG                  pDumpQOut,
    PULONG                  pDumpQIn
)
{
	ULONG                   DumpQOut;
	ULONG                   DumpQIn;
    ULONG                   cbData;
    
    if ( pExt->Trace[DxbQType].fInit == FALSE )
    {
        dxbInitQueueTrace( pExt, DxbQType );
        fReStart = TRUE;        
    }
    
    DigiAcquireSpinLock( pExt->Trace[DxbQType].pLock );
    if ( fReStart == TRUE )
    {
        // Trace all currently in queue.
        if ( DxbQType == DXB_CMD_QUEUE )
            dxbGetCmdQOffsets( pExt, &DumpQIn, &DumpQOut );
        else
            dxbGetEventQOffsets( pExt, &DumpQIn, &DumpQOut );                            
    }    
    else
    {
        // Trace from where we left off last time
        if ( DxbQType == DXB_CMD_QUEUE )
            DumpQIn = dxbGetCmdQIn( pExt );            
        else
            DumpQIn = dxbGetEventQIn( pExt );
        DumpQOut = pExt->Trace[DxbQType].TraceQOut;
    }                            
    cbData = MIN(dxbQueueCbData( DumpQIn, DumpQOut, pExt->Trace[DxbQType].cbTotal), cbBufSize );
    if ( cbData > 0 )
    {
        DigiDump( DIGIINIT, ("\nQueue trace cdData 0x%x DumpQOut 0x%x DumpQIn 0x%x\n", cbData,DumpQOut, DumpQIn));
        DumpQOut = dxbQueueReadBlock( pExt, pExt->Trace[DxbQType].pQueue, pDest, DumpQOut, cbData, TRUE, FALSE );    
        DigiDump( DIGIINIT, ("\nQueue trace cdData 0x%x DumpQOut 0x%x DumpQIn 0x%x\n", cbData,DumpQOut, DumpQIn));
    }        
    pExt->Trace[DxbQType].TraceQOut = DumpQOut;
    *pDumpQOut = DumpQOut;
    *pDumpQIn  = DumpQIn;            
    DigiReleaseSpinLock( pExt->Trace[DxbQType].pLock );
    return cbData;    
}    

#ifdef NOT_USED
ULONG DxbQueueDump(
    PDXB_DEVICE_EXTENSION   pExt,
    DXB_QUEUE_TYPE          DxbQType,
    PUCHAR                  pDest,
    ULONG                   cbToRead
)    
{
    PDXB_MESSAGE_QUEUE      pQueue;
	ULONG                   DumpQOut;
	ULONG                   DumpQIn;
    ULONG                   cbData;
    PDIGI_SPINLOCK          pLock;
    ULONG                   cbRead;
    
    if ( DxbQType == DXB_CMD_QUEUE )
    {
    	DigiAcquireSpinLock( &pExt->DxbCmdQ.Lock );
        pLock = &pExt->DxbCmdQ.Lock;
        pQueue = &pExt->DxbCmdQ;
        dxbGetCmdQOffsets( pExt, &DumpQIn, &DumpQOut );  
        cbData = dxbQueueCbData( DumpQIn, DumpQOut, pExt->DxbCmdQ.cbTotal );
    }
    else
    {
        ASSERT( DxbQType == DXB_EVENT_QUEUE );
    	DigiAcquireSpinLock( &pExt->DxbEventQ.Lock );
        pLock = &pExt->DxbEventQ.Lock;        
        pQueue = &pExt->DxbEventQ;
        dxbGetEventQOffsets( pExt, &DumpQIn, &DumpQOut );            
        cbData = dxbQueueCbData( DumpQIn, DumpQOut, pExt->DxbEventQ.cbTotal );
    }
    if ( cbData > cbToRead )
    {
        // Can't dump all the data currently in the queue...
        //  Just dump the last bytes in the queue that will fit in the dump buffer.
        DumpQIn += ( cbData - cbToRead );
        dxbQueueNormalize( pQueue, DumpQIn );            
        cbData = cbToRead;
    }
    if ( cbData > 0 )
        dxbQueueReadBlock( pExt, pQueue, pDest, DumpQOut, cbData, TRUE, FALSE );    
    DigiReleaseSpinLock( pLock );
    return cbData;
}
#endif

NTSTATUS
DxbQueueTrace(
	PDXB_DEVICE_EXTENSION pExt, 
	PIRP                  pIrp )
/*++

Description:

	This routine processes a request to trace the contents of the Dxb message queues.

Arguments:

	pExt
		The device extension identifying the adapter

	pIrp
		The IRP containing the request

Return Value:

   STATUS_SUCCESS or fail status
   
--*/
{
	const PTRACE_HEADER pTrace = pIrp->AssociatedIrp.SystemBuffer;
    ULONG   InPtr = 0;
    ULONG   OutPtr = 0;
	NTSTATUS Status;
    if ( pTrace->QueueType >= DXB_QUEUE_TYPE_COUNT )
    {
        Status = STATUS_INVALID_PARAMETER;
        goto Exit;
    }

	// Don't do zero-length reads!
	if ( pTrace->Length == 0 )
	{
		Status = STATUS_INVALID_PARAMETER;
		goto Exit;
	}

	Status = DigiLockBuffer( pIrp, pTrace->pBuffer, pTrace->Length, &pTrace->pLockedBuffer );
	if ( NT_ERROR( Status ) )
		goto Exit;

    pTrace->BytesRead = QueueTrace( pExt, pTrace->QueueType, pTrace->pBuffer, pTrace->Length, FALSE, &OutPtr, &InPtr );
    KeQuerySystemTime(&pTrace->TimeStamp);
    pTrace->OutPtr = OutPtr;
    pTrace->InPtr = InPtr;
    
Exit:
	dxbIoCompleteRequest( pIrp, Status, NT_SUCCESS( Status ) ? sizeof *pTrace : 0 );
	return( Status );
}
