xref: /reactos/drivers/usb/usbstor_new/queue.c (revision 34593d93)
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
USBSTOR_QueueInitialize(PFDO_DEVICE_EXTENSION FDODeviceExtension)18 USBSTOR_QueueInitialize(
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
USBSTOR_CancelIo(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)44 USBSTOR_CancelIo(
45     IN  PDEVICE_OBJECT DeviceObject,
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     //
58     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
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     //
78     USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
79     IoCompleteRequest(Irp, IO_NO_INCREMENT);
80 
81     //
82     // start the next one
83     //
84     USBSTOR_QueueNextRequest(DeviceObject);
85 }
86 
87 VOID
88 NTAPI
USBSTOR_Cancel(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)89 USBSTOR_Cancel(
90     IN  PDEVICE_OBJECT DeviceObject,
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     //
103     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
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     //
134     USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
135     IoCompleteRequest(Irp, IO_NO_INCREMENT);
136 
137     //
138     // start the next one
139     //
140     USBSTOR_QueueNextRequest(DeviceObject);
141 }
142 
143 BOOLEAN
USBSTOR_QueueAddIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)144 USBSTOR_QueueAddIrp(
145     IN PDEVICE_OBJECT DeviceObject,
146     IN PIRP Irp)
147 {
148     PDRIVER_CANCEL OldDriverCancel;
149     KIRQL OldLevel;
150     PFDO_DEVICE_EXTENSION FDODeviceExtension;
151     BOOLEAN IrpListFreeze;
152     BOOLEAN SrbProcessing;
153     PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
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     //
169     IoMarkIrpPending(Irp);
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
USBSTOR_RemoveIrp(IN PDEVICE_OBJECT DeviceObject)262 USBSTOR_RemoveIrp(
263     IN PDEVICE_OBJECT DeviceObject)
264 {
265     KIRQL OldLevel;
266     PFDO_DEVICE_EXTENSION FDODeviceExtension;
267     PLIST_ENTRY Entry;
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
USBSTOR_QueueWaitForPendingRequests(IN PDEVICE_OBJECT DeviceObject)313 USBSTOR_QueueWaitForPendingRequests(
314     IN PDEVICE_OBJECT DeviceObject)
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
USBSTOR_QueueTerminateRequest(IN PDEVICE_OBJECT FDODeviceObject,IN PIRP Irp)334 USBSTOR_QueueTerminateRequest(
335     IN PDEVICE_OBJECT FDODeviceObject,
336     IN PIRP Irp)
337 {
338     KIRQL OldLevel;
339     PFDO_DEVICE_EXTENSION FDODeviceExtension;
340     PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
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
USBSTOR_QueueNextRequest(IN PDEVICE_OBJECT DeviceObject)391 USBSTOR_QueueNextRequest(
392     IN PDEVICE_OBJECT DeviceObject)
393 {
394     PFDO_DEVICE_EXTENSION FDODeviceExtension;
395     PIRP Irp;
396     PIO_STACK_LOCATION IoStack;
397     PSCSI_REQUEST_BLOCK Request;
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     //
424     Irp = USBSTOR_RemoveIrp(DeviceObject);
425 
426     //
427     // is there an irp pending
428     //
429     if (!Irp)
430     {
431         //
432         // no work to do
433         //
434         IoStartNextPacket(DeviceObject, TRUE);
435         return;
436     }
437 
438     //
439     // get current stack location
440     //
441     IoStack = IoGetCurrentIrpStackLocation(Irp);
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     //
461     IoStartPacket(DeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo);
462 
463     //
464     // start next request
465     //
466     IoStartNextPacket(DeviceObject, TRUE);
467 }
468 
469 VOID
USBSTOR_QueueRelease(IN PDEVICE_OBJECT DeviceObject)470 USBSTOR_QueueRelease(
471     IN PDEVICE_OBJECT DeviceObject)
472 {
473     PFDO_DEVICE_EXTENSION FDODeviceExtension;
474     PIRP Irp;
475     KIRQL OldLevel;
476     PIO_STACK_LOCATION IoStack;
477     PSCSI_REQUEST_BLOCK Request;
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     //
507     Irp = USBSTOR_RemoveIrp(DeviceObject);
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     //
523     IoStack = IoGetCurrentIrpStackLocation(Irp);
524 
525     //
526     // get srb
527     //
528     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
529 
530     //
531     // start new packet
532     //
533     IoStartPacket(DeviceObject,
534                   Irp,
535                   &Request->QueueSortKey,
536                   USBSTOR_CancelIo);
537 }
538 
539 
540 VOID
541 NTAPI
USBSTOR_StartIo(PDEVICE_OBJECT DeviceObject,PIRP Irp)542 USBSTOR_StartIo(
543     PDEVICE_OBJECT DeviceObject,
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     //
572     IoSetCancelRoutine(Irp, NULL);
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         //
593         USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
594 
595         //
596         // complete request
597         //
598         IoCompleteRequest(Irp, IO_NO_INCREMENT);
599 
600         //
601         // queue next request
602         //
603         USBSTOR_QueueNextRequest(DeviceObject);
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     //
635     IoStack = IoGetCurrentIrpStackLocation(Irp);
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;
657         USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
658         IoCompleteRequest(Irp, IO_NO_INCREMENT);
659         return;
660     }
661 
662     //
663     // execute scsi
664     //
665     USBSTOR_HandleExecuteSCSI(IoStack->DeviceObject, Irp, 0);
666 
667     //
668     // FIXME: handle error
669     //
670 }
671