diff --git a/reactos/drivers/usb/usbstor/error.c b/reactos/drivers/usb/usbstor/error.c index 23d7f88c671..6608b5302fc 100644 --- a/reactos/drivers/usb/usbstor/error.c +++ b/reactos/drivers/usb/usbstor/error.c @@ -110,106 +110,159 @@ USBSTOR_HandleTransferError( PDEVICE_OBJECT DeviceObject, PIRP_CONTEXT Context) { - NTSTATUS Status; + NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION Stack; - USBD_PIPE_HANDLE PipeHandle; + //USBD_PIPE_HANDLE PipeHandle; PSCSI_REQUEST_BLOCK Request; PCDB pCDB; - DPRINT1("Entered Handle Transfer Error\n"); + // - // Determine pipehandle + // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification // - if (Context->cbw->CommandBlock[0] == SCSIOP_WRITE) + Status = USBSTOR_ResetDevice(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension); + if (NT_SUCCESS(Status)) { // - // write request used bulk out pipe - // - PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle; + // step 2 reset bulk in pipe section 5.3.4 + // + Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle); + if (NT_SUCCESS(Status)) + { + // + // finally reset bulk out pipe + // + Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle); + } + } + + if (Context->Irp) + { + // + // get next stack location + // + Stack = IoGetCurrentIrpStackLocation(Context->Irp); + + // + // get request block + // + Request = (PSCSI_REQUEST_BLOCK)Stack->Parameters.Others.Argument1; + ASSERT(Request); + + // + // obtain request type + // + pCDB = (PCDB)Request->Cdb; + ASSERT(pCDB); + + // + // Cleanup the IRP context + if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY) + { + FreeItem(Context->TransferData); + } + + if (Status != STATUS_SUCCESS) + { + // + // Complete the master IRP + // + Context->Irp->IoStatus.Status = Status; + Context->Irp->IoStatus.Information = 0; + USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp); + IoCompleteRequest(Context->Irp, IO_NO_INCREMENT); + + // + // Start the next request + // + USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject); + } } else { - // - // default bulk in pipe - // - PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle; - } - - switch (Context->Urb.UrbHeader.Status) - { - case USBD_STATUS_STALL_PID: + if (Status != STATUS_SUCCESS) { // - // First attempt to reset the pipe + // Signal the context event // - DPRINT1("Resetting Pipe\n"); - Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, PipeHandle); - if (NT_SUCCESS(Status)) - { - Status = STATUS_SUCCESS; - break; - } - - DPRINT1("Failed to reset pipe %x\n", Status); - - // - // FIXME: Reset of pipe failed, attempt to reset port - // - - Status = STATUS_UNSUCCESSFUL; - break; - } - // - // FIXME: Handle more errors - // - default: - { - DPRINT1("Error not handled\n"); - Status = STATUS_UNSUCCESSFUL; - } - } - - Stack = IoGetCurrentIrpStackLocation(Context->Irp); - Request = (PSCSI_REQUEST_BLOCK)Stack->Parameters.Others.Argument1; - pCDB = (PCDB)Request->Cdb; - if (Status != STATUS_SUCCESS) - { - /* Complete the master IRP */ - Context->Irp->IoStatus.Status = Status; - Context->Irp->IoStatus.Information = 0; - USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp); - IoCompleteRequest(Context->Irp, IO_NO_INCREMENT); - - /* Start the next request */ - USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject); - - /* Signal the context event */ - if (Context->Event) + ASSERT(Context->Event); KeSetEvent(Context->Event, 0, FALSE); - - /* Cleanup the IRP context */ - if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY) - FreeItem(Context->TransferData); - FreeItem(Context->cbw); - FreeItem(Context); + } } - else + + if (NT_SUCCESS(Status)) { - DPRINT1("Retrying\n"); - Status = USBSTOR_HandleExecuteSCSI(*Context->PDODeviceExtension->PDODeviceObject, Context->Irp); - - /* Cleanup the old IRP context */ - if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY) - FreeItem(Context->TransferData); - FreeItem(Context->cbw); - FreeItem(Context); + USBSTOR_HandleExecuteSCSI(*Context->PDODeviceExtension->PDODeviceObject, Context->Irp); } + // + // cleanup irp context + // + FreeItem(Context->cbw); + FreeItem(Context); + + DPRINT1("USBSTOR_HandleTransferError returning with Status %x\n", Status); return Status; } +VOID +NTAPI +USBSTOR_ResetHandlerWorkItemRoutine( + PVOID Context) +{ + NTSTATUS Status; + USHORT Value; + PIO_STACK_LOCATION IoStack; + + PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; + + // + // clear stall on BulkIn pipe + // + Status = USBSTOR_ResetPipeWithHandle(WorkItemData->Context->FDODeviceExtension->LowerDeviceObject, WorkItemData->Context->FDODeviceExtension->InterfaceInformation->Pipes[WorkItemData->Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle); + DPRINT1("USBSTOR_ResetPipeWithHandle Status %x\n", Status); + + // + // get next stack location + // + + IoStack = IoGetNextIrpStackLocation(WorkItemData->Irp); + + // + // now initialize the urb for sending the csw + // + UsbBuildInterruptOrBulkTransferRequest(&WorkItemData->Context->Urb, + sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), + WorkItemData->Context->FDODeviceExtension->InterfaceInformation->Pipes[WorkItemData->Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle, + WorkItemData->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)&WorkItemData->Context->Urb; + IoStack->Parameters.DeviceIoControl.InputBufferLength = WorkItemData->Context->Urb.UrbHeader.Length; + WorkItemData->Irp->IoStatus.Status = STATUS_SUCCESS; + + + // + // setup completion routine + // + IoSetCompletionRoutine(WorkItemData->Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE); + + // + // call driver + // + IoCallDriver(WorkItemData->Context->FDODeviceExtension->LowerDeviceObject, WorkItemData->Irp); +} + VOID NTAPI ErrorHandlerWorkItemRoutine( @@ -217,8 +270,21 @@ ErrorHandlerWorkItemRoutine( { NTSTATUS Status; PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; - - Status = USBSTOR_HandleTransferError(WorkItemData->DeviceObject, WorkItemData->Context); + + if (WorkItemData->Context->ErrorIndex == 2) + { + // + // reset device + // + Status = USBSTOR_HandleTransferError(WorkItemData->DeviceObject, WorkItemData->Context); + } + else + { + // + // clear stall + // + USBSTOR_ResetHandlerWorkItemRoutine(WorkItemData); + } // // Free Work Item Data diff --git a/reactos/drivers/usb/usbstor/misc.c b/reactos/drivers/usb/usbstor/misc.c index 4c49e7587fa..4daf7488a4c 100644 --- a/reactos/drivers/usb/usbstor/misc.c +++ b/reactos/drivers/usb/usbstor/misc.c @@ -411,7 +411,6 @@ USBSTOR_ResetDevice( // execute request // Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_RESET_DEVICE, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_OUT, 0, NULL); - DPRINT1("Status %x\n", Status); // // done diff --git a/reactos/drivers/usb/usbstor/scsi.c b/reactos/drivers/usb/usbstor/scsi.c index d9d1016757b..b248d199034 100644 --- a/reactos/drivers/usb/usbstor/scsi.c +++ b/reactos/drivers/usb/usbstor/scsi.c @@ -83,6 +83,75 @@ USBSTOR_AllocateIrpContext() } +BOOLEAN +USBSTOR_IsCSWValid( + PIRP_CONTEXT Context) +{ + // + // sanity checks + // + 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)Context->csw) + { + DPRINT1("[USBSTOR] Expected Tag %x but got %x\n", (ULONG)Context->csw, Context->csw->Tag); + return FALSE; + } + + if (Context->csw->Status != 0x00) + { + DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status); + return FALSE; + } + + // + // CSW is valid + // + return TRUE; + +} + +NTSTATUS +USBSTOR_QueueWorkItem( + PIRP_CONTEXT Context, + PIRP Irp) +{ + PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData; + + // + // Allocate Work Item Data + // + ErrorHandlerWorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG); + if (!ErrorHandlerWorkItemData) + { + // + // no memory + // + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Initialize and queue the work item to handle the error + // + ExInitializeWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, + ErrorHandlerWorkItemRoutine, + ErrorHandlerWorkItemData); + + ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject; + ErrorHandlerWorkItemData->Context = Context; + ErrorHandlerWorkItemData->Irp = Irp; + ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject; + + DPRINT1("Queuing WorkItemROutine\n"); + ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue); + return STATUS_MORE_PROCESSING_REQUIRED; +} + + // // driver verifier // @@ -102,7 +171,7 @@ USBSTOR_CSWCompletionRoutine( PREAD_CAPACITY_DATA_EX CapacityDataEx; PREAD_CAPACITY_DATA CapacityData; PUFI_CAPACITY_RESPONSE Response; - PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData; + NTSTATUS Status; PURB Urb; @@ -143,6 +212,48 @@ USBSTOR_CSWCompletionRoutine( } } + DPRINT1("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status); + + if (!NT_SUCCESS(Irp->IoStatus.Information)) + { + if (Context->ErrorIndex == 0) + { + // + // increment error index + // + Context->ErrorIndex = 1; + + // + // clear stall and resend cbw + // + Status = USBSTOR_QueueWorkItem(Context, Irp); + ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED); + return STATUS_MORE_PROCESSING_REQUIRED; + } + + // + // 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)) + { + // + // 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 (Context->Irp) { // @@ -164,55 +275,6 @@ USBSTOR_CSWCompletionRoutine( // 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"); - // - // free the allocated irp - // - IoFreeIrp(Irp); - - // - // 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->Context = Context; - DPRINT1("Queuing WorkItemROutine\n"); - ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue); - - return STATUS_MORE_PROCESSING_REQUIRED; - } - } - } - Request->SrbStatus = SRB_STATUS_SUCCESS; // @@ -267,30 +329,11 @@ USBSTOR_CSWCompletionRoutine( } } - // - // sanity checks - // - if (Context->csw->Signature != CSW_SIGNATURE) - { - DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw->Signature); - } - - if (Context->csw->Tag != (ULONG)Context->csw) - { - DPRINT1("[USBSTOR] Expected Tag %x but got %x\n", (ULONG)Context->csw, Context->csw->Tag); - } - - if (Context->csw->Status != 0x00) - { - DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status); - } - // // free cbw // FreeItem(Context->cbw); - if (Context->Irp) { // @@ -511,6 +554,19 @@ USBSTOR_CBWCompletionRoutine( return STATUS_MORE_PROCESSING_REQUIRED; } +VOID +DumpCBW( + PUCHAR Block) +{ + DPRINT1("%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_SendRequest( IN PDEVICE_OBJECT DeviceObject, @@ -561,6 +617,7 @@ USBSTOR_SendRequest( Context->cbw); DPRINT("CBW %p\n", Context->cbw); + DumpCBW((PUCHAR)Context->cbw); // // now initialize the urb @@ -777,21 +834,6 @@ USBSTOR_SendInquiryCmd( // KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - KeResetEvent(&Event); - DPRINT("Resending request\n"); - - // - // now send the request - // - Status = USBSTOR_SendRequest(DeviceObject, NULL, &Event, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_INQUIRY_RESPONSE), (PUCHAR)Response); - - // - // wait for the action to complete - // - KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); - - - DPRINT1("Response %p\n", Response); DPRINT1("DeviceType %x\n", Response->DeviceType); DPRINT1("RMB %x\n", Response->RMB); diff --git a/reactos/drivers/usb/usbstor/usbstor.h b/reactos/drivers/usb/usbstor/usbstor.h index dbc8ef51ae7..700443e75f2 100644 --- a/reactos/drivers/usb/usbstor/usbstor.h +++ b/reactos/drivers/usb/usbstor/usbstor.h @@ -279,6 +279,7 @@ typedef struct PPDO_DEVICE_EXTENSION PDODeviceExtension; PMDL TransferBufferMDL; PKEVENT Event; + ULONG ErrorIndex; }IRP_CONTEXT, *PIRP_CONTEXT; typedef struct _ERRORHANDLER_WORKITEM_DATA @@ -286,6 +287,7 @@ typedef struct _ERRORHANDLER_WORKITEM_DATA PDEVICE_OBJECT DeviceObject; PIRP_CONTEXT Context; WORK_QUEUE_ITEM WorkQueueItem; + PIRP Irp; } ERRORHANDLER_WORKITEM_DATA, *PERRORHANDLER_WORKITEM_DATA; @@ -390,6 +392,13 @@ NTSTATUS USBSTOR_SendInquiryCmd( IN PDEVICE_OBJECT DeviceObject); +NTSTATUS +NTAPI +USBSTOR_CSWCompletionRoutine( + PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Ctx); + //--------------------------------------------------------------------- // // disk.c routines @@ -442,6 +451,13 @@ NTAPI ErrorHandlerWorkItemRoutine( PVOID Context); +VOID +NTAPI +ResetHandlerWorkItemRoutine( + PVOID Context); + + + VOID USBSTOR_QueueNextRequest( IN PDEVICE_OBJECT DeviceObject); @@ -458,3 +474,8 @@ USBSTOR_GetEndpointStatus( IN UCHAR bEndpointAddress, OUT PUSHORT Value); +NTSTATUS +USBSTOR_ResetPipeWithHandle( + IN PDEVICE_OBJECT DeviceObject, + IN USBD_PIPE_HANDLE PipeHandle); +