scsiport.c

来自「一个类似windows」· C语言 代码 · 共 2,184 行 · 第 1/5 页

C
2,184
字号
	  *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
	    DeviceExtension->PortCapabilities;

	  Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
	}
	break;

      case IOCTL_SCSI_GET_INQUIRY_DATA:
	{
	  DPRINT("  IOCTL_SCSI_GET_INQUIRY_DATA\n");

	  /* Copy inquiry data to the port device extension */
	  Irp->IoStatus.Information =
	    SpiGetInquiryData(DeviceExtension,
			      Irp->AssociatedIrp.SystemBuffer);
	  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:
        DPRINT("  IOCTL_SCSI_MINIPORT\n");
        DPRINT("  Signature: %.8s\n", ((PSRB_IO_CONTROL)Irp->AssociatedIrp.SystemBuffer)->Signature);
        DPRINT("  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;
}

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))
    {
      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
SpiAllocateSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
			PSCSI_REQUEST_BLOCK Srb)
{
  ULONG index;

  DPRINT("SpiAllocateSrbExtension\n");

  DPRINT("DeviceExtension->VirtualAddress %x, DeviceExtension->SrbExtensionSize %x\n",
         DeviceExtension->VirtualAddress, DeviceExtension->SrbExtensionSize);

  Srb->SrbExtension = NULL;
  if (DeviceExtension->VirtualAddress != NULL &&
      DeviceExtension->SrbExtensionSize > 0)
    {
      index = RtlFindClearBitsAndSet(&DeviceExtension->SrbExtensionAllocMap, 1, 0);
      if (index != 0xffffffff)
        {
	  DeviceExtension->CurrentSrbExtensions++;
          Srb->SrbExtension = (PVOID)((ULONG_PTR)DeviceExtension->VirtualAddress + index * DeviceExtension->SrbExtensionSize);
	}
    }
  DPRINT("%x\n", Srb->SrbExtension);
}

static VOID
SpiFreeSrbExtension(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
		    PSCSI_REQUEST_BLOCK Srb)
{
  ULONG index;

  if (DeviceExtension->VirtualAddress != NULL &&
      DeviceExtension->SrbExtensionSize > 0 &&
      Srb->SrbExtension != NULL)
    {
      index = ((ULONG_PTR)Srb->SrbExtension - (ULONG_PTR)DeviceExtension->VirtualAddress) / DeviceExtension->SrbExtensionSize;
      RtlClearBits(&DeviceExtension->SrbExtensionAllocMap, index, 1);
      DeviceExtension->CurrentSrbExtensions--;
    }
  Srb->SrbExtension = NULL;
}


static BOOLEAN STDCALL
ScsiPortStartPacket(IN OUT PVOID Context)
{
  PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
  PSCSI_REQUEST_BLOCK Srb;
  PIRP Irp;
  PIO_STACK_LOCATION IrpStack;

  DPRINT("ScsiPortStartPacket(Context %x) called\n", Context);

  Srb = (PSCSI_REQUEST_BLOCK)Context;
  Irp = (PIRP)Srb->OriginalRequest;
  IrpStack = IoGetCurrentIrpStackLocation(Irp);
  DeviceExtension = IrpStack->DeviceObject->DeviceExtension;

  return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
				    Srb));
}


static PSCSI_PORT_LUN_EXTENSION
SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
			 IN UCHAR PathId,
			 IN UCHAR TargetId,
			 IN UCHAR Lun)
{
  PSCSI_PORT_LUN_EXTENSION LunExtension;
  ULONG LunExtensionSize;

  DPRINT("SpiAllocateLunExtension (%p %u %u %u)\n",
	 DeviceExtension, PathId, TargetId, Lun);

  LunExtensionSize =
    sizeof(SCSI_PORT_LUN_EXTENSION) + DeviceExtension->LunExtensionSize;
  DPRINT("LunExtensionSize %lu\n", LunExtensionSize);

  LunExtension = ExAllocatePool(NonPagedPool,
				LunExtensionSize);
  if (LunExtension == NULL)
    {
      return NULL;
    }

  RtlZeroMemory(LunExtension,
		LunExtensionSize);

  InsertTailList(&DeviceExtension->LunExtensionListHead,
		 &LunExtension->List);

  LunExtension->PathId = PathId;
  LunExtension->TargetId = TargetId;
  LunExtension->Lun = Lun;

  LunExtension->PendingIrpCount = 0;
  LunExtension->ActiveIrpCount = 0;

  LunExtension->NextIrp = NULL;

  return LunExtension;
}


static VOID
SpiRemoveLunExtension (IN PSCSI_PORT_LUN_EXTENSION LunExtension)
{
  DPRINT("SpiRemoveLunExtension(%p) called\n",
	 LunExtension);

  if (LunExtension == NULL)
    return;

  RemoveEntryList (&LunExtension->List);


  /* Release LUN extersion data */


  ExFreePool (LunExtension);

  return;
}


static PSCSI_PORT_LUN_EXTENSION
SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
		    IN UCHAR PathId,
		    IN UCHAR TargetId,
		    IN UCHAR Lun)
{
  PSCSI_PORT_LUN_EXTENSION LunExtension;
  PLIST_ENTRY Entry;

  DPRINT("SpiGetLunExtension(%p %u %u %u) called\n",
	 DeviceExtension, PathId, TargetId, Lun);

  if (IsListEmpty(&DeviceExtension->LunExtensionListHead))
    return NULL;

  Entry = DeviceExtension->LunExtensionListHead.Flink;
  while (Entry != &DeviceExtension->LunExtensionListHead)
    {
      LunExtension = CONTAINING_RECORD(Entry,
				       SCSI_PORT_LUN_EXTENSION,
				       List);
      if (LunExtension->PathId == PathId &&
	  LunExtension->TargetId == TargetId &&
	  LunExtension->Lun == Lun)
	{
	  return LunExtension;
	}

      Entry = Entry->Flink;
    }

  return NULL;
}


static NTSTATUS
SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject,
		IN OUT PSCSI_REQUEST_BLOCK Srb,
		IN OUT PIO_STATUS_BLOCK IoStatusBlock,
		IN OUT PKEVENT Event)
{
  PIO_STACK_LOCATION IrpStack;
  PIRP Irp;
  NTSTATUS Status;

  DPRINT ("SpiSendInquiry() called\n");


  KeInitializeEvent (Event,
		     NotificationEvent,
		     FALSE);

  Irp = IoBuildDeviceIoControlRequest (IOCTL_SCSI_EXECUTE_OUT,
				       DeviceObject,
				       NULL,
				       0,
				       Srb->DataBuffer,
				       Srb->DataTransferLength,
				       TRUE,
				       Event,
				       IoStatusBlock);
  if (Irp == NULL)
    {
      DPRINT("IoBuildDeviceIoControlRequest() failed\n");
      return STATUS_INSUFFICIENT_RESOURCES;
    }

  /* Attach Srb to the Irp */
  IrpStack = IoGetNextIrpStackLocation (Irp);
  IrpStack->Parameters.Scsi.Srb = Srb;
  Srb->OriginalRequest = Irp;

  /* Call the driver */
  Status = IoCallDriver (DeviceObject,
			 Irp);

  return Status;
}

static VOID
SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
{
  PSCSI_REQUEST_BLOCK Srb;
  PCDB Cdb;
  ULONG Bus;
  ULONG Target;
  PSCSI_PORT_SCAN_ADAPTER ScanDataArray;
  PSCSI_PORT_SCAN_ADAPTER ScanData;
  ULONG i;
  ULONG MaxCount;
  ULONG WaitCount;
  ULONG ActiveCount;
  PVOID* EventArray;
  PKWAIT_BLOCK WaitBlockArray;

  DPRINT ("SpiScanAdapter() called\n");

  MaxCount = DeviceExtension->PortConfig->NumberOfBuses *
               DeviceExtension->PortConfig->MaximumNumberOfTargets;

  ScanDataArray = ExAllocatePool(NonPagedPool, MaxCount * (sizeof(SCSI_PORT_SCAN_ADAPTER) + sizeof(PVOID) + sizeof(KWAIT_BLOCK)));
  if (ScanDataArray == NULL)
    {
      return;
    }
  EventArray = (PVOID*)((PUCHAR)ScanDataArray + MaxCount * sizeof(SCSI_PORT_SCAN_ADAPTER));
  WaitBlockArray = (PKWAIT_BLOCK)((PUCHAR)EventArray + MaxCount * sizeof(PVOID));

  for (Bus = 0; Bus < DeviceExtension->PortConfig->NumberOfBuses; Bus++)
    {
      for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++)
	{
	  ScanData = &ScanDataArray[Bus * DeviceExtension->PortConfig->MaximumNumberOfTargets + Target];
	  ScanData->Bus = Bus;
	  ScanData->Target = Target;
	  ScanData->Lun = 0;
	  ScanData->Active = FALSE;
	}
    }
  do
    {
      ActiveCount = 0;
      WaitCount = 0;
      for (i = 0; i < MaxCount; i++)
        {
          ScanData = &ScanDataArray[i];
	  Srb = &ScanData->Srb;
          if (ScanData->Active)
       

⌨️ 快捷键说明

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