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)
8 * 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
18 USBSTOR_GetEndpointStatus(
19 IN PDEVICE_OBJECT DeviceObject
,
20 IN UCHAR bEndpointAddress
,
26 DPRINT("Allocating URB\n");
27 Urb
= (PURB
)AllocateItem(NonPagedPool
, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST
));
30 DPRINT1("OutofMemory!\n");
31 return STATUS_INSUFFICIENT_RESOURCES
;
35 UsbBuildGetStatusRequest(Urb
, URB_FUNCTION_GET_STATUS_FROM_ENDPOINT
, bEndpointAddress
& 0x0F, Value
, NULL
, NULL
);
38 DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject
, Urb
);
39 Status
= USBSTOR_SyncUrbRequest(DeviceObject
, Urb
);
46 USBSTOR_ResetPipeWithHandle(
47 IN PDEVICE_OBJECT DeviceObject
,
48 IN USBD_PIPE_HANDLE PipeHandle
)
53 DPRINT("Allocating URB\n");
54 Urb
= (PURB
)AllocateItem(NonPagedPool
, sizeof(struct _URB_PIPE_REQUEST
));
57 DPRINT1("OutofMemory!\n");
58 return STATUS_INSUFFICIENT_RESOURCES
;
61 Urb
->UrbPipeRequest
.Hdr
.Length
= sizeof(struct _URB_PIPE_REQUEST
);
62 Urb
->UrbPipeRequest
.Hdr
.Function
= URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL
;
63 Urb
->UrbPipeRequest
.PipeHandle
= PipeHandle
;
66 DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject
, Urb
);
67 Status
= USBSTOR_SyncUrbRequest(DeviceObject
, Urb
);
75 USBSTOR_ResetPipeWorkItemRoutine(
76 IN PDEVICE_OBJECT FdoDevice
,
80 PFDO_DEVICE_EXTENSION FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)Ctx
;
81 PIRP_CONTEXT Context
= &FDODeviceExtension
->CurrentIrpContext
;
83 // clear stall on the corresponding pipe
84 Status
= USBSTOR_ResetPipeWithHandle(FDODeviceExtension
->LowerDeviceObject
, Context
->Urb
.UrbBulkOrInterruptTransfer
.PipeHandle
);
85 DPRINT1("USBSTOR_ResetPipeWithHandle Status %x\n", Status
);
87 // now resend the csw as the stall got cleared
88 USBSTOR_SendCSWRequest(FDODeviceExtension
, Context
->Irp
);
93 USBSTOR_ResetDeviceWorkItemRoutine(
94 IN PDEVICE_OBJECT FdoDevice
,
97 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
102 DPRINT("USBSTOR_ResetDeviceWorkItemRoutine\n");
104 FDODeviceExtension
= FdoDevice
->DeviceExtension
;
106 for (ix
= 0; ix
< 3; ++ix
)
108 // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification
109 Status
= USBSTOR_ResetDevice(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
);
110 if (NT_SUCCESS(Status
))
112 // step 2 reset bulk in pipe section 5.3.4
113 Status
= USBSTOR_ResetPipeWithHandle(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
);
114 if (NT_SUCCESS(Status
))
116 // finally reset bulk out pipe
117 Status
= USBSTOR_ResetPipeWithHandle(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
);
118 if (NT_SUCCESS(Status
))
126 KeAcquireSpinLock(&FDODeviceExtension
->CommonLock
, &OldIrql
);
127 FDODeviceExtension
->Flags
&= ~USBSTOR_FDO_FLAGS_DEVICE_RESETTING
;
128 KeReleaseSpinLock(&FDODeviceExtension
->CommonLock
, OldIrql
);
130 USBSTOR_QueueNextRequest(FdoDevice
);
135 USBSTOR_QueueResetPipe(
136 IN PFDO_DEVICE_EXTENSION FDODeviceExtension
)
138 DPRINT("USBSTOR_QueueResetPipe\n");
140 IoQueueWorkItem(FDODeviceExtension
->ResetDeviceWorkItem
,
141 USBSTOR_ResetPipeWorkItemRoutine
,
148 USBSTOR_QueueResetDevice(
149 IN PFDO_DEVICE_EXTENSION FDODeviceExtension
)
153 DPRINT("USBSTOR_QueueResetDevice\n");
155 KeAcquireSpinLock(&FDODeviceExtension
->CommonLock
, &OldIrql
);
156 FDODeviceExtension
->Flags
|= USBSTOR_FDO_FLAGS_DEVICE_RESETTING
;
157 KeReleaseSpinLock(&FDODeviceExtension
->CommonLock
, OldIrql
);
159 IoQueueWorkItem(FDODeviceExtension
->ResetDeviceWorkItem
,
160 USBSTOR_ResetDeviceWorkItemRoutine
,
167 USBSTOR_TimerWorkerRoutine(
170 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
172 PERRORHANDLER_WORKITEM_DATA WorkItemData
= (PERRORHANDLER_WORKITEM_DATA
)Context
;
174 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)WorkItemData
->DeviceObject
->DeviceExtension
;
175 ASSERT(FDODeviceExtension
->Common
.IsFDO
);
177 // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification
178 Status
= USBSTOR_ResetDevice(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
);
179 if (NT_SUCCESS(Status
))
181 // step 2 reset bulk in pipe section 5.3.4
182 Status
= USBSTOR_ResetPipeWithHandle(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
);
183 if (NT_SUCCESS(Status
))
185 // finally reset bulk out pipe
186 Status
= USBSTOR_ResetPipeWithHandle(FDODeviceExtension
->LowerDeviceObject
, FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
);
189 DPRINT1("Status %x\n", Status
);
192 FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
194 // re-schedule request
195 //USBSTOR_HandleExecuteSCSI(WorkItemData->Context->PDODeviceExtension->Self, WorkItemData->Context->Irp, Context->RetryCount + 1);
197 // do not retry for the same packet again
198 FDODeviceExtension
->TimerWorkQueueEnabled
= FALSE
;
200 ExFreePoolWithTag(WorkItemData
, USB_STOR_TAG
);
205 USBSTOR_TimerRoutine(
206 PDEVICE_OBJECT DeviceObject
,
209 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
210 BOOLEAN ResetDevice
= FALSE
;
211 PERRORHANDLER_WORKITEM_DATA WorkItemData
;
213 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)Context
;
214 DPRINT1("[USBSTOR] TimerRoutine entered\n");
215 // DPRINT1("[USBSTOR] ActiveSrb %p ResetInProgress %x LastTimerActiveSrb %p\n", FDODeviceExtension->ActiveSrb, FDODeviceExtension->ResetInProgress, FDODeviceExtension->LastTimerActiveSrb);
217 KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension
->IrpListLock
);
219 // is there an active srb and no global reset is in progress
220 if (FDODeviceExtension
->ActiveSrb
&& /* FDODeviceExtension->ResetInProgress == FALSE && */ FDODeviceExtension
->TimerWorkQueueEnabled
)
222 if (FDODeviceExtension
->LastTimerActiveSrb
!= NULL
&& FDODeviceExtension
->LastTimerActiveSrb
== FDODeviceExtension
->ActiveSrb
)
225 DPRINT1("[USBSTOR] ActiveSrb %p hang detected\n", FDODeviceExtension
->ActiveSrb
);
231 FDODeviceExtension
->LastTimerActiveSrb
= FDODeviceExtension
->ActiveSrb
;
237 FDODeviceExtension
->LastTimerActiveSrb
= NULL
;
240 KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension
->IrpListLock
);
243 if (ResetDevice
&& FDODeviceExtension
->TimerWorkQueueEnabled
&& FDODeviceExtension
->SrbErrorHandlingActive
== FALSE
)
245 WorkItemData
= ExAllocatePoolWithTag(NonPagedPool
,
246 sizeof(ERRORHANDLER_WORKITEM_DATA
),
250 // Initialize and queue the work item to handle the error
251 ExInitializeWorkItem(&WorkItemData
->WorkQueueItem
,
252 USBSTOR_TimerWorkerRoutine
,
255 WorkItemData
->DeviceObject
= FDODeviceExtension
->FunctionalDeviceObject
;
257 DPRINT1("[USBSTOR] Queing Timer WorkItem\n");
258 ExQueueWorkItem(&WorkItemData
->WorkQueueItem
, DelayedWorkQueue
);