JavaScript is required to for searching.
跳过导航链接
退出打印视图
编写设备驱动程序     Oracle Solaris 11.1 Information Library (简体中文)
为本文档评分
search filter icon
search icon

文档信息

前言

第 1 部分针对 Oracle Solaris 平台设计设备驱动程序

1.  Oracle Solaris 设备驱动程序概述

2.  Oracle Solaris 内核和设备树

3.  多线程

4.  属性

5.  管理事件和排队任务

6.  驱动程序自动配置

7.  设备访问:程控 I/O

8.  中断处理程序

9.  直接内存访问 (Direct Memory Access, DMA)

10.  映射设备和内核内存

11.  设备上下文管理

12.  电源管理

13.  强化 Oracle Solaris 驱动程序

14.  分层驱动程序接口 (Layered Driver Interface, LDI)

第 2 部分设计特定种类的设备驱动程序

15.  字符设备驱动程序

16.  块设备驱动程序

17.  SCSI 目标驱动程序

18.  SCSI 主机总线适配器驱动程序

主机总线适配器驱动程序介绍

SCSI 接口

SCSA HBA 接口

SCSA HBA 入口点汇总

SCSA HBA 数据结构

scsi_hba_tran() 结构

scsi_address 结构

scsi_device 结构

scsi_pkt 结构 (HBA)

按目标实例的数据

传输结构克隆

SCSA HBA 函数

HBA 驱动程序的相关性和配置问题

声明和结构

每个命令的结构

模块初始化入口点

_init() 入口点(SCSI HBA 驱动程序)

_fini() 入口点(SCSI HBA 驱动程序)

自动配置入口点

attach() 入口点(SCSI HBA 驱动程序)

detach() 入口点(SCSI HBA 驱动程序)

SCSA HBA 驱动程序入口点

目标驱动程序实例初始化

tran_tgt_init() 入口点

tran_tgt_probe() 入口点

tran_tgt_free() 入口点

资源分配

tran_init_pkt() 入口点

分配和初始化 scsi_pkt(9S) 结构

分配 DMA 资源

重新分配用于数据传送的 DMA 资源

tran_destroy_pkt() 入口点

tran_sync_pkt() 入口点

tran_dmafree() 入口点

命令传输

tran_start() 入口点

中断处理程序和命令完成

超时处理程序

功能管理

tran_getcap() 入口点

tran_setcap() 入口点

中止和重置管理

tran_abort() 入口点

tran_reset() 入口点

tran_bus_reset() 入口点

tran_reset_notify() 入口点

动态重新配置

SCSI HBA 驱动程序特定问题

安装 HBA 驱动程序

HBA 配置属性

scsi-reset-delay 属性

scsi-options 属性

按目标的 scsi-options

x86 目标驱动程序配置属性

排队支持

19.  网络设备驱动程序

20.  USB 驱动程序

21.  SR-IOV 驱动程序

第 3 部分生成设备驱动程序

22.  编译、装入、打包和测试驱动程序

23.  调试、测试和调优设备驱动程序

24.  推荐的编码方法

第 4 部分附录

A.  硬件概述

B.  Oracle Solaris DDI/DKI 服务汇总

C.  使设备驱动程序支持 64 位

D.  控制台帧缓存器驱动程序

E.  pci.conf 文件

索引

请告诉我们如何提高我们的文档:
过于简略
不易阅读或难以理解
重要信息缺失
错误的内容
需要翻译的版本
其他
Your rating has been updated
感谢您的反馈!

您的反馈将非常有助于我们提供更好的文档。 您是否愿意参与我们的内容改进并提供进一步的意见?

SCSA HBA 接口

SCSA HBA 接口包括 HBA 入口点、HBA 数据结构和 HBA 框架。

SCSA HBA 入口点汇总

SCSA 定义了许多 HBA 驱动程序入口点。下表中列出了这些入口点。配置连接到 HBA 驱动程序的目标驱动程序实例时,系统将会调用这些入口点。另外,目标驱动程序发出 SCSA 请求时,也会调用这些入口点。有关更多信息,请参见SCSA HBA 驱动程序入口点

表 18-1 SCSA HBA 入口点汇总

函数名
调用原因
目标驱动程序调用 scsi_abort(9F)
系统重置总线
目标驱动程序调用 scsi_destroy_pkt(9F)
目标驱动程序调用 scsi_dmafree(9F)
目标驱动程序调用 scsi_ifgetcap(9F)
目标驱动程序调用 scsi_init_pkt(9F)
系统停止总线
目标驱动程序调用 scsi_reset(9F)
目标驱动程序调用 scsi_reset_notify(9F)
目标驱动程序调用 scsi_ifsetcap(9F)
目标驱动程序调用 scsi_transport(9F)
目标驱动程序调用 scsi_sync_pkt(9F)
tran_tgt_free(9E)
系统分离目标设备实例
tran_tgt_init(9E)
系统连接目标设备实例
tran_tgt_probe(9E)
目标驱动程序调用 scsi_probe(9F)
系统恢复总线上的活动

SCSA HBA 数据结构

SCSA 定义了多种数据结构,以便可在目标驱动程序和 HBA 驱动程序之间交换信息。其中包括以下数据结构:

scsi_hba_tran() 结构

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 结构字段的更多信息:

tran_hba_dip

指向 HBA 设备实例 dev_info 结构的指针。函数 scsi_hba_attach_setup(9F) 可用于设置此字段。

tran_hba_private

指向 HBA 驱动程序维护的专用数据的指针。通常,tran_hba_private 包含指向 HBA 驱动程序状态结构的指针。

tran_tgt_private

指向使用克隆时 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_privateNULL,并且决不能引用 tran_tgt_private。有关更多信息,请参见传输结构克隆

tran_sd

指向克隆时使用的按目标实例的 scsi_device(9S) 结构的指针。如果将 SCSI_HBA_TRAN_CLONE 传递给 scsi_hba_attach_setup(9F),则 tran_sd 会初始化指向按目标的 scsi_device 结构。在代表目标调用任何 HBA 函数之前,将进行此初始化。如果未指定 SCSI_HBA_TRAN_CLONE,则 tran_sdNULL,并且决不能引用 tran_sd。有关更多信息,请参见传输结构克隆

tran_tgt_init

指向初始化目标设备实例时调用的 HBA 驱动程序入口点的指针。如果无需进行按目标的初始化,则 HBA 可保持将 tran_tgt_init 设置为 NULL

tran_tgt_probe

指向在目标驱动程序实例调用 scsi_probe(9F) 时调用的 HBA 驱动程序入口点的指针。调用该例程可探测目标设备是否存在。如果此 HBA 无需进行目标探测定制,则 HBA 应将 tran_tgt_probe 设置为 scsi_hba_probe(9F)

tran_tgt_free

指向在目标设备实例被销毁时调用的 HBA 驱动程序入口点的指针。如果无需进行按目标的取消分配,则 HBA 可保持将 tran_tgt_free 设置为 NULL

tran_start

指向在目标驱动程序调用 scsi_transport(9F) 时调用的 HBA 驱动程序入口点的指针。

tran_reset

指向在目标驱动程序调用 scsi_reset(9F) 时调用的 HBA 驱动程序入口点的指针。

tran_abort

指向在目标驱动程序调用 scsi_abort(9F) 时调用的 HBA 驱动程序入口点的指针。

tran_getcap

指向在目标驱动程序调用 scsi_ifgetcap(9F) 时调用的 HBA 驱动程序入口点的指针。

tran_setcap

指向在目标驱动程序调用 scsi_ifsetcap(9F) 时调用的 HBA 驱动程序入口点的指针。

tran_init_pkt

指向在目标驱动程序调用 scsi_init_pkt(9F) 时调用的 HBA 驱动程序入口点的指针。

tran_destroy_pkt

指向在目标驱动程序调用 scsi_destroy_pkt(9F) 时调用的 HBA 驱动程序入口点的指针。

tran_dmafree

指向在目标驱动程序调用 scsi_dmafree(9F) 时调用的 HBA 驱动程序入口点的指针。

tran_sync_pkt

指向在目标驱动程序调用 scsi_sync_pkt(9F) 时调用的 HBA 驱动程序入口点的指针。

tran_reset_notify

指向在目标驱动程序调用 tran_reset_notify(9E) 时调用的 HBA 驱动程序入口点的指针。

tran_bus_reset

重置 SCSI 总线但不重置目标的函数项。

tran_quiesce

等待所有未完成的命令完成并阻塞(或排队)任何发出的 I/O 请求的函数项。

tran_unquiesce

允许 I/O 活动在 SCSI 总线上恢复的函数项。

tran_interconnect_type

表示 services.h 头文件中定义的传输互连类型的整数值。

scsi_address 结构

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 */
};
a_hba_tran

指向 HBA 驱动程序分配和初始化的 scsi_hba_tran(9S) 结构的指针。如果将 SCSI_HBA_TRAN_CLONE 指定为 scsi_hba_attach_setup(9F) 的标志, 则 a_hba_tran 指向该结构的副本。

a_target

标识 SCSI 总线上的 SCSI 目标。

a_lun

标识 SCSI 目标的 SCSI 逻辑单元。

scsi_device 结构

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 */
};

其中:

sd_address

为了进行 SCSI 资源分配而传递给例程的数据结构。

sd_dev

指向目标的 dev_info 结构的指针。

sd_mutex

供目标驱动程序使用的互斥锁。此互斥锁通过 HBA 框架进行初始化。目标驱动程序可将此互斥锁用作按设备的互斥锁。在调用 scsi_transport(9F)scsi_poll(9F) 期间,不应持有此互斥锁。有关互斥锁的更多信息,请参见第 3 章

sd_inq

目标设备的 SCSI 查询数据的指针。scsi_probe(9F) 例程可用于分配缓冲区、填充该缓冲区并将该缓冲区附加到此字段。

sd_sense

指向用于包含设备中的请求检测数据的缓冲区的指针。目标驱动程序必须分配和管理此缓冲区本身。有关更多信息,请参见attach() 入口点中目标驱动程序的 attach(9E) 例程。

sd_private

供目标驱动程序使用的指针字段。此字段通常用于存储指向专用目标驱动程序状态结构的指针。

scsi_pkt 结构 (HBA)

要执行 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 */
};

其中:

pkt_ha_private

指向按命令的 HBA 驱动程序专用数据的指针。

pkt_address

指向用于为此命令提供地址信息的 scsi_address(9S) 结构的指针。

pkt_private

指向按包的目标驱动程序专用数据的指针。

pkt_comp

指向在传输层完成此命令时 HBA 驱动程序调用的目标驱动程序完成例程的指针。

pkt_flags

命令的标志。

pkt_time

指定命令的完成超时时间(以秒为单位)。

pkt_scbp

指向命令的状态完成块的指针。

pkt_cdbp

指向命令的命令描述符块 (command descriptor block, CDB) 的指针。

pkt_resid

命令完成时传送的数据字节计数。此字段也可能会用于指定尚未分配资源的数据量。在传输过程中,HBA 必须修改此字段。

pkt_state

命令的状态。在传输过程中,HBA 必须修改此字段。

pkt_statistics

提供命令在传输层中发生的事件的历史记录。在传输过程中,HBA 必须修改此字段。

pkt_reason

命令完成的原因。在传输过程中,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 传输结构

image:图中显示了 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_targeta_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 克隆传输操作

image:图中显示了克隆的 HBA 结构的示例。

SCSA HBA 函数

SCSA 还提供了许多函数。下表中列出了这些函数,供 HBA 驱动程序使用。

表 18-2 SCSA HBA 函数

函数名
进行调用的驱动程序入口点