EFI Driver Model(下)-SCSI 驱动设计

本文详细阐述了SCSI接口在服务器环境中的优势,探讨了在EFIDriverModel架构下的SCSI驱动设计,涉及toplevel、middlelevel和lowerlevel层次,以及PCI和SCSI子系统的交互。特别关注了SCSIHostControllerDriver的实现和EFI_DRIVER_BINDING_PROTOCOL在启动和停止驱动中的作用,以及不同类型的SCSI适配器驱动策略。
摘要由CSDN通过智能技术生成

1、SCSI简介

  SCSI是Small Computer System Interface(小型计算机系统接口)的缩写,使用50针接口,外观和普通硬盘接口有些相似。SCSI硬盘和普通IDE硬盘相比有很多优点:接口速度快,并且由于主要用于服务器,因此硬盘本身的性能也比较高,硬盘转速快,缓存容量大,CPU占用率低,扩展性远优于IDE硬盘,并且支持热插拔。

2、SCSI驱动设计

  在EFI Driver Model中,UEFI驱动程序是重要的组成部分,它们与UEFI应用程序有所区别。对于UEFI驱动程序来说,EFI System Table、Memory、Handles、Images和Events等对象的管理至关重要。在初始化驱动程序时,有些驱动程序可能不会产生任何Handle,也不会向Handle Database增加任何Protocol,它们主要进行初始化操作,并在执行完毕后从系统内存中卸载。

  具体到SCSI驱动设计,它在Linux系统中通常被划分为三个层次:top level、middle level和lower level。Top level为具体的scsi设备驱动,例如常用的磁盘设备驱动。这些驱动与具体的scsi设备相关,因此通常由设备开发者提供。对于标准类设备,驱动可以通用。Middle level实际上是scsi总线层驱动,它负责按照scsi协议进行设备枚举、数据传输和出错处理。而在lower level层,驱动可能并不直接对硬件进行操作,例如可以做虚拟的scsi host。

  在SCSI驱动设计中,scsi_driver结构体和scsi磁盘驱动实例(如sd_template,定义在文件drivers/scsi/sd.c)是关键部分。PCI子系统和SCSI子系统的工作模式也是设计过程中需要考虑的重要因素。PCI子系统会注册PCI总线类型,扫描PCI总线以获取所有PCI设备。而SCSI子系统则注册SCSI总线类型,其较高层注册SCSI设备驱动,较低层(如SCSI HBA驱动)负责扫描SCSI总线以获取所有SCSI设备。

  总的来说,EFI Driver Model下的SCSI驱动设计是一个复杂而精细的过程,需要考虑到各种设备、总线和协议的特性,以确保驱动的稳定性和高效性。对于开发者来说,深入理解EFI Driver Model以及SCSI的工作原理是设计高质量驱动的基础。

驱动类别描述
SCSI host controllerConsumes PCI I/O Protocol on the SCSI host controller handle and produces the Ext SCSI Pass Thru Protocol,如果需要一个驱动程序与EFI 1.10规范兼容,则必须生成SCSI通过协议。
SCSI bus driverConsumes the Ext SCSI Pass Thru Protocol and produces a child handle for SCSI targets on the SCSI bus. Installs the Device Path Protocol and SCSI I/O Protocol onto each child handle.
SCSI 设备驱动使用SCSI I/O协议,并生成一个I/O抽象,它为启动符合EFI的操作系统所需的控制台设备和引导设备提供服务。

   EFI 1.10规范定义了SCSIPass Thru Protocol.用于SCSI host controller的UEFI驱动程序被需要符合EFI 1.10规范的平台上正常工作,生成SCSI通过协议,并为SCSI host controller管理的物理驱动器和逻辑驱动器生成BLOCK I/O协议。这意味着需要一个用于EFI 1.10平台中的SCSI主机控制器的UEFI Driver来执行上表中描述的SCSI驱动程序堆栈的所有功能。UEFI 2.0及以上规范要求平台固件为大容量存储设备提供SCSI总线驱动程序和SCSI设备驱动程序。

2.1 SCSI Host Controller Driver

  SCSI主机控制器驱动程序管理包含一个或多个SCSI通道的SCSI主机控制器,它为每个SCSI通道创建句柄,并安装扩展的SCSI Pass Thru Protocol和Device Path Protocol到每一个驱动产生的handle上。有关EFI_EXT_SCSI_PASS_THRU_PROTOCOL的详细信息,请参阅UEFI规范中的SCSI驱动程序模型和总线支持章节。

struct _EFI_EXT_SCSI_PASS_THRU_PROTOCOL {
  ///
  /// A pointer to the EFI_EXT_SCSI_PASS_THRU_MODE data for this SCSI channel.
  ///
  EFI_EXT_SCSI_PASS_THRU_MODE                *Mode;
  EFI_EXT_SCSI_PASS_THRU_PASSTHRU            PassThru;
  EFI_EXT_SCSI_PASS_THRU_GET_NEXT_TARGET_LUN GetNextTargetLun;
  EFI_EXT_SCSI_PASS_THRU_BUILD_DEVICE_PATH   BuildDevicePath;
  EFI_EXT_SCSI_PASS_THRU_GET_TARGET_LUN      GetTargetLun;
  EFI_EXT_SCSI_PASS_THRU_RESET_CHANNEL       ResetChannel;
  EFI_EXT_SCSI_PASS_THRU_RESET_TARGET_LUN    ResetTargetLun;
  EFI_EXT_SCSI_PASS_THRU_GET_NEXT_TARGET     GetNextTarget;
};

  一个SCSI主机控制器驱动程序遵循UEFI驱动程序模型。根据其管理的适配器,SCSI主机控制器驱动程序可以被归类为设备驱动程序或混合驱动程序。它为每个SCSI通道创建子句柄(如果有多个1),它还可以在自己的句柄上安装协议。通常,SCSI主机控制器驱动器是特定于芯片的,因为需要初始化和管理当前绑定的SCSI主机控制器。

  由于在一个平台中可能存在多个可能由一个SCSI主机控制器驱动程序管理的SCSI主机适配器,因此建议将SCSI主机控制器驱动程序设计为重新进入,并为每个SCSI主机控制器分配不同的私有上下文数据结构。

2.2 Single-Channel SCSI Adapters

如果SCSI适配器支持一个通道,则SCSI主机控制器驱动程序将执行以下操作:

  • 将扩展的SCSI Pass Thru Protocol安装到控制器句柄上的SCSI host controller的controller handle上。
  • 在模式结构中设置SCSI通道的逻辑属性。
  • 在模式结构中设置SCSI通道的物理属性

  下图显示了一个在单通道SCSI适配器上的实现示例。绿色的图层表示SCSI主机控制器驱动程序。
在这里插入图片描述
  因为只有一个SCSI通道,所以SCSI驱动程序可以简单地实现扩展SCSI通过协议的一个实例。平台固件提供了SCSI总线驱动程序和SCSI磁盘驱动程序,它们通过执行以下操作来完成驱动程序堆栈:

  • 扫描SCSI通道上的SCSI目标并创建子句柄。
  • 向每个子句柄安装设备路径协议
  • 向每个子句柄上安装SCSI I/O协议
  • 向每个子句柄安装I/O抽象,例如Block I/O协议

2.2 Multi-Channel SCSI Adapters

  如果SCSI适配器提供多个SCSI通道,则SCSI主机控制器驱动程序会更加复杂。下图显示了在双通道SCSI适配器上可能实现的SCSI驱动程序实现。
在这里插入图片描述
  在这种情况下,SCSI适配器通过执行以下操作产生两个物理SCSI通道:

  • 为每个物理SCSI通道创建一个子句柄。
  • 向每个子句柄安装设备路径协议。
  • 在每个子句柄上安装扩展的SCSI传递协议
  • 在每个子句柄上的模式结构中设置SCSI通道的逻辑属性。
  • 在每个子句柄上的模式结构中设置SCSI通道的物理属性。

  平台固件提供了SCSI总线驱动程序和SCSI磁盘驱动程序,通过执行以下操作,可以完成上述每个扩展SCSI通过协议上的两个驱动程序堆栈:

  • 扫描每个SCSI通道上的SCSI目标,并创建子句柄。
  • 向每个子句柄安装设备路径协议。
  • 向每个子句柄上安装SCSI I/O协议
  • 向每个子句柄安装I/O抽象,如Block I/O协议。

2.3 SCSI Adapters with RAID

  SCSI主机控制器驱动程序也可以支持具有RAID功能的SCSI适配器。下图显示了一个具有两个物理SCSI通道和一个逻辑通道的示例实现。这两个物理通道是在SCSI适配器上实现的,然后,RAID组件配置这两个通道,以生成一个逻辑SCSI通道。两个物理通道都安装了扩展SCSI通过通道,但除了用于诊断外,不使用这些通道。对于逻辑通道,SCSI主机控制器驱动程序根据RAID配置生成另一个扩展SCSI通过协议(关闭物理位)实例。发送到逻辑通道的扩展SCSI传递协议的请求由SCSI主机控制器驱动程序处理,并转换为物理SCSI通道上的请求,平台固件必须只枚举并从逻辑SCSI通道上存在的SCSI目标启动。
在这里插入图片描述
  在实现RAID时,SCSI适配器硬件可能无法将物理SCSI通道)暴露给上层软件。如果物理SCSI通道不能暴露于上层软件,则SCSI主机控制器驱动程序只需要为RAID生成单个逻辑通道。
  虽然基本理论与物理通道上的理论相同,但从制造和诊断的角度是不同的。如果物理SCSI通道暴露,任何SCSI命令,包括诊断命令,都可以发送到单个通道,这对生产线非常有帮助。此外,可以使用扩展SCSI传递协议支持的非阻塞模式同时将诊断命令发送到所有物理通道。诊断过程可能会从性能的增益中显著获益。总之,建议尽可能公开物理SCSI通道。
  当然,有许多可能的设计来实现SCSI RAID功能。关键是,SCSI主机控制器驱动程序可以为各种SCSI适配器类型设计和实现,并且这些SCSI主机控制器驱动程序可以生成包含可作为UEFI引导设备使用的SCSI目标的扩展SCSI通过协议。

3、源码分析

ScsiDiskDriverBindingSupported 用于检测该SCSI磁盘驱动程序是否支持特定的控制器设备

EFI_STATUS
EFIAPI
ScsiDiskDriverBindingSupported (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
  );

ScsiDiskDriverBindingStart 这个函数是用来启动指定的驱动程序并将其绑定到指定的ControllerHandle上的。它是EFI_DRIVER_BINDING_PROTOCOL协议的一部分,是UEFI(统一可扩展固件接口)引导过程中重要的一环,用于初始化和启动设备驱动程序。

EFI_STATUS
EFIAPI
ScsiDiskDriverBindingStart (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL
  );

ScsiDiskDriverBindingStop 用于停止指定控制器上的驱动程序。这个函数属于EFI_DRIVER_BINDING_PROTOCOL协议,该协议定义了驱动程序如何绑定到控制器、启动和停止服务。

EFI_STATUS
EFIAPI
ScsiDiskDriverBindingStop (
  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN  EFI_HANDLE                   Controller,
  IN  UINTN                        NumberOfChildren,
  IN  EFI_HANDLE                   *ChildHandleBuffer   OPTIONAL
  );

ScsiIo使用

 Status = gBS->OpenProtocol (
                  Controller,
                  &gEfiScsiIoProtocolGuid,
                  (VOID **)&ScsiIo,
                  This->DriverBindingHandle,
                  Controller,
                  EFI_OPEN_PROTOCOL_BY_DRIVER
                  );
  if (EFI_ERROR (Status)) {
    FreePool (ScsiDiskDevice);
    return Status;
  }

  ScsiDiskDevice->Signature                         = SCSI_DISK_DEV_SIGNATURE;
  ScsiDiskDevice->ScsiIo                            = ScsiIo;
  ScsiDiskDevice->BlkIo.Revision                    = EFI_BLOCK_IO_PROTOCOL_REVISION3;
  ScsiDiskDevice->BlkIo.Media                       = &ScsiDiskDevice->BlkIoMedia;
  ScsiDiskDevice->BlkIo.Media->IoAlign              = ScsiIo->IoAlign;
  ScsiDiskDevice->BlkIo.Reset                       = ScsiDiskReset;
  ScsiDiskDevice->BlkIo.ReadBlocks                  = ScsiDiskReadBlocks;
  ScsiDiskDevice->BlkIo.WriteBlocks                 = ScsiDiskWriteBlocks;
  ScsiDiskDevice->BlkIo.FlushBlocks                 = ScsiDiskFlushBlocks;
  ScsiDiskDevice->BlkIo2.Media                      = &ScsiDiskDevice->BlkIoMedia;
  ScsiDiskDevice->BlkIo2.Reset                      = ScsiDiskResetEx;
  ScsiDiskDevice->BlkIo2.ReadBlocksEx               = ScsiDiskReadBlocksEx;
  ScsiDiskDevice->BlkIo2.WriteBlocksEx              = ScsiDiskWriteBlocksEx;
  ScsiDiskDevice->BlkIo2.FlushBlocksEx              = ScsiDiskFlushBlocksEx;
  ScsiDiskDevice->StorageSecurity.ReceiveData       = ScsiDiskReceiveData;
  ScsiDiskDevice->StorageSecurity.SendData          = ScsiDiskSendData;
  ScsiDiskDevice->EraseBlock.Revision               = EFI_ERASE_BLOCK_PROTOCOL_REVISION;
  ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;
  ScsiDiskDevice->EraseBlock.EraseBlocks            = ScsiDiskEraseBlocks;
  ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt           = 1;
  ScsiDiskDevice->BlockLimitsVpdSupported           = FALSE;
  ScsiDiskDevice->Handle                            = Controller;
  Status = gBS->InstallMultipleProtocolInterfaces (
                      &Controller,
                      &gEfiBlockIoProtocolGuid,
                      &ScsiDiskDevice->BlkIo,
                      &gEfiBlockIo2ProtocolGuid,
                      &ScsiDiskDevice->BlkIo2,
                      &gEfiDiskInfoProtocolGuid,
                      &ScsiDiskDevice->DiskInfo,
                      NULL
                      );
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值