reactos/drivers/usb/usbstor/scsi.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;
}