[USBSTOR]

- Rewrite error handling
- Check if CSW is valid
- Check if the error handling was already started
- Reset device if required
- Error handling was completely broken and did not follow the reset procedure as defined in USB Mass Storage Specification Bulk Only Section 5.3.4
- Mass storage device now longer hang when receiving the read capacity request and ReactOS assigns a symbolic link
- Mass storage devices not yet fully working

svn path=/trunk/; revision=55601
This commit is contained in:
Johannes Anderwald 2012-02-15 03:52:37 +00:00
parent 377558ac5a
commit 58df973ed5
4 changed files with 291 additions and 163 deletions

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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);