mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
1430 lines
37 KiB
C
1430 lines
37 KiB
C
|
/*
|
||
|
* PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
|
||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||
|
* FILE: drivers/usb/usbstor/pdo.c
|
||
|
* PURPOSE: USB block storage device driver.
|
||
|
* PROGRAMMERS:
|
||
|
* James Tabor
|
||
|
* Michael Martin (michael.martin@reactos.org)
|
||
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
||
|
*/
|
||
|
|
||
|
#include "usbstor.h"
|
||
|
|
||
|
#define NDEBUG
|
||
|
#include <debug.h>
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_BuildCBW(
|
||
|
IN ULONG Tag,
|
||
|
IN ULONG DataTransferLength,
|
||
|
IN UCHAR LUN,
|
||
|
IN UCHAR CommandBlockLength,
|
||
|
IN PUCHAR CommandBlock,
|
||
|
IN OUT PCBW Control)
|
||
|
{
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
ASSERT(CommandBlockLength <= 16);
|
||
|
|
||
|
//
|
||
|
// now initialize CBW
|
||
|
//
|
||
|
Control->Signature = CBW_SIGNATURE;
|
||
|
Control->Tag = Tag;
|
||
|
Control->DataTransferLength = DataTransferLength;
|
||
|
Control->Flags = (CommandBlock[0] != SCSIOP_WRITE) ? 0x80 : 0x00;
|
||
|
Control->LUN = (LUN & MAX_LUN);
|
||
|
Control->CommandBlockLength = CommandBlockLength;
|
||
|
|
||
|
//
|
||
|
// copy command block
|
||
|
//
|
||
|
RtlCopyMemory(Control->CommandBlock, CommandBlock, CommandBlockLength);
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
PIRP_CONTEXT
|
||
|
USBSTOR_AllocateIrpContext()
|
||
|
{
|
||
|
PIRP_CONTEXT Context;
|
||
|
|
||
|
//
|
||
|
// allocate irp context
|
||
|
//
|
||
|
Context = (PIRP_CONTEXT)AllocateItem(NonPagedPool, sizeof(IRP_CONTEXT));
|
||
|
if (!Context)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// allocate cbw block
|
||
|
//
|
||
|
Context->cbw = (PCBW)AllocateItem(NonPagedPool, 512);
|
||
|
if (!Context->cbw)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
FreeItem(Context);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return Context;
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
USBSTOR_IsCSWValid(
|
||
|
PIRP_CONTEXT Context)
|
||
|
{
|
||
|
//
|
||
|
// sanity checks
|
||
|
//
|
||
|
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 != (ULONG)Context->csw)
|
||
|
{
|
||
|
DPRINT1("[USBSTOR] Expected Tag %x but got %x\n", (ULONG)Context->csw, Context->csw->Tag);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (Context->csw->Status != 0x00)
|
||
|
{
|
||
|
DPRINT1("[USBSTOR] Expected Status 0x00 but got %x\n", Context->csw->Status);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// CSW is valid
|
||
|
//
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_QueueWorkItem(
|
||
|
PIRP_CONTEXT Context,
|
||
|
PIRP Irp)
|
||
|
{
|
||
|
PERRORHANDLER_WORKITEM_DATA ErrorHandlerWorkItemData;
|
||
|
|
||
|
//
|
||
|
// Allocate Work Item Data
|
||
|
//
|
||
|
ErrorHandlerWorkItemData = ExAllocatePoolWithTag(NonPagedPool, sizeof(ERRORHANDLER_WORKITEM_DATA), USB_STOR_TAG);
|
||
|
if (!ErrorHandlerWorkItemData)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// error handling started
|
||
|
//
|
||
|
Context->FDODeviceExtension->SrbErrorHandlingActive = TRUE;
|
||
|
|
||
|
//
|
||
|
// srb error handling finished
|
||
|
//
|
||
|
Context->FDODeviceExtension->TimerWorkQueueEnabled = FALSE;
|
||
|
|
||
|
//
|
||
|
// Initialize and queue the work item to handle the error
|
||
|
//
|
||
|
ExInitializeWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem,
|
||
|
ErrorHandlerWorkItemRoutine,
|
||
|
ErrorHandlerWorkItemData);
|
||
|
|
||
|
ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
|
||
|
ErrorHandlerWorkItemData->Context = Context;
|
||
|
ErrorHandlerWorkItemData->Irp = Irp;
|
||
|
ErrorHandlerWorkItemData->DeviceObject = Context->FDODeviceExtension->FunctionalDeviceObject;
|
||
|
|
||
|
DPRINT1("Queuing WorkItemROutine\n");
|
||
|
ExQueueWorkItem(&ErrorHandlerWorkItemData->WorkQueueItem, DelayedWorkQueue);
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// driver verifier
|
||
|
//
|
||
|
IO_COMPLETION_ROUTINE USBSTOR_CSWCompletionRoutine;
|
||
|
|
||
|
NTSTATUS
|
||
|
NTAPI
|
||
|
USBSTOR_CSWCompletionRoutine(
|
||
|
PDEVICE_OBJECT DeviceObject,
|
||
|
PIRP Irp,
|
||
|
PVOID Ctx)
|
||
|
{
|
||
|
PIRP_CONTEXT Context;
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
PSCSI_REQUEST_BLOCK Request;
|
||
|
PCDB pCDB;
|
||
|
PREAD_CAPACITY_DATA_EX CapacityDataEx;
|
||
|
PREAD_CAPACITY_DATA CapacityData;
|
||
|
PUFI_CAPACITY_RESPONSE Response;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
//
|
||
|
// access context
|
||
|
//
|
||
|
Context = (PIRP_CONTEXT)Ctx;
|
||
|
|
||
|
//
|
||
|
// is there a mdl
|
||
|
//
|
||
|
if (Context->TransferBufferMDL)
|
||
|
{
|
||
|
//
|
||
|
// is there an irp associated
|
||
|
//
|
||
|
if (Context->Irp)
|
||
|
{
|
||
|
//
|
||
|
// did we allocate the mdl
|
||
|
//
|
||
|
if (Context->TransferBufferMDL != Context->Irp->MdlAddress)
|
||
|
{
|
||
|
//
|
||
|
// free mdl
|
||
|
//
|
||
|
IoFreeMdl(Context->TransferBufferMDL);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// free mdl
|
||
|
//
|
||
|
IoFreeMdl(Context->TransferBufferMDL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status);
|
||
|
|
||
|
if (!NT_SUCCESS(Irp->IoStatus.Information))
|
||
|
{
|
||
|
if (Context->ErrorIndex == 0)
|
||
|
{
|
||
|
//
|
||
|
// increment error index
|
||
|
//
|
||
|
Context->ErrorIndex = 1;
|
||
|
|
||
|
//
|
||
|
// clear stall and resend cbw
|
||
|
//
|
||
|
Status = USBSTOR_QueueWorkItem(Context, Irp);
|
||
|
ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// perform reset recovery
|
||
|
//
|
||
|
Context->ErrorIndex = 2;
|
||
|
IoFreeIrp(Irp);
|
||
|
Status = USBSTOR_QueueWorkItem(Context, NULL);
|
||
|
ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
if (!USBSTOR_IsCSWValid(Context))
|
||
|
{
|
||
|
//
|
||
|
// perform reset recovery
|
||
|
//
|
||
|
Context->ErrorIndex = 2;
|
||
|
IoFreeIrp(Irp);
|
||
|
Status = USBSTOR_QueueWorkItem(Context, NULL);
|
||
|
ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// get current stack location
|
||
|
//
|
||
|
IoStack = IoGetCurrentIrpStackLocation(Context->Irp);
|
||
|
|
||
|
//
|
||
|
// get request block
|
||
|
//
|
||
|
Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
|
||
|
ASSERT(Request);
|
||
|
|
||
|
Status = Irp->IoStatus.Status;
|
||
|
|
||
|
//
|
||
|
// get SCSI command data block
|
||
|
//
|
||
|
pCDB = (PCDB)Request->Cdb;
|
||
|
Request->SrbStatus = SRB_STATUS_SUCCESS;
|
||
|
|
||
|
//
|
||
|
// read capacity needs special work
|
||
|
//
|
||
|
if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
|
||
|
{
|
||
|
//
|
||
|
// get output buffer
|
||
|
//
|
||
|
Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData;
|
||
|
|
||
|
//
|
||
|
// store in pdo
|
||
|
//
|
||
|
Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
|
||
|
Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);
|
||
|
|
||
|
if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX))
|
||
|
{
|
||
|
//
|
||
|
// get input buffer
|
||
|
//
|
||
|
CapacityDataEx = (PREAD_CAPACITY_DATA_EX)Request->DataBuffer;
|
||
|
|
||
|
//
|
||
|
// set result
|
||
|
//
|
||
|
CapacityDataEx->BytesPerBlock = Response->BlockLength;
|
||
|
CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress;
|
||
|
Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// get input buffer
|
||
|
//
|
||
|
CapacityData = (PREAD_CAPACITY_DATA)Request->DataBuffer;
|
||
|
|
||
|
//
|
||
|
// set result
|
||
|
//
|
||
|
CapacityData->BytesPerBlock = Response->BlockLength;
|
||
|
CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress;
|
||
|
Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// free response
|
||
|
//
|
||
|
FreeItem(Context->TransferData);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// free cbw
|
||
|
//
|
||
|
FreeItem(Context->cbw);
|
||
|
|
||
|
//
|
||
|
// FIXME: check status
|
||
|
//
|
||
|
Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
|
||
|
Context->Irp->IoStatus.Information = Context->TransferDataLength;
|
||
|
|
||
|
//
|
||
|
// terminate current request
|
||
|
//
|
||
|
USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp);
|
||
|
|
||
|
//
|
||
|
// complete request
|
||
|
//
|
||
|
IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);
|
||
|
|
||
|
//
|
||
|
// start next request
|
||
|
//
|
||
|
USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);
|
||
|
|
||
|
//
|
||
|
// free our allocated irp
|
||
|
//
|
||
|
IoFreeIrp(Irp);
|
||
|
|
||
|
//
|
||
|
// free context
|
||
|
//
|
||
|
FreeItem(Context);
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
USBSTOR_SendCSW(
|
||
|
PIRP_CONTEXT Context,
|
||
|
PIRP Irp)
|
||
|
{
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
|
||
|
//
|
||
|
// get next irp stack location
|
||
|
//
|
||
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// now initialize the urb for sending the csw
|
||
|
//
|
||
|
UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
|
||
|
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
|
||
|
Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
|
||
|
Context->csw,
|
||
|
NULL,
|
||
|
512, //FIXME
|
||
|
USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
|
||
|
NULL);
|
||
|
|
||
|
//
|
||
|
// initialize stack location
|
||
|
//
|
||
|
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
|
||
|
IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
|
||
|
IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
|
||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
|
||
|
|
||
|
//
|
||
|
// setup completion routine
|
||
|
//
|
||
|
IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
|
||
|
|
||
|
//
|
||
|
// call driver
|
||
|
//
|
||
|
IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// driver verifier
|
||
|
//
|
||
|
IO_COMPLETION_ROUTINE USBSTOR_DataCompletionRoutine;
|
||
|
|
||
|
NTSTATUS
|
||
|
NTAPI
|
||
|
USBSTOR_DataCompletionRoutine(
|
||
|
PDEVICE_OBJECT DeviceObject,
|
||
|
PIRP Irp,
|
||
|
PVOID Ctx)
|
||
|
{
|
||
|
PIRP_CONTEXT Context;
|
||
|
NTSTATUS Status;
|
||
|
|
||
|
|
||
|
DPRINT("USBSTOR_DataCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
|
||
|
|
||
|
//
|
||
|
// access context
|
||
|
//
|
||
|
Context = (PIRP_CONTEXT)Ctx;
|
||
|
|
||
|
if (!NT_SUCCESS(Irp->IoStatus.Status))
|
||
|
{
|
||
|
//
|
||
|
// clear stall and resend cbw
|
||
|
//
|
||
|
Context->ErrorIndex = 1;
|
||
|
Status = USBSTOR_QueueWorkItem(Context, Irp);
|
||
|
ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// send csw
|
||
|
//
|
||
|
USBSTOR_SendCSW(Context, Irp);
|
||
|
|
||
|
//
|
||
|
// cancel completion
|
||
|
//
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// driver verifier
|
||
|
//
|
||
|
IO_COMPLETION_ROUTINE USBSTOR_CBWCompletionRoutine;
|
||
|
|
||
|
NTSTATUS
|
||
|
NTAPI
|
||
|
USBSTOR_CBWCompletionRoutine(
|
||
|
PDEVICE_OBJECT DeviceObject,
|
||
|
PIRP Irp,
|
||
|
PVOID Ctx)
|
||
|
{
|
||
|
PIRP_CONTEXT Context;
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
UCHAR Code;
|
||
|
USBD_PIPE_HANDLE PipeHandle;
|
||
|
|
||
|
DPRINT("USBSTOR_CBWCompletionRoutine Irp %p Ctx %p Status %x\n", Irp, Ctx, Irp->IoStatus.Status);
|
||
|
|
||
|
//
|
||
|
// access context
|
||
|
//
|
||
|
Context = (PIRP_CONTEXT)Ctx;
|
||
|
|
||
|
//
|
||
|
// get next stack location
|
||
|
//
|
||
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// is there data to be submitted
|
||
|
//
|
||
|
if (Context->TransferDataLength)
|
||
|
{
|
||
|
//
|
||
|
// get command code
|
||
|
//
|
||
|
Code = Context->cbw->CommandBlock[0];
|
||
|
|
||
|
if (Code == SCSIOP_WRITE)
|
||
|
{
|
||
|
//
|
||
|
// write request use bulk out pipe
|
||
|
//
|
||
|
PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// default bulk in pipe
|
||
|
//
|
||
|
PipeHandle = Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// now initialize the urb for sending data
|
||
|
//
|
||
|
UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
|
||
|
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
|
||
|
PipeHandle,
|
||
|
NULL,
|
||
|
Context->TransferBufferMDL,
|
||
|
Context->TransferDataLength,
|
||
|
((Code == SCSIOP_WRITE) ? USBD_TRANSFER_DIRECTION_OUT : (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK)),
|
||
|
NULL);
|
||
|
|
||
|
//
|
||
|
// setup completion routine
|
||
|
//
|
||
|
IoSetCompletionRoutine(Irp, USBSTOR_DataCompletionRoutine, Context, TRUE, TRUE, TRUE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// now initialize the urb for sending the csw
|
||
|
//
|
||
|
|
||
|
UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
|
||
|
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
|
||
|
Context->FDODeviceExtension->InterfaceInformation->Pipes[Context->FDODeviceExtension->BulkInPipeIndex].PipeHandle,
|
||
|
Context->csw,
|
||
|
NULL,
|
||
|
512, //FIXME
|
||
|
USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
|
||
|
NULL);
|
||
|
|
||
|
//
|
||
|
// setup completion routine
|
||
|
//
|
||
|
IoSetCompletionRoutine(Irp, USBSTOR_CSWCompletionRoutine, Context, TRUE, TRUE, TRUE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// initialize stack location
|
||
|
//
|
||
|
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
|
||
|
IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
|
||
|
IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
|
||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
|
||
|
//
|
||
|
// call driver
|
||
|
//
|
||
|
IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
|
||
|
|
||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_SendCBW(
|
||
|
PIRP_CONTEXT Context,
|
||
|
PIRP Irp)
|
||
|
{
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
|
||
|
//
|
||
|
// get next stack location
|
||
|
//
|
||
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// initialize stack location
|
||
|
//
|
||
|
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
||
|
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
|
||
|
IoStack->Parameters.Others.Argument1 = (PVOID)&Context->Urb;
|
||
|
IoStack->Parameters.DeviceIoControl.InputBufferLength = Context->Urb.UrbHeader.Length;
|
||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
|
||
|
//
|
||
|
// setup completion routine
|
||
|
//
|
||
|
IoSetCompletionRoutine(Irp, USBSTOR_CBWCompletionRoutine, Context, TRUE, TRUE, TRUE);
|
||
|
|
||
|
//
|
||
|
// call driver
|
||
|
//
|
||
|
return IoCallDriver(Context->FDODeviceExtension->LowerDeviceObject, Irp);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_SendRequest(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP OriginalRequest,
|
||
|
IN UCHAR CommandLength,
|
||
|
IN PUCHAR Command,
|
||
|
IN ULONG TransferDataLength,
|
||
|
IN PUCHAR TransferData,
|
||
|
IN ULONG RetryCount)
|
||
|
{
|
||
|
PIRP_CONTEXT Context;
|
||
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
PFDO_DEVICE_EXTENSION FDODeviceExtension;
|
||
|
PIRP Irp;
|
||
|
PUCHAR MdlVirtualAddress;
|
||
|
|
||
|
//
|
||
|
// first allocate irp context
|
||
|
//
|
||
|
Context = USBSTOR_AllocateIrpContext();
|
||
|
if (!Context)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// get FDO device extension
|
||
|
//
|
||
|
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// now build the cbw
|
||
|
//
|
||
|
USBSTOR_BuildCBW((ULONG)Context->cbw,
|
||
|
TransferDataLength,
|
||
|
PDODeviceExtension->LUN,
|
||
|
CommandLength,
|
||
|
Command,
|
||
|
Context->cbw);
|
||
|
|
||
|
DPRINT("CBW %p\n", Context->cbw);
|
||
|
DumpCBW((PUCHAR)Context->cbw);
|
||
|
|
||
|
//
|
||
|
// now initialize the urb
|
||
|
//
|
||
|
UsbBuildInterruptOrBulkTransferRequest(&Context->Urb,
|
||
|
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
|
||
|
FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle,
|
||
|
Context->cbw,
|
||
|
NULL,
|
||
|
sizeof(CBW),
|
||
|
USBD_TRANSFER_DIRECTION_OUT,
|
||
|
NULL);
|
||
|
|
||
|
//
|
||
|
// initialize rest of context
|
||
|
//
|
||
|
Context->Irp = OriginalRequest;
|
||
|
Context->TransferData = TransferData;
|
||
|
Context->TransferDataLength = TransferDataLength;
|
||
|
Context->FDODeviceExtension = FDODeviceExtension;
|
||
|
Context->PDODeviceExtension = PDODeviceExtension;
|
||
|
Context->RetryCount = RetryCount;
|
||
|
|
||
|
//
|
||
|
// is there transfer data
|
||
|
//
|
||
|
if (Context->TransferDataLength)
|
||
|
{
|
||
|
//
|
||
|
// check if the original request already does have an mdl associated
|
||
|
//
|
||
|
if (OriginalRequest)
|
||
|
{
|
||
|
if ((OriginalRequest->MdlAddress != NULL) &&
|
||
|
(Context->TransferData == NULL || Command[0] == SCSIOP_READ || Command[0] == SCSIOP_WRITE))
|
||
|
{
|
||
|
//
|
||
|
// Sanity check that the Mdl does describe the TransferData for read/write
|
||
|
//
|
||
|
if (CommandLength == UFI_READ_WRITE_CMD_LEN)
|
||
|
{
|
||
|
MdlVirtualAddress = MmGetMdlVirtualAddress(OriginalRequest->MdlAddress);
|
||
|
|
||
|
//
|
||
|
// is there an offset
|
||
|
//
|
||
|
if (MdlVirtualAddress != Context->TransferData)
|
||
|
{
|
||
|
//
|
||
|
// lets build an mdl
|
||
|
//
|
||
|
Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, MmGetMdlByteCount(OriginalRequest->MdlAddress), FALSE, FALSE, NULL);
|
||
|
if (!Context->TransferBufferMDL)
|
||
|
{
|
||
|
//
|
||
|
// failed to allocate MDL
|
||
|
//
|
||
|
FreeItem(Context->cbw);
|
||
|
FreeItem(Context);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// now build the partial mdl
|
||
|
//
|
||
|
IoBuildPartialMdl(OriginalRequest->MdlAddress, Context->TransferBufferMDL, Context->TransferData, Context->TransferDataLength);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!Context->TransferBufferMDL)
|
||
|
{
|
||
|
//
|
||
|
// I/O paging request
|
||
|
//
|
||
|
Context->TransferBufferMDL = OriginalRequest->MdlAddress;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// allocate mdl for buffer, buffer must be allocated from NonPagedPool
|
||
|
//
|
||
|
Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
|
||
|
if (!Context->TransferBufferMDL)
|
||
|
{
|
||
|
//
|
||
|
// failed to allocate MDL
|
||
|
//
|
||
|
FreeItem(Context->cbw);
|
||
|
FreeItem(Context);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// build mdl for nonpaged pool
|
||
|
//
|
||
|
MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// allocate mdl for buffer, buffer must be allocated from NonPagedPool
|
||
|
//
|
||
|
Context->TransferBufferMDL = IoAllocateMdl(Context->TransferData, Context->TransferDataLength, FALSE, FALSE, NULL);
|
||
|
if (!Context->TransferBufferMDL)
|
||
|
{
|
||
|
//
|
||
|
// failed to allocate MDL
|
||
|
//
|
||
|
FreeItem(Context->cbw);
|
||
|
FreeItem(Context);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// build mdl for nonpaged pool
|
||
|
//
|
||
|
MmBuildMdlForNonPagedPool(Context->TransferBufferMDL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// now allocate the request
|
||
|
//
|
||
|
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
|
||
|
if (!Irp)
|
||
|
{
|
||
|
FreeItem(Context->cbw);
|
||
|
FreeItem(Context);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
if (OriginalRequest)
|
||
|
{
|
||
|
//
|
||
|
// mark orignal irp as pending
|
||
|
//
|
||
|
IoMarkIrpPending(OriginalRequest);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// send request
|
||
|
//
|
||
|
USBSTOR_SendCBW(Context, Irp);
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return STATUS_PENDING;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_SendFormatCapacity(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP Irp,
|
||
|
IN ULONG RetryCount)
|
||
|
{
|
||
|
UFI_READ_FORMAT_CAPACITY Cmd;
|
||
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
PSCSI_REQUEST_BLOCK Request;
|
||
|
|
||
|
//
|
||
|
// get current stack location
|
||
|
//
|
||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// get request block
|
||
|
//
|
||
|
Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
|
||
|
|
||
|
//
|
||
|
// initialize inquiry cmd
|
||
|
//
|
||
|
RtlZeroMemory(&Cmd, sizeof(UFI_READ_FORMAT_CAPACITY));
|
||
|
Cmd.Code = SCSIOP_READ_FORMATTED_CAPACITY;
|
||
|
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
|
||
|
Cmd.AllocationLengthMsb = HTONS(Request->DataTransferLength & 0xFFFF) >> 8;
|
||
|
Cmd.AllocationLengthLsb = HTONS(Request->DataTransferLength & 0xFFFF) & 0xFF;
|
||
|
|
||
|
//
|
||
|
// now send the request
|
||
|
//
|
||
|
return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_FORMAT_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_SendInquiry(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP Irp,
|
||
|
IN ULONG RetryCount)
|
||
|
{
|
||
|
UFI_INQUIRY_CMD Cmd;
|
||
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
PSCSI_REQUEST_BLOCK Request;
|
||
|
|
||
|
//
|
||
|
// get current stack location
|
||
|
//
|
||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// get request block
|
||
|
//
|
||
|
Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// initialize inquiry cmd
|
||
|
//
|
||
|
RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
|
||
|
Cmd.Code = SCSIOP_INQUIRY;
|
||
|
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
|
||
|
Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
|
||
|
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
ASSERT(Request->DataTransferLength >= sizeof(UFI_INQUIRY_RESPONSE));
|
||
|
|
||
|
//
|
||
|
// now send the request
|
||
|
//
|
||
|
return USBSTOR_SendRequest(DeviceObject, Irp, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_SendCapacity(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP Irp,
|
||
|
IN ULONG RetryCount)
|
||
|
{
|
||
|
UFI_CAPACITY_CMD Cmd;
|
||
|
PUFI_CAPACITY_RESPONSE Response;
|
||
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// allocate capacity response
|
||
|
//
|
||
|
Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, PAGE_SIZE);
|
||
|
if (!Response)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// initialize capacity cmd
|
||
|
//
|
||
|
RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
|
||
|
Cmd.Code = SCSIOP_READ_CAPACITY;
|
||
|
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
|
||
|
|
||
|
//
|
||
|
// send request, response will be freed in completion routine
|
||
|
//
|
||
|
return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), (PUCHAR)Response, RetryCount);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_SendModeSense(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP Irp,
|
||
|
IN ULONG RetryCount)
|
||
|
{
|
||
|
#if 0
|
||
|
UFI_SENSE_CMD Cmd;
|
||
|
NTSTATUS Status;
|
||
|
PVOID Response;
|
||
|
PCBW OutControl;
|
||
|
PCDB pCDB;
|
||
|
PUFI_MODE_PARAMETER_HEADER Header;
|
||
|
#endif
|
||
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
PSCSI_REQUEST_BLOCK Request;
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
|
||
|
|
||
|
//
|
||
|
// get current stack location
|
||
|
//
|
||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// get request block
|
||
|
//
|
||
|
Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
|
||
|
|
||
|
RtlZeroMemory(Request->DataBuffer, Request->DataTransferLength);
|
||
|
Request->SrbStatus = SRB_STATUS_SUCCESS;
|
||
|
Irp->IoStatus.Information = Request->DataTransferLength;
|
||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
|
||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
|
||
|
//
|
||
|
// start next request
|
||
|
//
|
||
|
USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
#if 0
|
||
|
//
|
||
|
// get SCSI command data block
|
||
|
//
|
||
|
pCDB = (PCDB)Request->Cdb;
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// allocate sense response from non paged pool
|
||
|
//
|
||
|
Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength);
|
||
|
if (!Response)
|
||
|
{
|
||
|
//
|
||
|
// no memory
|
||
|
//
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
|
||
|
|
||
|
// Supported pages
|
||
|
// MODE_PAGE_ERROR_RECOVERY
|
||
|
// MODE_PAGE_FLEXIBILE
|
||
|
// MODE_PAGE_LUN_MAPPING
|
||
|
// MODE_PAGE_FAULT_REPORTING
|
||
|
// MODE_SENSE_RETURN_ALL
|
||
|
|
||
|
//
|
||
|
// initialize mode sense cmd
|
||
|
//
|
||
|
RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
|
||
|
Cmd.Code = SCSIOP_MODE_SENSE;
|
||
|
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
|
||
|
Cmd.PageCode = pCDB->MODE_SENSE.PageCode;
|
||
|
Cmd.PC = pCDB->MODE_SENSE.Pc;
|
||
|
Cmd.AllocationLength = HTONS(pCDB->MODE_SENSE.AllocationLength);
|
||
|
|
||
|
DPRINT1("PageCode %x\n", pCDB->MODE_SENSE.PageCode);
|
||
|
DPRINT1("PC %x\n", pCDB->MODE_SENSE.Pc);
|
||
|
|
||
|
//
|
||
|
// now send mode sense cmd
|
||
|
//
|
||
|
Status = USBSTOR_SendCBW(DeviceObject, UFI_SENSE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl);
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
//
|
||
|
// failed to send CBW
|
||
|
//
|
||
|
DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendCBW failed with %x\n", Status);
|
||
|
FreeItem(Response);
|
||
|
ASSERT(FALSE);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// now send data block response
|
||
|
//
|
||
|
Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response);
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
//
|
||
|
// failed to send CBW
|
||
|
//
|
||
|
DPRINT1("USBSTOR_SendCapacityCmd> USBSTOR_SendData failed with %x\n", Status);
|
||
|
FreeItem(Response);
|
||
|
ASSERT(FALSE);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Header = (PUFI_MODE_PARAMETER_HEADER)Response;
|
||
|
|
||
|
//
|
||
|
// TODO: build layout
|
||
|
//
|
||
|
// first struct is the header
|
||
|
// MODE_PARAMETER_HEADER / _MODE_PARAMETER_HEADER10
|
||
|
//
|
||
|
// followed by
|
||
|
// MODE_PARAMETER_BLOCK
|
||
|
//
|
||
|
//
|
||
|
UNIMPLEMENTED;
|
||
|
|
||
|
//
|
||
|
// send csw
|
||
|
//
|
||
|
Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
|
||
|
|
||
|
DPRINT1("------------------------\n");
|
||
|
DPRINT1("CSW %p\n", &CSW);
|
||
|
DPRINT1("Signature %x\n", CSW.Signature);
|
||
|
DPRINT1("Tag %x\n", CSW.Tag);
|
||
|
DPRINT1("DataResidue %x\n", CSW.DataResidue);
|
||
|
DPRINT1("Status %x\n", CSW.Status);
|
||
|
|
||
|
//
|
||
|
// FIXME: handle error
|
||
|
//
|
||
|
ASSERT(CSW.Status == 0);
|
||
|
ASSERT(CSW.DataResidue == 0);
|
||
|
|
||
|
//
|
||
|
// calculate transfer length
|
||
|
//
|
||
|
*TransferBufferLength = Request->DataTransferLength - CSW.DataResidue;
|
||
|
|
||
|
//
|
||
|
// copy buffer
|
||
|
//
|
||
|
RtlCopyMemory(Request->DataBuffer, Response, *TransferBufferLength);
|
||
|
|
||
|
//
|
||
|
// free item
|
||
|
//
|
||
|
FreeItem(OutControl);
|
||
|
|
||
|
//
|
||
|
// free response
|
||
|
//
|
||
|
FreeItem(Response);
|
||
|
|
||
|
//
|
||
|
// done
|
||
|
//
|
||
|
return Status;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_SendReadWrite(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP Irp,
|
||
|
IN ULONG RetryCount)
|
||
|
{
|
||
|
UFI_READ_WRITE_CMD Cmd;
|
||
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
PCDB pCDB;
|
||
|
ULONG BlockCount, Temp;
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
PSCSI_REQUEST_BLOCK Request;
|
||
|
|
||
|
//
|
||
|
// get current stack location
|
||
|
//
|
||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// get request block
|
||
|
//
|
||
|
Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
|
||
|
|
||
|
//
|
||
|
// get SCSI command data block
|
||
|
//
|
||
|
pCDB = (PCDB)Request->Cdb;
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// informal debug print
|
||
|
//
|
||
|
DPRINT("USBSTOR_SendReadWrite DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);
|
||
|
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
ASSERT(PDODeviceExtension->BlockLength);
|
||
|
|
||
|
//
|
||
|
// block count
|
||
|
//
|
||
|
BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength;
|
||
|
|
||
|
//
|
||
|
// initialize read cmd
|
||
|
//
|
||
|
RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD));
|
||
|
Cmd.Code = pCDB->AsByte[0];
|
||
|
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
|
||
|
Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb;
|
||
|
Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb;
|
||
|
Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0;
|
||
|
Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1;
|
||
|
Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2;
|
||
|
Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3;
|
||
|
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
Temp = (Cmd.ContiguousLogicBlocksByte0 << 8 | Cmd.ContiguousLogicBlocksByte1);
|
||
|
ASSERT(Temp == BlockCount);
|
||
|
|
||
|
DPRINT("USBSTOR_SendReadWrite BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);
|
||
|
|
||
|
//
|
||
|
// send request
|
||
|
//
|
||
|
return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_SendTestUnit(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN OUT PIRP Irp,
|
||
|
IN ULONG RetryCount)
|
||
|
{
|
||
|
UFI_TEST_UNIT_CMD Cmd;
|
||
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
PSCSI_REQUEST_BLOCK Request;
|
||
|
|
||
|
//
|
||
|
// get current stack location
|
||
|
//
|
||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// get request block
|
||
|
//
|
||
|
Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
|
||
|
|
||
|
//
|
||
|
// no transfer length
|
||
|
//
|
||
|
ASSERT(Request->DataTransferLength == 0);
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// initialize test unit cmd
|
||
|
//
|
||
|
RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD));
|
||
|
Cmd.Code = SCSIOP_TEST_UNIT_READY;
|
||
|
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
|
||
|
|
||
|
//
|
||
|
// send the request
|
||
|
//
|
||
|
return USBSTOR_SendRequest(DeviceObject, Irp, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, NULL, RetryCount);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_SendUnknownRequest(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN OUT PIRP Irp,
|
||
|
IN ULONG RetryCount)
|
||
|
{
|
||
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
PSCSI_REQUEST_BLOCK Request;
|
||
|
UFI_UNKNOWN_CMD Cmd;
|
||
|
|
||
|
//
|
||
|
// get current stack location
|
||
|
//
|
||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// get request block
|
||
|
//
|
||
|
Request = IoStack->Parameters.Others.Argument1;
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// check that we're sending to the right LUN
|
||
|
//
|
||
|
ASSERT(Request->Cdb[1] == (PDODeviceExtension->LUN & MAX_LUN));
|
||
|
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
ASSERT(Request->CdbLength <= sizeof(UFI_UNKNOWN_CMD));
|
||
|
|
||
|
//
|
||
|
// initialize test unit cmd
|
||
|
//
|
||
|
RtlCopyMemory(&Cmd, Request->Cdb, Request->CdbLength);
|
||
|
|
||
|
//
|
||
|
// send the request
|
||
|
//
|
||
|
return USBSTOR_SendRequest(DeviceObject, Irp, Request->CdbLength, (PUCHAR)&Cmd, Request->DataTransferLength, Request->DataBuffer, RetryCount);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
USBSTOR_HandleExecuteSCSI(
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN PIRP Irp,
|
||
|
IN ULONG RetryCount)
|
||
|
{
|
||
|
PCDB pCDB;
|
||
|
NTSTATUS Status;
|
||
|
PIO_STACK_LOCATION IoStack;
|
||
|
PSCSI_REQUEST_BLOCK Request;
|
||
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
||
|
|
||
|
//
|
||
|
// get PDO device extension
|
||
|
//
|
||
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// sanity check
|
||
|
//
|
||
|
ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
|
||
|
|
||
|
//
|
||
|
// get current stack location
|
||
|
//
|
||
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
|
||
|
//
|
||
|
// get request block
|
||
|
//
|
||
|
Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
|
||
|
|
||
|
//
|
||
|
// get SCSI command data block
|
||
|
//
|
||
|
pCDB = (PCDB)Request->Cdb;
|
||
|
|
||
|
DPRINT("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
|
||
|
|
||
|
if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
|
||
|
{
|
||
|
//
|
||
|
// sanity checks
|
||
|
//
|
||
|
ASSERT(Request->DataBuffer);
|
||
|
|
||
|
DPRINT("SCSIOP_READ_CAPACITY Length %lu\n", Request->DataTransferLength);
|
||
|
Status = USBSTOR_SendCapacity(DeviceObject, Irp, RetryCount);
|
||
|
}
|
||
|
else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE)
|
||
|
{
|
||
|
DPRINT("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength);
|
||
|
ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength);
|
||
|
ASSERT(Request->DataBuffer);
|
||
|
|
||
|
//
|
||
|
// send mode sense command
|
||
|
//
|
||
|
Status = USBSTOR_SendModeSense(DeviceObject, Irp, RetryCount);
|
||
|
}
|
||
|
else if (pCDB->AsByte[0] == SCSIOP_READ_FORMATTED_CAPACITY)
|
||
|
{
|
||
|
DPRINT("SCSIOP_READ_FORMATTED_CAPACITY DataTransferLength %lu\n", Request->DataTransferLength);
|
||
|
|
||
|
//
|
||
|
// send read format capacity
|
||
|
//
|
||
|
Status = USBSTOR_SendFormatCapacity(DeviceObject, Irp, RetryCount);
|
||
|
}
|
||
|
else if (pCDB->AsByte[0] == SCSIOP_INQUIRY)
|
||
|
{
|
||
|
DPRINT("SCSIOP_INQUIRY DataTransferLength %lu\n", Request->DataTransferLength);
|
||
|
|
||
|
//
|
||
|
// send read format capacity
|
||
|
//
|
||
|
Status = USBSTOR_SendInquiry(DeviceObject, Irp, RetryCount);
|
||
|
}
|
||
|
else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ || pCDB->MODE_SENSE.OperationCode == SCSIOP_WRITE)
|
||
|
{
|
||
|
DPRINT("SCSIOP_READ / SCSIOP_WRITE DataTransferLength %lu\n", Request->DataTransferLength);
|
||
|
|
||
|
//
|
||
|
// send read / write command
|
||
|
//
|
||
|
Status = USBSTOR_SendReadWrite(DeviceObject, Irp, RetryCount);
|
||
|
}
|
||
|
else if (pCDB->AsByte[0] == SCSIOP_MEDIUM_REMOVAL)
|
||
|
{
|
||
|
DPRINT("SCSIOP_MEDIUM_REMOVAL\n");
|
||
|
|
||
|
//
|
||
|
// just complete the request
|
||
|
//
|
||
|
Request->SrbStatus = SRB_STATUS_SUCCESS;
|
||
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
Irp->IoStatus.Information = Request->DataTransferLength;
|
||
|
USBSTOR_QueueTerminateRequest(PDODeviceExtension->LowerDeviceObject, Irp);
|
||
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
|
||
|
//
|
||
|
// start next request
|
||
|
//
|
||
|
USBSTOR_QueueNextRequest(PDODeviceExtension->LowerDeviceObject);
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
|
||
|
{
|
||
|
DPRINT("SCSIOP_TEST_UNIT_READY\n");
|
||
|
|
||
|
//
|
||
|
// send test unit command
|
||
|
//
|
||
|
Status = USBSTOR_SendTestUnit(DeviceObject, Irp, RetryCount);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Unknown request. Simply forward
|
||
|
DPRINT1("Forwarding unknown Operation Code %x\n", pCDB->AsByte[0]);
|
||
|
Status = USBSTOR_SendUnknownRequest(DeviceObject, Irp, RetryCount);
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|