mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 19:02:32 +00:00
![Johannes Anderwald](/assets/img/avatar_default.png)
- Rewrite scsi method to act asynchronous svn path=/branches/usb-bringup/; revision=51673
535 lines
16 KiB
C
535 lines
16 KiB
C
/*
|
|
* PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: drivers/usb/usbstor/disk.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_HandleExecuteSCSI(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN OUT PSCSI_REQUEST_BLOCK Request,
|
|
IN PPDO_DEVICE_EXTENSION PDODeviceExtension)
|
|
{
|
|
PCDB pCDB;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// get SCSI command data block
|
|
//
|
|
pCDB = (PCDB)Request->Cdb;
|
|
|
|
DPRINT1("USBSTOR_HandleExecuteSCSI Operation Code %x\n", pCDB->AsByte[0]);
|
|
|
|
|
|
if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
|
|
{
|
|
//
|
|
// sanity checks
|
|
//
|
|
ASSERT(Request->DataBuffer);
|
|
|
|
DPRINT1("SCSIOP_READ_CAPACITY Length %\n", Request->DataTransferLength);
|
|
Status = USBSTOR_SendCapacityCmd(DeviceObject, Irp);
|
|
}
|
|
else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE)
|
|
{
|
|
DPRINT1("SCSIOP_MODE_SENSE DataTransferLength %lu\n", Request->DataTransferLength);
|
|
ASSERT(pCDB->MODE_SENSE.AllocationLength == Request->DataTransferLength);
|
|
ASSERT(Request->DataBuffer);
|
|
|
|
//
|
|
// send mode sense command
|
|
//
|
|
Status = USBSTOR_SendModeSenseCmd(DeviceObject, Irp);
|
|
}
|
|
else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_READ)
|
|
{
|
|
DPRINT1("SCSIOP_READ DataTransferLength %lu\n", Request->DataTransferLength);
|
|
ASSERT(Request->DataBuffer);
|
|
|
|
//
|
|
// send read command
|
|
//
|
|
Status = USBSTOR_SendReadCmd(DeviceObject, Irp);
|
|
}
|
|
else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
|
|
{
|
|
DPRINT1("SCSIOP_TEST_UNIT_READY\n");
|
|
|
|
//
|
|
// send test unit command
|
|
//
|
|
Status = USBSTOR_SendTestUnitCmd(DeviceObject, Irp);
|
|
}
|
|
else
|
|
{
|
|
UNIMPLEMENTED;
|
|
Request->SrbStatus = SRB_STATUS_ERROR;
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
USBSTOR_HandleInternalDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PSCSI_REQUEST_BLOCK Request;
|
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// get request block
|
|
//
|
|
Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(Request);
|
|
ASSERT(PDODeviceExtension);
|
|
|
|
switch(Request->Function)
|
|
{
|
|
case SRB_FUNCTION_EXECUTE_SCSI:
|
|
{
|
|
DPRINT1("SRB_FUNCTION_EXECUTE_SCSI\n");
|
|
return USBSTOR_HandleExecuteSCSI(DeviceObject, Irp, Request, PDODeviceExtension);
|
|
}
|
|
case SRB_FUNCTION_RELEASE_DEVICE:
|
|
{
|
|
DPRINT1("SRB_FUNCTION_RELEASE_DEVICE\n");
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(PDODeviceExtension->Claimed == TRUE);
|
|
|
|
//
|
|
// release claim
|
|
//
|
|
PDODeviceExtension->Claimed = TRUE;
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case SRB_FUNCTION_CLAIM_DEVICE:
|
|
{
|
|
DPRINT1("SRB_FUNCTION_CLAIM_DEVICE\n");
|
|
//
|
|
// check if the device has been claimed
|
|
//
|
|
if (PDODeviceExtension->Claimed)
|
|
{
|
|
//
|
|
// device has already been claimed
|
|
//
|
|
Status = STATUS_DEVICE_BUSY;
|
|
Request->SrbStatus = SRB_STATUS_BUSY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// claim device
|
|
//
|
|
PDODeviceExtension->Claimed = TRUE;
|
|
|
|
//
|
|
// output device object
|
|
//
|
|
Request->DataBuffer = DeviceObject;
|
|
|
|
//
|
|
// completed successfully
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case SRB_FUNCTION_RELEASE_QUEUE:
|
|
{
|
|
DPRINT1("SRB_FUNCTION_RELEASE_QUEUE UNIMPLEMENTED\n");
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
case SRB_FUNCTION_FLUSH:
|
|
{
|
|
DPRINT1("SRB_FUNCTION_FLUSH UNIMPLEMENTED\n");
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
case SRB_FUNCTION_SET_LINK_TIMEOUT:
|
|
{
|
|
DPRINT1("SRB_FUNCTION_FLUSH UNIMPLEMENTED\n");
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
//
|
|
// not supported
|
|
//
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
Request->SrbStatus = SRB_STATUS_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// complete request
|
|
//
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
|
|
ULONG
|
|
USBSTOR_GetFieldLength(
|
|
IN PUCHAR Name,
|
|
IN ULONG MaxLength)
|
|
{
|
|
ULONG Index;
|
|
ULONG LastCharacterPosition = 0;
|
|
|
|
//
|
|
// scan the field and return last positon which contains a valid character
|
|
//
|
|
for(Index = 0; Index < MaxLength; Index++)
|
|
{
|
|
if (Name[Index] != ' ')
|
|
{
|
|
//
|
|
// trim white spaces from field
|
|
//
|
|
LastCharacterPosition = Index;
|
|
}
|
|
}
|
|
|
|
//
|
|
// convert from zero based index to length
|
|
//
|
|
return LastCharacterPosition + 1;
|
|
}
|
|
|
|
NTSTATUS
|
|
USBSTOR_HandleQueryProperty(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PSTORAGE_PROPERTY_QUERY PropertyQuery;
|
|
PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader;
|
|
PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor;
|
|
ULONG FieldLengthVendor, FieldLengthProduct, FieldLengthRevision, TotalLength;
|
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
|
PUFI_INQUIRY_RESPONSE InquiryData;
|
|
PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor;
|
|
PUCHAR Buffer;
|
|
|
|
DPRINT1("USBSTOR_HandleQueryProperty\n");
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(IoStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(STORAGE_PROPERTY_QUERY));
|
|
ASSERT(Irp->AssociatedIrp.SystemBuffer);
|
|
|
|
//
|
|
// get property query
|
|
//
|
|
PropertyQuery = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// check property type
|
|
//
|
|
if (PropertyQuery->PropertyId != StorageDeviceProperty &&
|
|
PropertyQuery->PropertyId != StorageAdapterProperty)
|
|
{
|
|
//
|
|
// only device property / adapter property are supported
|
|
//
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
}
|
|
|
|
//
|
|
// check query type
|
|
//
|
|
if (PropertyQuery->QueryType == PropertyExistsQuery)
|
|
{
|
|
//
|
|
// device property / adapter property is supported
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (PropertyQuery->QueryType != PropertyStandardQuery)
|
|
{
|
|
//
|
|
// only standard query and exists query are supported
|
|
//
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
}
|
|
|
|
//
|
|
// check if it is a device property
|
|
//
|
|
if (PropertyQuery->PropertyId == StorageDeviceProperty)
|
|
{
|
|
DPRINT1("USBSTOR_HandleQueryProperty StorageDeviceProperty OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
ASSERT(PDODeviceExtension);
|
|
|
|
//
|
|
// get inquiry data
|
|
//
|
|
InquiryData = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
|
|
ASSERT(InquiryData);
|
|
|
|
//
|
|
// compute extra parameters length
|
|
//
|
|
FieldLengthVendor = USBSTOR_GetFieldLength(InquiryData->Vendor, 8);
|
|
FieldLengthProduct = USBSTOR_GetFieldLength(InquiryData->Product, 16);
|
|
FieldLengthRevision = USBSTOR_GetFieldLength(InquiryData->Revision, 4);
|
|
|
|
//
|
|
// FIXME handle serial number
|
|
//
|
|
|
|
//
|
|
// total length required is sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLength + 3 extra null bytes - 1
|
|
// -1 due STORAGE_DEVICE_DESCRIPTOR contains one byte length of parameter data
|
|
//
|
|
TotalLength = sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + 2;
|
|
|
|
//
|
|
// check if output buffer is long enough
|
|
//
|
|
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < TotalLength)
|
|
{
|
|
//
|
|
// buffer too small
|
|
//
|
|
DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
|
|
ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(STORAGE_DESCRIPTOR_HEADER));
|
|
|
|
//
|
|
// return required size
|
|
//
|
|
DescriptorHeader->Version = TotalLength;
|
|
DescriptorHeader->Size = TotalLength;
|
|
|
|
Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// get device descriptor
|
|
//
|
|
DeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// initialize device descriptor
|
|
//
|
|
DeviceDescriptor->Version = TotalLength;
|
|
DeviceDescriptor->Size = TotalLength;
|
|
DeviceDescriptor->DeviceType = InquiryData->DeviceType;
|
|
DeviceDescriptor->DeviceTypeModifier = (InquiryData->RMB & 0x7F);
|
|
DeviceDescriptor->RemovableMedia = TRUE;
|
|
DeviceDescriptor->CommandQueueing = FALSE;
|
|
DeviceDescriptor->BusType = BusTypeUsb;
|
|
DeviceDescriptor->VendorIdOffset = sizeof(STORAGE_DEVICE_DESCRIPTOR) - sizeof(UCHAR);
|
|
DeviceDescriptor->ProductIdOffset = DeviceDescriptor->VendorIdOffset + FieldLengthVendor + 1;
|
|
DeviceDescriptor->ProductRevisionOffset = DeviceDescriptor->ProductIdOffset + FieldLengthProduct + 1;
|
|
DeviceDescriptor->SerialNumberOffset = 0; //FIXME
|
|
DeviceDescriptor->RawPropertiesLength = FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + 3;
|
|
|
|
//
|
|
// copy descriptors
|
|
//
|
|
Buffer = (PUCHAR)((ULONG_PTR)DeviceDescriptor + sizeof(STORAGE_DEVICE_DESCRIPTOR) - sizeof(UCHAR));
|
|
|
|
//
|
|
// copy vendor
|
|
//
|
|
RtlCopyMemory(Buffer, InquiryData->Vendor, FieldLengthVendor);
|
|
Buffer[FieldLengthVendor] = '\0';
|
|
Buffer += FieldLengthVendor + 1;
|
|
|
|
//
|
|
// copy product
|
|
//
|
|
RtlCopyMemory(Buffer, InquiryData->Product, FieldLengthProduct);
|
|
Buffer[FieldLengthProduct] = '\0';
|
|
Buffer += FieldLengthProduct + 1;
|
|
|
|
//
|
|
// copy revision
|
|
//
|
|
RtlCopyMemory(Buffer, InquiryData->Revision, FieldLengthRevision);
|
|
Buffer[FieldLengthRevision] = '\0';
|
|
Buffer += FieldLengthRevision + 1;
|
|
|
|
//
|
|
// TODO: copy revision
|
|
//
|
|
|
|
DPRINT("Vendor %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->VendorIdOffset));
|
|
DPRINT("Product %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->ProductIdOffset));
|
|
DPRINT("Revision %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->ProductRevisionOffset));
|
|
|
|
//
|
|
// done
|
|
//
|
|
Irp->IoStatus.Information = TotalLength;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// adapter property query request
|
|
//
|
|
DPRINT1("USBSTOR_HandleQueryProperty StorageAdapterProperty OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
|
|
|
|
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_ADAPTER_DESCRIPTOR))
|
|
{
|
|
//
|
|
// buffer too small
|
|
//
|
|
DescriptorHeader = (PSTORAGE_DESCRIPTOR_HEADER)Irp->AssociatedIrp.SystemBuffer;
|
|
ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(STORAGE_DESCRIPTOR_HEADER));
|
|
|
|
//
|
|
// return required size
|
|
//
|
|
DescriptorHeader->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
|
|
DescriptorHeader->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
|
|
|
|
Irp->IoStatus.Information = sizeof(STORAGE_DESCRIPTOR_HEADER);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// get adapter descriptor, information is returned in the same buffer
|
|
//
|
|
AdapterDescriptor = (PSTORAGE_ADAPTER_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// fill out descriptor
|
|
//
|
|
AdapterDescriptor->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
|
|
AdapterDescriptor->Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
|
|
AdapterDescriptor->MaximumTransferLength = MAXULONG; //FIXME compute some sane value
|
|
AdapterDescriptor->MaximumPhysicalPages = 25; //FIXME compute some sane value
|
|
AdapterDescriptor->AlignmentMask = 0;
|
|
AdapterDescriptor->AdapterUsesPio = FALSE;
|
|
AdapterDescriptor->AdapterScansDown = FALSE;
|
|
AdapterDescriptor->CommandQueueing = FALSE;
|
|
AdapterDescriptor->AcceleratedTransfer = FALSE;
|
|
AdapterDescriptor->BusType = BusTypeUsb;
|
|
AdapterDescriptor->BusMajorVersion = 0x2; //FIXME verify
|
|
AdapterDescriptor->BusMinorVersion = 0x00; //FIXME
|
|
|
|
//
|
|
// store returned length
|
|
//
|
|
Irp->IoStatus.Information = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
USBSTOR_HandleDeviceControl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY)
|
|
{
|
|
//
|
|
// query property
|
|
//
|
|
Status = USBSTOR_HandleQueryProperty(DeviceObject, Irp);
|
|
}
|
|
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS)
|
|
{
|
|
//
|
|
// query get scsi address
|
|
//
|
|
DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_GET_ADDRESS NOT implemented\n");
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH)
|
|
{
|
|
//
|
|
// query scsi pass through
|
|
//
|
|
DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH NOT implemented\n");
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)
|
|
{
|
|
//
|
|
// query scsi pass through direct
|
|
//
|
|
DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH_DIRECT NOT implemented\n");
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER)
|
|
{
|
|
//
|
|
// query serial number
|
|
//
|
|
DPRINT1("USBSTOR_HandleDeviceControl IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER NOT implemented\n");
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// unsupported
|
|
//
|
|
DPRINT("USBSTOR_HandleDeviceControl IoControl %x not supported\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
|
|
Status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|