[USBSTOR] Do not try to retry a failed request
[reactos.git] / drivers / usb / usbstor / queue.c
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 = FDODeviceExtension->IrpListFreeze;
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 FDODeviceExtension->IrpListFreeze)
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->IrpListFreeze = FALSE;
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 PFDO_DEVICE_EXTENSION FDODeviceExtension;
306 PPDO_DEVICE_EXTENSION PDODeviceExtension;
307 KIRQL OldLevel;
308 BOOLEAN ResetInProgress;
309
310 DPRINT("USBSTOR_StartIo\n");
311
312 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
313 ASSERT(FDODeviceExtension->Common.IsFDO);
314
315 IoAcquireCancelSpinLock(&OldLevel);
316
317 IoSetCancelRoutine(Irp, NULL);
318
319 // check if the irp has been cancelled
320 if (Irp->Cancel)
321 {
322 IoReleaseCancelSpinLock(OldLevel);
323
324 Irp->IoStatus.Status = STATUS_CANCELLED;
325 Irp->IoStatus.Information = 0;
326
327 USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
328 IoCompleteRequest(Irp, IO_NO_INCREMENT);
329 USBSTOR_QueueNextRequest(DeviceObject);
330 return;
331 }
332
333 IoReleaseCancelSpinLock(OldLevel);
334
335 KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
336
337 ResetInProgress = FDODeviceExtension->ResetInProgress;
338 ASSERT(ResetInProgress == FALSE);
339
340 KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
341
342 IoStack = IoGetCurrentIrpStackLocation(Irp);
343
344 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
345 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
346
347 // TODO: this condition is always false
348 if (ResetInProgress)
349 {
350 // hard reset is in progress
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 return;
356 }
357
358 USBSTOR_HandleExecuteSCSI(IoStack->DeviceObject, Irp);
359
360 // FIXME: handle error
361 }