atapi.c

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

C
2,047
字号
	   }
	   else
	   {
	      BusMasterBasePort = 0;
	   }

	   DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig.VendorID, PciConfig.DeviceID);
	   ConfigInfo->NumberOfBuses = 1;
	   ConfigInfo->MaximumNumberOfTargets = 2;
	   ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */

	   /* FIXME:
	        We must not store and use the last tested slot number. If there is a recall
		to the some device and we will claim the primary channel again than the call
		to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
		claim the secondary channel.
	    */
	   ChannelFound = FALSE;
	   if (LastSlotNumber.u.AsULONG != SlotNumber.u.AsULONG)
	   {
	      /* try to claim primary channel */
	      if ((PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_SPACE) &&
		  (PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_SPACE))
	      {
		 /* primary channel is enabled */
		 ChannelFound = AtapiClaimHwResources(DevExt,
		                                      ConfigInfo,
		                                      PCIBus,
		                                      PciConfig.u.type0.BaseAddresses[0] & PCI_ADDRESS_IO_ADDRESS_MASK,
			                              PciConfig.u.type0.BaseAddresses[1] & PCI_ADDRESS_IO_ADDRESS_MASK,
			                              BusMasterBasePort,
			                              PciConfig.u.type0.InterruptLine);
	         if (ChannelFound)
		 {
                    AtapiFindDevices(DevExt, ConfigInfo);
                    *Again = TRUE;
		    ConfigInfo->SlotNumber = LastSlotNumber.u.AsULONG = SlotNumber.u.AsULONG;
                    return SP_RETURN_FOUND;
		 }
	      }
	   }
	   if (!ChannelFound)
	   {
	      /* try to claim secondary channel */
	      if ((PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_SPACE) &&
		  (PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_SPACE))
	      {
	         /* secondary channel is enabled */
	         ChannelFound = AtapiClaimHwResources(DevExt,
		                                      ConfigInfo,
		                                      PCIBus,
		                                      PciConfig.u.type0.BaseAddresses[2] & PCI_ADDRESS_IO_ADDRESS_MASK,
			                              PciConfig.u.type0.BaseAddresses[3] & PCI_ADDRESS_IO_ADDRESS_MASK,
						      BusMasterBasePort ? BusMasterBasePort + 8 : 0,
			                              PciConfig.u.type0.InterruptLine);
		 if (ChannelFound)
		 {
		    AtapiFindDevices(DevExt, ConfigInfo);
                    *Again = FALSE;
		    LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
                    return SP_RETURN_FOUND;
		 }
	      }
	   }
	}
     }
     StartFunctionNumber = 0;
  }
  *Again = FALSE;
  LastSlotNumber.u.AsULONG = 0xFFFFFFFF;
  DPRINT("AtapiFindNativePciController() done!\n");

  return(SP_RETURN_NOT_FOUND);
}
#endif


static BOOLEAN STDCALL
AtapiInitialize(IN PVOID DeviceExtension)
{
  return(TRUE);
}


static BOOLEAN STDCALL
AtapiResetBus(IN PVOID DeviceExtension,
	      IN ULONG PathId)
{
  return(TRUE);
}


static BOOLEAN STDCALL
AtapiStartIo(IN PVOID DeviceExtension,
	     IN PSCSI_REQUEST_BLOCK Srb)
{
  PATAPI_MINIPORT_EXTENSION DevExt;
  ULONG Result;

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

  DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;

  switch (Srb->Function)
    {
      case SRB_FUNCTION_EXECUTE_SCSI:
	DevExt->CurrentSrb = Srb;
	if (DevExt->DeviceFlags[Srb->TargetId] & DEVICE_ATAPI)
	  {
	    Result = AtapiSendAtapiCommand(DevExt,
					   Srb);
	  }
	else
	  {
	    Result = AtapiSendIdeCommand(DevExt,
					 Srb);
	  }
	break;

      case SRB_FUNCTION_ABORT_COMMAND:
	if (DevExt->CurrentSrb != NULL)
	  {
	    Result = SRB_STATUS_ABORT_FAILED;
	  }
	else
	  {
	    Result = SRB_STATUS_SUCCESS;
	  }
	break;

      case SRB_FUNCTION_IO_CONTROL:
        {
          PSRB_IO_CONTROL SrbIoControl = (PSRB_IO_CONTROL)Srb->DataBuffer;
          if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) ||
              Srb->DataTransferLength < SrbIoControl->Length + sizeof(SRB_IO_CONTROL))
            {
              Result = SRB_STATUS_INVALID_REQUEST;
            }
          else
            {
              if (!_strnicmp((char*)SrbIoControl->Signature, "ScsiDisk", 8))
                {
                  switch (SrbIoControl->ControlCode)
                    {
                      default:
                        Result = SRB_STATUS_INVALID_REQUEST;
                        break;

                      case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
                      case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
                      case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
                      case IOCTL_SCSI_MINIPORT_ENABLE_SMART:
                      case IOCTL_SCSI_MINIPORT_DISABLE_SMART:
                      case IOCTL_SCSI_MINIPORT_RETURN_STATUS:
                      case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
                      case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
                      case IOCTL_SCSI_MINIPORT_READ_SMART_LOG:
#if 0
                      case IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG:
#endif
                        Result = AtapiSendSmartCommand(DevExt, Srb);
                        break;

                      case IOCTL_SCSI_MINIPORT_SMART_VERSION:
                        {
                          GETVERSIONINPARAMS Version;      
                          ULONG i;

                          DPRINT("IOCTL_SCSI_MINIPORT_SMART_VERSION\n");

                          RtlZeroMemory(&Version, sizeof(GETVERSIONINPARAMS));
                          Version.bVersion = 1;
                          Version.bRevision = 1;
                          for (i = 0; i < 2; i++)
                            {
                              switch (DevExt->DeviceFlags[i] & (DEVICE_PRESENT|DEVICE_ATAPI))
                                {
                                  case DEVICE_PRESENT:
                                    Version.bIDEDeviceMap |= 0x01 << i;
                                    break;
/*
                                  case DEVICE_PRESENT|DEVICE_ATAPI:
                                    Version.bIDEDeviceMap |= 0x11 << i;
                                    break;
*/
                                }
                            }
                          Version.fCapabilities = CAP_ATA_ID_CMD/*|CAP_ATAPI_ID_CMD|CAP_SMART_CMD*/;
                          SrbIoControl->Length = min(sizeof(GETVERSIONINPARAMS), Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
                          memcpy(SrbIoControl + 1, &Version, SrbIoControl->Length);
                          Result = SRB_STATUS_SUCCESS;
                          break;
                        }

                      case IOCTL_SCSI_MINIPORT_IDENTIFY:
                        {
                          SENDCMDOUTPARAMS OutParams;
                          SENDCMDINPARAMS InParams = *(PSENDCMDINPARAMS)(SrbIoControl + 1);

                          DPRINT("IOCTL_SCSI_MINIPORT_IDENTIFY\n");

                          if (Srb->DataTransferLength < sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1)
                            {
                              Result = SRB_STATUS_INVALID_REQUEST;
                              break;
                            }
                  
                          RtlZeroMemory(&OutParams, sizeof(SENDCMDOUTPARAMS));

                          if (InParams.irDriveRegs.bCommandReg != IDE_CMD_IDENT_ATA_DRV)
                            {
                              DPRINT("bCommandReg: %x\n", InParams.irDriveRegs.bCommandReg);
                              OutParams.DriverStatus.bIDEError = 1;
                              Result = SRB_STATUS_INVALID_REQUEST;
                            }
                          else if (InParams.bDriveNumber > 1 ||
                                   (DevExt->DeviceFlags[InParams.bDriveNumber] & (DEVICE_PRESENT|DEVICE_ATAPI)) != DEVICE_PRESENT)
                            {
                              OutParams.DriverStatus.bIDEError = 1;
                              Result = SRB_STATUS_NO_DEVICE;
                            }
                          else
                            {
                              Result = SRB_STATUS_SUCCESS;
                            }
                          if (Result == SRB_STATUS_SUCCESS)
                            {
                              SrbIoControl->Length = min(sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE, Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
                            }
                          else
                            {
                              SrbIoControl->Length = min(sizeof(SENDCMDOUTPARAMS) - 1, Srb->DataTransferLength - sizeof(SRB_IO_CONTROL));
                            }

                          if (SrbIoControl->Length >= sizeof(SENDCMDOUTPARAMS) - 1)
                            {
                              OutParams.cBufferSize = min(SrbIoControl->Length, IDENTIFY_BUFFER_SIZE);
                            }
                          
                          memcpy(SrbIoControl + 1, &OutParams, min (SrbIoControl->Length, sizeof(SENDCMDOUTPARAMS) - 1));
                         
                          if (SrbIoControl->Length > sizeof(SENDCMDOUTPARAMS) - 1)
                            {
                              RtlCopyMemory((PVOID)((ULONG_PTR)(SrbIoControl + 1) + sizeof(SENDCMDOUTPARAMS) - 1), &DevExt->DeviceParams[InParams.bDriveNumber], OutParams.cBufferSize);
                            }
                          break;
                        }
                    }
                }
              else
                {
                  Result = SRB_STATUS_INVALID_REQUEST;
                  SrbIoControl->Length = 0;
                }
            }
          break;
        }

      default:
	Result = SRB_STATUS_INVALID_REQUEST;
	break;
    }

  Srb->SrbStatus = Result;


  if (Result != SRB_STATUS_PENDING)
    {
      DevExt->CurrentSrb = NULL;

      ScsiPortNotification(RequestComplete,
			   DeviceExtension,
			   Srb);
      ScsiPortNotification(NextRequest,
			   DeviceExtension,
			   NULL);
    }
  else
    {
      DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
    }

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

  return(TRUE);
}

static BOOLEAN STDCALL
AtapiInterrupt(IN PVOID DeviceExtension)
{
  PATAPI_MINIPORT_EXTENSION DevExt;
  UCHAR Status;
  DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;

  if (DevExt->Handler == NULL)
    {
      Status =  IDEReadAltStatus(DevExt->ControlPortBase);
      if ((Status & (IDE_SR_DRDY|IDE_SR_BUSY|IDE_SR_ERR|IDE_SR_DRQ)) != IDE_SR_DRDY)
        {
	  static ULONG Count = 0;
	  Count++;
	  DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
	          DevExt->CommandPortBase, Status, Count);
	}
      return FALSE;
    }
#ifdef ENABLE_DMA
  if (DevExt->UseDma)
    {
      Status = IDEReadDMAStatus(DevExt->BusMasterRegisterBase);
      if (!(Status & 0x04))
        {
	  return FALSE;
	}
    }
  else
#endif
    {
      Status = IDEReadAltStatus(DevExt->ControlPortBase);
      if (Status & IDE_SR_BUSY)
        {
	  return FALSE;
	}
    }
  return DevExt->Handler(DevExt);
}

//  ----------------------------------------------------  Discardable statics

#ifdef ENABLE_DMA
static BOOLEAN
AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension, ULONG UnitNumber)
{
  BOOLEAN Result = FALSE;
  UCHAR Status;

  if (UnitNumber < 2)
    {
      if (DeviceExtension->PRDTable)
        {
          if (DeviceExtension->DeviceParams[UnitNumber].Capabilities & IDE_DRID_DMA_SUPPORTED)
            {
              if ((DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0004) &&
                  (DeviceExtension->DeviceParams[UnitNumber].UltraDmaModes & 0x7F00))
                {
                  Result = TRUE;
                }
              else if (DeviceExtension->DeviceParams[UnitNumber].TMFieldsValid & 0x0002)
	        {
	          if ((DeviceExtension->DeviceParams[UnitNumber].MultiDmaModes & 0x0404) == 0x0404)
	            {
                      Result = TRUE;
                    }
#if 0
                  /* FIXME:
	           *   should we support single mode dma ?
	           */
	          else if ((DeviceExtension->DeviceParams[UnitNumber].DmaModes & 0x0404) == 0x0404)
	            {
                      Result = TRUE;
	            }
#endif
                }
              Status = IDEReadDMAStatus(DeviceExtension->BusMasterRegisterBase);
              if (Result)
                {
                  IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status | (UnitNumber ? 0x40 : 0x20));
	        }
              else
                {
                  IDEWriteDMAStatus(DeviceExtension->BusMasterRegisterBase, Status & (UnitNumber ? ~0x40 : ~0x20));
                }
	    }
	}
    }
  return Result;
}
#endif

/**********************************************************************
 * NAME							INTERNAL
 *	AtapiFindDevices
 *
 * DESCRIPTION
 *	Searches for devices on the given port.
 *
 * RUN LEVEL
 *	PASSIVE_LEVEL
 *
 * ARGUMENTS
 *	DeviceExtension
 *		Port device specific information.
 *
 *	ConfigInfo
 *		Port configuration information.
 *
 * RETURN VALUE
 *	TRUE: At least one device is attached to the port.
 *	FALSE: No device is attached to the port.
 */

static BOOLEAN
AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
		 PPORT_CONFIGURATION_INFORMATION ConfigInfo)
{
  BOOLEAN DeviceFound = FALSE;
  ULONG CommandPortBase;
  ULONG ControlPortBase;
  ULONG UnitNumber;
  ULONG Retries;

⌨️ 快捷键说明

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