1 /* 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) 9 */ 10 11 #include "usbstor.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 17 NTSTATUS 18 USBSTOR_GetEndpointStatus( 19 IN PDEVICE_OBJECT DeviceObject, 20 IN UCHAR bEndpointAddress, 21 OUT PUSHORT Value) 22 { 23 PURB Urb; 24 NTSTATUS Status; 25 26 DPRINT("Allocating URB\n"); 27 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 28 if (!Urb) 29 { 30 DPRINT1("OutofMemory!\n"); 31 return STATUS_INSUFFICIENT_RESOURCES; 32 } 33 34 // build status 35 UsbBuildGetStatusRequest(Urb, URB_FUNCTION_GET_STATUS_FROM_ENDPOINT, bEndpointAddress & 0x0F, Value, NULL, NULL); 36 37 // send the request 38 DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject, Urb); 39 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb); 40 41 FreeItem(Urb); 42 return Status; 43 } 44 45 NTSTATUS 46 USBSTOR_ResetPipeWithHandle( 47 IN PDEVICE_OBJECT DeviceObject, 48 IN USBD_PIPE_HANDLE PipeHandle) 49 { 50 PURB Urb; 51 NTSTATUS Status; 52 53 DPRINT("Allocating URB\n"); 54 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST)); 55 if (!Urb) 56 { 57 DPRINT1("OutofMemory!\n"); 58 return STATUS_INSUFFICIENT_RESOURCES; 59 } 60 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; 64 65 // send the request 66 DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject, Urb); 67 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb); 68 69 FreeItem(Urb); 70 return Status; 71 } 72 73 VOID 74 NTAPI 75 USBSTOR_ResetPipeWorkItemRoutine( 76 IN PDEVICE_OBJECT FdoDevice, 77 IN PVOID Ctx) 78 { 79 NTSTATUS Status; 80 PFDO_DEVICE_EXTENSION FDODeviceExtension = (PFDO_DEVICE_EXTENSION)Ctx; 81 PIRP_CONTEXT Context = &FDODeviceExtension->CurrentIrpContext; 82 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); 86 87 // now resend the csw as the stall got cleared 88 USBSTOR_SendCSWRequest(FDODeviceExtension, Context->Irp); 89 } 90 91 VOID 92 NTAPI 93 USBSTOR_ResetDeviceWorkItemRoutine( 94 IN PDEVICE_OBJECT FdoDevice, 95 IN PVOID Context) 96 { 97 PFDO_DEVICE_EXTENSION FDODeviceExtension; 98 UINT32 ix; 99 NTSTATUS Status; 100 KIRQL OldIrql; 101 102 DPRINT("USBSTOR_ResetDeviceWorkItemRoutine\n"); 103 104 FDODeviceExtension = FdoDevice->DeviceExtension; 105 106 for (ix = 0; ix < 3; ++ix) 107 { 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)) 111 { 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)) 115 { 116 // finally reset bulk out pipe 117 Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle); 118 if (NT_SUCCESS(Status)) 119 { 120 break; 121 } 122 } 123 } 124 } 125 126 KeAcquireSpinLock(&FDODeviceExtension->CommonLock, &OldIrql); 127 FDODeviceExtension->Flags &= ~USBSTOR_FDO_FLAGS_DEVICE_RESETTING; 128 KeReleaseSpinLock(&FDODeviceExtension->CommonLock, OldIrql); 129 130 USBSTOR_QueueNextRequest(FdoDevice); 131 } 132 133 VOID 134 NTAPI 135 USBSTOR_QueueResetPipe( 136 IN PFDO_DEVICE_EXTENSION FDODeviceExtension) 137 { 138 DPRINT("USBSTOR_QueueResetPipe\n"); 139 140 IoQueueWorkItem(FDODeviceExtension->ResetDeviceWorkItem, 141 USBSTOR_ResetPipeWorkItemRoutine, 142 CriticalWorkQueue, 143 FDODeviceExtension); 144 } 145 146 VOID 147 NTAPI 148 USBSTOR_QueueResetDevice( 149 IN PFDO_DEVICE_EXTENSION FDODeviceExtension) 150 { 151 KIRQL OldIrql; 152 153 DPRINT("USBSTOR_QueueResetDevice\n"); 154 155 KeAcquireSpinLock(&FDODeviceExtension->CommonLock, &OldIrql); 156 FDODeviceExtension->Flags |= USBSTOR_FDO_FLAGS_DEVICE_RESETTING; 157 KeReleaseSpinLock(&FDODeviceExtension->CommonLock, OldIrql); 158 159 IoQueueWorkItem(FDODeviceExtension->ResetDeviceWorkItem, 160 USBSTOR_ResetDeviceWorkItemRoutine, 161 CriticalWorkQueue, 162 NULL); 163 } 164 165 VOID 166 NTAPI 167 USBSTOR_TimerWorkerRoutine( 168 IN PVOID Context) 169 { 170 PFDO_DEVICE_EXTENSION FDODeviceExtension; 171 NTSTATUS Status; 172 PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; 173 174 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)WorkItemData->DeviceObject->DeviceExtension; 175 ASSERT(FDODeviceExtension->Common.IsFDO); 176 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)) 180 { 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)) 184 { 185 // finally reset bulk out pipe 186 Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle); 187 } 188 } 189 DPRINT1("Status %x\n", Status); 190 191 // clear timer srb 192 FDODeviceExtension->LastTimerActiveSrb = NULL; 193 194 // re-schedule request 195 //USBSTOR_HandleExecuteSCSI(WorkItemData->Context->PDODeviceExtension->Self, WorkItemData->Context->Irp, Context->RetryCount + 1); 196 197 // do not retry for the same packet again 198 FDODeviceExtension->TimerWorkQueueEnabled = FALSE; 199 200 ExFreePoolWithTag(WorkItemData, USB_STOR_TAG); 201 } 202 203 VOID 204 NTAPI 205 USBSTOR_TimerRoutine( 206 PDEVICE_OBJECT DeviceObject, 207 PVOID Context) 208 { 209 PFDO_DEVICE_EXTENSION FDODeviceExtension; 210 BOOLEAN ResetDevice = FALSE; 211 PERRORHANDLER_WORKITEM_DATA WorkItemData; 212 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); 216 217 KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock); 218 219 // is there an active srb and no global reset is in progress 220 if (FDODeviceExtension->ActiveSrb && /* FDODeviceExtension->ResetInProgress == FALSE && */ FDODeviceExtension->TimerWorkQueueEnabled) 221 { 222 if (FDODeviceExtension->LastTimerActiveSrb != NULL && FDODeviceExtension->LastTimerActiveSrb == FDODeviceExtension->ActiveSrb) 223 { 224 // check if empty 225 DPRINT1("[USBSTOR] ActiveSrb %p hang detected\n", FDODeviceExtension->ActiveSrb); 226 ResetDevice = TRUE; 227 } 228 else 229 { 230 // update pointer 231 FDODeviceExtension->LastTimerActiveSrb = FDODeviceExtension->ActiveSrb; 232 } 233 } 234 else 235 { 236 // reset srb 237 FDODeviceExtension->LastTimerActiveSrb = NULL; 238 } 239 240 KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock); 241 242 243 if (ResetDevice && FDODeviceExtension->TimerWorkQueueEnabled && FDODeviceExtension->SrbErrorHandlingActive == FALSE) 244 { 245 WorkItemData = ExAllocatePoolWithTag(NonPagedPool, 246 sizeof(ERRORHANDLER_WORKITEM_DATA), 247 USB_STOR_TAG); 248 if (WorkItemData) 249 { 250 // Initialize and queue the work item to handle the error 251 ExInitializeWorkItem(&WorkItemData->WorkQueueItem, 252 USBSTOR_TimerWorkerRoutine, 253 WorkItemData); 254 255 WorkItemData->DeviceObject = FDODeviceExtension->FunctionalDeviceObject; 256 257 DPRINT1("[USBSTOR] Queing Timer WorkItem\n"); 258 ExQueueWorkItem(&WorkItemData->WorkQueueItem, DelayedWorkQueue); 259 } 260 } 261 } 262