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