[USBSTOR] Do not try to retry a failed request
[reactos.git] / drivers / usb / usbstor / scsi.c
index 4c7c3ef..002b8f2 100644 (file)
@@ -5,6 +5,8 @@
  * COPYRIGHT:   2005-2006 James Tabor
  *              2011-2012 Michael Martin (michael.martin@reactos.org)
  *              2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
+ *              2017 Vadim Galyant
+ *              2019 Victor Perevertkin (victor.perevertkin@reactos.org)
  */
 
 #include "usbstor.h"
 #include <debug.h>
 
 
+static
 NTSTATUS
-USBSTOR_BuildCBW(
-    IN ULONG Tag,
-    IN ULONG DataTransferLength,
-    IN UCHAR LUN,
-    IN UCHAR CommandBlockLength,
-    IN PUCHAR CommandBlock,
-    IN OUT PCBW Control)
+USBSTOR_SrbStatusToNtStatus(
+    IN PSCSI_REQUEST_BLOCK Srb)
 {
-    ASSERT(CommandBlockLength <= 16);
+    UCHAR SrbStatus;
 
-    Control->Signature = CBW_SIGNATURE;
-    Control->Tag = Tag;
-    Control->DataTransferLength = DataTransferLength;
-    Control->Flags = (CommandBlock[0] != SCSIOP_WRITE) ? 0x80 : 0x00;
-    Control->LUN = (LUN & MAX_LUN);
-    Control->CommandBlockLength = CommandBlockLength;
+    SrbStatus = SRB_STATUS(Srb->SrbStatus);
 
-    RtlCopyMemory(Control->CommandBlock, CommandBlock, CommandBlockLength);
+    switch (SrbStatus)
+    {
+        case SRB_STATUS_SUCCESS:
+            return STATUS_SUCCESS;
+
+        case SRB_STATUS_DATA_OVERRUN:
+            return STATUS_BUFFER_OVERFLOW;
+
+        case SRB_STATUS_BAD_FUNCTION:
+        case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+            return STATUS_INVALID_DEVICE_REQUEST;
+
+        case SRB_STATUS_INVALID_LUN:
+        case SRB_STATUS_INVALID_TARGET_ID:
+        case SRB_STATUS_NO_HBA:
+        case SRB_STATUS_NO_DEVICE:
+            return STATUS_DEVICE_DOES_NOT_EXIST;
+
+        case SRB_STATUS_TIMEOUT:
+            return STATUS_IO_TIMEOUT;
 
-    return STATUS_SUCCESS;
+        case SRB_STATUS_BUS_RESET:
+        case SRB_STATUS_COMMAND_TIMEOUT:
+        case SRB_STATUS_SELECTION_TIMEOUT:
+            return STATUS_DEVICE_NOT_CONNECTED;
+
+        default:
+            return STATUS_IO_DEVICE_ERROR;
+    }
 }
 
-PIRP_CONTEXT
-USBSTOR_AllocateIrpContext()
+static
+NTSTATUS
+USBSTOR_IssueBulkOrInterruptRequest(
+    IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
+    IN PIRP Irp,
+    IN USBD_PIPE_HANDLE PipeHandle,
+    IN ULONG TransferFlags,
+    IN ULONG TransferBufferLength,
+    IN PVOID TransferBuffer,
+    IN PMDL TransferBufferMDL,
+    IN PIO_COMPLETION_ROUTINE CompletionRoutine,
+    IN PIRP_CONTEXT Context)
 {
-    PIRP_CONTEXT Context;
+    PIO_STACK_LOCATION NextStack;
 
-    Context = (PIRP_CONTEXT)AllocateItem(NonPagedPool, sizeof(IRP_CONTEXT));
-    if (!Context)
-    {
-        return NULL;
-    }
+    RtlZeroMemory(&Context->Urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
 
-    Context->cbw = (PCBW)AllocateItem(NonPagedPool, 512);
-    if (!Context->cbw)
-    {
-        FreeItem(Context);
-        return NULL;
-    }
+    Context->Urb.UrbHeader.Length = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
+    Context->Urb.UrbHeader.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
 
-    return Context;
+    Context->Urb.UrbBulkOrInterruptTransfer.PipeHandle = PipeHandle;
+    Context->Urb.UrbBulkOrInterruptTransfer.TransferFlags = TransferFlags;
+    Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferLength = TransferBufferLength;
+    Context->Urb.UrbBulkOrInterruptTransfer.TransferBuffer = TransferBuffer;
+    Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferMDL = TransferBufferMDL;
+
+    NextStack = IoGetNextIrpStackLocation(Irp); 
+    NextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 
+    NextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB; 
+    NextStack->Parameters.Others.Argument1 = &Context->Urb; 
+
+    IoSetCompletionRoutine(Irp,
+                           CompletionRoutine,
+                           Context,
+                           TRUE,
+                           TRUE,
+                           TRUE); 
+
+    return IoCallDriver(FDODeviceExtension->LowerDeviceObject, Irp);
 }
 
+static
 BOOLEAN
 USBSTOR_IsCSWValid(
     PIRP_CONTEXT Context)
 {
-    if (Context->csw->Signature != CSW_SIGNATURE)
-    {
-        DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw->Signature);
-        return FALSE;
-    }
-
-    if (Context->csw->Tag != (ULONG_PTR)Context->csw)
+    if (Context->csw.Signature != CSW_SIGNATURE)
     {
-        DPRINT1("[USBSTOR] Expected Tag %Ix but got %x\n", (ULONG_PTR)Context->csw, Context->csw->Tag);
+        DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw.Signature);
         return FALSE;
     }
 
-    if (Context->csw->Status != 0x00)
+    if (Context->csw.Tag != PtrToUlong(&Context->csw))
     {
-        DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status);
+        DPRINT1("[USBSTOR] Expected Tag %Ix but got %x\n", PtrToUlong(&Context->csw), Context->csw.Tag);
         return FALSE;
     }
 
@@ -116,6 +150,13 @@ USBSTOR_QueueWorkItem(
     return STATUS_MORE_PROCESSING_REQUIRED;
 }
 
+static
+NTSTATUS
+USBSTOR_IssueRequestSense(
+    IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
+    IN PIRP Irp,
+    IN PIRP_CONTEXT Context);
+
 IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine;
 
 NTSTATUS
@@ -127,156 +168,138 @@ USBSTOR_CSWCompletionRoutine(
 {
     PIRP_CONTEXT Context;
     PIO_STACK_LOCATION IoStack;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PFDO_DEVICE_EXTENSION FDODeviceExtension;
     PSCSI_REQUEST_BLOCK Request;
-    PCDB pCDB;
-    PREAD_CAPACITY_DATA_EX CapacityDataEx;
-    PREAD_CAPACITY_DATA CapacityData;
     PUFI_CAPACITY_RESPONSE Response;
     NTSTATUS Status;
 
     Context = (PIRP_CONTEXT)Ctx;
 
-    if (Context->TransferBufferMDL)
+    DPRINT("USBSTOR_CSWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
+
+    // first check for Irp errors
+    if (!NT_SUCCESS(Irp->IoStatus.Status))
     {
-        // is there an irp associated
-        if (Context->Irp)
+        if (USBD_STATUS(Context->Urb.UrbHeader.Status) == USBD_STATUS(USBD_STATUS_STALL_PID))
         {
-            // did we allocate the mdl
-            if (Context->TransferBufferMDL != Context->Irp->MdlAddress)
+            if (Context->StallRetryCount < 2)
             {
-                IoFreeMdl(Context->TransferBufferMDL);
+                ++Context->StallRetryCount;
+
+                // clear stall and resend cbw
+                Context->ErrorIndex = 1;
+                Status = USBSTOR_QueueWorkItem(Context, Irp);
+                ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
+
+                return STATUS_MORE_PROCESSING_REQUIRED;
             }
         }
         else
         {
-            IoFreeMdl(Context->TransferBufferMDL);
-        }
-    }
-
-    DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status);
-
-    if (!NT_SUCCESS(Irp->IoStatus.Information))
-    {
-        if (Context->ErrorIndex == 0)
-        {
-            Context->ErrorIndex = 1;
-
-            // clear stall and resend cbw
-            Status = USBSTOR_QueueWorkItem(Context, Irp);
-            ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
-            return STATUS_MORE_PROCESSING_REQUIRED;
+            DPRINT1("USBSTOR_CSWCompletionRoutine: Urb.Hdr.Status - %x\n", Context->Urb.UrbHeader.Status);
         }
 
         // perform reset recovery
         Context->ErrorIndex = 2;
-        IoFreeIrp(Irp);
         Status = USBSTOR_QueueWorkItem(Context, NULL);
         ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
         return STATUS_MORE_PROCESSING_REQUIRED;
     }
 
-    if (!USBSTOR_IsCSWValid(Context))
+    // now check the CSW packet validity
+    if (!USBSTOR_IsCSWValid(Context) || Context->csw.Status == CSW_STATUS_PHASE_ERROR)
     {
         // perform reset recovery
         Context->ErrorIndex = 2;
-        IoFreeIrp(Irp);
         Status = USBSTOR_QueueWorkItem(Context, NULL);
         ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
         return STATUS_MORE_PROCESSING_REQUIRED;
     }
 
-
-    IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
-
-    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
+    FDODeviceExtension = Context->FDODeviceExtension;
+    Request = IoStack->Parameters.Scsi.Srb;
     ASSERT(Request);
 
-    Status = Irp->IoStatus.Status;
-
-    pCDB = (PCDB)Request->Cdb;
-    Request->SrbStatus = SRB_STATUS_SUCCESS;
-
-    // read capacity needs special work
-    if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
+    // finally check for CSW errors
+    if (Context->csw.Status == CSW_STATUS_COMMAND_PASSED)
     {
-        // get output buffer
-        Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData;
-
-        // store in pdo
-        Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
-        Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);
+        // should happen only when a sense request was sent
+        if (Request != FDODeviceExtension->ActiveSrb)
+        {
+            ASSERT(IoStack->Parameters.Scsi.Srb == &Context->SenseSrb);
+            FDODeviceExtension->ActiveSrb->SenseInfoBufferLength = Request->DataTransferLength;
+            Request = FDODeviceExtension->ActiveSrb;
+            IoStack->Parameters.Scsi.Srb = Request;
+            Request->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+        }
 
-        if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX))
+        // read capacity needs special work
+        if (Request->Cdb[0] == SCSIOP_READ_CAPACITY)
         {
-            // get input buffer
-            CapacityDataEx = (PREAD_CAPACITY_DATA_EX)Request->DataBuffer;
-
-            // set result
-            CapacityDataEx->BytesPerBlock = Response->BlockLength;
-            CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress;
-            Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX);
-       }
-       else
-       {
-            // get input buffer
-            CapacityData = (PREAD_CAPACITY_DATA)Request->DataBuffer;
-
-            // set result
-            CapacityData->BytesPerBlock = Response->BlockLength;
-            CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress;
-            Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
-       }
-
-       FreeItem(Context->TransferData);
-    }
+            // get output buffer
+            Response = (PUFI_CAPACITY_RESPONSE)Request->DataBuffer;
 
-    FreeItem(Context->cbw);
+            // store in pdo
+            PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
+            PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);
+        }
 
-    // FIXME: check status
-    Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
-    Context->Irp->IoStatus.Information = Context->TransferDataLength;
+        Status = USBSTOR_SrbStatusToNtStatus(Request);
+    }
+    else if (Context->csw.Status == CSW_STATUS_COMMAND_FAILED)
+    {
+        // the command is correct but with failed status - issue request sense
+        DPRINT("USBSTOR_CSWCompletionRoutine: CSW_STATUS_COMMAND_FAILED\n");
+
+        ASSERT(FDODeviceExtension->ActiveSrb == Request);
+        
+        // setting a generic error status, additional information
+        // should be read by higher-level driver from SenseInfoBuffer
+        Request->SrbStatus = SRB_STATUS_ERROR;
+        Request->ScsiStatus = 2;
+        Request->DataTransferLength = 0;
+
+        DPRINT("Flags: %x SBL: %x, buf: %p\n", Request->SrbFlags, Request->SenseInfoBufferLength, Request->SenseInfoBuffer);
+
+        if (!(Request->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) &&
+              Request->SenseInfoBufferLength &&
+              Request->SenseInfoBuffer)
+        {
+            USBSTOR_IssueRequestSense(FDODeviceExtension, Irp, Context);
+            return STATUS_MORE_PROCESSING_REQUIRED;
+        }
 
-    // terminate current request
-    USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp);
+        Status = STATUS_IO_DEVICE_ERROR;
+    }
 
-    IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = Request->DataTransferLength;
 
-    USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
+    // terminate current request
+    USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
+    USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
 
-    IoFreeIrp(Irp);
-    FreeItem(Context);
-    return STATUS_MORE_PROCESSING_REQUIRED;
+    ExFreePoolWithTag(Context, USB_STOR_TAG);
+    return Status;
 }
 
-VOID
-USBSTOR_SendCSW(
+NTSTATUS
+USBSTOR_SendCSWRequest(
     PIRP_CONTEXT Context,
     PIRP Irp)
 {
-    PIO_STACK_LOCATION IoStack;
-
-    IoStack = IoGetNextIrpStackLocation(Irp);
-
-    // now initialize the urb for sending the csw
-    UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
-                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
-                                           Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
-                                           Context->csw,
-                                           NULL,
-                                           512, //FIXME
-                                           USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
-                                           NULL);
-
-    // initialize stack location
-    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
-    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
-    IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
-    IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
-    Irp->IoStatus.Status = STATUS_SUCCESS;
-
-    IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
-
-    IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
+    return USBSTOR_IssueBulkOrInterruptRequest(Context->FDODeviceExtension,
+                                               Irp,
+                                               Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
+                                               USBD_TRANSFER_DIRECTION_IN,
+                                               sizeof(CSW),
+                                               &Context->csw,
+                                               NULL,
+                                               USBSTOR_CSWCompletionRoutine,
+                                               Context);
 }
 
 IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine;
@@ -290,22 +313,55 @@ USBSTOR_DataCompletionRoutine(
 {
     PIRP_CONTEXT Context;
     NTSTATUS Status;
-
+    PIO_STACK_LOCATION IoStack;
+    PSCSI_REQUEST_BLOCK Request;
 
     DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
 
     Context = (PIRP_CONTEXT)Ctx;
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    Request = IoStack->Parameters.Scsi.Srb;
 
-    if (!NT_SUCCESS(Irp->IoStatus.Status))
+    // for Sense Request a partial MDL was already freed (if existed)
+    if (Request == Context->FDODeviceExtension->ActiveSrb &&
+        Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferMDL != Irp->MdlAddress)
     {
+        IoFreeMdl(Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferMDL);
+    }
+
+    if (NT_SUCCESS(Irp->IoStatus.Status))
+    {
+        if (Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferLength < Request->DataTransferLength)
+        {
+            Request->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+        }
+        else
+        {
+            Request->SrbStatus = SRB_STATUS_SUCCESS;
+        }
+
+        Request->DataTransferLength = Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferLength;
+        USBSTOR_SendCSWRequest(Context, Irp);
+    }
+    else if (USBD_STATUS(Context->Urb.UrbHeader.Status) == USBD_STATUS(USBD_STATUS_STALL_PID))
+    {
+        ++Context->StallRetryCount;
+
+        Request->SrbStatus = SRB_STATUS_DATA_OVERRUN;
+        Request->DataTransferLength = Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferLength;
+
         // clear stall and resend cbw
         Context->ErrorIndex = 1;
         Status = USBSTOR_QueueWorkItem(Context, Irp);
         ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
-        return STATUS_MORE_PROCESSING_REQUIRED;
     }
-
-    USBSTOR_SendCSW(Context, Irp);
+    else
+    {
+        // perform reset recovery
+        Context->ErrorIndex = 2;
+        Status = USBSTOR_QueueWorkItem(Context, NULL);
+        ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
+    }
 
     return STATUS_MORE_PROCESSING_REQUIRED;
 }
@@ -321,663 +377,244 @@ USBSTOR_CBWCompletionRoutine(
 {
     PIRP_CONTEXT Context;
     PIO_STACK_LOCATION IoStack;
-    UCHAR Code;
+    PSCSI_REQUEST_BLOCK Request;
     USBD_PIPE_HANDLE PipeHandle;
+    ULONG TransferFlags;
+    PMDL Mdl = NULL;
+    PVOID TransferBuffer = NULL;
+    NTSTATUS Status;
 
     DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
 
     Context = (PIRP_CONTEXT)Ctx;
-    IoStack = IoGetNextIrpStackLocation(Irp);
+    IoStack = IoGetCurrentIrpStackLocation(Irp);
+    Request = IoStack->Parameters.Scsi.Srb;
 
-    // is there data to be submitted
-    if (Context->TransferDataLength)
+    if (!NT_SUCCESS(Irp->IoStatus.Status))
     {
-        // get command code
-        Code = Context->cbw->CommandBlock[0];
+        goto ResetRecovery;
+    }
 
-        if (Code == SCSIOP_WRITE)
-        {
-            // write request - use bulk out pipe
-            PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
-        }
-        else
-        {
-            // default bulk in pipe
-            PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
-        }
+    // a request without the buffer AND not a sense request
+    // for a sense request we provide just a TransferBuffer, an Mdl will be allocated by usbport (see below)
+    if (!Irp->MdlAddress && Request == Context->FDODeviceExtension->ActiveSrb)
+    {
+        Request->SrbStatus = SRB_STATUS_SUCCESS;
+        USBSTOR_SendCSWRequest(Context, Irp);
+        return STATUS_MORE_PROCESSING_REQUIRED;
+    }
 
-        // now initialize the urb for sending data
-        UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
-                                               sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
-                                               PipeHandle,
-                                               NULL,
-                                               Context->TransferBufferMDL,
-                                               Context->TransferDataLength,
-                                               ((Code == SCSIOP_WRITE) ? USBD_TRANSFER_DIRECTION_OUT : (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)),
-                                               NULL);
+    // a request with the data buffer
 
-        IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE);
+    if ((Request->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) == SRB_FLAGS_DATA_IN)
+    {
+        PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
+        TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
     }
-    else
+    else if ((Request->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) == SRB_FLAGS_DATA_OUT)
     {
-        // now initialize the urb for sending the csw
-        UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
-                                               sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
-                                               Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
-                                               Context->csw,
-                                               NULL,
-                                               512, //FIXME
-                                               USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
-                                               NULL);
-
-        IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
+        PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
+        TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
     }
-
-    // initialize stack location
-    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
-    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
-    IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
-    IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
-    Irp->IoStatus.Status = STATUS_SUCCESS;
-
-    IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
-
-    return STATUS_MORE_PROCESSING_REQUIRED;
-}
-
-VOID
-DumpCBW(
-    PUCHAR Block)
-{
-    DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-        Block[0] & 0xFF, Block[1] & 0xFF, Block[2] & 0xFF, Block[3] & 0xFF, Block[4] & 0xFF, Block[5] & 0xFF, Block[6] & 0xFF, Block[7] & 0xFF, Block[8] & 0xFF, Block[9] & 0xFF,
-        Block[10] & 0xFF, Block[11] & 0xFF, Block[12] & 0xFF, Block[13] & 0xFF, Block[14] & 0xFF, Block[15] & 0xFF, Block[16] & 0xFF, Block[17] & 0xFF, Block[18] & 0xFF, Block[19] & 0xFF,
-        Block[20] & 0xFF, Block[21] & 0xFF, Block[22] & 0xFF, Block[23] & 0xFF, Block[24] & 0xFF, Block[25] & 0xFF, Block[26] & 0xFF, Block[27] & 0xFF, Block[28] & 0xFF, Block[29] & 0xFF,
-        Block[30] & 0xFF);
-
-}
-
-NTSTATUS
-USBSTOR_SendCBW(
-    PIRP_CONTEXT Context,
-    PIRP Irp)
-{
-    PIO_STACK_LOCATION IoStack;
-
-    IoStack = IoGetNextIrpStackLocation(Irp);
-
-    // initialize stack location
-    IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
-    IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
-    IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
-    IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
-    Irp->IoStatus.Status = STATUS_SUCCESS;
-
-    IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE);
-
-    return IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
-}
-
-NTSTATUS
-USBSTOR_SendRequest(
-    IN PDEVICE_OBJECT DeviceObject,
-    IN PIRP OriginalRequest,
-    IN UCHAR CommandLength,
-    IN PUCHAR Command,
-    IN ULONG TransferDataLength,
-    IN PUCHAR TransferData,
-    IN ULONG RetryCount)
-{
-    PIRP_CONTEXT Context;
-    PPDO_DEVICE_EXTENSION PDODeviceExtension;
-    PFDO_DEVICE_EXTENSION FDODeviceExtension;
-    PIRP Irp;
-    PUCHAR MdlVirtualAddress;
-
-    Context = USBSTOR_AllocateIrpContext();
-    if (!Context)
+    else
     {
-        return STATUS_INSUFFICIENT_RESOURCES;
+        // we check the validity of a request in disk.c so we should never be here
+        DPRINT1("Warning: shouldn't be here\n");
+        goto ResetRecovery;
     }
 
-    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
-
-    USBSTOR_BuildCBW(PtrToUlong(Context->cbw),
-                     TransferDataLength,
-                     PDODeviceExtension->LUN,
-                     CommandLength,
-                     Command,
-                     Context->cbw);
-
-    DPRINT("CBW %p\n", Context->cbw);
-    DumpCBW((PUCHAR)Context->cbw);
-
-    // now initialize the urb
-    UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
-                                           sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
-                                           FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
-                                           Context->cbw,
-                                           NULL,
-                                           sizeof(CBW),
-                                           USBD_TRANSFER_DIRECTION_OUT,
-                                           NULL);
-
-    // initialize rest of context
-    Context->Irp = OriginalRequest;
-    Context->TransferData = TransferData;
-    Context->TransferDataLength = TransferDataLength;
-    Context->FDODeviceExtension = FDODeviceExtension;
-    Context->PDODeviceExtension = PDODeviceExtension;
-    Context->RetryCount = RetryCount;
-
-    // is there transfer data
-    if (Context->TransferDataLength)
+    // if it is not a Sense Request
+    if (Request == Context->FDODeviceExtension->ActiveSrb)
     {
-        // check if the original request already does have an mdl associated
-        if (OriginalRequest)
+        if (MmGetMdlVirtualAddress(Irp->MdlAddress) == Request->DataBuffer)
         {
-            if ((OriginalRequest->MdlAddress != NULL) &&
-                (Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE))
-            {
-                // Sanity check that the Mdl does describe the TransferData for read/write
-                if (CommandLength == UFI_READ_WRITE_CMD_LEN)
-                {
-                    MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress);
-
-                    // is there an offset
-                    if (MdlVirtualAddress != Context->TransferData)
-                    {
-                        // lets build an mdl
-                        Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
-                        if (!Context->TransferBufferMDL)
-                        {
-                            FreeItem(Context->cbw);
-                            FreeItem(Context);
-                            return STATUS_INSUFFICIENT_RESOURCES;
-                        }
-
-                        IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
-                    }
-                }
-
-                if (!Context->TransferBufferMDL)
-                {
-                    // I/O paging request
-                    Context->TransferBufferMDL = OriginalRequest->MdlAddress;
-                }
-            }
-            else
-            {
-                // allocate mdl for buffer, buffer must be allocated from NonPagedPool
-                Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
-                if (!Context->TransferBufferMDL)
-                {
-                    FreeItem(Context->cbw);
-                    FreeItem(Context);
-                    return STATUS_INSUFFICIENT_RESOURCES;
-                }
-
-                MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
-            }
+            Mdl = Irp->MdlAddress;
         }
         else
         {
-            // allocate mdl for buffer, buffer must be allocated from NonPagedPool
-            Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
-            if (!Context->TransferBufferMDL)
+            Mdl = IoAllocateMdl(Request->DataBuffer,
+                                Request->DataTransferLength,
+                                FALSE,
+                                FALSE,
+                                NULL);
+    
+            if (Mdl)
             {
-                FreeItem(Context->cbw);
-                FreeItem(Context);
-                return STATUS_INSUFFICIENT_RESOURCES;
+                IoBuildPartialMdl(Irp->MdlAddress,
+                                  Mdl,
+                                  Request->DataBuffer,
+                                  Request->DataTransferLength);
             }
+        }
 
-            MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
+        if (!Mdl)
+        {
+            DPRINT1("USBSTOR_CBWCompletionRoutine: Mdl - %p\n", Mdl);
+            goto ResetRecovery;
         }
     }
-
-    Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
-    if (!Irp)
+    else
     {
-        FreeItem(Context->cbw);
-        FreeItem(Context);
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
+        TransferBuffer = Request->DataBuffer;
 
-    if (OriginalRequest)
-    {
-        IoMarkIrpPending(OriginalRequest);
+        if (!Request->DataBuffer)
+        {
+            DPRINT("USBSTOR_CBWCompletionRoutine: Request->DataBuffer == NULL!\n");
+            return STATUS_INVALID_PARAMETER;
+        }
     }
 
-    USBSTOR_SendCBW(Context, Irp);
-
-    return STATUS_PENDING;
-}
-
-NTSTATUS
-USBSTOR_SendFormatCapacity(
-    IN PDEVICE_OBJECT DeviceObject,
-    IN PIRP Irp,
-    IN ULONG RetryCount)
-{
-    UFI_READ_FORMAT_CAPACITY Cmd;
-    PPDO_DEVICE_EXTENSION PDODeviceExtension;
-    PIO_STACK_LOCATION IoStack;
-    PSCSI_REQUEST_BLOCK Request;
-
-    IoStack = IoGetCurrentIrpStackLocation(Irp);
-    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
-
-    // initialize inquiry cmd
-    RtlZeroMemory(&Cmd, sizeof(UFI_READ_FORMAT_CAPACITY));
-    Cmd.Code = SCSIOP_READ_FORMATTED_CAPACITY;
-    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
-    Cmd.AllocationLengthMsb = HTONS(Request->DataTransferLength & 0xFFFF) >> 8;
-    Cmd.AllocationLengthLsb = HTONS(Request->DataTransferLength & 0xFFFF) & 0xFF;
-
-    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_FORMAT_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
-}
-
-NTSTATUS
-USBSTOR_SendInquiry(
-    IN PDEVICE_OBJECT DeviceObject,
-    IN PIRP Irp,
-    IN ULONG RetryCount)
-{
-    UFI_INQUIRY_CMD Cmd;
-    PPDO_DEVICE_EXTENSION PDODeviceExtension;
-    PIO_STACK_LOCATION IoStack;
-    PSCSI_REQUEST_BLOCK Request;
-
-    IoStack = IoGetCurrentIrpStackLocation(Irp);
-    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
-    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
-    // initialize inquiry cmd
-    RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
-    Cmd.Code = SCSIOP_INQUIRY;
-    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
-    Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
+    USBSTOR_IssueBulkOrInterruptRequest(Context->FDODeviceExtension,
+                                        Irp,
+                                        PipeHandle,
+                                        TransferFlags,
+                                        Request->DataTransferLength,
+                                        TransferBuffer,
+                                        Mdl,
+                                        USBSTOR_DataCompletionRoutine,
+                                        Context);
 
-    ASSERT(Request->DataTransferLength >= sizeof(UFI_INQUIRY_RESPONSE));
+    return STATUS_MORE_PROCESSING_REQUIRED;
 
-    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
+ResetRecovery:
+    Context->ErrorIndex = 2;
+    Status = USBSTOR_QueueWorkItem(Context, NULL);
+    ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
+    return STATUS_MORE_PROCESSING_REQUIRED;
 }
 
-NTSTATUS
-USBSTOR_SendCapacity(
-    IN PDEVICE_OBJECT DeviceObject,
-    IN PIRP Irp,
-    IN ULONG RetryCount)
+VOID
+DumpCBW(
+    PUCHAR Block)
 {
-    UFI_CAPACITY_CMD Cmd;
-    PUFI_CAPACITY_RESPONSE Response;
-    PPDO_DEVICE_EXTENSION PDODeviceExtension;
-
-    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
-    Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, PAGE_SIZE);
-    if (!Response)
-    {
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    // initialize capacity cmd
-    RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
-    Cmd.Code = SCSIOP_READ_CAPACITY;
-    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
-
-    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), (PUCHAR)Response, RetryCount);
+    DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+        Block[0] & 0xFF, Block[1] & 0xFF, Block[2] & 0xFF, Block[3] & 0xFF, Block[4] & 0xFF, Block[5] & 0xFF, Block[6] & 0xFF, Block[7] & 0xFF, Block[8] & 0xFF, Block[9] & 0xFF,
+        Block[10] & 0xFF, Block[11] & 0xFF, Block[12] & 0xFF, Block[13] & 0xFF, Block[14] & 0xFF, Block[15] & 0xFF, Block[16] & 0xFF, Block[17] & 0xFF, Block[18] & 0xFF, Block[19] & 0xFF,
+        Block[20] & 0xFF, Block[21] & 0xFF, Block[22] & 0xFF, Block[23] & 0xFF, Block[24] & 0xFF, Block[25] & 0xFF, Block[26] & 0xFF, Block[27] & 0xFF, Block[28] & 0xFF, Block[29] & 0xFF,
+        Block[30] & 0xFF);
 }
 
+static
 NTSTATUS
-USBSTOR_SendModeSense(
-    IN PDEVICE_OBJECT DeviceObject,
+USBSTOR_SendCBWRequest(
+    IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
     IN PIRP Irp,
-    IN ULONG RetryCount)
+    IN PIRP_CONTEXT Context)
 {
-#if 0
-    UFI_SENSE_CMD Cmd;
-    NTSTATUS Status;
-    PVOID Response;
-    PCBW OutControl;
-    PCDB pCDB;
-    PUFI_MODE_PARAMETER_HEADER Header;
-#endif
     PPDO_DEVICE_EXTENSION PDODeviceExtension;
     PIO_STACK_LOCATION IoStack;
     PSCSI_REQUEST_BLOCK Request;
 
-    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-    ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+    RtlZeroMemory(&Context->cbw, sizeof(CBW));
+    RtlZeroMemory(&Context->Urb, sizeof(URB));
 
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+    PDODeviceExtension = IoStack->DeviceObject->DeviceExtension;
+    Request = IoStack->Parameters.Scsi.Srb;
 
-    RtlZeroMemory(Request->DataBuffer, Request->DataTransferLength);
-    Request->SrbStatus = SRB_STATUS_SUCCESS;
-    Irp->IoStatus.Information = Request->DataTransferLength;
-    Irp->IoStatus.Status = STATUS_SUCCESS;
-    USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    Context->cbw.Signature = CBW_SIGNATURE;
+    Context->cbw.Tag = PtrToUlong(&Context->cbw);
+    Context->cbw.DataTransferLength = Request->DataTransferLength;
+    Context->cbw.Flags = ((UCHAR)Request->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) << 1;
+    Context->cbw.LUN = PDODeviceExtension->LUN;
+    Context->cbw.CommandBlockLength = Request->CdbLength;
 
-    USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
+    RtlCopyMemory(&Context->cbw.CommandBlock, Request->Cdb, Request->CdbLength);
 
-    return STATUS_SUCCESS;
-
-#if 0
-    //
-    // get SCSI command data block
-    //
-    pCDB = (PCDB)Request->Cdb;
+    DPRINT("CBW for IRP %p\n", Irp);
+    DumpCBW((PUCHAR)&Context->cbw);
 
-    //
-    // get PDO device extension
-    //
-    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
-    //
-    // allocate sense response from non paged pool
-    //
-    Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength);
-    if (!Response)
-    {
-        //
-        // no memory
-        //
-        return STATUS_INSUFFICIENT_RESOURCES;
-    }
-
-    //
-    // sanity check
-    //
-
-
-    // Supported pages
-    // MODE_PAGE_ERROR_RECOVERY
-    // MODE_PAGE_FLEXIBILE
-    // MODE_PAGE_LUN_MAPPING
-    // MODE_PAGE_FAULT_REPORTING
-    // MODE_SENSE_RETURN_ALL
-
-    //
-    // initialize mode sense cmd
-    //
-    RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
-    Cmd.Code = SCSIOP_MODE_SENSE;
-    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
-    Cmd.PageCode = pCDB->MODE_SENSE.PageCode;
-    Cmd.PC = pCDB->MODE_SENSE.Pc;
-    Cmd.AllocationLength = HTONS(pCDB->MODE_SENSE.AllocationLength);
-
-    DPRINT1("PageCode %x\n", pCDB->MODE_SENSE.PageCode);
-    DPRINT1("PC %x\n", pCDB->MODE_SENSE.Pc);
-
-    //
-    // now send mode sense cmd
-    //
-    Status = USBSTOR_SendCBW(DeviceObject, UFI_SENSE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl);
-    if (!NT_SUCCESS(Status))
-    {
-        //
-        // failed to send CBW
-        //
-        DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status);
-        FreeItem(Response);
-        ASSERT(FALSE);
-        return Status;
-    }
-
-    //
-    // now send data block response
-    //
-    Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response);
-    if (!NT_SUCCESS(Status))
-    {
-        //
-        // failed to send CBW
-        //
-        DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status);
-        FreeItem(Response);
-        ASSERT(FALSE);
-        return Status;
-    }
-
-    Header = (PUFI_MODE_PARAMETER_HEADER)Response;
-
-    //
-    // TODO: build layout
-    //
-    // first struct is the header
-    // MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
-    //
-    // followed by
-    // MODE_PARAMETER_BLOCK
-    //
-    //
-    UNIMPLEMENTED;
-
-    //
-    // send csw
-    //
-    Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
-
-    DPRINT1("------------------------\n");
-    DPRINT1("CSW %p\n", &CSW);
-    DPRINT1("Signature %x\n", CSW.Signature);
-    DPRINT1("Tag %x\n", CSW.Tag);
-    DPRINT1("DataResidue %x\n", CSW.DataResidue);
-    DPRINT1("Status %x\n", CSW.Status);
-
-    //
-    // FIXME: handle error
-    //
-    ASSERT(CSW.Status == 0);
-    ASSERT(CSW.DataResidue == 0);
-
-    //
-    // calculate transfer length
-    //
-    *TransferBufferLength = Request->DataTransferLength - CSW.DataResidue;
-
-    //
-    // copy buffer
-    //
-    RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength);
-
-    //
-    // free item
-    //
-    FreeItem(OutControl);
-
-    //
-    // free response
-    //
-    FreeItem(Response);
-
-    //
-    // done
-    //
-    return Status;
-#endif
+    // initialize rest of context
+    Context->Irp = Irp;
+    Context->FDODeviceExtension = FDODeviceExtension;
+    Context->StallRetryCount = 0;
+
+    return USBSTOR_IssueBulkOrInterruptRequest(
+        FDODeviceExtension,
+        Irp,
+        FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
+        USBD_TRANSFER_DIRECTION_OUT,
+        sizeof(CBW),
+        &Context->cbw,
+        NULL,
+        USBSTOR_CBWCompletionRoutine,
+        Context);
 }
 
+static
 NTSTATUS
-USBSTOR_SendReadWrite(
-    IN PDEVICE_OBJECT DeviceObject,
+USBSTOR_IssueRequestSense(
+    IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
     IN PIRP Irp,
-    IN ULONG RetryCount)
+    IN PIRP_CONTEXT Context)
 {
-    UFI_READ_WRITE_CMD Cmd;
-    PPDO_DEVICE_EXTENSION PDODeviceExtension;
-    PCDB pCDB;
-    ULONG BlockCount, Temp;
     PIO_STACK_LOCATION IoStack;
-    PSCSI_REQUEST_BLOCK Request;
-
-    IoStack = IoGetCurrentIrpStackLocation(Irp);
-    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
-
-    pCDB = (PCDB)Request->Cdb;
-
-    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
-    DPRINT("USBSTOR_SendReadWrite DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);
-
-    ASSERT(PDODeviceExtension->BlockLength);
-
-    BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength;
-
-    // initialize read cmd
-    RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD));
-    Cmd.Code = pCDB->AsByte[0];
-    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
-    Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb;
-    Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb;
-    Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0;
-    Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1;
-    Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2;
-    Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3;
-
-    Temp = (Cmd.ContiguousLogicBlocksByte0 << 8 | Cmd.ContiguousLogicBlocksByte1);
-    ASSERT(Temp == BlockCount);
-
-    DPRINT("USBSTOR_SendReadWrite BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);
-
-    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
-}
+    PSCSI_REQUEST_BLOCK CurrentSrb;
+    PSCSI_REQUEST_BLOCK SenseSrb;
+    PCDB pCDB;
 
-NTSTATUS
-USBSTOR_SendTestUnit(
-    IN PDEVICE_OBJECT DeviceObject,
-    IN OUT PIRP Irp,
-    IN ULONG RetryCount)
-{
-    UFI_TEST_UNIT_CMD Cmd;
-    PPDO_DEVICE_EXTENSION PDODeviceExtension;
-    PIO_STACK_LOCATION IoStack;
-    PSCSI_REQUEST_BLOCK Request;
+    DPRINT("USBSTOR_IssueRequestSense: \n");
 
+    CurrentSrb = FDODeviceExtension->ActiveSrb;
+    SenseSrb = &Context->SenseSrb;
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+    IoStack->Parameters.Scsi.Srb = SenseSrb;
 
-    ASSERT(Request->DataTransferLength == 0);
+    RtlZeroMemory(SenseSrb, sizeof(*SenseSrb));
 
-    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
-
-    // initialize test unit cmd
-    RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD));
-    Cmd.Code = SCSIOP_TEST_UNIT_READY;
-    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
-
-    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, NULL, RetryCount);
-}
-
-NTSTATUS
-USBSTOR_SendUnknownRequest(
-    IN PDEVICE_OBJECT DeviceObject,
-    IN OUT PIRP Irp,
-    IN ULONG RetryCount)
-{
-    PPDO_DEVICE_EXTENSION PDODeviceExtension;
-    PIO_STACK_LOCATION IoStack;
-    PSCSI_REQUEST_BLOCK Request;
-    UFI_UNKNOWN_CMD Cmd;
+    SenseSrb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+    SenseSrb->Length = sizeof(*SenseSrb);
+    SenseSrb->CdbLength = CDB6GENERIC_LENGTH;
+    SenseSrb->SrbFlags = SRB_FLAGS_DATA_IN |
+                         SRB_FLAGS_NO_QUEUE_FREEZE |
+                         SRB_FLAGS_DISABLE_AUTOSENSE;
 
-    IoStack = IoGetCurrentIrpStackLocation(Irp);
-    Request = IoStack->Parameters.Others.Argument1;
-    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+    ASSERT(CurrentSrb->SenseInfoBufferLength);
+    ASSERT(CurrentSrb->SenseInfoBuffer);
+    DPRINT("SenseInfoBuffer %x, SenseInfoBufferLength %x\n", CurrentSrb->SenseInfoBuffer, CurrentSrb->SenseInfoBufferLength);
 
-    // check that we're sending to the right LUN
-    ASSERT(Request->Cdb[1] == (PDODeviceExtension->LUN & MAX_LUN));
-    ASSERT(Request->CdbLength <= sizeof(UFI_UNKNOWN_CMD));
+    SenseSrb->DataTransferLength = CurrentSrb->SenseInfoBufferLength;
+    SenseSrb->DataBuffer = CurrentSrb->SenseInfoBuffer;
 
-    RtlCopyMemory(&Cmd, Request->Cdb, Request->CdbLength);
+    pCDB = (PCDB)SenseSrb->Cdb;
+    pCDB->CDB6GENERIC.OperationCode = SCSIOP_REQUEST_SENSE;
+    pCDB->AsByte[4] = CurrentSrb->SenseInfoBufferLength;
 
-    return USBSTOR_SendRequest(DeviceObject, Irp, Request->CdbLength, (PUCHAR)&Cmd, Request->DataTransferLength, Request->DataBuffer, RetryCount);
+    return USBSTOR_SendCBWRequest(FDODeviceExtension, Irp, Context);
 }
 
 NTSTATUS
 USBSTOR_HandleExecuteSCSI(
     IN PDEVICE_OBJECT DeviceObject,
-    IN PIRP Irp,
-    IN ULONG RetryCount)
+    IN PIRP Irp)
 {
     PCDB pCDB;
     NTSTATUS Status;
     PIO_STACK_LOCATION IoStack;
     PSCSI_REQUEST_BLOCK Request;
     PPDO_DEVICE_EXTENSION PDODeviceExtension;
+    PIRP_CONTEXT Context;
 
     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
     ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
 
     IoStack = IoGetCurrentIrpStackLocation(Irp);
-    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
+    Request = IoStack->Parameters.Scsi.Srb;
     pCDB = (PCDB)Request->Cdb;
 
-    DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
-
-    if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
-    {
-        ASSERT(Request->DataBuffer);
+    DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x, Length %lu\n", pCDB->CDB10.OperationCode, Request->DataTransferLength);
 
-        DPRINT("SCSIOP_READ_CAPACITY Length %lu\n", Request->DataTransferLength);
-        Status = USBSTOR_SendCapacity(DeviceObject, Irp, RetryCount);
-    }
-    else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE)
-    {
-        DPRINT("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength);
-        ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength);
-        ASSERT(Request->DataBuffer);
-
-        Status = USBSTOR_SendModeSense(DeviceObject, Irp, RetryCount);
-    }
-    else if (pCDB->AsByte[0] == SCSIOP_READ_FORMATTED_CAPACITY)
-    {
-        DPRINT("SCSIOP_READ_FORMATTED_CAPACITY DataTransferLength %lu\n", Request->DataTransferLength);
-
-        Status = USBSTOR_SendFormatCapacity(DeviceObject, Irp, RetryCount);
-    }
-    else if (pCDB->AsByte[0] == SCSIOP_INQUIRY)
-    {
-        DPRINT("SCSIOP_INQUIRY DataTransferLength %lu\n", Request->DataTransferLength);
-
-        Status = USBSTOR_SendInquiry(DeviceObject, Irp, RetryCount);
-    }
-    else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ ||  pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE)
-    {
-        DPRINT("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength);
-
-        Status = USBSTOR_SendReadWrite(DeviceObject, Irp, RetryCount);
-    }
-    else if (pCDB->AsByte[0] == SCSIOP_MEDIUM_REMOVAL)
-    {
-        DPRINT("SCSIOP_MEDIUM_REMOVAL\n");
-
-        // just complete the request
-        Request->SrbStatus = SRB_STATUS_SUCCESS;
-        Irp->IoStatus.Status = STATUS_SUCCESS;
-        Irp->IoStatus.Information = Request->DataTransferLength;
-        USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
-        USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
+    // check that we're sending to the right LUN
+    ASSERT(pCDB->CDB10.LogicalUnitNumber == (PDODeviceExtension->LUN & MAX_LUN));
+    Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(IRP_CONTEXT), USB_STOR_TAG);
 
-        return STATUS_SUCCESS;
-    }
-    else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
+    if (!Context)
     {
-        DPRINT("SCSIOP_TEST_UNIT_READY\n");
-
-        Status = USBSTOR_SendTestUnit(DeviceObject, Irp, RetryCount);
+        Status = STATUS_INSUFFICIENT_RESOURCES;
     }
     else
     {
-        // Unknown request. Simply forward
-        DPRINT1("Forwarding unknown Operation Code %x\n", pCDB->AsByte[0]);
-        Status = USBSTOR_SendUnknownRequest(DeviceObject, Irp, RetryCount);
+        Status = USBSTOR_SendCBWRequest(PDODeviceExtension->LowerDeviceObject->DeviceExtension, Irp, Context);
     }
 
     return Status;