ReactOS  0.4.13-dev-92-gf251225
queue.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: drivers/usb/usbstor/queue.c
5  * PURPOSE: USB block storage device driver.
6  * PROGRAMMERS:
7  * James Tabor
8  * Michael Martin (michael.martin@reactos.org)
9  * Johannes Anderwald (johannes.anderwald@reactos.org)
10  */
11 
12 #include "usbstor.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 VOID
19  PFDO_DEVICE_EXTENSION FDODeviceExtension)
20 {
21  //
22  // sanity check
23  //
24  ASSERT(FDODeviceExtension->Common.IsFDO);
25 
26  //
27  // initialize queue lock
28  //
29  KeInitializeSpinLock(&FDODeviceExtension->IrpListLock);
30 
31  //
32  // initialize irp list head
33  //
34  InitializeListHead(&FDODeviceExtension->IrpListHead);
35 
36  //
37  // initialize event
38  //
39  KeInitializeEvent(&FDODeviceExtension->NoPendingRequests, NotificationEvent, TRUE);
40 }
41 
42 VOID
43 NTAPI
46  IN PIRP Irp)
47 {
48  PFDO_DEVICE_EXTENSION FDODeviceExtension;
49 
50  //
51  // get FDO device extension
52  //
53  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
54 
55  //
56  // sanity check
57  //
59  ASSERT(FDODeviceExtension->Common.IsFDO);
60 
61  //
62  // this IRP isn't in our list here
63  //
64 
65  //
66  // now release the cancel lock
67  //
68  IoReleaseCancelSpinLock(Irp->CancelIrql);
69 
70  //
71  // set cancel status
72  //
73  Irp->IoStatus.Status = STATUS_CANCELLED;
74 
75  //
76  // now cancel the irp
77  //
80 
81  //
82  // start the next one
83  //
85 }
86 
87 VOID
88 NTAPI
91  IN PIRP Irp)
92 {
93  PFDO_DEVICE_EXTENSION FDODeviceExtension;
94 
95  //
96  // get FDO device extension
97  //
98  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
99 
100  //
101  // sanity check
102  //
104  ASSERT(FDODeviceExtension->Common.IsFDO);
105 
106  //
107  // acquire irp list lock
108  //
109  KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock);
110 
111  //
112  // remove the irp from the list
113  //
114  RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
115 
116  //
117  // release irp list lock
118  //
119  KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock);
120 
121  //
122  // now release the cancel lock
123  //
124  IoReleaseCancelSpinLock(Irp->CancelIrql);
125 
126  //
127  // set cancel status
128  //
129  Irp->IoStatus.Status = STATUS_CANCELLED;
130 
131  //
132  // now cancel the irp
133  //
136 
137  //
138  // start the next one
139  //
141 }
142 
143 BOOLEAN
146  IN PIRP Irp)
147 {
148  PDRIVER_CANCEL OldDriverCancel;
149  KIRQL OldLevel;
150  PFDO_DEVICE_EXTENSION FDODeviceExtension;
151  BOOLEAN IrpListFreeze;
152  BOOLEAN SrbProcessing;
154  PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
155 
156  //
157  // get FDO device extension
158  //
159  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
160 
161  //
162  // sanity check
163  //
164  ASSERT(FDODeviceExtension->Common.IsFDO);
165 
166  //
167  // mark irp pending
168  //
170 
171  //
172  // acquire lock
173  //
174  KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
175 
176  //
177  // check if there are irp pending
178  //
179  SrbProcessing = FDODeviceExtension->IrpPendingCount != 0;
180 
181  if (SrbProcessing)
182  {
183  //
184  // add irp to queue
185  //
186  InsertTailList(&FDODeviceExtension->IrpListHead, &Irp->Tail.Overlay.ListEntry);
187  }
188 
189  //
190  // increment pending count
191  //
192  FDODeviceExtension->IrpPendingCount++;
193 
194 
195  //
196  // clear the no requests pending event
197  //
198  KeClearEvent(&FDODeviceExtension->NoPendingRequests);
199 
200  //
201  // check if queue is freezed
202  //
203  IrpListFreeze = FDODeviceExtension->IrpListFreeze;
204 
205  //
206  // release list lock
207  //
208  KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
209 
210  //
211  // synchronize with cancellations by holding the cancel lock
212  //
213  IoAcquireCancelSpinLock(&Irp->CancelIrql);
214 
215  //
216  // now set the driver cancel routine
217  //
218  if (SrbProcessing)
219  {
220  ASSERT(FDODeviceExtension->ActiveSrb != NULL);
221 
222  OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_Cancel);
223  }
224  else
225  {
226  ASSERT(FDODeviceExtension->ActiveSrb == NULL);
227 
228  FDODeviceExtension->ActiveSrb = Request;
229  OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_CancelIo);
230  }
231 
232  //
233  // check if the irp has already been cancelled
234  //
235  if (Irp->Cancel && OldDriverCancel == NULL)
236  {
237  //
238  // cancel irp
239  //
240  Irp->CancelRoutine(DeviceObject, Irp);
241 
242  //
243  // irp was cancelled
244  //
245  return FALSE;
246  }
247 
248  //
249  // release the cancel lock
250  //
251  IoReleaseCancelSpinLock(Irp->CancelIrql);
252 
253  //
254  // if list is freezed, dont start this packet
255  //
256  DPRINT("IrpListFreeze: %lu IrpPendingCount %lu\n", IrpListFreeze, FDODeviceExtension->IrpPendingCount);
257 
258  return (IrpListFreeze || SrbProcessing);
259 }
260 
261 PIRP
264 {
265  KIRQL OldLevel;
266  PFDO_DEVICE_EXTENSION FDODeviceExtension;
268  PIRP Irp = NULL;
269 
270  //
271  // get FDO device extension
272  //
273  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
274 
275  //
276  // sanity check
277  //
278  ASSERT(FDODeviceExtension->Common.IsFDO);
279 
280  //
281  // acquire lock
282  //
283  KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
284 
285  //
286  // check if list is empty
287  //
288  if (!IsListEmpty(&FDODeviceExtension->IrpListHead))
289  {
290  //
291  // remove entry
292  //
293  Entry = RemoveHeadList(&FDODeviceExtension->IrpListHead);
294 
295  //
296  // get offset to start of irp
297  //
298  Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
299  }
300 
301  //
302  // release list lock
303  //
304  KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
305 
306  //
307  // return result
308  //
309  return Irp;
310 }
311 
312 VOID
315 {
316  PFDO_DEVICE_EXTENSION FDODeviceExtension;
317 
318  //
319  // get FDO device extension
320  //
321  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
322 
323  //
324  // perform the wait
325  //
326  KeWaitForSingleObject(&FDODeviceExtension->NoPendingRequests,
327  Executive,
328  KernelMode,
329  FALSE,
330  NULL);
331 }
332 
333 VOID
335  IN PDEVICE_OBJECT FDODeviceObject,
336  IN PIRP Irp)
337 {
338  KIRQL OldLevel;
339  PFDO_DEVICE_EXTENSION FDODeviceExtension;
341  PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
342 
343  //
344  // get FDO device extension
345  //
346  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FDODeviceObject->DeviceExtension;
347 
348  //
349  // sanity check
350  //
351  ASSERT(FDODeviceExtension->Common.IsFDO);
352 
353  //
354  // acquire lock
355  //
356  KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
357 
358  //
359  // decrement pending irp count
360  //
361  FDODeviceExtension->IrpPendingCount--;
362 
363  //
364  // check if this was our current active SRB
365  //
366  if (FDODeviceExtension->ActiveSrb == Request)
367  {
368  //
369  // indicate processing is completed
370  //
371  FDODeviceExtension->ActiveSrb = NULL;
372  }
373 
374  //
375  // Set the event if nothing else is pending
376  //
377  if (FDODeviceExtension->IrpPendingCount == 0 &&
378  FDODeviceExtension->ActiveSrb == NULL)
379  {
380  KeSetEvent(&FDODeviceExtension->NoPendingRequests, IO_NO_INCREMENT, FALSE);
381  }
382 
383  //
384  // release lock
385  //
386  KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
387 
388 }
389 
390 VOID
393 {
394  PFDO_DEVICE_EXTENSION FDODeviceExtension;
395  PIRP Irp;
396  PIO_STACK_LOCATION IoStack;
398 
399  //
400  // get pdo device extension
401  //
402  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
403 
404  //
405  // sanity check
406  //
407  ASSERT(FDODeviceExtension->Common.IsFDO);
408 
409  //
410  // check first if there's already a request pending or the queue is frozen
411  //
412  if (FDODeviceExtension->ActiveSrb != NULL ||
413  FDODeviceExtension->IrpListFreeze)
414  {
415  //
416  // no work to do yet
417  //
418  return;
419  }
420 
421  //
422  // remove first irp from list
423  //
425 
426  //
427  // is there an irp pending
428  //
429  if (!Irp)
430  {
431  //
432  // no work to do
433  //
435  return;
436  }
437 
438  //
439  // get current stack location
440  //
442 
443  //
444  // get srb
445  //
446  Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
447 
448  //
449  // sanity check
450  //
451  ASSERT(Request);
452 
453  //
454  // set the active SRB
455  //
456  FDODeviceExtension->ActiveSrb = Request;
457 
458  //
459  // start next packet
460  //
462 
463  //
464  // start next request
465  //
467 }
468 
469 VOID
472 {
473  PFDO_DEVICE_EXTENSION FDODeviceExtension;
474  PIRP Irp;
475  KIRQL OldLevel;
476  PIO_STACK_LOCATION IoStack;
478 
479  //
480  // get FDO device extension
481  //
482  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
483 
484  //
485  // sanity check
486  //
487  ASSERT(FDODeviceExtension->Common.IsFDO);
488 
489  //
490  // acquire lock
491  //
492  KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
493 
494  //
495  // clear freezed status
496  //
497  FDODeviceExtension->IrpListFreeze = FALSE;
498 
499  //
500  // release irp list lock
501  //
502  KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
503 
504  //
505  // grab newest irp
506  //
508 
509  //
510  // is there an irp
511  //
512  if (!Irp)
513  {
514  //
515  // no irp
516  //
517  return;
518  }
519 
520  //
521  // get current irp stack location
522  //
524 
525  //
526  // get srb
527  //
528  Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
529 
530  //
531  // start new packet
532  //
534  Irp,
535  &Request->QueueSortKey,
537 }
538 
539 
540 VOID
541 NTAPI
544  PIRP Irp)
545 {
546  PIO_STACK_LOCATION IoStack;
547  PFDO_DEVICE_EXTENSION FDODeviceExtension;
548  PPDO_DEVICE_EXTENSION PDODeviceExtension;
549  KIRQL OldLevel;
550  BOOLEAN ResetInProgress;
551 
552  DPRINT("USBSTOR_StartIo\n");
553 
554  //
555  // get FDO device extension
556  //
557  FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
558 
559  //
560  // sanity check
561  //
562  ASSERT(FDODeviceExtension->Common.IsFDO);
563 
564  //
565  // acquire cancel spinlock
566  //
567  IoAcquireCancelSpinLock(&OldLevel);
568 
569  //
570  // set cancel routine to zero
571  //
573 
574  //
575  // check if the irp has been cancelled
576  //
577  if (Irp->Cancel)
578  {
579  //
580  // irp has been cancelled, release cancel spinlock
581  //
582  IoReleaseCancelSpinLock(OldLevel);
583 
584  //
585  // irp is cancelled
586  //
587  Irp->IoStatus.Status = STATUS_CANCELLED;
588  Irp->IoStatus.Information = 0;
589 
590  //
591  // terminate request
592  //
594 
595  //
596  // complete request
597  //
599 
600  //
601  // queue next request
602  //
604 
605  //
606  // done
607  //
608  return;
609  }
610 
611  //
612  // release cancel spinlock
613  //
614  IoReleaseCancelSpinLock(OldLevel);
615 
616  //
617  // acquire lock
618  //
619  KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
620 
621  //
622  // check reset is in progress
623  //
624  ResetInProgress = FDODeviceExtension->ResetInProgress;
625  ASSERT(ResetInProgress == FALSE);
626 
627  //
628  // release lock
629  //
630  KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
631 
632  //
633  // get current irp stack location
634  //
636 
637  //
638  // get pdo device extension
639  //
640  PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
641 
642  //
643  // sanity check
644  //
645  ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
646 
647  //
648  // is a reset in progress
649  //
650  if (ResetInProgress)
651  {
652  //
653  // hard reset is in progress
654  //
655  Irp->IoStatus.Information = 0;
656  Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
659  return;
660  }
661 
662  //
663  // execute scsi
664  //
666 
667  //
668  // FIXME: handle error
669  //
670 }
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define STATUS_DEVICE_DOES_NOT_EXIST
Definition: ntstatus.h:414
#define IN
Definition: typedefs.h:38
DRIVER_CANCEL * PDRIVER_CANCEL
Definition: iotypes.h:2404
#define TRUE
Definition: types.h:120
VOID NTAPI USBSTOR_CancelIo(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: queue.c:44
struct _Entry Entry
Definition: kefuncs.h:640
struct _SCSI_REQUEST_BLOCK * PSCSI_REQUEST_BLOCK
_In_ PIRP Irp
Definition: csq.h:116
LIST_ENTRY ListEntry
Definition: pci.h:82
VOID NTAPI KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:192
VOID NTAPI IoAcquireCancelSpinLock(OUT PKIRQL Irql)
Definition: util.c:56
struct _PDO_DEVICE_EXTENSION * PPDO_DEVICE_EXTENSION
BOOLEAN USBSTOR_QueueAddIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: queue.c:144
IRP
Definition: iotypes.h:2462
#define InsertTailList(ListHead, Entry)
IoSetCancelRoutine(Irp, CancelRoutine)
LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait)
Definition: eventobj.c:159
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
struct _FDO_DEVICE_EXTENSION * PFDO_DEVICE_EXTENSION
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
_In_ NDIS_HANDLE _In_ PNDIS_REQUEST Request
Definition: ndis.h:5155
UCHAR KIRQL
Definition: env_spec_w32.h:591
VOID USBSTOR_QueueNextRequest(IN PDEVICE_OBJECT DeviceObject)
Definition: queue.c:391
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
VOID USBSTOR_QueueRelease(IN PDEVICE_OBJECT DeviceObject)
Definition: queue.c:470
FORCEINLINE VOID KeInitializeSpinLock(_Out_ PKSPIN_LOCK SpinLock)
Definition: kefuncs.h:251
VOID NTAPI IoStartPacket(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PULONG Key, IN PDRIVER_CANCEL CancelFunction)
Definition: device.c:1875
PVOID DeviceExtension
Definition: env_spec_w32.h:418
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
#define IoCompleteRequest
Definition: irp.c:1240
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
COMMON_DEVICE_EXTENSION Common
Definition: pci.h:55
void DPRINT(...)
Definition: polytest.cpp:61
VOID USBSTOR_QueueTerminateRequest(IN PDEVICE_OBJECT FDODeviceObject, IN PIRP Irp)
Definition: queue.c:334
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
VOID NTAPI KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:215
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
PDEVICE_OBJECT DeviceObject
Definition: iotypes.h:2866
VOID USBSTOR_QueueInitialize(PFDO_DEVICE_EXTENSION FDODeviceExtension)
Definition: queue.c:18
VOID NTAPI USBSTOR_StartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Definition: queue.c:542
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
Definition: typedefs.h:117
NTSTATUS USBSTOR_HandleExecuteSCSI(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN ULONG RetryCount)
Definition: scsi.c:1306
COMMON_DEVICE_EXTENSION Common
Definition: pci.h:80
VOID NTAPI IoReleaseCancelSpinLock(IN KIRQL Irql)
Definition: util.c:150
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
VOID USBSTOR_QueueWaitForPendingRequests(IN PDEVICE_OBJECT DeviceObject)
Definition: queue.c:313
PVOID PIRP
Definition: usb.h:38
#define IO_NO_INCREMENT
Definition: iotypes.h:565
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2771
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
IoMarkIrpPending(Irp)
PIRP USBSTOR_RemoveIrp(IN PDEVICE_OBJECT DeviceObject)
Definition: queue.c:262
base of all file and directory entries
Definition: entries.h:82
VOID NTAPI USBSTOR_Cancel(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: queue.c:89
VOID NTAPI IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN Cancelable)
Definition: device.c:1846