⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsiport.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:

      if (!((HwInitializationData->AdapterInterfaceType == PCIBus) &&
          (HwInitializationData->VendorIdLength > 0) &&
          (HwInitializationData->VendorId != NULL) &&
          (HwInitializationData->DeviceIdLength > 0) &&
          (HwInitializationData->DeviceId != NULL)))
      {
          /* Construct a resource list */
          ResourceList = SpiConfigToResource(DeviceExtension,
                                             PortConfig);

          if (ResourceList)
          {
              UNICODE_STRING UnicodeString;
              RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter");
              DPRINT("Reporting resources\n");
              Status = IoReportResourceUsage(&UnicodeString,
                                             DriverObject,
                                             NULL,
                                             0,
                                             PortDeviceObject,
                                             ResourceList,
                                             FIELD_OFFSET(CM_RESOURCE_LIST,
                                                 List[0].PartialResourceList.PartialDescriptors) +
                                                 ResourceList->List[0].PartialResourceList.Count
                                                 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
                                             FALSE,
                                             &Conflict);
              ExFreePool(ResourceList);

              /* In case of a failure or a conflict, break */
              if (Conflict || (!NT_SUCCESS(Status)))
              {
                  if (Conflict)
                      Status = STATUS_CONFLICTING_ADDRESSES;
                  break;
              }
            }
      }

      /* Reset the Conflict var */
      Conflict = FALSE;

      /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */
      if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS)
          DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
      else
          DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets;

      DeviceExtension->BusNum = PortConfig->NumberOfBuses;
      DeviceExtension->CachesData = PortConfig->CachesData;
      DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent;
      DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing;
      DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu;

      /* If something was disabled via registry - apply it */
      if (ConfigInfo.DisableMultipleLun)
          DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE;

      if (ConfigInfo.DisableTaggedQueueing)
          DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE;

      /* Check if we need to alloc SRB data */
      if (DeviceExtension->SupportsTaggedQueuing ||
          DeviceExtension->MultipleReqsPerLun)
      {
          DeviceExtension->NeedSrbDataAlloc = TRUE;
      }
      else
      {
          DeviceExtension->NeedSrbDataAlloc = FALSE;
      }

      /* Get a pointer to the port capabilities */
      PortCapabilities = &DeviceExtension->PortCapabilities;

      /* Copy one field there */
      DeviceExtension->MapBuffers = PortConfig->MapBuffers;
      PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers;

      if (DeviceExtension->AdapterObject == NULL &&
          (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master))
      {
          DPRINT1("DMA is not supported yet\n");
          ASSERT(FALSE);
      }

      if (DeviceExtension->SrbExtensionBuffer == NULL &&
          (DeviceExtension->SrbExtensionSize != 0  ||
          PortConfig->AutoRequestSense))
      {
          DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense;
          DeviceExtension->NeedSrbExtensionAlloc = TRUE;

          /* Allocate common buffer */
          Status = SpiAllocateCommonBuffer(DeviceExtension, 0);

          /* Check for failure */
          if (!NT_SUCCESS(Status))
              break;
      }

      /* Allocate SrbData, if needed */
      if (DeviceExtension->NeedSrbDataAlloc)
      {
          ULONG Count;
          PSCSI_REQUEST_BLOCK_INFO SrbData;

          if (DeviceExtension->SrbDataCount != 0)
              Count = DeviceExtension->SrbDataCount;
          else
              Count = DeviceExtension->RequestsNumber * 2;

          /* Allocate the data */
          SrbData = ExAllocatePoolWithTag(NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT);
          if (SrbData == NULL)
              return STATUS_INSUFFICIENT_RESOURCES;

          RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO));

          DeviceExtension->SrbInfo = SrbData;
          DeviceExtension->FreeSrbInfo = SrbData;
          DeviceExtension->SrbDataCount = Count;

          /* Link it to the list */
          while (Count > 0)
          {
              SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1);
              SrbData++;
              Count--;
          }

          /* Mark the last entry of the list */
          SrbData--;
          SrbData->Requests.Flink = NULL;
      }

      /* Initialize port capabilities */
      PortCapabilities = &DeviceExtension->PortCapabilities;
      PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
      PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength;

      if (PortConfig->ReceiveEvent)
          PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION;

      PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing;
      PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown;

      if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement)
          PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask;

      PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement;

      if (PortCapabilities->MaximumPhysicalPages == 0)
      {
          PortCapabilities->MaximumPhysicalPages =
              BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength);

          /* Apply miniport's limits */
          if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages)
          {
              PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks;
          }
      }

      /* Deal with interrupts */
      if (DeviceExtension->HwInterrupt == NULL ||
          (PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0))
      {
          /* No interrupts */
          KeInitializeSpinLock(&DeviceExtension->IrqLock);

          /* FIXME: Use synchronization routine */
          ASSERT("No interrupts branch requires changes in synchronization\n");

          DeviceExtension->Interrupt = (PVOID)DeviceExtension;
          DPRINT("No interrupts\n");

      }
      else
      {
          /* Are 2 interrupts needed? */
          if (DeviceExtension->HwInterrupt != NULL &&
              (PortConfig->BusInterruptLevel != 0 || PortConfig->BusInterruptVector != 0) &&
              (PortConfig->BusInterruptLevel2 != 0 || PortConfig->BusInterruptVector2 != 0))
          {
              DPRINT1("2 interrupts requested! Not yet supported\n");
              ASSERT(FALSE);
          }
          else
          {
              BOOLEAN InterruptShareable;

              /* No, only 1 interrupt */
              DPRINT("1 interrupt, IRQ is %d\n", PortConfig->BusInterruptLevel);

              DeviceExtension->InterruptLevel = PortConfig->BusInterruptLevel;

              /* Register an interrupt handler for this device */
              MappedIrq = HalGetInterruptVector(PortConfig->AdapterInterfaceType,
                                                PortConfig->SystemIoBusNumber,
                                                PortConfig->BusInterruptLevel,
                                                PortConfig->BusInterruptVector,
                                                &Dirql,
                                                &Affinity);

              /* Determing IRQ sharability as usual */
              if (PortConfig->AdapterInterfaceType == MicroChannel ||
                  PortConfig->InterruptMode == LevelSensitive)
              {
                  InterruptShareable = TRUE;
              }
              else
              {
                  InterruptShareable = FALSE;
              }

              Status = IoConnectInterrupt(&DeviceExtension->Interrupt,
                                          (PKSERVICE_ROUTINE)ScsiPortIsr,
                                          DeviceExtension,
                                          NULL,
                                          MappedIrq,
                                          Dirql,
                                          Dirql,
                                          PortConfig->InterruptMode,
                                          InterruptShareable,
                                          Affinity,
                                          FALSE);

              if (!(NT_SUCCESS(Status)))
              {
                  DPRINT1("Could not connect interrupt %d\n",
                      PortConfig->BusInterruptVector);
                  DeviceExtension->Interrupt = NULL;
                  break;
              }

          }
      }

      /* Save IoAddress (from access ranges) */
      if (HwInitializationData->NumberOfAccessRanges != 0)
      {
          DeviceExtension->IoAddress =
              ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart;

          DPRINT("Io Address %x\n", DeviceExtension->IoAddress);
      }

      /* Set flag that it's allowed to disconnect during this command */
      DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED;

      /* Initialize counter of active requests (-1 means there are none) */
      DeviceExtension->ActiveRequestCounter = -1;

      /* Analyze what we have about DMA */
      if (DeviceExtension->AdapterObject != NULL &&
          PortConfig->Master &&
          PortConfig->NeedPhysicalAddresses)
      {
          DeviceExtension->MapRegisters = TRUE;
      }
      else
      {
          DeviceExtension->MapRegisters = FALSE;
      }

      /* Call HwInitialize at DISPATCH_LEVEL */
      KeRaiseIrql(DISPATCH_LEVEL, &Dirql);

      if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
                                  DeviceExtension->HwInitialize,
                                  DeviceExtension->MiniPortDeviceExtension))
      {
          DPRINT1("HwInitialize() failed!\n");
          KeLowerIrql(Dirql);
          Status = STATUS_ADAPTER_HARDWARE_ERROR;
          break;
      }

      /* Check if a notification is needed */
      if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)
      {
          /* Call DPC right away, because we're already at DISPATCH_LEVEL */
          ScsiPortDpcForIsr(NULL,
                            DeviceExtension->DeviceObject,
                            NULL,
                            NULL);
      }

      /* Lower irql back to what it was */
      KeLowerIrql(Dirql);

      /* Start our timer */
      IoStartTimer(PortDeviceObject);

      /* Initialize bus scanning information */
      DeviceExtension->BusesConfig = ExAllocatePoolWithTag(PagedPool,
          sizeof(PSCSI_BUS_SCAN_INFO) * DeviceExtension->PortConfig->NumberOfBuses
          + sizeof(ULONG), TAG_SCSIPORT);

      if (!DeviceExtension->BusesConfig)
      {
          DPRINT1("Out of resources!\n");
          Status = STATUS_INSUFFICIENT_RESOURCES;
          break;
      }

      /* Zero it */
      RtlZeroMemory(DeviceExtension->BusesConfig,
          sizeof(PSCSI_BUS_SCAN_INFO) * DeviceExtension->PortConfig->NumberOfBuses
          + sizeof(ULONG));

      /* Store number of buses there */
      DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum;

      /* Scan the adapter for devices */
      SpiScanAdapter(DeviceExtension);

      /* Build the registry device map */
      SpiBuildDeviceMap(DeviceExtension,
                       (PUNICODE_STRING)Argument2);

      /* Create the dos device link */
      swprintf(DosNameBuffer,
               L"\\??\\Scsi%lu:",
              SystemConfig->ScsiPortCount);
      RtlInitUnicodeString(&DosDeviceName, DosNameBuffer);
      IoCreateSymbolicLink(&DosDeviceName, &DeviceName);

      /* Increase the port count */
      SystemConfig->ScsiPortCount++;
      FirstConfigCall = FALSE;

      /* Increase adapter number and bus number respectively */
      ConfigInfo.AdapterNumber++;

      if (!Again)
          ConfigInfo.BusNumber++;

      DPRINT("Bus: %lu  MaxBus: %lu\n", BusNumber, MaxBus);

      DeviceFound = TRUE;
    }

    /* Clean up the mess */
    SpiCleanupAfterInit(DeviceExtension);

    /* Close registry keys */
    if (ConfigInfo.ServiceKey != NULL)
        ZwClose(ConfigInfo.ServiceKey);

    if (ConfigInfo.DeviceKey != NULL)
        ZwClose(ConfigInfo.DeviceKey);

    if (ConfigInfo.BusKey != NULL)
        ZwClose(ConfigInfo.BusKey);

    if (ConfigInfo.AccessRanges != NULL)
        ExFreePool(ConfigInfo.AccessRanges);

    if (ConfigInfo.Parameter != NULL)
        ExFreePool(ConfigInfo.Parameter);

    DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n",
        Status, DeviceFound);

    return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS;
}

static VOID
SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
{
    PSCSI_LUN_INFO LunInfo;
    PVOID Ptr;
    ULONG Bus, Lun;

    /* Check if we have something to clean up */
    if (DeviceExtension == NULL)
        return;

    /* Stop the timer and disconnect the interrupt */
    if (DeviceExtension->Interrupt)
    {
        IoStopTimer(DeviceExtension->DeviceObject);
        IoDisconnectInterrupt(DeviceExtension->Interrupt);
    }

    /* Delete ConfigInfo */
    if (DeviceExtension->BusesConfig)
    {
        for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++)
        {
            if (!DeviceExtension->BusesConfig->BusScanInfo[Bus])
                continue;

            LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo;

            while (!LunInfo)
            {
                /* Free current, but save pointer to the next one */
                Ptr = LunInfo->Next;
                ExFreePool(LunInfo);

⌨️ 快捷键说明

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