class2.c

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

C
2,461
字号
  Srb->SenseInfoBuffer = (SENSE_DATA*)ROUND_UP((ULONG_PTR)(Srb + 1), SENSEINFO_ALIGNMENT);
  Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;

  Srb->DataBuffer = BufferAddress;
  Srb->DataTransferLength = BufferLength;

  Srb->ScsiStatus = 0;
  Srb->SrbStatus = 0;
  Srb->NextSrb = NULL;

  if (BufferAddress != NULL)
    {
      if (Irp->MdlAddress == NULL)
	{
	  /* Allocate an MDL */
	  if (!IoAllocateMdl(BufferAddress,
			     BufferLength,
			     FALSE,
			     FALSE,
			     Irp))
	    {
	      DPRINT("Mdl-Allocation failed\n");
	      return(STATUS_INSUFFICIENT_RESOURCES);
	    }

	  MmBuildMdlForNonPagedPool(Irp->MdlAddress);
	}

      /* Set data direction */
      Srb->SrbFlags = (WriteToDevice) ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
    }
  else
    {
      /* Set data direction */
      Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
    }

  /* Set the retry counter */
  Stack = IoGetCurrentIrpStackLocation(Irp);
  Stack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;

  /* Set the completion routine */
  IoSetCompletionRoutine(Irp,
			 ScsiClassIoComplete,
			 Srb,
			 TRUE,
			 TRUE,
			 TRUE);

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

  /* Call the port driver */
  return(IoCallDriver(DeviceExtension->PortDeviceObject,
		      Irp));
}


/*
 * @implemented
 */
NTSTATUS STDCALL
ScsiClassSendSrbSynchronous(PDEVICE_OBJECT DeviceObject,
			    PSCSI_REQUEST_BLOCK Srb,
			    PVOID BufferAddress,
			    ULONG BufferLength,
			    BOOLEAN WriteToDevice)
{
  PDEVICE_EXTENSION DeviceExtension;
  IO_STATUS_BLOCK IoStatusBlock;
  PIO_STACK_LOCATION IrpStack;
  ULONG RequestType;
  BOOLEAN Retry;
  ULONG RetryCount;
  KEVENT Event;
  PIRP Irp;
  NTSTATUS Status;
  LARGE_INTEGER RetryWait;

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

  RetryCount = MAXIMUM_RETRIES;
  DeviceExtension = DeviceObject->DeviceExtension;

  Srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  Srb->PathId = DeviceExtension->PathId;
  Srb->TargetId = DeviceExtension->TargetId;
  Srb->Lun = DeviceExtension->Lun;
  Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;

  Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  Srb->SenseInfoBuffer = ExAllocatePool(NonPagedPool,
					SENSE_BUFFER_SIZE);
  if (Srb->SenseInfoBuffer == NULL)
    return(STATUS_INSUFFICIENT_RESOURCES);

  if (BufferAddress == NULL)
    {
        BufferLength = 0;
        RequestType = IOCTL_SCSI_EXECUTE_NONE;
        Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
    }
  else
    {
      if (WriteToDevice == TRUE)
	{
	  RequestType = IOCTL_SCSI_EXECUTE_IN;	// needs _in_ to the device
	  Srb->SrbFlags = SRB_FLAGS_DATA_OUT;	// needs _out_ from the caller
	}
      else
	{
	  RequestType = IOCTL_SCSI_EXECUTE_OUT;
	  Srb->SrbFlags = SRB_FLAGS_DATA_IN;
	}
    }

  Srb->DataBuffer = BufferAddress;

TryAgain:
  Srb->DataTransferLength = BufferLength;
  KeInitializeEvent(&Event,
		    NotificationEvent,
		    FALSE);

  Irp = IoBuildDeviceIoControlRequest(RequestType,
				      DeviceExtension->PortDeviceObject,
				      NULL,
				      0,
				      BufferAddress,
				      BufferLength,
				      TRUE,
				      &Event,
				      &IoStatusBlock);
  if (Irp == NULL)
    {
      DPRINT("IoBuildDeviceIoControlRequest() failed\n");
      ExFreePool(Srb->SenseInfoBuffer);
      Srb->SenseInfoBuffer = NULL;
      Srb->SenseInfoBufferLength = 0;
      return(STATUS_INSUFFICIENT_RESOURCES);
    }

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

  /* Call the SCSI port driver */
  Status = IoCallDriver(DeviceExtension->PortDeviceObject,
			Irp);
  if (Status == STATUS_PENDING)
    {
      KeWaitForSingleObject(&Event,
			    Suspended,
			    KernelMode,
			    FALSE,
			    NULL);
    }

  if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS)
    {
      /* Release the queue if it is frozen */
      if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)
	{
	  ScsiClassReleaseQueue (DeviceObject);
	}

      /* Get more detailed status information */
      Retry = ScsiClassInterpretSenseInfo(DeviceObject,
					  Srb,
					  IRP_MJ_SCSI,
					  0,
					  MAXIMUM_RETRIES - RetryCount,
					  &Status);
      if (Retry == TRUE)
	{
	  DPRINT("Try again (RetryCount %lu)\n", RetryCount);

	  /* FIXME: Wait a little if we got a timeout error */

	  if (RetryCount--)
	    {
	      RetryWait.QuadPart = - RETRY_WAIT;
	      KeDelayExecutionThread(KernelMode, FALSE, &RetryWait);
	      goto TryAgain;
	    }
	}
    }
  else
    {
      Status = STATUS_SUCCESS;
    }

  ExFreePool(Srb->SenseInfoBuffer);

  DPRINT("ScsiClassSendSrbSynchronous() done\n");

  return(Status);
}


/*
 * @implemented
 */
VOID STDCALL
ScsiClassSplitRequest(IN PDEVICE_OBJECT DeviceObject,
		      IN PIRP Irp,
		      IN ULONG MaximumBytes)
{
  PDEVICE_EXTENSION DeviceExtension;
  PIO_STACK_LOCATION CurrentStack;
  PIO_STACK_LOCATION NextStack;
  PIO_STACK_LOCATION NewStack;
  PSCSI_REQUEST_BLOCK Srb;
  LARGE_INTEGER Offset;
  PIRP NewIrp;
  PVOID DataBuffer;
  ULONG TransferLength;
  ULONG RequestCount;
  ULONG DataLength;
  ULONG i;

  DPRINT("ScsiClassSplitRequest(DeviceObject %lx  Irp %lx  MaximumBytes %lu)\n",
	 DeviceObject, Irp, MaximumBytes);

  DeviceExtension = DeviceObject->DeviceExtension;
  CurrentStack = IoGetCurrentIrpStackLocation(Irp);
  NextStack = IoGetNextIrpStackLocation(Irp);
  DataBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);

  /* Initialize transfer data for first request */
  Offset = CurrentStack->Parameters.Read.ByteOffset;
  TransferLength = CurrentStack->Parameters.Read.Length;

  /* Set the result length */
  Irp->IoStatus.Information = TransferLength;

  DataLength = MaximumBytes;
  RequestCount = ROUND_UP(TransferLength, MaximumBytes) / MaximumBytes;

  /* Save request count in the original IRP */
  NextStack->Parameters.Others.Argument1 = (PVOID)RequestCount;

  DPRINT("RequestCount %lu\n", RequestCount);

  for (i = 0; i < RequestCount; i++)
    {
      /* Create a new IRP */
      NewIrp = IoAllocateIrp(DeviceObject->StackSize,
			     FALSE);
      if (NewIrp == NULL)
	{
	  Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
	  Irp->IoStatus.Information = 0;

	  if (i == 0)
	    IoCompleteRequest(Irp,
			      IO_NO_INCREMENT);
	  return;
	}

      /* Initialize the new IRP */
      NewIrp->MdlAddress = Irp->MdlAddress;
      NewIrp->Tail.Overlay.Thread = PsGetCurrentThread();

      IoSetNextIrpStackLocation(NewIrp);
      NewStack = IoGetCurrentIrpStackLocation(NewIrp);

      NewStack->MajorFunction = CurrentStack->MajorFunction;
      NewStack->Parameters.Read.ByteOffset = Offset;
      NewStack->Parameters.Read.Length = DataLength;
      NewStack->DeviceObject = DeviceObject;

      ScsiClassBuildRequest(DeviceObject,
			    NewIrp);

      NewStack = IoGetNextIrpStackLocation(NewIrp);
      Srb = NewStack->Parameters.Others.Argument1;
      Srb->DataBuffer = DataBuffer;

      NewIrp->AssociatedIrp.MasterIrp = Irp;

      /* Initialize completion routine */
      IoSetCompletionRoutine(NewIrp,
			     ScsiClassIoCompleteAssociated,
			     Srb,
			     TRUE,
			     TRUE,
			     TRUE);

      /* Send the new IRP down to the port driver */
      IoCallDriver(DeviceExtension->PortDeviceObject,
		   NewIrp);

      /* Adjust transfer data for next request */
      DataBuffer = (PCHAR)DataBuffer + MaximumBytes;
      TransferLength -= MaximumBytes;
      DataLength = (TransferLength > MaximumBytes) ? MaximumBytes : TransferLength;
      Offset.QuadPart = Offset.QuadPart + MaximumBytes;
    }
}


/* INTERNAL FUNCTIONS *******************************************************/

static NTSTATUS STDCALL
ScsiClassCreateClose(IN PDEVICE_OBJECT DeviceObject,
		     IN PIRP Irp)
{
  PDEVICE_EXTENSION DeviceExtension;

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

  DeviceExtension = DeviceObject->DeviceExtension;

  if (DeviceExtension->ClassCreateClose)
    return(DeviceExtension->ClassCreateClose(DeviceObject,
					     Irp));

  Irp->IoStatus.Status = STATUS_SUCCESS;
  Irp->IoStatus.Information = 0;
  IoCompleteRequest(Irp, IO_NO_INCREMENT);

  return(STATUS_SUCCESS);
}


static NTSTATUS STDCALL
ScsiClassReadWrite(IN PDEVICE_OBJECT DeviceObject,
		   IN PIRP Irp)
{
  PDEVICE_EXTENSION DeviceExtension;
  PIO_STACK_LOCATION IrpStack;
  ULONG MaximumTransferLength;
  ULONG CurrentTransferLength;
  ULONG MaximumTransferPages;
  ULONG CurrentTransferPages;
  NTSTATUS Status;

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

  DeviceExtension = DeviceObject->DeviceExtension;
  IrpStack  = IoGetCurrentIrpStackLocation(Irp);

  DPRINT("Relative Offset: %I64u  Length: %lu\n",
	 IrpStack->Parameters.Read.ByteOffset.QuadPart,
	 IrpStack->Parameters.Read.Length);

  MaximumTransferLength = DeviceExtension->PortCapabilities->MaximumTransferLength;
  MaximumTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;

  CurrentTransferLength = IrpStack->Parameters.Read.Length;

  if ((DeviceObject->Flags & DO_VERIFY_VOLUME) &&
      !(IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME))
    {
      IoSetHardErrorOrVerifyDevice(Irp,
				   DeviceObject);

      Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
      Irp->IoStatus.Information = 0;

      IoCompleteRequest(Irp,
			IO_NO_INCREMENT);
      return(STATUS_VERIFY_REQUIRED);
    }

  /* Class driver verifies the IRP */
  Status = DeviceExtension->ClassReadWriteVerification(DeviceObject,
						       Irp);
  if (!NT_SUCCESS(Status))
    {
      IoCompleteRequest(Irp,
			IO_NO_INCREMENT);
      return(Status);
    }
  else if (Status == STATUS_PENDING)
    {
      IoMarkIrpPending(Irp);
      return(STATUS_PENDING);
    }

  /* Finish a zero-byte transfer */
  if (CurrentTransferLength == 0)
    {
      Irp->IoStatus.Status = STATUS_SUCCESS;
      Irp->IoStatus.Information = 0;
      IoCompleteRequest(Irp,
			IO_NO_INCREMENT);
      return(STATUS_SUCCESS);
    }

  if (DeviceExtension->ClassStartIo != NULL)
    {
      DPRINT("ScsiClassReadWrite() starting packet\n");

      IoMarkIrpPending(Irp);
      IoStartPacket(DeviceObject,
		    Irp,
		    NULL,
		    NULL);

      return(STATUS_PENDING);
    }

  /* Adjust partition-relative starting offset to absolute offset */
  IrpStack->Parameters.Read.ByteOffset.QuadPart +=
    (DeviceExtension->StartingOffset.QuadPart + DeviceExtension->DMByteSkew);

  /* Calculate number of pages in this transfer */
  CurrentTransferPages =
    ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress),
				   IrpStack->Parameters.Read.Length);

  if (CurrentTransferLength > MaximumTransferLength ||
      CurrentTransferPages > MaximumTransferPages)
    {
       DPRINT("Split current request: MaximumTransferLength %lu  CurrentTransferLength %lu\n",
	      MaximumTransferLength, CurrentTransferLength);

      /* Adjust the maximum transfer length */
      CurrentTransferPages = DeviceExtension->PortCapabilities->MaximumPhysicalPages;

      if (MaximumTransferLength > CurrentTransferPages * PAGE_SIZE)
	  MaximumTransferLength = CurrentTransferPages * PAGE_SIZE;

      if (MaximumTransferLength == 0)
	  MaximumTransferLength = PAGE_SIZE;

      IoMarkIrpPending(Irp);

      /* Split current request */
      ScsiClassSplitRequest(DeviceObject,
			    Irp,
			    MaximumTransferLength);

      return(STATUS_PENDING);
    }

  ScsiClassBuildRequest(DeviceObject,
			Irp);

  DPRINT("ScsiClassReadWrite() done\n");

  /* Call the port driver */
  return(IoCallDriver(DeviceExtension->PortDeviceObject,
		      Irp));
}


static NTSTATUS STDCALL
ScsiClassDeviceDispatch(IN PDEVICE_OBJECT DeviceObject,
			IN PIRP Irp)
{
  PDEVICE_EXTENSION DeviceExtension;

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

  DeviceExtension = DeviceObject->DeviceExtension;
  if (DeviceExtension->ClassDeviceControl)
    {
      return(DeviceExtension->ClassDeviceControl(DeviceObject, Irp));
    }

  Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  IoCompleteRequest(Irp, IO_NO_INCREMENT);

  return(STATUS_INVALID_DEVICE_REQUEST);
}


static NTSTATUS STDCALL
ScsiClassShutdownFlush(IN PDEVICE_OBJECT DeviceObject,
		       IN PIRP Irp)
{
  PDEVICE_EXTENSION DeviceExtension;

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

  DeviceExtension = DeviceObject->DeviceExtension;
  if (DeviceExtension->ClassShutdownFlush)
    {
      return(DeviceExtension->ClassShutdownFlush(DeviceObject, Irp));
    }

  Irp->IoStatus.Status = STATUS_INVALID_DEVICE_

⌨️ 快捷键说明

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