[USBSTOR]
[reactos.git] / drivers / usb / usbstor / disk.c
index cdd1f16..0f426c8 100644 (file)
 
 #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;
-    ULONG TransferredLength;
-
-    //
-    // 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);
-
-        if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX))
-        {
-            //
-            // retrieve capacity extended structure
-            //
-            Status = USBSTOR_SendCapacityCmd(DeviceObject, (PREAD_CAPACITY_DATA_EX)Request->DataBuffer, NULL);
-        }
-        else
-        {
-            //
-            // sanity check
-            //
-            ASSERT(Request->DataTransferLength == sizeof(READ_CAPACITY_DATA));
-
-            //
-            // retrieve capacity
-            //
-            Status = USBSTOR_SendCapacityCmd(DeviceObject, NULL, (PREAD_CAPACITY_DATA)Request->DataBuffer);
-        }
-        DPRINT1("USBSTOR_SendCapacityCmd %x\n", Status);
-
-        if (NT_SUCCESS(Status))
-        {
-            //
-            // store returned info length
-            //
-            Irp->IoStatus.Information = Request->DataTransferLength;
-            Request->SrbStatus = SRB_STATUS_SUCCESS;
-        }
-        else
-        {
-            //
-            // failed to retrieve capacity
-            //
-            Irp->IoStatus.Information = 0;
-            Request->SrbStatus = SRB_STATUS_ERROR;
-        }
-    }
-    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, Request, &TransferredLength);
-        DPRINT1("USBSTOR_SendModeSenseCmd Status %x BytesReturned %lu\n", Status, TransferredLength);
-
-        if (NT_SUCCESS(Status))
-        {
-            //
-            // store returned info length
-            //
-            Irp->IoStatus.Information = TransferredLength;
-            Request->SrbStatus = SRB_STATUS_SUCCESS;
-        }
-        else
-        {
-            //
-            // failed to retrieve sense data
-            //
-            Irp->IoStatus.Information = 0;
-            Request->SrbStatus = SRB_STATUS_ERROR;
-        }
-    }
-    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, Request, &TransferredLength);
-        DPRINT1("USBSTOR_SendReadCmd Status %x BytesReturned %lu\n", Status, TransferredLength);
-
-        if (NT_SUCCESS(Status))
-        {
-            //
-            // store returned info length
-            //
-            Irp->IoStatus.Information = TransferredLength;
-            Request->SrbStatus = SRB_STATUS_SUCCESS;
-        }
-        else
-        {
-            //
-            // failed to read
-            //
-            Irp->IoStatus.Information = 0;
-            Request->SrbStatus = SRB_STATUS_ERROR;
-        }
-    }
-    else if (pCDB->MODE_SENSE.OperationCode == SCSIOP_TEST_UNIT_READY)
-    {
-        DPRINT1("SCSIOP_TEST_UNIT_READY\n");
-
-        //
-        // send test unit command
-        //
-        Status = USBSTOR_SendTestUnitCmd(DeviceObject, Request);
-
-        if (NT_SUCCESS(Status))
-        {
-            //
-            // store returned info length
-            //
-            Request->SrbStatus = SRB_STATUS_SUCCESS;
-        }
-        else
-        {
-            //
-            // test unit command failed
-            //
-            Request->SrbStatus = SRB_STATUS_ERROR;
-        }
-    }
-    else
-    {
-        UNIMPLEMENTED;
-        Request->SrbStatus = SRB_STATUS_ERROR;
-        Status = STATUS_NOT_SUPPORTED;
-        DbgBreakPoint();
-    }
-
-    return Status;
-}
-
 NTSTATUS
 USBSTOR_HandleInternalDeviceControl(
     IN PDEVICE_OBJECT DeviceObject,
@@ -186,6 +31,11 @@ USBSTOR_HandleInternalDeviceControl(
     //
     Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
 
+    //
+    // sanity check
+    //
+    ASSERT(Request);
+
     //
     // get device extension
     //
@@ -194,16 +44,65 @@ USBSTOR_HandleInternalDeviceControl(
     //
     // sanity check
     //
-    ASSERT(Request);
-    ASSERT(PDODeviceExtension);
+    ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
 
     switch(Request->Function)
     {
         case SRB_FUNCTION_EXECUTE_SCSI:
         {
-            DPRINT1("SRB_FUNCTION_EXECUTE_SCSI\n");
-            Status = USBSTOR_HandleExecuteSCSI(DeviceObject, Irp, Request, PDODeviceExtension);
-            break;
+            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:
         {
@@ -216,7 +115,7 @@ USBSTOR_HandleInternalDeviceControl(
             //
             // release claim
             //
-            PDODeviceExtension->Claimed = TRUE;
+            PDODeviceExtension->Claimed = FALSE;
             Status = STATUS_SUCCESS;
             break;
         }
@@ -254,20 +153,36 @@ USBSTOR_HandleInternalDeviceControl(
         }
         case SRB_FUNCTION_RELEASE_QUEUE:
         {
-            DPRINT1("SRB_FUNCTION_RELEASE_QUEUE UNIMPLEMENTED\n");
-            Status = STATUS_NOT_IMPLEMENTED;
+            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_FLUSH:
+        case SRB_FUNCTION_FLUSH_QUEUE:
         {
-            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;
+            DPRINT1("SRB_FUNCTION_FLUSH / SRB_FUNCTION_FLUSH_QUEUE\n");
+
+            //
+            // flush all requests
+            //
+            USBSTOR_QueueFlushIrps(PDODeviceExtension->LowerDeviceObject);
+
+            //
+            // set status success
+            //
+            Request->SrbStatus = SRB_STATUS_SUCCESS;
+            Status = STATUS_SUCCESS;
             break;
         }
         default:
@@ -280,6 +195,11 @@ USBSTOR_HandleInternalDeviceControl(
         }
     }
 
+    //
+    // complete request
+    //
+    Irp->IoStatus.Status = Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
     return Status;
 }
 
@@ -320,11 +240,15 @@ USBSTOR_HandleQueryProperty(
     PSTORAGE_PROPERTY_QUERY PropertyQuery;
     PSTORAGE_DESCRIPTOR_HEADER DescriptorHeader;
     PSTORAGE_ADAPTER_DESCRIPTOR AdapterDescriptor;
-    ULONG FieldLengthVendor, FieldLengthProduct, FieldLengthRevision, TotalLength;
+    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;
 
     DPRINT1("USBSTOR_HandleQueryProperty\n");
 
@@ -387,6 +311,14 @@ USBSTOR_HandleQueryProperty(
         //
         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
@@ -402,14 +334,28 @@ USBSTOR_HandleQueryProperty(
         FieldLengthRevision = USBSTOR_GetFieldLength(InquiryData->Revision, 4);
 
         //
-        // FIXME handle serial number
+        // 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 + 3 extra null bytes - 1
+        // 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 + 2;
+        TotalLength = sizeof(STORAGE_DEVICE_DESCRIPTOR) + FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3;
 
         //
         // check if output buffer is long enough
@@ -450,8 +396,8 @@ USBSTOR_HandleQueryProperty(
         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;
+        DeviceDescriptor->SerialNumberOffset = (FieldLengthSerialNumber > 0 ? DeviceDescriptor->ProductRevisionOffset + FieldLengthRevision + 1 : 0);
+        DeviceDescriptor->RawPropertiesLength = FieldLengthVendor + FieldLengthProduct + FieldLengthRevision + FieldLengthSerialNumber + 3 + (FieldLengthSerialNumber > 0 ? + 1 : 0);
 
         //
         // copy descriptors
@@ -480,12 +426,34 @@ USBSTOR_HandleQueryProperty(
         Buffer += FieldLengthRevision + 1;
 
         //
-        // TODO: copy revision
+        // 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
@@ -558,6 +526,11 @@ USBSTOR_HandleDeviceControl(
 {
     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
@@ -571,14 +544,6 @@ USBSTOR_HandleDeviceControl(
         //
         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)
     {
         //
@@ -603,6 +568,108 @@ USBSTOR_HandleDeviceControl(
         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) = ExAllocatePool(NonPagedPool, sizeof(IO_SCSI_CAPABILITIES));
+            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) ? 1 : 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
     {
         //