第 1 部分针对 Oracle Solaris 平台设计设备驱动程序
9. 直接内存访问 (Direct Memory Access, DMA)
14. 分层驱动程序接口 (Layered Driver Interface, LDI)
目标驱动程序必须包括头文件 <sys/scsi/scsi.h>。
SCSI 目标驱动程序必须使用以下命令生成二进制模块:
ld -r xx xx.o -N"misc/scsi"
调用 probe(9E) 或 attach(9E) 例程之前,主机总线适配器驱动程序将为目标驱动程序分配并初始化 scsi_device(9S) 结构。此结构可存储有关每个 SCSI 逻辑单元的信息,包括指向信息区(包含通用信息和特定于设备的信息)的指针。对于连接到系统的每个逻辑单元,都存在一个 scsi_device(9S) 结构。目标驱动程序可以通过调用 ddi_get_driver_private(9F) 来检索指向此结构的指针。
scsi_device(9S) 结构包含以下字段:
struct scsi_device { struct scsi_address sd_address; /* opaque address */ dev_info_t *sd_dev; /* device node */ kmutex_t sd_mutex; void *sd_reserved; struct scsi_inquiry *sd_inq; struct scsi_extended_sense *sd_sense; caddr_t sd_private; };
其中:
为了进行 SCSI 资源分配而传递给例程的数据结构。
指向目标的 dev_info 结构的指针。
供目标驱动程序使用的互斥锁。此互斥锁由主机总线适配器驱动程序初始化,并可被目标驱动程序用作每设备互斥锁。请勿在调用 scsi_transport(9F) 或 scsi_poll(9F) 期间持有此互斥锁。有关互斥锁的更多信息,请参见第 3 章。
目标设备的 SCSI 查询数据的指针。scsi_probe(9F) 例程将分配缓冲区,使用查询数据填充该缓冲区,并将该缓冲区连接到此字段。
指向用于包含设备中的 SCSI 请求检测数据的缓冲区的指针。目标驱动程序必须分配和管理此缓冲区。请参见attach() 入口点(SCSI 目标驱动程序)。
供目标驱动程序使用的指针字段。此字段通常用于存储指向专用目标驱动程序状态结构的指针。
struct scsi_pkt { opaque_t pkt_ha_private; /* private data for host adapter */ struct scsi_address pkt_address; /* destination packet is for */ 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 */ };
其中:
scsi_init_pkt(9F) 设置的目标设备的地址。
用于存储目标驱动程序的专用数据的位置。pkt_private 通常用于保存命令的 buf(9S) 指针。
完成例程的地址。主机总线适配器驱动程序将在传输命令后调用此例程。传输命令并不表示命令已成功。目标可能处于繁忙状态。另一种可能性是在经过超时时间段之前目标未响应。请参见 pkt_time 字段的说明。目标驱动程序必须在该字段中提供有效值。如果不需要通知驱动程序,则该值可以为 NULL。
注 - 有两种不同的 SCSI 回调例程。pkt_comp 字段标识完成回调例程,该例程将在主机总线适配器完成其处理时调用。此外,还提供了资源回调例程,该例程将在当前尚不可用资源可能可用时调用。请参见 scsi_init_pkt(9F) 手册页。
提供其他控制信息,例如,在没有断开连接权限的情况下传输命令 (FLAG_NODISCON),或禁用回调 (FLAG_NOINTR)。有关详细信息,请参见 scsi_pkt(9S) 手册页。
超时值(以秒为单位)。如果命令在该时间内未完成,则主机总线适配器将调用完成例程,并将 pkt_reason 设置为 CMD_TIMEOUT。目标驱动程序应将该字段设置为大于命令可能需要的最长时间。如果超时值为零,则不请求超时。超时从在 SCSI 总线上传输命令时开始。
指向 SCSI 状态完成块的指针。该字段由主机总线适配器驱动程序填充。
指向 SCSI 命令描述符块(要发送到目标设备的实际命令)的指针。主机总线适配器驱动程序不会解释该字段。目标驱动程序必须使用目标设备可以处理的命令填充该字段。
剩余操作。pkt_resid 字段有两种不同的用途,具体取决于如何使用 pkt_resid。使用 pkt_resid 为命令 scsi_init_pkt(9F) 分配 DMA 资源时,pkt_resid 指示不可分配的字节数。由于 DMA 硬件具有分散/集中限制或其他设备限制,因此可能无法分配 DMA 资源。传输命令后,pkt_resid 指示不可传输的数据字节数。该字段由主机总线适配器驱动程序在调用完成例程之前填充。
指示命令的状态。主机总线适配器驱动程序在命令执行过程中填充该字段。该字段的每一位分别根据以下五种命令状态设置:
STATE_GOT_BUS-已获取总线
STATE_GOT_TARGET-已选定目标
STATE_SENT_CMD-已发送命令
STATE_XFERRED_DATA-已传输数据(如果适用)
STATE_GOT_STATUS-已从设备接收状态
包含与传输相关的统计信息(由主机总线适配器驱动程序设置)。
提供调用完成例程的原因。完成例程会对该字段进行解码。然后,执行相应的操作。如果命令完成(即未发生传输错误),则该字段将设置为 CMD_CMPLT。如果该字段中存在其他值,则指示发生了错误。完成命令后,目标驱动程序应检查 pkt_scbp 字段以查看条件状态。有关更多信息,请参见 scsi_pkt(9S) 手册页。