2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbstor/error.c
5 * PURPOSE: USB block storage device driver.
8 * Michael Martin (michael.martin@reactos.org)
9 * Johannes Anderwald (johannes.anderwald@reactos.org)
15 USBSTOR_GetEndpointStatus(
16 IN PDEVICE_OBJECT DeviceObject
,
17 IN UCHAR bEndpointAddress
,
26 DPRINT("Allocating URB\n");
27 Urb
= (PURB
)AllocateItem(NonPagedPool
, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
));
33 DPRINT1("OutofMemory!\n");
34 return STATUS_INSUFFICIENT_RESOURCES
;
40 UsbBuildGetStatusRequest(Urb
, URB_FUNCTION_GET_STATUS_FROM_ENDPOINT
, bEndpointAddress
& 0x0F, Value
, NULL
, NULL
);
45 DPRINT1("Sending Request DeviceObject %x, Urb %x\n", DeviceObject
, Urb
);
46 Status
= USBSTOR_SyncUrbRequest(DeviceObject
, Urb
);
62 USBSTOR_ResetPipeWithHandle(
63 IN PDEVICE_OBJECT DeviceObject
,
64 IN USBD_PIPE_HANDLE PipeHandle
)
72 DPRINT("Allocating URB\n");
73 Urb
= (PURB
)AllocateItem(NonPagedPool
, sizeof(struct _URB_PIPE_REQUEST
));
79 DPRINT1("OutofMemory!\n");
80 return STATUS_INSUFFICIENT_RESOURCES
;
86 Urb
->UrbPipeRequest
.Hdr
.Length
= sizeof(struct _URB_PIPE_REQUEST
);
87 Urb
->UrbPipeRequest
.Hdr
.Function
= URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL
;
88 Urb
->UrbPipeRequest
.PipeHandle
= PipeHandle
;
93 DPRINT1("Sending Request DeviceObject %x, Urb %x\n", DeviceObject
, Urb
);
94 Status
= USBSTOR_SyncUrbRequest(DeviceObject
, Urb
);
109 USBSTOR_HandleTransferError(
110 PDEVICE_OBJECT DeviceObject
,
111 PIRP_CONTEXT Context
)
113 NTSTATUS Status
= STATUS_SUCCESS
;
114 PIO_STACK_LOCATION Stack
;
115 PSCSI_REQUEST_BLOCK Request
;
122 ASSERT(Context
->PDODeviceExtension
);
123 ASSERT(Context
->PDODeviceExtension
->Self
);
124 ASSERT(Context
->Irp
);
127 // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification
129 Status
= USBSTOR_ResetDevice(Context
->FDODeviceExtension
->LowerDeviceObject
, Context
->FDODeviceExtension
);
130 if (NT_SUCCESS(Status
))
133 // step 2 reset bulk in pipe section 5.3.4
135 Status
= USBSTOR_ResetPipeWithHandle(Context
->FDODeviceExtension
->LowerDeviceObject
, Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
);
136 if (NT_SUCCESS(Status
))
139 // finally reset bulk out pipe
141 Status
= USBSTOR_ResetPipeWithHandle(Context
->FDODeviceExtension
->LowerDeviceObject
, Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
);
146 // get next stack location
148 Stack
= IoGetCurrentIrpStackLocation(Context
->Irp
);
153 Request
= (PSCSI_REQUEST_BLOCK
)Stack
->Parameters
.Others
.Argument1
;
157 // obtain request type
159 pCDB
= (PCDB
)Request
->Cdb
;
162 if (Status
!= STATUS_SUCCESS
|| Context
->RetryCount
>= 1)
165 // Complete the master IRP
167 Context
->Irp
->IoStatus
.Status
= Status
;
168 Context
->Irp
->IoStatus
.Information
= 0;
169 USBSTOR_QueueTerminateRequest(Context
->PDODeviceExtension
->LowerDeviceObject
, Context
->Irp
);
170 IoCompleteRequest(Context
->Irp
, IO_NO_INCREMENT
);
173 // Start the next request
175 USBSTOR_QueueNextRequest(Context
->PDODeviceExtension
->LowerDeviceObject
);
178 // srb handling finished
180 Context
->FDODeviceExtension
->SrbErrorHandlingActive
= FALSE
;
185 Context
->FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
189 DPRINT1("Retrying Count %lu %p\n", Context
->RetryCount
, Context
->PDODeviceExtension
->Self
);
192 // re-schedule request
194 USBSTOR_HandleExecuteSCSI(Context
->PDODeviceExtension
->Self
, Context
->Irp
, Context
->RetryCount
+ 1);
197 // srb error handling finished
199 Context
->FDODeviceExtension
->SrbErrorHandlingActive
= FALSE
;
202 // srb error handling finished
204 Context
->FDODeviceExtension
->TimerWorkQueueEnabled
= TRUE
;
209 Context
->FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
213 // cleanup irp context
215 FreeItem(Context
->cbw
);
219 DPRINT1("USBSTOR_HandleTransferError returning with Status %x\n", Status
);
225 USBSTOR_ResetHandlerWorkItemRoutine(
229 PERRORHANDLER_WORKITEM_DATA WorkItemData
= (PERRORHANDLER_WORKITEM_DATA
)Context
;
232 // clear stall on BulkIn pipe
234 Status
= USBSTOR_ResetPipeWithHandle(WorkItemData
->Context
->FDODeviceExtension
->LowerDeviceObject
, WorkItemData
->Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[WorkItemData
->Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
);
235 DPRINT1("USBSTOR_ResetPipeWithHandle Status %x\n", Status
);
238 // now resend the csw as the stall got cleared
240 USBSTOR_SendCSW(WorkItemData
->Context
, WorkItemData
->Irp
);
245 ErrorHandlerWorkItemRoutine(
249 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
250 PERRORHANDLER_WORKITEM_DATA WorkItemData
= (PERRORHANDLER_WORKITEM_DATA
)Context
;
255 FDODeviceExtension
= WorkItemData
->Context
->FDODeviceExtension
;
257 if (WorkItemData
->Context
->ErrorIndex
== 2)
262 Status
= USBSTOR_HandleTransferError(WorkItemData
->DeviceObject
, WorkItemData
->Context
);
269 USBSTOR_ResetHandlerWorkItemRoutine(WorkItemData
);
273 // Free Work Item Data
275 ExFreePool(WorkItemData
);
280 USBSTOR_TimerWorkerRoutine(
283 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
285 PERRORHANDLER_WORKITEM_DATA WorkItemData
= (PERRORHANDLER_WORKITEM_DATA
)Context
;
288 // get device extension
290 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)WorkItemData
->DeviceObject
->DeviceExtension
;
291 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
294 // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification
296 Status
= USBSTOR_ResetDevice(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
);
297 if (NT_SUCCESS(Status
))
300 // step 2 reset bulk in pipe section 5.3.4
302 Status
= USBSTOR_ResetPipeWithHandle(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
);
303 if (NT_SUCCESS(Status
))
306 // finally reset bulk out pipe
308 Status
= USBSTOR_ResetPipeWithHandle(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
);
311 DPRINT1("Status %x\n", Status
);
316 FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
319 // re-schedule request
321 //USBSTOR_HandleExecuteSCSI(WorkItemData->Context->PDODeviceExtension->Self, WorkItemData->Context->Irp, Context->RetryCount + 1);
326 // do not retry for the same packet again
328 FDODeviceExtension
->TimerWorkQueueEnabled
= FALSE
;
331 // Free Work Item Data
333 ExFreePool(WorkItemData
);
339 USBSTOR_TimerRoutine(
340 PDEVICE_OBJECT DeviceObject
,
343 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
344 BOOLEAN ResetDevice
= FALSE
;
345 PERRORHANDLER_WORKITEM_DATA WorkItemData
;
348 // get device extension
350 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)Context
;
351 DPRINT1("[USBSTOR] TimerRoutine entered\n");
352 DPRINT1("[USBSTOR] ActiveSrb %p ResetInProgress %x LastTimerActiveSrb %p\n", FDODeviceExtension
->ActiveSrb
, FDODeviceExtension
->ResetInProgress
, FDODeviceExtension
->LastTimerActiveSrb
);
357 KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension
->IrpListLock
);
360 // is there an active srb and no global reset is in progress
362 if (FDODeviceExtension
->ActiveSrb
&& FDODeviceExtension
->ResetInProgress
== FALSE
&& FDODeviceExtension
->TimerWorkQueueEnabled
)
364 if (FDODeviceExtension
->LastTimerActiveSrb
!= NULL
&& FDODeviceExtension
->LastTimerActiveSrb
== FDODeviceExtension
->ActiveSrb
)
369 DPRINT1("[USBSTOR] ActiveSrb %p hang detected\n", FDODeviceExtension
->ActiveSrb
);
377 FDODeviceExtension
->LastTimerActiveSrb
= FDODeviceExtension
->ActiveSrb
;
385 FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
391 KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension
->IrpListLock
);
394 if (ResetDevice
&& FDODeviceExtension
->TimerWorkQueueEnabled
&& FDODeviceExtension
->SrbErrorHandlingActive
== FALSE
)
396 WorkItemData
= (PERRORHANDLER_WORKITEM_DATA
)ExAllocatePool(NonPagedPool
, sizeof(ERRORHANDLER_WORKITEM_DATA
));
400 // Initialize and queue the work item to handle the error
402 ExInitializeWorkItem(&WorkItemData
->WorkQueueItem
,
403 USBSTOR_TimerWorkerRoutine
,
406 WorkItemData
->DeviceObject
= FDODeviceExtension
->FunctionalDeviceObject
;
408 DPRINT1("[USBSTOR] Queing Timer WorkItem\n");
409 ExQueueWorkItem(&WorkItemData
->WorkQueueItem
, DelayedWorkQueue
);