/* * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: USB block storage device driver. * COPYRIGHT: 2005-2006 James Tabor * 2011-2012 Michael Martin (michael.martin@reactos.org) * 2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org) */ #include "usbstor.h" #define NDEBUG #include NTSTATUS USBSTOR_HandleInternalDeviceControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { PIO_STACK_LOCATION IoStack; PSCSI_REQUEST_BLOCK Request; PPDO_DEVICE_EXTENSION PDODeviceExtension; NTSTATUS Status; IoStack = IoGetCurrentIrpStackLocation(Irp); Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1; ASSERT(Request); PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 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) { Status = STATUS_INVALID_PARAMETER; break; } } else { // sense buffer request if (Request->DataTransferLength || Request->DataBuffer || Irp->MdlAddress) { Status = STATUS_INVALID_PARAMETER; break; } } // add the request if (!USBSTOR_QueueAddIrp(PDODeviceExtension->LowerDeviceObject, Irp)) { IoStartPacket(PDODeviceExtension->LowerDeviceObject, Irp, &Request->QueueSortKey, USBSTOR_CancelIo); } return STATUS_PENDING; } case SRB_FUNCTION_RELEASE_DEVICE: { DPRINT1("SRB_FUNCTION_RELEASE_DEVICE\n"); 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; Status = STATUS_SUCCESS; break; } case SRB_FUNCTION_RELEASE_QUEUE: { DPRINT1("SRB_FUNCTION_RELEASE_QUEUE\n"); USBSTOR_QueueRelease(PDODeviceExtension->LowerDeviceObject); 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 Request->SrbStatus = SRB_STATUS_SUCCESS; Status = STATUS_SUCCESS; break; } default: { // // not supported // Status = STATUS_NOT_SUPPORTED; Request->SrbStatus = SRB_STATUS_ERROR; } } 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"); IoStack = IoGetCurrentIrpStackLocation(Irp); ASSERT(IoStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(STORAGE_PROPERTY_QUERY)); ASSERT(Irp->AssociatedIrp.SystemBuffer); 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); PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(PDODeviceExtension); ASSERT(PDODeviceExtension->Common.IsFDO == FALSE); FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension; ASSERT(FDODeviceExtension); ASSERT(FDODeviceExtension->Common.IsFDO); 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); if (FDODeviceExtension->SerialNumber) { FieldLengthSerialNumber = wcslen(FDODeviceExtension->SerialNumber->bString); } else { 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; } // initialize the device descriptor DeviceDescriptor = (PSTORAGE_DEVICE_DESCRIPTOR)Irp->AssociatedIrp.SystemBuffer; 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)); RtlCopyMemory(Buffer, InquiryData->Vendor, FieldLengthVendor); Buffer[FieldLengthVendor] = '\0'; Buffer += FieldLengthVendor + 1; RtlCopyMemory(Buffer, InquiryData->Product, FieldLengthProduct); Buffer[FieldLengthProduct] = '\0'; Buffer += FieldLengthProduct + 1; RtlCopyMemory(Buffer, InquiryData->Revision, FieldLengthRevision); Buffer[FieldLengthRevision] = '\0'; Buffer += FieldLengthRevision + 1; if (FieldLengthSerialNumber) { RtlInitUnicodeString(&SerialNumber, FDODeviceExtension->SerialNumber->bString); AnsiString.Buffer = (PCHAR)Buffer; AnsiString.Length = 0; AnsiString.MaximumLength = FieldLengthSerialNumber * sizeof(WCHAR); 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)); 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); 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; IoStack = IoGetCurrentIrpStackLocation(Irp); switch (IoStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_STORAGE_QUERY_PROPERTY: Status = USBSTOR_HandleQueryProperty(DeviceObject, Irp); break; case IOCTL_SCSI_PASS_THROUGH: DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH NOT implemented\n"); Status = STATUS_NOT_SUPPORTED; break; case IOCTL_SCSI_PASS_THROUGH_DIRECT: DPRINT1("USBSTOR_HandleDeviceControl IOCTL_SCSI_PASS_THROUGH_DIRECT NOT implemented\n"); Status = STATUS_NOT_SUPPORTED; break; case IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER: DPRINT1("USBSTOR_HandleDeviceControl IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER NOT implemented\n"); Status = STATUS_NOT_SUPPORTED; break; case 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; } break; } case IOCTL_SCSI_GET_INQUIRY_DATA: { 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; 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; break; } case 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; break; } default: DPRINT("USBSTOR_HandleDeviceControl IoControl %x not supported\n", IoStack->Parameters.DeviceIoControl.IoControlCode); Status = STATUS_NOT_SUPPORTED; break; } return Status; }