Implemented IOCTL_SCSI_MINIPORT.
[reactos.git] / reactos / drivers / storage / scsiport / scsiport.c
index 93d6dab..600b799 100644 (file)
@@ -32,8 +32,9 @@
 #include <ddk/srb.h>
 #include <ddk/scsi.h>
 #include <ddk/ntddscsi.h>
-#include <ntos/minmax.h>
-#include <rosrtl/string.h>
+#include <ddk/ntddstor.h>
+#include <ddk/ntdddisk.h>
+#include <stdio.h>
 
 #define NDEBUG
 #include <debug.h>
@@ -138,6 +139,10 @@ SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
                    PSCSI_REQUEST_BLOCK Srb);
 
 
+static NTSTATUS
+SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
+               IN PIRP Irp);
+
 /* FUNCTIONS *****************************************************************/
 
 /**********************************************************************
@@ -274,6 +279,7 @@ ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
 /*
  * @implemented
  */
+#undef ScsiPortConvertPhysicalAddressToUlong
 ULONG STDCALL
 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
 {
@@ -478,7 +484,7 @@ ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
     }
   if (Srb == NULL)
     {
-      EndAddress = DeviceExtension->VirtualAddress + DeviceExtension->CommonBufferLength;
+      EndAddress = (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + DeviceExtension->CommonBufferLength);
       if (VirtualAddress >= DeviceExtension->VirtualAddress && VirtualAddress < EndAddress)
         {
          Offset = (ULONG_PTR)VirtualAddress - (ULONG_PTR)DeviceExtension->VirtualAddress;
@@ -506,14 +512,14 @@ ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
     }
   else
     {
-      EndAddress = Srb->DataBuffer + Srb->DataTransferLength;
+      EndAddress = (PVOID)((ULONG_PTR)Srb->DataBuffer + Srb->DataTransferLength);
       if (VirtualAddress == NULL)
        {
          VirtualAddress = Srb->DataBuffer;
        }
       else if (VirtualAddress < Srb->DataBuffer || VirtualAddress >= EndAddress)
        {
-         EndAddress = Srb->SenseInfoBuffer + Srb->SenseInfoBufferLength;
+         EndAddress = (PVOID)((ULONG_PTR)Srb->SenseInfoBuffer + Srb->SenseInfoBufferLength);
          if (VirtualAddress < Srb->SenseInfoBuffer || VirtualAddress >= EndAddress)
            {
              PhysicalAddress.QuadPart = 0LL;
@@ -530,18 +536,18 @@ ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
        }
 
       BufferLength = PAGE_SIZE - (ULONG_PTR)VirtualAddress % PAGE_SIZE;
-      while (VirtualAddress + BufferLength < EndAddress)
+      while ((ULONG_PTR)VirtualAddress + BufferLength < (ULONG_PTR)EndAddress)
        {
-         NextPhysicalAddress = MmGetPhysicalAddress(VirtualAddress + BufferLength);
+         NextPhysicalAddress = MmGetPhysicalAddress((PVOID)((ULONG_PTR)VirtualAddress + BufferLength));
          if (PhysicalAddress.QuadPart + BufferLength != NextPhysicalAddress.QuadPart)
            {
              break;
            }
          BufferLength += PAGE_SIZE;
        }
-      if (VirtualAddress + BufferLength >= EndAddress)
+      if ((ULONG_PTR)VirtualAddress + BufferLength >= (ULONG_PTR)EndAddress)
        {
-         BufferLength = EndAddress - VirtualAddress;
+         BufferLength = (ULONG)((ULONG_PTR)EndAddress - (ULONG_PTR)VirtualAddress);
        }
     }
   if (Length != NULL)
@@ -837,6 +843,9 @@ ScsiPortInitialize(IN PVOID Argument1,
 
       DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);
 
+      /* Increase the stacksize. We reenter our device on IOCTL_SCSI_MINIPORT */
+      PortDeviceObject->StackSize++;
+
       /* Set the buffering strategy here... */
       PortDeviceObject->Flags |= DO_DIRECT_IO;
       PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
@@ -925,7 +934,7 @@ ScsiPortInitialize(IN PVOID Argument1,
       PortConfig->DemandMode = FALSE;
       PortConfig->MapBuffers = HwInitializationData->MapBuffers;
       PortConfig->NeedPhysicalAddresses = HwInitializationData->NeedPhysicalAddresses;
-      PortConfig->TaggedQueuing = HwInitializationData->TaggedQueueing;
+      PortConfig->TaggedQueuing = HwInitializationData->TaggedQueuing;
       PortConfig->AutoRequestSense = HwInitializationData->AutoRequestSense;
       PortConfig->MultipleRequestPerLu = HwInitializationData->MultipleRequestPerLu;
       PortConfig->ReceiveEvent = HwInitializationData->ReceiveEvent;
@@ -937,7 +946,7 @@ ScsiPortInitialize(IN PVOID Argument1,
       PortConfig->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
       PortConfig->SpecificLuExtensionSize = HwInitializationData->SpecificLuExtensionSize;
 
-      PortConfig->AccessRanges = (PACCESS_RANGE)(PortConfig + 1);
+      PortConfig->AccessRanges = (ACCESS_RANGE(*)[])(PortConfig + 1);
 
       /* Search for matching PCI device */
       if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
@@ -1458,9 +1467,9 @@ SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
 
                  for (i = 0; i < PortConfig->NumberOfAccessRanges; i++)
                    {
-                     PortConfig->AccessRanges[i].RangeStart.QuadPart =
+                     (*PortConfig->AccessRanges)[i].RangeStart.QuadPart =
                        PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_ADDRESS_MASK;
-                     if (PortConfig->AccessRanges[i].RangeStart.QuadPart != 0)
+                     if ((*PortConfig->AccessRanges)[i].RangeStart.QuadPart != 0)
                        {
                          RangeLength = (ULONG)-1;
                          HalSetBusDataByOffset (PCIConfiguration,
@@ -1485,9 +1494,9 @@ SpiGetPciConfigData (IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
                                                 sizeof(ULONG));
                          if (RangeLength != 0)
                            {
-                             PortConfig->AccessRanges[i].RangeLength =
+                             (*PortConfig->AccessRanges)[i].RangeLength =
                                -(RangeLength & PCI_ADDRESS_IO_ADDRESS_MASK);
-                             PortConfig->AccessRanges[i].RangeInMemory =
+                             (*PortConfig->AccessRanges)[i].RangeInMemory =
                                !(PciConfig.u.type0.BaseAddresses[i] & PCI_ADDRESS_IO_SPACE);
 
                              DPRINT("RangeStart 0x%lX  RangeLength 0x%lX  RangeInMemory %s\n",
@@ -1710,10 +1719,10 @@ ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
 {
   PIO_STACK_LOCATION Stack;
   PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+  NTSTATUS Status = STATUS_SUCCESS;
 
   DPRINT("ScsiPortDeviceControl()\n");
 
-  Irp->IoStatus.Status = STATUS_SUCCESS;
   Irp->IoStatus.Information = 0;
 
 
@@ -1755,16 +1764,167 @@ ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
          DPRINT("Inquiry data size: %lu\n", Irp->IoStatus.Information);
        }
        break;
+      
+      case IOCTL_SCSI_PASS_THROUGH:
+        DPRINT("  IOCTL_SCSI_PASS_THROUGH\n");
+        Status = STATUS_NOT_IMPLEMENTED;
+        break;
+
+      case IOCTL_SCSI_PASS_THROUGH_DIRECT:
+        DPRINT("  IOCTL_SCSI_PASS_THROUGH_DIRECT\n");
+        Status = STATUS_NOT_IMPLEMENTED;
+        break;
+
+      case IOCTL_SCSI_MINIPORT:
+        DPRINT1("  IOCTL_SCSI_MINIPORT\n");
+        DPRINT1("  Signature: %.8s\n", ((PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer)->Signature);
+        DPRINT1("  ControlCode: 0x%lX\n", ((PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer)->ControlCode);
+        return SpiScsiMiniport(DeviceObject, Irp);
 
       default:
        DPRINT1("  unknown ioctl code: 0x%lX\n",
               Stack->Parameters.DeviceIoControl.IoControlCode);
+        Status = STATUS_INVALID_DEVICE_REQUEST;
        break;
     }
 
+  Irp->IoStatus.Status = Status;
   IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
-  return(STATUS_SUCCESS);
+  return Status;
+}
+
+static NTSTATUS STDCALL
+SpiCompletion(IN PDEVICE_OBJECT DeviceObject,
+             IN PIRP Irp,
+             IN PVOID Context)
+{
+  PSCSI_REQUEST_BLOCK Srb;
+  
+  DPRINT("SpiCompletion(DeviceObject %x, Irp %x, Context %x)\n",
+         DeviceObject, Irp, Context);
+
+  Srb = (PSCSI_REQUEST_BLOCK)Context;
+  Irp->IoStatus.Information = 0;
+
+  switch (SRB_STATUS(Srb->SrbStatus))
+    {
+      case SRB_STATUS_SUCCESS:
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = Srb->DataTransferLength;
+        break;
+
+      case SRB_STATUS_INVALID_PATH_ID:
+      case SRB_STATUS_INVALID_TARGET_ID:
+      case SRB_STATUS_INVALID_LUN:
+      case SRB_STATUS_NO_HBA:
+        Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
+       break;
+
+      case SRB_STATUS_NO_DEVICE:
+        Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
+        break;
+
+      case SRB_STATUS_BUSY:
+       Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
+        break;
+
+      case SRB_STATUS_DATA_OVERRUN:
+       Irp->IoStatus.Status = STATUS_DATA_OVERRUN;
+        Irp->IoStatus.Information = Srb->DataTransferLength;
+        break;
+
+      case SRB_STATUS_INVALID_REQUEST:
+        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+        break;
+
+      default:
+       Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
+       break;
+    }
+
+  ExFreePool(Srb);
+
+  if (Irp->PendingReturned)
+    {
+      IoMarkIrpPending (Irp);
+    }
+  return Irp->IoStatus.Status;
+}
+
+static NTSTATUS
+SpiScsiMiniport(IN PDEVICE_OBJECT DeviceObject,
+               IN PIRP Irp)
+{
+  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
+  PSRB_IO_CONTROL SrbIoControl;
+  PIO_STACK_LOCATION IrpStack;
+  PSCSI_REQUEST_BLOCK Srb;
+  PSCSI_PORT_LUN_EXTENSION LunExtension;
+  
+  DPRINT("SpiScsiMiniport(DeviceObject %x, Irp %x)\n",
+         DeviceObject, Irp);
+
+  DeviceExtension = DeviceObject->DeviceExtension;
+  SrbIoControl = (PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer;
+
+  IrpStack = IoGetCurrentIrpStackLocation(Irp);
+  if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1)
+    {
+      Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_INVALID_PARAMETER;
+    }
+  if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SRB_IO_CONTROL) + SrbIoControl->Length)
+    {
+      Irp->IoStatus.Information = sizeof(SRB_IO_CONTROL) + SrbIoControl->Length;
+      Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_BUFFER_TOO_SMALL;
+    }
+  if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
+    {
+      Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
+      Irp->IoStatus.Information = 0;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_NO_SUCH_DEVICE;
+    }
+
+  Srb = ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
+  if (Srb == NULL)
+    {
+      Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);
+      return STATUS_INSUFFICIENT_RESOURCES;
+    }
+  RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
+  Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+  Srb->OriginalRequest = Irp;
+  Srb->Function = SRB_FUNCTION_IO_CONTROL;
+  Srb->DataBuffer = (PVOID)SrbIoControl;
+  Srb->DataTransferLength = sizeof(SRB_IO_CONTROL) + SrbIoControl->Length;
+
+  /* We using the first extension from the list. The miniport driver is responsible to find the correct device. */
+  LunExtension = CONTAINING_RECORD(DeviceExtension->LunExtensionListHead.Flink,
+                                  SCSI_PORT_LUN_EXTENSION,
+                                  List);
+  Srb->PathId = LunExtension->PathId;
+  Srb->TargetId = LunExtension->TargetId;
+  Srb->Lun = LunExtension->Lun;
+  
+  IrpStack = IoGetNextIrpStackLocation(Irp);
+  
+  IrpStack->MajorFunction = IRP_MJ_SCSI;
+  IrpStack->Parameters.Scsi.Srb = Srb;
+
+  IoSetCompletionRoutine(Irp,
+                        SpiCompletion,
+                        Srb,
+                        TRUE,
+                        TRUE,
+                        TRUE);
+
+  return IoCallDriver(DeviceObject, Irp);
 }
 
 static VOID
@@ -1786,7 +1946,7 @@ SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
       if (index != 0xffffffff)
         {
          DeviceExtension->CurrentSrbExtensions++;
-          Srb->SrbExtension = DeviceExtension->VirtualAddress + index * DeviceExtension->SrbExtensionSize;
+          Srb->SrbExtension = (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + index * DeviceExtension->SrbExtensionSize);
        }
     }
   DPRINT("%x\n", Srb->SrbExtension);
@@ -2337,7 +2497,8 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
 {
   PSCSI_PORT_LUN_EXTENSION LunExtension;
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING KeyName;
+  UNICODE_STRING KeyName =
+    RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
   UNICODE_STRING ValueName;
   WCHAR NameBuffer[64];
   ULONG Disposition;
@@ -2365,8 +2526,6 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
     }
 
   /* Open or create the 'Scsi' subkey */
-  RtlRosInitUnicodeStringFromLiteral(&KeyName,
-                                 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
   InitializeObjectAttributes(&ObjectAttributes,
                             &KeyName,
                             OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
@@ -2471,7 +2630,7 @@ SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
     }
 
   /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */
-  UlongData = ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig->AccessRanges[0].RangeStart);
+  UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart);
   DPRINT("  IOAddress = %lx\n", UlongData);
   RtlInitUnicodeString(&ValueName,
                       L"IOAddress");
@@ -2889,8 +3048,15 @@ SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
 
                  if (Srb->SrbStatus == SRB_STATUS_BUSY)
                    {
+                      CompleteThisRequest = FALSE;
+                     Irp->Tail.Overlay.DriverContext[3] = Srb;
+
                      SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
                       SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
+
+                      Srb->OriginalRequest = LunExtension;
+                      Irp->Tail.Overlay.DriverContext[2] = 0;
+
                      InsertHeadList(&DeviceExtension->PendingIrpListHead, (PLIST_ENTRY)&Irp->Tail.Overlay.DriverContext[0]);
                      DeviceExtension->PendingIrpCount++;
                      LunExtension->PendingIrpCount++;
@@ -2916,6 +3082,7 @@ SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
                                    SenseInfoBuffer,
                                    sizeof(SENSE_DATA));
                      OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+                      OriginalSrb->SrbExtension = Srb->SrbExtension;
                      ExFreePool(Srb);
                      CompleteThisRequest = TRUE;
                    }
@@ -2934,7 +3101,7 @@ SpiProcessRequests(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
                          CompleteThisRequest = FALSE;
                          Irp->Tail.Overlay.DriverContext[3] = Srb;
                          SpiRemoveActiveIrp(DeviceExtension, Irp, PrevIrp);
-                         SpiFreeSrbExtension(DeviceExtension, Srb);
+                         SpiFreeSrbExtension(DeviceExtension, OriginalSrb);
 
                           Srb->OriginalRequest = LunExtension;
                           Irp->Tail.Overlay.DriverContext[2] = 0;