Source code of Windows XP (NT5)
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
27 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Copyright (c) 1991 Nokia Data Systems AB
  4. Module Name:
  5. dlcque.c
  6. Abstract:
  7. This module provides primitives to manage the dlc command and
  8. event queues.
  9. Contents:
  10. QueueDlcEvent
  11. MakeDlcEvent
  12. IsCommandOnList
  13. SearchAndRemoveCommand
  14. SearchAndRemoveAnyCommand
  15. SearchAndRemoveCommandByHandle
  16. SearchAndRemoveSpecificCommand
  17. QueueDlcCommand
  18. AbortCommand
  19. CancelDlcCommand
  20. PurgeDlcEventQueue
  21. PurgeDlcFlowControlQueue
  22. Author:
  23. Antti Saarenheimo 29-Aug-1991
  24. Environment:
  25. Kernel mode
  26. Revision History:
  27. --*/
  28. #include <dlc.h>
  29. #include "dlcdebug.h"
  30. /*++
  31. Design notes about the DLC event and command queue management
  32. -------------------------------------------------------------
  33. In DLC API the READ command may be given before or after the actual
  34. event has happened. This means, that all DLC events of the READ command
  35. must be queued and also the READ command must be queued to wait for
  36. the set of events it was designated.
  37. For each new DLC (READ) command the driver searches first the event queue
  38. and then queues the command, if the desired event was not found.
  39. The same thing is made also for the events: the dlc command queue
  40. is checked first and then the event is queued (if it was a read event)
  41. or it is dropped away (if the event was not meant for READ and there
  42. was no command waiting for it).
  43. The events are implemented by the event masks. The event is executed
  44. if the result of bit-OR operation for the event masks in the command
  45. and in the event is not zero.
  46. All commands and receive events of a dlc station (direct, sap or link)
  47. are returned as a DLC completion event when the station is closed.
  48. The same operation is done also by the total reset or all sap stations
  49. (and the only direct station).
  50. A READ command may be used to read that command completion from
  51. the event list. The READ command may have been give before, in the
  52. same time linked to the next CCB field of the close/reset command or
  53. after the close/reset command has completed.
  54. DirOpenAdapter command deletes all events (and commands) from the
  55. event queue. The received data and CCBs are not returned back, if
  56. there is not given any READ command for that purpose.
  57. (This has been fixed:
  58. There could be a minor incompatibility with IBM OS/2 DLC API,
  59. the NT DLC driver may not always complete a dlc command with
  60. the READ command linked to commmand's CCB, if there is another
  61. matching DLC command pending)
  62. Here is the solution:
  63. Actually we could make a special
  64. READ command, that is chained to the very end of the command queue
  65. and that can be matched only with a CCB pointer of the completed
  66. DLC command. We could modify the command aborting to support also
  67. this case, and there should be a special CCB input field in the
  68. NT READ for the completed command (do we also need to return
  69. the READ flag or command completion flag?).
  70. ----
  71. We need at least these procedures:
  72. MakeDlcEvent(
  73. pFileContext, Event, StationId, pOwnerObject, pEventInformation, SecInfo);
  74. - scans the command queues
  75. - saves the event if it can't find a matching command and
  76. if the command's event masks defines, that the event should be saved
  77. QueueDlcCommand(
  78. pFileContext, Event, StationId, StationIdMask, pIrp, AbortHandle, pfComp );
  79. - scans the event queue for a matching event
  80. - saves the event if can't find a match
  81. AbortCommand(
  82. pFileContext, Event, StationId, StationIdMask, AbortHandle, ppCcbLink );
  83. - aborts a command in the command queue
  84. ****** Subprocedures (used by the api functions)
  85. PDLC_COMMAND
  86. SearchPrevCommand(
  87. pQueue, EventMask, StationId, StationIdMask, SearchHandle, pPrevCommand
  88. - returns pointer to the previous element before the matching
  89. dlc command in a queue,
  90. (Macro: SearchPrevEvent
  91. - searches and removes the given event from the event queue and
  92. returns its pointer)
  93. --*/
  94. VOID
  95. QueueDlcEvent(
  96. IN PDLC_FILE_CONTEXT pFileContext,
  97. IN PDLC_PACKET pPacket
  98. )
  99. /*++
  100. Routine Description:
  101. The routine tries first to find a matching event in the command
  102. queues and queues the DLC event if it can't find anything and if
  103. the event belongs to the mask of the queued commands.
  104. There are two event queues, both having a mask for the checked
  105. events. The queue is checked only if the event bits are found
  106. in the mask of the queue.
  107. Arguments:
  108. pFileContext - process specific adapter context
  109. pPacket - Event packet
  110. Return Value:
  111. None
  112. --*/
  113. {
  114. PDLC_COMMAND pDlcCommand;
  115. DIAG_FUNCTION("QueueDlcEvent");
  116. //
  117. // get search mask
  118. //
  119. pPacket->Event.Overlay.StationIdMask = (USHORT)((pPacket->Event.StationId == -1) ? 0 : -1);
  120. //
  121. // DLC commands can be completed with a special READ command,
  122. // that is linked to the CCB pointer of the command.
  123. // NT DLC must queue that special read command before the
  124. // command that it was linked. We must check here
  125. // if there is a special READ command just for this command
  126. // completion.
  127. // ************** HACK-HACK-HACK **************
  128. // Close/Reset command completions use different
  129. // EventInformation from the other command completions
  130. // and they search the read command by themself =>
  131. // we don't need to care about it.
  132. // If SeconadryInfo == 0
  133. // then this is a Close/Reset command completion
  134. // and we don't search the special read command.
  135. //
  136. // ************** HACK-HACK-HACK **************
  137. //
  138. if (!IsListEmpty(&pFileContext->CommandQueue)) {
  139. pDlcCommand = NULL;
  140. if (pPacket->Event.Event == DLC_COMMAND_COMPLETION
  141. && pPacket->Event.SecondaryInfo != 0) {
  142. pDlcCommand = SearchAndRemoveCommandByHandle(
  143. &pFileContext->CommandQueue,
  144. (ULONG)-1, // mask for all events
  145. (USHORT)DLC_IGNORE_STATION_ID,
  146. (USHORT)DLC_STATION_MASK_SPECIFIC,
  147. pPacket->Event.pEventInformation
  148. );
  149. }
  150. if (pDlcCommand == NULL) {
  151. pDlcCommand = SearchAndRemoveCommand(&pFileContext->CommandQueue,
  152. pPacket->Event.Event,
  153. pPacket->Event.StationId,
  154. pPacket->Event.Overlay.StationIdMask
  155. );
  156. }
  157. if (pDlcCommand != NULL) {
  158. BOOLEAN DeallocateEvent;
  159. DeallocateEvent = pDlcCommand->Overlay.pfCompletionHandler(
  160. pFileContext,
  161. pPacket->Event.pOwnerObject,
  162. pDlcCommand->pIrp,
  163. (UINT)pPacket->Event.Event,
  164. pPacket->Event.pEventInformation,
  165. pPacket->Event.SecondaryInfo
  166. );
  167. if (DeallocateEvent) {
  168. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pPacket);
  169. }
  170. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pDlcCommand);
  171. return;
  172. }
  173. }
  174. //
  175. // queue this event packet if it is to be picked up by a READ
  176. //
  177. if (pPacket->Event.Event & DLC_READ_FLAGS) {
  178. LlcInsertTailList(&pFileContext->EventQueue, pPacket);
  179. }
  180. }
  181. NTSTATUS
  182. MakeDlcEvent(
  183. IN PDLC_FILE_CONTEXT pFileContext,
  184. IN ULONG Event,
  185. IN USHORT StationId,
  186. IN PDLC_OBJECT pDlcObject,
  187. IN PVOID pEventInformation,
  188. IN ULONG SecondaryInfo,
  189. IN BOOLEAN FreeEventInfo
  190. )
  191. /*++
  192. Routine Description:
  193. The routine allocates a event packet, saves the event information
  194. into it and queues (or completes) the event packet.
  195. Arguments:
  196. pFileContext - process specific adapter context
  197. Event - event code
  198. StationId - station id the event is destined
  199. pDlcObject - the optional dlc object used in the event completion
  200. pEventInformation - generic event information
  201. SecondaryInfo - optional misc. data
  202. FreeEventInfo - TRUE if pEventInformation should be deallocated
  203. Return Value:
  204. NTSTATUS:
  205. STATUS_SUCCESS
  206. DLC_STATUS_NO_MEMORY
  207. --*/
  208. {
  209. PDLC_EVENT pDlcEvent;
  210. DIAG_FUNCTION("MakeDlcEvent");
  211. //
  212. // We couldn't find any matching commands for this event and
  213. // this event is a queued event => allocate a packet and
  214. // queue the event.
  215. //
  216. pDlcEvent = ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  217. if (pDlcEvent == NULL) {
  218. return DLC_STATUS_NO_MEMORY;
  219. }
  220. pDlcEvent->Event = Event;
  221. pDlcEvent->StationId = StationId;
  222. pDlcEvent->pOwnerObject = pDlcObject;
  223. pDlcEvent->SecondaryInfo = SecondaryInfo;
  224. pDlcEvent->pEventInformation = pEventInformation;
  225. pDlcEvent->bFreeEventInfo = FreeEventInfo;
  226. QueueDlcEvent(pFileContext, (PDLC_PACKET)pDlcEvent);
  227. return STATUS_SUCCESS;
  228. }
  229. PDLC_COMMAND
  230. IsCommandOnList(
  231. IN PVOID RequestHandle,
  232. IN PLIST_ENTRY List
  233. )
  234. /*++
  235. Routine Description:
  236. Searches the command queue of a DLC file context for a 'request handle'
  237. which is the address (in user space) of a command CCB, such as a READ
  238. If RequestHandle is located, a pointer to the DLC_COMMAND containing
  239. it is returned, else NULL
  240. Note: Assumes that handles are not shared between processes (it looks
  241. as though the entire driver assumes this) and this function is called
  242. within the context of the process to which the searched handle belongs
  243. Arguments:
  244. RequestHandle - address of CCB to look for
  245. List - address of a list of DLC_COMMAND structures
  246. Return Value:
  247. PDLC_COMMAND
  248. Success - address of located DLC_COMMAND structure containing
  249. RequestHandle (in AbortHandle field)
  250. Failure - NULL
  251. --*/
  252. {
  253. PLIST_ENTRY entry;
  254. if (!IsListEmpty(List)) {
  255. for (entry = List->Flink; entry != List; entry = entry->Flink) {
  256. if (((PDLC_COMMAND)entry)->AbortHandle == RequestHandle) {
  257. return (PDLC_COMMAND)entry;
  258. }
  259. }
  260. }
  261. return NULL;
  262. }
  263. PDLC_COMMAND
  264. SearchAndRemoveCommand(
  265. IN PLIST_ENTRY pQueueBase,
  266. IN ULONG Event,
  267. IN USHORT StationId,
  268. IN USHORT StationIdMask
  269. )
  270. /*++
  271. Routine Description:
  272. The routine searches and removes the given command or event from
  273. command, event or receive command queue.
  274. The station id, its mask, event mask and search handle are used
  275. to define the search.
  276. Arguments:
  277. pQueueBase - address of queue's base pointer
  278. Event - event code
  279. StationId - station id of this command
  280. StationIdMask - station id mask for the event station id
  281. pSearchHandle - additional search key, this is actually an
  282. orginal user mode ccb pointer (vdm or Windows/Nt)
  283. Return Value:
  284. PDLC_COMMAND
  285. --*/
  286. {
  287. PDLC_COMMAND pCmd;
  288. DIAG_FUNCTION("SearchAndRemoveCommand");
  289. //
  290. // Events and commands are both saved to entry lists and this
  291. // procedure is used to search a macthing event for a command
  292. // or vice verse. Commands has a masks, that may defines
  293. // the search for a specific station id, all stations on a sap
  294. // or all station ids.
  295. // the newest element in the list and the next element is the oldest
  296. // The commands are always scanned from the oldest to the newest.
  297. //
  298. if (!IsListEmpty(pQueueBase)) {
  299. for (pCmd = (PDLC_COMMAND)pQueueBase->Flink;
  300. pCmd != (PDLC_COMMAND)pQueueBase;
  301. pCmd = (PDLC_COMMAND)pCmd->LlcPacket.pNext) {
  302. if ((pCmd->Event & Event)
  303. && (pCmd->StationId & pCmd->StationIdMask & StationIdMask)
  304. == (StationId & pCmd->StationIdMask & StationIdMask)) {
  305. LlcRemoveEntryList(pCmd);
  306. return pCmd;
  307. }
  308. }
  309. }
  310. return NULL;
  311. }
  312. PDLC_COMMAND
  313. SearchAndRemoveAnyCommand(
  314. IN PDLC_FILE_CONTEXT pFileContext,
  315. IN ULONG EventMask,
  316. IN USHORT StationId,
  317. IN USHORT StationIdMask,
  318. IN PVOID pSearchHandle
  319. )
  320. /*++
  321. Routine Description:
  322. The routine searches a dlc command from the normal read command queue
  323. for events and the special receive command queue.
  324. Arguments:
  325. pQueueBase - address of queue's base pointer
  326. Event - event code
  327. StationId - station id of this command
  328. StationIdMask - station id mask for the event station id
  329. pSearchHandle - additional search key, this is actually an
  330. orginal user mode ccb pointer (vdm or Windows/Nt)
  331. Return Value:
  332. PDLC_COMMAND
  333. --*/
  334. {
  335. PDLC_COMMAND pDlcCommand;
  336. DIAG_FUNCTION("SearchAndRemoveAnyCommand");
  337. pDlcCommand = SearchAndRemoveCommandByHandle(&pFileContext->CommandQueue,
  338. EventMask,
  339. StationId,
  340. StationIdMask,
  341. pSearchHandle
  342. );
  343. if (pDlcCommand == NULL) {
  344. pDlcCommand = SearchAndRemoveCommandByHandle(&pFileContext->ReceiveQueue,
  345. EventMask,
  346. StationId,
  347. StationIdMask,
  348. pSearchHandle
  349. );
  350. }
  351. return pDlcCommand;
  352. }
  353. PDLC_COMMAND
  354. SearchAndRemoveCommandByHandle(
  355. IN PLIST_ENTRY pQueueBase,
  356. IN ULONG Event,
  357. IN USHORT StationId,
  358. IN USHORT StationIdMask,
  359. IN PVOID pSearchHandle
  360. )
  361. /*++
  362. Routine Description:
  363. The routine searches and removes the given command or event from
  364. command, event or receive command queue using a search handle.
  365. This search routine is tailored to find the commands belonging
  366. only to the deleted object (this searches only the exact macthes).
  367. The other search routine supports wild cards only for the read
  368. commands and thus it cannot be used here. We just want to remove
  369. only those commands, that read events from the deleted object but not
  370. from elsewhere.
  371. Arguments:
  372. pQueueBase - address of queue's base pointer
  373. Event - event code or mask for the searched events
  374. StationId - station id of this command
  375. StationIdMask - station id mask for the event station id
  376. pSearchHandle - additional search key, this is actually an orginal user
  377. mode ccb pointer (vdm or Windows/Nt)
  378. Return Value:
  379. PDLC_COMMAND
  380. --*/
  381. {
  382. PDLC_COMMAND pCmd;
  383. DIAG_FUNCTION("SearchAndRemoveCommandByHandle");
  384. if (!IsListEmpty(pQueueBase)) {
  385. for (pCmd = (PDLC_COMMAND)pQueueBase->Flink;
  386. pCmd != (PDLC_COMMAND)pQueueBase;
  387. pCmd = (PDLC_COMMAND)pCmd->LlcPacket.pNext) {
  388. //
  389. // The event mask match always!
  390. //
  391. if ((pCmd->Event & Event)
  392. && (pSearchHandle == DLC_MATCH_ANY_COMMAND
  393. || pSearchHandle == pCmd->AbortHandle
  394. || (pCmd->StationId & StationIdMask) == (StationId & StationIdMask))) {
  395. LlcRemoveEntryList(pCmd);
  396. return pCmd;
  397. }
  398. }
  399. }
  400. return NULL;
  401. }
  402. PDLC_COMMAND
  403. SearchAndRemoveSpecificCommand(
  404. IN PLIST_ENTRY pQueueBase,
  405. IN PVOID pSearchHandle
  406. )
  407. /*++
  408. Routine Description:
  409. Searches for a DLC_COMMAND structure having a specific search handle (ie
  410. abort handle or application CCB address). If found, removes the DLC_COMMAND
  411. from the queue, else returns NULL
  412. Arguments:
  413. pQueueBase - address of queue's base pointer
  414. pSearchHandle - additional search key, this is actually an orginal user
  415. mode ccb pointer (vdm or Windows/Nt)
  416. Return Value:
  417. PDLC_COMMAND
  418. --*/
  419. {
  420. DIAG_FUNCTION("SearchAndRemoveSpecificCommand");
  421. if (!IsListEmpty(pQueueBase)) {
  422. PDLC_COMMAND pCmd;
  423. for (pCmd = (PDLC_COMMAND)pQueueBase->Flink;
  424. pCmd != (PDLC_COMMAND)pQueueBase;
  425. pCmd = (PDLC_COMMAND)pCmd->LlcPacket.pNext) {
  426. //
  427. // The event mask match always!
  428. //
  429. if (pSearchHandle == pCmd->AbortHandle) {
  430. LlcRemoveEntryList(pCmd);
  431. return pCmd;
  432. }
  433. }
  434. }
  435. return NULL;
  436. }
  437. NTSTATUS
  438. QueueDlcCommand(
  439. IN PDLC_FILE_CONTEXT pFileContext,
  440. IN ULONG Event,
  441. IN USHORT StationId,
  442. IN USHORT StationIdMask,
  443. IN PIRP pIrp,
  444. IN PVOID AbortHandle,
  445. IN PFCOMPLETION_HANDLER pfCompletionHandler
  446. )
  447. /*++
  448. Routine Description:
  449. The routine tries first to find a matching event in the event
  450. queue and queues the DLC command if it can't find an event.
  451. Arguments:
  452. pFileContext - process specific adapter context
  453. Event - event code
  454. StationId - station id the event is destined
  455. StationIdMask - mask used to define the destination station group
  456. pIrp - the i/o request packet of the related DLC command,
  457. link to the input and output parameters.
  458. AbortHandle - handle used to cancel the command from the queue
  459. pfCompletionHandler - completion handler of the command, called when a
  460. matching event has been found.
  461. Return Value:
  462. NTSTATUS
  463. --*/
  464. {
  465. PDLC_COMMAND pDlcCommand;
  466. PDLC_EVENT pEvent;
  467. DIAG_FUNCTION("QueueDlcCommand");
  468. pEvent = SearchAndRemoveEvent(&pFileContext->EventQueue,
  469. Event,
  470. StationId,
  471. StationIdMask
  472. );
  473. if (pEvent != NULL) {
  474. BOOLEAN DeallocateEvent;
  475. DeallocateEvent = pfCompletionHandler(pFileContext,
  476. pEvent->pOwnerObject,
  477. pIrp,
  478. (UINT)pEvent->Event,
  479. pEvent->pEventInformation,
  480. pEvent->SecondaryInfo
  481. );
  482. if (DeallocateEvent) {
  483. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pEvent);
  484. }
  485. } else {
  486. //
  487. // We couldn't find any matching command for this event and
  488. // this event is a queued event => allocate a packet and
  489. // queue the event.
  490. //
  491. pDlcCommand = (PDLC_COMMAND)ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
  492. if (pDlcCommand == NULL) {
  493. return DLC_STATUS_NO_MEMORY;
  494. }
  495. pDlcCommand->Event = Event;
  496. pDlcCommand->pIrp = pIrp;
  497. pDlcCommand->StationId = StationId;
  498. pDlcCommand->StationIdMask = StationIdMask;
  499. pDlcCommand->AbortHandle = AbortHandle;
  500. pDlcCommand->Overlay.pfCompletionHandler = pfCompletionHandler;
  501. //
  502. // The permanent receive commands, that do not actually read
  503. // anuting (just enable the data receiving) are put to another
  504. // queue to speed up the search of the read commands.
  505. //
  506. if (Event == LLC_RECEIVE_COMMAND_FLAG) {
  507. LlcInsertTailList(&pFileContext->ReceiveQueue, pDlcCommand);
  508. } else {
  509. LlcInsertTailList(&pFileContext->CommandQueue, pDlcCommand);
  510. }
  511. //
  512. // Asynchronous commands returns ALWAYS the pending status.
  513. //
  514. }
  515. return STATUS_PENDING;
  516. }
  517. NTSTATUS
  518. AbortCommand(
  519. IN PDLC_FILE_CONTEXT pFileContext,
  520. IN USHORT StationId,
  521. IN USHORT StationIdMask,
  522. IN PVOID AbortHandle,
  523. IN OUT PVOID *ppCcbLink,
  524. IN UINT CancelStatus,
  525. IN BOOLEAN SuppressCommandCompletion
  526. )
  527. /*++
  528. Routine Description:
  529. The routine searches and cancels a command from a command queue.
  530. The commands must always belong to the defined DLC object.
  531. A NULL value in abort handle selects all matching commands
  532. found in the queue.
  533. Arguments:
  534. pFileContext -
  535. StationId - station id the searched command is destined for
  536. StationIdMask - station id mask used in the search
  537. AbortHandle - handle used to cancel the command from the
  538. queue. The whole command queue will be scanned
  539. if this handle is NULL
  540. ppCcbLink - the canceled commands are linked by their next
  541. CCB pointer fieldsr. The caller must provide
  542. the next CCB address in this parameter
  543. (usually *ppCcbLink == NULL) and the function
  544. will return the address of the last cancelled
  545. CCB field.
  546. CancelStatus - Status for the command to be canceled
  547. SuppressCommandCompletion - the flag is set, if the normal command
  548. completion is suppressed.
  549. Return Value:
  550. - no mathing command was found
  551. STATUS_SUCCESS - the command was canceled
  552. --*/
  553. {
  554. PDLC_COMMAND pDlcCommand;
  555. DIAG_FUNCTION("AbortCommand");
  556. pDlcCommand = SearchAndRemoveAnyCommand(pFileContext,
  557. (ULONG)(-1), // search all commands
  558. StationId,
  559. StationIdMask,
  560. AbortHandle
  561. );
  562. if (pDlcCommand == NULL && AbortHandle == DLC_MATCH_ANY_COMMAND) {
  563. pDlcCommand = pFileContext->pTimerQueue;
  564. if (pDlcCommand != NULL) {
  565. pFileContext->pTimerQueue = (PDLC_COMMAND)pDlcCommand->LlcPacket.pNext;
  566. }
  567. }
  568. if (pDlcCommand != NULL) {
  569. CancelDlcCommand(pFileContext,
  570. pDlcCommand,
  571. ppCcbLink,
  572. CancelStatus,
  573. SuppressCommandCompletion
  574. );
  575. return STATUS_SUCCESS;
  576. } else {
  577. return DLC_STATUS_INVALID_CCB_POINTER;
  578. }
  579. }
  580. VOID
  581. CancelDlcCommand(
  582. IN PDLC_FILE_CONTEXT pFileContext,
  583. IN PDLC_COMMAND pDlcCommand,
  584. IN OUT PVOID *ppCcbLink,
  585. IN UINT CancelStatus,
  586. IN BOOLEAN SuppressCommandCompletion
  587. )
  588. /*++
  589. Routine Description:
  590. The cancels and optionally completes the given DLC command. Called when one
  591. DLC I/O request is used to kill another (e.g. READ.CANCEL, DIR.TIMER.CANCEL)
  592. Arguments:
  593. pFileContext -
  594. pDlcCommand -
  595. ppCcbLink - the canceled commands are linked by their next
  596. CCB pointer fields. The caller must provide
  597. the next CCB address in this parameter
  598. (usually *ppCcbLink == NULL) and the function
  599. will return the address of the last cancelled
  600. CCB field
  601. CancelStatus - Status for the command to be canceled
  602. SuppressCommandCompletion - if set, normal command completion is suppressed
  603. Return Value:
  604. None
  605. --*/
  606. {
  607. PVOID pOldCcbLink;
  608. DIAG_FUNCTION("CancelDlcCommand");
  609. //
  610. // We must return the current CCB link to be linked to the next cancelled
  611. // CCB command (or to the CCB pointer of cancelling command). But first
  612. // save the previous CCB link before we read a new one
  613. //
  614. pOldCcbLink = *ppCcbLink;
  615. *ppCcbLink = ((PNT_DLC_PARMS)pDlcCommand->pIrp->AssociatedIrp.SystemBuffer)->Async.Ccb.pCcbAddress;
  616. //
  617. // Check if we must suppress any kind of command completion indications to
  618. // the applications. I/O system should not care, if its event handle is
  619. // removed
  620. //
  621. if (SuppressCommandCompletion) {
  622. pDlcCommand->pIrp->UserEvent = NULL;
  623. }
  624. CompleteAsyncCommand(pFileContext, CancelStatus, pDlcCommand->pIrp, pOldCcbLink, FALSE);
  625. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pDlcCommand);
  626. }
  627. VOID
  628. PurgeDlcEventQueue(
  629. IN PDLC_FILE_CONTEXT pFileContext
  630. )
  631. /*++
  632. Routine Description:
  633. Deletes all events from a FILE_CONTEXT event queue. Called when the
  634. FILE_CONTEXT is being deleted and before we deallocate the packet pool from
  635. which the events were allocated
  636. Arguments:
  637. pFileContext - pointer to FILE_CONTEXT owning the queue
  638. Return Value:
  639. None.
  640. --*/
  641. {
  642. PDLC_EVENT p;
  643. while (!IsListEmpty(&pFileContext->EventQueue)) {
  644. p = (PDLC_EVENT)RemoveHeadList(&pFileContext->EventQueue);
  645. if (p->bFreeEventInfo && p->pEventInformation) {
  646. #if DBG
  647. DbgPrint("PurgeDlcEventQueue: deallocating pEventInformation: %x\n", p->pEventInformation);
  648. #endif
  649. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, p->pEventInformation);
  650. }
  651. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, p);
  652. }
  653. }
  654. VOID
  655. PurgeDlcFlowControlQueue(
  656. IN PDLC_FILE_CONTEXT pFileContext
  657. )
  658. /*++
  659. Routine Description:
  660. Deletes all packets from the flow control queue. Called when the FILE_CONTEXT
  661. is being deleted and before we deallocate the packet pool from which flow
  662. control packets were allocated
  663. Arguments:
  664. pFileContext - pointer to FILE_CONTEXT owning the queue
  665. Return Value:
  666. None.
  667. --*/
  668. {
  669. PDLC_RESET_LOCAL_BUSY_CMD p;
  670. while (!IsListEmpty(&pFileContext->FlowControlQueue)) {
  671. p = (PDLC_RESET_LOCAL_BUSY_CMD)RemoveHeadList(&pFileContext->FlowControlQueue);
  672. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, p);
  673. }
  674. }
  675. /*
  676. //
  677. // Internal consistency check to hunt a bougus event in the event queue.
  678. //
  679. //extern BOOLEAN EventCheckDisabled;
  680. //
  681. int
  682. CheckEventQueue(
  683. PDLC_FILE_CONTEXT pFileContext
  684. )
  685. {
  686. static PDLC_FILE_CONTEXT pOldFileContext = NULL;
  687. if (pFileContext == NULL)
  688. {
  689. pFileContext = pOldFileContext;
  690. }
  691. else
  692. {
  693. pOldFileContext = pFileContext;
  694. }
  695. if (pFileContext == NULL)
  696. return 0;
  697. if (!IsListEmpty( &pFileContext->EventQueue ) &&
  698. pFileContext->EventQueue.Flink == pFileContext->EventQueue.Blink &&
  699. &pFileContext->EventQueue != pFileContext->EventQueue.Flink->Flink)
  700. {
  701. FooDebugBreak();
  702. }
  703. return 0;
  704. }
  705. int
  706. FooDebugBreak()
  707. {
  708. INT i;
  709. return i++;
  710. }
  711. */
  712. // PDLC_EVENT pEvent;
  713. //
  714. // if (EventCheckDisabled || pFileContext->AdapterNumber != 0 ||
  715. // pFileContext->EventQueue == NULL)
  716. // return;
  717. //
  718. // pEvent = (PDLC_EVENT)pFileContext->pEventQueue->LlcPacket.pNext;
  719. // for (;;)
  720. // {
  721. // if (pEvent->Event == LLC_STATUS_CHANGE &&
  722. // pEvent->pOwnerObject == NULL)
  723. // DebugBreak();
  724. // if (pEvent == pFileContext->pEventQueue)
  725. // break;
  726. // pEvent = (PDLC_EVENT)pEvent->LlcPacket.pNext;
  727. // }
  728. //}
  729. //