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)
9 * 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
20 USBSTOR_SrbStatusToNtStatus(
21 IN PSCSI_REQUEST_BLOCK Srb
)
25 SrbStatus
= SRB_STATUS(Srb
->SrbStatus
);
29 case SRB_STATUS_SUCCESS
:
30 return STATUS_SUCCESS
;
32 case SRB_STATUS_DATA_OVERRUN
:
33 return STATUS_BUFFER_OVERFLOW
;
35 case SRB_STATUS_BAD_FUNCTION
:
36 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH
:
37 return STATUS_INVALID_DEVICE_REQUEST
;
39 case SRB_STATUS_INVALID_LUN
:
40 case SRB_STATUS_INVALID_TARGET_ID
:
41 case SRB_STATUS_NO_HBA
:
42 case SRB_STATUS_NO_DEVICE
:
43 return STATUS_DEVICE_DOES_NOT_EXIST
;
45 case SRB_STATUS_TIMEOUT
:
46 return STATUS_IO_TIMEOUT
;
48 case SRB_STATUS_BUS_RESET
:
49 case SRB_STATUS_COMMAND_TIMEOUT
:
50 case SRB_STATUS_SELECTION_TIMEOUT
:
51 return STATUS_DEVICE_NOT_CONNECTED
;
54 return STATUS_IO_DEVICE_ERROR
;
60 USBSTOR_IssueBulkOrInterruptRequest(
61 IN PFDO_DEVICE_EXTENSION FDODeviceExtension
,
63 IN USBD_PIPE_HANDLE PipeHandle
,
64 IN ULONG TransferFlags
,
65 IN ULONG TransferBufferLength
,
66 IN PVOID TransferBuffer
,
67 IN PMDL TransferBufferMDL
,
68 IN PIO_COMPLETION_ROUTINE CompletionRoutine
,
69 IN PIRP_CONTEXT Context
)
71 PIO_STACK_LOCATION NextStack
;
73 RtlZeroMemory(&Context
->Urb
, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
));
75 Context
->Urb
.UrbHeader
.Length
= sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
);
76 Context
->Urb
.UrbHeader
.Function
= URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
;
78 Context
->Urb
.UrbBulkOrInterruptTransfer
.PipeHandle
= PipeHandle
;
79 Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferFlags
= TransferFlags
;
80 Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferLength
= TransferBufferLength
;
81 Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBuffer
= TransferBuffer
;
82 Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferMDL
= TransferBufferMDL
;
84 NextStack
= IoGetNextIrpStackLocation(Irp
);
85 NextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
86 NextStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
87 NextStack
->Parameters
.Others
.Argument1
= &Context
->Urb
;
89 IoSetCompletionRoutine(Irp
,
96 return IoCallDriver(FDODeviceExtension
->LowerDeviceObject
, Irp
);
102 PIRP_CONTEXT Context
)
104 if (Context
->csw
.Signature
!= CSW_SIGNATURE
)
106 DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE
, Context
->csw
.Signature
);
110 if (Context
->csw
.Tag
!= PtrToUlong(&Context
->csw
))
112 DPRINT1("[USBSTOR] Expected Tag %Ix but got %x\n", PtrToUlong(&Context
->csw
), Context
->csw
.Tag
);
120 USBSTOR_QueueWorkItem(
121 PIRP_CONTEXT Context
,
124 PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData
;
126 ErrorHandlerWorkItemData
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(ERRORHANDLER_WORKITEM_DATA
), USB_STOR_TAG
);
127 if (!ErrorHandlerWorkItemData
)
129 return STATUS_INSUFFICIENT_RESOURCES
;
132 // error handling started
133 Context
->FDODeviceExtension
->SrbErrorHandlingActive
= TRUE
;
135 // srb error handling finished
136 Context
->FDODeviceExtension
->TimerWorkQueueEnabled
= FALSE
;
138 // Initialize and queue the work item to handle the error
139 ExInitializeWorkItem(&ErrorHandlerWorkItemData
->WorkQueueItem
,
140 ErrorHandlerWorkItemRoutine
,
141 ErrorHandlerWorkItemData
);
143 ErrorHandlerWorkItemData
->DeviceObject
= Context
->FDODeviceExtension
->FunctionalDeviceObject
;
144 ErrorHandlerWorkItemData
->Context
= Context
;
145 ErrorHandlerWorkItemData
->Irp
= Irp
;
146 ErrorHandlerWorkItemData
->DeviceObject
= Context
->FDODeviceExtension
->FunctionalDeviceObject
;
148 DPRINT1("Queuing WorkItemROutine\n");
149 ExQueueWorkItem(&ErrorHandlerWorkItemData
->WorkQueueItem
, DelayedWorkQueue
);
150 return STATUS_MORE_PROCESSING_REQUIRED
;
153 IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine
;
157 USBSTOR_CSWCompletionRoutine(
158 PDEVICE_OBJECT DeviceObject
,
162 PIRP_CONTEXT Context
;
163 PIO_STACK_LOCATION IoStack
;
164 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
165 PSCSI_REQUEST_BLOCK Request
;
166 PUFI_CAPACITY_RESPONSE Response
;
169 Context
= (PIRP_CONTEXT
)Ctx
;
171 DPRINT("USBSTOR_CSWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp
, Ctx
, Irp
->IoStatus
.Status
);
173 // first check for Irp errors
174 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
176 if (USBD_STATUS(Context
->Urb
.UrbHeader
.Status
) == USBD_STATUS(USBD_STATUS_STALL_PID
))
178 if (Context
->RetryCount
< 2)
180 ++Context
->RetryCount
;
182 // clear stall and resend cbw
183 Context
->ErrorIndex
= 1;
184 Status
= USBSTOR_QueueWorkItem(Context
, Irp
);
185 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
187 return STATUS_MORE_PROCESSING_REQUIRED
;
192 DPRINT1("USBSTOR_CSWCompletionRoutine: Urb.Hdr.Status - %x\n", Context
->Urb
.UrbHeader
.Status
);
195 // perform reset recovery
196 Context
->ErrorIndex
= 2;
197 Status
= USBSTOR_QueueWorkItem(Context
, NULL
);
198 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
199 return STATUS_MORE_PROCESSING_REQUIRED
;
202 // now check the CSW packet validity
203 if (!USBSTOR_IsCSWValid(Context
) || Context
->csw
.Status
== CSW_STATUS_PHASE_ERROR
)
205 // perform reset recovery
206 Context
->ErrorIndex
= 2;
207 Status
= USBSTOR_QueueWorkItem(Context
, NULL
);
208 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
209 return STATUS_MORE_PROCESSING_REQUIRED
;
212 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
213 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)IoStack
->DeviceObject
->DeviceExtension
;
214 Request
= IoStack
->Parameters
.Scsi
.Srb
;
217 // finally check for CSW errors
218 if (Context
->csw
.Status
== CSW_STATUS_COMMAND_PASSED
)
220 // read capacity needs special work
221 if (Request
->Cdb
[0] == SCSIOP_READ_CAPACITY
)
224 Response
= (PUFI_CAPACITY_RESPONSE
)Request
->DataBuffer
;
227 PDODeviceExtension
->BlockLength
= NTOHL(Response
->BlockLength
);
228 PDODeviceExtension
->LastLogicBlockAddress
= NTOHL(Response
->LastLogicalBlockAddress
);
231 Status
= USBSTOR_SrbStatusToNtStatus(Request
);
233 else if (Context
->csw
.Status
== CSW_STATUS_COMMAND_FAILED
)
235 // the command is correct but with failed status - issue request sense
236 DPRINT("USBSTOR_CSWCompletionRoutine: CSW_STATUS_COMMAND_FAILED\n");
238 ASSERT(Context
->FDODeviceExtension
->ActiveSrb
== Request
);
240 // setting a generic error status, additional information
241 // should be read by higher-level driver from SenseInfoBuffer
242 Request
->SrbStatus
= SRB_STATUS_ERROR
;
243 Request
->ScsiStatus
= 2;
244 Request
->DataTransferLength
= 0;
246 DPRINT("Flags: %x SBL: %x, buf: %p\n", Request
->SrbFlags
, Request
->SenseInfoBufferLength
, Request
->SenseInfoBuffer
);
248 if (!(Request
->SrbFlags
& SRB_FLAGS_DISABLE_AUTOSENSE
) &&
249 Request
->SenseInfoBufferLength
&&
250 Request
->SenseInfoBuffer
)
252 // TODO: issue request sense
255 Status
= STATUS_IO_DEVICE_ERROR
;
258 Irp
->IoStatus
.Status
= Status
;
259 Irp
->IoStatus
.Information
= Request
->DataTransferLength
;
261 // terminate current request
262 USBSTOR_QueueTerminateRequest(PDODeviceExtension
->LowerDeviceObject
, Irp
);
263 USBSTOR_QueueNextRequest(PDODeviceExtension
->LowerDeviceObject
);
265 ExFreePoolWithTag(Context
, USB_STOR_TAG
);
270 USBSTOR_SendCSWRequest(
271 PIRP_CONTEXT Context
,
274 return USBSTOR_IssueBulkOrInterruptRequest(Context
->FDODeviceExtension
,
276 Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
,
277 USBD_TRANSFER_DIRECTION_IN
,
281 USBSTOR_CSWCompletionRoutine
,
285 IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine
;
289 USBSTOR_DataCompletionRoutine(
290 PDEVICE_OBJECT DeviceObject
,
294 PIRP_CONTEXT Context
;
296 PIO_STACK_LOCATION IoStack
;
297 PSCSI_REQUEST_BLOCK Request
;
299 DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp
, Ctx
, Irp
->IoStatus
.Status
);
301 Context
= (PIRP_CONTEXT
)Ctx
;
302 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
303 Request
= IoStack
->Parameters
.Scsi
.Srb
;
305 if (Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferMDL
!= Irp
->MdlAddress
)
307 IoFreeMdl(Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferMDL
);
310 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
312 if (Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferLength
< Request
->DataTransferLength
)
314 Request
->SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
318 Request
->SrbStatus
= SRB_STATUS_SUCCESS
;
321 Request
->DataTransferLength
= Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferLength
;
322 USBSTOR_SendCSWRequest(Context
, Irp
);
324 else if (USBD_STATUS(Context
->Urb
.UrbHeader
.Status
) == USBD_STATUS(USBD_STATUS_STALL_PID
))
326 ++Context
->RetryCount
;
328 Request
->SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
329 Request
->DataTransferLength
= Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferLength
;
331 // clear stall and resend cbw
332 Context
->ErrorIndex
= 1;
333 Status
= USBSTOR_QueueWorkItem(Context
, Irp
);
334 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
338 // perform reset recovery
339 Context
->ErrorIndex
= 2;
340 Status
= USBSTOR_QueueWorkItem(Context
, NULL
);
341 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
344 return STATUS_MORE_PROCESSING_REQUIRED
;
347 IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine
;
351 USBSTOR_CBWCompletionRoutine(
352 PDEVICE_OBJECT DeviceObject
,
356 PIRP_CONTEXT Context
;
357 PIO_STACK_LOCATION IoStack
;
358 PSCSI_REQUEST_BLOCK Request
;
359 USBD_PIPE_HANDLE PipeHandle
;
362 PVOID TransferBuffer
= NULL
;
365 DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp
, Ctx
, Irp
->IoStatus
.Status
);
367 Context
= (PIRP_CONTEXT
)Ctx
;
368 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
369 Request
= IoStack
->Parameters
.Scsi
.Srb
;
371 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
376 // a request without the buffer
377 if (!Irp
->MdlAddress
)
379 Request
->SrbStatus
= SRB_STATUS_SUCCESS
;
380 USBSTOR_SendCSWRequest(Context
, Irp
);
381 return STATUS_MORE_PROCESSING_REQUIRED
;
384 // a request with the data buffer
386 if ((Request
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
) == SRB_FLAGS_DATA_IN
)
388 PipeHandle
= Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
;
389 TransferFlags
= USBD_TRANSFER_DIRECTION_IN
| USBD_SHORT_TRANSFER_OK
;
391 else if ((Request
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
) == SRB_FLAGS_DATA_OUT
)
393 PipeHandle
= Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
;
394 TransferFlags
= USBD_TRANSFER_DIRECTION_OUT
;
398 // we check the validity of a request in disk.c so we should never be here
399 DPRINT1("Warning: shouldn't be here\n");
403 if (MmGetMdlVirtualAddress(Irp
->MdlAddress
) == Request
->DataBuffer
)
405 Mdl
= Irp
->MdlAddress
;
409 Mdl
= IoAllocateMdl(Request
->DataBuffer
,
410 Request
->DataTransferLength
,
417 IoBuildPartialMdl(Irp
->MdlAddress
,
420 Request
->DataTransferLength
);
426 DPRINT1("USBSTOR_DataTransfer: Mdl - %p\n", Mdl
);
430 USBSTOR_IssueBulkOrInterruptRequest(Context
->FDODeviceExtension
,
434 Request
->DataTransferLength
,
437 USBSTOR_DataCompletionRoutine
,
440 return STATUS_MORE_PROCESSING_REQUIRED
;
443 Context
->ErrorIndex
= 2;
444 Status
= USBSTOR_QueueWorkItem(Context
, NULL
);
445 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
446 return STATUS_MORE_PROCESSING_REQUIRED
;
453 DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
454 Block
[0] & 0xFF, Block
[1] & 0xFF, Block
[2] & 0xFF, Block
[3] & 0xFF, Block
[4] & 0xFF, Block
[5] & 0xFF, Block
[6] & 0xFF, Block
[7] & 0xFF, Block
[8] & 0xFF, Block
[9] & 0xFF,
455 Block
[10] & 0xFF, Block
[11] & 0xFF, Block
[12] & 0xFF, Block
[13] & 0xFF, Block
[14] & 0xFF, Block
[15] & 0xFF, Block
[16] & 0xFF, Block
[17] & 0xFF, Block
[18] & 0xFF, Block
[19] & 0xFF,
456 Block
[20] & 0xFF, Block
[21] & 0xFF, Block
[22] & 0xFF, Block
[23] & 0xFF, Block
[24] & 0xFF, Block
[25] & 0xFF, Block
[26] & 0xFF, Block
[27] & 0xFF, Block
[28] & 0xFF, Block
[29] & 0xFF,
462 USBSTOR_SendCBWRequest(
463 IN PFDO_DEVICE_EXTENSION FDODeviceExtension
,
465 IN PIRP_CONTEXT Context
)
467 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
468 PIO_STACK_LOCATION IoStack
;
469 PSCSI_REQUEST_BLOCK Request
;
471 RtlZeroMemory(&Context
->cbw
, sizeof(CBW
));
472 RtlZeroMemory(&Context
->Urb
, sizeof(URB
));
474 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
475 PDODeviceExtension
= IoStack
->DeviceObject
->DeviceExtension
;
476 Request
= IoStack
->Parameters
.Scsi
.Srb
;
478 Context
->cbw
.Signature
= CBW_SIGNATURE
;
479 Context
->cbw
.Tag
= PtrToUlong(&Context
->cbw
);
480 Context
->cbw
.DataTransferLength
= Request
->DataTransferLength
;
481 Context
->cbw
.Flags
= ((UCHAR
)Request
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
) << 1;
482 Context
->cbw
.LUN
= PDODeviceExtension
->LUN
;
483 Context
->cbw
.CommandBlockLength
= Request
->CdbLength
;
485 RtlCopyMemory(&Context
->cbw
.CommandBlock
, Request
->Cdb
, Request
->CdbLength
);
487 DPRINT("CBW for IRP %p\n", Irp
);
488 DumpCBW((PUCHAR
)&Context
->cbw
);
490 // initialize rest of context
492 Context
->FDODeviceExtension
= FDODeviceExtension
;
493 Context
->RetryCount
= 0;
495 return USBSTOR_IssueBulkOrInterruptRequest(
498 FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
,
499 USBD_TRANSFER_DIRECTION_OUT
,
503 USBSTOR_CBWCompletionRoutine
,
508 USBSTOR_HandleExecuteSCSI(
509 IN PDEVICE_OBJECT DeviceObject
,
515 PIO_STACK_LOCATION IoStack
;
516 PSCSI_REQUEST_BLOCK Request
;
517 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
518 PIRP_CONTEXT Context
;
520 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
521 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
523 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
524 Request
= IoStack
->Parameters
.Scsi
.Srb
;
525 pCDB
= (PCDB
)Request
->Cdb
;
527 DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x, Length %lu\n", pCDB
->CDB10
.OperationCode
, Request
->DataTransferLength
);
529 // check that we're sending to the right LUN
530 ASSERT(pCDB
->CDB10
.LogicalUnitNumber
== (PDODeviceExtension
->LUN
& MAX_LUN
));
531 Context
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(IRP_CONTEXT
), USB_STOR_TAG
);
535 Status
= STATUS_INSUFFICIENT_RESOURCES
;
539 Status
= USBSTOR_SendCBWRequest(PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
, Irp
, Context
);