Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363/* * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: USB block storage device driver. * COPYRIGHT: 2005-2006 James Tabor * 2011-2012 Michael Martin (michael.martin@reactos.org) * 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org) */
#include "usbstor.h"
#define NDEBUG#include <debug.h>
VOIDUSBSTOR_QueueInitialize( PFDO_DEVICE_EXTENSION FDODeviceExtension){ ASSERT(FDODeviceExtension->Common.IsFDO); KeInitializeSpinLock(&FDODeviceExtension->IrpListLock); InitializeListHead(&FDODeviceExtension->IrpListHead); KeInitializeEvent(&FDODeviceExtension->NoPendingRequests, NotificationEvent, TRUE);}
VOIDNTAPIUSBSTOR_CancelIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ PFDO_DEVICE_EXTENSION FDODeviceExtension;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT_IRQL_EQUAL(DISPATCH_LEVEL); ASSERT(FDODeviceExtension->Common.IsFDO);
// this IRP isn't in our list here // now release the cancel lock IoReleaseCancelSpinLock(Irp->CancelIrql); Irp->IoStatus.Status = STATUS_CANCELLED;
USBSTOR_QueueTerminateRequest(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT);
USBSTOR_QueueNextRequest(DeviceObject);}
VOIDNTAPIUSBSTOR_Cancel( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ PFDO_DEVICE_EXTENSION FDODeviceExtension;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT_IRQL_EQUAL(DISPATCH_LEVEL); ASSERT(FDODeviceExtension->Common.IsFDO);
KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock); RemoveEntryList(&Irp->Tail.Overlay.ListEntry); KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock);
IoReleaseCancelSpinLock(Irp->CancelIrql); Irp->IoStatus.Status = STATUS_CANCELLED;
USBSTOR_QueueTerminateRequest(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT);
USBSTOR_QueueNextRequest(DeviceObject);}
BOOLEANUSBSTOR_QueueAddIrp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ PDRIVER_CANCEL OldDriverCancel; KIRQL OldLevel; PFDO_DEVICE_EXTENSION FDODeviceExtension; BOOLEAN IrpListFreeze; BOOLEAN SrbProcessing; PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
IoMarkIrpPending(Irp);
KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
SrbProcessing = FDODeviceExtension->IrpPendingCount != 0;
if (SrbProcessing) { // add irp to queue InsertTailList(&FDODeviceExtension->IrpListHead, &Irp->Tail.Overlay.ListEntry); }
FDODeviceExtension->IrpPendingCount++; KeClearEvent(&FDODeviceExtension->NoPendingRequests);
// check if queue is freezed IrpListFreeze = BooleanFlagOn(FDODeviceExtension->Flags, USBSTOR_FDO_FLAGS_IRP_LIST_FREEZE);
KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
// synchronize with cancellations by holding the cancel lock IoAcquireCancelSpinLock(&Irp->CancelIrql);
if (SrbProcessing) { ASSERT(FDODeviceExtension->ActiveSrb != NULL);
OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_Cancel); } else { ASSERT(FDODeviceExtension->ActiveSrb == NULL);
FDODeviceExtension->ActiveSrb = Request; OldDriverCancel = IoSetCancelRoutine(Irp, USBSTOR_CancelIo); }
// check if the irp has already been cancelled if (Irp->Cancel && OldDriverCancel == NULL) { // cancel irp Irp->CancelRoutine(DeviceObject, Irp); return FALSE; }
IoReleaseCancelSpinLock(Irp->CancelIrql);
// if list is freezed, dont start this packet DPRINT("IrpListFreeze: %lu IrpPendingCount %lu\n", IrpListFreeze, FDODeviceExtension->IrpPendingCount);
return (IrpListFreeze || SrbProcessing);}
PIRPUSBSTOR_RemoveIrp( IN PDEVICE_OBJECT DeviceObject){ KIRQL OldLevel; PFDO_DEVICE_EXTENSION FDODeviceExtension; PLIST_ENTRY Entry; PIRP Irp = NULL;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
if (!IsListEmpty(&FDODeviceExtension->IrpListHead)) { Entry = RemoveHeadList(&FDODeviceExtension->IrpListHead);
// get offset to start of irp Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); }
KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
return Irp;}
VOIDUSBSTOR_QueueWaitForPendingRequests( IN PDEVICE_OBJECT DeviceObject){ PFDO_DEVICE_EXTENSION FDODeviceExtension;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
KeWaitForSingleObject(&FDODeviceExtension->NoPendingRequests, Executive, KernelMode, FALSE, NULL);}
VOIDUSBSTOR_QueueTerminateRequest( IN PDEVICE_OBJECT FDODeviceObject, IN PIRP Irp){ KIRQL OldLevel; PFDO_DEVICE_EXTENSION FDODeviceExtension; PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp); PSCSI_REQUEST_BLOCK Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FDODeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
FDODeviceExtension->IrpPendingCount--;
// check if this was our current active SRB if (FDODeviceExtension->ActiveSrb == Request) { // indicate processing is completed FDODeviceExtension->ActiveSrb = NULL; }
// Set the event if nothing else is pending if (FDODeviceExtension->IrpPendingCount == 0 && FDODeviceExtension->ActiveSrb == NULL) { KeSetEvent(&FDODeviceExtension->NoPendingRequests, IO_NO_INCREMENT, FALSE); }
KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);}
VOIDUSBSTOR_QueueNextRequest( IN PDEVICE_OBJECT DeviceObject){ PFDO_DEVICE_EXTENSION FDODeviceExtension; PIRP Irp; PIO_STACK_LOCATION IoStack; PSCSI_REQUEST_BLOCK Request;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
// check first if there's already a request pending or the queue is frozen if (FDODeviceExtension->ActiveSrb != NULL || BooleanFlagOn(FDODeviceExtension->Flags, USBSTOR_FDO_FLAGS_IRP_LIST_FREEZE)) { // no work to do yet return; }
// remove first irp from list Irp = USBSTOR_RemoveIrp(DeviceObject);
// is there an irp pending if (!Irp) { // no work to do IoStartNextPacket(DeviceObject, TRUE); return; }
IoStack = IoGetCurrentIrpStackLocation(Irp); Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; ASSERT(Request);
FDODeviceExtension->ActiveSrb = Request;
// start next packet IoStartPacket(DeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo); IoStartNextPacket(DeviceObject, TRUE);}
VOIDUSBSTOR_QueueRelease( IN PDEVICE_OBJECT DeviceObject){ PFDO_DEVICE_EXTENSION FDODeviceExtension; PIRP Irp; KIRQL OldLevel; PIO_STACK_LOCATION IoStack; PSCSI_REQUEST_BLOCK Request;
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel);
// clear freezed status FDODeviceExtension->Flags &= ~USBSTOR_FDO_FLAGS_IRP_LIST_FREEZE;
KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel);
// grab newest irp Irp = USBSTOR_RemoveIrp(DeviceObject);
if (!Irp) { return; }
IoStack = IoGetCurrentIrpStackLocation(Irp); Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
IoStartPacket(DeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo);}
VOIDNTAPIUSBSTOR_StartIo( PDEVICE_OBJECT DeviceObject, PIRP Irp){ PIO_STACK_LOCATION IoStack; PSCSI_REQUEST_BLOCK Request; PFDO_DEVICE_EXTENSION FDODeviceExtension; PPDO_DEVICE_EXTENSION PDODeviceExtension; KIRQL OldLevel; BOOLEAN ResetInProgress;
DPRINT("USBSTOR_StartIo\n");
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
IoAcquireCancelSpinLock(&OldLevel);
IoSetCancelRoutine(Irp, NULL);
// check if the irp has been cancelled if (Irp->Cancel) { IoReleaseCancelSpinLock(OldLevel);
Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0;
USBSTOR_QueueTerminateRequest(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); USBSTOR_QueueNextRequest(DeviceObject); return; }
IoReleaseCancelSpinLock(OldLevel);
KeAcquireSpinLock(&FDODeviceExtension->CommonLock, &OldLevel); ResetInProgress = BooleanFlagOn(FDODeviceExtension->Flags, USBSTOR_FDO_FLAGS_DEVICE_RESETTING); KeReleaseSpinLock(&FDODeviceExtension->CommonLock, OldLevel);
IoStack = IoGetCurrentIrpStackLocation(Irp);
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension; Request = IoStack->Parameters.Scsi.Srb; ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
if (ResetInProgress) { // hard reset is in progress Request->SrbStatus = SRB_STATUS_NO_DEVICE; Request->DataTransferLength = 0; Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; USBSTOR_QueueTerminateRequest(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); USBSTOR_QueueNextRequest(DeviceObject); return; }
USBSTOR_HandleExecuteSCSI(IoStack->DeviceObject, Irp);
// FIXME: handle error}