/* * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/usb/usbstor/queue.c * PURPOSE: USB block storage device driver. * PROGRAMMERS: * James Tabor * Michael Martin (michael.martin@reactos.org) * Johannes Anderwald (johannes.anderwald@reactos.org) */ #include "usbstor.h" #define NDEBUG #include VOID USBSTOR_QueueInitialize( PFDO_DEVICE_EXTENSION FDODeviceExtension) { // // sanity check // ASSERT(FDODeviceExtension->Common.IsFDO); // // initialize queue lock // KeInitializeSpinLock(&FDODeviceExtension->IrpListLock); // // initialize irp list head // InitializeListHead(&FDODeviceExtension->IrpListHead); // // initialize event // KeInitializeEvent(&FDODeviceExtension->NoPendingRequests, NotificationEvent, TRUE); } VOID NTAPI USBSTOR_CancelIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PFDO_DEVICE_EXTENSION FDODeviceExtension; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); ASSERT(FDODeviceExtension->Common.IsFDO); // // this IRP isn't in our list here // // // now release the cancel lock // IoReleaseCancelSpinLock(Irp->CancelIrql); // // set cancel status // Irp->IoStatus.Status = STATUS_CANCELLED; // // now cancel the irp // USBSTOR_QueueTerminateRequest(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); // // start the next one // USBSTOR_QueueNextRequest(DeviceObject); } VOID NTAPI USBSTOR_Cancel( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PFDO_DEVICE_EXTENSION FDODeviceExtension; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); ASSERT(FDODeviceExtension->Common.IsFDO); // // acquire irp list lock // KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock); // // remove the irp from the list // RemoveEntryList(&Irp->Tail.Overlay.ListEntry); // // release irp list lock // KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock); // // now release the cancel lock // IoReleaseCancelSpinLock(Irp->CancelIrql); // // set cancel status // Irp->IoStatus.Status = STATUS_CANCELLED; // // now cancel the irp // USBSTOR_QueueTerminateRequest(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); // // start the next one // USBSTOR_QueueNextRequest(DeviceObject); } BOOLEAN USBSTOR_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; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(FDODeviceExtension->Common.IsFDO); // // mark irp pending // IoMarkIrpPending(Irp); // // acquire lock // KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); // // check if there are irp pending // SrbProcessing = FDODeviceExtension->IrpPendingCount != 0; if (SrbProcessing) { // // add irp to queue // InsertTailList(&FDODeviceExtension->IrpListHead, &Irp->Tail.Overlay.ListEntry); } // // increment pending count // FDODeviceExtension->IrpPendingCount++; // // clear the no requests pending event // KeClearEvent(&FDODeviceExtension->NoPendingRequests); // // check if queue is freezed // IrpListFreeze = FDODeviceExtension->IrpListFreeze; // // release list lock // KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); // // synchronize with cancellations by holding the cancel lock // IoAcquireCancelSpinLock(&Irp->CancelIrql); // // now set the driver cancel routine // 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); // // irp was cancelled // return FALSE; } // // release the cancel lock // IoReleaseCancelSpinLock(Irp->CancelIrql); // // if list is freezed, dont start this packet // DPRINT("IrpListFreeze: %lu IrpPendingCount %lu\n", IrpListFreeze, FDODeviceExtension->IrpPendingCount); return (IrpListFreeze || SrbProcessing); } PIRP USBSTOR_RemoveIrp( IN PDEVICE_OBJECT DeviceObject) { KIRQL OldLevel; PFDO_DEVICE_EXTENSION FDODeviceExtension; PLIST_ENTRY Entry; PIRP Irp = NULL; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(FDODeviceExtension->Common.IsFDO); // // acquire lock // KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); // // check if list is empty // if (!IsListEmpty(&FDODeviceExtension->IrpListHead)) { // // remove entry // Entry = RemoveHeadList(&FDODeviceExtension->IrpListHead); // // get offset to start of irp // Irp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); } // // release list lock // KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); // // return result // return Irp; } VOID USBSTOR_QueueWaitForPendingRequests( IN PDEVICE_OBJECT DeviceObject) { PFDO_DEVICE_EXTENSION FDODeviceExtension; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // perform the wait // KeWaitForSingleObject(&FDODeviceExtension->NoPendingRequests, Executive, KernelMode, FALSE, NULL); } VOID USBSTOR_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; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)FDODeviceObject->DeviceExtension; // // sanity check // ASSERT(FDODeviceExtension->Common.IsFDO); // // acquire lock // KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); // // decrement pending irp count // 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); } // // release lock // KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); } VOID USBSTOR_QueueNextRequest( IN PDEVICE_OBJECT DeviceObject) { PFDO_DEVICE_EXTENSION FDODeviceExtension; PIRP Irp; PIO_STACK_LOCATION IoStack; PSCSI_REQUEST_BLOCK Request; // // get pdo device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(FDODeviceExtension->Common.IsFDO); // // check first if there's already a request pending or the queue is frozen // if (FDODeviceExtension->ActiveSrb != NULL || FDODeviceExtension->IrpListFreeze) { // // 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; } // // get current stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); // // get srb // Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; // // sanity check // ASSERT(Request); // // set the active SRB // FDODeviceExtension->ActiveSrb = Request; // // start next packet // IoStartPacket(DeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo); // // start next request // IoStartNextPacket(DeviceObject, TRUE); } VOID USBSTOR_QueueRelease( IN PDEVICE_OBJECT DeviceObject) { PFDO_DEVICE_EXTENSION FDODeviceExtension; PIRP Irp; KIRQL OldLevel; PIO_STACK_LOCATION IoStack; PSCSI_REQUEST_BLOCK Request; // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(FDODeviceExtension->Common.IsFDO); // // acquire lock // KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); // // clear freezed status // FDODeviceExtension->IrpListFreeze = FALSE; // // release irp list lock // KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); // // grab newest irp // Irp = USBSTOR_RemoveIrp(DeviceObject); // // is there an irp // if (!Irp) { // // no irp // return; } // // get current irp stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); // // get srb // Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; // // start new packet // IoStartPacket(DeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo); } VOID NTAPI USBSTOR_StartIo( PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION IoStack; PFDO_DEVICE_EXTENSION FDODeviceExtension; PPDO_DEVICE_EXTENSION PDODeviceExtension; KIRQL OldLevel; BOOLEAN ResetInProgress; DPRINT("USBSTOR_StartIo\n"); // // get FDO device extension // FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; // // sanity check // ASSERT(FDODeviceExtension->Common.IsFDO); // // acquire cancel spinlock // IoAcquireCancelSpinLock(&OldLevel); // // set cancel routine to zero // IoSetCancelRoutine(Irp, NULL); // // check if the irp has been cancelled // if (Irp->Cancel) { // // irp has been cancelled, release cancel spinlock // IoReleaseCancelSpinLock(OldLevel); // // irp is cancelled // Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; // // terminate request // USBSTOR_QueueTerminateRequest(DeviceObject, Irp); // // complete request // IoCompleteRequest(Irp, IO_NO_INCREMENT); // // queue next request // USBSTOR_QueueNextRequest(DeviceObject); // // done // return; } // // release cancel spinlock // IoReleaseCancelSpinLock(OldLevel); // // acquire lock // KeAcquireSpinLock(&FDODeviceExtension->IrpListLock, &OldLevel); // // check reset is in progress // ResetInProgress = FDODeviceExtension->ResetInProgress; ASSERT(ResetInProgress == FALSE); // // release lock // KeReleaseSpinLock(&FDODeviceExtension->IrpListLock, OldLevel); // // get current irp stack location // IoStack = IoGetCurrentIrpStackLocation(Irp); // // get pdo device extension // PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension; // // sanity check // ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); // // is a reset in progress // if (ResetInProgress) { // // hard reset is in progress // Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; USBSTOR_QueueTerminateRequest(DeviceObject, Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); return; } // // execute scsi // USBSTOR_HandleExecuteSCSI(IoStack->DeviceObject, Irp, 0); // // FIXME: handle error // }