reactos/drivers/usb/usbstor/scsi.c

890 lines
22 KiB
C
Raw Normal View History

/*
* 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"
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 = 0x80;
Control->LUN = (LUN & MAX_LUN);
Control->CommandBlockLength = CommandBlockLength;
//
// copy command block
//
RtlCopyMemory(Control->CommandBlock, CommandBlock, CommandBlockLength);
//
// done
//
return STATUS_SUCCESS;
}
NTSTATUS
USBSTOR_SendCBW(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR CommandBlockLength,
IN PUCHAR CommandBlock,
IN ULONG DataTransferLength,
OUT PCBW *OutControl)
{
PCBW Control;
NTSTATUS Status;
PURB Urb;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get FDO device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
// first allocate CBW
//
Control = (PCBW)AllocateItem(NonPagedPool, 512);
if (!Control)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// first allocate CBW
//
Status = USBSTOR_BuildCBW(0xDEADDEAD, DataTransferLength, PDODeviceExtension->LUN, CommandBlockLength, CommandBlock, Control);
if (!NT_SUCCESS(Status))
{
//
// failed to build CBW
//
return Status;
}
//
// now build the urb
//
Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
if (!Urb)
{
//
// failed to allocate urb
//
FreeItem(Control);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// now initialize the urb
//
Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
Urb->UrbBulkOrInterruptTransfer.TransferBuffer = (PVOID)Control;
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = sizeof(CBW);
Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT | USBD_SHORT_TRANSFER_OK;
//
// now send urb
//
Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
//
// free urb
//
FreeItem(Urb);
//
// store cbw
//
*OutControl = Control;
//
// return operation status
//
return Status;
}
NTSTATUS
USBSTOR_SendData(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG DataTransferLength,
IN PVOID DataTransfer)
{
PMDL TransferBufferMDL;
PURB Urb;
NTSTATUS Status;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get FDO device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
// allocate mdl for buffer, buffer must be allocated from NonPagedPool
//
TransferBufferMDL = IoAllocateMdl(DataTransfer, DataTransferLength, FALSE, FALSE, NULL);
if (!TransferBufferMDL)
{
//
// failed to allocate MDL
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// build mdl for nonpaged pool
//
MmBuildMdlForNonPagedPool(TransferBufferMDL);
//
// now build the urb
//
Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
if (!Urb)
{
//
// failed to allocate urb
//
IoFreeMdl(TransferBufferMDL);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// now initialize the urb
//
Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle;
Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = TransferBufferMDL;
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DataTransferLength;
Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
//
// now send urb
//
Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
//
// free urb
//
FreeItem(Urb);
//
// free mdl
//
IoFreeMdl(TransferBufferMDL);
//
// done
//
return Status;
}
NTSTATUS
USBSTOR_SendCSW(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Data,
IN ULONG DataLength,
OUT PCSW OutCSW)
{
NTSTATUS Status;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
PURB Urb;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get FDO device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
// now build the urb
//
Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
if (!Urb)
{
//
// failed to allocate urb
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// now initialize the urb
//
Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle;
Urb->UrbBulkOrInterruptTransfer.TransferBuffer = Data;
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DataLength;
Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
//
// now send urb
//
Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
if (NT_SUCCESS(Status))
{
//
// copy csw status
//
RtlCopyMemory(OutCSW, Data, sizeof(CSW));
}
//
// free urb
//
FreeItem(Urb);
//
// done
//
return Status;
}
NTSTATUS
USBSTOR_SendInquiryCmd(
IN PDEVICE_OBJECT DeviceObject)
{
UFI_INQUIRY_CMD Cmd;
CSW CSW;
NTSTATUS Status;
PUFI_INQUIRY_RESPONSE Response;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PCBW OutControl;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// allocate inquiry response
//
Response = (PUFI_INQUIRY_RESPONSE)AllocateItem(NonPagedPool, sizeof(UFI_INQUIRY_RESPONSE));
if (!Response)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// 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);
//
// now send inquiry cmd
//
Status = USBSTOR_SendCBW(DeviceObject, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_INQUIRY_RESPONSE), &OutControl);
if (!NT_SUCCESS(Status))
{
//
// failed to send CBW
//
DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendCBW failed with %x\n", Status);
FreeItem(Response);
ASSERT(FALSE);
return Status;
}
//
// now send inquiry response
//
Status = USBSTOR_SendData(DeviceObject, sizeof(UFI_INQUIRY_RESPONSE), Response);
if (!NT_SUCCESS(Status))
{
//
// failed to send CBW
//
DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendData failed with %x\n", Status);
FreeItem(Response);
ASSERT(FALSE);
return Status;
}
DPRINT1("Response %p\n", Response);
DPRINT1("DeviceType %x\n", Response->DeviceType);
DPRINT1("RMB %x\n", Response->RMB);
DPRINT1("Version %x\n", Response->Version);
DPRINT1("Format %x\n", Response->Format);
DPRINT1("Length %x\n", Response->Length);
DPRINT1("Reserved %x\n", Response->Reserved);
DPRINT1("Vendor %c%c%c%c%c%c%c%c\n", Response->Vendor[0], Response->Vendor[1], Response->Vendor[2], Response->Vendor[3], Response->Vendor[4], Response->Vendor[5], Response->Vendor[6], Response->Vendor[7]);
DPRINT1("Product %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", Response->Product[0], Response->Product[1], Response->Product[2], Response->Product[3],
Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
//
// 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);
//
// free item
//
FreeItem(OutControl);
//
// store inquiry data
//
PDODeviceExtension->InquiryData = (PVOID)Response;
//
// FIXME: handle error
//
ASSERT(CSW.Status == 0);
//
// done
//
return Status;
}
NTSTATUS
USBSTOR_SendCapacityCmd(
IN PDEVICE_OBJECT DeviceObject,
OUT PREAD_CAPACITY_DATA_EX CapacityDataEx,
OUT PREAD_CAPACITY_DATA CapacityData)
{
UFI_CAPACITY_CMD Cmd;
CSW CSW;
NTSTATUS Status;
PUFI_CAPACITY_RESPONSE Response;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PCBW OutControl;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// allocate capacity response
//
Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, sizeof(UFI_CAPACITY_RESPONSE));
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);
//
// now send capacity cmd
//
Status = USBSTOR_SendCBW(DeviceObject, UFI_CAPACITY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_CAPACITY_RESPONSE), &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 inquiry response
//
Status = USBSTOR_SendData(DeviceObject, sizeof(UFI_CAPACITY_RESPONSE), 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;
}
DPRINT1("LastLogicalBlockAddress %lu\n", NTOHL(Response->LastLogicalBlockAddress));
DPRINT1("BlockLength %lu\n", NTOHL(Response->BlockLength));
DPRINT1("Medium Length %lu\n", NTOHL(Response->BlockLength) * NTOHL(Response->LastLogicalBlockAddress));
//
// store response
//
if (CapacityDataEx)
{
CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress;
CapacityDataEx->BytesPerBlock = Response->BlockLength;
}
else
{
CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress;
CapacityData->BytesPerBlock = Response->BlockLength;
}
//
// store result in device extension
//
PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);
PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
//
// 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);
//
// free item
//
FreeItem(OutControl);
//
// free response
//
FreeItem(Response);
//
// done
//
return Status;
}
NTSTATUS
USBSTOR_SendModeSenseCmd(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PSCSI_REQUEST_BLOCK Request,
OUT PULONG TransferBufferLength)
{
UFI_SENSE_CMD Cmd;
CSW CSW;
NTSTATUS Status;
PVOID Response;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PCBW OutControl;
PCDB pCDB;
PUFI_MODE_PARAMETER_HEADER Header;
//
// 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;
}
NTSTATUS
USBSTOR_SendReadCmd(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PSCSI_REQUEST_BLOCK Request,
OUT PULONG TransferBufferLength)
{
UFI_READ_CMD Cmd;
CSW CSW;
NTSTATUS Status;
PVOID Response;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PCBW OutControl;
PCDB pCDB;
ULONG BlockCount;
//
// get SCSI command data block
//
pCDB = (PCDB)Request->Cdb;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// allocate read buffer response from non paged pool
//
Response = (PUFI_CAPACITY_RESPONSE)AllocateItem(NonPagedPool, Request->DataTransferLength);
if (!Response)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// FIXME: support more logical blocks
//
ASSERT(Request->DataTransferLength == PDODeviceExtension->BlockLength);
//
// block count
//
BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength;
//
// initialize read sense cmd
//
RtlZeroMemory(&Cmd, sizeof(UFI_READ_CMD));
Cmd.Code = SCSIOP_READ;
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
Cmd.ContiguousLogicBlocks = _byteswap_ushort(BlockCount);
RtlCopyMemory(&Cmd.LogicalBlockAddress, pCDB->READ12.LogicalBlock, sizeof(UCHAR) * 4);
DPRINT1("BlockAddress %lu BlockCount %lu BlockLength %lu\n", NTOHL(Cmd.LogicalBlockAddress), BlockCount, PDODeviceExtension->BlockLength);
//
// now send read cmd
//
Status = USBSTOR_SendCBW(DeviceObject, UFI_READ_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, &OutControl);
if (!NT_SUCCESS(Status))
{
//
// failed to send CBW
//
DPRINT1("USBSTOR_SendReadCmd> USBSTOR_SendCBW failed with %x\n", Status);
FreeItem(Response);
ASSERT(FALSE);
return Status;
}
//
// now read the logical block
//
Status = USBSTOR_SendData(DeviceObject, Request->DataTransferLength, Response);
if (!NT_SUCCESS(Status))
{
//
// failed to read logical block
//
DPRINT1("USBSTOR_SendReadCmd> USBSTOR_SendData failed with %x\n", Status);
FreeItem(Response);
ASSERT(FALSE);
return Status;
}
DbgBreakPoint();
//
// 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;
}
NTSTATUS
USBSTOR_SendTestUnitCmd(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PSCSI_REQUEST_BLOCK Request)
{
UFI_TEST_UNIT_CMD Cmd;
CSW CSW;
NTSTATUS Status;
PVOID Response;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PCBW OutControl;
PCDB pCDB;
ULONG BlockCount;
//
// initialize test unit cmd
//
RtlZeroMemory(&Cmd, sizeof(UFI_TEST_UNIT_CMD));
Cmd.Code = SCSIOP_TEST_UNIT_READY;
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
//
// no data should be transferred
//
ASSERT(Request->DataTransferLength == 0);
//
// now send test unit cmd
//
Status = USBSTOR_SendCBW(DeviceObject, UFI_TEST_UNIT_CMD_LEN, (PUCHAR)&Cmd, 0, &OutControl);
if (!NT_SUCCESS(Status))
{
//
// failed to send CBW
//
DPRINT1("USBSTOR_SendReadCmd> USBSTOR_SendCBW failed with %x\n", Status);
FreeItem(Response);
ASSERT(FALSE);
return Status;
}
//
// 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);
//
// free item
//
FreeItem(OutControl);
//
// FIXME: read sense buffer
//
//
// done
//
return Status;
}