* Sync up to trunk head (r64939).
[reactos.git] / drivers / usb / usbstor / queue.c
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
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
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
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
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
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
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
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
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
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
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 }