Writing Device Drivers

_fini(9E)

The _fini(9E) function is called when the system is about to try to unload the SCSI HBA driver. The _fini(9E) function must call mod_remove(9F) to determine if the driver can be unloaded. If mod_remove(9F) returns 0, the module can be unloaded, and the HBA driver must deallocate any global resources allocated in _init(9E) and must call scsi_hba_fini(9F).

_fini(9E) must return the value returned by mod_remove(9F).


Note -

The HBA driver must not free any resources or call scsi_hba_fini(9F) unless mod_remove(9F) returns 0.


Example 15-1 shows SCSI HBA module intialization.


Example 15-1 SCSI HBA Module Initialization

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);
}