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
);
100 USBSTOR_AllocateIrpContext()
102 PIRP_CONTEXT Context
;
104 Context
= (PIRP_CONTEXT
)AllocateItem(NonPagedPool
, sizeof(IRP_CONTEXT
));
110 Context
->cbw
= (PCBW
)AllocateItem(NonPagedPool
, 512);
123 PIRP_CONTEXT Context
)
125 if (Context
->csw
->Signature
!= CSW_SIGNATURE
)
127 DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE
, Context
->csw
->Signature
);
131 if (Context
->csw
->Tag
!= (ULONG_PTR
)Context
->csw
)
133 DPRINT1("[USBSTOR] Expected Tag %Ix but got %x\n", (ULONG_PTR
)Context
->csw
, Context
->csw
->Tag
);
141 USBSTOR_QueueWorkItem(
142 PIRP_CONTEXT Context
,
145 PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData
;
147 ErrorHandlerWorkItemData
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(ERRORHANDLER_WORKITEM_DATA
), USB_STOR_TAG
);
148 if (!ErrorHandlerWorkItemData
)
150 return STATUS_INSUFFICIENT_RESOURCES
;
153 // error handling started
154 Context
->FDODeviceExtension
->SrbErrorHandlingActive
= TRUE
;
156 // srb error handling finished
157 Context
->FDODeviceExtension
->TimerWorkQueueEnabled
= FALSE
;
159 // Initialize and queue the work item to handle the error
160 ExInitializeWorkItem(&ErrorHandlerWorkItemData
->WorkQueueItem
,
161 ErrorHandlerWorkItemRoutine
,
162 ErrorHandlerWorkItemData
);
164 ErrorHandlerWorkItemData
->DeviceObject
= Context
->FDODeviceExtension
->FunctionalDeviceObject
;
165 ErrorHandlerWorkItemData
->Context
= Context
;
166 ErrorHandlerWorkItemData
->Irp
= Irp
;
167 ErrorHandlerWorkItemData
->DeviceObject
= Context
->FDODeviceExtension
->FunctionalDeviceObject
;
169 DPRINT1("Queuing WorkItemROutine\n");
170 ExQueueWorkItem(&ErrorHandlerWorkItemData
->WorkQueueItem
, DelayedWorkQueue
);
171 return STATUS_MORE_PROCESSING_REQUIRED
;
174 IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine
;
178 USBSTOR_CSWCompletionRoutine(
179 PDEVICE_OBJECT DeviceObject
,
183 PIRP_CONTEXT Context
;
184 PIO_STACK_LOCATION IoStack
;
185 PSCSI_REQUEST_BLOCK Request
;
186 PUFI_CAPACITY_RESPONSE Response
;
189 Context
= (PIRP_CONTEXT
)Ctx
;
191 DPRINT("USBSTOR_CSWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp
, Ctx
, Irp
->IoStatus
.Status
);
193 // first check for Irp errors
194 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
196 if (USBD_STATUS(Context
->Urb
.UrbHeader
.Status
) == USBD_STATUS(USBD_STATUS_STALL_PID
))
198 if (Context
->RetryCount
< 2)
200 ++Context
->RetryCount
;
202 // clear stall and resend cbw
203 Context
->ErrorIndex
= 1;
204 Status
= USBSTOR_QueueWorkItem(Context
, Irp
);
205 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
207 return STATUS_MORE_PROCESSING_REQUIRED
;
212 DPRINT1("USBSTOR_CSWCompletionRoutine: Urb.Hdr.Status - %x\n", Context
->Urb
.UrbHeader
.Status
);
215 // perform reset recovery
216 Context
->ErrorIndex
= 2;
217 Status
= USBSTOR_QueueWorkItem(Context
, NULL
);
218 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
219 return STATUS_MORE_PROCESSING_REQUIRED
;
222 // now check the CSW packet validity
223 if (!USBSTOR_IsCSWValid(Context
) || Context
->csw
->Status
== CSW_STATUS_PHASE_ERROR
)
225 // perform reset recovery
226 Context
->ErrorIndex
= 2;
227 Status
= USBSTOR_QueueWorkItem(Context
, NULL
);
228 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
229 return STATUS_MORE_PROCESSING_REQUIRED
;
232 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
233 Request
= IoStack
->Parameters
.Scsi
.Srb
;
236 // finally check for CSW errors
237 if (Context
->csw
->Status
== CSW_STATUS_COMMAND_PASSED
)
239 // read capacity needs special work
240 if (Request
->Cdb
[0] == SCSIOP_READ_CAPACITY
)
243 Response
= (PUFI_CAPACITY_RESPONSE
)Context
->TransferData
;
246 Context
->PDODeviceExtension
->BlockLength
= NTOHL(Response
->BlockLength
);
247 Context
->PDODeviceExtension
->LastLogicBlockAddress
= NTOHL(Response
->LastLogicalBlockAddress
);
250 Status
= USBSTOR_SrbStatusToNtStatus(Request
);
252 else if (Context
->csw
->Status
== CSW_STATUS_COMMAND_FAILED
)
254 // the command is correct but with failed status - issue request sense
255 DPRINT("USBSTOR_CSWCompletionRoutine: CSW_STATUS_COMMAND_FAILED\n");
257 ASSERT(Context
->FDODeviceExtension
->ActiveSrb
== Request
);
259 // setting a generic error status, additional information
260 // should be read by higher-level driver from SenseInfoBuffer
261 Request
->SrbStatus
= SRB_STATUS_ERROR
;
262 Request
->ScsiStatus
= 2;
263 Request
->DataTransferLength
= 0;
265 DPRINT("Flags: %x SBL: %x, buf: %p\n", Request
->SrbFlags
, Request
->SenseInfoBufferLength
, Request
->SenseInfoBuffer
);
267 if (!(Request
->SrbFlags
& SRB_FLAGS_DISABLE_AUTOSENSE
) &&
268 Request
->SenseInfoBufferLength
&&
269 Request
->SenseInfoBuffer
)
271 // TODO: issue request sense
274 Status
= STATUS_IO_DEVICE_ERROR
;
277 Irp
->IoStatus
.Status
= Status
;
278 Irp
->IoStatus
.Information
= Request
->DataTransferLength
;
280 FreeItem(Context
->cbw
);
282 // terminate current request
283 USBSTOR_QueueTerminateRequest(Context
->PDODeviceExtension
->LowerDeviceObject
, Irp
);
284 USBSTOR_QueueNextRequest(Context
->PDODeviceExtension
->LowerDeviceObject
);
291 USBSTOR_SendCSWRequest(
292 PIRP_CONTEXT Context
,
295 return USBSTOR_IssueBulkOrInterruptRequest(Context
->FDODeviceExtension
,
297 Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
,
298 USBD_TRANSFER_DIRECTION_IN
,
302 USBSTOR_CSWCompletionRoutine
,
306 IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine
;
310 USBSTOR_DataCompletionRoutine(
311 PDEVICE_OBJECT DeviceObject
,
315 PIRP_CONTEXT Context
;
317 PIO_STACK_LOCATION IoStack
;
318 PSCSI_REQUEST_BLOCK Request
;
320 DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp
, Ctx
, Irp
->IoStatus
.Status
);
322 Context
= (PIRP_CONTEXT
)Ctx
;
323 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
324 Request
= IoStack
->Parameters
.Scsi
.Srb
;
326 if (Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferMDL
!= Irp
->MdlAddress
)
328 IoFreeMdl(Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferMDL
);
331 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
333 if (Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferLength
< Request
->DataTransferLength
)
335 Request
->SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
339 Request
->SrbStatus
= SRB_STATUS_SUCCESS
;
342 Request
->DataTransferLength
= Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferLength
;
343 USBSTOR_SendCSWRequest(Context
, Irp
);
345 else if (USBD_STATUS(Context
->Urb
.UrbHeader
.Status
) == USBD_STATUS(USBD_STATUS_STALL_PID
))
347 ++Context
->RetryCount
;
349 Request
->SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
350 Request
->DataTransferLength
= Context
->Urb
.UrbBulkOrInterruptTransfer
.TransferBufferLength
;
352 // clear stall and resend cbw
353 Context
->ErrorIndex
= 1;
354 Status
= USBSTOR_QueueWorkItem(Context
, Irp
);
355 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
359 // perform reset recovery
360 Context
->ErrorIndex
= 2;
361 Status
= USBSTOR_QueueWorkItem(Context
, NULL
);
362 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
365 return STATUS_MORE_PROCESSING_REQUIRED
;
368 IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine
;
372 USBSTOR_CBWCompletionRoutine(
373 PDEVICE_OBJECT DeviceObject
,
377 PIRP_CONTEXT Context
;
378 PIO_STACK_LOCATION IoStack
;
379 PSCSI_REQUEST_BLOCK Request
;
380 USBD_PIPE_HANDLE PipeHandle
;
383 PVOID TransferBuffer
= NULL
;
386 DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp
, Ctx
, Irp
->IoStatus
.Status
);
388 Context
= (PIRP_CONTEXT
)Ctx
;
389 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
390 Request
= IoStack
->Parameters
.Scsi
.Srb
;
392 if (!NT_SUCCESS(Irp
->IoStatus
.Status
))
397 // a request without the buffer
398 if (!Irp
->MdlAddress
)
400 Request
->SrbStatus
= SRB_STATUS_SUCCESS
;
401 USBSTOR_SendCSWRequest(Context
, Irp
);
402 return STATUS_MORE_PROCESSING_REQUIRED
;
405 // a request with the data buffer
407 if ((Request
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
) == SRB_FLAGS_DATA_IN
)
409 PipeHandle
= Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkInPipeIndex
].PipeHandle
;
410 TransferFlags
= USBD_TRANSFER_DIRECTION_IN
| USBD_SHORT_TRANSFER_OK
;
412 else if ((Request
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
) == SRB_FLAGS_DATA_OUT
)
414 PipeHandle
= Context
->FDODeviceExtension
->InterfaceInformation
->Pipes
[Context
->FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
;
415 TransferFlags
= USBD_TRANSFER_DIRECTION_OUT
;
419 // we check the validity of a request in disk.c so we should never be here
420 DPRINT1("Warning: shouldn't be here\n");
424 if (MmGetMdlVirtualAddress(Irp
->MdlAddress
) == Request
->DataBuffer
)
426 Mdl
= Irp
->MdlAddress
;
430 Mdl
= IoAllocateMdl(Request
->DataBuffer
,
431 Request
->DataTransferLength
,
438 IoBuildPartialMdl(Irp
->MdlAddress
,
441 Request
->DataTransferLength
);
447 DPRINT1("USBSTOR_DataTransfer: Mdl - %p\n", Mdl
);
451 USBSTOR_IssueBulkOrInterruptRequest(Context
->FDODeviceExtension
,
455 Request
->DataTransferLength
,
458 USBSTOR_DataCompletionRoutine
,
461 return STATUS_MORE_PROCESSING_REQUIRED
;
464 Context
->ErrorIndex
= 2;
465 Status
= USBSTOR_QueueWorkItem(Context
, NULL
);
466 ASSERT(Status
== STATUS_MORE_PROCESSING_REQUIRED
);
467 return STATUS_MORE_PROCESSING_REQUIRED
;
474 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",
475 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,
476 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,
477 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,
483 USBSTOR_SendCBWRequest(
484 IN PFDO_DEVICE_EXTENSION FDODeviceExtension
,
486 IN PIRP_CONTEXT Context
)
488 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
489 PIO_STACK_LOCATION IoStack
;
490 PSCSI_REQUEST_BLOCK Request
;
494 Context
= USBSTOR_AllocateIrpContext();
497 return STATUS_INSUFFICIENT_RESOURCES
;
502 RtlZeroMemory(Context
->cbw
, sizeof(CBW
));
503 RtlZeroMemory(&Context
->Urb
, sizeof(URB
));
506 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
507 PDODeviceExtension
= IoStack
->DeviceObject
->DeviceExtension
;
508 Request
= IoStack
->Parameters
.Scsi
.Srb
;
510 Context
->cbw
->Signature
= CBW_SIGNATURE
;
511 Context
->cbw
->Tag
= PtrToUlong(Context
->cbw
);
512 Context
->cbw
->DataTransferLength
= Request
->DataTransferLength
;
513 Context
->cbw
->Flags
= ((UCHAR
)Request
->SrbFlags
& SRB_FLAGS_UNSPECIFIED_DIRECTION
) << 1;
514 Context
->cbw
->LUN
= PDODeviceExtension
->LUN
;
515 Context
->cbw
->CommandBlockLength
= Request
->CdbLength
;
517 RtlCopyMemory(Context
->cbw
->CommandBlock
, Request
->Cdb
, Request
->CdbLength
);
519 DPRINT("CBW %p\n", Context
->cbw
);
520 DumpCBW((PUCHAR
)Context
->cbw
);
522 // initialize rest of context
524 Context
->TransferData
= Request
->DataBuffer
;
525 Context
->TransferDataLength
= Request
->DataTransferLength
;
526 Context
->FDODeviceExtension
= FDODeviceExtension
;
527 Context
->PDODeviceExtension
= PDODeviceExtension
;
528 Context
->RetryCount
= 0;
530 return USBSTOR_IssueBulkOrInterruptRequest(
533 FDODeviceExtension
->InterfaceInformation
->Pipes
[FDODeviceExtension
->BulkOutPipeIndex
].PipeHandle
,
534 USBD_TRANSFER_DIRECTION_OUT
,
538 USBSTOR_CBWCompletionRoutine
,
543 USBSTOR_HandleExecuteSCSI(
544 IN PDEVICE_OBJECT DeviceObject
,
550 PIO_STACK_LOCATION IoStack
;
551 PSCSI_REQUEST_BLOCK Request
;
552 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
554 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
555 ASSERT(PDODeviceExtension
->Common
.IsFDO
== FALSE
);
557 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
558 Request
= IoStack
->Parameters
.Scsi
.Srb
;
559 pCDB
= (PCDB
)Request
->Cdb
;
561 DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x, Length %lu\n", pCDB
->CDB10
.OperationCode
, Request
->DataTransferLength
);
563 // check that we're sending to the right LUN
564 ASSERT(pCDB
->CDB10
.LogicalUnitNumber
== (PDODeviceExtension
->LUN
& MAX_LUN
));
565 Status
= USBSTOR_SendCBWRequest(PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
, Irp
, NULL
);