2011-02-04 23:10:34 +03:00
/* bnx2fc_fcoe.c: Broadcom NetXtreme II Linux FCoE offload driver.
* This file contains the code that interacts with libfc , libfcoe ,
* cnic modules to create FCoE instances , send / receive non - offloaded
* FIP / FCoE packets , listen to link events etc .
*
2011-07-27 22:32:13 +04:00
* Copyright ( c ) 2008 - 2011 Broadcom Corporation
2011-02-04 23:10:34 +03:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation .
*
* Written by : Bhanu Prakash Gollapudi ( bprakash @ broadcom . com )
*/
# include "bnx2fc.h"
static struct list_head adapter_list ;
2011-07-27 01:51:39 +04:00
static struct list_head if_list ;
2011-02-04 23:10:34 +03:00
static u32 adapter_count ;
static DEFINE_MUTEX ( bnx2fc_dev_lock ) ;
DEFINE_PER_CPU ( struct bnx2fc_percpu_s , bnx2fc_percpu ) ;
# define DRV_MODULE_NAME "bnx2fc"
# define DRV_MODULE_VERSION BNX2FC_VERSION
2011-07-27 22:32:13 +04:00
# define DRV_MODULE_RELDATE "Jun 23, 2011"
2011-02-04 23:10:34 +03:00
static char version [ ] __devinitdata =
" Broadcom NetXtreme II FCoE Driver " DRV_MODULE_NAME \
" v " DRV_MODULE_VERSION " ( " DRV_MODULE_RELDATE " ) \n " ;
MODULE_AUTHOR ( " Bhanu Prakash Gollapudi <bprakash@broadcom.com> " ) ;
MODULE_DESCRIPTION ( " Broadcom NetXtreme II BCM57710 FCoE Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( DRV_MODULE_VERSION ) ;
# define BNX2FC_MAX_QUEUE_DEPTH 256
# define BNX2FC_MIN_QUEUE_DEPTH 32
# define FCOE_WORD_TO_BYTE 4
static struct scsi_transport_template * bnx2fc_transport_template ;
static struct scsi_transport_template * bnx2fc_vport_xport_template ;
struct workqueue_struct * bnx2fc_wq ;
/* bnx2fc structure needs only one instance of the fcoe_percpu_s structure.
* Here the io threads are per cpu but the l2 thread is just one
*/
struct fcoe_percpu_s bnx2fc_global ;
DEFINE_SPINLOCK ( bnx2fc_global_lock ) ;
static struct cnic_ulp_ops bnx2fc_cnic_cb ;
static struct libfc_function_template bnx2fc_libfc_fcn_templ ;
static struct scsi_host_template bnx2fc_shost_template ;
static struct fc_function_template bnx2fc_transport_function ;
static struct fc_function_template bnx2fc_vport_xport_function ;
static int bnx2fc_create ( struct net_device * netdev , enum fip_state fip_mode ) ;
static int bnx2fc_destroy ( struct net_device * net_device ) ;
static int bnx2fc_enable ( struct net_device * netdev ) ;
static int bnx2fc_disable ( struct net_device * netdev ) ;
static void bnx2fc_recv_frame ( struct sk_buff * skb ) ;
2011-07-27 01:51:39 +04:00
static void bnx2fc_start_disc ( struct bnx2fc_interface * interface ) ;
2011-02-04 23:10:34 +03:00
static int bnx2fc_shost_config ( struct fc_lport * lport , struct device * dev ) ;
static int bnx2fc_net_config ( struct fc_lport * lp ) ;
static int bnx2fc_lport_config ( struct fc_lport * lport ) ;
static int bnx2fc_em_config ( struct fc_lport * lport ) ;
static int bnx2fc_bind_adapter_devices ( struct bnx2fc_hba * hba ) ;
static void bnx2fc_unbind_adapter_devices ( struct bnx2fc_hba * hba ) ;
static int bnx2fc_bind_pcidev ( struct bnx2fc_hba * hba ) ;
static void bnx2fc_unbind_pcidev ( struct bnx2fc_hba * hba ) ;
2011-07-27 01:51:39 +04:00
static struct fc_lport * bnx2fc_if_create ( struct bnx2fc_interface * interface ,
2011-02-04 23:10:34 +03:00
struct device * parent , int npiv ) ;
static void bnx2fc_destroy_work ( struct work_struct * work ) ;
static struct bnx2fc_hba * bnx2fc_hba_lookup ( struct net_device * phys_dev ) ;
2011-07-27 01:51:39 +04:00
static struct bnx2fc_interface * bnx2fc_interface_lookup ( struct net_device
* phys_dev ) ;
2011-02-04 23:10:34 +03:00
static struct bnx2fc_hba * bnx2fc_find_hba_for_cnic ( struct cnic_dev * cnic ) ;
static int bnx2fc_fw_init ( struct bnx2fc_hba * hba ) ;
static void bnx2fc_fw_destroy ( struct bnx2fc_hba * hba ) ;
static void bnx2fc_port_shutdown ( struct fc_lport * lport ) ;
2011-07-27 01:51:39 +04:00
static void bnx2fc_stop ( struct bnx2fc_interface * interface ) ;
2011-02-04 23:10:34 +03:00
static int __init bnx2fc_mod_init ( void ) ;
static void __exit bnx2fc_mod_exit ( void ) ;
unsigned int bnx2fc_debug_level ;
module_param_named ( debug_logging , bnx2fc_debug_level , int , S_IRUGO | S_IWUSR ) ;
static int bnx2fc_cpu_callback ( struct notifier_block * nfb ,
unsigned long action , void * hcpu ) ;
/* notification function for CPU hotplug events */
static struct notifier_block bnx2fc_cpu_notifier = {
. notifier_call = bnx2fc_cpu_callback ,
} ;
static void bnx2fc_clean_rx_queue ( struct fc_lport * lp )
{
struct fcoe_percpu_s * bg ;
struct fcoe_rcv_info * fr ;
struct sk_buff_head * list ;
struct sk_buff * skb , * next ;
struct sk_buff * head ;
bg = & bnx2fc_global ;
spin_lock_bh ( & bg - > fcoe_rx_list . lock ) ;
list = & bg - > fcoe_rx_list ;
head = list - > next ;
for ( skb = head ; skb ! = ( struct sk_buff * ) list ;
skb = next ) {
next = skb - > next ;
fr = fcoe_dev_from_skb ( skb ) ;
if ( fr - > fr_dev = = lp ) {
__skb_unlink ( skb , list ) ;
kfree_skb ( skb ) ;
}
}
spin_unlock_bh ( & bg - > fcoe_rx_list . lock ) ;
}
int bnx2fc_get_paged_crc_eof ( struct sk_buff * skb , int tlen )
{
int rc ;
spin_lock ( & bnx2fc_global_lock ) ;
rc = fcoe_get_paged_crc_eof ( skb , tlen , & bnx2fc_global ) ;
spin_unlock ( & bnx2fc_global_lock ) ;
return rc ;
}
static void bnx2fc_abort_io ( struct fc_lport * lport )
{
/*
* This function is no - op for bnx2fc , but we do
* not want to leave it as NULL either , as libfc
* can call the default function which is
* fc_fcp_abort_io .
*/
}
static void bnx2fc_cleanup ( struct fc_lport * lport )
{
struct fcoe_port * port = lport_priv ( lport ) ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface = port - > priv ;
struct bnx2fc_hba * hba = interface - > hba ;
2011-02-04 23:10:34 +03:00
struct bnx2fc_rport * tgt ;
int i ;
BNX2FC_MISC_DBG ( " Entered %s \n " , __func__ ) ;
mutex_lock ( & hba - > hba_mutex ) ;
spin_lock_bh ( & hba - > hba_lock ) ;
for ( i = 0 ; i < BNX2FC_NUM_MAX_SESS ; i + + ) {
tgt = hba - > tgt_ofld_list [ i ] ;
if ( tgt ) {
/* Cleanup IOs belonging to requested vport */
if ( tgt - > port = = port ) {
spin_unlock_bh ( & hba - > hba_lock ) ;
BNX2FC_TGT_DBG ( tgt , " flush/cleanup \n " ) ;
bnx2fc_flush_active_ios ( tgt ) ;
spin_lock_bh ( & hba - > hba_lock ) ;
}
}
}
spin_unlock_bh ( & hba - > hba_lock ) ;
mutex_unlock ( & hba - > hba_mutex ) ;
}
static int bnx2fc_xmit_l2_frame ( struct bnx2fc_rport * tgt ,
struct fc_frame * fp )
{
struct fc_rport_priv * rdata = tgt - > rdata ;
struct fc_frame_header * fh ;
int rc = 0 ;
fh = fc_frame_header_get ( fp ) ;
BNX2FC_TGT_DBG ( tgt , " Xmit L2 frame rport = 0x%x, oxid = 0x%x, "
" r_ctl = 0x%x \n " , rdata - > ids . port_id ,
ntohs ( fh - > fh_ox_id ) , fh - > fh_r_ctl ) ;
if ( ( fh - > fh_type = = FC_TYPE_ELS ) & &
( fh - > fh_r_ctl = = FC_RCTL_ELS_REQ ) ) {
switch ( fc_frame_payload_op ( fp ) ) {
case ELS_ADISC :
rc = bnx2fc_send_adisc ( tgt , fp ) ;
break ;
case ELS_LOGO :
rc = bnx2fc_send_logo ( tgt , fp ) ;
break ;
case ELS_RLS :
rc = bnx2fc_send_rls ( tgt , fp ) ;
break ;
default :
break ;
}
} else if ( ( fh - > fh_type = = FC_TYPE_BLS ) & &
( fh - > fh_r_ctl = = FC_RCTL_BA_ABTS ) )
BNX2FC_TGT_DBG ( tgt , " ABTS frame \n " ) ;
else {
BNX2FC_TGT_DBG ( tgt , " Send L2 frame type 0x%x "
" rctl 0x%x thru non-offload path \n " ,
fh - > fh_type , fh - > fh_r_ctl ) ;
return - ENODEV ;
}
if ( rc )
return - ENOMEM ;
else
return 0 ;
}
/**
* bnx2fc_xmit - bnx2fc ' s FCoE frame transmit function
*
* @ lport : the associated local port
* @ fp : the fc_frame to be transmitted
*/
static int bnx2fc_xmit ( struct fc_lport * lport , struct fc_frame * fp )
{
struct ethhdr * eh ;
struct fcoe_crc_eof * cp ;
struct sk_buff * skb ;
struct fc_frame_header * fh ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
struct bnx2fc_hba * hba ;
2011-02-04 23:10:34 +03:00
struct fcoe_port * port ;
struct fcoe_hdr * hp ;
struct bnx2fc_rport * tgt ;
struct fcoe_dev_stats * stats ;
u8 sof , eof ;
u32 crc ;
unsigned int hlen , tlen , elen ;
int wlen , rc = 0 ;
port = ( struct fcoe_port * ) lport_priv ( lport ) ;
2011-07-27 01:51:39 +04:00
interface = port - > priv ;
hba = interface - > hba ;
2011-02-04 23:10:34 +03:00
fh = fc_frame_header_get ( fp ) ;
skb = fp_skb ( fp ) ;
if ( ! lport - > link_up ) {
BNX2FC_HBA_DBG ( lport , " bnx2fc_xmit link down \n " ) ;
kfree_skb ( skb ) ;
return 0 ;
}
if ( unlikely ( fh - > fh_r_ctl = = FC_RCTL_ELS_REQ ) ) {
2011-07-27 01:51:39 +04:00
if ( ! interface - > ctlr . sel_fcf ) {
2011-02-04 23:10:34 +03:00
BNX2FC_HBA_DBG ( lport , " FCF not selected yet! \n " ) ;
kfree_skb ( skb ) ;
return - EINVAL ;
}
2011-07-27 01:51:39 +04:00
if ( fcoe_ctlr_els_send ( & interface - > ctlr , lport , skb ) )
2011-02-04 23:10:34 +03:00
return 0 ;
}
sof = fr_sof ( fp ) ;
eof = fr_eof ( fp ) ;
/*
* Snoop the frame header to check if the frame is for
* an offloaded session
*/
/*
* tgt_ofld_list access is synchronized using
* both hba mutex and hba lock . Atleast hba mutex or
* hba lock needs to be held for read access .
*/
spin_lock_bh ( & hba - > hba_lock ) ;
tgt = bnx2fc_tgt_lookup ( port , ntoh24 ( fh - > fh_d_id ) ) ;
if ( tgt & & ( test_bit ( BNX2FC_FLAG_SESSION_READY , & tgt - > flags ) ) ) {
/* This frame is for offloaded session */
BNX2FC_HBA_DBG ( lport , " xmit: Frame is for offloaded session "
" port_id = 0x%x \n " , ntoh24 ( fh - > fh_d_id ) ) ;
spin_unlock_bh ( & hba - > hba_lock ) ;
rc = bnx2fc_xmit_l2_frame ( tgt , fp ) ;
if ( rc ! = - ENODEV ) {
kfree_skb ( skb ) ;
return rc ;
}
} else {
spin_unlock_bh ( & hba - > hba_lock ) ;
}
elen = sizeof ( struct ethhdr ) ;
hlen = sizeof ( struct fcoe_hdr ) ;
tlen = sizeof ( struct fcoe_crc_eof ) ;
wlen = ( skb - > len - tlen + sizeof ( crc ) ) / FCOE_WORD_TO_BYTE ;
skb - > ip_summed = CHECKSUM_NONE ;
crc = fcoe_fc_crc ( fp ) ;
/* copy port crc and eof to the skb buff */
if ( skb_is_nonlinear ( skb ) ) {
skb_frag_t * frag ;
if ( bnx2fc_get_paged_crc_eof ( skb , tlen ) ) {
kfree_skb ( skb ) ;
return - ENOMEM ;
}
frag = & skb_shinfo ( skb ) - > frags [ skb_shinfo ( skb ) - > nr_frags - 1 ] ;
cp = kmap_atomic ( frag - > page , KM_SKB_DATA_SOFTIRQ )
+ frag - > page_offset ;
} else {
cp = ( struct fcoe_crc_eof * ) skb_put ( skb , tlen ) ;
}
memset ( cp , 0 , sizeof ( * cp ) ) ;
cp - > fcoe_eof = eof ;
cp - > fcoe_crc32 = cpu_to_le32 ( ~ crc ) ;
if ( skb_is_nonlinear ( skb ) ) {
kunmap_atomic ( cp , KM_SKB_DATA_SOFTIRQ ) ;
cp = NULL ;
}
/* adjust skb network/transport offsets to match mac/fcoe/port */
skb_push ( skb , elen + hlen ) ;
skb_reset_mac_header ( skb ) ;
skb_reset_network_header ( skb ) ;
skb - > mac_len = elen ;
skb - > protocol = htons ( ETH_P_FCOE ) ;
2011-07-27 01:51:39 +04:00
skb - > dev = interface - > netdev ;
2011-02-04 23:10:34 +03:00
/* fill up mac and fcoe headers */
eh = eth_hdr ( skb ) ;
eh - > h_proto = htons ( ETH_P_FCOE ) ;
2011-07-27 01:51:39 +04:00
if ( interface - > ctlr . map_dest )
2011-02-04 23:10:34 +03:00
fc_fcoe_set_mac ( eh - > h_dest , fh - > fh_d_id ) ;
else
/* insert GW address */
2011-07-27 01:51:39 +04:00
memcpy ( eh - > h_dest , interface - > ctlr . dest_addr , ETH_ALEN ) ;
2011-02-04 23:10:34 +03:00
2011-07-27 01:51:39 +04:00
if ( unlikely ( interface - > ctlr . flogi_oxid ! = FC_XID_UNKNOWN ) )
memcpy ( eh - > h_source , interface - > ctlr . ctl_src_addr , ETH_ALEN ) ;
2011-02-04 23:10:34 +03:00
else
memcpy ( eh - > h_source , port - > data_src_addr , ETH_ALEN ) ;
hp = ( struct fcoe_hdr * ) ( eh + 1 ) ;
memset ( hp , 0 , sizeof ( * hp ) ) ;
if ( FC_FCOE_VER )
FC_FCOE_ENCAPS_VER ( hp , FC_FCOE_VER ) ;
hp - > fcoe_sof = sof ;
/* fcoe lso, mss is in max_payload which is non-zero for FCP data */
if ( lport - > seq_offload & & fr_max_payload ( fp ) ) {
skb_shinfo ( skb ) - > gso_type = SKB_GSO_FCOE ;
skb_shinfo ( skb ) - > gso_size = fr_max_payload ( fp ) ;
} else {
skb_shinfo ( skb ) - > gso_type = 0 ;
skb_shinfo ( skb ) - > gso_size = 0 ;
}
/*update tx stats */
stats = per_cpu_ptr ( lport - > dev_stats , get_cpu ( ) ) ;
stats - > TxFrames + + ;
stats - > TxWords + = wlen ;
put_cpu ( ) ;
/* send down to lld */
fr_dev ( fp ) = lport ;
if ( port - > fcoe_pending_queue . qlen )
fcoe_check_wait_queue ( lport , skb ) ;
else if ( fcoe_start_io ( skb ) )
fcoe_check_wait_queue ( lport , skb ) ;
return 0 ;
}
/**
* bnx2fc_rcv - This is bnx2fc ' s receive function called by NET_RX_SOFTIRQ
*
* @ skb : the receive socket buffer
* @ dev : associated net device
* @ ptype : context
* @ olddev : last device
*
* This function receives the packet and builds FC frame and passes it up
*/
static int bnx2fc_rcv ( struct sk_buff * skb , struct net_device * dev ,
struct packet_type * ptype , struct net_device * olddev )
{
struct fc_lport * lport ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
struct fc_frame_header * fh ;
struct fcoe_rcv_info * fr ;
struct fcoe_percpu_s * bg ;
unsigned short oxid ;
2011-07-27 01:51:39 +04:00
interface = container_of ( ptype , struct bnx2fc_interface ,
fcoe_packet_type ) ;
lport = interface - > ctlr . lp ;
2011-02-04 23:10:34 +03:00
if ( unlikely ( lport = = NULL ) ) {
2011-06-28 10:30:53 +04:00
printk ( KERN_ERR PFX " bnx2fc_rcv: lport is NULL \n " ) ;
2011-02-04 23:10:34 +03:00
goto err ;
}
if ( unlikely ( eth_hdr ( skb ) - > h_proto ! = htons ( ETH_P_FCOE ) ) ) {
2011-06-28 10:30:53 +04:00
printk ( KERN_ERR PFX " bnx2fc_rcv: Wrong FC type frame \n " ) ;
2011-02-04 23:10:34 +03:00
goto err ;
}
/*
* Check for minimum frame length , and make sure required FCoE
* and FC headers are pulled into the linear data area .
*/
if ( unlikely ( ( skb - > len < FCOE_MIN_FRAME ) | |
! pskb_may_pull ( skb , FCOE_HEADER_LEN ) ) )
goto err ;
skb_set_transport_header ( skb , sizeof ( struct fcoe_hdr ) ) ;
fh = ( struct fc_frame_header * ) skb_transport_header ( skb ) ;
oxid = ntohs ( fh - > fh_ox_id ) ;
fr = fcoe_dev_from_skb ( skb ) ;
fr - > fr_dev = lport ;
bg = & bnx2fc_global ;
spin_lock_bh ( & bg - > fcoe_rx_list . lock ) ;
__skb_queue_tail ( & bg - > fcoe_rx_list , skb ) ;
if ( bg - > fcoe_rx_list . qlen = = 1 )
wake_up_process ( bg - > thread ) ;
spin_unlock_bh ( & bg - > fcoe_rx_list . lock ) ;
return 0 ;
err :
kfree_skb ( skb ) ;
return - 1 ;
}
static int bnx2fc_l2_rcv_thread ( void * arg )
{
struct fcoe_percpu_s * bg = arg ;
struct sk_buff * skb ;
set_user_nice ( current , - 20 ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
while ( ! kthread_should_stop ( ) ) {
schedule ( ) ;
spin_lock_bh ( & bg - > fcoe_rx_list . lock ) ;
while ( ( skb = __skb_dequeue ( & bg - > fcoe_rx_list ) ) ! = NULL ) {
spin_unlock_bh ( & bg - > fcoe_rx_list . lock ) ;
bnx2fc_recv_frame ( skb ) ;
spin_lock_bh ( & bg - > fcoe_rx_list . lock ) ;
}
2011-03-22 04:51:13 +03:00
__set_current_state ( TASK_INTERRUPTIBLE ) ;
2011-02-04 23:10:34 +03:00
spin_unlock_bh ( & bg - > fcoe_rx_list . lock ) ;
}
2011-03-22 04:51:13 +03:00
__set_current_state ( TASK_RUNNING ) ;
2011-02-04 23:10:34 +03:00
return 0 ;
}
static void bnx2fc_recv_frame ( struct sk_buff * skb )
{
u32 fr_len ;
struct fc_lport * lport ;
struct fcoe_rcv_info * fr ;
struct fcoe_dev_stats * stats ;
struct fc_frame_header * fh ;
struct fcoe_crc_eof crc_eof ;
struct fc_frame * fp ;
struct fc_lport * vn_port ;
struct fcoe_port * port ;
u8 * mac = NULL ;
u8 * dest_mac = NULL ;
struct fcoe_hdr * hp ;
fr = fcoe_dev_from_skb ( skb ) ;
lport = fr - > fr_dev ;
if ( unlikely ( lport = = NULL ) ) {
2011-06-28 10:30:53 +04:00
printk ( KERN_ERR PFX " Invalid lport struct \n " ) ;
2011-02-04 23:10:34 +03:00
kfree_skb ( skb ) ;
return ;
}
if ( skb_is_nonlinear ( skb ) )
skb_linearize ( skb ) ;
mac = eth_hdr ( skb ) - > h_source ;
dest_mac = eth_hdr ( skb ) - > h_dest ;
/* Pull the header */
hp = ( struct fcoe_hdr * ) skb_network_header ( skb ) ;
fh = ( struct fc_frame_header * ) skb_transport_header ( skb ) ;
skb_pull ( skb , sizeof ( struct fcoe_hdr ) ) ;
fr_len = skb - > len - sizeof ( struct fcoe_crc_eof ) ;
stats = per_cpu_ptr ( lport - > dev_stats , get_cpu ( ) ) ;
stats - > RxFrames + + ;
stats - > RxWords + = fr_len / FCOE_WORD_TO_BYTE ;
fp = ( struct fc_frame * ) skb ;
fc_frame_init ( fp ) ;
fr_dev ( fp ) = lport ;
fr_sof ( fp ) = hp - > fcoe_sof ;
if ( skb_copy_bits ( skb , fr_len , & crc_eof , sizeof ( crc_eof ) ) ) {
put_cpu ( ) ;
kfree_skb ( skb ) ;
return ;
}
fr_eof ( fp ) = crc_eof . fcoe_eof ;
fr_crc ( fp ) = crc_eof . fcoe_crc32 ;
if ( pskb_trim ( skb , fr_len ) ) {
put_cpu ( ) ;
kfree_skb ( skb ) ;
return ;
}
fh = fc_frame_header_get ( fp ) ;
vn_port = fc_vport_id_lookup ( lport , ntoh24 ( fh - > fh_d_id ) ) ;
if ( vn_port ) {
port = lport_priv ( vn_port ) ;
if ( compare_ether_addr ( port - > data_src_addr , dest_mac )
! = 0 ) {
BNX2FC_HBA_DBG ( lport , " fpma mismatch \n " ) ;
put_cpu ( ) ;
kfree_skb ( skb ) ;
return ;
}
}
if ( fh - > fh_r_ctl = = FC_RCTL_DD_SOL_DATA & &
fh - > fh_type = = FC_TYPE_FCP ) {
/* Drop FCP data. We dont this in L2 path */
put_cpu ( ) ;
kfree_skb ( skb ) ;
return ;
}
if ( fh - > fh_r_ctl = = FC_RCTL_ELS_REQ & &
fh - > fh_type = = FC_TYPE_ELS ) {
switch ( fc_frame_payload_op ( fp ) ) {
case ELS_LOGO :
if ( ntoh24 ( fh - > fh_s_id ) = = FC_FID_FLOGI ) {
/* drop non-FIP LOGO */
put_cpu ( ) ;
kfree_skb ( skb ) ;
return ;
}
break ;
}
}
if ( le32_to_cpu ( fr_crc ( fp ) ) ! =
~ crc32 ( ~ 0 , skb - > data , fr_len ) ) {
if ( stats - > InvalidCRCCount < 5 )
printk ( KERN_WARNING PFX " dropping frame with "
" CRC error \n " ) ;
stats - > InvalidCRCCount + + ;
put_cpu ( ) ;
kfree_skb ( skb ) ;
return ;
}
put_cpu ( ) ;
fc_exch_recv ( lport , fp ) ;
}
/**
* bnx2fc_percpu_io_thread - thread per cpu for ios
*
* @ arg : ptr to bnx2fc_percpu_info structure
*/
int bnx2fc_percpu_io_thread ( void * arg )
{
struct bnx2fc_percpu_s * p = arg ;
struct bnx2fc_work * work , * tmp ;
LIST_HEAD ( work_list ) ;
set_user_nice ( current , - 20 ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
while ( ! kthread_should_stop ( ) ) {
schedule ( ) ;
spin_lock_bh ( & p - > fp_work_lock ) ;
while ( ! list_empty ( & p - > work_list ) ) {
list_splice_init ( & p - > work_list , & work_list ) ;
spin_unlock_bh ( & p - > fp_work_lock ) ;
list_for_each_entry_safe ( work , tmp , & work_list , list ) {
list_del_init ( & work - > list ) ;
bnx2fc_process_cq_compl ( work - > tgt , work - > wqe ) ;
kfree ( work ) ;
}
spin_lock_bh ( & p - > fp_work_lock ) ;
}
2011-03-22 04:51:13 +03:00
__set_current_state ( TASK_INTERRUPTIBLE ) ;
2011-02-04 23:10:34 +03:00
spin_unlock_bh ( & p - > fp_work_lock ) ;
}
2011-03-22 04:51:13 +03:00
__set_current_state ( TASK_RUNNING ) ;
2011-02-04 23:10:34 +03:00
return 0 ;
}
static struct fc_host_statistics * bnx2fc_get_host_stats ( struct Scsi_Host * shost )
{
struct fc_host_statistics * bnx2fc_stats ;
struct fc_lport * lport = shost_priv ( shost ) ;
struct fcoe_port * port = lport_priv ( lport ) ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface = port - > priv ;
struct bnx2fc_hba * hba = interface - > hba ;
2011-02-04 23:10:34 +03:00
struct fcoe_statistics_params * fw_stats ;
int rc = 0 ;
fw_stats = ( struct fcoe_statistics_params * ) hba - > stats_buffer ;
if ( ! fw_stats )
return NULL ;
bnx2fc_stats = fc_get_host_stats ( shost ) ;
init_completion ( & hba - > stat_req_done ) ;
if ( bnx2fc_send_stat_req ( hba ) )
return bnx2fc_stats ;
rc = wait_for_completion_timeout ( & hba - > stat_req_done , ( 2 * HZ ) ) ;
if ( ! rc ) {
BNX2FC_HBA_DBG ( lport , " FW stat req timed out \n " ) ;
return bnx2fc_stats ;
}
2011-06-14 15:33:44 +04:00
bnx2fc_stats - > invalid_crc_count + = fw_stats - > rx_stat2 . fc_crc_cnt ;
2011-02-04 23:10:34 +03:00
bnx2fc_stats - > tx_frames + = fw_stats - > tx_stat . fcoe_tx_pkt_cnt ;
bnx2fc_stats - > tx_words + = ( fw_stats - > tx_stat . fcoe_tx_byte_cnt ) / 4 ;
bnx2fc_stats - > rx_frames + = fw_stats - > rx_stat0 . fcoe_rx_pkt_cnt ;
bnx2fc_stats - > rx_words + = ( fw_stats - > rx_stat0 . fcoe_rx_byte_cnt ) / 4 ;
bnx2fc_stats - > dumped_frames = 0 ;
bnx2fc_stats - > lip_count = 0 ;
bnx2fc_stats - > nos_count = 0 ;
bnx2fc_stats - > loss_of_sync_count = 0 ;
bnx2fc_stats - > loss_of_signal_count = 0 ;
bnx2fc_stats - > prim_seq_protocol_err_count = 0 ;
return bnx2fc_stats ;
}
static int bnx2fc_shost_config ( struct fc_lport * lport , struct device * dev )
{
struct fcoe_port * port = lport_priv ( lport ) ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface = port - > priv ;
2011-02-04 23:10:34 +03:00
struct Scsi_Host * shost = lport - > host ;
int rc = 0 ;
shost - > max_cmd_len = BNX2FC_MAX_CMD_LEN ;
shost - > max_lun = BNX2FC_MAX_LUN ;
shost - > max_id = BNX2FC_MAX_FCP_TGT ;
shost - > max_channel = 0 ;
if ( lport - > vport )
shost - > transportt = bnx2fc_vport_xport_template ;
else
shost - > transportt = bnx2fc_transport_template ;
/* Add the new host to SCSI-ml */
rc = scsi_add_host ( lport - > host , dev ) ;
if ( rc ) {
printk ( KERN_ERR PFX " Error on scsi_add_host \n " ) ;
return rc ;
}
if ( ! lport - > vport )
fc_host_max_npiv_vports ( lport - > host ) = USHRT_MAX ;
sprintf ( fc_host_symbolic_name ( lport - > host ) , " %s v%s over %s " ,
BNX2FC_NAME , BNX2FC_VERSION ,
2011-07-27 01:51:39 +04:00
interface - > netdev - > name ) ;
2011-02-04 23:10:34 +03:00
return 0 ;
}
static void bnx2fc_link_speed_update ( struct fc_lport * lport )
{
struct fcoe_port * port = lport_priv ( lport ) ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface = port - > priv ;
struct net_device * netdev = interface - > netdev ;
2011-04-27 22:32:38 +04:00
struct ethtool_cmd ecmd ;
2011-02-04 23:10:34 +03:00
if ( ! dev_ethtool_get_settings ( netdev , & ecmd ) ) {
lport - > link_supported_speeds & =
~ ( FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT ) ;
if ( ecmd . supported & ( SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full ) )
lport - > link_supported_speeds | = FC_PORTSPEED_1GBIT ;
if ( ecmd . supported & SUPPORTED_10000baseT_Full )
lport - > link_supported_speeds | = FC_PORTSPEED_10GBIT ;
2011-04-27 22:32:38 +04:00
switch ( ethtool_cmd_speed ( & ecmd ) ) {
case SPEED_1000 :
2011-02-04 23:10:34 +03:00
lport - > link_speed = FC_PORTSPEED_1GBIT ;
2011-04-27 22:32:38 +04:00
break ;
2011-05-27 22:47:25 +04:00
case SPEED_2500 :
lport - > link_speed = FC_PORTSPEED_2GBIT ;
break ;
2011-04-27 22:32:38 +04:00
case SPEED_10000 :
2011-02-04 23:10:34 +03:00
lport - > link_speed = FC_PORTSPEED_10GBIT ;
2011-04-27 22:32:38 +04:00
break ;
}
2011-02-04 23:10:34 +03:00
}
}
static int bnx2fc_link_ok ( struct fc_lport * lport )
{
struct fcoe_port * port = lport_priv ( lport ) ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface = port - > priv ;
struct bnx2fc_hba * hba = interface - > hba ;
2011-02-04 23:10:34 +03:00
struct net_device * dev = hba - > phys_dev ;
int rc = 0 ;
if ( ( dev - > flags & IFF_UP ) & & netif_carrier_ok ( dev ) )
clear_bit ( ADAPTER_STATE_LINK_DOWN , & hba - > adapter_state ) ;
else {
set_bit ( ADAPTER_STATE_LINK_DOWN , & hba - > adapter_state ) ;
rc = - 1 ;
}
return rc ;
}
/**
* bnx2fc_get_link_state - get network link state
*
* @ hba : adapter instance pointer
*
* updates adapter structure flag based on netdev state
*/
void bnx2fc_get_link_state ( struct bnx2fc_hba * hba )
{
2011-07-27 01:51:39 +04:00
if ( test_bit ( __LINK_STATE_NOCARRIER , & hba - > phys_dev - > state ) )
2011-02-04 23:10:34 +03:00
set_bit ( ADAPTER_STATE_LINK_DOWN , & hba - > adapter_state ) ;
else
clear_bit ( ADAPTER_STATE_LINK_DOWN , & hba - > adapter_state ) ;
}
static int bnx2fc_net_config ( struct fc_lport * lport )
{
struct bnx2fc_hba * hba ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
struct fcoe_port * port ;
u64 wwnn , wwpn ;
port = lport_priv ( lport ) ;
2011-07-27 01:51:39 +04:00
interface = port - > priv ;
hba = interface - > hba ;
2011-02-04 23:10:34 +03:00
/* require support for get_pauseparam ethtool op. */
if ( ! hba - > phys_dev - > ethtool_ops | |
! hba - > phys_dev - > ethtool_ops - > get_pauseparam )
return - EOPNOTSUPP ;
2011-03-18 03:13:34 +03:00
if ( fc_set_mfs ( lport , BNX2FC_MFS ) )
2011-02-04 23:10:34 +03:00
return - EINVAL ;
skb_queue_head_init ( & port - > fcoe_pending_queue ) ;
port - > fcoe_pending_queue_active = 0 ;
setup_timer ( & port - > timer , fcoe_queue_timer , ( unsigned long ) lport ) ;
bnx2fc_link_speed_update ( lport ) ;
if ( ! lport - > vport ) {
2011-07-27 01:51:39 +04:00
wwnn = fcoe_wwn_from_mac ( interface - > ctlr . ctl_src_addr , 1 , 0 ) ;
2011-02-04 23:10:34 +03:00
BNX2FC_HBA_DBG ( lport , " WWNN = 0x%llx \n " , wwnn ) ;
fc_set_wwnn ( lport , wwnn ) ;
2011-07-27 01:51:39 +04:00
wwpn = fcoe_wwn_from_mac ( interface - > ctlr . ctl_src_addr , 2 , 0 ) ;
2011-02-04 23:10:34 +03:00
BNX2FC_HBA_DBG ( lport , " WWPN = 0x%llx \n " , wwpn ) ;
fc_set_wwpn ( lport , wwpn ) ;
}
return 0 ;
}
static void bnx2fc_destroy_timer ( unsigned long data )
{
struct bnx2fc_hba * hba = ( struct bnx2fc_hba * ) data ;
2011-07-27 01:51:39 +04:00
BNX2FC_MISC_DBG ( " ERROR:bnx2fc_destroy_timer - "
2011-02-04 23:10:34 +03:00
" Destroy compl not received!! \n " ) ;
2011-07-27 01:51:39 +04:00
set_bit ( BNX2FC_FLAG_DESTROY_CMPL , & hba - > flags ) ;
2011-02-04 23:10:34 +03:00
wake_up_interruptible ( & hba - > destroy_wait ) ;
}
/**
* bnx2fc_indicate_netevent - Generic netdev event handler
*
* @ context : adapter structure pointer
* @ event : event type
2011-07-20 18:55:24 +04:00
* @ vlan_id : vlan id - associated vlan id with this event
2011-02-04 23:10:34 +03:00
*
* Handles NETDEV_UP , NETDEV_DOWN , NETDEV_GOING_DOWN , NETDEV_CHANGE and
* NETDEV_CHANGE_MTU events
*/
2011-07-20 18:55:24 +04:00
static void bnx2fc_indicate_netevent ( void * context , unsigned long event ,
u16 vlan_id )
2011-02-04 23:10:34 +03:00
{
struct bnx2fc_hba * hba = ( struct bnx2fc_hba * ) context ;
2011-07-27 01:51:39 +04:00
struct fc_lport * lport ;
2011-02-04 23:10:34 +03:00
struct fc_lport * vport ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
int wait_for_upload = 0 ;
2011-02-04 23:10:34 +03:00
u32 link_possible = 1 ;
2011-07-20 18:55:24 +04:00
/* Ignore vlans for now */
if ( vlan_id ! = 0 )
return ;
2011-02-04 23:10:34 +03:00
switch ( event ) {
case NETDEV_UP :
if ( ! test_bit ( ADAPTER_STATE_UP , & hba - > adapter_state ) )
printk ( KERN_ERR " indicate_netevent: " \
2011-07-27 01:51:39 +04:00
" hba is not UP!! \n " ) ;
2011-02-04 23:10:34 +03:00
break ;
case NETDEV_DOWN :
clear_bit ( ADAPTER_STATE_GOING_DOWN , & hba - > adapter_state ) ;
clear_bit ( ADAPTER_STATE_UP , & hba - > adapter_state ) ;
link_possible = 0 ;
break ;
case NETDEV_GOING_DOWN :
set_bit ( ADAPTER_STATE_GOING_DOWN , & hba - > adapter_state ) ;
link_possible = 0 ;
break ;
case NETDEV_CHANGE :
break ;
default :
printk ( KERN_ERR PFX " Unkonwn netevent %ld " , event ) ;
return ;
}
2011-07-27 01:51:39 +04:00
mutex_lock ( & bnx2fc_dev_lock ) ;
list_for_each_entry ( interface , & if_list , list ) {
2011-02-04 23:10:34 +03:00
2011-07-27 01:51:39 +04:00
if ( interface - > hba ! = hba )
continue ;
lport = interface - > ctlr . lp ;
BNX2FC_HBA_DBG ( lport , " netevent handler - event=%s %ld \n " ,
interface - > netdev - > name , event ) ;
bnx2fc_link_speed_update ( lport ) ;
if ( link_possible & & ! bnx2fc_link_ok ( lport ) ) {
printk ( KERN_ERR " indicate_netevent: ctlr_link_up \n " ) ;
fcoe_ctlr_link_up ( & interface - > ctlr ) ;
} else if ( fcoe_ctlr_link_down ( & interface - > ctlr ) ) {
2011-02-04 23:10:34 +03:00
mutex_lock ( & lport - > lp_mutex ) ;
list_for_each_entry ( vport , & lport - > vports , list )
fc_host_port_type ( vport - > host ) =
FC_PORTTYPE_UNKNOWN ;
mutex_unlock ( & lport - > lp_mutex ) ;
fc_host_port_type ( lport - > host ) = FC_PORTTYPE_UNKNOWN ;
per_cpu_ptr ( lport - > dev_stats ,
get_cpu ( ) ) - > LinkFailureCount + + ;
put_cpu ( ) ;
fcoe_clean_pending_queue ( lport ) ;
2011-07-27 01:51:39 +04:00
wait_for_upload = 1 ;
}
}
mutex_unlock ( & bnx2fc_dev_lock ) ;
2011-02-04 23:10:34 +03:00
2011-07-27 01:51:39 +04:00
if ( wait_for_upload ) {
clear_bit ( ADAPTER_STATE_READY , & hba - > adapter_state ) ;
init_waitqueue_head ( & hba - > shutdown_wait ) ;
BNX2FC_MISC_DBG ( " indicate_netevent "
" num_ofld_sess = %d \n " ,
hba - > num_ofld_sess ) ;
hba - > wait_for_link_down = 1 ;
wait_event_interruptible ( hba - > shutdown_wait ,
( hba - > num_ofld_sess = = 0 ) ) ;
BNX2FC_MISC_DBG ( " wakeup - num_ofld_sess = %d \n " ,
2011-02-04 23:10:34 +03:00
hba - > num_ofld_sess ) ;
2011-07-27 01:51:39 +04:00
hba - > wait_for_link_down = 0 ;
2011-02-04 23:10:34 +03:00
2011-07-27 01:51:39 +04:00
if ( signal_pending ( current ) )
flush_signals ( current ) ;
2011-02-04 23:10:34 +03:00
}
}
static int bnx2fc_libfc_config ( struct fc_lport * lport )
{
/* Set the function pointers set by bnx2fc driver */
memcpy ( & lport - > tt , & bnx2fc_libfc_fcn_templ ,
sizeof ( struct libfc_function_template ) ) ;
fc_elsct_init ( lport ) ;
fc_exch_init ( lport ) ;
fc_rport_init ( lport ) ;
fc_disc_init ( lport ) ;
return 0 ;
}
static int bnx2fc_em_config ( struct fc_lport * lport )
{
if ( ! fc_exch_mgr_alloc ( lport , FC_CLASS_3 , FCOE_MIN_XID ,
FCOE_MAX_XID , NULL ) ) {
printk ( KERN_ERR PFX " em_config:fc_exch_mgr_alloc failed \n " ) ;
return - ENOMEM ;
}
return 0 ;
}
static int bnx2fc_lport_config ( struct fc_lport * lport )
{
lport - > link_up = 0 ;
lport - > qfull = 0 ;
lport - > max_retry_count = 3 ;
lport - > max_rport_retry_count = 3 ;
lport - > e_d_tov = 2 * 1000 ;
lport - > r_a_tov = 10 * 1000 ;
lport - > service_params = ( FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL ) ;
lport - > does_npiv = 1 ;
memset ( & lport - > rnid_gen , 0 , sizeof ( struct fc_els_rnid_gen ) ) ;
lport - > rnid_gen . rnid_atype = BNX2FC_RNID_HBA ;
/* alloc stats structure */
if ( fc_lport_init_stats ( lport ) )
return - ENOMEM ;
/* Finish fc_lport configuration */
fc_lport_config ( lport ) ;
return 0 ;
}
/**
* bnx2fc_fip_recv - handle a received FIP frame .
*
* @ skb : the received skb
* @ dev : associated & net_device
* @ ptype : the & packet_type structure which was used to register this handler .
* @ orig_dev : original receive & net_device , in case @ dev is a bond .
*
* Returns : 0 for success
*/
static int bnx2fc_fip_recv ( struct sk_buff * skb , struct net_device * dev ,
struct packet_type * ptype ,
struct net_device * orig_dev )
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
interface = container_of ( ptype , struct bnx2fc_interface ,
fip_packet_type ) ;
fcoe_ctlr_recv ( & interface - > ctlr , skb ) ;
2011-02-04 23:10:34 +03:00
return 0 ;
}
/**
* bnx2fc_update_src_mac - Update Ethernet MAC filters .
*
* @ fip : FCoE controller .
* @ old : Unicast MAC address to delete if the MAC is non - zero .
* @ new : Unicast MAC address to add .
*
* Remove any previously - set unicast MAC filter .
* Add secondary FCoE MAC address filter for our OUI .
*/
static void bnx2fc_update_src_mac ( struct fc_lport * lport , u8 * addr )
{
struct fcoe_port * port = lport_priv ( lport ) ;
memcpy ( port - > data_src_addr , addr , ETH_ALEN ) ;
}
/**
* bnx2fc_get_src_mac - return the ethernet source address for an lport
*
* @ lport : libfc port
*/
static u8 * bnx2fc_get_src_mac ( struct fc_lport * lport )
{
struct fcoe_port * port ;
port = ( struct fcoe_port * ) lport_priv ( lport ) ;
return port - > data_src_addr ;
}
/**
* bnx2fc_fip_send - send an Ethernet - encapsulated FIP frame .
*
* @ fip : FCoE controller .
* @ skb : FIP Packet .
*/
static void bnx2fc_fip_send ( struct fcoe_ctlr * fip , struct sk_buff * skb )
{
skb - > dev = bnx2fc_from_ctlr ( fip ) - > netdev ;
dev_queue_xmit ( skb ) ;
}
static int bnx2fc_vport_create ( struct fc_vport * vport , bool disabled )
{
struct Scsi_Host * shost = vport_to_shost ( vport ) ;
struct fc_lport * n_port = shost_priv ( shost ) ;
struct fcoe_port * port = lport_priv ( n_port ) ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface = port - > priv ;
struct net_device * netdev = interface - > netdev ;
2011-02-04 23:10:34 +03:00
struct fc_lport * vn_port ;
2011-07-27 01:51:39 +04:00
if ( ! test_bit ( BNX2FC_FLAG_FW_INIT_DONE , & interface - > hba - > flags ) ) {
2011-02-04 23:10:34 +03:00
printk ( KERN_ERR PFX " vn ports cannot be created on "
2011-07-27 01:51:39 +04:00
" this interface \n " ) ;
2011-02-04 23:10:34 +03:00
return - EIO ;
}
mutex_lock ( & bnx2fc_dev_lock ) ;
2011-07-27 01:51:39 +04:00
vn_port = bnx2fc_if_create ( interface , & vport - > dev , 1 ) ;
2011-02-04 23:10:34 +03:00
mutex_unlock ( & bnx2fc_dev_lock ) ;
if ( IS_ERR ( vn_port ) ) {
printk ( KERN_ERR PFX " bnx2fc_vport_create (%s) failed \n " ,
netdev - > name ) ;
return - EIO ;
}
if ( disabled ) {
fc_vport_set_state ( vport , FC_VPORT_DISABLED ) ;
} else {
vn_port - > boot_time = jiffies ;
fc_lport_init ( vn_port ) ;
fc_fabric_login ( vn_port ) ;
fc_vport_setlink ( vn_port ) ;
}
return 0 ;
}
static int bnx2fc_vport_destroy ( struct fc_vport * vport )
{
struct Scsi_Host * shost = vport_to_shost ( vport ) ;
struct fc_lport * n_port = shost_priv ( shost ) ;
struct fc_lport * vn_port = vport - > dd_data ;
struct fcoe_port * port = lport_priv ( vn_port ) ;
2011-08-05 04:38:39 +04:00
struct fc_lport * v_port ;
bool found = false ;
2011-02-04 23:10:34 +03:00
mutex_lock ( & n_port - > lp_mutex ) ;
2011-08-05 04:38:39 +04:00
list_for_each_entry ( v_port , & n_port - > vports , list )
if ( v_port - > vport = = vport ) {
found = true ;
break ;
}
if ( ! found ) {
mutex_unlock ( & n_port - > lp_mutex ) ;
return - ENOENT ;
}
2011-02-04 23:10:34 +03:00
list_del ( & vn_port - > list ) ;
mutex_unlock ( & n_port - > lp_mutex ) ;
queue_work ( bnx2fc_wq , & port - > destroy_work ) ;
return 0 ;
}
static int bnx2fc_vport_disable ( struct fc_vport * vport , bool disable )
{
struct fc_lport * lport = vport - > dd_data ;
if ( disable ) {
fc_vport_set_state ( vport , FC_VPORT_DISABLED ) ;
fc_fabric_logoff ( lport ) ;
} else {
lport - > boot_time = jiffies ;
fc_fabric_login ( lport ) ;
fc_vport_setlink ( lport ) ;
}
return 0 ;
}
2011-08-05 04:38:40 +04:00
static int bnx2fc_interface_setup ( struct bnx2fc_interface * interface )
2011-02-04 23:10:34 +03:00
{
2011-07-27 01:51:39 +04:00
struct net_device * netdev = interface - > netdev ;
struct net_device * physdev = interface - > hba - > phys_dev ;
2011-02-04 23:10:34 +03:00
struct netdev_hw_addr * ha ;
int sel_san_mac = 0 ;
/* setup Source MAC Address */
rcu_read_lock ( ) ;
for_each_dev_addr ( physdev , ha ) {
BNX2FC_MISC_DBG ( " net_config: ha->type = %d, fip_mac = " ,
ha - > type ) ;
printk ( KERN_INFO " %2x:%2x:%2x:%2x:%2x:%2x \n " , ha - > addr [ 0 ] ,
ha - > addr [ 1 ] , ha - > addr [ 2 ] , ha - > addr [ 3 ] ,
ha - > addr [ 4 ] , ha - > addr [ 5 ] ) ;
if ( ( ha - > type = = NETDEV_HW_ADDR_T_SAN ) & &
( is_valid_ether_addr ( ha - > addr ) ) ) {
2011-07-27 01:51:39 +04:00
memcpy ( interface - > ctlr . ctl_src_addr , ha - > addr ,
ETH_ALEN ) ;
2011-02-04 23:10:34 +03:00
sel_san_mac = 1 ;
BNX2FC_MISC_DBG ( " Found SAN MAC \n " ) ;
}
}
rcu_read_unlock ( ) ;
if ( ! sel_san_mac )
return - ENODEV ;
2011-07-27 01:51:39 +04:00
interface - > fip_packet_type . func = bnx2fc_fip_recv ;
interface - > fip_packet_type . type = htons ( ETH_P_FIP ) ;
interface - > fip_packet_type . dev = netdev ;
dev_add_pack ( & interface - > fip_packet_type ) ;
2011-02-04 23:10:34 +03:00
2011-07-27 01:51:39 +04:00
interface - > fcoe_packet_type . func = bnx2fc_rcv ;
interface - > fcoe_packet_type . type = __constant_htons ( ETH_P_FCOE ) ;
interface - > fcoe_packet_type . dev = netdev ;
dev_add_pack ( & interface - > fcoe_packet_type ) ;
2011-02-04 23:10:34 +03:00
return 0 ;
}
static int bnx2fc_attach_transport ( void )
{
bnx2fc_transport_template =
fc_attach_transport ( & bnx2fc_transport_function ) ;
if ( bnx2fc_transport_template = = NULL ) {
printk ( KERN_ERR PFX " Failed to attach FC transport \n " ) ;
return - ENODEV ;
}
bnx2fc_vport_xport_template =
fc_attach_transport ( & bnx2fc_vport_xport_function ) ;
if ( bnx2fc_vport_xport_template = = NULL ) {
printk ( KERN_ERR PFX
" Failed to attach FC transport for vport \n " ) ;
fc_release_transport ( bnx2fc_transport_template ) ;
bnx2fc_transport_template = NULL ;
return - ENODEV ;
}
return 0 ;
}
static void bnx2fc_release_transport ( void )
{
fc_release_transport ( bnx2fc_transport_template ) ;
fc_release_transport ( bnx2fc_vport_xport_template ) ;
bnx2fc_transport_template = NULL ;
bnx2fc_vport_xport_template = NULL ;
}
static void bnx2fc_interface_release ( struct kref * kref )
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
struct net_device * netdev ;
2011-07-27 01:51:39 +04:00
interface = container_of ( kref , struct bnx2fc_interface , kref ) ;
2011-04-25 23:30:09 +04:00
BNX2FC_MISC_DBG ( " Interface is being released \n " ) ;
2011-02-04 23:10:34 +03:00
2011-07-27 01:51:39 +04:00
netdev = interface - > netdev ;
2011-02-04 23:10:34 +03:00
/* tear-down FIP controller */
2011-07-27 01:51:39 +04:00
if ( test_and_clear_bit ( BNX2FC_CTLR_INIT_DONE , & interface - > if_flags ) )
fcoe_ctlr_destroy ( & interface - > ctlr ) ;
kfree ( interface ) ;
2011-02-04 23:10:34 +03:00
dev_put ( netdev ) ;
module_put ( THIS_MODULE ) ;
}
2011-07-27 01:51:39 +04:00
static inline void bnx2fc_interface_get ( struct bnx2fc_interface * interface )
2011-02-04 23:10:34 +03:00
{
2011-07-27 01:51:39 +04:00
kref_get ( & interface - > kref ) ;
2011-02-04 23:10:34 +03:00
}
2011-07-27 01:51:39 +04:00
static inline void bnx2fc_interface_put ( struct bnx2fc_interface * interface )
2011-02-04 23:10:34 +03:00
{
2011-07-27 01:51:39 +04:00
kref_put ( & interface - > kref , bnx2fc_interface_release ) ;
2011-02-04 23:10:34 +03:00
}
2011-07-27 01:51:39 +04:00
static void bnx2fc_hba_destroy ( struct bnx2fc_hba * hba )
2011-02-04 23:10:34 +03:00
{
2011-07-27 01:51:39 +04:00
/* Free the command manager */
if ( hba - > cmd_mgr ) {
bnx2fc_cmd_mgr_free ( hba - > cmd_mgr ) ;
hba - > cmd_mgr = NULL ;
}
kfree ( hba - > tgt_ofld_list ) ;
2011-02-04 23:10:34 +03:00
bnx2fc_unbind_pcidev ( hba ) ;
kfree ( hba ) ;
}
/**
2011-07-27 01:51:39 +04:00
* bnx2fc_hba_create - create a new bnx2fc hba
2011-02-04 23:10:34 +03:00
*
* @ cnic : pointer to cnic device
*
2011-07-27 01:51:39 +04:00
* Creates a new FCoE hba on the given device .
*
2011-02-04 23:10:34 +03:00
*/
2011-07-27 01:51:39 +04:00
static struct bnx2fc_hba * bnx2fc_hba_create ( struct cnic_dev * cnic )
2011-02-04 23:10:34 +03:00
{
struct bnx2fc_hba * hba ;
int rc ;
hba = kzalloc ( sizeof ( * hba ) , GFP_KERNEL ) ;
if ( ! hba ) {
printk ( KERN_ERR PFX " Unable to allocate hba structure \n " ) ;
return NULL ;
}
spin_lock_init ( & hba - > hba_lock ) ;
mutex_init ( & hba - > hba_mutex ) ;
hba - > cnic = cnic ;
rc = bnx2fc_bind_pcidev ( hba ) ;
2011-07-27 01:51:39 +04:00
if ( rc ) {
printk ( KERN_ERR PFX " create_adapter: bind error \n " ) ;
2011-02-04 23:10:34 +03:00
goto bind_err ;
2011-07-27 01:51:39 +04:00
}
2011-02-04 23:10:34 +03:00
hba - > phys_dev = cnic - > netdev ;
2011-07-27 01:51:39 +04:00
hba - > next_conn_id = 0 ;
hba - > tgt_ofld_list =
kzalloc ( sizeof ( struct bnx2fc_rport * ) * BNX2FC_NUM_MAX_SESS ,
GFP_KERNEL ) ;
if ( ! hba - > tgt_ofld_list ) {
printk ( KERN_ERR PFX " Unable to allocate tgt offload list \n " ) ;
goto tgtofld_err ;
}
hba - > num_ofld_sess = 0 ;
hba - > cmd_mgr = bnx2fc_cmd_mgr_alloc ( hba , BNX2FC_MIN_XID ,
BNX2FC_MAX_XID ) ;
if ( ! hba - > cmd_mgr ) {
printk ( KERN_ERR PFX " em_config:bnx2fc_cmd_mgr_alloc failed \n " ) ;
goto cmgr_err ;
}
2011-02-04 23:10:34 +03:00
init_waitqueue_head ( & hba - > shutdown_wait ) ;
init_waitqueue_head ( & hba - > destroy_wait ) ;
2011-07-27 01:51:39 +04:00
INIT_LIST_HEAD ( & hba - > vports ) ;
2011-02-04 23:10:34 +03:00
return hba ;
2011-07-27 01:51:39 +04:00
cmgr_err :
kfree ( hba - > tgt_ofld_list ) ;
tgtofld_err :
bnx2fc_unbind_pcidev ( hba ) ;
2011-02-04 23:10:34 +03:00
bind_err :
kfree ( hba ) ;
return NULL ;
}
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * bnx2fc_interface_create ( struct bnx2fc_hba * hba ,
struct net_device * netdev ,
enum fip_state fip_mode )
2011-02-04 23:10:34 +03:00
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
int rc = 0 ;
2011-07-27 01:51:39 +04:00
interface = kzalloc ( sizeof ( * interface ) , GFP_KERNEL ) ;
if ( ! interface ) {
printk ( KERN_ERR PFX " Unable to allocate interface structure \n " ) ;
return NULL ;
}
2011-02-04 23:10:34 +03:00
dev_hold ( netdev ) ;
2011-07-27 01:51:39 +04:00
kref_init ( & interface - > kref ) ;
interface - > hba = hba ;
interface - > netdev = netdev ;
2011-02-04 23:10:34 +03:00
/* Initialize FIP */
2011-07-27 01:51:39 +04:00
fcoe_ctlr_init ( & interface - > ctlr , fip_mode ) ;
interface - > ctlr . send = bnx2fc_fip_send ;
interface - > ctlr . update_mac = bnx2fc_update_src_mac ;
interface - > ctlr . get_src_addr = bnx2fc_get_src_mac ;
set_bit ( BNX2FC_CTLR_INIT_DONE , & interface - > if_flags ) ;
2011-02-04 23:10:34 +03:00
2011-08-05 04:38:40 +04:00
rc = bnx2fc_interface_setup ( interface ) ;
2011-07-27 01:51:39 +04:00
if ( ! rc )
return interface ;
2011-02-04 23:10:34 +03:00
2011-07-27 01:51:39 +04:00
fcoe_ctlr_destroy ( & interface - > ctlr ) ;
2011-02-04 23:10:34 +03:00
dev_put ( netdev ) ;
2011-07-27 01:51:39 +04:00
kfree ( interface ) ;
return NULL ;
2011-02-04 23:10:34 +03:00
}
/**
* bnx2fc_if_create - Create FCoE instance on a given interface
*
2011-07-27 01:51:39 +04:00
* @ interface : FCoE interface to create a local port on
2011-02-04 23:10:34 +03:00
* @ parent : Device pointer to be the parent in sysfs for the SCSI host
* @ npiv : Indicates if the port is vport or not
*
* Creates a fc_lport instance and a Scsi_Host instance and configure them .
*
* Returns : Allocated fc_lport or an error pointer
*/
2011-07-27 01:51:39 +04:00
static struct fc_lport * bnx2fc_if_create ( struct bnx2fc_interface * interface ,
2011-02-04 23:10:34 +03:00
struct device * parent , int npiv )
{
2011-04-29 02:55:44 +04:00
struct fc_lport * lport , * n_port ;
2011-02-04 23:10:34 +03:00
struct fcoe_port * port ;
struct Scsi_Host * shost ;
struct fc_vport * vport = dev_to_vport ( parent ) ;
2011-05-27 22:47:27 +04:00
struct bnx2fc_lport * blport ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_hba * hba ;
2011-02-04 23:10:34 +03:00
int rc = 0 ;
2011-05-27 22:47:27 +04:00
blport = kzalloc ( sizeof ( struct bnx2fc_lport ) , GFP_KERNEL ) ;
if ( ! blport ) {
2011-07-27 01:51:39 +04:00
BNX2FC_HBA_DBG ( interface - > ctlr . lp , " Unable to alloc blport \n " ) ;
2011-05-27 22:47:27 +04:00
return NULL ;
}
2011-02-04 23:10:34 +03:00
/* Allocate Scsi_Host structure */
2011-04-29 02:55:44 +04:00
if ( ! npiv )
lport = libfc_host_alloc ( & bnx2fc_shost_template , sizeof ( * port ) ) ;
else
lport = libfc_vport_create ( vport , sizeof ( * port ) ) ;
2011-02-04 23:10:34 +03:00
if ( ! lport ) {
printk ( KERN_ERR PFX " could not allocate scsi host structure \n " ) ;
2011-05-27 22:47:27 +04:00
goto free_blport ;
2011-02-04 23:10:34 +03:00
}
shost = lport - > host ;
port = lport_priv ( lport ) ;
port - > lport = lport ;
2011-07-27 01:51:39 +04:00
port - > priv = interface ;
2011-02-04 23:10:34 +03:00
INIT_WORK ( & port - > destroy_work , bnx2fc_destroy_work ) ;
/* Configure fcoe_port */
rc = bnx2fc_lport_config ( lport ) ;
if ( rc )
goto lp_config_err ;
if ( npiv ) {
printk ( KERN_ERR PFX " Setting vport names, 0x%llX 0x%llX \n " ,
vport - > node_name , vport - > port_name ) ;
fc_set_wwnn ( lport , vport - > node_name ) ;
fc_set_wwpn ( lport , vport - > port_name ) ;
}
/* Configure netdev and networking properties of the lport */
rc = bnx2fc_net_config ( lport ) ;
if ( rc ) {
printk ( KERN_ERR PFX " Error on bnx2fc_net_config \n " ) ;
goto lp_config_err ;
}
rc = bnx2fc_shost_config ( lport , parent ) ;
if ( rc ) {
printk ( KERN_ERR PFX " Couldnt configure shost for %s \n " ,
2011-07-27 01:51:39 +04:00
interface - > netdev - > name ) ;
2011-02-04 23:10:34 +03:00
goto lp_config_err ;
}
/* Initialize the libfc library */
rc = bnx2fc_libfc_config ( lport ) ;
if ( rc ) {
printk ( KERN_ERR PFX " Couldnt configure libfc \n " ) ;
goto shost_err ;
}
fc_host_port_type ( lport - > host ) = FC_PORTTYPE_UNKNOWN ;
/* Allocate exchange manager */
2011-04-29 02:55:44 +04:00
if ( ! npiv )
2011-02-04 23:10:34 +03:00
rc = bnx2fc_em_config ( lport ) ;
2011-04-29 02:55:44 +04:00
else {
shost = vport_to_shost ( vport ) ;
n_port = shost_priv ( shost ) ;
rc = fc_exch_mgr_list_clone ( n_port , lport ) ;
}
if ( rc ) {
printk ( KERN_ERR PFX " Error on bnx2fc_em_config \n " ) ;
goto shost_err ;
2011-02-04 23:10:34 +03:00
}
2011-07-27 01:51:39 +04:00
bnx2fc_interface_get ( interface ) ;
2011-05-27 22:47:27 +04:00
2011-07-27 01:51:39 +04:00
hba = interface - > hba ;
2011-05-27 22:47:27 +04:00
spin_lock_bh ( & hba - > hba_lock ) ;
blport - > lport = lport ;
list_add_tail ( & blport - > list , & hba - > vports ) ;
spin_unlock_bh ( & hba - > hba_lock ) ;
2011-02-04 23:10:34 +03:00
return lport ;
shost_err :
scsi_remove_host ( shost ) ;
lp_config_err :
scsi_host_put ( lport - > host ) ;
2011-05-27 22:47:27 +04:00
free_blport :
kfree ( blport ) ;
2011-02-04 23:10:34 +03:00
return NULL ;
}
2011-08-05 04:38:40 +04:00
static void bnx2fc_interface_cleanup ( struct bnx2fc_interface * interface )
2011-02-04 23:10:34 +03:00
{
2011-08-05 04:38:41 +04:00
struct fc_lport * lport = interface - > ctlr . lp ;
2011-02-04 23:10:34 +03:00
struct fcoe_port * port = lport_priv ( lport ) ;
2011-05-27 22:47:27 +04:00
struct bnx2fc_lport * blport , * tmp ;
2011-08-05 04:38:41 +04:00
struct bnx2fc_hba * hba = interface - > hba ;
2011-02-04 23:10:34 +03:00
/* Stop the transmit retry timer */
del_timer_sync ( & port - > timer ) ;
/* Free existing transmit skbs */
fcoe_clean_pending_queue ( lport ) ;
2011-08-05 04:38:41 +04:00
/* Dont listen for Ethernet packets anymore */
__dev_remove_pack ( & interface - > fcoe_packet_type ) ;
__dev_remove_pack ( & interface - > fip_packet_type ) ;
synchronize_net ( ) ;
spin_lock_bh ( & hba - > hba_lock ) ;
list_for_each_entry_safe ( blport , tmp , & hba - > vports , list ) {
if ( blport - > lport = = lport ) {
list_del ( & blport - > list ) ;
kfree ( blport ) ;
}
}
spin_unlock_bh ( & hba - > hba_lock ) ;
}
static void bnx2fc_if_destroy ( struct fc_lport * lport )
{
2011-02-04 23:10:34 +03:00
/* Free queued packets for the receive thread */
bnx2fc_clean_rx_queue ( lport ) ;
/* Detach from scsi-ml */
fc_remove_host ( lport - > host ) ;
scsi_remove_host ( lport - > host ) ;
/*
* Note that only the physical lport will have the exchange manager .
* for vports , this function is NOP
*/
fc_exch_mgr_free ( lport ) ;
/* Free memory used by statistical counters */
fc_lport_free_stats ( lport ) ;
/* Release Scsi_Host */
scsi_host_put ( lport - > host ) ;
}
/**
* bnx2fc_destroy - Destroy a bnx2fc FCoE interface
*
* @ buffer : The name of the Ethernet interface to be destroyed
* @ kp : The associated kernel parameter
*
* Called from sysfs .
*
* Returns : 0 for success
*/
static int bnx2fc_destroy ( struct net_device * netdev )
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface = NULL ;
struct fc_lport * lport ;
2011-02-04 23:10:34 +03:00
int rc = 0 ;
2011-03-18 03:13:27 +03:00
rtnl_lock ( ) ;
2011-02-04 23:10:34 +03:00
mutex_lock ( & bnx2fc_dev_lock ) ;
2011-07-27 01:51:39 +04:00
interface = bnx2fc_interface_lookup ( netdev ) ;
if ( ! interface | | ! interface - > ctlr . lp ) {
2011-02-04 23:10:34 +03:00
rc = - ENODEV ;
2011-07-27 01:51:39 +04:00
printk ( KERN_ERR PFX " bnx2fc_destroy: interface or lport not found \n " ) ;
2011-02-04 23:10:34 +03:00
goto netdev_err ;
}
2011-08-05 04:38:40 +04:00
bnx2fc_interface_cleanup ( interface ) ;
2011-07-27 01:51:39 +04:00
lport = interface - > ctlr . lp ;
bnx2fc_stop ( interface ) ;
list_del ( & interface - > list ) ;
destroy_workqueue ( interface - > timer_work_queue ) ;
bnx2fc_interface_put ( interface ) ;
2011-08-05 04:38:41 +04:00
bnx2fc_if_destroy ( lport ) ;
2011-02-04 23:10:34 +03:00
netdev_err :
mutex_unlock ( & bnx2fc_dev_lock ) ;
rtnl_unlock ( ) ;
return rc ;
}
static void bnx2fc_destroy_work ( struct work_struct * work )
{
struct fcoe_port * port ;
struct fc_lport * lport ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
port = container_of ( work , struct fcoe_port , destroy_work ) ;
lport = port - > lport ;
2011-07-27 01:51:39 +04:00
interface = port - > priv ;
2011-02-04 23:10:34 +03:00
BNX2FC_HBA_DBG ( lport , " Entered bnx2fc_destroy_work \n " ) ;
bnx2fc_port_shutdown ( lport ) ;
rtnl_lock ( ) ;
mutex_lock ( & bnx2fc_dev_lock ) ;
2011-08-05 04:38:41 +04:00
bnx2fc_if_destroy ( lport ) ;
2011-02-04 23:10:34 +03:00
mutex_unlock ( & bnx2fc_dev_lock ) ;
rtnl_unlock ( ) ;
}
static void bnx2fc_unbind_adapter_devices ( struct bnx2fc_hba * hba )
{
bnx2fc_free_fw_resc ( hba ) ;
bnx2fc_free_task_ctx ( hba ) ;
}
/**
* bnx2fc_bind_adapter_devices - binds bnx2fc adapter with the associated
* pci structure
*
* @ hba : Adapter instance
*/
static int bnx2fc_bind_adapter_devices ( struct bnx2fc_hba * hba )
{
if ( bnx2fc_setup_task_ctx ( hba ) )
goto mem_err ;
if ( bnx2fc_setup_fw_resc ( hba ) )
goto mem_err ;
return 0 ;
mem_err :
bnx2fc_unbind_adapter_devices ( hba ) ;
return - ENOMEM ;
}
static int bnx2fc_bind_pcidev ( struct bnx2fc_hba * hba )
{
struct cnic_dev * cnic ;
if ( ! hba - > cnic ) {
printk ( KERN_ERR PFX " cnic is NULL \n " ) ;
return - ENODEV ;
}
cnic = hba - > cnic ;
hba - > pcidev = cnic - > pcidev ;
if ( hba - > pcidev )
pci_dev_get ( hba - > pcidev ) ;
return 0 ;
}
static void bnx2fc_unbind_pcidev ( struct bnx2fc_hba * hba )
{
if ( hba - > pcidev )
pci_dev_put ( hba - > pcidev ) ;
hba - > pcidev = NULL ;
}
/**
* bnx2fc_ulp_start - cnic callback to initialize & start adapter instance
*
* @ handle : transport handle pointing to adapter struture
*
* This function maps adapter structure to pcidev structure and initiates
* firmware handshake to enable / initialize on - chip FCoE components .
* This bnx2fc - cnic interface api callback is used after following
* conditions are met -
* a ) underlying network interface is up ( marked by event NETDEV_UP
* from netdev
* b ) bnx2fc adatper structure is registered .
*/
static void bnx2fc_ulp_start ( void * handle )
{
struct bnx2fc_hba * hba = handle ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
struct fc_lport * lport ;
2011-02-04 23:10:34 +03:00
mutex_lock ( & bnx2fc_dev_lock ) ;
2011-07-27 01:51:39 +04:00
if ( ! test_bit ( BNX2FC_FLAG_FW_INIT_DONE , & hba - > flags ) )
2011-02-04 23:10:34 +03:00
bnx2fc_fw_init ( hba ) ;
BNX2FC_MISC_DBG ( " bnx2fc started. \n " ) ;
2011-07-27 01:51:39 +04:00
list_for_each_entry ( interface , & if_list , list ) {
if ( interface - > hba = = hba ) {
lport = interface - > ctlr . lp ;
/* Kick off Fabric discovery*/
printk ( KERN_ERR PFX " ulp_init: start discovery \n " ) ;
lport - > tt . frame_send = bnx2fc_xmit ;
bnx2fc_start_disc ( interface ) ;
}
2011-02-04 23:10:34 +03:00
}
2011-07-27 01:51:39 +04:00
mutex_unlock ( & bnx2fc_dev_lock ) ;
2011-02-04 23:10:34 +03:00
}
static void bnx2fc_port_shutdown ( struct fc_lport * lport )
{
BNX2FC_MISC_DBG ( " Entered %s \n " , __func__ ) ;
fc_fabric_logoff ( lport ) ;
fc_lport_destroy ( lport ) ;
}
2011-07-27 01:51:39 +04:00
static void bnx2fc_stop ( struct bnx2fc_interface * interface )
2011-02-04 23:10:34 +03:00
{
struct fc_lport * lport ;
struct fc_lport * vport ;
2011-07-27 01:51:39 +04:00
if ( ! test_bit ( BNX2FC_FLAG_FW_INIT_DONE , & interface - > hba - > flags ) )
return ;
2011-02-04 23:10:34 +03:00
2011-07-27 01:51:39 +04:00
lport = interface - > ctlr . lp ;
bnx2fc_port_shutdown ( lport ) ;
mutex_lock ( & lport - > lp_mutex ) ;
list_for_each_entry ( vport , & lport - > vports , list )
fc_host_port_type ( vport - > host ) =
FC_PORTTYPE_UNKNOWN ;
mutex_unlock ( & lport - > lp_mutex ) ;
fc_host_port_type ( lport - > host ) = FC_PORTTYPE_UNKNOWN ;
fcoe_ctlr_link_down ( & interface - > ctlr ) ;
fcoe_clean_pending_queue ( lport ) ;
2011-02-04 23:10:34 +03:00
}
static int bnx2fc_fw_init ( struct bnx2fc_hba * hba )
{
# define BNX2FC_INIT_POLL_TIME (1000 / HZ)
int rc = - 1 ;
int i = HZ ;
rc = bnx2fc_bind_adapter_devices ( hba ) ;
if ( rc ) {
printk ( KERN_ALERT PFX
" bnx2fc_bind_adapter_devices failed - rc = %d \n " , rc ) ;
goto err_out ;
}
rc = bnx2fc_send_fw_fcoe_init_msg ( hba ) ;
if ( rc ) {
printk ( KERN_ALERT PFX
" bnx2fc_send_fw_fcoe_init_msg failed - rc = %d \n " , rc ) ;
goto err_unbind ;
}
/*
* Wait until the adapter init message is complete , and adapter
* state is UP .
*/
while ( ! test_bit ( ADAPTER_STATE_UP , & hba - > adapter_state ) & & i - - )
msleep ( BNX2FC_INIT_POLL_TIME ) ;
if ( ! test_bit ( ADAPTER_STATE_UP , & hba - > adapter_state ) ) {
printk ( KERN_ERR PFX " bnx2fc_start: %s failed to initialize. "
" Ignoring... \n " ,
hba - > cnic - > netdev - > name ) ;
rc = - 1 ;
goto err_unbind ;
}
2011-07-27 01:51:39 +04:00
set_bit ( BNX2FC_FLAG_FW_INIT_DONE , & hba - > flags ) ;
2011-02-04 23:10:34 +03:00
return 0 ;
err_unbind :
bnx2fc_unbind_adapter_devices ( hba ) ;
err_out :
return rc ;
}
static void bnx2fc_fw_destroy ( struct bnx2fc_hba * hba )
{
2011-07-27 01:51:39 +04:00
if ( test_and_clear_bit ( BNX2FC_FLAG_FW_INIT_DONE , & hba - > flags ) ) {
2011-02-04 23:10:34 +03:00
if ( bnx2fc_send_fw_fcoe_destroy_msg ( hba ) = = 0 ) {
init_timer ( & hba - > destroy_timer ) ;
hba - > destroy_timer . expires = BNX2FC_FW_TIMEOUT +
jiffies ;
hba - > destroy_timer . function = bnx2fc_destroy_timer ;
hba - > destroy_timer . data = ( unsigned long ) hba ;
add_timer ( & hba - > destroy_timer ) ;
wait_event_interruptible ( hba - > destroy_wait ,
2011-07-27 01:51:39 +04:00
test_bit ( BNX2FC_FLAG_DESTROY_CMPL ,
& hba - > flags ) ) ;
2011-02-04 23:10:34 +03:00
/* This should never happen */
if ( signal_pending ( current ) )
flush_signals ( current ) ;
del_timer_sync ( & hba - > destroy_timer ) ;
}
bnx2fc_unbind_adapter_devices ( hba ) ;
}
}
/**
* bnx2fc_ulp_stop - cnic callback to shutdown adapter instance
*
* @ handle : transport handle pointing to adapter structure
*
* Driver checks if adapter is already in shutdown mode , if not start
* the shutdown process .
*/
static void bnx2fc_ulp_stop ( void * handle )
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_hba * hba = handle ;
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
printk ( KERN_ERR " ULP_STOP \n " ) ;
mutex_lock ( & bnx2fc_dev_lock ) ;
2011-07-27 01:51:39 +04:00
if ( ! test_bit ( BNX2FC_FLAG_FW_INIT_DONE , & hba - > flags ) )
goto exit ;
list_for_each_entry ( interface , & if_list , list ) {
if ( interface - > hba = = hba )
bnx2fc_stop ( interface ) ;
}
BUG_ON ( hba - > num_ofld_sess ! = 0 ) ;
mutex_lock ( & hba - > hba_mutex ) ;
clear_bit ( ADAPTER_STATE_UP , & hba - > adapter_state ) ;
clear_bit ( ADAPTER_STATE_GOING_DOWN ,
& hba - > adapter_state ) ;
clear_bit ( ADAPTER_STATE_READY , & hba - > adapter_state ) ;
mutex_unlock ( & hba - > hba_mutex ) ;
2011-02-04 23:10:34 +03:00
bnx2fc_fw_destroy ( hba ) ;
2011-07-27 01:51:39 +04:00
exit :
2011-02-04 23:10:34 +03:00
mutex_unlock ( & bnx2fc_dev_lock ) ;
}
2011-07-27 01:51:39 +04:00
static void bnx2fc_start_disc ( struct bnx2fc_interface * interface )
2011-02-04 23:10:34 +03:00
{
struct fc_lport * lport ;
int wait_cnt = 0 ;
BNX2FC_MISC_DBG ( " Entered %s \n " , __func__ ) ;
/* Kick off FIP/FLOGI */
2011-07-27 01:51:39 +04:00
if ( ! test_bit ( BNX2FC_FLAG_FW_INIT_DONE , & interface - > hba - > flags ) ) {
2011-02-04 23:10:34 +03:00
printk ( KERN_ERR PFX " Init not done yet \n " ) ;
return ;
}
2011-07-27 01:51:39 +04:00
lport = interface - > ctlr . lp ;
2011-02-04 23:10:34 +03:00
BNX2FC_HBA_DBG ( lport , " calling fc_fabric_login \n " ) ;
if ( ! bnx2fc_link_ok ( lport ) ) {
BNX2FC_HBA_DBG ( lport , " ctlr_link_up \n " ) ;
2011-07-27 01:51:39 +04:00
fcoe_ctlr_link_up ( & interface - > ctlr ) ;
2011-02-04 23:10:34 +03:00
fc_host_port_type ( lport - > host ) = FC_PORTTYPE_NPORT ;
2011-07-27 01:51:39 +04:00
set_bit ( ADAPTER_STATE_READY , & interface - > hba - > adapter_state ) ;
2011-02-04 23:10:34 +03:00
}
/* wait for the FCF to be selected before issuing FLOGI */
2011-07-27 01:51:39 +04:00
while ( ! interface - > ctlr . sel_fcf ) {
2011-02-04 23:10:34 +03:00
msleep ( 250 ) ;
/* give up after 3 secs */
if ( + + wait_cnt > 12 )
break ;
}
2011-08-05 04:38:35 +04:00
/* Reset max receive frame size to default */
if ( fc_set_mfs ( lport , BNX2FC_MFS ) )
return ;
2011-02-04 23:10:34 +03:00
fc_lport_init ( lport ) ;
fc_fabric_login ( lport ) ;
}
/**
* bnx2fc_ulp_init - Initialize an adapter instance
*
* @ dev : cnic device handle
* Called from cnic_register_driver ( ) context to initialize all
* enumerated cnic devices . This routine allocates adapter structure
* and other device specific resources .
*/
static void bnx2fc_ulp_init ( struct cnic_dev * dev )
{
struct bnx2fc_hba * hba ;
int rc = 0 ;
BNX2FC_MISC_DBG ( " Entered %s \n " , __func__ ) ;
/* bnx2fc works only when bnx2x is loaded */
2011-07-27 01:51:39 +04:00
if ( ! test_bit ( CNIC_F_BNX2X_CLASS , & dev - > flags ) | |
( dev - > max_fcoe_conn = = 0 ) ) {
2011-02-04 23:10:34 +03:00
printk ( KERN_ERR PFX " bnx2fc FCoE not supported on %s, "
2011-07-27 01:51:39 +04:00
" flags: %lx fcoe_conn: %d \n " ,
dev - > netdev - > name , dev - > flags , dev - > max_fcoe_conn ) ;
2011-02-04 23:10:34 +03:00
return ;
}
2011-07-27 01:51:39 +04:00
hba = bnx2fc_hba_create ( dev ) ;
2011-02-04 23:10:34 +03:00
if ( ! hba ) {
printk ( KERN_ERR PFX " hba initialization failed \n " ) ;
return ;
}
/* Add HBA to the adapter list */
mutex_lock ( & bnx2fc_dev_lock ) ;
2011-07-27 01:51:39 +04:00
list_add_tail ( & hba - > list , & adapter_list ) ;
2011-02-04 23:10:34 +03:00
adapter_count + + ;
mutex_unlock ( & bnx2fc_dev_lock ) ;
clear_bit ( BNX2FC_CNIC_REGISTERED , & hba - > reg_with_cnic ) ;
rc = dev - > register_device ( dev , CNIC_ULP_FCOE ,
( void * ) hba ) ;
if ( rc )
2011-06-28 10:30:53 +04:00
printk ( KERN_ERR PFX " register_device failed, rc = %d \n " , rc ) ;
2011-02-04 23:10:34 +03:00
else
set_bit ( BNX2FC_CNIC_REGISTERED , & hba - > reg_with_cnic ) ;
}
static int bnx2fc_disable ( struct net_device * netdev )
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
int rc = 0 ;
2011-03-18 03:13:27 +03:00
rtnl_lock ( ) ;
2011-02-04 23:10:34 +03:00
mutex_lock ( & bnx2fc_dev_lock ) ;
2011-07-27 01:51:39 +04:00
interface = bnx2fc_interface_lookup ( netdev ) ;
if ( ! interface | | ! interface - > ctlr . lp ) {
2011-02-04 23:10:34 +03:00
rc = - ENODEV ;
2011-07-27 01:51:39 +04:00
printk ( KERN_ERR PFX " bnx2fc_disable: interface or lport not found \n " ) ;
2011-02-04 23:10:34 +03:00
} else {
2011-07-27 01:51:39 +04:00
fcoe_ctlr_link_down ( & interface - > ctlr ) ;
fcoe_clean_pending_queue ( interface - > ctlr . lp ) ;
2011-02-04 23:10:34 +03:00
}
mutex_unlock ( & bnx2fc_dev_lock ) ;
rtnl_unlock ( ) ;
return rc ;
}
static int bnx2fc_enable ( struct net_device * netdev )
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
int rc = 0 ;
2011-03-18 03:13:27 +03:00
rtnl_lock ( ) ;
2011-02-04 23:10:34 +03:00
mutex_lock ( & bnx2fc_dev_lock ) ;
2011-07-27 01:51:39 +04:00
interface = bnx2fc_interface_lookup ( netdev ) ;
if ( ! interface | | ! interface - > ctlr . lp ) {
2011-02-04 23:10:34 +03:00
rc = - ENODEV ;
2011-07-27 01:51:39 +04:00
printk ( KERN_ERR PFX " bnx2fc_enable: interface or lport not found \n " ) ;
} else if ( ! bnx2fc_link_ok ( interface - > ctlr . lp ) )
fcoe_ctlr_link_up ( & interface - > ctlr ) ;
2011-02-04 23:10:34 +03:00
mutex_unlock ( & bnx2fc_dev_lock ) ;
rtnl_unlock ( ) ;
return rc ;
}
/**
* bnx2fc_create - Create bnx2fc FCoE interface
*
* @ buffer : The name of Ethernet interface to create on
* @ kp : The associated kernel param
*
* Called from sysfs .
*
* Returns : 0 for success
*/
static int bnx2fc_create ( struct net_device * netdev , enum fip_state fip_mode )
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
struct bnx2fc_hba * hba ;
struct net_device * phys_dev ;
struct fc_lport * lport ;
struct ethtool_drvinfo drvinfo ;
int rc = 0 ;
int vlan_id ;
BNX2FC_MISC_DBG ( " Entered bnx2fc_create \n " ) ;
if ( fip_mode ! = FIP_MODE_FABRIC ) {
printk ( KERN_ERR " fip mode not FABRIC \n " ) ;
return - EIO ;
}
2011-03-18 03:13:27 +03:00
rtnl_lock ( ) ;
2011-02-04 23:10:34 +03:00
mutex_lock ( & bnx2fc_dev_lock ) ;
if ( ! try_module_get ( THIS_MODULE ) ) {
rc = - EINVAL ;
goto mod_err ;
}
/* obtain physical netdev */
if ( netdev - > priv_flags & IFF_802_1Q_VLAN ) {
phys_dev = vlan_dev_real_dev ( netdev ) ;
vlan_id = vlan_dev_vlan_id ( netdev ) ;
} else {
printk ( KERN_ERR PFX " Not a vlan device \n " ) ;
rc = - EINVAL ;
goto netdev_err ;
}
/* verify if the physical device is a netxtreme2 device */
if ( phys_dev - > ethtool_ops & & phys_dev - > ethtool_ops - > get_drvinfo ) {
memset ( & drvinfo , 0 , sizeof ( drvinfo ) ) ;
phys_dev - > ethtool_ops - > get_drvinfo ( phys_dev , & drvinfo ) ;
2011-07-27 01:51:39 +04:00
if ( strncmp ( drvinfo . driver , " bnx2x " , strlen ( " bnx2x " ) ) ) {
2011-02-04 23:10:34 +03:00
printk ( KERN_ERR PFX " Not a netxtreme2 device \n " ) ;
rc = - EINVAL ;
goto netdev_err ;
}
} else {
printk ( KERN_ERR PFX " unable to obtain drv_info \n " ) ;
rc = - EINVAL ;
goto netdev_err ;
}
2011-07-27 01:51:39 +04:00
/* obtain interface and initialize rest of the structure */
2011-02-04 23:10:34 +03:00
hba = bnx2fc_hba_lookup ( phys_dev ) ;
if ( ! hba ) {
rc = - ENODEV ;
printk ( KERN_ERR PFX " bnx2fc_create: hba not found \n " ) ;
goto netdev_err ;
}
2011-07-27 01:51:39 +04:00
if ( bnx2fc_interface_lookup ( netdev ) ) {
2011-02-04 23:10:34 +03:00
rc = - EEXIST ;
goto netdev_err ;
}
2011-07-27 01:51:39 +04:00
interface = bnx2fc_interface_create ( hba , netdev , fip_mode ) ;
if ( ! interface ) {
printk ( KERN_ERR PFX " bnx2fc_interface_create failed \n " ) ;
2011-02-04 23:10:34 +03:00
goto ifput_err ;
}
2011-07-27 01:51:39 +04:00
interface - > vlan_id = vlan_id ;
interface - > vlan_enabled = 1 ;
interface - > timer_work_queue =
2011-02-04 23:10:34 +03:00
create_singlethread_workqueue ( " bnx2fc_timer_wq " ) ;
2011-07-27 01:51:39 +04:00
if ( ! interface - > timer_work_queue ) {
2011-02-04 23:10:34 +03:00
printk ( KERN_ERR PFX " ulp_init could not create timer_wq \n " ) ;
rc = - EINVAL ;
goto ifput_err ;
}
2011-07-27 01:51:39 +04:00
lport = bnx2fc_if_create ( interface , & interface - > hba - > pcidev - > dev , 0 ) ;
2011-02-04 23:10:34 +03:00
if ( ! lport ) {
printk ( KERN_ERR PFX " Failed to create interface (%s) \n " ,
netdev - > name ) ;
2011-08-05 04:38:40 +04:00
bnx2fc_interface_cleanup ( interface ) ;
2011-02-04 23:10:34 +03:00
rc = - EINVAL ;
goto if_create_err ;
}
2011-07-27 01:51:39 +04:00
/* Add interface to if_list */
list_add_tail ( & interface - > list , & if_list ) ;
2011-02-04 23:10:34 +03:00
lport - > boot_time = jiffies ;
/* Make this master N_port */
2011-07-27 01:51:39 +04:00
interface - > ctlr . lp = lport ;
2011-02-04 23:10:34 +03:00
2011-07-27 01:51:39 +04:00
BNX2FC_HBA_DBG ( lport , " create: START DISC \n " ) ;
bnx2fc_start_disc ( interface ) ;
2011-02-04 23:10:34 +03:00
/*
* Release from kref_init in bnx2fc_interface_setup , on success
* lport should be holding a reference taken in bnx2fc_if_create
*/
2011-07-27 01:51:39 +04:00
bnx2fc_interface_put ( interface ) ;
2011-02-04 23:10:34 +03:00
/* put netdev that was held while calling dev_get_by_name */
mutex_unlock ( & bnx2fc_dev_lock ) ;
rtnl_unlock ( ) ;
return 0 ;
if_create_err :
2011-07-27 01:51:39 +04:00
destroy_workqueue ( interface - > timer_work_queue ) ;
2011-02-04 23:10:34 +03:00
ifput_err :
2011-07-27 01:51:39 +04:00
bnx2fc_interface_put ( interface ) ;
2011-02-04 23:10:34 +03:00
netdev_err :
module_put ( THIS_MODULE ) ;
mod_err :
mutex_unlock ( & bnx2fc_dev_lock ) ;
rtnl_unlock ( ) ;
return rc ;
}
/**
2011-07-27 01:51:39 +04:00
* bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc hba instance
2011-02-04 23:10:34 +03:00
*
* @ cnic : Pointer to cnic device instance
*
* */
static struct bnx2fc_hba * bnx2fc_find_hba_for_cnic ( struct cnic_dev * cnic )
{
struct list_head * list ;
struct list_head * temp ;
struct bnx2fc_hba * hba ;
/* Called with bnx2fc_dev_lock held */
list_for_each_safe ( list , temp , & adapter_list ) {
hba = ( struct bnx2fc_hba * ) list ;
if ( hba - > cnic = = cnic )
return hba ;
}
return NULL ;
}
2011-07-27 01:51:39 +04:00
static struct bnx2fc_interface * bnx2fc_interface_lookup ( struct net_device
* netdev )
{
struct bnx2fc_interface * interface ;
/* Called with bnx2fc_dev_lock held */
list_for_each_entry ( interface , & if_list , list ) {
if ( interface - > netdev = = netdev )
return interface ;
}
return NULL ;
}
static struct bnx2fc_hba * bnx2fc_hba_lookup ( struct net_device
* phys_dev )
2011-02-04 23:10:34 +03:00
{
struct bnx2fc_hba * hba ;
/* Called with bnx2fc_dev_lock held */
2011-07-27 01:51:39 +04:00
list_for_each_entry ( hba , & adapter_list , list ) {
2011-02-04 23:10:34 +03:00
if ( hba - > phys_dev = = phys_dev )
return hba ;
}
2011-07-27 01:51:39 +04:00
printk ( KERN_ERR PFX " adapter_lookup: hba NULL \n " ) ;
2011-02-04 23:10:34 +03:00
return NULL ;
}
/**
* bnx2fc_ulp_exit - shuts down adapter instance and frees all resources
*
* @ dev cnic device handle
*/
static void bnx2fc_ulp_exit ( struct cnic_dev * dev )
{
struct bnx2fc_hba * hba ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface , * tmp ;
struct fc_lport * lport ;
2011-02-04 23:10:34 +03:00
BNX2FC_MISC_DBG ( " Entered bnx2fc_ulp_exit \n " ) ;
if ( ! test_bit ( CNIC_F_BNX2X_CLASS , & dev - > flags ) ) {
printk ( KERN_ERR PFX " bnx2fc port check: %s, flags: %lx \n " ,
dev - > netdev - > name , dev - > flags ) ;
return ;
}
mutex_lock ( & bnx2fc_dev_lock ) ;
hba = bnx2fc_find_hba_for_cnic ( dev ) ;
if ( ! hba ) {
printk ( KERN_ERR PFX " bnx2fc_ulp_exit: hba not found, dev 0%p \n " ,
dev ) ;
mutex_unlock ( & bnx2fc_dev_lock ) ;
return ;
}
2011-07-27 01:51:39 +04:00
list_del_init ( & hba - > list ) ;
2011-02-04 23:10:34 +03:00
adapter_count - - ;
2011-07-27 01:51:39 +04:00
list_for_each_entry_safe ( interface , tmp , & if_list , list ) {
2011-02-04 23:10:34 +03:00
/* destroy not called yet, move to quiesced list */
2011-07-27 01:51:39 +04:00
if ( interface - > hba = = hba ) {
2011-08-05 04:38:40 +04:00
bnx2fc_interface_cleanup ( interface ) ;
2011-07-27 01:51:39 +04:00
bnx2fc_stop ( interface ) ;
list_del ( & interface - > list ) ;
lport = interface - > ctlr . lp ;
bnx2fc_interface_put ( interface ) ;
2011-08-05 04:38:41 +04:00
bnx2fc_if_destroy ( lport ) ;
2011-07-27 01:51:39 +04:00
}
2011-02-04 23:10:34 +03:00
}
mutex_unlock ( & bnx2fc_dev_lock ) ;
bnx2fc_ulp_stop ( hba ) ;
/* unregister cnic device */
if ( test_and_clear_bit ( BNX2FC_CNIC_REGISTERED , & hba - > reg_with_cnic ) )
hba - > cnic - > unregister_device ( hba - > cnic , CNIC_ULP_FCOE ) ;
2011-07-27 01:51:39 +04:00
bnx2fc_hba_destroy ( hba ) ;
2011-02-04 23:10:34 +03:00
}
/**
* bnx2fc_fcoe_reset - Resets the fcoe
*
* @ shost : shost the reset is from
*
* Returns : always 0
*/
static int bnx2fc_fcoe_reset ( struct Scsi_Host * shost )
{
struct fc_lport * lport = shost_priv ( shost ) ;
fc_lport_reset ( lport ) ;
return 0 ;
}
static bool bnx2fc_match ( struct net_device * netdev )
{
mutex_lock ( & bnx2fc_dev_lock ) ;
if ( netdev - > priv_flags & IFF_802_1Q_VLAN ) {
struct net_device * phys_dev = vlan_dev_real_dev ( netdev ) ;
if ( bnx2fc_hba_lookup ( phys_dev ) ) {
mutex_unlock ( & bnx2fc_dev_lock ) ;
return true ;
}
}
mutex_unlock ( & bnx2fc_dev_lock ) ;
return false ;
}
static struct fcoe_transport bnx2fc_transport = {
. name = { " bnx2fc " } ,
. attached = false ,
. list = LIST_HEAD_INIT ( bnx2fc_transport . list ) ,
. match = bnx2fc_match ,
. create = bnx2fc_create ,
. destroy = bnx2fc_destroy ,
. enable = bnx2fc_enable ,
. disable = bnx2fc_disable ,
} ;
/**
* bnx2fc_percpu_thread_create - Create a receive thread for an
* online CPU
*
* @ cpu : cpu index for the online cpu
*/
static void bnx2fc_percpu_thread_create ( unsigned int cpu )
{
struct bnx2fc_percpu_s * p ;
struct task_struct * thread ;
p = & per_cpu ( bnx2fc_percpu , cpu ) ;
thread = kthread_create ( bnx2fc_percpu_io_thread ,
( void * ) p ,
" bnx2fc_thread/%d " , cpu ) ;
/* bind thread to the cpu */
2011-08-05 04:38:36 +04:00
if ( likely ( ! IS_ERR ( thread ) ) ) {
2011-02-04 23:10:34 +03:00
kthread_bind ( thread , cpu ) ;
p - > iothread = thread ;
wake_up_process ( thread ) ;
}
}
static void bnx2fc_percpu_thread_destroy ( unsigned int cpu )
{
struct bnx2fc_percpu_s * p ;
struct task_struct * thread ;
struct bnx2fc_work * work , * tmp ;
BNX2FC_MISC_DBG ( " destroying io thread for CPU %d \n " , cpu ) ;
/* Prevent any new work from being queued for this CPU */
p = & per_cpu ( bnx2fc_percpu , cpu ) ;
spin_lock_bh ( & p - > fp_work_lock ) ;
thread = p - > iothread ;
p - > iothread = NULL ;
/* Free all work in the list */
2011-08-05 04:38:36 +04:00
list_for_each_entry_safe ( work , tmp , & p - > work_list , list ) {
2011-02-04 23:10:34 +03:00
list_del_init ( & work - > list ) ;
bnx2fc_process_cq_compl ( work - > tgt , work - > wqe ) ;
kfree ( work ) ;
}
spin_unlock_bh ( & p - > fp_work_lock ) ;
if ( thread )
kthread_stop ( thread ) ;
}
/**
* bnx2fc_cpu_callback - Handler for CPU hotplug events
*
* @ nfb : The callback data block
* @ action : The event triggering the callback
* @ hcpu : The index of the CPU that the event is for
*
* This creates or destroys per - CPU data for fcoe
*
* Returns NOTIFY_OK always .
*/
static int bnx2fc_cpu_callback ( struct notifier_block * nfb ,
unsigned long action , void * hcpu )
{
unsigned cpu = ( unsigned long ) hcpu ;
switch ( action ) {
case CPU_ONLINE :
case CPU_ONLINE_FROZEN :
printk ( PFX " CPU %x online: Create Rx thread \n " , cpu ) ;
bnx2fc_percpu_thread_create ( cpu ) ;
break ;
case CPU_DEAD :
case CPU_DEAD_FROZEN :
printk ( PFX " CPU %x offline: Remove Rx thread \n " , cpu ) ;
bnx2fc_percpu_thread_destroy ( cpu ) ;
break ;
default :
break ;
}
return NOTIFY_OK ;
}
/**
* bnx2fc_mod_init - module init entry point
*
* Initialize driver wide global data structures , and register
* with cnic module
* */
static int __init bnx2fc_mod_init ( void )
{
struct fcoe_percpu_s * bg ;
struct task_struct * l2_thread ;
int rc = 0 ;
unsigned int cpu = 0 ;
struct bnx2fc_percpu_s * p ;
printk ( KERN_INFO PFX " %s " , version ) ;
/* register as a fcoe transport */
rc = fcoe_transport_attach ( & bnx2fc_transport ) ;
if ( rc ) {
printk ( KERN_ERR " failed to register an fcoe transport, check "
" if libfcoe is loaded \n " ) ;
goto out ;
}
INIT_LIST_HEAD ( & adapter_list ) ;
2011-07-27 01:51:39 +04:00
INIT_LIST_HEAD ( & if_list ) ;
2011-02-04 23:10:34 +03:00
mutex_init ( & bnx2fc_dev_lock ) ;
adapter_count = 0 ;
/* Attach FC transport template */
rc = bnx2fc_attach_transport ( ) ;
if ( rc )
goto detach_ft ;
bnx2fc_wq = alloc_workqueue ( " bnx2fc " , 0 , 0 ) ;
if ( ! bnx2fc_wq ) {
rc = - ENOMEM ;
goto release_bt ;
}
bg = & bnx2fc_global ;
skb_queue_head_init ( & bg - > fcoe_rx_list ) ;
l2_thread = kthread_create ( bnx2fc_l2_rcv_thread ,
( void * ) bg ,
" bnx2fc_l2_thread " ) ;
if ( IS_ERR ( l2_thread ) ) {
rc = PTR_ERR ( l2_thread ) ;
goto free_wq ;
}
wake_up_process ( l2_thread ) ;
spin_lock_bh ( & bg - > fcoe_rx_list . lock ) ;
bg - > thread = l2_thread ;
spin_unlock_bh ( & bg - > fcoe_rx_list . lock ) ;
for_each_possible_cpu ( cpu ) {
p = & per_cpu ( bnx2fc_percpu , cpu ) ;
INIT_LIST_HEAD ( & p - > work_list ) ;
spin_lock_init ( & p - > fp_work_lock ) ;
}
for_each_online_cpu ( cpu ) {
bnx2fc_percpu_thread_create ( cpu ) ;
}
/* Initialize per CPU interrupt thread */
register_hotcpu_notifier ( & bnx2fc_cpu_notifier ) ;
cnic_register_driver ( CNIC_ULP_FCOE , & bnx2fc_cnic_cb ) ;
return 0 ;
free_wq :
destroy_workqueue ( bnx2fc_wq ) ;
release_bt :
bnx2fc_release_transport ( ) ;
detach_ft :
fcoe_transport_detach ( & bnx2fc_transport ) ;
out :
return rc ;
}
static void __exit bnx2fc_mod_exit ( void )
{
LIST_HEAD ( to_be_deleted ) ;
struct bnx2fc_hba * hba , * next ;
struct fcoe_percpu_s * bg ;
struct task_struct * l2_thread ;
struct sk_buff * skb ;
unsigned int cpu = 0 ;
/*
* NOTE : Since cnic calls register_driver routine rtnl_lock ,
* it will have higher precedence than bnx2fc_dev_lock .
* unregister_device ( ) cannot be called with bnx2fc_dev_lock
* held .
*/
mutex_lock ( & bnx2fc_dev_lock ) ;
list_splice ( & adapter_list , & to_be_deleted ) ;
INIT_LIST_HEAD ( & adapter_list ) ;
adapter_count = 0 ;
mutex_unlock ( & bnx2fc_dev_lock ) ;
/* Unregister with cnic */
2011-07-27 01:51:39 +04:00
list_for_each_entry_safe ( hba , next , & to_be_deleted , list ) {
list_del_init ( & hba - > list ) ;
printk ( KERN_ERR PFX " MOD_EXIT:destroy hba = 0x%p \n " ,
hba ) ;
2011-02-04 23:10:34 +03:00
bnx2fc_ulp_stop ( hba ) ;
/* unregister cnic device */
if ( test_and_clear_bit ( BNX2FC_CNIC_REGISTERED ,
& hba - > reg_with_cnic ) )
2011-07-27 01:51:39 +04:00
hba - > cnic - > unregister_device ( hba - > cnic ,
CNIC_ULP_FCOE ) ;
bnx2fc_hba_destroy ( hba ) ;
2011-02-04 23:10:34 +03:00
}
cnic_unregister_driver ( CNIC_ULP_FCOE ) ;
/* Destroy global thread */
bg = & bnx2fc_global ;
spin_lock_bh ( & bg - > fcoe_rx_list . lock ) ;
l2_thread = bg - > thread ;
bg - > thread = NULL ;
while ( ( skb = __skb_dequeue ( & bg - > fcoe_rx_list ) ) ! = NULL )
kfree_skb ( skb ) ;
spin_unlock_bh ( & bg - > fcoe_rx_list . lock ) ;
if ( l2_thread )
kthread_stop ( l2_thread ) ;
unregister_hotcpu_notifier ( & bnx2fc_cpu_notifier ) ;
/* Destroy per cpu threads */
for_each_online_cpu ( cpu ) {
bnx2fc_percpu_thread_destroy ( cpu ) ;
}
destroy_workqueue ( bnx2fc_wq ) ;
/*
* detach from scsi transport
* must happen after all destroys are done
*/
bnx2fc_release_transport ( ) ;
/* detach from fcoe transport */
fcoe_transport_detach ( & bnx2fc_transport ) ;
}
module_init ( bnx2fc_mod_init ) ;
module_exit ( bnx2fc_mod_exit ) ;
static struct fc_function_template bnx2fc_transport_function = {
. show_host_node_name = 1 ,
. show_host_port_name = 1 ,
. show_host_supported_classes = 1 ,
. show_host_supported_fc4s = 1 ,
. show_host_active_fc4s = 1 ,
. show_host_maxframe_size = 1 ,
. show_host_port_id = 1 ,
. show_host_supported_speeds = 1 ,
. get_host_speed = fc_get_host_speed ,
. show_host_speed = 1 ,
. show_host_port_type = 1 ,
. get_host_port_state = fc_get_host_port_state ,
. show_host_port_state = 1 ,
. show_host_symbolic_name = 1 ,
. dd_fcrport_size = ( sizeof ( struct fc_rport_libfc_priv ) +
sizeof ( struct bnx2fc_rport ) ) ,
. show_rport_maxframe_size = 1 ,
. show_rport_supported_classes = 1 ,
. show_host_fabric_name = 1 ,
. show_starget_node_name = 1 ,
. show_starget_port_name = 1 ,
. show_starget_port_id = 1 ,
. set_rport_dev_loss_tmo = fc_set_rport_loss_tmo ,
. show_rport_dev_loss_tmo = 1 ,
. get_fc_host_stats = bnx2fc_get_host_stats ,
. issue_fc_host_lip = bnx2fc_fcoe_reset ,
. terminate_rport_io = fc_rport_terminate_io ,
. vport_create = bnx2fc_vport_create ,
. vport_delete = bnx2fc_vport_destroy ,
. vport_disable = bnx2fc_vport_disable ,
2011-08-05 04:38:37 +04:00
. bsg_request = fc_lport_bsg_request ,
2011-02-04 23:10:34 +03:00
} ;
static struct fc_function_template bnx2fc_vport_xport_function = {
. show_host_node_name = 1 ,
. show_host_port_name = 1 ,
. show_host_supported_classes = 1 ,
. show_host_supported_fc4s = 1 ,
. show_host_active_fc4s = 1 ,
. show_host_maxframe_size = 1 ,
. show_host_port_id = 1 ,
. show_host_supported_speeds = 1 ,
. get_host_speed = fc_get_host_speed ,
. show_host_speed = 1 ,
. show_host_port_type = 1 ,
. get_host_port_state = fc_get_host_port_state ,
. show_host_port_state = 1 ,
. show_host_symbolic_name = 1 ,
. dd_fcrport_size = ( sizeof ( struct fc_rport_libfc_priv ) +
sizeof ( struct bnx2fc_rport ) ) ,
. show_rport_maxframe_size = 1 ,
. show_rport_supported_classes = 1 ,
. show_host_fabric_name = 1 ,
. show_starget_node_name = 1 ,
. show_starget_port_name = 1 ,
. show_starget_port_id = 1 ,
. set_rport_dev_loss_tmo = fc_set_rport_loss_tmo ,
. show_rport_dev_loss_tmo = 1 ,
. get_fc_host_stats = fc_get_host_stats ,
. issue_fc_host_lip = bnx2fc_fcoe_reset ,
. terminate_rport_io = fc_rport_terminate_io ,
2011-08-05 04:38:37 +04:00
. bsg_request = fc_lport_bsg_request ,
2011-02-04 23:10:34 +03:00
} ;
/**
* scsi_host_template structure used while registering with SCSI - ml
*/
static struct scsi_host_template bnx2fc_shost_template = {
. module = THIS_MODULE ,
. name = " Broadcom Offload FCoE Initiator " ,
. queuecommand = bnx2fc_queuecommand ,
. eh_abort_handler = bnx2fc_eh_abort , /* abts */
. eh_device_reset_handler = bnx2fc_eh_device_reset , /* lun reset */
. eh_target_reset_handler = bnx2fc_eh_target_reset , /* tgt reset */
. eh_host_reset_handler = fc_eh_host_reset ,
. slave_alloc = fc_slave_alloc ,
. change_queue_depth = fc_change_queue_depth ,
. change_queue_type = fc_change_queue_type ,
. this_id = - 1 ,
. cmd_per_lun = 3 ,
2011-03-18 03:13:29 +03:00
. can_queue = BNX2FC_CAN_QUEUE ,
2011-02-04 23:10:34 +03:00
. use_clustering = ENABLE_CLUSTERING ,
. sg_tablesize = BNX2FC_MAX_BDS_PER_CMD ,
. max_sectors = 512 ,
} ;
static struct libfc_function_template bnx2fc_libfc_fcn_templ = {
. frame_send = bnx2fc_xmit ,
. elsct_send = bnx2fc_elsct_send ,
. fcp_abort_io = bnx2fc_abort_io ,
. fcp_cleanup = bnx2fc_cleanup ,
. rport_event_callback = bnx2fc_rport_event_handler ,
} ;
/**
* bnx2fc_cnic_cb - global template of bnx2fc - cnic driver interface
* structure carrying callback function pointers
*/
static struct cnic_ulp_ops bnx2fc_cnic_cb = {
. owner = THIS_MODULE ,
. cnic_init = bnx2fc_ulp_init ,
. cnic_exit = bnx2fc_ulp_exit ,
. cnic_start = bnx2fc_ulp_start ,
. cnic_stop = bnx2fc_ulp_stop ,
. indicate_kcqes = bnx2fc_indicate_kcqe ,
. indicate_netevent = bnx2fc_indicate_netevent ,
} ;