/*++ 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 */