reactos/drivers/usb/usbstor/disk.c

692 lines
22 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"
#define NDEBUG
#include <debug.h>
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;
//
// sanity check
//
ASSERT(Request);
//
// get device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// sanity check
//
ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
switch(Request->Function)
{
case SRB_FUNCTION_EXECUTE_SCSI:
{
DPRINT("SRB_FUNCTION_EXECUTE_SCSI\n");
//
// check if request is valid
//
if (Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT))
{
//
// data is transferred with this irp
//
if ((Request->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) == (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT) ||
Request->DataTransferLength == 0 ||
Irp->MdlAddress == NULL)
{
//
// invalid parameter
//
Status = STATUS_INVALID_PARAMETER;
break;
}
}
else
{
//
// sense buffer request
//
if (Request->DataTransferLength ||
Request->DataBuffer ||
Irp->MdlAddress)
{
//
// invalid parameter
//
Status = STATUS_INVALID_PARAMETER;
break;
}
}
//
// add the request
//
if (!USBSTOR_QueueAddIrp(PDODeviceExtension->LowerDeviceObject, Irp))
{
//
// irp was not added to the queue
//
IoStartPacket(PDODeviceExtension->LowerDeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo);
}
//
// irp pending
//
return STATUS_PENDING;
}
case SRB_FUNCTION_RELEASE_DEVICE:
{
DPRINT1("SRB_FUNCTION_RELEASE_DEVICE\n");
//
// sanity check
//
ASSERT(PDODeviceExtension->Claimed == TRUE);
//
// release claim
//
PDODeviceExtension->Claimed = FALSE;
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\n");
//
// release queue
//
USBSTOR_QueueRelease(PDODeviceExtension->LowerDeviceObject);
//
// set status success
//
Request->SrbStatus = SRB_STATUS_SUCCESS;
Status = STATUS_SUCCESS;
break;
}
case SRB_FUNCTION_SHUTDOWN:
case SRB_FUNCTION_FLUSH:
case SRB_FUNCTION_FLUSH_QUEUE:
{
DPRINT1("SRB_FUNCTION_FLUSH / SRB_FUNCTION_FLUSH_QUEUE / SRB_FUNCTION_SHUTDOWN\n");
// HACK: don't flush pending requests
#if 0 // we really need a proper storage stack
//
// wait for pending requests to finish
//
USBSTOR_QueueWaitForPendingRequests(PDODeviceExtension->LowerDeviceObject);
#endif
//
// set status success
//
Request->SrbStatus = SRB_STATUS_SUCCESS;
Status = STATUS_SUCCESS;
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 position 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, FieldLengthSerialNumber;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PUFI_INQUIRY_RESPONSE InquiryData;
PSTORAGE_DEVICE_DESCRIPTOR DeviceDescriptor;
PUCHAR Buffer;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
UNICODE_STRING SerialNumber;
ANSI_STRING AnsiString;
NTSTATUS Status;
DPRINT("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)
{
DPRINT("USBSTOR_HandleQueryProperty StorageDeviceProperty OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
//
// get device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(PDODeviceExtension);
ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
//
// get device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
ASSERT(FDODeviceExtension);
ASSERT(FDODeviceExtension->Common.IsFDO);
//
// 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);
//
// is there a serial number
//
if (FDODeviceExtension->SerialNumber)
{
//
// get length
//
FieldLengthSerialNumber = wcslen(FDODeviceExtension->SerialNumber->bString);
}
else
{
//
// no serial number
//
FieldLengthSerialNumber = 0;
}
//
// total length required is sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLength + 4 extra null bytes - 1
// -1 due STORAGE_DEVICE_DESCRIPTOR contains one byte length of parameter data
//
TotalLength = sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3;
//
// 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 = (InquiryData->RMB & 0x80) ? TRUE : FALSE;
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 = (FieldLengthSerialNumber > 0 ? DeviceDescriptor->ProductRevisionOffset + FieldLengthRevision + 1 : 0);
DeviceDescriptor->RawPropertiesLength = FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3 + (FieldLengthSerialNumber > 0 ? + 1 : 0);
//
// 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;
//
// copy serial number
//
if (FieldLengthSerialNumber)
{
//
// init unicode string
//
RtlInitUnicodeString(&SerialNumber, FDODeviceExtension->SerialNumber->bString);
//
// init ansi string
//
AnsiString.Buffer = (PCHAR)Buffer;
AnsiString.Length = 0;
AnsiString.MaximumLength = FieldLengthSerialNumber * sizeof(WCHAR);
//
// convert to ansi code
//
Status = RtlUnicodeStringToAnsiString(&AnsiString, &SerialNumber, FALSE);
ASSERT(Status == STATUS_SUCCESS);
}
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));
DPRINT("Serial %s\n", (LPCSTR)((ULONG_PTR)DeviceDescriptor + DeviceDescriptor->SerialNumberOffset));
//
// done
//
Irp->IoStatus.Information = TotalLength;
return STATUS_SUCCESS;
}
else
{
//
// adapter property query request
//
DPRINT("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;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PSCSI_ADAPTER_BUS_INFO BusInfo;
PSCSI_INQUIRY_DATA InquiryData;
PINQUIRYDATA ScsiInquiryData;
PUFI_INQUIRY_RESPONSE UFIInquiryResponse;
//
// 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_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 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_CAPABILITIES)
{
PIO_SCSI_CAPABILITIES Capabilities;
/* Legacy port capability query */
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID))
{
Capabilities = *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = ExAllocatePoolWithTag(NonPagedPool,
sizeof(IO_SCSI_CAPABILITIES),
USB_STOR_TAG);
Irp->IoStatus.Information = sizeof(PVOID);
}
else
{
Capabilities = Irp->AssociatedIrp.SystemBuffer;
Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
}
if (Capabilities)
{
Capabilities->MaximumTransferLength = MAXULONG;
Capabilities->MaximumPhysicalPages = 25;
Capabilities->SupportedAsynchronousEvents = 0;
Capabilities->AlignmentMask = 0;
Capabilities->TaggedQueuing = FALSE;
Capabilities->AdapterScansDown = FALSE;
Capabilities->AdapterUsesPio = FALSE;
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_INQUIRY_DATA)
{
//
// get device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ASSERT(PDODeviceExtension);
ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
//
// get parameters
//
BusInfo = Irp->AssociatedIrp.SystemBuffer;
InquiryData = (PSCSI_INQUIRY_DATA)(BusInfo + 1);
ScsiInquiryData = (PINQUIRYDATA)InquiryData->InquiryData;
//
// get inquiry data
//
UFIInquiryResponse = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
ASSERT(UFIInquiryResponse);
BusInfo->NumberOfBuses = 1;
BusInfo->BusData[0].NumberOfLogicalUnits = 1; //FIXME
BusInfo->BusData[0].InitiatorBusId = 0;
BusInfo->BusData[0].InquiryDataOffset = sizeof(SCSI_ADAPTER_BUS_INFO);
InquiryData->PathId = 0;
InquiryData->TargetId = 0;
InquiryData->Lun = PDODeviceExtension->LUN & MAX_LUN;
InquiryData->DeviceClaimed = PDODeviceExtension->Claimed;
InquiryData->InquiryDataLength = sizeof(INQUIRYDATA);
InquiryData->NextInquiryDataOffset = 0;
RtlZeroMemory(ScsiInquiryData, sizeof(INQUIRYDATA));
ScsiInquiryData->DeviceType = UFIInquiryResponse->DeviceType;
ScsiInquiryData->DeviceTypeQualifier = (UFIInquiryResponse->RMB & 0x7F);
/* Hack for IoReadPartitionTable call in disk.sys */
ScsiInquiryData->RemovableMedia = ((ScsiInquiryData->DeviceType != DIRECT_ACCESS_DEVICE) ? ((UFIInquiryResponse->RMB & 0x80) ? 1 : 0) : 0);
ScsiInquiryData->Versions = 0x04;
ScsiInquiryData->ResponseDataFormat = 0x02;
ScsiInquiryData->AdditionalLength = 31;
ScsiInquiryData->SoftReset = 0;
ScsiInquiryData->CommandQueue = 0;
ScsiInquiryData->LinkedCommands = 0;
ScsiInquiryData->RelativeAddressing = 0;
RtlCopyMemory(&ScsiInquiryData->VendorId, UFIInquiryResponse->Vendor, USBSTOR_GetFieldLength(UFIInquiryResponse->Vendor, 8));
RtlCopyMemory(&ScsiInquiryData->ProductId, UFIInquiryResponse->Product, USBSTOR_GetFieldLength(UFIInquiryResponse->Product, 16));
Irp->IoStatus.Information = sizeof(SCSI_ADAPTER_BUS_INFO) + sizeof(SCSI_INQUIRY_DATA) + sizeof(INQUIRYDATA) - 1;
Status = STATUS_SUCCESS;
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_GET_ADDRESS)
{
PSCSI_ADDRESS Address = Irp->AssociatedIrp.SystemBuffer;
Address->Length = sizeof(SCSI_ADDRESS);
Address->PortNumber = 0;
Address->PathId = 0;
Address->TargetId = 0;
Address->Lun = (((PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->LUN & MAX_LUN);
Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
Status = STATUS_SUCCESS;
}
else
{
//
// unsupported
//
DPRINT("USBSTOR_HandleDeviceControl IoControl %x not supported\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
Status = STATUS_NOT_SUPPORTED;
}
return Status;
}