第 1 部分针对 Oracle Solaris 平台设计设备驱动程序
9. 直接内存访问 (Direct Memory Access, DMA)
14. 分层驱动程序接口 (Layered Driver Interface, LDI)
SCSA HBA 接口包括 HBA 入口点、HBA 数据结构和 HBA 框架。
SCSA 定义了许多 HBA 驱动程序入口点。下表中列出了这些入口点。配置连接到 HBA 驱动程序的目标驱动程序实例时,系统将会调用这些入口点。另外,目标驱动程序发出 SCSA 请求时,也会调用这些入口点。有关更多信息,请参见SCSA HBA 驱动程序入口点。
表 18-1 SCSA HBA 入口点汇总
|
SCSA 定义了多种数据结构,以便可在目标驱动程序和 HBA 驱动程序之间交换信息。其中包括以下数据结构:
HBA 驱动程序的每个实例都必须在 scsi_hba_tran(9S) 入口点中使用 scsi_hba_tran_alloc(9F) 函数分配 attach(9E) 结构。scsi_hba_tran_alloc() 函数可初始化 scsi_hba_tran 结构。HBA 驱动程序必须初始化传输结构中的特定向量才能指向 HBA 驱动程序中的入口点。初始化 scsi_hba_tran 结构后,HBA 驱动程序通过调用 scsi_hba_attach_setup(9F) 函数将传输结构导出到 SCSA。
注意 - 由于 SCSA 将指向传输结构的指针保存在 devinfo 节点的驱动程序专用字段中,因此 HBA 驱动程序决不能使用 ddi_set_driver_private(9F)。但是,HBA 驱动程序可以使用 ddi_get_driver_private(9F) 来检索指向传输结构的指针。 |
SCSA 接口要求 HBA 驱动程序提供许多可通过 scsi_hba_tran 结构调用的入口点。有关更多信息,请参见SCSA HBA 驱动程序入口点。
scsi_hba_tran 结构包含以下字段:
struct scsi_hba_tran { dev_info_t *tran_hba_dip; /* HBAs dev_info pointer */ void *tran_hba_private; /* HBA softstate */ void *tran_tgt_private; /* HBA target private pointer */ struct scsi_device *tran_sd; /* scsi_device */ int (*tran_tgt_init)(); /* Transport target */ /* Initialization */ int (*tran_tgt_probe)(); /* Transport target probe */ void (*tran_tgt_free)(); /* Transport target free */ int (*tran_start)(); /* Transport start */ int (*tran_reset)(); /* Transport reset */ int (*tran_abort)(); /* Transport abort */ int (*tran_getcap)(); /* Capability retrieval */ int (*tran_setcap)(); /* Capability establishment */ struct scsi_pkt *(*tran_init_pkt)(); /* Packet and DMA allocation */ void (*tran_destroy_pkt)(); /* Packet and DMA */ /* Deallocation */ void (*tran_dmafree)(); /* DMA deallocation */ void (*tran_sync_pkt)(); /* Sync DMA */ void (*tran_reset_notify)(); /* Bus reset notification */ int (*tran_bus_reset)(); /* Reset bus only */ int (*tran_quiesce)(); /* Quiesce a bus */ int (*tran_unquiesce)(); /* Unquiesce a bus */ int tran_interconnect_type; /* transport interconnect */ };
下面的描述提供了有关这些 scsi_hba_tran 结构字段的更多信息:
指向 HBA 设备实例 dev_info 结构的指针。函数 scsi_hba_attach_setup(9F) 可用于设置此字段。
指向 HBA 驱动程序维护的专用数据的指针。通常,tran_hba_private 包含指向 HBA 驱动程序状态结构的指针。
指向使用克隆时 HBA 驱动程序维护的专用数据的指针。通过在调用 scsi_hba_attach_setup(9F) 时指定 SCSI_HBA_TRAN_CLONE,可对每个目标克隆一次 scsi_hba_tran(9S) 结构。借助该方法,HBA 可将此字段初始化为指向 tran_tgt_init(9E) 入口点中按目标实例的数据结构。如果未指定 SCSI_HBA_TRAN_CLONE,则 tran_tgt_private 为 NULL,并且决不能引用 tran_tgt_private。有关更多信息,请参见传输结构克隆。
指向克隆时使用的按目标实例的 scsi_device(9S) 结构的指针。如果将 SCSI_HBA_TRAN_CLONE 传递给 scsi_hba_attach_setup(9F),则 tran_sd 会初始化指向按目标的 scsi_device 结构。在代表目标调用任何 HBA 函数之前,将进行此初始化。如果未指定 SCSI_HBA_TRAN_CLONE,则 tran_sd 为 NULL,并且决不能引用 tran_sd。有关更多信息,请参见传输结构克隆。
指向初始化目标设备实例时调用的 HBA 驱动程序入口点的指针。如果无需进行按目标的初始化,则 HBA 可保持将 tran_tgt_init 设置为 NULL。
指向在目标驱动程序实例调用 scsi_probe(9F) 时调用的 HBA 驱动程序入口点的指针。调用该例程可探测目标设备是否存在。如果此 HBA 无需进行目标探测定制,则 HBA 应将 tran_tgt_probe 设置为 scsi_hba_probe(9F)。
指向在目标设备实例被销毁时调用的 HBA 驱动程序入口点的指针。如果无需进行按目标的取消分配,则 HBA 可保持将 tran_tgt_free 设置为 NULL。
指向在目标驱动程序调用 scsi_transport(9F) 时调用的 HBA 驱动程序入口点的指针。
指向在目标驱动程序调用 scsi_reset(9F) 时调用的 HBA 驱动程序入口点的指针。
指向在目标驱动程序调用 scsi_abort(9F) 时调用的 HBA 驱动程序入口点的指针。
指向在目标驱动程序调用 scsi_ifgetcap(9F) 时调用的 HBA 驱动程序入口点的指针。
指向在目标驱动程序调用 scsi_ifsetcap(9F) 时调用的 HBA 驱动程序入口点的指针。
指向在目标驱动程序调用 scsi_init_pkt(9F) 时调用的 HBA 驱动程序入口点的指针。
指向在目标驱动程序调用 scsi_destroy_pkt(9F) 时调用的 HBA 驱动程序入口点的指针。
指向在目标驱动程序调用 scsi_dmafree(9F) 时调用的 HBA 驱动程序入口点的指针。
指向在目标驱动程序调用 scsi_sync_pkt(9F) 时调用的 HBA 驱动程序入口点的指针。
指向在目标驱动程序调用 tran_reset_notify(9E) 时调用的 HBA 驱动程序入口点的指针。
重置 SCSI 总线但不重置目标的函数项。
等待所有未完成的命令完成并阻塞(或排队)任何发出的 I/O 请求的函数项。
允许 I/O 活动在 SCSI 总线上恢复的函数项。
表示 services.h 头文件中定义的传输互连类型的整数值。
scsi_address(9S) 结构可为目标驱动程序实例分配和传输的各个 SCSI 命令提供传输及寻址信息。
scsi_address 结构包含以下字段:
struct scsi_address { struct scsi_hba_tran *a_hba_tran; /* Transport vectors */ ushort_t a_target; /* Target identifier */ uchar_t a_lun; /* LUN on that target */ uchar_t a_sublun; /* Sub LUN on that LUN */ /* Not used */ };
指向 HBA 驱动程序分配和初始化的 scsi_hba_tran(9S) 结构的指针。如果将 SCSI_HBA_TRAN_CLONE 指定为 scsi_hba_attach_setup(9F) 的标志, 则 a_hba_tran 指向该结构的副本。
标识 SCSI 总线上的 SCSI 目标。
标识 SCSI 目标的 SCSI 逻辑单元。
HBA 框架可为目标设备的各个实例分配和初始化 scsi_device(9S) 结构。该框架调用 HBA 驱动程序的 tran_tgt_init(9E) 入口点之前,将进行分配和初始化。此结构可存储有关每个 SCSI 逻辑单元的信息,包括指向信息区(包含通用信息和特定于设备的信息)的指针。对于连接到系统的每个目标设备实例,都存在一个 scsi_device(9S) 结构。
如果按目标的初始化成功,则 HBA 框架会使用 ddi_set_driver_private(9F) 将目标驱动程序的按实例的专用数据设置为指向 scsi_device(9S) 结构。请注意,如果 tran_tgt_init () 返回成功信息或该向量为 null,则表明初始化成功。
scsi_device(9S) 结构包含以下字段:
struct scsi_device { struct scsi_address sd_address; /* routing information */ dev_info_t *sd_dev; /* device dev_info node */ kmutex_t sd_mutex; /* mutex used by device */ void *sd_reserved; struct scsi_inquiry *sd_inq; struct scsi_extended_sense *sd_sense; caddr_t sd_private; /* for driver's use */ };
其中:
为了进行 SCSI 资源分配而传递给例程的数据结构。
指向目标的 dev_info 结构的指针。
供目标驱动程序使用的互斥锁。此互斥锁通过 HBA 框架进行初始化。目标驱动程序可将此互斥锁用作按设备的互斥锁。在调用 scsi_transport(9F) 或 scsi_poll(9F) 期间,不应持有此互斥锁。有关互斥锁的更多信息,请参见第 3 章。
目标设备的 SCSI 查询数据的指针。scsi_probe(9F) 例程可用于分配缓冲区、填充该缓冲区并将该缓冲区附加到此字段。
指向用于包含设备中的请求检测数据的缓冲区的指针。目标驱动程序必须分配和管理此缓冲区本身。有关更多信息,请参见attach() 入口点中目标驱动程序的 attach(9E) 例程。
供目标驱动程序使用的指针字段。此字段通常用于存储指向专用目标驱动程序状态结构的指针。
要执行 SCSI 命令,目标驱动程序必须首先为该命令分配 scsi_pkt(9S) 结构。然后,目标驱动程序必须指定其自身的专用数据区长度、命令状态和命令长度。HBA 驱动程序负责实现 tran_init_pkt(9E) 入口点中的包分配。另外,HBA 驱动程序还负责释放其 tran_destroy_pkt(9E) 入口点中的包。有关更多信息,请参见scsi_pkt 结构(目标驱动程序)。
scsi_pkt(9S) 结构包含以下字段:
struct scsi_pkt { opaque_t pkt_ha_private; /* private data for host adapter */ struct scsi_address pkt_address; /* destination address */ opaque_t pkt_private; /* private data for target driver */ void (*pkt_comp)(struct scsi_pkt *); /* completion routine */ uint_t pkt_flags; /* flags */ int pkt_time; /* time allotted to complete command */ uchar_t *pkt_scbp; /* pointer to status block */ uchar_t *pkt_cdbp; /* pointer to command block */ ssize_t pkt_resid; /* data bytes not transferred */ uint_t pkt_state; /* state of command */ uint_t pkt_statistics; /* statistics */ uchar_t pkt_reason; /* reason completion called */ };
其中:
指向按命令的 HBA 驱动程序专用数据的指针。
指向用于为此命令提供地址信息的 scsi_address(9S) 结构的指针。
指向按包的目标驱动程序专用数据的指针。
指向在传输层完成此命令时 HBA 驱动程序调用的目标驱动程序完成例程的指针。
命令的标志。
指定命令的完成超时时间(以秒为单位)。
指向命令的状态完成块的指针。
指向命令的命令描述符块 (command descriptor block, CDB) 的指针。
命令完成时未传送的数据字节计数。此字段也可能会用于指定尚未分配资源的数据量。在传输过程中,HBA 必须修改此字段。
命令的状态。在传输过程中,HBA 必须修改此字段。
提供命令在传输层中发生的事件的历史记录。在传输过程中,HBA 必须修改此字段。
命令完成的原因。在传输过程中,HBA 必须修改此字段。
在执行 attach(9E) 期间,HBA 驱动程序必须分配 scsi_hba_tran(9S) 结构。然后,HBA 驱动程序必须将此传输结构中的向量初始化为指向 HBA 驱动程序所需的入口点。此 scsi_hba_tran 结构随后将传递给 scsi_hba_attach_setup(9F)。
scsi_hba_tran 结构包含 tran_hba_private 字段,该字段可用于引用 HBA 驱动程序的按实例状态。
每个 scsi_address(9S) 结构都包含一个指向 scsi_hba_tran 结构的指针。此外,scsi_address 结构还为特定的目标设备提供了目标(即 a_target)和逻辑单元 (a_lun) 地址。通过 scsi_device(9S) 结构可直接或间接向 HBA 驱动程序的每个入口点传递一个指向 scsi_address 结构的指针。因此,HBA 驱动程序可以引用其自身的状态。HBA 驱动程序还可以标识已寻址的目标设备。
下图说明了用于传输操作的 HBA 数据结构。
图 18-3 HBA 传输结构
如果 HBA 驱动程序需要维护 scsi_hba_tran(9S) 结构中按目标的专用数据,则克隆可能会非常有用。克隆还可用于维护比 scsi_address(9S) 结构中所提供的更为复杂的地址。
在克隆过程中,HBA 驱动程序仍必须在执行 attach(9E) 期间分配 scsi_hba_tran 结构。此外,HBA 驱动程序还必须初始化 HBA 驱动程序的 tran_hba_private 软状态指针和入口点向量。当框架开始将目标驱动程序实例连接到 HBA 驱动程序时,将会产生差异。调用 HBA 驱动程序的 tran_tgt_init(9E) 入口点之前,框架会克隆与 HBA 的该实例关联的 scsi_hba_tran 结构。相应地,为特定目标设备实例分配和初始化的每个 scsi_address 结构都会指向 scsi_hba_tran 结构的按目标实例的副本。scsi_address 结构不会指向 HBA 驱动程序在执行 attach() 期间分配的 scsi_hba_tran 结构。
指定克隆时,HBA 驱动程序可以使用两个重要的指针。这些指针包含在 scsi_hba_tran 结构中。第一个指针是 tran_tgt_private 字段,驱动程序可以使用该指针指向按目标的 HBA 专用数据。tran_tgt_private 指针非常有用,例如在 HBA 驱动程序需要维护比 a_target 和 a_lun 所提供的更为复杂的地址的情况下。第二个指针是 tran_sd 字段,该指针指向引用特定目标设备的 scsi_device(9S) 结构。
指定克隆时,HBA 驱动程序必须分配和初始化按目标的数据。HBA 驱动程序随后必须在执行其 tran_tgt_init(9E) 入口点过程中将 tran_tgt_private 字段初始化为指向此数据。HBA 驱动程序必须在执行其 tran_tgt_free(9E) 入口点过程中释放按目标的数据。
克隆时,框架会在调用 HBA 驱动程序 tran_tgt_init() 入口点之前将 tran_sd 字段初始化为指向 scsi_device 结构。该驱动程序通过将 SCSI_HBA_TRAN_CLONE 标志传递给 scsi_hba_attach_setup(9F) 来请求克隆。下图说明了用于克隆传输操作的 HBA 数据结构。
图 18-4 克隆传输操作
SCSA 还提供了许多函数。下表中列出了这些函数,供 HBA 驱动程序使用。
表 18-2 SCSA HBA 函数
|