class2.c

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

C
2,461
字号
 * RUN LEVEL
 *	PASSIVE_LEVEL
 *
 * ARGUMENTS
 *	DeviceExtension
 *		Class specific device extension.
 *
 *	NumberElements
 *		Maximum number of elements of the lookaside list.
 *
 * RETURN VALUE
 *	None.
 *
 * @implemented
 */
VOID STDCALL
ScsiClassInitializeSrbLookasideList(IN PDEVICE_EXTENSION DeviceExtension,
				    IN ULONG NumberElements)
{
  ExInitializeNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
				  NULL,
				  NULL,
				  NonPagedPool,
				  sizeof(SCSI_REQUEST_BLOCK) + sizeof(SENSE_DATA) + SENSEINFO_ALIGNMENT - 1,
				  TAG_SRBT,
				  (USHORT)NumberElements);
}


/*
 * @unimplemented
 */
NTSTATUS STDCALL
ScsiClassInternalIoControl(IN PDEVICE_OBJECT DeviceObject,
			   IN PIRP Irp)
{
  DPRINT("ScsiClassInternalIoContol() called\n");

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

  return(STATUS_SUCCESS);
}


/*
 * Implements part of the directives on:
 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/kmarch/hh/kmarch/other_c694d732-fa95-4841-8d61-2a55ee787905.xml.asp
 */
static VOID
ScsiClassInvalidateMedia(IN PDEVICE_OBJECT DeviceObject,
			 OUT NTSTATUS *Status)
{
  PDEVICE_EXTENSION DeviceExtension;
  PDEVICE_EXTENSION PhysicalExtension;

  DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;

  if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
    {
      DPRINT("Invalidate: test char yields TRUE\n");
    }
  else
    {
      DPRINT("Invalidate: test char yields FALSE\n");
    }

  if ((DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) &&
      (DeviceObject->Vpb->Flags & VPB_MOUNTED))
    {
      DPRINT("Set DO_VERIFY_VOLUME\n");
      DeviceObject->Flags |= DO_VERIFY_VOLUME;
      *Status = STATUS_VERIFY_REQUIRED;
    }
  else
    {
      *Status = STATUS_IO_DEVICE_ERROR;
    }

  /* Increment the media change count */
  PhysicalExtension->MediaChangeCount++;
}


/*
 * @implemented
 */
BOOLEAN STDCALL
ScsiClassInterpretSenseInfo(IN PDEVICE_OBJECT DeviceObject,
			    IN PSCSI_REQUEST_BLOCK Srb,
			    IN UCHAR MajorFunctionCode,
			    IN ULONG IoDeviceCode,
			    IN ULONG RetryCount,
			    OUT NTSTATUS *Status)
{
  PDEVICE_EXTENSION DeviceExtension;
  PDEVICE_EXTENSION PhysicalExtension;
#if 0
  PIO_ERROR_LOG_PACKET LogPacket;
#endif
  PSENSE_DATA SenseData;
  BOOLEAN LogError;
  BOOLEAN Retry;

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

  DPRINT("Srb->SrbStatus %lx\n", Srb->SrbStatus);

  if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_PENDING)
    {
      *Status = STATUS_SUCCESS;
      return(FALSE);
    }

  DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  PhysicalExtension = (PDEVICE_EXTENSION)DeviceExtension->PhysicalDevice->DeviceExtension;
  SenseData = Srb->SenseInfoBuffer;
  LogError = FALSE;
  Retry = TRUE;

  if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
      (Srb->SenseInfoBufferLength > 0))
    {
      /* Got valid sense data, interpret them */

      DPRINT("ErrorCode: %x\n", SenseData->ErrorCode);
      DPRINT("SenseKey: %x\n", SenseData->SenseKey);
      DPRINT("SenseCode: %x\n", SenseData->AdditionalSenseCode);

      switch (SenseData->SenseKey & 0xf)
	{
	  case SCSI_SENSE_NO_SENSE:
	    DPRINT("SCSI_SENSE_NO_SENSE\n");
	    if (SenseData->IncorrectLength)
	      {
		DPRINT("Incorrect block length\n");
		*Status = STATUS_INVALID_BLOCK_LENGTH;
		Retry = FALSE;
	      }
	    else
	      {
		DPRINT("Unspecified error\n");
		*Status = STATUS_IO_DEVICE_ERROR;
		Retry = FALSE;
	      }
	    break;

	  case SCSI_SENSE_RECOVERED_ERROR:
	    DPRINT("SCSI_SENSE_RECOVERED_ERROR\n");
	    *Status = STATUS_SUCCESS;
	    Retry = FALSE;
	    break;

	  case SCSI_SENSE_NOT_READY:
	    DPRINT("SCSI_SENSE_NOT_READY\n");
	    *Status = STATUS_DEVICE_NOT_READY;
	    switch (SenseData->AdditionalSenseCode)
	      {
		case SCSI_ADSENSE_LUN_NOT_READY:
		  DPRINT("SCSI_ADSENSE_LUN_NOT_READY\n");
		  break;

		case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
		  DPRINT("SCSI_ADSENSE_NO_MEDIA_IN_DEVICE\n");
		  ScsiClassInvalidateMedia(DeviceObject,
					   Status);

		  *Status = STATUS_NO_MEDIA_IN_DEVICE;
		  Retry = FALSE;

		  if((DeviceExtension->MediaChangeEvent != NULL) &&
		    (!DeviceExtension->MediaChangeEvent))
		    {
		    KeSetEvent(DeviceExtension->MediaChangeEvent,
		    	       0,
		    	       FALSE);
		    DeviceExtension->MediaChangeNoMedia = TRUE;
		    }
		  break;
	      }
	    break;

	  case SCSI_SENSE_MEDIUM_ERROR:
	    DPRINT("SCSI_SENSE_MEDIUM_ERROR\n");
	    *Status = STATUS_DEVICE_DATA_ERROR;
	    Retry = FALSE;
	    break;

	  case SCSI_SENSE_HARDWARE_ERROR:
	    DPRINT("SCSI_SENSE_HARDWARE_ERROR\n");
	    *Status = STATUS_IO_DEVICE_ERROR;
	    break;

	  case SCSI_SENSE_ILLEGAL_REQUEST:
	    DPRINT("SCSI_SENSE_ILLEGAL_REQUEST\n");
	    *Status = STATUS_INVALID_DEVICE_REQUEST;
	    switch (SenseData->AdditionalSenseCode)
	      {
		case SCSI_ADSENSE_ILLEGAL_COMMAND:
		  DPRINT("SCSI_ADSENSE_ILLEGAL_COMMAND\n");
		  Retry = FALSE;
		  break;

		case SCSI_ADSENSE_ILLEGAL_BLOCK:
		  DPRINT("SCSI_ADSENSE_ILLEGAL_BLOCK\n");
		  *Status = STATUS_NONEXISTENT_SECTOR;
		  Retry = FALSE;
		  break;

		case SCSI_ADSENSE_INVALID_LUN:
		  DPRINT("SCSI_ADSENSE_INVALID_LUN\n");
		  *Status = STATUS_NO_SUCH_DEVICE;
		  Retry = FALSE;
		  break;

		case SCSI_ADSENSE_MUSIC_AREA:
		  DPRINT("SCSI_ADSENSE_MUSIC_AREA\n");
		  Retry = FALSE;
		  break;

		case SCSI_ADSENSE_DATA_AREA:
		  DPRINT("SCSI_ADSENSE_DATA_AREA\n");
		  Retry = FALSE;
		  break;

		case SCSI_ADSENSE_VOLUME_OVERFLOW:
		  DPRINT("SCSI_ADSENSE_VOLUME_OVERFLOW\n");
		  Retry = FALSE;
		  break;

		case SCSI_ADSENSE_INVALID_CDB:
		  DPRINT("SCSI_ADSENSE_INVALID_CDB\n");
		  Retry = FALSE;
		  break;
	      }
	    break;

	  case SCSI_SENSE_UNIT_ATTENTION:
	    DPRINT("SCSI_SENSE_UNIT_ATTENTION\n");
	    switch (SenseData->AdditionalSenseCode)
	      {
		case SCSI_ADSENSE_MEDIUM_CHANGED:
		  DPRINT("SCSI_ADSENSE_MEDIUM_CHANGED\n");
                  if(DeviceExtension->MediaChangeEvent != NULL)
                    {
                    KeSetEvent(DeviceExtension->MediaChangeEvent,
                               0,
                               FALSE);
                    DeviceExtension->MediaChangeNoMedia = FALSE;
                    }
		  break;

		case SCSI_ADSENSE_BUS_RESET:
		  DPRINT("SCSI_ADSENSE_BUS_RESET\n");
		  break;

		default:
		  DPRINT("Unit attention\n");
		  break;
	      }

	    ScsiClassInvalidateMedia(DeviceObject,
				     Status);
	    Retry = FALSE;
	    break;

	  case SCSI_SENSE_DATA_PROTECT:
	    DPRINT("SCSI_SENSE_DATA_PROTECT\n");
	    *Status = STATUS_MEDIA_WRITE_PROTECTED;
	    Retry = FALSE;
	    break;

	  case SCSI_SENSE_ABORTED_COMMAND:
	    DPRINT("SCSI_SENSE_ABORTED_COMMAND\n");
	    *Status = STATUS_IO_DEVICE_ERROR;
	    break;

	  default:
	    DPRINT("SCSI error (sense key: %x)\n",
		    SenseData->SenseKey & 0xf);
	    *Status = STATUS_IO_DEVICE_ERROR;
	    break;
	}
    }
  else
    {
      /* Got no or invalid sense data, return generic error codes */
      switch (SRB_STATUS(Srb->SrbStatus))
	{
	  /* FIXME: add more srb status codes */

	  case SRB_STATUS_INVALID_PATH_ID:
	  case SRB_STATUS_INVALID_TARGET_ID:
	  case SRB_STATUS_INVALID_LUN:
	  case SRB_STATUS_NO_DEVICE:
	  case SRB_STATUS_NO_HBA:
	    *Status = STATUS_NO_SUCH_DEVICE;
	    Retry = FALSE;
	    break;

	  case SRB_STATUS_BUSY:
	    *Status = STATUS_DEVICE_BUSY;
	    Retry = TRUE;
	    break;

	  case SRB_STATUS_DATA_OVERRUN:
	    *Status = STATUS_DATA_OVERRUN;
	    Retry = FALSE;
	    break;

	  case SRB_STATUS_INVALID_REQUEST:
	    *Status = STATUS_INVALID_DEVICE_REQUEST;
	    Retry = FALSE;
	    break;

	  default:
	    DPRINT("SCSI error (SRB status: %x)\n",
		    SRB_STATUS(Srb->SrbStatus));
	    LogError = TRUE;
	    *Status = STATUS_IO_DEVICE_ERROR;
	    break;
	}
    }

  /* Call the class driver specific error function */
  if (DeviceExtension->ClassError != NULL)
    {
      DeviceExtension->ClassError(DeviceObject,
				  Srb,
				  Status,
				  &Retry);
    }

  if (LogError == TRUE)
    {
#if 0
      /* Allocate error packet */
      LogPacket = IoAllocateErrorLogEntry (DeviceObject,
					   sizeof(IO_ERROR_LOG_PACKET) +
					     5 * sizeof(ULONG));
      if (LogPacket == NULL)
	{
	  DPRINT ("Failed to allocate a log packet!\n");
	  return Retry;
	}

      /* Initialize error packet */
      LogPacket->MajorFunctionCode = MajorFunctionCode;
      LogPacket->RetryCount = (UCHAR)RetryCount;
      LogPacket->DumpDataSize = 6 * sizeof(ULONG);
      LogPacket->ErrorCode = 0; /* FIXME */
      LogPacket->FinalStatus = *Status;
      LogPacket->IoControlCode = IoDeviceCode;
      LogPacket->DeviceOffset.QuadPart = 0; /* FIXME */
      LogPacket->DumpData[0] = Srb->PathId;
      LogPacket->DumpData[1] = Srb->TargetId;
      LogPacket->DumpData[2] = Srb->Lun;
      LogPacket->DumpData[3] = 0;
      LogPacket->DumpData[4] = (Srb->SrbStatus << 8) | Srb->ScsiStatus;
      if (SenseData != NULL)
	{
	  LogPacket->DumpData[5] = (SenseData->SenseKey << 16) |
				   (SenseData->AdditionalSenseCode << 8) |
				   SenseData->AdditionalSenseCodeQualifier;
	}

      /* Write error packet */
      IoWriteErrorLogEntry (LogPacket);
#endif
    }

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

  return Retry;
}


/*
 * @implemented
 */
NTSTATUS STDCALL
ScsiClassIoComplete(IN PDEVICE_OBJECT DeviceObject,
		    IN PIRP Irp,
		    IN PVOID Context)
{
  PDEVICE_EXTENSION DeviceExtension;
  PIO_STACK_LOCATION IrpStack;
  PSCSI_REQUEST_BLOCK Srb;
  BOOLEAN Retry;
  NTSTATUS Status;

  DPRINT("ScsiClassIoComplete(DeviceObject %p  Irp %p  Context %p) called\n",
	  DeviceObject, Irp, Context);

  DeviceExtension = DeviceObject->DeviceExtension;

  IrpStack = IoGetCurrentIrpStackLocation(Irp);

  /*
   * BUGBUG -> Srb = IrpStack->Parameters.Scsi.Srb;
   * Must pass Srb as Context arg!! See comment about Completion routines in
   * IofCallDriver for more info.
   */

  Srb = (PSCSI_REQUEST_BLOCK)Context;

  DPRINT("Srb %p\n", Srb);

  if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS)
    {
      Status = STATUS_SUCCESS;
    }
  else
    {
      /* 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,
					  IrpStack->MajorFunction,
					  0,
					  MAXIMUM_RETRIES - ((ULONG)IrpStack->Parameters.Others.Argument4),
					  &Status);

      /* Retry the request if verify should be overridden */
      if ((IrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME) &&
	  Status == STATUS_VERIFY_REQUIRED)
	{
	  Status = STATUS_IO_DEVICE_ERROR;
	  Retry = TRUE;
	}

      /* Retry the request */
      if ((Retry) &&
	  ((ULONG_PTR)IrpStack->Parameters.Others.Argument4 > 0))
	{
	  IrpStack->Parameters.Others.Argument4 = (PVOID) ((ULONG_PTR)IrpStack->Parameters.Others.Argument4 - 1);

	  ScsiClassRetryRequest(DeviceObject,
				Irp,
				Srb,
				FALSE);

	  return(STATUS_MORE_PROCESSING_REQUIRED);
	}
    }

  /* Free the SRB */
  ExFreeToNPagedLookasideList(&DeviceExtension->SrbLookasideListHead,
			      Srb);

  Irp->IoStatus.Status = Status;
  if (!NT_SUCCESS(Status))
    {
      Irp->IoStatus.Information = 0;
      if (IoIsErrorUserInduced(Status))
	{
	  IoSetHardErrorOrVerifyDevice(Irp,
				       DeviceObject);
	}
    }

  if (Irp->PendingReturned)
    {
      IoMarkIrpPending (Irp);
    }

  if (DeviceExtension->ClassStartIo != NULL)
    {
      if (IrpStack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
	{
	  KIRQL oldIrql;
	  oldIrql = KeGetCurrentIrql();
          if (oldIrql < DISPATCH_LEVEL)
            {
              KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
              IoStartNextPacket (DeviceObject, FALSE);
              KeLowerIrql(oldIrql);
	    }
          else
            {
              IoStartNextPacket (DeviceObject, FALSE);
	    }
	}
    }

  DPRINT("ScsiClassIoComplete() done (Status %lx)\n", Status);

⌨️ 快捷键说明

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