2009-09-23 17:46:15 -07:00
/*
* Copyright ( c ) 2005 - 2009 Brocade Communications Systems , Inc .
* All rights reserved
* www . brocade . com
*
* Linux driver for Brocade Fibre Channel Host Bus Adapter .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License ( GPL ) Version 2 as
* published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*/
/**
* bfad . c Linux driver PCI interface module .
*/
# include <linux/module.h>
# include "bfad_drv.h"
# include "bfad_im.h"
# include "bfad_tm.h"
# include "bfad_ipfc.h"
# include "bfad_trcmod.h"
# include <fcb/bfa_fcb_vf.h>
# include <fcb/bfa_fcb_rport.h>
# include <fcb/bfa_fcb_port.h>
# include <fcb/bfa_fcb.h>
BFA_TRC_FILE ( LDRV , BFAD ) ;
static DEFINE_MUTEX ( bfad_mutex ) ;
LIST_HEAD ( bfad_list ) ;
static int bfad_inst ;
int bfad_supported_fc4s ;
static char * host_name ;
static char * os_name ;
static char * os_patch ;
static int num_rports ;
static int num_ios ;
static int num_tms ;
static int num_fcxps ;
static int num_ufbufs ;
static int reqq_size ;
static int rspq_size ;
static int num_sgpgs ;
static int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT ;
static int bfa_io_max_sge = BFAD_IO_MAX_SGE ;
static int log_level = BFA_LOG_WARNING ;
static int ioc_auto_recover = BFA_TRUE ;
static int ipfc_enable = BFA_FALSE ;
static int ipfc_mtu = - 1 ;
int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH ;
int bfa_linkup_delay = - 1 ;
module_param ( os_name , charp , S_IRUGO | S_IWUSR ) ;
module_param ( os_patch , charp , S_IRUGO | S_IWUSR ) ;
module_param ( host_name , charp , S_IRUGO | S_IWUSR ) ;
module_param ( num_rports , int , S_IRUGO | S_IWUSR ) ;
module_param ( num_ios , int , S_IRUGO | S_IWUSR ) ;
module_param ( num_tms , int , S_IRUGO | S_IWUSR ) ;
module_param ( num_fcxps , int , S_IRUGO | S_IWUSR ) ;
module_param ( num_ufbufs , int , S_IRUGO | S_IWUSR ) ;
module_param ( reqq_size , int , S_IRUGO | S_IWUSR ) ;
module_param ( rspq_size , int , S_IRUGO | S_IWUSR ) ;
module_param ( num_sgpgs , int , S_IRUGO | S_IWUSR ) ;
module_param ( rport_del_timeout , int , S_IRUGO | S_IWUSR ) ;
module_param ( bfa_lun_queue_depth , int , S_IRUGO | S_IWUSR ) ;
module_param ( bfa_io_max_sge , int , S_IRUGO | S_IWUSR ) ;
module_param ( log_level , int , S_IRUGO | S_IWUSR ) ;
module_param ( ioc_auto_recover , int , S_IRUGO | S_IWUSR ) ;
module_param ( ipfc_enable , int , S_IRUGO | S_IWUSR ) ;
module_param ( ipfc_mtu , int , S_IRUGO | S_IWUSR ) ;
module_param ( bfa_linkup_delay , int , S_IRUGO | S_IWUSR ) ;
/*
* Stores the module parm num_sgpgs value ;
* used to reset for bfad next instance .
*/
static int num_sgpgs_parm ;
static bfa_status_t
bfad_fc4_probe ( struct bfad_s * bfad )
{
int rc ;
rc = bfad_im_probe ( bfad ) ;
if ( rc ! = BFA_STATUS_OK )
goto ext ;
bfad_tm_probe ( bfad ) ;
if ( ipfc_enable )
bfad_ipfc_probe ( bfad ) ;
ext :
return rc ;
}
static void
bfad_fc4_probe_undo ( struct bfad_s * bfad )
{
bfad_im_probe_undo ( bfad ) ;
bfad_tm_probe_undo ( bfad ) ;
if ( ipfc_enable )
bfad_ipfc_probe_undo ( bfad ) ;
}
static void
bfad_fc4_probe_post ( struct bfad_s * bfad )
{
if ( bfad - > im )
bfad_im_probe_post ( bfad - > im ) ;
bfad_tm_probe_post ( bfad ) ;
if ( ipfc_enable )
bfad_ipfc_probe_post ( bfad ) ;
}
static bfa_status_t
bfad_fc4_port_new ( struct bfad_s * bfad , struct bfad_port_s * port , int roles )
{
int rc = BFA_STATUS_FAILED ;
if ( roles & BFA_PORT_ROLE_FCP_IM )
rc = bfad_im_port_new ( bfad , port ) ;
if ( rc ! = BFA_STATUS_OK )
goto ext ;
if ( roles & BFA_PORT_ROLE_FCP_TM )
rc = bfad_tm_port_new ( bfad , port ) ;
if ( rc ! = BFA_STATUS_OK )
goto ext ;
if ( ( roles & BFA_PORT_ROLE_FCP_IPFC ) & & ipfc_enable )
rc = bfad_ipfc_port_new ( bfad , port , port - > pvb_type ) ;
ext :
return rc ;
}
static void
bfad_fc4_port_delete ( struct bfad_s * bfad , struct bfad_port_s * port , int roles )
{
if ( roles & BFA_PORT_ROLE_FCP_IM )
bfad_im_port_delete ( bfad , port ) ;
if ( roles & BFA_PORT_ROLE_FCP_TM )
bfad_tm_port_delete ( bfad , port ) ;
if ( ( roles & BFA_PORT_ROLE_FCP_IPFC ) & & ipfc_enable )
bfad_ipfc_port_delete ( bfad , port ) ;
}
/**
* BFA callbacks
*/
void
bfad_hcb_comp ( void * arg , bfa_status_t status )
{
struct bfad_hal_comp * fcomp = ( struct bfad_hal_comp * ) arg ;
fcomp - > status = status ;
complete ( & fcomp - > comp ) ;
}
/**
* bfa_init callback
*/
void
bfa_cb_init ( void * drv , bfa_status_t init_status )
{
struct bfad_s * bfad = drv ;
if ( init_status = = BFA_STATUS_OK )
bfad - > bfad_flags | = BFAD_HAL_INIT_DONE ;
complete ( & bfad - > comp ) ;
}
/**
* BFA_FCS callbacks
*/
static struct bfad_port_s *
bfad_get_drv_port ( struct bfad_s * bfad , struct bfad_vf_s * vf_drv ,
struct bfad_vport_s * vp_drv )
{
2009-09-25 12:29:54 -07:00
return ( vp_drv ) ? ( & ( vp_drv ) - > drv_port )
: ( ( vf_drv ) ? ( & ( vf_drv ) - > base_port ) : ( & ( bfad ) - > pport ) ) ;
2009-09-23 17:46:15 -07:00
}
struct bfad_port_s *
bfa_fcb_port_new ( struct bfad_s * bfad , struct bfa_fcs_port_s * port ,
enum bfa_port_role roles , struct bfad_vf_s * vf_drv ,
struct bfad_vport_s * vp_drv )
{
bfa_status_t rc ;
struct bfad_port_s * port_drv ;
if ( ! vp_drv & & ! vf_drv ) {
port_drv = & bfad - > pport ;
port_drv - > pvb_type = BFAD_PORT_PHYS_BASE ;
} else if ( ! vp_drv & & vf_drv ) {
port_drv = & vf_drv - > base_port ;
port_drv - > pvb_type = BFAD_PORT_VF_BASE ;
} else if ( vp_drv & & ! vf_drv ) {
port_drv = & vp_drv - > drv_port ;
port_drv - > pvb_type = BFAD_PORT_PHYS_VPORT ;
} else {
port_drv = & vp_drv - > drv_port ;
port_drv - > pvb_type = BFAD_PORT_VF_VPORT ;
}
port_drv - > fcs_port = port ;
port_drv - > roles = roles ;
rc = bfad_fc4_port_new ( bfad , port_drv , roles ) ;
if ( rc ! = BFA_STATUS_OK ) {
bfad_fc4_port_delete ( bfad , port_drv , roles ) ;
port_drv = NULL ;
}
return port_drv ;
}
void
bfa_fcb_port_delete ( struct bfad_s * bfad , enum bfa_port_role roles ,
struct bfad_vf_s * vf_drv , struct bfad_vport_s * vp_drv )
{
struct bfad_port_s * port_drv ;
/*
* this will be only called from rmmod context
*/
if ( vp_drv & & ! vp_drv - > comp_del ) {
port_drv = bfad_get_drv_port ( bfad , vf_drv , vp_drv ) ;
bfa_trc ( bfad , roles ) ;
bfad_fc4_port_delete ( bfad , port_drv , roles ) ;
}
}
void
bfa_fcb_port_online ( struct bfad_s * bfad , enum bfa_port_role roles ,
struct bfad_vf_s * vf_drv , struct bfad_vport_s * vp_drv )
{
struct bfad_port_s * port_drv = bfad_get_drv_port ( bfad , vf_drv , vp_drv ) ;
if ( roles & BFA_PORT_ROLE_FCP_IM )
bfad_im_port_online ( bfad , port_drv ) ;
if ( roles & BFA_PORT_ROLE_FCP_TM )
bfad_tm_port_online ( bfad , port_drv ) ;
if ( ( roles & BFA_PORT_ROLE_FCP_IPFC ) & & ipfc_enable )
bfad_ipfc_port_online ( bfad , port_drv ) ;
bfad - > bfad_flags | = BFAD_PORT_ONLINE ;
}
void
bfa_fcb_port_offline ( struct bfad_s * bfad , enum bfa_port_role roles ,
struct bfad_vf_s * vf_drv , struct bfad_vport_s * vp_drv )
{
struct bfad_port_s * port_drv = bfad_get_drv_port ( bfad , vf_drv , vp_drv ) ;
if ( roles & BFA_PORT_ROLE_FCP_IM )
bfad_im_port_offline ( bfad , port_drv ) ;
if ( roles & BFA_PORT_ROLE_FCP_TM )
bfad_tm_port_offline ( bfad , port_drv ) ;
if ( ( roles & BFA_PORT_ROLE_FCP_IPFC ) & & ipfc_enable )
bfad_ipfc_port_offline ( bfad , port_drv ) ;
}
void
bfa_fcb_vport_delete ( struct bfad_vport_s * vport_drv )
{
if ( vport_drv - > comp_del ) {
complete ( vport_drv - > comp_del ) ;
return ;
}
kfree ( vport_drv ) ;
}
/**
* FCS RPORT alloc callback , after successful PLOGI by FCS
*/
bfa_status_t
bfa_fcb_rport_alloc ( struct bfad_s * bfad , struct bfa_fcs_rport_s * * rport ,
struct bfad_rport_s * * rport_drv )
{
bfa_status_t rc = BFA_STATUS_OK ;
* rport_drv = kzalloc ( sizeof ( struct bfad_rport_s ) , GFP_ATOMIC ) ;
if ( * rport_drv = = NULL ) {
rc = BFA_STATUS_ENOMEM ;
goto ext ;
}
* rport = & ( * rport_drv ) - > fcs_rport ;
ext :
return rc ;
}
void
bfad_hal_mem_release ( struct bfad_s * bfad )
{
int i ;
struct bfa_meminfo_s * hal_meminfo = & bfad - > meminfo ;
struct bfa_mem_elem_s * meminfo_elem ;
for ( i = 0 ; i < BFA_MEM_TYPE_MAX ; i + + ) {
meminfo_elem = & hal_meminfo - > meminfo [ i ] ;
if ( meminfo_elem - > kva ! = NULL ) {
switch ( meminfo_elem - > mem_type ) {
case BFA_MEM_TYPE_KVA :
vfree ( meminfo_elem - > kva ) ;
break ;
case BFA_MEM_TYPE_DMA :
dma_free_coherent ( & bfad - > pcidev - > dev ,
meminfo_elem - > mem_len ,
meminfo_elem - > kva ,
( dma_addr_t ) meminfo_elem - > dma ) ;
break ;
default :
bfa_assert ( 0 ) ;
break ;
}
}
}
memset ( hal_meminfo , 0 , sizeof ( struct bfa_meminfo_s ) ) ;
}
void
bfad_update_hal_cfg ( struct bfa_iocfc_cfg_s * bfa_cfg )
{
if ( num_rports > 0 )
bfa_cfg - > fwcfg . num_rports = num_rports ;
if ( num_ios > 0 )
bfa_cfg - > fwcfg . num_ioim_reqs = num_ios ;
if ( num_tms > 0 )
bfa_cfg - > fwcfg . num_tskim_reqs = num_tms ;
if ( num_fcxps > 0 )
bfa_cfg - > fwcfg . num_fcxp_reqs = num_fcxps ;
if ( num_ufbufs > 0 )
bfa_cfg - > fwcfg . num_uf_bufs = num_ufbufs ;
if ( reqq_size > 0 )
bfa_cfg - > drvcfg . num_reqq_elems = reqq_size ;
if ( rspq_size > 0 )
bfa_cfg - > drvcfg . num_rspq_elems = rspq_size ;
if ( num_sgpgs > 0 )
bfa_cfg - > drvcfg . num_sgpgs = num_sgpgs ;
/*
* populate the hal values back to the driver for sysfs use .
* otherwise , the default values will be shown as 0 in sysfs
*/
num_rports = bfa_cfg - > fwcfg . num_rports ;
num_ios = bfa_cfg - > fwcfg . num_ioim_reqs ;
num_tms = bfa_cfg - > fwcfg . num_tskim_reqs ;
num_fcxps = bfa_cfg - > fwcfg . num_fcxp_reqs ;
num_ufbufs = bfa_cfg - > fwcfg . num_uf_bufs ;
reqq_size = bfa_cfg - > drvcfg . num_reqq_elems ;
rspq_size = bfa_cfg - > drvcfg . num_rspq_elems ;
num_sgpgs = bfa_cfg - > drvcfg . num_sgpgs ;
}
bfa_status_t
bfad_hal_mem_alloc ( struct bfad_s * bfad )
{
struct bfa_meminfo_s * hal_meminfo = & bfad - > meminfo ;
struct bfa_mem_elem_s * meminfo_elem ;
bfa_status_t rc = BFA_STATUS_OK ;
dma_addr_t phys_addr ;
int retry_count = 0 ;
int reset_value = 1 ;
int min_num_sgpgs = 512 ;
void * kva ;
int i ;
bfa_cfg_get_default ( & bfad - > ioc_cfg ) ;
retry :
bfad_update_hal_cfg ( & bfad - > ioc_cfg ) ;
bfad - > cfg_data . ioc_queue_depth = bfad - > ioc_cfg . fwcfg . num_ioim_reqs ;
bfa_cfg_get_meminfo ( & bfad - > ioc_cfg , hal_meminfo ) ;
for ( i = 0 ; i < BFA_MEM_TYPE_MAX ; i + + ) {
meminfo_elem = & hal_meminfo - > meminfo [ i ] ;
switch ( meminfo_elem - > mem_type ) {
case BFA_MEM_TYPE_KVA :
kva = vmalloc ( meminfo_elem - > mem_len ) ;
if ( kva = = NULL ) {
bfad_hal_mem_release ( bfad ) ;
rc = BFA_STATUS_ENOMEM ;
goto ext ;
}
memset ( kva , 0 , meminfo_elem - > mem_len ) ;
meminfo_elem - > kva = kva ;
break ;
case BFA_MEM_TYPE_DMA :
kva = dma_alloc_coherent ( & bfad - > pcidev - > dev ,
meminfo_elem - > mem_len ,
& phys_addr , GFP_KERNEL ) ;
if ( kva = = NULL ) {
bfad_hal_mem_release ( bfad ) ;
/*
* If we cannot allocate with default
* num_sgpages try with half the value .
*/
if ( num_sgpgs > min_num_sgpgs ) {
printk ( KERN_INFO " bfad[%d]: memory "
" allocation failed with "
" num_sgpgs: %d \n " ,
bfad - > inst_no , num_sgpgs ) ;
nextLowerInt ( & num_sgpgs ) ;
printk ( KERN_INFO " bfad[%d]: trying to "
" allocate memory with "
" num_sgpgs: %d \n " ,
bfad - > inst_no , num_sgpgs ) ;
retry_count + + ;
goto retry ;
} else {
if ( num_sgpgs_parm > 0 )
num_sgpgs = num_sgpgs_parm ;
else {
reset_value =
( 1 < < retry_count ) ;
num_sgpgs * = reset_value ;
}
rc = BFA_STATUS_ENOMEM ;
goto ext ;
}
}
if ( num_sgpgs_parm > 0 )
num_sgpgs = num_sgpgs_parm ;
else {
reset_value = ( 1 < < retry_count ) ;
num_sgpgs * = reset_value ;
}
memset ( kva , 0 , meminfo_elem - > mem_len ) ;
meminfo_elem - > kva = kva ;
meminfo_elem - > dma = phys_addr ;
break ;
default :
break ;
}
}
ext :
return rc ;
}
/**
* Create a vport under a vf .
*/
bfa_status_t
bfad_vport_create ( struct bfad_s * bfad , u16 vf_id ,
struct bfa_port_cfg_s * port_cfg )
{
struct bfad_vport_s * vport ;
int rc = BFA_STATUS_OK ;
unsigned long flags ;
struct completion fcomp ;
vport = kzalloc ( sizeof ( struct bfad_vport_s ) , GFP_KERNEL ) ;
if ( ! vport ) {
rc = BFA_STATUS_ENOMEM ;
goto ext ;
}
vport - > drv_port . bfad = bfad ;
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
rc = bfa_fcs_vport_create ( & vport - > fcs_vport , & bfad - > bfa_fcs , vf_id ,
port_cfg , vport ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
if ( rc ! = BFA_STATUS_OK )
goto ext_free_vport ;
if ( port_cfg - > roles & BFA_PORT_ROLE_FCP_IM ) {
rc = bfad_im_scsi_host_alloc ( bfad , vport - > drv_port . im_port ) ;
if ( rc ! = BFA_STATUS_OK )
goto ext_free_fcs_vport ;
}
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
bfa_fcs_vport_start ( & vport - > fcs_vport ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
return BFA_STATUS_OK ;
ext_free_fcs_vport :
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
vport - > comp_del = & fcomp ;
init_completion ( vport - > comp_del ) ;
bfa_fcs_vport_delete ( & vport - > fcs_vport ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
wait_for_completion ( vport - > comp_del ) ;
ext_free_vport :
kfree ( vport ) ;
ext :
return rc ;
}
/**
* Create a vf and its base vport implicitely .
*/
bfa_status_t
bfad_vf_create ( struct bfad_s * bfad , u16 vf_id ,
struct bfa_port_cfg_s * port_cfg )
{
struct bfad_vf_s * vf ;
int rc = BFA_STATUS_OK ;
vf = kzalloc ( sizeof ( struct bfad_vf_s ) , GFP_KERNEL ) ;
if ( ! vf ) {
rc = BFA_STATUS_FAILED ;
goto ext ;
}
rc = bfa_fcs_vf_create ( & vf - > fcs_vf , & bfad - > bfa_fcs , vf_id , port_cfg ,
vf ) ;
if ( rc ! = BFA_STATUS_OK )
kfree ( vf ) ;
ext :
return rc ;
}
void
bfad_bfa_tmo ( unsigned long data )
{
struct bfad_s * bfad = ( struct bfad_s * ) data ;
unsigned long flags ;
struct list_head doneq ;
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
bfa_timer_tick ( & bfad - > bfa ) ;
bfa_comp_deq ( & bfad - > bfa , & doneq ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
if ( ! list_empty ( & doneq ) ) {
bfa_comp_process ( & bfad - > bfa , & doneq ) ;
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
bfa_comp_free ( & bfad - > bfa , & doneq ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
}
mod_timer ( & bfad - > hal_tmo , jiffies + msecs_to_jiffies ( BFA_TIMER_FREQ ) ) ;
}
void
bfad_init_timer ( struct bfad_s * bfad )
{
init_timer ( & bfad - > hal_tmo ) ;
bfad - > hal_tmo . function = bfad_bfa_tmo ;
bfad - > hal_tmo . data = ( unsigned long ) bfad ;
mod_timer ( & bfad - > hal_tmo , jiffies + msecs_to_jiffies ( BFA_TIMER_FREQ ) ) ;
}
int
bfad_pci_init ( struct pci_dev * pdev , struct bfad_s * bfad )
{
unsigned long bar0_len ;
int rc = - ENODEV ;
if ( pci_enable_device ( pdev ) ) {
BFA_PRINTF ( BFA_ERR , " pci_enable_device fail %p \n " , pdev ) ;
goto out ;
}
if ( pci_request_regions ( pdev , BFAD_DRIVER_NAME ) )
goto out_disable_device ;
pci_set_master ( pdev ) ;
if ( pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 64 ) ) ! = 0 )
if ( pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 32 ) ) ! = 0 ) {
BFA_PRINTF ( BFA_ERR , " pci_set_dma_mask fail %p \n " , pdev ) ;
goto out_release_region ;
}
bfad - > pci_bar0_map = pci_resource_start ( pdev , 0 ) ;
bar0_len = pci_resource_len ( pdev , 0 ) ;
bfad - > pci_bar0_kva = ioremap ( bfad - > pci_bar0_map , bar0_len ) ;
if ( bfad - > pci_bar0_kva = = NULL ) {
BFA_PRINTF ( BFA_ERR , " Fail to map bar0 \n " ) ;
goto out_release_region ;
}
bfad - > hal_pcidev . pci_slot = PCI_SLOT ( pdev - > devfn ) ;
bfad - > hal_pcidev . pci_func = PCI_FUNC ( pdev - > devfn ) ;
bfad - > hal_pcidev . pci_bar_kva = bfad - > pci_bar0_kva ;
bfad - > hal_pcidev . device_id = pdev - > device ;
bfad - > pci_name = pci_name ( pdev ) ;
bfad - > pci_attr . vendor_id = pdev - > vendor ;
bfad - > pci_attr . device_id = pdev - > device ;
bfad - > pci_attr . ssid = pdev - > subsystem_device ;
bfad - > pci_attr . ssvid = pdev - > subsystem_vendor ;
bfad - > pci_attr . pcifn = PCI_FUNC ( pdev - > devfn ) ;
bfad - > pcidev = pdev ;
return 0 ;
out_release_region :
pci_release_regions ( pdev ) ;
out_disable_device :
pci_disable_device ( pdev ) ;
out :
return rc ;
}
void
bfad_pci_uninit ( struct pci_dev * pdev , struct bfad_s * bfad )
{
# if defined(__ia64__)
pci_iounmap ( pdev , bfad - > pci_bar0_kva ) ;
# else
iounmap ( bfad - > pci_bar0_kva ) ;
# endif
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
pci_set_drvdata ( pdev , NULL ) ;
}
void
bfad_fcs_port_cfg ( struct bfad_s * bfad )
{
struct bfa_port_cfg_s port_cfg ;
struct bfa_pport_attr_s attr ;
char symname [ BFA_SYMNAME_MAXLEN ] ;
sprintf ( symname , " %s-%d " , BFAD_DRIVER_NAME , bfad - > inst_no ) ;
memcpy ( port_cfg . sym_name . symname , symname , strlen ( symname ) ) ;
bfa_pport_get_attr ( & bfad - > bfa , & attr ) ;
port_cfg . nwwn = attr . nwwn ;
port_cfg . pwwn = attr . pwwn ;
bfa_fcs_cfg_base_port ( & bfad - > bfa_fcs , & port_cfg ) ;
}
bfa_status_t
bfad_drv_init ( struct bfad_s * bfad )
{
bfa_status_t rc ;
unsigned long flags ;
struct bfa_fcs_driver_info_s driver_info ;
int i ;
bfad - > cfg_data . rport_del_timeout = rport_del_timeout ;
bfad - > cfg_data . lun_queue_depth = bfa_lun_queue_depth ;
bfad - > cfg_data . io_max_sge = bfa_io_max_sge ;
bfad - > cfg_data . binding_method = FCP_PWWN_BINDING ;
rc = bfad_hal_mem_alloc ( bfad ) ;
if ( rc ! = BFA_STATUS_OK ) {
printk ( KERN_WARNING " bfad%d bfad_hal_mem_alloc failure \n " ,
bfad - > inst_no ) ;
printk ( KERN_WARNING
" Not enough memory to attach all Brocade HBA ports, "
" System may need more memory. \n " ) ;
goto out_hal_mem_alloc_failure ;
}
bfa_init_log ( & bfad - > bfa , bfad - > logmod ) ;
bfa_init_trc ( & bfad - > bfa , bfad - > trcmod ) ;
bfa_init_aen ( & bfad - > bfa , bfad - > aen ) ;
INIT_LIST_HEAD ( & bfad - > file_q ) ;
INIT_LIST_HEAD ( & bfad - > file_free_q ) ;
for ( i = 0 ; i < BFAD_AEN_MAX_APPS ; i + + ) {
bfa_q_qe_init ( & bfad - > file_buf [ i ] . qe ) ;
list_add_tail ( & bfad - > file_buf [ i ] . qe , & bfad - > file_free_q ) ;
}
bfa_init_plog ( & bfad - > bfa , & bfad - > plog_buf ) ;
bfa_plog_init ( & bfad - > plog_buf ) ;
bfa_plog_str ( & bfad - > plog_buf , BFA_PL_MID_DRVR , BFA_PL_EID_DRIVER_START ,
0 , " Driver Attach " ) ;
bfa_attach ( & bfad - > bfa , bfad , & bfad - > ioc_cfg , & bfad - > meminfo ,
& bfad - > hal_pcidev ) ;
init_completion ( & bfad - > comp ) ;
/*
* Enable Interrupt and wait bfa_init completion
*/
if ( bfad_setup_intr ( bfad ) ) {
printk ( KERN_WARNING " bfad%d: bfad_setup_intr failed \n " ,
bfad - > inst_no ) ;
goto out_setup_intr_failure ;
}
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
bfa_init ( & bfad - > bfa ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
/*
* Set up interrupt handler for each vectors
*/
if ( ( bfad - > bfad_flags & BFAD_MSIX_ON )
& & bfad_install_msix_handler ( bfad ) ) {
printk ( KERN_WARNING " %s: install_msix failed, bfad%d \n " ,
2009-09-25 12:29:54 -07:00
__func__ , bfad - > inst_no ) ;
2009-09-23 17:46:15 -07:00
}
bfad_init_timer ( bfad ) ;
wait_for_completion ( & bfad - > comp ) ;
memset ( & driver_info , 0 , sizeof ( driver_info ) ) ;
strncpy ( driver_info . version , BFAD_DRIVER_VERSION ,
sizeof ( driver_info . version ) - 1 ) ;
if ( host_name )
strncpy ( driver_info . host_machine_name , host_name ,
sizeof ( driver_info . host_machine_name ) - 1 ) ;
if ( os_name )
strncpy ( driver_info . host_os_name , os_name ,
sizeof ( driver_info . host_os_name ) - 1 ) ;
if ( os_patch )
strncpy ( driver_info . host_os_patch , os_patch ,
sizeof ( driver_info . host_os_patch ) - 1 ) ;
strncpy ( driver_info . os_device_name , bfad - > pci_name ,
sizeof ( driver_info . os_device_name - 1 ) ) ;
/*
* FCS INIT
*/
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
bfa_fcs_log_init ( & bfad - > bfa_fcs , bfad - > logmod ) ;
bfa_fcs_trc_init ( & bfad - > bfa_fcs , bfad - > trcmod ) ;
bfa_fcs_aen_init ( & bfad - > bfa_fcs , bfad - > aen ) ;
bfa_fcs_init ( & bfad - > bfa_fcs , & bfad - > bfa , bfad , BFA_FALSE ) ;
bfa_fcs_driver_info_init ( & bfad - > bfa_fcs , & driver_info ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
bfad - > bfad_flags | = BFAD_DRV_INIT_DONE ;
return BFA_STATUS_OK ;
out_setup_intr_failure :
bfa_detach ( & bfad - > bfa ) ;
bfad_hal_mem_release ( bfad ) ;
out_hal_mem_alloc_failure :
return BFA_STATUS_FAILED ;
}
void
bfad_drv_uninit ( struct bfad_s * bfad )
{
del_timer_sync ( & bfad - > hal_tmo ) ;
bfa_isr_disable ( & bfad - > bfa ) ;
bfa_detach ( & bfad - > bfa ) ;
bfad_remove_intr ( bfad ) ;
bfa_assert ( list_empty ( & bfad - > file_q ) ) ;
bfad_hal_mem_release ( bfad ) ;
}
void
bfad_drv_start ( struct bfad_s * bfad )
{
unsigned long flags ;
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
bfa_start ( & bfad - > bfa ) ;
bfa_fcs_start ( & bfad - > bfa_fcs ) ;
bfad - > bfad_flags | = BFAD_HAL_START_DONE ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
bfad_fc4_probe_post ( bfad ) ;
}
void
bfad_drv_stop ( struct bfad_s * bfad )
{
unsigned long flags ;
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
init_completion ( & bfad - > comp ) ;
bfad - > pport . flags | = BFAD_PORT_DELETE ;
bfa_fcs_exit ( & bfad - > bfa_fcs ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
wait_for_completion ( & bfad - > comp ) ;
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
init_completion ( & bfad - > comp ) ;
bfa_stop ( & bfad - > bfa ) ;
bfad - > bfad_flags & = ~ BFAD_HAL_START_DONE ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
wait_for_completion ( & bfad - > comp ) ;
}
bfa_status_t
bfad_cfg_pport ( struct bfad_s * bfad , enum bfa_port_role role )
{
int rc = BFA_STATUS_OK ;
/*
* Allocate scsi_host for the physical port
*/
if ( ( bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM )
& & ( role & BFA_PORT_ROLE_FCP_IM ) ) {
if ( bfad - > pport . im_port = = NULL ) {
rc = BFA_STATUS_FAILED ;
goto out ;
}
rc = bfad_im_scsi_host_alloc ( bfad , bfad - > pport . im_port ) ;
if ( rc ! = BFA_STATUS_OK )
goto out ;
bfad - > pport . roles | = BFA_PORT_ROLE_FCP_IM ;
}
bfad - > bfad_flags | = BFAD_CFG_PPORT_DONE ;
out :
return rc ;
}
void
bfad_uncfg_pport ( struct bfad_s * bfad )
{
if ( ( bfad - > pport . roles & BFA_PORT_ROLE_FCP_IPFC ) & & ipfc_enable ) {
bfad_ipfc_port_delete ( bfad , & bfad - > pport ) ;
bfad - > pport . roles & = ~ BFA_PORT_ROLE_FCP_IPFC ;
}
if ( ( bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM )
& & ( bfad - > pport . roles & BFA_PORT_ROLE_FCP_IM ) ) {
bfad_im_scsi_host_free ( bfad , bfad - > pport . im_port ) ;
bfad_im_port_clean ( bfad - > pport . im_port ) ;
kfree ( bfad - > pport . im_port ) ;
bfad - > pport . roles & = ~ BFA_PORT_ROLE_FCP_IM ;
}
bfad - > bfad_flags & = ~ BFAD_CFG_PPORT_DONE ;
}
void
bfad_drv_log_level_set ( struct bfad_s * bfad )
{
if ( log_level > BFA_LOG_INVALID & & log_level < = BFA_LOG_LEVEL_MAX )
bfa_log_set_level_all ( & bfad - > log_data , log_level ) ;
}
/*
* PCI_entry PCI driver entries * {
*/
/**
* PCI probe entry .
*/
int
bfad_pci_probe ( struct pci_dev * pdev , const struct pci_device_id * pid )
{
struct bfad_s * bfad ;
int error = - ENODEV , retval ;
char buf [ 16 ] ;
/*
* For single port cards - only claim function 0
*/
if ( ( pdev - > device = = BFA_PCI_DEVICE_ID_FC_8G1P )
& & ( PCI_FUNC ( pdev - > devfn ) ! = 0 ) )
return - ENODEV ;
BFA_TRACE ( BFA_INFO , " bfad_pci_probe entry " ) ;
bfad = kzalloc ( sizeof ( struct bfad_s ) , GFP_KERNEL ) ;
if ( ! bfad ) {
error = - ENOMEM ;
goto out ;
}
bfad - > trcmod = kzalloc ( sizeof ( struct bfa_trc_mod_s ) , GFP_KERNEL ) ;
if ( ! bfad - > trcmod ) {
printk ( KERN_WARNING " Error alloc trace buffer! \n " ) ;
error = - ENOMEM ;
goto out_alloc_trace_failure ;
}
/*
* LOG / TRACE INIT
*/
bfa_trc_init ( bfad - > trcmod ) ;
bfa_trc ( bfad , bfad_inst ) ;
bfad - > logmod = & bfad - > log_data ;
sprintf ( buf , " %d " , bfad_inst ) ;
bfa_log_init ( bfad - > logmod , buf , bfa_os_printf ) ;
bfad_drv_log_level_set ( bfad ) ;
bfad - > aen = & bfad - > aen_buf ;
if ( ! ( bfad_load_fwimg ( pdev ) ) ) {
printk ( KERN_WARNING " bfad_load_fwimg failure! \n " ) ;
kfree ( bfad - > trcmod ) ;
goto out_alloc_trace_failure ;
}
retval = bfad_pci_init ( pdev , bfad ) ;
if ( retval ) {
printk ( KERN_WARNING " bfad_pci_init failure! \n " ) ;
error = retval ;
goto out_pci_init_failure ;
}
mutex_lock ( & bfad_mutex ) ;
bfad - > inst_no = bfad_inst + + ;
list_add_tail ( & bfad - > list_entry , & bfad_list ) ;
mutex_unlock ( & bfad_mutex ) ;
spin_lock_init ( & bfad - > bfad_lock ) ;
pci_set_drvdata ( pdev , bfad ) ;
bfad - > ref_count = 0 ;
bfad - > pport . bfad = bfad ;
retval = bfad_drv_init ( bfad ) ;
if ( retval ! = BFA_STATUS_OK )
goto out_drv_init_failure ;
if ( ! ( bfad - > bfad_flags & BFAD_HAL_INIT_DONE ) ) {
printk ( KERN_WARNING " bfad%d: hal init failed \n " , bfad - > inst_no ) ;
goto ok ;
}
/*
* PPORT FCS config
*/
bfad_fcs_port_cfg ( bfad ) ;
retval = bfad_cfg_pport ( bfad , BFA_PORT_ROLE_FCP_IM ) ;
if ( retval ! = BFA_STATUS_OK )
goto out_cfg_pport_failure ;
/*
* BFAD level FC4 ( IM / TM / IPFC ) specific resource allocation
*/
retval = bfad_fc4_probe ( bfad ) ;
if ( retval ! = BFA_STATUS_OK ) {
printk ( KERN_WARNING " bfad_fc4_probe failed \n " ) ;
goto out_fc4_probe_failure ;
}
bfad_drv_start ( bfad ) ;
/*
* If bfa_linkup_delay is set to - 1 default ; try to retrive the
* value using the bfad_os_get_linkup_delay ( ) ; else use the
* passed in module param value as the bfa_linkup_delay .
*/
if ( bfa_linkup_delay < 0 ) {
bfa_linkup_delay = bfad_os_get_linkup_delay ( bfad ) ;
bfad_os_rport_online_wait ( bfad ) ;
bfa_linkup_delay = - 1 ;
} else {
bfad_os_rport_online_wait ( bfad ) ;
}
bfa_log ( bfad - > logmod , BFA_LOG_LINUX_DEVICE_CLAIMED , bfad - > pci_name ) ;
ok :
return 0 ;
out_fc4_probe_failure :
bfad_fc4_probe_undo ( bfad ) ;
bfad_uncfg_pport ( bfad ) ;
out_cfg_pport_failure :
bfad_drv_uninit ( bfad ) ;
out_drv_init_failure :
mutex_lock ( & bfad_mutex ) ;
bfad_inst - - ;
list_del ( & bfad - > list_entry ) ;
mutex_unlock ( & bfad_mutex ) ;
bfad_pci_uninit ( pdev , bfad ) ;
out_pci_init_failure :
kfree ( bfad - > trcmod ) ;
out_alloc_trace_failure :
kfree ( bfad ) ;
out :
return error ;
}
/**
* PCI remove entry .
*/
void
bfad_pci_remove ( struct pci_dev * pdev )
{
struct bfad_s * bfad = pci_get_drvdata ( pdev ) ;
unsigned long flags ;
bfa_trc ( bfad , bfad - > inst_no ) ;
if ( ( bfad - > bfad_flags & BFAD_DRV_INIT_DONE )
& & ! ( bfad - > bfad_flags & BFAD_HAL_INIT_DONE ) ) {
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
init_completion ( & bfad - > comp ) ;
bfa_stop ( & bfad - > bfa ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
wait_for_completion ( & bfad - > comp ) ;
bfad_remove_intr ( bfad ) ;
del_timer_sync ( & bfad - > hal_tmo ) ;
goto hal_detach ;
} else if ( ! ( bfad - > bfad_flags & BFAD_DRV_INIT_DONE ) ) {
goto remove_sysfs ;
}
if ( bfad - > bfad_flags & BFAD_HAL_START_DONE )
bfad_drv_stop ( bfad ) ;
bfad_remove_intr ( bfad ) ;
del_timer_sync ( & bfad - > hal_tmo ) ;
bfad_fc4_probe_undo ( bfad ) ;
if ( bfad - > bfad_flags & BFAD_CFG_PPORT_DONE )
bfad_uncfg_pport ( bfad ) ;
hal_detach :
spin_lock_irqsave ( & bfad - > bfad_lock , flags ) ;
bfa_detach ( & bfad - > bfa ) ;
spin_unlock_irqrestore ( & bfad - > bfad_lock , flags ) ;
bfad_hal_mem_release ( bfad ) ;
remove_sysfs :
mutex_lock ( & bfad_mutex ) ;
bfad_inst - - ;
list_del ( & bfad - > list_entry ) ;
mutex_unlock ( & bfad_mutex ) ;
bfad_pci_uninit ( pdev , bfad ) ;
kfree ( bfad - > trcmod ) ;
kfree ( bfad ) ;
}
static struct pci_device_id bfad_id_table [ ] = {
{
. vendor = BFA_PCI_VENDOR_ID_BROCADE ,
. device = BFA_PCI_DEVICE_ID_FC_8G2P ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
{
. vendor = BFA_PCI_VENDOR_ID_BROCADE ,
. device = BFA_PCI_DEVICE_ID_FC_8G1P ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
} ,
{
. vendor = BFA_PCI_VENDOR_ID_BROCADE ,
. device = BFA_PCI_DEVICE_ID_CT ,
. subvendor = PCI_ANY_ID ,
. subdevice = PCI_ANY_ID ,
. class = ( PCI_CLASS_SERIAL_FIBER < < 8 ) ,
. class_mask = ~ 0 ,
} ,
{ 0 , 0 } ,
} ;
MODULE_DEVICE_TABLE ( pci , bfad_id_table ) ;
static struct pci_driver bfad_pci_driver = {
. name = BFAD_DRIVER_NAME ,
. id_table = bfad_id_table ,
. probe = bfad_pci_probe ,
. remove = __devexit_p ( bfad_pci_remove ) ,
} ;
/**
* Linux driver module functions
*/
bfa_status_t
bfad_fc4_module_init ( void )
{
int rc ;
rc = bfad_im_module_init ( ) ;
if ( rc ! = BFA_STATUS_OK )
goto ext ;
bfad_tm_module_init ( ) ;
if ( ipfc_enable )
bfad_ipfc_module_init ( ) ;
ext :
return rc ;
}
void
bfad_fc4_module_exit ( void )
{
if ( ipfc_enable )
bfad_ipfc_module_exit ( ) ;
bfad_tm_module_exit ( ) ;
bfad_im_module_exit ( ) ;
}
/**
* Driver module init .
*/
static int __init
bfad_init ( void )
{
int error = 0 ;
printk ( KERN_INFO " Brocade BFA FC/FCOE SCSI driver - version: %s \n " ,
BFAD_DRIVER_VERSION ) ;
if ( num_sgpgs > 0 )
num_sgpgs_parm = num_sgpgs ;
error = bfad_fc4_module_init ( ) ;
if ( error ) {
error = - ENOMEM ;
printk ( KERN_WARNING " bfad_fc4_module_init failure \n " ) ;
goto ext ;
}
if ( ! strcmp ( FCPI_NAME , " fcpim " ) )
bfad_supported_fc4s | = BFA_PORT_ROLE_FCP_IM ;
if ( ! strcmp ( FCPT_NAME , " fcptm " ) )
bfad_supported_fc4s | = BFA_PORT_ROLE_FCP_TM ;
if ( ! strcmp ( IPFC_NAME , " ipfc " ) )
bfad_supported_fc4s | = BFA_PORT_ROLE_FCP_IPFC ;
bfa_ioc_auto_recover ( ioc_auto_recover ) ;
bfa_fcs_rport_set_del_timeout ( rport_del_timeout ) ;
error = pci_register_driver ( & bfad_pci_driver ) ;
if ( error ) {
printk ( KERN_WARNING " bfad pci_register_driver failure \n " ) ;
goto ext ;
}
return 0 ;
ext :
bfad_fc4_module_exit ( ) ;
return error ;
}
/**
* Driver module exit .
*/
static void __exit
bfad_exit ( void )
{
pci_unregister_driver ( & bfad_pci_driver ) ;
bfad_fc4_module_exit ( ) ;
bfad_free_fwimg ( ) ;
}
# define BFAD_PROTO_NAME FCPI_NAME FCPT_NAME IPFC_NAME
module_init ( bfad_init ) ;
module_exit ( bfad_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Brocade Fibre Channel HBA Driver " BFAD_PROTO_NAME ) ;
MODULE_AUTHOR ( " Brocade Communications Systems, Inc. " ) ;
MODULE_VERSION ( BFAD_DRIVER_VERSION ) ;