The _fini(9E) function is called when the system is about to try to unload the SCSI HBA driver. The _fini() function must call mod_remove(9F) to determine whether the driver can be unloaded. If mod_remove() returns 0, the module can be unloaded. The HBA driver must deallocate any global resources allocated in _init(9E). The HBA driver must also call scsi_hba_fini(9F).
_fini() must return the value returned by mod_remove().
The HBA driver must not free any resources or call scsi_hba_fini(9F) unless mod_remove(9F) returns 0.
Example 18–1 shows module initialization for SCSI HBA.
static struct dev_ops isp_dev_ops = {
DEVO_REV, /* devo_rev */
0, /* refcnt */
isp_getinfo, /* getinfo */
nulldev, /* identify */
nulldev, /* probe */
isp_attach, /* attach */
isp_detach, /* detach */
nodev, /* reset */
NULL, /* driver operations */
NULL, /* bus operations */
isp_power, /* power management */
isp_quiesce, /* quiesce */
};
/*
* 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);
}