- Sync with trunk r58248 to bring the latest changes from Amine (headers) and others...
[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 VOID
15 USBSTOR_QueueInitialize(
16 PFDO_DEVICE_EXTENSION FDODeviceExtension)
17 {
18 //
19 // sanity check
20 //
21 ASSERT(FDODeviceExtension->Common.IsFDO);
22
23 //
24 // initialize queue lock
25 //
26 KeInitializeSpinLock(&FDODeviceExtension->IrpListLock);
27
28 //
29 // initialize irp list head
30 //
31 InitializeListHead(&FDODeviceExtension->IrpListHead);
32
33 //
34 // initialize event
35 //
36 KeInitializeEvent(&FDODeviceExtension->NoPendingRequests, NotificationEvent, TRUE);
37 }
38
39 VOID
40 NTAPI
41 USBSTOR_CancelIo(
42 IN PDEVICE_OBJECT DeviceObject,
43 IN PIRP Irp)
44 {
45 PFDO_DEVICE_EXTENSION FDODeviceExtension;
46
47 //
48 // get FDO device extension
49 //
50 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
51
52 //
53 // sanity check
54 //
55 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
56 ASSERT(FDODeviceExtension->Common.IsFDO);
57
58 //
59 // this IRP isn't in our list here
60 //
61
62 //
63 // now release the cancel lock
64 //
65 IoReleaseCancelSpinLock(Irp->CancelIrql);
66
67 //
68 // set cancel status
69 //
70 Irp->IoStatus.Status = STATUS_CANCELLED;
71
72 //
73 // now cancel the irp
74 //
75 USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
76 IoCompleteRequest(Irp, IO_NO_INCREMENT);
77
78 //
79 // start the next one
80 //
81 USBSTOR_QueueNextRequest(DeviceObject);
82 }
83
84 VOID
85 NTAPI
86 USBSTOR_Cancel(
87 IN PDEVICE_OBJECT DeviceObject,
88 IN PIRP Irp)
89 {
90 PFDO_DEVICE_EXTENSION FDODeviceExtension;
91
92 //
93 // get FDO device extension
94 //
95 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
96
97 //
98 // sanity check
99 //
100 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
101 ASSERT(FDODeviceExtension->Common.IsFDO);
102
103 //
104 // acquire irp list lock
105 //
106 KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock);
107
108 //
109 // remove the irp from the list
110 //
111 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
112
113 //
114 // release irp list lock
115 //
116 KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock);
117
118 //
119 // now release the cancel lock
120 //
121 IoReleaseCancelSpinLock(Irp->CancelIrql);
122
123 //
124 // set cancel status
125 //
126 Irp->IoStatus.Status = STATUS_CANCELLED;
127
128 //
129 // now cancel the irp
130 //
131 USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
132 IoCompleteRequest(Irp, IO_NO_INCREMENT);
133
134 //
135 // start the next one
136 //
137 USBSTOR_QueueNextRequest(DeviceObject);
138 }
139
140 BOOLEAN
141 USBSTOR_QueueAddIrp(
142 IN PDEVICE_OBJECT DeviceObject,
143 IN PIRP Irp)
144 {
145 PDRIVER_CANCEL OldDriverCancel;
146 KIRQL OldLevel;
147 PFDO_DEVICE_EXTENSION FDODeviceExtension;
148 BOOLEAN IrpListFreeze;
149 BOOLEAN SrbProcessing;
150 PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
151 PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
152
153 //
154 // get FDO device extension
155 //
156 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
157
158 //
159 // sanity check
160 //
161 ASSERT(FDODeviceExtension->Common.IsFDO);
162
163 //
164 // mark irp pending
165 //
166 IoMarkIrpPending(Irp);
167
168 //
169 // acquire lock
170 //
171 KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
172
173 //
174 // check if there are irp pending
175 //
176 SrbProcessing = FDODeviceExtension->IrpPendingCount != 0;
177
178 if (SrbProcessing)
179 {
180 //
181 // add irp to queue
182 //
183 InsertTailList(&FDODeviceExtension->IrpListHead, &Irp->Tail.Overlay.ListEntry);
184 }
185
186 //
187 // increment pending count
188 //
189 FDODeviceExtension->IrpPendingCount++;
190
191
192 //
193 // clear the no requests pending event
194 //
195 KeClearEvent(&FDODeviceExtension->NoPendingRequests);
196
197 //
198 // check if queue is freezed
199 //
200 IrpListFreeze = FDODeviceExtension->IrpListFreeze;
201
202 //
203 // release list lock
204 //
205 KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
206
207 //
208 // synchronize with cancellations by holding the cancel lock
209 //
210 IoAcquireCancelSpinLock(&Irp->CancelIrql);
211
212 //
213 // now set the driver cancel routine
214 //
215 if (SrbProcessing)
216 {
217 ASSERT(FDODeviceExtension->ActiveSrb != NULL);
218
219 OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_Cancel);
220 }
221 else
222 {
223 ASSERT(FDODeviceExtension->ActiveSrb == NULL);
224
225 FDODeviceExtension->ActiveSrb = Request;
226 OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_CancelIo);
227 }
228
229 //
230 // check if the irp has already been cancelled
231 //
232 if (Irp->Cancel && OldDriverCancel == NULL)
233 {
234 //
235 // cancel irp
236 //
237 Irp->CancelRoutine(DeviceObject, Irp);
238
239 //
240 // irp was cancelled
241 //
242 return FALSE;
243 }
244
245 //
246 // release the cancel lock
247 //
248 IoReleaseCancelSpinLock(Irp->CancelIrql);
249
250 //
251 // if list is freezed, dont start this packet
252 //
253 DPRINT("IrpListFreeze: %lu IrpPendingCount %lu\n", IrpListFreeze, FDODeviceExtension->IrpPendingCount);
254
255 return (IrpListFreeze || SrbProcessing);
256 }
257
258 PIRP
259 USBSTOR_RemoveIrp(
260 IN PDEVICE_OBJECT DeviceObject)
261 {
262 KIRQL OldLevel;
263 PFDO_DEVICE_EXTENSION FDODeviceExtension;
264 PLIST_ENTRY Entry;
265 PIRP Irp = NULL;
266
267 //
268 // get FDO device extension
269 //
270 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
271
272 //
273 // sanity check
274 //
275 ASSERT(FDODeviceExtension->Common.IsFDO);
276
277 //
278 // acquire lock
279 //
280 KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
281
282 //
283 // check if list is empty
284 //
285 if (!IsListEmpty(&FDODeviceExtension->IrpListHead))
286 {
287 //
288 // remove entry
289 //
290 Entry = RemoveHeadList(&FDODeviceExtension->IrpListHead);
291
292 //
293 // get offset to start of irp
294 //
295 Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
296 }
297
298 //
299 // release list lock
300 //
301 KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
302
303 //
304 // return result
305 //
306 return Irp;
307 }
308
309 VOID
310 USBSTOR_QueueWaitForPendingRequests(
311 IN PDEVICE_OBJECT DeviceObject)
312 {
313 PFDO_DEVICE_EXTENSION FDODeviceExtension;
314
315 //
316 // get FDO device extension
317 //
318 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
319
320 //
321 // perform the wait
322 //
323 KeWaitForSingleObject(&FDODeviceExtension->NoPendingRequests,
324 Executive,
325 KernelMode,
326 FALSE,
327 NULL);
328 }
329
330 VOID
331 USBSTOR_QueueTerminateRequest(
332 IN PDEVICE_OBJECT FDODeviceObject,
333 IN PIRP Irp)
334 {
335 KIRQL OldLevel;
336 PFDO_DEVICE_EXTENSION FDODeviceExtension;
337 PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
338 PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
339
340 //
341 // get FDO device extension
342 //
343 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FDODeviceObject->DeviceExtension;
344
345 //
346 // sanity check
347 //
348 ASSERT(FDODeviceExtension->Common.IsFDO);
349
350 //
351 // acquire lock
352 //
353 KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
354
355 //
356 // decrement pending irp count
357 //
358 FDODeviceExtension->IrpPendingCount--;
359
360 //
361 // check if this was our current active SRB
362 //
363 if (FDODeviceExtension->ActiveSrb == Request)
364 {
365 //
366 // indicate processing is completed
367 //
368 FDODeviceExtension->ActiveSrb = NULL;
369 }
370
371 //
372 // Set the event if nothing else is pending
373 //
374 if (FDODeviceExtension->IrpPendingCount == 0 &&
375 FDODeviceExtension->ActiveSrb == NULL)
376 {
377 KeSetEvent(&FDODeviceExtension->NoPendingRequests, IO_NO_INCREMENT, FALSE);
378 }
379
380 //
381 // release lock
382 //
383 KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
384
385 }
386
387 VOID
388 USBSTOR_QueueNextRequest(
389 IN PDEVICE_OBJECT DeviceObject)
390 {
391 PFDO_DEVICE_EXTENSION FDODeviceExtension;
392 PIRP Irp;
393 PIO_STACK_LOCATION IoStack;
394 PSCSI_REQUEST_BLOCK Request;
395
396 //
397 // get pdo device extension
398 //
399 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
400
401 //
402 // sanity check
403 //
404 ASSERT(FDODeviceExtension->Common.IsFDO);
405
406 //
407 // check first if there's already a request pending or the queue is frozen
408 //
409 if (FDODeviceExtension->ActiveSrb != NULL ||
410 FDODeviceExtension->IrpListFreeze)
411 {
412 //
413 // no work to do yet
414 //
415 return;
416 }
417
418 //
419 // remove first irp from list
420 //
421 Irp = USBSTOR_RemoveIrp(DeviceObject);
422
423 //
424 // is there an irp pending
425 //
426 if (!Irp)
427 {
428 //
429 // no work to do
430 //
431 IoStartNextPacket(DeviceObject, TRUE);
432 return;
433 }
434
435 //
436 // get current stack location
437 //
438 IoStack = IoGetCurrentIrpStackLocation(Irp);
439
440 //
441 // get srb
442 //
443 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
444
445 //
446 // sanity check
447 //
448 ASSERT(Request);
449
450 //
451 // set the active SRB
452 //
453 FDODeviceExtension->ActiveSrb = Request;
454
455 //
456 // start next packet
457 //
458 IoStartPacket(DeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo);
459
460 //
461 // start next request
462 //
463 IoStartNextPacket(DeviceObject, TRUE);
464 }
465
466 VOID
467 USBSTOR_QueueRelease(
468 IN PDEVICE_OBJECT DeviceObject)
469 {
470 PFDO_DEVICE_EXTENSION FDODeviceExtension;
471 PIRP Irp;
472 KIRQL OldLevel;
473 PIO_STACK_LOCATION IoStack;
474 PSCSI_REQUEST_BLOCK Request;
475
476 //
477 // get FDO device extension
478 //
479 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
480
481 //
482 // sanity check
483 //
484 ASSERT(FDODeviceExtension->Common.IsFDO);
485
486 //
487 // acquire lock
488 //
489 KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
490
491 //
492 // clear freezed status
493 //
494 FDODeviceExtension->IrpListFreeze = FALSE;
495
496 //
497 // release irp list lock
498 //
499 KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
500
501 //
502 // grab newest irp
503 //
504 Irp = USBSTOR_RemoveIrp(DeviceObject);
505
506 //
507 // is there an irp
508 //
509 if (!Irp)
510 {
511 //
512 // no irp
513 //
514 return;
515 }
516
517 //
518 // get current irp stack location
519 //
520 IoStack = IoGetCurrentIrpStackLocation(Irp);
521
522 //
523 // get srb
524 //
525 Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
526
527 //
528 // start new packet
529 //
530 IoStartPacket(DeviceObject,
531 Irp,
532 &Request->QueueSortKey,
533 USBSTOR_CancelIo);
534 }
535
536
537 VOID
538 NTAPI
539 USBSTOR_StartIo(
540 PDEVICE_OBJECT DeviceObject,
541 PIRP Irp)
542 {
543 PIO_STACK_LOCATION IoStack;
544 PFDO_DEVICE_EXTENSION FDODeviceExtension;
545 PPDO_DEVICE_EXTENSION PDODeviceExtension;
546 KIRQL OldLevel;
547 NTSTATUS Status;
548 BOOLEAN ResetInProgress;
549
550 DPRINT("USBSTOR_StartIo\n");
551
552 //
553 // get FDO device extension
554 //
555 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
556
557 //
558 // sanity check
559 //
560 ASSERT(FDODeviceExtension->Common.IsFDO);
561
562 //
563 // acquire cancel spinlock
564 //
565 IoAcquireCancelSpinLock(&OldLevel);
566
567 //
568 // set cancel routine to zero
569 //
570 IoSetCancelRoutine(Irp, NULL);
571
572 //
573 // check if the irp has been cancelled
574 //
575 if (Irp->Cancel)
576 {
577 //
578 // irp has been cancelled, release cancel spinlock
579 //
580 IoReleaseCancelSpinLock(OldLevel);
581
582 //
583 // irp is cancelled
584 //
585 Irp->IoStatus.Status = STATUS_CANCELLED;
586 Irp->IoStatus.Information = 0;
587
588 //
589 // terminate request
590 //
591 USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
592
593 //
594 // complete request
595 //
596 IoCompleteRequest(Irp, IO_NO_INCREMENT);
597
598 //
599 // queue next request
600 //
601 USBSTOR_QueueNextRequest(DeviceObject);
602
603 //
604 // done
605 //
606 return;
607 }
608
609 //
610 // release cancel spinlock
611 //
612 IoReleaseCancelSpinLock(OldLevel);
613
614 //
615 // acquire lock
616 //
617 KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
618
619 //
620 // check reset is in progress
621 //
622 ResetInProgress = FDODeviceExtension->ResetInProgress;
623 ASSERT(ResetInProgress == FALSE);
624
625 //
626 // release lock
627 //
628 KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
629
630 //
631 // get current irp stack location
632 //
633 IoStack = IoGetCurrentIrpStackLocation(Irp);
634
635 //
636 // get pdo device extension
637 //
638 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
639
640 //
641 // sanity check
642 //
643 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
644
645 //
646 // is a reset in progress
647 //
648 if (ResetInProgress)
649 {
650 //
651 // hard reset is in progress
652 //
653 Irp->IoStatus.Information = 0;
654 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
655 USBSTOR_QueueTerminateRequest(DeviceObject, Irp);
656 IoCompleteRequest(Irp, IO_NO_INCREMENT);
657 return;
658 }
659
660 //
661 // execute scsi
662 //
663 Status = USBSTOR_HandleExecuteSCSI(IoStack->DeviceObject, Irp, 0);
664
665 //
666 // FIXME: handle error
667 //
668 }