scsiport.c

来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 2,013 行 · 第 1/5 页

C
2,013
字号
    if (!NT_SUCCESS(Status))
    {
        DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status);
        ConfigInfo->ServiceKey = NULL;
    }

    /* If we could open driver's service key, then proceed to the Parameters key */
    if (ConfigInfo->ServiceKey != NULL)
    {
        RtlInitUnicodeString(&KeyName, L"Parameters");
        InitializeObjectAttributes(&ObjectAttributes,
                                   &KeyName,
                                   OBJ_CASE_INSENSITIVE,
                                   ConfigInfo->ServiceKey,
                                   (PSECURITY_DESCRIPTOR) NULL);

        /* Try to open it */
        Status = ZwOpenKey(&ConfigInfo->DeviceKey,
                           KEY_READ,
                           &ObjectAttributes);

        if (NT_SUCCESS(Status))
        {
            /* Yes, Parameters key exist, and it must be used instead of
               the Service key */
            ZwClose(ConfigInfo->ServiceKey);
            ConfigInfo->ServiceKey = ConfigInfo->DeviceKey;
            ConfigInfo->DeviceKey = NULL;
        }
    }

    if (ConfigInfo->ServiceKey != NULL)
    {
        /* Open the Device key */
        RtlInitUnicodeString(&KeyName, L"Device");
        InitializeObjectAttributes(&ObjectAttributes,
                                   &KeyName,
                                   OBJ_CASE_INSENSITIVE,
                                   ConfigInfo->ServiceKey,
                                   NULL);

        /* We don't check for failure here - not needed */
        ZwOpenKey(&ConfigInfo->DeviceKey,
                  KEY_READ,
                  &ObjectAttributes);
    }
}


/**********************************************************************
 * NAME							EXPORTED
 *	ScsiPortInitialize
 *
 * DESCRIPTION
 *	Initializes SCSI port driver specific data.
 *
 * RUN LEVEL
 *	PASSIVE_LEVEL
 *
 * ARGUMENTS
 *	Argument1
 *		Pointer to the miniport driver's driver object.
 *
 *	Argument2
 *		Pointer to the miniport driver's registry path.
 *
 *	HwInitializationData
 *		Pointer to port driver specific configuration data.
 *
 *	HwContext
  		Miniport driver specific context.
 *
 * RETURN VALUE
 * 	Status.
 *
 * @implemented
 */

ULONG STDCALL
ScsiPortInitialize(IN PVOID Argument1,
		   IN PVOID Argument2,
		   IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
		   IN PVOID HwContext)
{
    PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
    PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
    PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL;
    PCONFIGURATION_INFORMATION SystemConfig;
    PPORT_CONFIGURATION_INFORMATION PortConfig;
    PORT_CONFIGURATION_INFORMATION InitialPortConfig;
    CONFIGURATION_INFO ConfigInfo;
    ULONG DeviceExtensionSize;
    ULONG PortConfigSize;
    BOOLEAN Again;
    BOOLEAN DeviceFound = FALSE;
    BOOLEAN FirstConfigCall = TRUE;
    ULONG Result;
    NTSTATUS Status;
    ULONG MaxBus;
    ULONG BusNumber = 0;
    PCI_SLOT_NUMBER SlotNumber;

    PDEVICE_OBJECT PortDeviceObject;
    WCHAR NameBuffer[80];
    UNICODE_STRING DeviceName;
    WCHAR DosNameBuffer[80];
    UNICODE_STRING DosDeviceName;
    PIO_SCSI_CAPABILITIES PortCapabilities;
    ULONG MappedIrq;
    KIRQL Dirql;
    KAFFINITY Affinity;

    PCM_RESOURCE_LIST ResourceList;
    BOOLEAN Conflict;


    DPRINT ("ScsiPortInitialize() called!\n");

    /* Check params for validity */
    if ((HwInitializationData->HwInitialize == NULL) ||
        (HwInitializationData->HwStartIo == NULL) ||
        (HwInitializationData->HwInterrupt == NULL) ||
        (HwInitializationData->HwFindAdapter == NULL) ||
        (HwInitializationData->HwResetBus == NULL))
    {
        return STATUS_INVALID_PARAMETER;
    }

    /* Set handlers */
    DriverObject->DriverStartIo = ScsiPortStartIo;
    DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
    DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ScsiPortDeviceControl;
    DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;

    /* Obtain configuration information */
    SystemConfig = IoGetConfigurationInformation();

    /* Zero the internal configuration info structure */
    RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO));

    /* Zero starting slot number */
    SlotNumber.u.AsULONG = 0;

    /* Allocate space for access ranges */
    if (HwInitializationData->NumberOfAccessRanges)
    {
        ConfigInfo.AccessRanges =
            ExAllocatePoolWithTag(PagedPool,
            HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT);

        /* Fail if failed */
        if (ConfigInfo.AccessRanges == NULL)
            return STATUS_INSUFFICIENT_RESOURCES;
    }

    /* Open registry keys */
    SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2);

    /* Last adapter number = not known */
    ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE;

    /* Calculate sizes of DeviceExtension and PortConfig */
    DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
        HwInitializationData->DeviceExtensionSize;

    MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1;
    DPRINT("MaxBus: %lu\n", MaxBus);

    while (TRUE)
    {
        /* Create a unicode device name */
        swprintf(NameBuffer,
                 L"\\Device\\ScsiPort%lu",
                 SystemConfig->ScsiPortCount);
        RtlInitUnicodeString(&DeviceName, NameBuffer);

        DPRINT("Creating device: %wZ\n", &DeviceName);

        /* Create the port device */
        Status = IoCreateDevice(DriverObject,
                                DeviceExtensionSize,
                                &DeviceName,
                                FILE_DEVICE_CONTROLLER,
                                0,
                                FALSE,
                                &PortDeviceObject);

        if (!NT_SUCCESS(Status))
        {
            DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
            PortDeviceObject = NULL;
            break;
        }

        DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject);

        /* Set the buffering strategy here... */
        PortDeviceObject->Flags |= DO_DIRECT_IO;
        PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */

        /* Fill Device Extension */
        DeviceExtension = PortDeviceObject->DeviceExtension;
        DeviceExtension->Length = DeviceExtensionSize;
        DeviceExtension->DeviceObject = PortDeviceObject;
        DeviceExtension->PortNumber = SystemConfig->ScsiPortCount;

        /* Driver's routines... */
        DeviceExtension->HwInitialize = HwInitializationData->HwInitialize;
        DeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
        DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
        DeviceExtension->HwResetBus = HwInitializationData->HwResetBus;
        DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;

        /* Extensions sizes */
        DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
        DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize;
        DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;

        /* Round Srb extension size to the quadword */
        DeviceExtension->SrbExtensionSize =
            ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize +
            sizeof(LONGLONG) - 1);

        /* Fill some numbers (bus count, lun count, etc) */
        DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS;
        DeviceExtension->RequestsNumber = 16;

        /* Initialize the spin lock in the controller extension */
        KeInitializeSpinLock(&DeviceExtension->IrqLock);
        KeInitializeSpinLock(&DeviceExtension->SpinLock);

        /* Initialize the DPC object */
        IoInitializeDpcRequest(PortDeviceObject,
                               ScsiPortDpcForIsr);

        /* Initialize the device timer */
        DeviceExtension->TimerCount = -1;
        IoInitializeTimer(PortDeviceObject,
                          ScsiPortIoTimer,
                          DeviceExtension);

        /* Initialize miniport timer */
        KeInitializeTimer(&DeviceExtension->MiniportTimer);
        KeInitializeDpc(&DeviceExtension->MiniportTimerDpc,
                        SpiMiniportTimerDpc,
                        PortDeviceObject);

CreatePortConfig:

        Status = SpiCreatePortConfig(DeviceExtension,
                                     HwInitializationData,
                                     &ConfigInfo,
                                     &InitialPortConfig,
                                     FirstConfigCall);

        if (!NT_SUCCESS(Status))
            break;

        /* Allocate and initialize port configuration info */
        PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) +
                          HwInitializationData->NumberOfAccessRanges *
                          sizeof(ACCESS_RANGE) + 7) & ~7;
        DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT);

        /* Fail if failed */
        if (DeviceExtension->PortConfig == NULL)
        {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        PortConfig = DeviceExtension->PortConfig;

        /* Copy information here */
        RtlCopyMemory(PortConfig,
                      &InitialPortConfig,
                      sizeof(PORT_CONFIGURATION_INFORMATION));


        /* Copy extension sizes into the PortConfig */
        PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize;
        PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize;

        /* Initialize Access ranges */
        if (HwInitializationData->NumberOfAccessRanges != 0)
        {
            PortConfig->AccessRanges = (PVOID)(PortConfig+1);

            /* Align to LONGLONG */
            PortConfig->AccessRanges = (PVOID)((ULONG)(PortConfig->AccessRanges) + 7);
            PortConfig->AccessRanges = (PVOID)((ULONG)(PortConfig->AccessRanges) & ~7);

            /* Copy the data */
            RtlCopyMemory(PortConfig->AccessRanges,
                          ConfigInfo.AccessRanges,
                          HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
        }

      /* Search for matching PCI device */
      if ((HwInitializationData->AdapterInterfaceType == PCIBus) &&
          (HwInitializationData->VendorIdLength > 0) &&
          (HwInitializationData->VendorId != NULL) &&
          (HwInitializationData->DeviceIdLength > 0) &&
          (HwInitializationData->DeviceId != NULL))
      {
          PortConfig->BusInterruptLevel = 0;

          /* Get PCI device data */
          DPRINT("VendorId '%.*s'  DeviceId '%.*s'\n",
                 HwInitializationData->VendorIdLength,
                 HwInitializationData->VendorId,
                 HwInitializationData->DeviceIdLength,
                 HwInitializationData->DeviceId);

          if (!SpiGetPciConfigData(DriverObject,
                                   PortDeviceObject,
                                   HwInitializationData,
                                   PortConfig,
                                   RegistryPath,
                                   ConfigInfo.BusNumber,
                                   &SlotNumber))
          {
              /* Continue to the next bus, nothing here */
              ConfigInfo.BusNumber++;
              DeviceExtension->PortConfig = NULL;
              ExFreePool(PortConfig);
              Again = FALSE;
              goto CreatePortConfig;
          }

          if (!PortConfig->BusInterruptLevel)
          {
              /* Bypass this slot, because no interrupt was assigned */
              DeviceExtension->PortConfig = NULL;
              ExFreePool(PortConfig);
              goto CreatePortConfig;
          }
      }
      else
      {
          DPRINT("Non-pci bus\n");
      }

      /* Note: HwFindAdapter is called once for each bus */
      Again = FALSE;
      DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
      Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension,
                                                     HwContext,
                                                     0,  /* BusInformation */
                                                     ConfigInfo.Parameter, /* ArgumentString */
                                                     PortConfig,
                                                     &Again);

      DPRINT("HwFindAdapter() Result: %lu  Again: %s\n",
             Result, (Again) ? "True" : "False");

      /* Free MapRegisterBase, it's not needed anymore */
      if (DeviceExtension->MapRegisterBase != NULL)
      {
          ExFreePool(DeviceExtension->MapRegisterBase);
          DeviceExtension->MapRegisterBase = NULL;
      }

      /* If result is nothing good... */
      if (Result != SP_RETURN_FOUND)
      {
          DPRINT("HwFindAdapter() Result: %lu\n", Result);

          if (Result == SP_RETURN_NOT_FOUND)
          {
              /* We can continue on the next bus */
              ConfigInfo.BusNumber++;
              Again = FALSE;

              DeviceExtension->PortConfig = NULL;
              ExFreePool(PortConfig);
              goto CreatePortConfig;
          }

          /* Otherwise, break */
          Status = STATUS_INTERNAL_ERROR;
          break;
      }

      DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n",
          PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]);

      /* If the SRB extension size was updated */
      if (!DeviceExtension->NonCachedExtension &&
          (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize))
      {
          /* Set it (rounding to LONGLONG again) */
          DeviceExtension->SrbExtensionSize =
              (PortConfig->SrbExtensionSize +
               sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1);
      }

      /* The same with LUN extension size */
      if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize)
          DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?