本节介绍 SCSI HBA 驱动程序执行的操作的入口点。
以下 SCSI HBA 驱动程序代码说明了典型的 dev_ops(9S) 结构。该驱动程序必须将此结构中的 devo_bus_ops 字段初始化为 NULL。SCSI HBA 驱动程序可提供特殊用途的叶驱动程序接口,在这种情况下,devo_cb_ops 字段可能会指向 cb_ops(9S) 结构。在此示例中,由于未导出任何叶驱动程序接口,因此 devo_cb_ops 字段会初始化为 NULL。
_init(9E) 函数用于初始化可装入模块。_init() 在可装入模块中的其他任何例程之前调用。
在 SCSI HBA 中,_init() 函数在调用 mod_install(9F) 之前,必须先调用 scsi_hba_init(9F) 来通知框架是否存在 HBA 驱动程序。如果 scsi_hba__init () 返回非零值,则 _init() 应返回该值。否则,_init() 必须返回 mod_install(9F) 所返回的值。
该驱动程序在调用 mod_install(9F) 之前应初始化任何必需的全局状态。
如果 mod_install() 失败,则 _init() 函数必须释放分配的所有全局资源。_init() 必须在返回之前调用 scsi_hba_fini(9F)。
以下示例使用全局互斥锁说明如何分配对驱动程序的所有实例而言具有全局性的数据。该代码声明了全局互斥锁和软状态结构信息。全局互斥锁和软状态是在执行 _init() 的过程中初始化的。
如果系统准备尝试卸载 SCSI HBA 驱动程序,则会调用 _fini(9E) 函数。 _fini() 函数必须调用 mod_remove(9F) 来确定是否可以卸载该驱动程序。如果 mod_remove() 返回 0,则可以卸载该模块。HBA 驱动程序必须取消分配 _init(9E) 中分配的所有全局资源。HBA 驱动程序还必须调用 scsi_hba_fini(9F)。
_fini() 必须返回 mod_remove() 所返回的值。
除非 mod_remove(9F) 返回 0,否则 HBA 驱动程序决不能释放任何资源或调用 scsi_hba_fini(9F)。
示例 18–1 说明了 SCSI HBA 的模块初始化。
static struct dev_ops isp_dev_ops = { DEVO_REV, /* devo_rev */ 0, /* refcnt */ isp_getinfo, /* getinfo */ nulldev, /* probe */ isp_attach, /* attach */ isp_detach, /* detach */ nodev, /* reset */ NULL, /* driver operations */ NULL, /* bus operations */ isp_power, /* power management */ }; /* * Local static data */ static kmutex_t isp_global_mutex; static void *isp_state; int _init(void) { int err; if ((err = ddi_soft_state_init(&isp_state, sizeof (struct isp), 0)) != 0) { return (err); } if ((err = scsi_hba_init(&modlinkage)) == 0) { mutex_init(&isp_global_mutex, "isp global mutex", MUTEX_DRIVER, NULL); if ((err = mod_install(&modlinkage)) != 0) { mutex_destroy(&isp_global_mutex); scsi_hba_fini(&modlinkage); ddi_soft_state_fini(&isp_state); } } return (err); } int _fini(void) { int err; if ((err = mod_remove(&modlinkage)) == 0) { mutex_destroy(&isp_global_mutex); scsi_hba_fini(&modlinkage); ddi_soft_state_fini(&isp_state); } return (err); }