xref: /reactos/drivers/usb/usbstor/queue.c (revision b5218987)
1 /*
2  * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     USB block storage device driver.
5  * COPYRIGHT:   2005-2006 James Tabor
6  *              2011-2012 Michael Martin (michael.martin@reactos.org)
7  *              2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 
10 #include "usbstor.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 
16 VOID
17 USBSTOR_QueueInitialize(
18     PFDO_DEVICE_EXTENSION FDODeviceExtension)
19 {
20     ASSERT(FDODeviceExtension->Common.IsFDO);
21     KeInitializeSpinLock(&FDODeviceExtension->IrpListLock);
22     InitializeListHead(&FDODeviceExtension->IrpListHead);
23     KeInitializeEvent(&FDODeviceExtension->NoPendingRequests, NotificationEvent, TRUE);
24 }
25 
26 VOID
27 NTAPI
28 USBSTOR_CancelIo(
29     IN  PDEVICE_OBJECT DeviceObject,
30     IN  PIRP Irp)
31 {
32     PFDO_DEVICE_EXTENSION FDODeviceExtension;
33 
34     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
35     ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
36     ASSERT(FDODeviceExtension->Common.IsFDO);
37 
38     // this IRP isn't in our list here
39     // now release the cancel lock
40     IoReleaseCancelSpinLock(Irp->CancelIrql);
41     Irp->IoStatus.Status = STATUS_CANCELLED;
42 
43     USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
44     IoCompleteRequest(Irp, IO_NO_INCREMENT);
45 
46     USBSTOR_QueueNextRequest(DeviceObject);
47 }
48 
49 VOID
50 NTAPI
51 USBSTOR_Cancel(
52     IN  PDEVICE_OBJECT DeviceObject,
53     IN  PIRP Irp)
54 {
55     PFDO_DEVICE_EXTENSION FDODeviceExtension;
56 
57     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
58     ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
59     ASSERT(FDODeviceExtension->Common.IsFDO);
60 
61     KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock);
62     RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
63     KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock);
64 
65     IoReleaseCancelSpinLock(Irp->CancelIrql);
66     Irp->IoStatus.Status = STATUS_CANCELLED;
67 
68     USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
69     IoCompleteRequest(Irp, IO_NO_INCREMENT);
70 
71     USBSTOR_QueueNextRequest(DeviceObject);
72 }
73 
74 BOOLEAN
75 USBSTOR_QueueAddIrp(
76     IN PDEVICE_OBJECT DeviceObject,
77     IN PIRP Irp)
78 {
79     PDRIVER_CANCEL OldDriverCancel;
80     KIRQL OldLevel;
81     PFDO_DEVICE_EXTENSION FDODeviceExtension;
82     BOOLEAN IrpListFreeze;
83     BOOLEAN SrbProcessing;
84     PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
85     PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
86 
87     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
88     ASSERT(FDODeviceExtension->Common.IsFDO);
89 
90     IoMarkIrpPending(Irp);
91 
92     KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
93 
94     SrbProcessing = FDODeviceExtension->IrpPendingCount != 0;
95 
96     if (SrbProcessing)
97     {
98         // add irp to queue
99         InsertTailList(&FDODeviceExtension->IrpListHead, &Irp->Tail.Overlay.ListEntry);
100     }
101 
102     FDODeviceExtension->IrpPendingCount++;
103     KeClearEvent(&FDODeviceExtension->NoPendingRequests);
104 
105     // check if queue is freezed
106     IrpListFreeze = BooleanFlagOn(FDODeviceExtension->Flags, USBSTOR_FDO_FLAGS_IRP_LIST_FREEZE);
107 
108     KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
109 
110     // synchronize with cancellations by holding the cancel lock
111     IoAcquireCancelSpinLock(&Irp->CancelIrql);
112 
113     if (SrbProcessing)
114     {
115         ASSERT(FDODeviceExtension->ActiveSrb != NULL);
116 
117         OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_Cancel);
118     }
119     else
120     {
121         ASSERT(FDODeviceExtension->ActiveSrb == NULL);
122 
123         FDODeviceExtension->ActiveSrb = Request;
124         OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_CancelIo);
125     }
126 
127     // check if the irp has already been cancelled
128     if (Irp->Cancel && OldDriverCancel == NULL)
129     {
130         // cancel irp
131         Irp->CancelRoutine(DeviceObject, Irp);
132         return FALSE;
133     }
134 
135     IoReleaseCancelSpinLock(Irp->CancelIrql);
136 
137     // if list is freezed, dont start this packet
138     DPRINT("IrpListFreeze: %lu IrpPendingCount %lu\n", IrpListFreeze, FDODeviceExtension->IrpPendingCount);
139 
140     return (IrpListFreeze || SrbProcessing);
141 }
142 
143 PIRP
144 USBSTOR_RemoveIrp(
145     IN PDEVICE_OBJECT DeviceObject)
146 {
147     KIRQL OldLevel;
148     PFDO_DEVICE_EXTENSION FDODeviceExtension;
149     PLIST_ENTRY Entry;
150     PIRP Irp = NULL;
151 
152     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
153     ASSERT(FDODeviceExtension->Common.IsFDO);
154 
155     KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
156 
157     if (!IsListEmpty(&FDODeviceExtension->IrpListHead))
158     {
159         Entry = RemoveHeadList(&FDODeviceExtension->IrpListHead);
160 
161         // get offset to start of irp
162         Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
163     }
164 
165     KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
166 
167     return Irp;
168 }
169 
170 VOID
171 USBSTOR_QueueWaitForPendingRequests(
172     IN PDEVICE_OBJECT DeviceObject)
173 {
174     PFDO_DEVICE_EXTENSION FDODeviceExtension;
175 
176     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
177 
178     KeWaitForSingleObject(&FDODeviceExtension->NoPendingRequests,
179                           Executive,
180                           KernelMode,
181                           FALSE,
182                           NULL);
183 }
184 
185 VOID
186 USBSTOR_QueueTerminateRequest(
187     IN PDEVICE_OBJECT FDODeviceObject,
188     IN PIRP Irp)
189 {
190     KIRQL OldLevel;
191     PFDO_DEVICE_EXTENSION FDODeviceExtension;
192     PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
193     PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
194 
195     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FDODeviceObject->DeviceExtension;
196     ASSERT(FDODeviceExtension->Common.IsFDO);
197 
198     KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
199 
200     FDODeviceExtension->IrpPendingCount--;
201 
202     // check if this was our current active SRB
203     if (FDODeviceExtension->ActiveSrb == Request)
204     {
205         // indicate processing is completed
206         FDODeviceExtension->ActiveSrb = NULL;
207     }
208 
209     // Set the event if nothing else is pending
210     if (FDODeviceExtension->IrpPendingCount == 0 &&
211         FDODeviceExtension->ActiveSrb == NULL)
212     {
213         KeSetEvent(&FDODeviceExtension->NoPendingRequests, IO_NO_INCREMENT, FALSE);
214     }
215 
216     KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
217 }
218 
219 VOID
220 USBSTOR_QueueNextRequest(
221     IN PDEVICE_OBJECT DeviceObject)
222 {
223     PFDO_DEVICE_EXTENSION FDODeviceExtension;
224     PIRP Irp;
225     PIO_STACK_LOCATION IoStack;
226     PSCSI_REQUEST_BLOCK Request;
227 
228     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
229     ASSERT(FDODeviceExtension->Common.IsFDO);
230 
231     // check first if there's already a request pending or the queue is frozen
232     if (FDODeviceExtension->ActiveSrb != NULL ||
233         BooleanFlagOn(FDODeviceExtension->Flags, USBSTOR_FDO_FLAGS_IRP_LIST_FREEZE))
234     {
235         // no work to do yet
236         return;
237     }
238 
239     // remove first irp from list
240     Irp = USBSTOR_RemoveIrp(DeviceObject);
241 
242     // is there an irp pending
243     if (!Irp)
244     {
245         // no work to do
246         IoStartNextPacket(DeviceObject, TRUE);
247         return;
248     }
249 
250     IoStack = IoGetCurrentIrpStackLocation(Irp);
251     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
252     ASSERT(Request);
253 
254     FDODeviceExtension->ActiveSrb = Request;
255 
256     // start next packet
257     IoStartPacket(DeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo);
258     IoStartNextPacket(DeviceObject, TRUE);
259 }
260 
261 VOID
262 USBSTOR_QueueRelease(
263     IN PDEVICE_OBJECT DeviceObject)
264 {
265     PFDO_DEVICE_EXTENSION FDODeviceExtension;
266     PIRP Irp;
267     KIRQL OldLevel;
268     PIO_STACK_LOCATION IoStack;
269     PSCSI_REQUEST_BLOCK Request;
270 
271     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
272     ASSERT(FDODeviceExtension->Common.IsFDO);
273 
274     KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
275 
276     // clear freezed status
277     FDODeviceExtension->Flags &= ~USBSTOR_FDO_FLAGS_IRP_LIST_FREEZE;
278 
279     KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
280 
281     // grab newest irp
282     Irp = USBSTOR_RemoveIrp(DeviceObject);
283 
284     if (!Irp)
285     {
286         return;
287     }
288 
289     IoStack = IoGetCurrentIrpStackLocation(Irp);
290     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
291 
292     IoStartPacket(DeviceObject,
293                   Irp,
294                   &Request->QueueSortKey,
295                   USBSTOR_CancelIo);
296 }
297 
298 VOID
299 NTAPI
300 USBSTOR_StartIo(
301     PDEVICE_OBJECT DeviceObject,
302     PIRP Irp)
303 {
304     PIO_STACK_LOCATION IoStack;
305     PSCSI_REQUEST_BLOCK Request;
306     PFDO_DEVICE_EXTENSION FDODeviceExtension;
307     PPDO_DEVICE_EXTENSION PDODeviceExtension;
308     KIRQL OldLevel;
309     BOOLEAN ResetInProgress;
310 
311     DPRINT("USBSTOR_StartIo\n");
312 
313     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
314     ASSERT(FDODeviceExtension->Common.IsFDO);
315 
316     IoAcquireCancelSpinLock(&OldLevel);
317 
318     IoSetCancelRoutine(Irp, NULL);
319 
320     // check if the irp has been cancelled
321     if (Irp->Cancel)
322     {
323         IoReleaseCancelSpinLock(OldLevel);
324 
325         Irp->IoStatus.Status = STATUS_CANCELLED;
326         Irp->IoStatus.Information = 0;
327 
328         USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
329         IoCompleteRequest(Irp, IO_NO_INCREMENT);
330         USBSTOR_QueueNextRequest(DeviceObject);
331         return;
332     }
333 
334     IoReleaseCancelSpinLock(OldLevel);
335 
336     KeAcquireSpinLock(&FDODeviceExtension->CommonLock, &OldLevel);
337     ResetInProgress = BooleanFlagOn(FDODeviceExtension->Flags, USBSTOR_FDO_FLAGS_DEVICE_RESETTING);
338     KeReleaseSpinLock(&FDODeviceExtension->CommonLock, OldLevel);
339 
340     IoStack = IoGetCurrentIrpStackLocation(Irp);
341 
342     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
343     Request = IoStack->Parameters.Scsi.Srb;
344     ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
345 
346     if (ResetInProgress)
347     {
348         // hard reset is in progress
349         Request->SrbStatus = SRB_STATUS_NO_DEVICE;
350         Request->DataTransferLength = 0;
351         Irp->IoStatus.Information = 0;
352         Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
353         USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
354         IoCompleteRequest(Irp, IO_NO_INCREMENT);
355         USBSTOR_QueueNextRequest(DeviceObject);
356         return;
357     }
358 
359     USBSTOR_HandleExecuteSCSI(IoStack->DeviceObject, Irp);
360 
361     // FIXME: handle error
362 }
363