[USBSTOR]
[reactos.git] / drivers / usb / usbstor / scsi.c
index 0e2b926..4966309 100644 (file)
@@ -102,8 +102,11 @@ USBSTOR_CSWCompletionRoutine(
     PREAD_CAPACITY_DATA_EX CapacityDataEx;
     PREAD_CAPACITY_DATA CapacityData;
     PUFI_CAPACITY_RESPONSE Response;
+    PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData;
+    NTSTATUS Status;
+    PURB Urb;
 
-    DPRINT1("USBSTOR_CSWCompletionRoutine Irp %p Ctx %p\n", Irp, Ctx);
+    DPRINT("USBSTOR_CSWCompletionRoutine Irp %p Ctx %p\n", Irp, Ctx);
 
     //
     // access context
@@ -153,16 +156,75 @@ USBSTOR_CSWCompletionRoutine(
         Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
         ASSERT(Request);
 
-        //
-        // FIXME: check status
-        //
-        Request->SrbStatus = SRB_STATUS_SUCCESS;
+        Status = Irp->IoStatus.Status;
+
+        Urb = &Context->Urb;
 
         //
         // get SCSI command data block
         //
         pCDB = (PCDB)Request->Cdb;
 
+        //
+        // check status
+        //
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Status %x\n", Status);
+            DPRINT1("UrbStatus %x\n", Urb->UrbHeader.Status);
+
+            //
+            // Check for errors that can be handled
+            // FIXME: Verify all usb errors that can be recovered via pipe reset/port reset/controller reset
+            //
+            if ((Urb->UrbHeader.Status & USB_RECOVERABLE_ERRORS) == Urb->UrbHeader.Status)
+            {
+                DPRINT1("Attempting Error Recovery\n");
+                //
+                // If a Read Capacity Request free TransferBuffer
+                //
+                if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
+                {
+                    FreeItem(Context->TransferData);
+                }
+
+                //
+                // Clean up the rest
+                //
+                FreeItem(Context->cbw);
+                FreeItem(Context);
+
+                //
+                // Allocate Work Item Data
+                //
+                ErrorHandlerWorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG);
+                if (!ErrorHandlerWorkItemData)
+                {
+                    DPRINT1("Failed to allocate memory\n");
+                    Status = STATUS_INSUFFICIENT_RESOURCES;
+                }
+                else
+                {
+                    //
+                    // Initialize and queue the work item to handle the error
+                    //
+                    ExInitializeWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem,
+                                        ErrorHandlerWorkItemRoutine,
+                                        ErrorHandlerWorkItemData);
+    
+                    ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
+                    ErrorHandlerWorkItemData->Irp = Irp;
+                    ErrorHandlerWorkItemData->Context = Context;
+                    DPRINT1("Queuing WorkItemROutine\n");
+                    ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue);
+
+                    return STATUS_MORE_PROCESSING_REQUIRED;
+                }
+            }
+        }
+
+        Request->SrbStatus = SRB_STATUS_SUCCESS;
+
         //
         // read capacity needs special work
         //
@@ -233,6 +295,16 @@ USBSTOR_CSWCompletionRoutine(
         // complete request
         //
         IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
+
+        //
+        // terminate current request
+        //
+        USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, TRUE);
+
+        //
+        // start next request
+        //
+        USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
     }
 
     if (Context->Event)
@@ -270,7 +342,7 @@ USBSTOR_DataCompletionRoutine(
     PIRP_CONTEXT Context;
     PIO_STACK_LOCATION IoStack;
 
-    DPRINT1("USBSTOR_DataCompletionRoutine Irp %p Ctx %p\n", Irp, Ctx);
+    DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p\n", Irp, Ctx);
 
     //
     // access context
@@ -335,7 +407,7 @@ USBSTOR_CBWCompletionRoutine(
     UCHAR Code;
     USBD_PIPE_HANDLE PipeHandle;
 
-    DPRINT1("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p\n", Irp, Ctx);
+    DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p\n", Irp, Ctx);
 
     //
     // access context
@@ -432,7 +504,7 @@ USBSTOR_SendRequest(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP OriginalRequest,
     IN OPTIONAL PKEVENT Event,
-    IN ULONG CommandLength,
+    IN UCHAR CommandLength,
     IN PUCHAR Command,
     IN ULONG TransferDataLength,
     IN PUCHAR TransferData)
@@ -442,6 +514,7 @@ USBSTOR_SendRequest(
     PFDO_DEVICE_EXTENSION FDODeviceExtension;
     PIRP Irp;
     PIO_STACK_LOCATION IoStack;
+    PUCHAR MdlVirtualAddress;
 
     //
     // first allocate irp context
@@ -503,12 +576,40 @@ USBSTOR_SendRequest(
     if (Context->TransferDataLength)
     {
         //
-        // check if the original request already does not have an mdl associated
+        // check if the original request already does have an mdl associated
         //
         if (OriginalRequest)
         {
-            if (OriginalRequest->MdlAddress != NULL && Context->TransferData == NULL)
+            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);
+                    if (MdlVirtualAddress != Context->TransferData)
+                                       {
+                        //
+                        // lets build an mdl
+                        //
+                                               Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
+                        if (!Context->TransferBufferMDL)
+                        {
+                            //
+                            // failed to allocate MDL
+                            //
+                            return STATUS_INSUFFICIENT_RESOURCES;
+                        }
+
+                                               //
+                                               // now build the partial mdl
+                                               //
+                                               IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
+                                       }
+                }
+
                 //
                 // I/O paging request
                 //
@@ -725,14 +826,15 @@ USBSTOR_SendModeSenseCmd(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp)
 {
+#if 0
     UFI_SENSE_CMD Cmd;
     NTSTATUS Status;
     PVOID Response;
-    PPDO_DEVICE_EXTENSION PDODeviceExtension;
     PCBW OutControl;
     PCDB pCDB;
     PUFI_MODE_PARAMETER_HEADER Header;
-
+#endif
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
     PIO_STACK_LOCATION IoStack;
     PSCSI_REQUEST_BLOCK Request;
 
@@ -752,6 +854,26 @@ USBSTOR_SendModeSenseCmd(
     Irp->IoStatus.Status = STATUS_SUCCESS;
     IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
+
+    //
+    // terminate current request
+    //
+    USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, TRUE);
+
+    //
+    // start next request
+    //
+    USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
+
     return STATUS_SUCCESS;
 
 #if 0
@@ -897,13 +1019,11 @@ USBSTOR_SendReadWriteCmd(
     IN PIRP Irp)
 {
     UFI_READ_WRITE_CMD Cmd;
-    NTSTATUS Status;
     PPDO_DEVICE_EXTENSION PDODeviceExtension;
     PCDB pCDB;
     ULONG BlockCount;
     PIO_STACK_LOCATION IoStack;
     PSCSI_REQUEST_BLOCK Request;
-    PVOID Buffer;
 
     //
     // get current stack location
@@ -928,7 +1048,7 @@ USBSTOR_SendReadWriteCmd(
     //
     // informal debug print
     //
-    DPRINT1("USBSTOR_SendReadWriteCmd DataTransferLength %x, BlockLength %x\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);
+    DPRINT("USBSTOR_SendReadWriteCmd DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);
 
     //
     // sanity check
@@ -946,18 +1066,19 @@ USBSTOR_SendReadWriteCmd(
     RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD));
     Cmd.Code = pCDB->AsByte[0];
     Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
-    Cmd.ContiguousLogicBlocks = _byteswap_ushort(BlockCount);
+    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;
 
-    DPRINT1("BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);
+    DPRINT("USBSTOR_SendReadWriteCmd BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);
 
     //
     // send request
     //
-       return USBSTOR_SendRequest(DeviceObject, Irp, NULL, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer);
+    return USBSTOR_SendRequest(DeviceObject, Irp, NULL, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer);
 }
 
 NTSTATUS
@@ -1013,6 +1134,17 @@ USBSTOR_HandleExecuteSCSI(
     NTSTATUS Status;
     PIO_STACK_LOCATION IoStack;
     PSCSI_REQUEST_BLOCK Request;
+    PPDO_DEVICE_EXTENSION PDODeviceExtension;
+
+    //
+    // get PDO device extension
+    //
+    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
+
+    //
+    // sanity check
+    //
+    ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
 
     //
     // get current stack location
@@ -1029,7 +1161,7 @@ USBSTOR_HandleExecuteSCSI(
     //
     pCDB = (PCDB)Request->Cdb;
 
-    DPRINT1("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
+    DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
 
     if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
     {
@@ -1038,7 +1170,7 @@ USBSTOR_HandleExecuteSCSI(
         //
         ASSERT(Request->DataBuffer);
 
-        DPRINT1("SCSIOP_READ_CAPACITY Length %\n", Request->DataTransferLength);
+        DPRINT("SCSIOP_READ_CAPACITY Length %\n", Request->DataTransferLength);
         Status = USBSTOR_SendCapacityCmd(DeviceObject, Irp);
     }
     else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE)
@@ -1052,9 +1184,9 @@ USBSTOR_HandleExecuteSCSI(
         //
         Status = USBSTOR_SendModeSenseCmd(DeviceObject, Irp);
     }
-    else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ /*||  pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE*/)
+    else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ ||  pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE)
     {
-        DPRINT1("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength);
+        DPRINT("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength);
 
         //
         // send read / write command
@@ -1063,7 +1195,7 @@ USBSTOR_HandleExecuteSCSI(
     }
     else if (pCDB->AsByte[0] == SCSIOP_MEDIUM_REMOVAL)
     {
-        DPRINT1("SCSIOP_MEDIUM_REMOVAL\n");
+        DPRINT("SCSIOP_MEDIUM_REMOVAL\n");
 
         //
         // just complete the request
@@ -1072,11 +1204,22 @@ USBSTOR_HandleExecuteSCSI(
         Irp->IoStatus.Status = STATUS_SUCCESS;
         Irp->IoStatus.Information = Request->DataTransferLength;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        //
+        // terminate current request
+        //
+        USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, TRUE);
+
+        //
+        // start next request
+        //
+        USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
+
         return STATUS_SUCCESS;
     }
     else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
     {
-        DPRINT1("SCSIOP_TEST_UNIT_READY\n");
+        DPRINT("SCSIOP_TEST_UNIT_READY\n");
 
         //
         // send test unit command