1 /* 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. 6 * PROGRAMMERS: 7 * James Tabor 8 * Michael Martin (michael.martin@reactos.org) 9 * Johannes Anderwald (johannes.anderwald@reactos.org) 10 */ 11 12 #include "usbstor.h" 13 14 #define NDEBUG 15 #include <debug.h> 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 // 27 // allocate urb 28 // 29 DPRINT("Allocating URB\n"); 30 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); 31 if (!Urb) 32 { 33 // 34 // out of memory 35 // 36 DPRINT1("OutofMemory!\n"); 37 return STATUS_INSUFFICIENT_RESOURCES; 38 } 39 40 // 41 // build status 42 // 43 UsbBuildGetStatusRequest(Urb, URB_FUNCTION_GET_STATUS_FROM_ENDPOINT, bEndpointAddress & 0x0F, Value, NULL, NULL); 44 45 // 46 // send the request 47 // 48 DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject, Urb); 49 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb); 50 51 // 52 // free urb 53 // 54 FreeItem(Urb); 55 56 // 57 // done 58 // 59 return Status; 60 } 61 62 63 64 NTSTATUS 65 USBSTOR_ResetPipeWithHandle( 66 IN PDEVICE_OBJECT DeviceObject, 67 IN USBD_PIPE_HANDLE PipeHandle) 68 { 69 PURB Urb; 70 NTSTATUS Status; 71 72 // 73 // allocate urb 74 // 75 DPRINT("Allocating URB\n"); 76 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_PIPE_REQUEST)); 77 if (!Urb) 78 { 79 // 80 // out of memory 81 // 82 DPRINT1("OutofMemory!\n"); 83 return STATUS_INSUFFICIENT_RESOURCES; 84 } 85 86 // 87 // initialize the urb 88 // 89 Urb->UrbPipeRequest.Hdr.Length = sizeof(struct _URB_PIPE_REQUEST); 90 Urb->UrbPipeRequest.Hdr.Function = URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL; 91 Urb->UrbPipeRequest.PipeHandle = PipeHandle; 92 93 // 94 // send the request 95 // 96 DPRINT1("Sending Request DeviceObject %p, Urb %p\n", DeviceObject, Urb); 97 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb); 98 99 // 100 // free urb 101 // 102 FreeItem(Urb); 103 104 // 105 // done 106 // 107 return Status; 108 } 109 110 111 NTSTATUS 112 USBSTOR_HandleTransferError( 113 PDEVICE_OBJECT DeviceObject, 114 PIRP_CONTEXT Context) 115 { 116 NTSTATUS Status = STATUS_SUCCESS; 117 PIO_STACK_LOCATION Stack; 118 PSCSI_REQUEST_BLOCK Request; 119 PCDB pCDB; 120 121 // 122 // sanity checks 123 // 124 ASSERT(Context); 125 ASSERT(Context->PDODeviceExtension); 126 ASSERT(Context->PDODeviceExtension->Self); 127 ASSERT(Context->Irp); 128 129 // 130 // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification 131 // 132 Status = USBSTOR_ResetDevice(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension); 133 if (NT_SUCCESS(Status)) 134 { 135 // 136 // step 2 reset bulk in pipe section 5.3.4 137 // 138 Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle); 139 if (NT_SUCCESS(Status)) 140 { 141 // 142 // finally reset bulk out pipe 143 // 144 Status = USBSTOR_ResetPipeWithHandle(Context->FDODeviceExtension->LowerDeviceObject, Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle); 145 } 146 } 147 148 // 149 // get next stack location 150 // 151 Stack = IoGetCurrentIrpStackLocation(Context->Irp); 152 153 // 154 // get request block 155 // 156 Request = (PSCSI_REQUEST_BLOCK)Stack->Parameters.Others.Argument1; 157 ASSERT(Request); 158 159 // 160 // obtain request type 161 // 162 pCDB = (PCDB)Request->Cdb; 163 ASSERT(pCDB); 164 165 if (Status != STATUS_SUCCESS || Context->RetryCount >= 1) 166 { 167 // 168 // Complete the master IRP 169 // 170 Context->Irp->IoStatus.Status = Status; 171 Context->Irp->IoStatus.Information = 0; 172 USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp); 173 IoCompleteRequest(Context->Irp, IO_NO_INCREMENT); 174 175 // 176 // Start the next request 177 // 178 USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject); 179 180 // 181 // srb handling finished 182 // 183 Context->FDODeviceExtension->SrbErrorHandlingActive = FALSE; 184 185 // 186 // clear timer srb 187 // 188 Context->FDODeviceExtension->LastTimerActiveSrb = NULL; 189 } 190 else 191 { 192 DPRINT1("Retrying Count %lu %p\n", Context->RetryCount, Context->PDODeviceExtension->Self); 193 194 // 195 // re-schedule request 196 // 197 USBSTOR_HandleExecuteSCSI(Context->PDODeviceExtension->Self, Context->Irp, Context->RetryCount + 1); 198 199 // 200 // srb error handling finished 201 // 202 Context->FDODeviceExtension->SrbErrorHandlingActive = FALSE; 203 204 // 205 // srb error handling finished 206 // 207 Context->FDODeviceExtension->TimerWorkQueueEnabled = TRUE; 208 209 // 210 // clear timer srb 211 // 212 Context->FDODeviceExtension->LastTimerActiveSrb = NULL; 213 } 214 215 // 216 // cleanup irp context 217 // 218 FreeItem(Context->cbw); 219 FreeItem(Context); 220 221 222 DPRINT1("USBSTOR_HandleTransferError returning with Status %x\n", Status); 223 return Status; 224 } 225 226 VOID 227 NTAPI 228 USBSTOR_ResetHandlerWorkItemRoutine( 229 PVOID Context) 230 { 231 NTSTATUS Status; 232 PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; 233 234 // 235 // clear stall on BulkIn pipe 236 // 237 Status = USBSTOR_ResetPipeWithHandle(WorkItemData->Context->FDODeviceExtension->LowerDeviceObject, WorkItemData->Context->FDODeviceExtension->InterfaceInformation->Pipes[WorkItemData->Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle); 238 DPRINT1("USBSTOR_ResetPipeWithHandle Status %x\n", Status); 239 240 // 241 // now resend the csw as the stall got cleared 242 // 243 USBSTOR_SendCSW(WorkItemData->Context, WorkItemData->Irp); 244 } 245 246 VOID 247 NTAPI 248 ErrorHandlerWorkItemRoutine( 249 PVOID Context) 250 { 251 PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; 252 253 if (WorkItemData->Context->ErrorIndex == 2) 254 { 255 // 256 // reset device 257 // 258 USBSTOR_HandleTransferError(WorkItemData->DeviceObject, WorkItemData->Context); 259 } 260 else 261 { 262 // 263 // clear stall 264 // 265 USBSTOR_ResetHandlerWorkItemRoutine(WorkItemData); 266 } 267 268 // 269 // Free Work Item Data 270 // 271 ExFreePoolWithTag(WorkItemData, USB_STOR_TAG); 272 } 273 274 VOID 275 NTAPI 276 USBSTOR_TimerWorkerRoutine( 277 IN PVOID Context) 278 { 279 PFDO_DEVICE_EXTENSION FDODeviceExtension; 280 NTSTATUS Status; 281 PERRORHANDLER_WORKITEM_DATA WorkItemData = (PERRORHANDLER_WORKITEM_DATA)Context; 282 283 // 284 // get device extension 285 // 286 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)WorkItemData->DeviceObject->DeviceExtension; 287 ASSERT(FDODeviceExtension->Common.IsFDO); 288 289 // 290 // first perform a mass storage reset step 1 in 5.3.4 USB Mass Storage Bulk Only Specification 291 // 292 Status = USBSTOR_ResetDevice(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension); 293 if (NT_SUCCESS(Status)) 294 { 295 // 296 // step 2 reset bulk in pipe section 5.3.4 297 // 298 Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle); 299 if (NT_SUCCESS(Status)) 300 { 301 // 302 // finally reset bulk out pipe 303 // 304 Status = USBSTOR_ResetPipeWithHandle(FDODeviceExtension->LowerDeviceObject, FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle); 305 } 306 } 307 DPRINT1("Status %x\n", Status); 308 309 // 310 // clear timer srb 311 // 312 FDODeviceExtension->LastTimerActiveSrb = NULL; 313 314 // 315 // re-schedule request 316 // 317 //USBSTOR_HandleExecuteSCSI(WorkItemData->Context->PDODeviceExtension->Self, WorkItemData->Context->Irp, Context->RetryCount + 1); 318 319 320 321 // 322 // do not retry for the same packet again 323 // 324 FDODeviceExtension->TimerWorkQueueEnabled = FALSE; 325 326 // 327 // Free Work Item Data 328 // 329 ExFreePoolWithTag(WorkItemData, USB_STOR_TAG); 330 } 331 332 333 VOID 334 NTAPI 335 USBSTOR_TimerRoutine( 336 PDEVICE_OBJECT DeviceObject, 337 PVOID Context) 338 { 339 PFDO_DEVICE_EXTENSION FDODeviceExtension; 340 BOOLEAN ResetDevice = FALSE; 341 PERRORHANDLER_WORKITEM_DATA WorkItemData; 342 343 // 344 // get device extension 345 // 346 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)Context; 347 DPRINT1("[USBSTOR] TimerRoutine entered\n"); 348 DPRINT1("[USBSTOR] ActiveSrb %p ResetInProgress %x LastTimerActiveSrb %p\n", FDODeviceExtension->ActiveSrb, FDODeviceExtension->ResetInProgress, FDODeviceExtension->LastTimerActiveSrb); 349 350 // 351 // acquire spinlock 352 // 353 KeAcquireSpinLockAtDpcLevel(&FDODeviceExtension->IrpListLock); 354 355 // 356 // is there an active srb and no global reset is in progress 357 // 358 if (FDODeviceExtension->ActiveSrb && FDODeviceExtension->ResetInProgress == FALSE && FDODeviceExtension->TimerWorkQueueEnabled) 359 { 360 if (FDODeviceExtension->LastTimerActiveSrb != NULL && FDODeviceExtension->LastTimerActiveSrb == FDODeviceExtension->ActiveSrb) 361 { 362 // 363 // check if empty 364 // 365 DPRINT1("[USBSTOR] ActiveSrb %p hang detected\n", FDODeviceExtension->ActiveSrb); 366 ResetDevice = TRUE; 367 } 368 else 369 { 370 // 371 // update pointer 372 // 373 FDODeviceExtension->LastTimerActiveSrb = FDODeviceExtension->ActiveSrb; 374 } 375 } 376 else 377 { 378 // 379 // reset srb 380 // 381 FDODeviceExtension->LastTimerActiveSrb = NULL; 382 } 383 384 // 385 // release lock 386 // 387 KeReleaseSpinLockFromDpcLevel(&FDODeviceExtension->IrpListLock); 388 389 390 if (ResetDevice && FDODeviceExtension->TimerWorkQueueEnabled && FDODeviceExtension->SrbErrorHandlingActive == FALSE) 391 { 392 WorkItemData = ExAllocatePoolWithTag(NonPagedPool, 393 sizeof(ERRORHANDLER_WORKITEM_DATA), 394 USB_STOR_TAG); 395 if (WorkItemData) 396 { 397 // 398 // Initialize and queue the work item to handle the error 399 // 400 ExInitializeWorkItem(&WorkItemData->WorkQueueItem, 401 USBSTOR_TimerWorkerRoutine, 402 WorkItemData); 403 404 WorkItemData->DeviceObject = FDODeviceExtension->FunctionalDeviceObject; 405 406 DPRINT1("[USBSTOR] Queing Timer WorkItem\n"); 407 ExQueueWorkItem(&WorkItemData->WorkQueueItem, DelayedWorkQueue); 408 } 409 } 410 } 411