You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
981 lines
28 KiB
981 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
Copyright (c) 1991 Nokia Data Systems AB
|
|
|
|
Module Name:
|
|
|
|
dlcque.c
|
|
|
|
Abstract:
|
|
|
|
This module provides primitives to manage the dlc command and
|
|
event queues.
|
|
|
|
Contents:
|
|
QueueDlcEvent
|
|
MakeDlcEvent
|
|
IsCommandOnList
|
|
SearchAndRemoveCommand
|
|
SearchAndRemoveAnyCommand
|
|
SearchAndRemoveCommandByHandle
|
|
SearchAndRemoveSpecificCommand
|
|
QueueDlcCommand
|
|
AbortCommand
|
|
CancelDlcCommand
|
|
PurgeDlcEventQueue
|
|
PurgeDlcFlowControlQueue
|
|
|
|
Author:
|
|
|
|
Antti Saarenheimo 29-Aug-1991
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <dlc.h>
|
|
#include "dlcdebug.h"
|
|
|
|
/*++
|
|
|
|
Design notes about the DLC event and command queue management
|
|
-------------------------------------------------------------
|
|
|
|
In DLC API the READ command may be given before or after the actual
|
|
event has happened. This means, that all DLC events of the READ command
|
|
must be queued and also the READ command must be queued to wait for
|
|
the set of events it was designated.
|
|
|
|
For each new DLC (READ) command the driver searches first the event queue
|
|
and then queues the command, if the desired event was not found.
|
|
The same thing is made also for the events: the dlc command queue
|
|
is checked first and then the event is queued (if it was a read event)
|
|
or it is dropped away (if the event was not meant for READ and there
|
|
was no command waiting for it).
|
|
|
|
The events are implemented by the event masks. The event is executed
|
|
if the result of bit-OR operation for the event masks in the command
|
|
and in the event is not zero.
|
|
|
|
All commands and receive events of a dlc station (direct, sap or link)
|
|
are returned as a DLC completion event when the station is closed.
|
|
The same operation is done also by the total reset or all sap stations
|
|
(and the only direct station).
|
|
A READ command may be used to read that command completion from
|
|
the event list. The READ command may have been give before, in the
|
|
same time linked to the next CCB field of the close/reset command or
|
|
after the close/reset command has completed.
|
|
DirOpenAdapter command deletes all events (and commands) from the
|
|
event queue. The received data and CCBs are not returned back, if
|
|
there is not given any READ command for that purpose.
|
|
|
|
(This has been fixed:
|
|
There could be a minor incompatibility with IBM OS/2 DLC API,
|
|
the NT DLC driver may not always complete a dlc command with
|
|
the READ command linked to commmand's CCB, if there is another
|
|
matching DLC command pending)
|
|
|
|
Here is the solution:
|
|
|
|
Actually we could make a special
|
|
READ command, that is chained to the very end of the command queue
|
|
and that can be matched only with a CCB pointer of the completed
|
|
DLC command. We could modify the command aborting to support also
|
|
this case, and there should be a special CCB input field in the
|
|
NT READ for the completed command (do we also need to return
|
|
the READ flag or command completion flag?).
|
|
|
|
----
|
|
|
|
We need at least these procedures:
|
|
|
|
MakeDlcEvent(
|
|
pFileContext, Event, StationId, pOwnerObject, pEventInformation, SecInfo);
|
|
|
|
- scans the command queues
|
|
- saves the event if it can't find a matching command and
|
|
if the command's event masks defines, that the event should be saved
|
|
|
|
QueueDlcCommand(
|
|
pFileContext, Event, StationId, StationIdMask, pIrp, AbortHandle, pfComp );
|
|
- scans the event queue for a matching event
|
|
- saves the event if can't find a match
|
|
|
|
AbortCommand(
|
|
pFileContext, Event, StationId, StationIdMask, AbortHandle, ppCcbLink );
|
|
- aborts a command in the command queue
|
|
|
|
****** Subprocedures (used by the api functions)
|
|
|
|
PDLC_COMMAND
|
|
SearchPrevCommand(
|
|
pQueue, EventMask, StationId, StationIdMask, SearchHandle, pPrevCommand
|
|
- returns pointer to the previous element before the matching
|
|
dlc command in a queue,
|
|
|
|
(Macro: SearchPrevEvent
|
|
- searches and removes the given event from the event queue and
|
|
returns its pointer)
|
|
--*/
|
|
|
|
|
|
VOID
|
|
QueueDlcEvent(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PDLC_PACKET pPacket
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine tries first to find a matching event in the command
|
|
queues and queues the DLC event if it can't find anything and if
|
|
the event belongs to the mask of the queued commands.
|
|
There are two event queues, both having a mask for the checked
|
|
events. The queue is checked only if the event bits are found
|
|
in the mask of the queue.
|
|
|
|
Arguments:
|
|
|
|
pFileContext - process specific adapter context
|
|
pPacket - Event packet
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_COMMAND pDlcCommand;
|
|
|
|
DIAG_FUNCTION("QueueDlcEvent");
|
|
|
|
//
|
|
// get search mask
|
|
//
|
|
|
|
pPacket->Event.Overlay.StationIdMask = (USHORT)((pPacket->Event.StationId == -1) ? 0 : -1);
|
|
|
|
//
|
|
// DLC commands can be completed with a special READ command,
|
|
// that is linked to the CCB pointer of the command.
|
|
// NT DLC must queue that special read command before the
|
|
// command that it was linked. We must check here
|
|
// if there is a special READ command just for this command
|
|
// completion.
|
|
// ************** HACK-HACK-HACK **************
|
|
// Close/Reset command completions use different
|
|
// EventInformation from the other command completions
|
|
// and they search the read command by themself =>
|
|
// we don't need to care about it.
|
|
// If SeconadryInfo == 0
|
|
// then this is a Close/Reset command completion
|
|
// and we don't search the special read command.
|
|
//
|
|
// ************** HACK-HACK-HACK **************
|
|
//
|
|
|
|
if (!IsListEmpty(&pFileContext->CommandQueue)) {
|
|
|
|
pDlcCommand = NULL;
|
|
|
|
if (pPacket->Event.Event == DLC_COMMAND_COMPLETION
|
|
&& pPacket->Event.SecondaryInfo != 0) {
|
|
|
|
pDlcCommand = SearchAndRemoveCommandByHandle(
|
|
&pFileContext->CommandQueue,
|
|
(ULONG)-1, // mask for all events
|
|
(USHORT)DLC_IGNORE_STATION_ID,
|
|
(USHORT)DLC_STATION_MASK_SPECIFIC,
|
|
pPacket->Event.pEventInformation
|
|
);
|
|
}
|
|
|
|
if (pDlcCommand == NULL) {
|
|
pDlcCommand = SearchAndRemoveCommand(&pFileContext->CommandQueue,
|
|
pPacket->Event.Event,
|
|
pPacket->Event.StationId,
|
|
pPacket->Event.Overlay.StationIdMask
|
|
);
|
|
}
|
|
|
|
if (pDlcCommand != NULL) {
|
|
|
|
BOOLEAN DeallocateEvent;
|
|
|
|
DeallocateEvent = pDlcCommand->Overlay.pfCompletionHandler(
|
|
pFileContext,
|
|
pPacket->Event.pOwnerObject,
|
|
pDlcCommand->pIrp,
|
|
(UINT)pPacket->Event.Event,
|
|
pPacket->Event.pEventInformation,
|
|
pPacket->Event.SecondaryInfo
|
|
);
|
|
|
|
if (DeallocateEvent) {
|
|
|
|
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pPacket);
|
|
|
|
}
|
|
|
|
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pDlcCommand);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// queue this event packet if it is to be picked up by a READ
|
|
//
|
|
|
|
if (pPacket->Event.Event & DLC_READ_FLAGS) {
|
|
LlcInsertTailList(&pFileContext->EventQueue, pPacket);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MakeDlcEvent(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN ULONG Event,
|
|
IN USHORT StationId,
|
|
IN PDLC_OBJECT pDlcObject,
|
|
IN PVOID pEventInformation,
|
|
IN ULONG SecondaryInfo,
|
|
IN BOOLEAN FreeEventInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine allocates a event packet, saves the event information
|
|
into it and queues (or completes) the event packet.
|
|
|
|
Arguments:
|
|
|
|
pFileContext - process specific adapter context
|
|
Event - event code
|
|
StationId - station id the event is destined
|
|
pDlcObject - the optional dlc object used in the event completion
|
|
pEventInformation - generic event information
|
|
SecondaryInfo - optional misc. data
|
|
FreeEventInfo - TRUE if pEventInformation should be deallocated
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
STATUS_SUCCESS
|
|
DLC_STATUS_NO_MEMORY
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_EVENT pDlcEvent;
|
|
|
|
DIAG_FUNCTION("MakeDlcEvent");
|
|
|
|
//
|
|
// We couldn't find any matching commands for this event and
|
|
// this event is a queued event => allocate a packet and
|
|
// queue the event.
|
|
//
|
|
|
|
pDlcEvent = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
|
|
|
|
if (pDlcEvent == NULL) {
|
|
return DLC_STATUS_NO_MEMORY;
|
|
}
|
|
pDlcEvent->Event = Event;
|
|
pDlcEvent->StationId = StationId;
|
|
pDlcEvent->pOwnerObject = pDlcObject;
|
|
pDlcEvent->SecondaryInfo = SecondaryInfo;
|
|
pDlcEvent->pEventInformation = pEventInformation;
|
|
pDlcEvent->bFreeEventInfo = FreeEventInfo;
|
|
QueueDlcEvent(pFileContext, (PDLC_PACKET)pDlcEvent);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
PDLC_COMMAND
|
|
IsCommandOnList(
|
|
IN PVOID RequestHandle,
|
|
IN PLIST_ENTRY List
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches the command queue of a DLC file context for a 'request handle'
|
|
which is the address (in user space) of a command CCB, such as a READ
|
|
|
|
If RequestHandle is located, a pointer to the DLC_COMMAND containing
|
|
it is returned, else NULL
|
|
|
|
Note: Assumes that handles are not shared between processes (it looks
|
|
as though the entire driver assumes this) and this function is called
|
|
within the context of the process to which the searched handle belongs
|
|
|
|
Arguments:
|
|
|
|
RequestHandle - address of CCB to look for
|
|
List - address of a list of DLC_COMMAND structures
|
|
|
|
Return Value:
|
|
|
|
PDLC_COMMAND
|
|
Success - address of located DLC_COMMAND structure containing
|
|
RequestHandle (in AbortHandle field)
|
|
Failure - NULL
|
|
|
|
--*/
|
|
|
|
{
|
|
PLIST_ENTRY entry;
|
|
|
|
if (!IsListEmpty(List)) {
|
|
for (entry = List->Flink; entry != List; entry = entry->Flink) {
|
|
if (((PDLC_COMMAND)entry)->AbortHandle == RequestHandle) {
|
|
return (PDLC_COMMAND)entry;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PDLC_COMMAND
|
|
SearchAndRemoveCommand(
|
|
IN PLIST_ENTRY pQueueBase,
|
|
IN ULONG Event,
|
|
IN USHORT StationId,
|
|
IN USHORT StationIdMask
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine searches and removes the given command or event from
|
|
command, event or receive command queue.
|
|
The station id, its mask, event mask and search handle are used
|
|
to define the search.
|
|
|
|
Arguments:
|
|
|
|
pQueueBase - address of queue's base pointer
|
|
|
|
Event - event code
|
|
|
|
StationId - station id of this command
|
|
|
|
StationIdMask - station id mask for the event station id
|
|
|
|
pSearchHandle - additional search key, this is actually an
|
|
orginal user mode ccb pointer (vdm or Windows/Nt)
|
|
|
|
Return Value:
|
|
|
|
PDLC_COMMAND
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_COMMAND pCmd;
|
|
|
|
DIAG_FUNCTION("SearchAndRemoveCommand");
|
|
|
|
//
|
|
// Events and commands are both saved to entry lists and this
|
|
// procedure is used to search a macthing event for a command
|
|
// or vice verse. Commands has a masks, that may defines
|
|
// the search for a specific station id, all stations on a sap
|
|
// or all station ids.
|
|
// the newest element in the list and the next element is the oldest
|
|
// The commands are always scanned from the oldest to the newest.
|
|
//
|
|
|
|
if (!IsListEmpty(pQueueBase)) {
|
|
|
|
for (pCmd = (PDLC_COMMAND)pQueueBase->Flink;
|
|
pCmd != (PDLC_COMMAND)pQueueBase;
|
|
pCmd = (PDLC_COMMAND)pCmd->LlcPacket.pNext) {
|
|
|
|
if ((pCmd->Event & Event)
|
|
&& (pCmd->StationId & pCmd->StationIdMask & StationIdMask)
|
|
== (StationId & pCmd->StationIdMask & StationIdMask)) {
|
|
|
|
LlcRemoveEntryList(pCmd);
|
|
return pCmd;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PDLC_COMMAND
|
|
SearchAndRemoveAnyCommand(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN ULONG EventMask,
|
|
IN USHORT StationId,
|
|
IN USHORT StationIdMask,
|
|
IN PVOID pSearchHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine searches a dlc command from the normal read command queue
|
|
for events and the special receive command queue.
|
|
|
|
Arguments:
|
|
|
|
pQueueBase - address of queue's base pointer
|
|
|
|
Event - event code
|
|
|
|
StationId - station id of this command
|
|
|
|
StationIdMask - station id mask for the event station id
|
|
|
|
pSearchHandle - additional search key, this is actually an
|
|
orginal user mode ccb pointer (vdm or Windows/Nt)
|
|
|
|
Return Value:
|
|
|
|
PDLC_COMMAND
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_COMMAND pDlcCommand;
|
|
|
|
DIAG_FUNCTION("SearchAndRemoveAnyCommand");
|
|
|
|
pDlcCommand = SearchAndRemoveCommandByHandle(&pFileContext->CommandQueue,
|
|
EventMask,
|
|
StationId,
|
|
StationIdMask,
|
|
pSearchHandle
|
|
);
|
|
if (pDlcCommand == NULL) {
|
|
pDlcCommand = SearchAndRemoveCommandByHandle(&pFileContext->ReceiveQueue,
|
|
EventMask,
|
|
StationId,
|
|
StationIdMask,
|
|
pSearchHandle
|
|
);
|
|
}
|
|
return pDlcCommand;
|
|
}
|
|
|
|
|
|
PDLC_COMMAND
|
|
SearchAndRemoveCommandByHandle(
|
|
IN PLIST_ENTRY pQueueBase,
|
|
IN ULONG Event,
|
|
IN USHORT StationId,
|
|
IN USHORT StationIdMask,
|
|
IN PVOID pSearchHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine searches and removes the given command or event from
|
|
command, event or receive command queue using a search handle.
|
|
This search routine is tailored to find the commands belonging
|
|
only to the deleted object (this searches only the exact macthes).
|
|
The other search routine supports wild cards only for the read
|
|
commands and thus it cannot be used here. We just want to remove
|
|
only those commands, that read events from the deleted object but not
|
|
from elsewhere.
|
|
|
|
Arguments:
|
|
|
|
pQueueBase - address of queue's base pointer
|
|
Event - event code or mask for the searched events
|
|
StationId - station id of this command
|
|
StationIdMask - station id mask for the event station id
|
|
pSearchHandle - additional search key, this is actually an orginal user
|
|
mode ccb pointer (vdm or Windows/Nt)
|
|
|
|
Return Value:
|
|
|
|
PDLC_COMMAND
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_COMMAND pCmd;
|
|
|
|
DIAG_FUNCTION("SearchAndRemoveCommandByHandle");
|
|
|
|
if (!IsListEmpty(pQueueBase)) {
|
|
|
|
for (pCmd = (PDLC_COMMAND)pQueueBase->Flink;
|
|
pCmd != (PDLC_COMMAND)pQueueBase;
|
|
pCmd = (PDLC_COMMAND)pCmd->LlcPacket.pNext) {
|
|
|
|
//
|
|
// The event mask match always!
|
|
//
|
|
|
|
if ((pCmd->Event & Event)
|
|
&& (pSearchHandle == DLC_MATCH_ANY_COMMAND
|
|
|| pSearchHandle == pCmd->AbortHandle
|
|
|| (pCmd->StationId & StationIdMask) == (StationId & StationIdMask))) {
|
|
|
|
LlcRemoveEntryList(pCmd);
|
|
return pCmd;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PDLC_COMMAND
|
|
SearchAndRemoveSpecificCommand(
|
|
IN PLIST_ENTRY pQueueBase,
|
|
IN PVOID pSearchHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches for a DLC_COMMAND structure having a specific search handle (ie
|
|
abort handle or application CCB address). If found, removes the DLC_COMMAND
|
|
from the queue, else returns NULL
|
|
|
|
Arguments:
|
|
|
|
pQueueBase - address of queue's base pointer
|
|
pSearchHandle - additional search key, this is actually an orginal user
|
|
mode ccb pointer (vdm or Windows/Nt)
|
|
|
|
Return Value:
|
|
|
|
PDLC_COMMAND
|
|
|
|
--*/
|
|
|
|
{
|
|
DIAG_FUNCTION("SearchAndRemoveSpecificCommand");
|
|
|
|
if (!IsListEmpty(pQueueBase)) {
|
|
|
|
PDLC_COMMAND pCmd;
|
|
|
|
for (pCmd = (PDLC_COMMAND)pQueueBase->Flink;
|
|
pCmd != (PDLC_COMMAND)pQueueBase;
|
|
pCmd = (PDLC_COMMAND)pCmd->LlcPacket.pNext) {
|
|
|
|
//
|
|
// The event mask match always!
|
|
//
|
|
|
|
if (pSearchHandle == pCmd->AbortHandle) {
|
|
LlcRemoveEntryList(pCmd);
|
|
return pCmd;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
QueueDlcCommand(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN ULONG Event,
|
|
IN USHORT StationId,
|
|
IN USHORT StationIdMask,
|
|
IN PIRP pIrp,
|
|
IN PVOID AbortHandle,
|
|
IN PFCOMPLETION_HANDLER pfCompletionHandler
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine tries first to find a matching event in the event
|
|
queue and queues the DLC command if it can't find an event.
|
|
|
|
Arguments:
|
|
|
|
pFileContext - process specific adapter context
|
|
Event - event code
|
|
StationId - station id the event is destined
|
|
StationIdMask - mask used to define the destination station group
|
|
pIrp - the i/o request packet of the related DLC command,
|
|
link to the input and output parameters.
|
|
AbortHandle - handle used to cancel the command from the queue
|
|
pfCompletionHandler - completion handler of the command, called when a
|
|
matching event has been found.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_COMMAND pDlcCommand;
|
|
PDLC_EVENT pEvent;
|
|
|
|
DIAG_FUNCTION("QueueDlcCommand");
|
|
|
|
pEvent = SearchAndRemoveEvent(&pFileContext->EventQueue,
|
|
Event,
|
|
StationId,
|
|
StationIdMask
|
|
);
|
|
if (pEvent != NULL) {
|
|
|
|
BOOLEAN DeallocateEvent;
|
|
|
|
DeallocateEvent = pfCompletionHandler(pFileContext,
|
|
pEvent->pOwnerObject,
|
|
pIrp,
|
|
(UINT)pEvent->Event,
|
|
pEvent->pEventInformation,
|
|
pEvent->SecondaryInfo
|
|
);
|
|
if (DeallocateEvent) {
|
|
|
|
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pEvent);
|
|
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// We couldn't find any matching command for this event and
|
|
// this event is a queued event => allocate a packet and
|
|
// queue the event.
|
|
//
|
|
|
|
pDlcCommand = (PDLC_COMMAND)ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
|
|
|
|
if (pDlcCommand == NULL) {
|
|
return DLC_STATUS_NO_MEMORY;
|
|
}
|
|
pDlcCommand->Event = Event;
|
|
pDlcCommand->pIrp = pIrp;
|
|
pDlcCommand->StationId = StationId;
|
|
pDlcCommand->StationIdMask = StationIdMask;
|
|
pDlcCommand->AbortHandle = AbortHandle;
|
|
pDlcCommand->Overlay.pfCompletionHandler = pfCompletionHandler;
|
|
|
|
//
|
|
// The permanent receive commands, that do not actually read
|
|
// anuting (just enable the data receiving) are put to another
|
|
// queue to speed up the search of the read commands.
|
|
//
|
|
|
|
if (Event == LLC_RECEIVE_COMMAND_FLAG) {
|
|
LlcInsertTailList(&pFileContext->ReceiveQueue, pDlcCommand);
|
|
} else {
|
|
LlcInsertTailList(&pFileContext->CommandQueue, pDlcCommand);
|
|
}
|
|
|
|
//
|
|
// Asynchronous commands returns ALWAYS the pending status.
|
|
//
|
|
}
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AbortCommand(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN USHORT StationId,
|
|
IN USHORT StationIdMask,
|
|
IN PVOID AbortHandle,
|
|
IN OUT PVOID *ppCcbLink,
|
|
IN UINT CancelStatus,
|
|
IN BOOLEAN SuppressCommandCompletion
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine searches and cancels a command from a command queue.
|
|
The commands must always belong to the defined DLC object.
|
|
A NULL value in abort handle selects all matching commands
|
|
found in the queue.
|
|
|
|
Arguments:
|
|
|
|
pFileContext -
|
|
StationId - station id the searched command is destined for
|
|
StationIdMask - station id mask used in the search
|
|
AbortHandle - handle used to cancel the command from the
|
|
queue. The whole command queue will be scanned
|
|
if this handle is NULL
|
|
ppCcbLink - the canceled commands are linked by their next
|
|
CCB pointer fieldsr. The caller must provide
|
|
the next CCB address in this parameter
|
|
(usually *ppCcbLink == NULL) and the function
|
|
will return the address of the last cancelled
|
|
CCB field.
|
|
CancelStatus - Status for the command to be canceled
|
|
SuppressCommandCompletion - the flag is set, if the normal command
|
|
completion is suppressed.
|
|
|
|
Return Value:
|
|
|
|
- no mathing command was found
|
|
STATUS_SUCCESS - the command was canceled
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_COMMAND pDlcCommand;
|
|
|
|
DIAG_FUNCTION("AbortCommand");
|
|
|
|
pDlcCommand = SearchAndRemoveAnyCommand(pFileContext,
|
|
(ULONG)(-1), // search all commands
|
|
StationId,
|
|
StationIdMask,
|
|
AbortHandle
|
|
);
|
|
if (pDlcCommand == NULL && AbortHandle == DLC_MATCH_ANY_COMMAND) {
|
|
pDlcCommand = pFileContext->pTimerQueue;
|
|
if (pDlcCommand != NULL) {
|
|
pFileContext->pTimerQueue = (PDLC_COMMAND)pDlcCommand->LlcPacket.pNext;
|
|
}
|
|
}
|
|
if (pDlcCommand != NULL) {
|
|
CancelDlcCommand(pFileContext,
|
|
pDlcCommand,
|
|
ppCcbLink,
|
|
CancelStatus,
|
|
SuppressCommandCompletion
|
|
);
|
|
return STATUS_SUCCESS;
|
|
} else {
|
|
return DLC_STATUS_INVALID_CCB_POINTER;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CancelDlcCommand(
|
|
IN PDLC_FILE_CONTEXT pFileContext,
|
|
IN PDLC_COMMAND pDlcCommand,
|
|
IN OUT PVOID *ppCcbLink,
|
|
IN UINT CancelStatus,
|
|
IN BOOLEAN SuppressCommandCompletion
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The cancels and optionally completes the given DLC command. Called when one
|
|
DLC I/O request is used to kill another (e.g. READ.CANCEL, DIR.TIMER.CANCEL)
|
|
|
|
Arguments:
|
|
|
|
pFileContext -
|
|
pDlcCommand -
|
|
ppCcbLink - the canceled commands are linked by their next
|
|
CCB pointer fields. The caller must provide
|
|
the next CCB address in this parameter
|
|
(usually *ppCcbLink == NULL) and the function
|
|
will return the address of the last cancelled
|
|
CCB field
|
|
CancelStatus - Status for the command to be canceled
|
|
SuppressCommandCompletion - if set, normal command completion is suppressed
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PVOID pOldCcbLink;
|
|
|
|
DIAG_FUNCTION("CancelDlcCommand");
|
|
|
|
//
|
|
// We must return the current CCB link to be linked to the next cancelled
|
|
// CCB command (or to the CCB pointer of cancelling command). But first
|
|
// save the previous CCB link before we read a new one
|
|
//
|
|
|
|
pOldCcbLink = *ppCcbLink;
|
|
*ppCcbLink = ((PNT_DLC_PARMS)pDlcCommand->pIrp->AssociatedIrp.SystemBuffer)->Async.Ccb.pCcbAddress;
|
|
|
|
//
|
|
// Check if we must suppress any kind of command completion indications to
|
|
// the applications. I/O system should not care, if its event handle is
|
|
// removed
|
|
//
|
|
|
|
if (SuppressCommandCompletion) {
|
|
pDlcCommand->pIrp->UserEvent = NULL;
|
|
}
|
|
CompleteAsyncCommand(pFileContext, CancelStatus, pDlcCommand->pIrp, pOldCcbLink, FALSE);
|
|
|
|
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pDlcCommand);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
PurgeDlcEventQueue(
|
|
IN PDLC_FILE_CONTEXT pFileContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes all events from a FILE_CONTEXT event queue. Called when the
|
|
FILE_CONTEXT is being deleted and before we deallocate the packet pool from
|
|
which the events were allocated
|
|
|
|
Arguments:
|
|
|
|
pFileContext - pointer to FILE_CONTEXT owning the queue
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_EVENT p;
|
|
|
|
while (!IsListEmpty(&pFileContext->EventQueue)) {
|
|
p = (PDLC_EVENT)RemoveHeadList(&pFileContext->EventQueue);
|
|
if (p->bFreeEventInfo && p->pEventInformation) {
|
|
|
|
#if DBG
|
|
DbgPrint("PurgeDlcEventQueue: deallocating pEventInformation: %x\n", p->pEventInformation);
|
|
#endif
|
|
|
|
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, p->pEventInformation);
|
|
|
|
}
|
|
|
|
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, p);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
PurgeDlcFlowControlQueue(
|
|
IN PDLC_FILE_CONTEXT pFileContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes all packets from the flow control queue. Called when the FILE_CONTEXT
|
|
is being deleted and before we deallocate the packet pool from which flow
|
|
control packets were allocated
|
|
|
|
Arguments:
|
|
|
|
pFileContext - pointer to FILE_CONTEXT owning the queue
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDLC_RESET_LOCAL_BUSY_CMD p;
|
|
|
|
while (!IsListEmpty(&pFileContext->FlowControlQueue)) {
|
|
p = (PDLC_RESET_LOCAL_BUSY_CMD)RemoveHeadList(&pFileContext->FlowControlQueue);
|
|
|
|
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, p);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
//
|
|
// Internal consistency check to hunt a bougus event in the event queue.
|
|
//
|
|
//extern BOOLEAN EventCheckDisabled;
|
|
//
|
|
int
|
|
CheckEventQueue(
|
|
PDLC_FILE_CONTEXT pFileContext
|
|
)
|
|
{
|
|
static PDLC_FILE_CONTEXT pOldFileContext = NULL;
|
|
|
|
if (pFileContext == NULL)
|
|
{
|
|
pFileContext = pOldFileContext;
|
|
}
|
|
else
|
|
{
|
|
pOldFileContext = pFileContext;
|
|
}
|
|
if (pFileContext == NULL)
|
|
return 0;
|
|
|
|
if (!IsListEmpty( &pFileContext->EventQueue ) &&
|
|
pFileContext->EventQueue.Flink == pFileContext->EventQueue.Blink &&
|
|
&pFileContext->EventQueue != pFileContext->EventQueue.Flink->Flink)
|
|
{
|
|
FooDebugBreak();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
FooDebugBreak()
|
|
{
|
|
INT i;
|
|
|
|
return i++;
|
|
}
|
|
*/
|
|
// PDLC_EVENT pEvent;
|
|
//
|
|
// if (EventCheckDisabled || pFileContext->AdapterNumber != 0 ||
|
|
// pFileContext->EventQueue == NULL)
|
|
// return;
|
|
//
|
|
// pEvent = (PDLC_EVENT)pFileContext->pEventQueue->LlcPacket.pNext;
|
|
// for (;;)
|
|
// {
|
|
// if (pEvent->Event == LLC_STATUS_CHANGE &&
|
|
// pEvent->pOwnerObject == NULL)
|
|
// DebugBreak();
|
|
// if (pEvent == pFileContext->pEventQueue)
|
|
// break;
|
|
// pEvent = (PDLC_EVENT)pEvent->LlcPacket.pNext;
|
|
// }
|
|
//}
|
|
//
|