mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 04:13:34 +00:00
* [USBCCGP] CORE-18689 - Don't do a double IRP completion * [USBPORT] CORE-17052 Handle port status better and CreateDevice MaxPacketSize * [USBSTOR] CORE-19773 Clamp LUN - Don't just assert on a POSSIBLE case * [USB] Disable LIST_ENTRY_CHECKS privately for USB * [CODEREVIEW] Co-authored-by: Hermès BÉLUSCA - MAÏTO <[email protected]> * [CODEREVIEW] Co-authored-by: Hermès BÉLUSCA - MAÏTO <[email protected]> --------- Co-authored-by: Hermès BÉLUSCA - MAÏTO <[email protected]>
575 lines
19 KiB
C
575 lines
19 KiB
C
/*
|
||
* PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
|
||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||
* PURPOSE: USB block storage device driver.
|
||
* COPYRIGHT: 2005-2006 James Tabor
|
||
* 2011-2012 Michael Martin ([email protected])
|
||
* 2011-2013 Johannes Anderwald ([email protected])
|
||
* 2017 Vadim Galyant
|
||
* 2019 Victor Perevertkin ([email protected])
|
||
*/
|
||
|
||
#include "usbstor.h"
|
||
|
||
#define NDEBUG
|
||
#include <debug.h>
|
||
|
||
|
||
static
|
||
NTSTATUS
|
||
USBSTOR_SrbStatusToNtStatus(
|
||
IN PSCSI_REQUEST_BLOCK Srb)
|
||
{
|
||
UCHAR SrbStatus;
|
||
|
||
SrbStatus = SRB_STATUS(Srb->SrbStatus);
|
||
|
||
switch (SrbStatus)
|
||
{
|
||
case SRB_STATUS_SUCCESS:
|
||
return STATUS_SUCCESS;
|
||
|
||
case SRB_STATUS_DATA_OVERRUN:
|
||
return STATUS_BUFFER_OVERFLOW;
|
||
|
||
case SRB_STATUS_BAD_FUNCTION:
|
||
case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
|
||
case SRB_STATUS_INVALID_LUN:
|
||
case SRB_STATUS_INVALID_TARGET_ID:
|
||
case SRB_STATUS_NO_HBA:
|
||
case SRB_STATUS_NO_DEVICE:
|
||
return STATUS_DEVICE_DOES_NOT_EXIST;
|
||
|
||
case SRB_STATUS_TIMEOUT:
|
||
return STATUS_IO_TIMEOUT;
|
||
|
||
case SRB_STATUS_BUS_RESET:
|
||
case SRB_STATUS_COMMAND_TIMEOUT:
|
||
case SRB_STATUS_SELECTION_TIMEOUT:
|
||
return STATUS_DEVICE_NOT_CONNECTED;
|
||
|
||
default:
|
||
return STATUS_IO_DEVICE_ERROR;
|
||
}
|
||
}
|
||
|
||
static
|
||
NTSTATUS
|
||
USBSTOR_IssueBulkOrInterruptRequest(
|
||
IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
|
||
IN PIRP Irp,
|
||
IN USBD_PIPE_HANDLE PipeHandle,
|
||
IN ULONG TransferFlags,
|
||
IN ULONG TransferBufferLength,
|
||
IN PVOID TransferBuffer,
|
||
IN PMDL TransferBufferMDL,
|
||
IN PIO_COMPLETION_ROUTINE CompletionRoutine)
|
||
{
|
||
PIO_STACK_LOCATION NextStack;
|
||
PIRP_CONTEXT Context = &FDODeviceExtension->CurrentIrpContext;
|
||
|
||
RtlZeroMemory(&Context->Urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
|
||
|
||
Context->Urb.UrbHeader.Length = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
|
||
Context->Urb.UrbHeader.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
|
||
|
||
Context->Urb.UrbBulkOrInterruptTransfer.PipeHandle = PipeHandle;
|
||
Context->Urb.UrbBulkOrInterruptTransfer.TransferFlags = TransferFlags;
|
||
Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferLength = TransferBufferLength;
|
||
Context->Urb.UrbBulkOrInterruptTransfer.TransferBuffer = TransferBuffer;
|
||
Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferMDL = TransferBufferMDL;
|
||
|
||
NextStack = IoGetNextIrpStackLocation(Irp);
|
||
NextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
NextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
|
||
NextStack->Parameters.Others.Argument1 = &Context->Urb;
|
||
|
||
IoSetCompletionRoutine(Irp,
|
||
CompletionRoutine,
|
||
FDODeviceExtension,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE);
|
||
|
||
return IoCallDriver(FDODeviceExtension->LowerDeviceObject, Irp);
|
||
}
|
||
|
||
static
|
||
BOOLEAN
|
||
USBSTOR_IsCSWValid(
|
||
PIRP_CONTEXT Context)
|
||
{
|
||
if (Context->csw.Signature != CSW_SIGNATURE)
|
||
{
|
||
DPRINT1("[USBSTOR] Expected Signature %x but got %x\n", CSW_SIGNATURE, Context->csw.Signature);
|
||
return FALSE;
|
||
}
|
||
|
||
if (Context->csw.Tag != PtrToUlong(Context->Irp))
|
||
{
|
||
DPRINT1("[USBSTOR] Expected Tag %Ix but got %x\n", PtrToUlong(Context->Irp), Context->csw.Tag);
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static
|
||
NTSTATUS
|
||
USBSTOR_IssueRequestSense(
|
||
IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
|
||
IN PIRP Irp);
|
||
|
||
IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine;
|
||
|
||
NTSTATUS
|
||
NTAPI
|
||
USBSTOR_CSWCompletionRoutine(
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PIRP Irp,
|
||
PVOID Ctx)
|
||
{
|
||
PIRP_CONTEXT Context;
|
||
PIO_STACK_LOCATION IoStack;
|
||
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
PFDO_DEVICE_EXTENSION FDODeviceExtension;
|
||
PSCSI_REQUEST_BLOCK Request;
|
||
|
||
DPRINT("USBSTOR_CSWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
|
||
|
||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
|
||
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)Ctx;
|
||
Context = &FDODeviceExtension->CurrentIrpContext;
|
||
Request = IoStack->Parameters.Scsi.Srb;
|
||
ASSERT(Request);
|
||
|
||
// first check for Irp errors
|
||
if (!NT_SUCCESS(Irp->IoStatus.Status))
|
||
{
|
||
if (USBD_STATUS(Context->Urb.UrbHeader.Status) == USBD_STATUS(USBD_STATUS_STALL_PID))
|
||
{
|
||
if (Context->StallRetryCount < 2)
|
||
{
|
||
++Context->StallRetryCount;
|
||
|
||
// clear stall and resend cbw
|
||
USBSTOR_QueueResetPipe(FDODeviceExtension);
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DPRINT1("USBSTOR_CSWCompletionRoutine: Urb.Hdr.Status - %x\n", Context->Urb.UrbHeader.Status);
|
||
}
|
||
|
||
goto ResetRecovery;
|
||
}
|
||
|
||
// now check the CSW packet validity
|
||
if (!USBSTOR_IsCSWValid(Context) || Context->csw.Status == CSW_STATUS_PHASE_ERROR)
|
||
{
|
||
goto ResetRecovery;
|
||
}
|
||
|
||
// finally check for CSW errors
|
||
if (Context->csw.Status == CSW_STATUS_COMMAND_PASSED)
|
||
{
|
||
// should happen only when a sense request was sent
|
||
if (Request != FDODeviceExtension->ActiveSrb)
|
||
{
|
||
ASSERT(IoStack->Parameters.Scsi.Srb == &Context->SenseSrb);
|
||
FDODeviceExtension->ActiveSrb->SenseInfoBufferLength = Request->DataTransferLength;
|
||
Request = FDODeviceExtension->ActiveSrb;
|
||
IoStack->Parameters.Scsi.Srb = Request;
|
||
Request->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
|
||
}
|
||
|
||
Irp->IoStatus.Status = USBSTOR_SrbStatusToNtStatus(Request);
|
||
}
|
||
else if (Context->csw.Status == CSW_STATUS_COMMAND_FAILED)
|
||
{
|
||
// the command is correct but with failed status - issue request sense
|
||
DPRINT("USBSTOR_CSWCompletionRoutine: CSW_STATUS_COMMAND_FAILED\n");
|
||
|
||
ASSERT(FDODeviceExtension->ActiveSrb == Request);
|
||
|
||
// setting a generic error status, additional information
|
||
// should be read by higher-level driver from SenseInfoBuffer
|
||
Request->SrbStatus = SRB_STATUS_ERROR;
|
||
Request->ScsiStatus = 2;
|
||
Request->DataTransferLength = 0;
|
||
|
||
DPRINT("Flags: %x SBL: %x, buf: %p\n", Request->SrbFlags, Request->SenseInfoBufferLength, Request->SenseInfoBuffer);
|
||
|
||
if (!(Request->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE) &&
|
||
Request->SenseInfoBufferLength &&
|
||
Request->SenseInfoBuffer)
|
||
{
|
||
USBSTOR_IssueRequestSense(FDODeviceExtension, Irp);
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
|
||
Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
|
||
}
|
||
|
||
Irp->IoStatus.Information = Request->DataTransferLength;
|
||
|
||
// terminate current request
|
||
USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
|
||
USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
|
||
|
||
return STATUS_CONTINUE_COMPLETION;
|
||
|
||
ResetRecovery:
|
||
|
||
Request = FDODeviceExtension->ActiveSrb;
|
||
IoStack->Parameters.Scsi.Srb = Request;
|
||
Irp->IoStatus.Information = 0;
|
||
Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
|
||
Request->SrbStatus = SRB_STATUS_BUS_RESET;
|
||
|
||
USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
|
||
USBSTOR_QueueResetDevice(FDODeviceExtension);
|
||
|
||
return STATUS_CONTINUE_COMPLETION;
|
||
}
|
||
|
||
NTSTATUS
|
||
USBSTOR_SendCSWRequest(
|
||
PFDO_DEVICE_EXTENSION FDODeviceExtension,
|
||
PIRP Irp)
|
||
{
|
||
return USBSTOR_IssueBulkOrInterruptRequest(FDODeviceExtension,
|
||
Irp,
|
||
FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle,
|
||
USBD_TRANSFER_DIRECTION_IN,
|
||
sizeof(CSW),
|
||
&FDODeviceExtension->CurrentIrpContext.csw,
|
||
NULL,
|
||
USBSTOR_CSWCompletionRoutine);
|
||
}
|
||
|
||
IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine;
|
||
|
||
NTSTATUS
|
||
NTAPI
|
||
USBSTOR_DataCompletionRoutine(
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PIRP Irp,
|
||
PVOID Ctx)
|
||
{
|
||
PIRP_CONTEXT Context;
|
||
PIO_STACK_LOCATION IoStack;
|
||
PSCSI_REQUEST_BLOCK Request;
|
||
PFDO_DEVICE_EXTENSION FDODeviceExtension;
|
||
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
||
DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
|
||
|
||
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)Ctx;
|
||
Context = &FDODeviceExtension->CurrentIrpContext;
|
||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
Request = IoStack->Parameters.Scsi.Srb;
|
||
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
|
||
|
||
// for Sense Request a partial MDL was already freed (if existed)
|
||
if (Request == FDODeviceExtension->ActiveSrb &&
|
||
Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferMDL != Irp->MdlAddress)
|
||
{
|
||
IoFreeMdl(Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferMDL);
|
||
}
|
||
|
||
if (NT_SUCCESS(Irp->IoStatus.Status))
|
||
{
|
||
if (Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferLength < Request->DataTransferLength)
|
||
{
|
||
Request->SrbStatus = SRB_STATUS_DATA_OVERRUN;
|
||
}
|
||
else
|
||
{
|
||
Request->SrbStatus = SRB_STATUS_SUCCESS;
|
||
}
|
||
|
||
Request->DataTransferLength = Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferLength;
|
||
USBSTOR_SendCSWRequest(FDODeviceExtension, Irp);
|
||
}
|
||
else if (USBD_STATUS(Context->Urb.UrbHeader.Status) == USBD_STATUS(USBD_STATUS_STALL_PID))
|
||
{
|
||
++Context->StallRetryCount;
|
||
|
||
Request->SrbStatus = SRB_STATUS_DATA_OVERRUN;
|
||
Request->DataTransferLength = Context->Urb.UrbBulkOrInterruptTransfer.TransferBufferLength;
|
||
|
||
// clear stall and resend cbw
|
||
USBSTOR_QueueResetPipe(FDODeviceExtension);
|
||
}
|
||
else
|
||
{
|
||
Irp->IoStatus.Information = 0;
|
||
Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
|
||
Request->SrbStatus = SRB_STATUS_BUS_RESET;
|
||
|
||
USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
|
||
USBSTOR_QueueResetDevice(FDODeviceExtension);
|
||
|
||
return STATUS_CONTINUE_COMPLETION;
|
||
}
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
|
||
IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine;
|
||
|
||
NTSTATUS
|
||
NTAPI
|
||
USBSTOR_CBWCompletionRoutine(
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PIRP Irp,
|
||
PVOID Ctx)
|
||
{
|
||
PIO_STACK_LOCATION IoStack;
|
||
PSCSI_REQUEST_BLOCK Request;
|
||
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
PFDO_DEVICE_EXTENSION FDODeviceExtension;
|
||
USBD_PIPE_HANDLE PipeHandle;
|
||
ULONG TransferFlags;
|
||
PMDL Mdl = NULL;
|
||
PVOID TransferBuffer = NULL;
|
||
|
||
DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
|
||
|
||
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)Ctx;
|
||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
Request = IoStack->Parameters.Scsi.Srb;
|
||
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
|
||
|
||
if (!NT_SUCCESS(Irp->IoStatus.Status))
|
||
{
|
||
goto ResetRecovery;
|
||
}
|
||
|
||
// a request without the buffer AND not a sense request
|
||
// for a sense request we provide just a TransferBuffer, an Mdl will be allocated by usbport (see below)
|
||
if (!Irp->MdlAddress && Request == FDODeviceExtension->ActiveSrb)
|
||
{
|
||
Request->SrbStatus = SRB_STATUS_SUCCESS;
|
||
USBSTOR_SendCSWRequest(FDODeviceExtension, Irp);
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
|
||
// a request with the data buffer
|
||
|
||
if ((Request->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) == SRB_FLAGS_DATA_IN)
|
||
{
|
||
PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle;
|
||
TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
|
||
}
|
||
else if ((Request->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) == SRB_FLAGS_DATA_OUT)
|
||
{
|
||
PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
|
||
TransferFlags = USBD_TRANSFER_DIRECTION_OUT;
|
||
}
|
||
else
|
||
{
|
||
// we check the validity of a request in disk.c so we should never be here
|
||
DPRINT1("Warning: shouldn't be here\n");
|
||
goto ResetRecovery;
|
||
}
|
||
|
||
// if it is not a Sense Request
|
||
if (Request == FDODeviceExtension->ActiveSrb)
|
||
{
|
||
if (MmGetMdlVirtualAddress(Irp->MdlAddress) == Request->DataBuffer)
|
||
{
|
||
Mdl = Irp->MdlAddress;
|
||
}
|
||
else
|
||
{
|
||
Mdl = IoAllocateMdl(Request->DataBuffer,
|
||
Request->DataTransferLength,
|
||
FALSE,
|
||
FALSE,
|
||
NULL);
|
||
|
||
if (Mdl)
|
||
{
|
||
IoBuildPartialMdl(Irp->MdlAddress,
|
||
Mdl,
|
||
Request->DataBuffer,
|
||
Request->DataTransferLength);
|
||
}
|
||
}
|
||
|
||
if (!Mdl)
|
||
{
|
||
DPRINT1("USBSTOR_CBWCompletionRoutine: Mdl - %p\n", Mdl);
|
||
goto ResetRecovery;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ASSERT(Request->DataBuffer);
|
||
TransferBuffer = Request->DataBuffer;
|
||
}
|
||
|
||
USBSTOR_IssueBulkOrInterruptRequest(FDODeviceExtension,
|
||
Irp,
|
||
PipeHandle,
|
||
TransferFlags,
|
||
Request->DataTransferLength,
|
||
TransferBuffer,
|
||
Mdl,
|
||
USBSTOR_DataCompletionRoutine);
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
||
ResetRecovery:
|
||
Request = FDODeviceExtension->ActiveSrb;
|
||
IoStack->Parameters.Scsi.Srb = Request;
|
||
Irp->IoStatus.Information = 0;
|
||
Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
|
||
Request->SrbStatus = SRB_STATUS_BUS_RESET;
|
||
|
||
USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
|
||
USBSTOR_QueueResetDevice(FDODeviceExtension);
|
||
|
||
return STATUS_CONTINUE_COMPLETION;
|
||
}
|
||
|
||
VOID
|
||
DumpCBW(
|
||
PUCHAR Block)
|
||
{
|
||
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",
|
||
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,
|
||
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,
|
||
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,
|
||
Block[30] & 0xFF);
|
||
}
|
||
|
||
static
|
||
NTSTATUS
|
||
USBSTOR_SendCBWRequest(
|
||
IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
|
||
IN PIRP Irp)
|
||
{
|
||
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
PIO_STACK_LOCATION IoStack;
|
||
PSCSI_REQUEST_BLOCK Request;
|
||
PIRP_CONTEXT Context = &FDODeviceExtension->CurrentIrpContext;
|
||
|
||
RtlZeroMemory(&Context->cbw, sizeof(CBW));
|
||
RtlZeroMemory(&Context->Urb, sizeof(URB));
|
||
|
||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
PDODeviceExtension = IoStack->DeviceObject->DeviceExtension;
|
||
Request = IoStack->Parameters.Scsi.Srb;
|
||
|
||
// Make a CBW structure from SCSI request block
|
||
Context->cbw.Signature = CBW_SIGNATURE;
|
||
Context->cbw.Tag = PtrToUlong(Irp);
|
||
Context->cbw.DataTransferLength = Request->DataTransferLength;
|
||
Context->cbw.Flags = ((UCHAR)Request->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) << 1;
|
||
|
||
// Per Bulk Only Transfer, LUN is 4 bits; clamp just in case
|
||
Context->cbw.LUN = (UCHAR)(PDODeviceExtension->LUN & 0x0F);
|
||
Context->cbw.CommandBlockLength = Request->CdbLength;
|
||
|
||
RtlCopyMemory(&Context->cbw.CommandBlock, Request->Cdb, Request->CdbLength);
|
||
|
||
DPRINT("CBW for IRP %p\n", Irp);
|
||
DumpCBW((PUCHAR)&Context->cbw);
|
||
|
||
// initialize rest of context
|
||
Context->Irp = Irp;
|
||
Context->StallRetryCount = 0;
|
||
|
||
return USBSTOR_IssueBulkOrInterruptRequest(
|
||
FDODeviceExtension,
|
||
Irp,
|
||
FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
|
||
USBD_TRANSFER_DIRECTION_OUT,
|
||
sizeof(CBW),
|
||
&Context->cbw,
|
||
NULL,
|
||
USBSTOR_CBWCompletionRoutine);
|
||
}
|
||
|
||
static
|
||
NTSTATUS
|
||
USBSTOR_IssueRequestSense(
|
||
IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
|
||
IN PIRP Irp)
|
||
{
|
||
PIO_STACK_LOCATION IoStack;
|
||
PSCSI_REQUEST_BLOCK CurrentSrb;
|
||
PSCSI_REQUEST_BLOCK SenseSrb;
|
||
|
||
DPRINT("USBSTOR_IssueRequestSense: \n");
|
||
|
||
CurrentSrb = FDODeviceExtension->ActiveSrb;
|
||
SenseSrb = &FDODeviceExtension->CurrentIrpContext.SenseSrb;
|
||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
IoStack->Parameters.Scsi.Srb = SenseSrb;
|
||
|
||
RtlZeroMemory(SenseSrb, sizeof(*SenseSrb));
|
||
|
||
SenseSrb->Function = SRB_FUNCTION_EXECUTE_SCSI;
|
||
SenseSrb->Length = sizeof(*SenseSrb);
|
||
SenseSrb->CdbLength = CDB6GENERIC_LENGTH;
|
||
SenseSrb->SrbFlags = SRB_FLAGS_DATA_IN |
|
||
SRB_FLAGS_NO_QUEUE_FREEZE |
|
||
SRB_FLAGS_DISABLE_AUTOSENSE;
|
||
|
||
ASSERT(CurrentSrb->SenseInfoBufferLength);
|
||
ASSERT(CurrentSrb->SenseInfoBuffer);
|
||
DPRINT("SenseInfoBuffer %x, SenseInfoBufferLength %x\n", CurrentSrb->SenseInfoBuffer, CurrentSrb->SenseInfoBufferLength);
|
||
|
||
SenseSrb->DataTransferLength = CurrentSrb->SenseInfoBufferLength;
|
||
SenseSrb->DataBuffer = CurrentSrb->SenseInfoBuffer;
|
||
|
||
SrbGetCdb(SenseSrb)->CDB6GENERIC.OperationCode = SCSIOP_REQUEST_SENSE;
|
||
SrbGetCdb(SenseSrb)->AsByte[4] = CurrentSrb->SenseInfoBufferLength;
|
||
|
||
return USBSTOR_SendCBWRequest(FDODeviceExtension, Irp);
|
||
}
|
||
|
||
NTSTATUS
|
||
USBSTOR_HandleExecuteSCSI(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp)
|
||
{
|
||
PIO_STACK_LOCATION IoStack;
|
||
PSCSI_REQUEST_BLOCK Request;
|
||
PPDO_DEVICE_EXTENSION PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
||
ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
|
||
|
||
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
Request = IoStack->Parameters.Scsi.Srb;
|
||
|
||
DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x, Length %lu\n", SrbGetCdb(Request)->CDB10.OperationCode, Request->DataTransferLength);
|
||
|
||
/*
|
||
* Some stacks/devices don’t propagate the LUN in the CDB10 header bits.
|
||
* USB BOT uses CBW.bCBWLUN for addressing.
|
||
*
|
||
* TODO: There's actually a bigger bug here though,
|
||
* while the above CAN HAPPPEN:
|
||
* Card Readers multiplex their card slots for example, but we can deal with
|
||
* that as we put more effort into fixing the USB stack.
|
||
*/
|
||
if (SrbGetCdb(Request)->CDB10.LogicalUnitNumber != PDODeviceExtension->LUN)
|
||
{
|
||
DPRINT1("USBSTOR_HandleExecuteSCSI: CDB LUN %lu != PDO LUN %lu (using CBW LUN)\n",
|
||
(ULONG)SrbGetCdb(Request)->CDB10.LogicalUnitNumber,
|
||
(ULONG)PDODeviceExtension->LUN);
|
||
}
|
||
|
||
return USBSTOR_SendCBWRequest(PDODeviceExtension->LowerDeviceObject->DeviceExtension, Irp);
|
||
}
|