2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: USB block storage device driver.
5 * COPYRIGHT: 2005-2006 James Tabor
6 * 2011-2012 Michael Martin (michael.martin@reactos.org)
7 * 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
17 USBSTOR_GetEndpointStatus(
18 IN PDEVICE_OBJECT DeviceObject
,
19 IN UCHAR bEndpointAddress
,
25 DPRINT("Allocating URB\n");
26 Urb
= (PURB
)AllocateItem(NonPagedPool
, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
));
29 DPRINT1("OutofMemory!\n");
30 return STATUS_INSUFFICIENT_RESOURCES
;
34 UsbBuildGetStatusRequest(Urb
, URB_FUNCTION_GET_STATUS_FROM_ENDPOINT
, bEndpointAddress
& 0x0F, Value
, NULL
, NULL
);
37 DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject
, Urb
);
38 Status
= USBSTOR_SyncUrbRequest(DeviceObject
, Urb
);
45 USBSTOR_ResetPipeWithHandle(
46 IN PDEVICE_OBJECT DeviceObject
,
47 IN USBD_PIPE_HANDLE PipeHandle
)
52 DPRINT("Allocating URB\n");
53 Urb
= (PURB
)AllocateItem(NonPagedPool
, sizeof(struct _URB_PIPE_REQUEST
));
56 DPRINT1("OutofMemory!\n");
57 return STATUS_INSUFFICIENT_RESOURCES
;
60 Urb
->UrbPipeRequest
.Hdr
.Length
= sizeof(struct _URB_PIPE_REQUEST
);
61 Urb
->UrbPipeRequest
.Hdr
.Function
= URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL
;
62 Urb
->UrbPipeRequest
.PipeHandle
= PipeHandle
;
65 DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject
, Urb
);
66 Status
= USBSTOR_SyncUrbRequest(DeviceObject
, Urb
);
73 USBSTOR_HandleTransferError(
74 PDEVICE_OBJECT DeviceObject
,
77 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
78 NTSTATUS Status
= STATUS_SUCCESS
;
79 PIO_STACK_LOCATION Stack
;
80 PSCSI_REQUEST_BLOCK Request
;
86 // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification
87 Status
= USBSTOR_ResetDevice(Context
->FDODeviceExtension
->LowerDeviceObject
, Context
->FDODeviceExtension
);
88 if (NT_SUCCESS(Status
))
90 // step 2 reset bulk in pipe section 5.3.4
91 Status
= USBSTOR_ResetPipeWithHandle(Context
->FDODeviceExtension
->LowerDeviceObject
, Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
);
92 if (NT_SUCCESS(Status
))
94 // finally reset bulk out pipe
95 Status
= USBSTOR_ResetPipeWithHandle(Context
->FDODeviceExtension
->LowerDeviceObject
, Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
);
99 Stack
= IoGetCurrentIrpStackLocation(Context
->Irp
);
100 ASSERT(Stack
->DeviceObject
);
101 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)Stack
->DeviceObject
->DeviceExtension
;
103 Request
= (PSCSI_REQUEST_BLOCK
)Stack
->Parameters
.Others
.Argument1
;
106 // obtain request type
107 pCDB
= (PCDB
)Request
->Cdb
;
110 if (Status
!= STATUS_SUCCESS
|| Context
->RetryCount
>= 1)
112 // Complete the master IRP
113 Context
->Irp
->IoStatus
.Status
= Status
;
114 Context
->Irp
->IoStatus
.Information
= 0;
115 USBSTOR_QueueTerminateRequest(PDODeviceExtension
->LowerDeviceObject
, Context
->Irp
);
116 IoCompleteRequest(Context
->Irp
, IO_NO_INCREMENT
);
118 // Start the next request
119 USBSTOR_QueueNextRequest(PDODeviceExtension
->LowerDeviceObject
);
121 // srb handling finished
122 Context
->FDODeviceExtension
->SrbErrorHandlingActive
= FALSE
;
125 Context
->FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
129 DPRINT1("Retrying Count %lu %p\n", Context
->RetryCount
, Stack
->DeviceObject
);
131 // re-schedule request
132 USBSTOR_HandleExecuteSCSI(Stack
->DeviceObject
, Context
->Irp
, Context
->RetryCount
+ 1);
134 // srb error handling finished
135 Context
->FDODeviceExtension
->SrbErrorHandlingActive
= FALSE
;
137 // srb error handling finished
138 Context
->FDODeviceExtension
->TimerWorkQueueEnabled
= TRUE
;
141 Context
->FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
146 DPRINT1("USBSTOR_HandleTransferError returning with Status %x\n", Status
);
152 USBSTOR_ResetHandlerWorkItemRoutine(
156 PERRORHANDLER_WORKITEM_DATA WorkItemData
= (PERRORHANDLER_WORKITEM_DATA
)Context
;
158 // clear stall on BulkIn pipe
159 Status
= USBSTOR_ResetPipeWithHandle(WorkItemData
->Context
->FDODeviceExtension
->LowerDeviceObject
, WorkItemData
->Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[WorkItemData
->Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
);
160 DPRINT1("USBSTOR_ResetPipeWithHandle Status %x\n", Status
);
162 // now resend the csw as the stall got cleared
163 USBSTOR_SendCSWRequest(WorkItemData
->Context
, WorkItemData
->Irp
);
168 ErrorHandlerWorkItemRoutine(
171 PERRORHANDLER_WORKITEM_DATA WorkItemData
= (PERRORHANDLER_WORKITEM_DATA
)Context
;
173 if (WorkItemData
->Context
->ErrorIndex
== 2)
176 USBSTOR_HandleTransferError(WorkItemData
->DeviceObject
, WorkItemData
->Context
);
181 USBSTOR_ResetHandlerWorkItemRoutine(WorkItemData
);
184 // Free Work Item Data
185 ExFreePoolWithTag(WorkItemData
, USB_STOR_TAG
);
190 USBSTOR_TimerWorkerRoutine(
193 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
195 PERRORHANDLER_WORKITEM_DATA WorkItemData
= (PERRORHANDLER_WORKITEM_DATA
)Context
;
197 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)WorkItemData
->DeviceObject
->DeviceExtension
;
198 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
200 // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification
201 Status
= USBSTOR_ResetDevice(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
);
202 if (NT_SUCCESS(Status
))
204 // step 2 reset bulk in pipe section 5.3.4
205 Status
= USBSTOR_ResetPipeWithHandle(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
);
206 if (NT_SUCCESS(Status
))
208 // finally reset bulk out pipe
209 Status
= USBSTOR_ResetPipeWithHandle(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
);
212 DPRINT1("Status %x\n", Status
);
215 FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
217 // re-schedule request
218 //USBSTOR_HandleExecuteSCSI(WorkItemData->Context->PDODeviceExtension->Self, WorkItemData->Context->Irp, Context->RetryCount + 1);
220 // do not retry for the same packet again
221 FDODeviceExtension
->TimerWorkQueueEnabled
= FALSE
;
223 ExFreePoolWithTag(WorkItemData
, USB_STOR_TAG
);
228 USBSTOR_TimerRoutine(
229 PDEVICE_OBJECT DeviceObject
,
232 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
233 BOOLEAN ResetDevice
= FALSE
;
234 PERRORHANDLER_WORKITEM_DATA WorkItemData
;
236 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)Context
;
237 DPRINT1("[USBSTOR] TimerRoutine entered\n");
238 DPRINT1("[USBSTOR] ActiveSrb %p ResetInProgress %x LastTimerActiveSrb %p\n", FDODeviceExtension
->ActiveSrb
, FDODeviceExtension
->ResetInProgress
, FDODeviceExtension
->LastTimerActiveSrb
);
240 KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension
->IrpListLock
);
242 // is there an active srb and no global reset is in progress
243 if (FDODeviceExtension
->ActiveSrb
&& FDODeviceExtension
->ResetInProgress
== FALSE
&& FDODeviceExtension
->TimerWorkQueueEnabled
)
245 if (FDODeviceExtension
->LastTimerActiveSrb
!= NULL
&& FDODeviceExtension
->LastTimerActiveSrb
== FDODeviceExtension
->ActiveSrb
)
248 DPRINT1("[USBSTOR] ActiveSrb %p hang detected\n", FDODeviceExtension
->ActiveSrb
);
254 FDODeviceExtension
->LastTimerActiveSrb
= FDODeviceExtension
->ActiveSrb
;
260 FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
263 KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension
->IrpListLock
);
266 if (ResetDevice
&& FDODeviceExtension
->TimerWorkQueueEnabled
&& FDODeviceExtension
->SrbErrorHandlingActive
== FALSE
)
268 WorkItemData
= ExAllocatePoolWithTag(NonPagedPool
,
269 sizeof(ERRORHANDLER_WORKITEM_DATA
),
273 // Initialize and queue the work item to handle the error
274 ExInitializeWorkItem(&WorkItemData
->WorkQueueItem
,
275 USBSTOR_TimerWorkerRoutine
,
278 WorkItemData
->DeviceObject
= FDODeviceExtension
->FunctionalDeviceObject
;
280 DPRINT1("[USBSTOR] Queing Timer WorkItem\n");
281 ExQueueWorkItem(&WorkItemData
->WorkQueueItem
, DelayedWorkQueue
);