windows-nt/Source/XPSP1/NT/net/qos/psched/sys/clstate.c
2020-09-26 16:20:57 +08:00

331 lines
7.6 KiB
C

/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
clstate.c
Abstract:
state machine for gpc client vcs
Author:
Yoram Bernet (yoramb) 28-Dec-1997
Rajesh Sundaram (rajeshsu) 01-Aug-1998
Environment:
Kernel Mode
Revision History:
Rajesh Sundaram (rajeshsu) 04-Apr-1998 - reworked completly as another state
(CL_INTERNAL_CALL_COMPLETE) added.
--*/
#include "psched.h"
#pragma hdrstop
/* External */
/* Static */
/* Forward */
/* End Forward */
/*++
Routine Description:
Initiate a close call on this VC and notify the GPC. Always called with the VC lock held.
Return Value:
None
--*/
VOID
InternalCloseCall(
PGPC_CLIENT_VC Vc
)
{
PADAPTER Adapter = Vc->Adapter;
PsDbgOut(DBG_INFO,
DBG_STATE,
("[InternalCloseCall]: Adapter %08X, ClVcState is %s on VC %x\n",
Vc->Adapter, GpcVcState[Vc->ClVcState], Vc));
switch(Vc->ClVcState){
case CL_INTERNAL_CLOSE_PENDING:
//
// We could get here if we get an unbind at our wan instance with a
// NDIS_STATUS_WAN_LINE_DOWN. We could be trying to do an InternalClose
// from both places.
//
PsAssert(Vc->Flags & INTERNAL_CLOSE_REQUESTED);
PS_UNLOCK_DPC(&Vc->Lock);
PS_UNLOCK(&Adapter->Lock);
break;
case CL_CALL_PENDING:
case CL_MODIFY_PENDING:
//
// We've been asked to close before the call
// has completed.
//
// Set a flag so that we'll close it when the
// call completes.
//
PsAssert(!(Vc->Flags & GPC_CLOSE_REQUESTED));
Vc->Flags |= INTERNAL_CLOSE_REQUESTED;
PS_UNLOCK_DPC(&Vc->Lock);
PS_UNLOCK(&Adapter->Lock);
break;
case CL_INTERNAL_CALL_COMPLETE:
//
// The call has been completed, but we may or may not
// have told the GPC. Wait till we tell the GPC. We will
// complete this when we transistion to CL_CALL_COMPLETE
//
PsAssert(!IsBestEffortVc(Vc));
Vc->Flags |= INTERNAL_CLOSE_REQUESTED;
PS_UNLOCK_DPC(&Vc->Lock);
PS_UNLOCK(&Adapter->Lock);
break;
case CL_CALL_COMPLETE:
//
// Transition to CL_INTERNAL_CLOSE_PENDING and
// ask the GPC to close.
//
Vc->ClVcState = CL_INTERNAL_CLOSE_PENDING;
Vc->Flags |= INTERNAL_CLOSE_REQUESTED;
PS_UNLOCK_DPC(&Vc->Lock);
PS_UNLOCK(&Adapter->Lock);
CmCloseCall(Vc);
break;
case CL_GPC_CLOSE_PENDING:
//
// The GPC has already asked us to close. Now,
// we are also closing down - We need not do
// anything here - Need not even inform the GPC.
// we can just pretend as the InternalClose never
// happened
Vc->Flags &= ~INTERNAL_CLOSE_REQUESTED;
PS_UNLOCK_DPC(&Vc->Lock);
PS_UNLOCK(&Adapter->Lock);
break;
default:
PS_UNLOCK_DPC(&Vc->Lock);
PS_UNLOCK(&Adapter->Lock);
PsDbgOut(DBG_FAILURE,
DBG_STATE,
("[InternalCloseCall]: invalid state %s on VC %x\n",
GpcVcState[Vc->ClVcState], Vc));
PsAssert(0);
break;
}
}
VOID
CallSucceededStateTransition(
PGPC_CLIENT_VC Vc
)
{
PsDbgOut(DBG_INFO,
DBG_STATE,
("[CallSucceededStateTransition]: Adapter %08X, ClVcState is %s on VC %x\n",
Vc->Adapter, GpcVcState[Vc->ClVcState], Vc));
PS_LOCK(&Vc->Lock);
switch(Vc->ClVcState){
case CL_GPC_CLOSE_PENDING:
PS_UNLOCK(&Vc->Lock);
PsDbgOut(DBG_FAILURE,
DBG_STATE,
("[CallSucceededStateTransition]: bad state %s on VC %x\n",
GpcVcState[Vc->ClVcState], Vc));
PsAssert(0);
break;
case CL_INTERNAL_CALL_COMPLETE:
PsAssert(!IsBestEffortVc(Vc));
#if DBG
if(Vc->Flags & GPC_MODIFY_REQUESTED) {
PsAssert(! (Vc->Flags & GPC_CLOSE_REQUESTED));
}
if(Vc->Flags & GPC_CLOSE_REQUESTED) {
PsAssert(! (Vc->Flags & GPC_MODIFY_REQUESTED));
}
#endif
//
// Note that if both a modify & a internal remove is requested,
// we just satisfy the modify. When the modify goes into internal
// call complete, we will satify the remove
//
if(Vc->Flags & GPC_MODIFY_REQUESTED) {
NDIS_STATUS Status;
Vc->ClVcState = CL_MODIFY_PENDING;
Vc->Flags &= ~GPC_MODIFY_REQUESTED;
PS_UNLOCK(&Vc->Lock);
Status = CmModifyCall(Vc);
if(Status != NDIS_STATUS_PENDING) {
CmModifyCallComplete(Status, Vc, Vc->ModifyCallParameters);
}
break;
}
if(Vc->Flags & GPC_CLOSE_REQUESTED) {
//
// The GPC has asked us to close after it
// was notified of the call completion but
// before we managed to transition to the
// CL_CALL_COMPLETE state.
//
Vc->ClVcState = CL_GPC_CLOSE_PENDING;
PS_UNLOCK(&Vc->Lock);
CmCloseCall(Vc);
break;
}
if(Vc->Flags & INTERNAL_CLOSE_REQUESTED){
//
// We had an internal close request while
// the call was pending. The GPC has already
// been notified, so - we need to ask it to
// close.
//
Vc->ClVcState = CL_INTERNAL_CLOSE_PENDING;
PS_UNLOCK(&Vc->Lock);
CmCloseCall(Vc);
break;
}
Vc->ClVcState = CL_CALL_COMPLETE;
PS_UNLOCK(&Vc->Lock);
break;
case CL_MODIFY_PENDING:
//
// Typically, just transition to CL_CALL_COMPLETE
//
PsAssert(!(Vc->Flags & GPC_CLOSE_REQUESTED));
PsAssert(!(Vc->Flags & GPC_MODIFY_REQUESTED));
PsAssert(!IsBestEffortVc(Vc));
Vc->ClVcState = CL_INTERNAL_CALL_COMPLETE;
PS_UNLOCK(&Vc->Lock);
break;
case CL_CALL_PENDING:
//
// Typically, just transition to CL_INTERNAL_CALL_COMPLETE.
//
PsAssert(!(Vc->Flags & GPC_CLOSE_REQUESTED));
PsAssert(!(Vc->Flags & GPC_MODIFY_REQUESTED));
//
// Call succeeded. Leave it up.
//
if(IsBestEffortVc(Vc))
{
Vc->ClVcState = CL_CALL_COMPLETE;
}
else
{
Vc->ClVcState = CL_INTERNAL_CALL_COMPLETE;
}
PS_UNLOCK(&Vc->Lock);
break;
default:
PS_UNLOCK(&Vc->Lock);
PsDbgOut(DBG_FAILURE,
DBG_STATE,
("[CallSucceededStateTransition]: invalid state %s on VC %x\n",
GpcVcState[Vc->ClVcState], Vc));
PsAssert(0);
}
}
/* end clstate.c */