2014-07-03 16:18:28 +04:00
/* bnx2fc_fcoe.c: QLogic NetXtreme II Linux FCoE offload driver.
2011-02-04 23:10:34 +03:00
* 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 .
*
2013-03-09 01:28:53 +04:00
* Copyright ( c ) 2008 - 2013 Broadcom Corporation
2014-07-03 16:18:28 +04:00
* Copyright ( c ) 2014 , QLogic 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
2013-12-12 03:30:23 +04:00
# define DRV_MODULE_RELDATE "Dec 11, 2013"
2011-02-04 23:10:34 +03:00
2012-12-22 01:08:55 +04:00
static char version [ ] =
2014-07-03 16:18:28 +04:00
" QLogic NetXtreme II FCoE Driver " DRV_MODULE_NAME \
2011-02-04 23:10:34 +03:00
" v " DRV_MODULE_VERSION " ( " DRV_MODULE_RELDATE " ) \n " ;
MODULE_AUTHOR ( " Bhanu Prakash Gollapudi <bprakash@broadcom.com> " ) ;
2014-07-03 16:18:28 +04:00
MODULE_DESCRIPTION ( " QLogic NetXtreme II BCM57710 FCoE Driver " ) ;
2011-02-04 23:10:34 +03:00
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 ;
2012-05-23 06:06:26 +04:00
static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ ;
2011-02-04 23:10:34 +03:00
static struct fc_function_template bnx2fc_vport_xport_function ;
static int bnx2fc_create ( struct net_device * netdev , enum fip_state fip_mode ) ;
2011-08-25 05:56:42 +04:00
static void __bnx2fc_destroy ( struct bnx2fc_interface * interface ) ;
2011-02-04 23:10:34 +03:00
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 ) ;
2012-11-27 10:53:40 +04:00
/* fcoe_syfs control interface handlers */
static int bnx2fc_ctlr_alloc ( struct net_device * netdev ) ;
static int bnx2fc_ctlr_enabled ( struct fcoe_ctlr_device * cdev ) ;
2011-02-04 23:10:34 +03:00
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_lport_config ( struct fc_lport * lport ) ;
2013-04-22 23:22:30 +04:00
static int bnx2fc_em_config ( struct fc_lport * lport , struct bnx2fc_hba * hba ) ;
2011-02-04 23:10:34 +03:00
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-08-05 04:38:42 +04:00
static inline void bnx2fc_interface_put ( struct bnx2fc_interface * interface ) ;
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 ,
} ;
2011-10-04 03:45:02 +04:00
static inline struct net_device * bnx2fc_netdev ( const struct fc_lport * lport )
{
return ( ( struct bnx2fc_interface * )
( ( struct fcoe_port * ) lport_priv ( lport ) ) - > priv ) - > netdev ;
}
2012-05-23 06:06:26 +04:00
static void bnx2fc_fcf_get_vlan_id ( struct fcoe_fcf_device * fcf_dev )
{
struct fcoe_ctlr_device * ctlr_dev =
fcoe_fcf_dev_to_ctlr_dev ( fcf_dev ) ;
struct fcoe_ctlr * ctlr = fcoe_ctlr_device_priv ( ctlr_dev ) ;
struct bnx2fc_interface * fcoe = fcoe_ctlr_priv ( ctlr ) ;
fcf_dev - > vlan_id = fcoe - > vlan_id ;
}
2011-02-04 23:10:34 +03:00
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 ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_hba * hba ;
2011-02-04 23:10:34 +03:00
struct fcoe_port * port ;
struct fcoe_hdr * hp ;
struct bnx2fc_rport * tgt ;
2012-05-25 21:26:43 +04:00
struct fc_stats * stats ;
2011-02-04 23:10:34 +03:00
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 ;
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
2011-07-27 01:51:39 +04:00
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 ) ) {
2012-05-23 06:06:16 +04:00
if ( ! 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 ;
}
2012-05-23 06:06:16 +04:00
if ( fcoe_ctlr_els_send ( 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 ] ;
2011-11-25 19:14:23 +04:00
cp = kmap_atomic ( skb_frag_page ( frag ) ) + frag - > page_offset ;
2011-02-04 23:10:34 +03:00
} 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 ) ) {
2011-11-25 19:14:23 +04:00
kunmap_atomic ( cp ) ;
2011-02-04 23:10:34 +03:00
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 ) ;
2012-05-23 06:06:16 +04:00
if ( 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 */
2012-05-23 06:06:16 +04:00
memcpy ( eh - > h_dest , ctlr - > dest_addr , ETH_ALEN ) ;
2011-02-04 23:10:34 +03:00
2012-05-23 06:06:16 +04:00
if ( unlikely ( ctlr - > flogi_oxid ! = FC_XID_UNKNOWN ) )
memcpy ( eh - > h_source , 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 */
2012-05-25 21:26:43 +04:00
stats = per_cpu_ptr ( lport - > stats , get_cpu ( ) ) ;
2011-02-04 23:10:34 +03:00
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 ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
2011-02-04 23:10:34 +03:00
struct fc_frame_header * fh ;
struct fcoe_rcv_info * fr ;
struct fcoe_percpu_s * bg ;
2014-11-20 13:17:33 +03:00
struct sk_buff * tmp_skb ;
2011-02-04 23:10:34 +03:00
unsigned short oxid ;
2011-07-27 01:51:39 +04:00
interface = container_of ( ptype , struct bnx2fc_interface ,
fcoe_packet_type ) ;
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
lport = 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 ;
}
2014-11-20 13:17:33 +03:00
tmp_skb = skb_share_check ( skb , GFP_ATOMIC ) ;
if ( ! tmp_skb )
goto err ;
skb = tmp_skb ;
2011-02-04 23:10:34 +03:00
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 ;
2012-03-10 02:50:13 +04:00
spin_lock ( & bg - > fcoe_rx_list . lock ) ;
2011-02-04 23:10:34 +03:00
__skb_queue_tail ( & bg - > fcoe_rx_list , skb ) ;
if ( bg - > fcoe_rx_list . qlen = = 1 )
wake_up_process ( bg - > thread ) ;
2012-03-10 02:50:13 +04:00
spin_unlock ( & bg - > fcoe_rx_list . lock ) ;
2011-02-04 23:10:34 +03:00
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 ;
2014-03-11 14:09:12 +04:00
set_user_nice ( current , MIN_NICE ) ;
2011-02-04 23:10:34 +03:00
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 ;
2012-05-25 21:26:43 +04:00
struct fc_stats * stats ;
2011-02-04 23:10:34 +03:00
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 ) ;
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 ) ) ) {
kfree_skb ( skb ) ;
return ;
}
fr_eof ( fp ) = crc_eof . fcoe_eof ;
fr_crc ( fp ) = crc_eof . fcoe_crc32 ;
if ( pskb_trim ( skb , fr_len ) ) {
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 ) ;
scsi: Convert uses of compare_ether_addr to ether_addr_equal
Preliminary to removing compare_ether_addr altogether:
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
2013-09-02 07:32:33 +04:00
if ( ! ether_addr_equal ( port - > data_src_addr , dest_mac ) ) {
2011-02-04 23:10:34 +03:00
BNX2FC_HBA_DBG ( lport , " fpma mismatch \n " ) ;
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 */
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 */
kfree_skb ( skb ) ;
return ;
}
break ;
}
}
2011-08-05 04:38:48 +04:00
if ( fh - > fh_r_ctl = = FC_RCTL_BA_ABTS ) {
/* Drop incoming ABTS */
kfree_skb ( skb ) ;
return ;
}
2014-06-23 18:41:02 +04:00
stats = per_cpu_ptr ( lport - > stats , smp_processor_id ( ) ) ;
stats - > RxFrames + + ;
stats - > RxWords + = fr_len / FCOE_WORD_TO_BYTE ;
2011-02-04 23:10:34 +03:00
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 + + ;
kfree_skb ( skb ) ;
return ;
}
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 ) ;
2014-03-11 14:09:12 +04:00
set_user_nice ( current , MIN_NICE ) ;
2011-02-04 23:10:34 +03:00
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 ;
}
2012-12-22 07:40:32 +04:00
BNX2FC_STATS ( hba , rx_stat2 , fc_crc_cnt ) ;
bnx2fc_stats - > invalid_crc_count + = hba - > bfw_stats . fc_crc_cnt ;
BNX2FC_STATS ( hba , tx_stat , fcoe_tx_pkt_cnt ) ;
bnx2fc_stats - > tx_frames + = hba - > bfw_stats . fcoe_tx_pkt_cnt ;
BNX2FC_STATS ( hba , tx_stat , fcoe_tx_byte_cnt ) ;
bnx2fc_stats - > tx_words + = ( ( hba - > bfw_stats . fcoe_tx_byte_cnt ) / 4 ) ;
BNX2FC_STATS ( hba , rx_stat0 , fcoe_rx_pkt_cnt ) ;
bnx2fc_stats - > rx_frames + = hba - > bfw_stats . fcoe_rx_pkt_cnt ;
BNX2FC_STATS ( hba , rx_stat0 , fcoe_rx_byte_cnt ) ;
bnx2fc_stats - > rx_words + = ( ( hba - > bfw_stats . fcoe_rx_byte_cnt ) / 4 ) ;
2011-02-04 23:10:34 +03:00
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 ;
2012-12-22 07:40:32 +04:00
memcpy ( & hba - > prev_stats , hba - > stats_buffer ,
sizeof ( struct fcoe_statistics_params ) ) ;
2011-02-04 23:10:34 +03:00
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 ;
2013-03-09 01:28:51 +04:00
struct bnx2fc_hba * hba = interface - > hba ;
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 ;
2013-03-09 01:28:51 +04:00
snprintf ( fc_host_symbolic_name ( lport - > host ) , 256 ,
2014-07-03 16:18:28 +04:00
" %s (QLogic %s) v%s over %s " ,
2013-03-09 01:28:51 +04:00
BNX2FC_NAME , hba - > chip_num , BNX2FC_VERSION ,
2011-07-27 01:51:39 +04:00
interface - > netdev - > name ) ;
2011-02-04 23:10:34 +03:00
return 0 ;
}
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 ) ;
}
2011-08-05 04:38:50 +04:00
static int bnx2fc_net_config ( struct fc_lport * lport , struct net_device * netdev )
2011-02-04 23:10:34 +03:00
{
struct bnx2fc_hba * hba ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
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 ;
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
2011-07-27 01:51:39 +04:00
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 ) ;
2012-12-06 10:24:44 +04:00
fcoe_link_speed_update ( lport ) ;
2011-02-04 23:10:34 +03:00
if ( ! lport - > vport ) {
2011-08-05 04:38:50 +04:00
if ( fcoe_get_wwn ( netdev , & wwnn , NETDEV_FCOE_WWNN ) )
2012-05-23 06:06:16 +04:00
wwnn = fcoe_wwn_from_mac ( ctlr - > ctl_src_addr ,
2011-08-05 04:38:50 +04:00
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-08-05 04:38:50 +04:00
if ( fcoe_get_wwn ( netdev , & wwpn , NETDEV_FCOE_WWPN ) )
2012-05-23 06:06:16 +04:00
wwpn = fcoe_wwn_from_mac ( ctlr - > ctl_src_addr ,
2011-08-05 04:38:50 +04:00
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-08-05 04:38:43 +04:00
printk ( KERN_ERR PFX " ERROR:bnx2fc_destroy_timer - "
" 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
2011-08-05 04:38:42 +04:00
* NETDEV_CHANGE_MTU events . Handle NETDEV_UNREGISTER only for vlans .
2011-02-04 23:10:34 +03:00
*/
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 ;
2012-11-27 10:53:40 +04:00
struct fcoe_ctlr_device * cdev ;
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-08-05 04:38:42 +04:00
struct bnx2fc_interface * interface , * tmp ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
2011-07-27 01:51:39 +04:00
int wait_for_upload = 0 ;
2011-02-04 23:10:34 +03:00
u32 link_possible = 1 ;
2011-08-05 04:38:42 +04:00
if ( vlan_id ! = 0 & & event ! = NETDEV_UNREGISTER )
2011-07-20 18:55:24 +04:00
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 ;
2011-08-05 04:38:42 +04:00
case NETDEV_UNREGISTER :
if ( ! vlan_id )
return ;
mutex_lock ( & bnx2fc_dev_lock ) ;
list_for_each_entry_safe ( interface , tmp , & if_list , list ) {
2011-08-31 02:54:50 +04:00
if ( interface - > hba = = hba & &
interface - > vlan_id = = ( vlan_id & VLAN_VID_MASK ) )
__bnx2fc_destroy ( interface ) ;
2011-08-05 04:38:42 +04:00
}
mutex_unlock ( & bnx2fc_dev_lock ) ;
2013-12-12 03:30:21 +04:00
/* Ensure ALL destroy work has been completed before return */
flush_workqueue ( bnx2fc_wq ) ;
2011-08-05 04:38:42 +04:00
return ;
2011-02-04 23:10:34 +03:00
default :
2012-04-24 19:24:16 +04:00
printk ( KERN_ERR PFX " Unknown netevent %ld " , event ) ;
2011-02-04 23:10:34 +03:00
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 ;
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
lport = ctlr - > lp ;
2011-07-27 01:51:39 +04:00
BNX2FC_HBA_DBG ( lport , " netevent handler - event=%s %ld \n " ,
interface - > netdev - > name , event ) ;
2012-12-06 10:24:44 +04:00
fcoe_link_speed_update ( lport ) ;
2011-07-27 01:51:39 +04:00
2012-11-27 10:53:40 +04:00
cdev = fcoe_ctlr_to_ctlr_dev ( ctlr ) ;
2011-07-27 01:51:39 +04:00
if ( link_possible & & ! bnx2fc_link_ok ( lport ) ) {
2012-11-27 10:53:40 +04:00
switch ( cdev - > enabled ) {
case FCOE_CTLR_DISABLED :
pr_info ( " Link up while interface is disabled. \n " ) ;
break ;
case FCOE_CTLR_ENABLED :
case FCOE_CTLR_UNUSED :
/* Reset max recv frame size to default */
fc_set_mfs ( lport , BNX2FC_MFS ) ;
/*
* ctlr link up will only be handled during
* enable to avoid sending discovery
* solicitation on a stale vlan
*/
if ( interface - > enabled )
fcoe_ctlr_link_up ( ctlr ) ;
} ;
2012-05-23 06:06:16 +04:00
} else if ( fcoe_ctlr_link_down ( ctlr ) ) {
2012-11-27 10:53:40 +04:00
switch ( cdev - > enabled ) {
case FCOE_CTLR_DISABLED :
pr_info ( " Link down while interface is disabled. \n " ) ;
break ;
case FCOE_CTLR_ENABLED :
case FCOE_CTLR_UNUSED :
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 - > stats ,
get_cpu ( ) ) - > LinkFailureCount + + ;
put_cpu ( ) ;
fcoe_clean_pending_queue ( lport ) ;
wait_for_upload = 1 ;
} ;
2011-07-27 01:51:39 +04:00
}
}
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 ) ;
2013-03-25 22:00:28 +04:00
fc_disc_init ( lport ) ;
fc_disc_config ( lport , lport ) ;
2011-02-04 23:10:34 +03:00
return 0 ;
}
2013-04-22 23:22:30 +04:00
static int bnx2fc_em_config ( struct fc_lport * lport , struct bnx2fc_hba * hba )
2011-02-04 23:10:34 +03:00
{
2013-04-22 23:22:30 +04:00
int fcoe_min_xid , fcoe_max_xid ;
2012-01-24 06:00:48 +04:00
2013-04-22 23:22:30 +04:00
fcoe_min_xid = hba - > max_xid + 1 ;
2012-01-24 06:00:48 +04:00
if ( nr_cpu_ids < = 2 )
2013-04-22 23:22:30 +04:00
fcoe_max_xid = hba - > max_xid + FCOE_XIDS_PER_CPU_OFFSET ;
2012-01-24 06:00:48 +04:00
else
2013-04-22 23:22:30 +04:00
fcoe_max_xid = hba - > max_xid + FCOE_MAX_XID_OFFSET ;
if ( ! fc_exch_mgr_alloc ( lport , FC_CLASS_3 , fcoe_min_xid ,
fcoe_max_xid , NULL ) ) {
2011-02-04 23:10:34 +03:00
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 ;
2012-01-24 06:00:47 +04:00
lport - > max_retry_count = BNX2FC_MAX_RETRY_CNT ;
lport - > max_rport_retry_count = BNX2FC_MAX_RPORT_RETRY_CNT ;
2011-02-04 23:10:34 +03:00
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 ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
2011-07-27 01:51:39 +04:00
interface = container_of ( ptype , struct bnx2fc_interface ,
fip_packet_type ) ;
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
fcoe_ctlr_recv ( 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-08-05 04:38:51 +04:00
int rc ;
char buf [ 32 ] ;
rc = fcoe_validate_vport_create ( vport ) ;
if ( rc ) {
fcoe_wwn_to_str ( vport - > port_name , buf , sizeof ( buf ) ) ;
printk ( KERN_ERR PFX " Failed to create vport, "
" WWPN (0x%s) already exists \n " ,
buf ) ;
return rc ;
}
2011-02-04 23:10:34 +03:00
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 ;
}
2011-09-03 07:34:30 +04:00
rtnl_lock ( ) ;
2011-02-04 23:10:34 +03:00
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 ) ;
2011-09-03 07:34:30 +04:00
rtnl_unlock ( ) ;
2011-02-04 23:10:34 +03:00
2014-11-04 13:37:17 +03:00
if ( ! vn_port ) {
2011-02-04 23:10:34 +03:00
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 ;
}
2011-08-05 04:38:42 +04:00
static void bnx2fc_free_vport ( struct bnx2fc_hba * hba , struct fc_lport * lport )
{
struct bnx2fc_lport * blport , * tmp ;
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 ) ;
}
2011-02-04 23:10:34 +03:00
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:42 +04:00
struct bnx2fc_interface * interface = port - > priv ;
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 ) ;
2011-08-05 04:38:42 +04:00
bnx2fc_free_vport ( interface - > hba , port - > lport ) ;
bnx2fc_port_shutdown ( port - > lport ) ;
bnx2fc_interface_put ( interface ) ;
2011-02-04 23:10:34 +03:00
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 ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr = bnx2fc_to_ctlr ( interface ) ;
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 ) ) ) {
2012-05-23 06:06:16 +04:00
memcpy ( ctlr - > ctl_src_addr , ha - > addr ,
2011-07-27 01:51:39 +04:00
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 )
{
2012-05-23 06:06:26 +04:00
struct fcoe_ctlr_device * ctlr_dev ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
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
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
2012-05-23 06:06:26 +04:00
ctlr_dev = fcoe_ctlr_to_ctlr_dev ( ctlr ) ;
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 ) )
2012-05-23 06:06:16 +04:00
fcoe_ctlr_destroy ( ctlr ) ;
2011-07-27 01:51:39 +04:00
2012-05-23 06:06:26 +04:00
fcoe_ctlr_device_delete ( ctlr_dev ) ;
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 ;
2012-06-26 05:31:19 +04:00
struct fcoe_capabilities * fcoe_cap ;
2011-02-04 23:10:34 +03:00
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 ;
2013-04-22 23:22:30 +04:00
hba - > max_tasks = cnic - > max_fcoe_exchanges ;
hba - > elstm_xids = ( hba - > max_tasks / 2 ) ;
hba - > max_outstanding_cmds = hba - > elstm_xids ;
hba - > max_xid = ( hba - > max_tasks - 1 ) ;
2011-02-04 23:10:34 +03:00
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 ;
2013-04-22 23:22:30 +04:00
hba - > cmd_mgr = bnx2fc_cmd_mgr_alloc ( hba ) ;
2011-07-27 01:51:39 +04:00
if ( ! hba - > cmd_mgr ) {
printk ( KERN_ERR PFX " em_config:bnx2fc_cmd_mgr_alloc failed \n " ) ;
goto cmgr_err ;
}
2012-06-26 05:31:19 +04:00
fcoe_cap = & hba - > fcoe_cap ;
fcoe_cap - > capability1 = BNX2FC_TM_MAX_SQES < <
FCOE_IOS_PER_CONNECTION_SHIFT ;
fcoe_cap - > capability1 | = BNX2FC_NUM_MAX_SESS < <
FCOE_LOGINS_PER_PORT_SHIFT ;
2013-04-22 23:22:30 +04:00
fcoe_cap - > capability2 = hba - > max_outstanding_cmds < <
2012-06-26 05:31:19 +04:00
FCOE_NUMBER_OF_EXCHANGES_SHIFT ;
fcoe_cap - > capability2 | = BNX2FC_MAX_NPIV < <
FCOE_NPIV_WWN_PER_PORT_SHIFT ;
fcoe_cap - > capability3 = BNX2FC_NUM_MAX_SESS < <
FCOE_TARGETS_SUPPORTED_SHIFT ;
2013-04-22 23:22:30 +04:00
fcoe_cap - > capability3 | = hba - > max_outstanding_cmds < <
2012-06-26 05:31:19 +04:00
FCOE_OUTSTANDING_COMMANDS_SHIFT ;
fcoe_cap - > capability4 = FCOE_CAPABILITY4_STATEFUL ;
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
{
2012-05-23 06:06:26 +04:00
struct fcoe_ctlr_device * ctlr_dev ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
int size ;
2011-02-04 23:10:34 +03:00
int rc = 0 ;
2012-05-23 06:06:16 +04:00
size = ( sizeof ( * interface ) + sizeof ( struct fcoe_ctlr ) ) ;
2012-05-23 06:06:26 +04:00
ctlr_dev = fcoe_ctlr_device_add ( & netdev - > dev , & bnx2fc_fcoe_sysfs_templ ,
size ) ;
if ( ! ctlr_dev ) {
2011-07-27 01:51:39 +04:00
printk ( KERN_ERR PFX " Unable to allocate interface structure \n " ) ;
return NULL ;
}
2012-05-23 06:06:26 +04:00
ctlr = fcoe_ctlr_device_priv ( ctlr_dev ) ;
2013-09-05 11:47:27 +04:00
ctlr - > cdev = ctlr_dev ;
2012-05-23 06:06:16 +04:00
interface = fcoe_ctlr_priv ( ctlr ) ;
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 */
2012-05-23 06:06:16 +04:00
fcoe_ctlr_init ( ctlr , fip_mode ) ;
ctlr - > send = bnx2fc_fip_send ;
ctlr - > update_mac = bnx2fc_update_src_mac ;
ctlr - > get_src_addr = bnx2fc_get_src_mac ;
2011-07-27 01:51:39 +04:00
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
2012-05-23 06:06:16 +04:00
fcoe_ctlr_destroy ( ctlr ) ;
2011-02-04 23:10:34 +03:00
dev_put ( netdev ) ;
2012-05-23 06:06:26 +04:00
fcoe_ctlr_device_delete ( ctlr_dev ) ;
2011-07-27 01:51:39 +04:00
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 )
{
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr = bnx2fc_to_ctlr ( interface ) ;
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 ;
2013-04-22 23:22:30 +04:00
struct bnx2fc_hba * hba = interface - > 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 ) {
2012-05-23 06:06:16 +04:00
BNX2FC_HBA_DBG ( 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 */
2013-04-22 23:22:30 +04:00
bnx2fc_shost_template . can_queue = hba - > max_outstanding_cmds ;
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 ;
2012-12-06 10:24:29 +04:00
port - > get_netdev = bnx2fc_netdev ;
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 */
2011-08-05 04:38:50 +04:00
rc = bnx2fc_net_config ( lport , interface - > netdev ) ;
2011-02-04 23:10:34 +03:00
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 )
2013-04-22 23:22:30 +04:00
rc = bnx2fc_em_config ( lport , hba ) ;
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
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-31 02:54:52 +04:00
static void bnx2fc_net_cleanup ( struct bnx2fc_interface * interface )
2011-02-04 23:10:34 +03:00
{
/* Dont listen for Ethernet packets anymore */
2011-07-27 01:51:39 +04:00
__dev_remove_pack ( & interface - > fcoe_packet_type ) ;
__dev_remove_pack ( & interface - > fip_packet_type ) ;
2011-02-04 23:10:34 +03:00
synchronize_net ( ) ;
}
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
{
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr = bnx2fc_to_ctlr ( interface ) ;
struct fc_lport * lport = ctlr - > lp ;
2011-02-04 23:10:34 +03:00
struct fcoe_port * port = lport_priv ( lport ) ;
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-31 02:54:52 +04:00
bnx2fc_net_cleanup ( interface ) ;
2011-08-05 04:38:41 +04:00
2011-08-05 04:38:42 +04:00
bnx2fc_free_vport ( hba , lport ) ;
2011-08-05 04:38:41 +04:00
}
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 ) ;
}
2011-08-25 05:56:42 +04:00
static void __bnx2fc_destroy ( struct bnx2fc_interface * interface )
2011-08-05 04:38:42 +04:00
{
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr = bnx2fc_to_ctlr ( interface ) ;
struct fc_lport * lport = ctlr - > lp ;
2011-08-31 02:54:51 +04:00
struct fcoe_port * port = lport_priv ( lport ) ;
2011-08-05 04:38:42 +04:00
bnx2fc_interface_cleanup ( interface ) ;
bnx2fc_stop ( interface ) ;
list_del ( & interface - > list ) ;
bnx2fc_interface_put ( interface ) ;
2011-08-31 02:54:51 +04:00
queue_work ( bnx2fc_wq , & port - > destroy_work ) ;
2011-08-05 04:38:42 +04:00
}
2011-02-04 23:10:34 +03:00
/**
* 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 ;
2012-01-24 06:00:46 +04:00
struct workqueue_struct * timer_work_queue ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
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 ) ;
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
if ( ! 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 ;
}
2012-01-24 06:00:46 +04:00
timer_work_queue = interface - > timer_work_queue ;
2011-08-25 05:56:42 +04:00
__bnx2fc_destroy ( interface ) ;
2012-01-24 06:00:46 +04:00
destroy_workqueue ( timer_work_queue ) ;
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 ;
port = container_of ( work , struct fcoe_port , destroy_work ) ;
lport = port - > lport ;
BNX2FC_HBA_DBG ( lport , " Entered bnx2fc_destroy_work \n " ) ;
2011-08-05 04:38:41 +04:00
bnx2fc_if_destroy ( lport ) ;
2011-02-04 23:10:34 +03:00
}
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 ;
2013-03-09 01:28:51 +04:00
struct pci_dev * pdev ;
2011-02-04 23:10:34 +03:00
if ( ! hba - > cnic ) {
printk ( KERN_ERR PFX " cnic is NULL \n " ) ;
return - ENODEV ;
}
cnic = hba - > cnic ;
2013-03-09 01:28:51 +04:00
pdev = hba - > pcidev = cnic - > pcidev ;
if ( ! hba - > pcidev )
return - ENODEV ;
2011-02-04 23:10:34 +03:00
2013-03-09 01:28:51 +04:00
switch ( pdev - > device ) {
case PCI_DEVICE_ID_NX2_57710 :
strncpy ( hba - > chip_num , " BCM57710 " , BCM_CHIP_LEN ) ;
break ;
case PCI_DEVICE_ID_NX2_57711 :
strncpy ( hba - > chip_num , " BCM57711 " , BCM_CHIP_LEN ) ;
break ;
case PCI_DEVICE_ID_NX2_57712 :
case PCI_DEVICE_ID_NX2_57712_MF :
case PCI_DEVICE_ID_NX2_57712_VF :
strncpy ( hba - > chip_num , " BCM57712 " , BCM_CHIP_LEN ) ;
break ;
case PCI_DEVICE_ID_NX2_57800 :
case PCI_DEVICE_ID_NX2_57800_MF :
case PCI_DEVICE_ID_NX2_57800_VF :
strncpy ( hba - > chip_num , " BCM57800 " , BCM_CHIP_LEN ) ;
break ;
case PCI_DEVICE_ID_NX2_57810 :
case PCI_DEVICE_ID_NX2_57810_MF :
case PCI_DEVICE_ID_NX2_57810_VF :
strncpy ( hba - > chip_num , " BCM57810 " , BCM_CHIP_LEN ) ;
break ;
case PCI_DEVICE_ID_NX2_57840 :
case PCI_DEVICE_ID_NX2_57840_MF :
case PCI_DEVICE_ID_NX2_57840_VF :
case PCI_DEVICE_ID_NX2_57840_2_20 :
case PCI_DEVICE_ID_NX2_57840_4_10 :
strncpy ( hba - > chip_num , " BCM57840 " , BCM_CHIP_LEN ) ;
break ;
default :
pr_err ( PFX " Unknown device id 0x%x \n " , pdev - > device ) ;
break ;
}
pci_dev_get ( hba - > pcidev ) ;
2011-02-04 23:10:34 +03:00
return 0 ;
}
static void bnx2fc_unbind_pcidev ( struct bnx2fc_hba * hba )
{
2013-03-09 01:28:51 +04:00
if ( hba - > pcidev ) {
hba - > chip_num [ 0 ] = ' \0 ' ;
2011-02-04 23:10:34 +03:00
pci_dev_put ( hba - > pcidev ) ;
2013-03-09 01:28:51 +04:00
}
2011-02-04 23:10:34 +03:00
hba - > pcidev = NULL ;
}
2012-06-26 05:31:19 +04:00
/**
* bnx2fc_ulp_get_stats - cnic callback to populate FCoE stats
*
* @ handle : transport handle pointing to adapter struture
*/
static int bnx2fc_ulp_get_stats ( void * handle )
{
struct bnx2fc_hba * hba = handle ;
struct cnic_dev * cnic ;
struct fcoe_stats_info * stats_addr ;
if ( ! hba )
return - EINVAL ;
cnic = hba - > cnic ;
stats_addr = & cnic - > stats_addr - > fcoe_stat ;
if ( ! stats_addr )
return - EINVAL ;
strncpy ( stats_addr - > version , BNX2FC_VERSION ,
sizeof ( stats_addr - > version ) ) ;
stats_addr - > txq_size = BNX2FC_SQ_WQES_MAX ;
stats_addr - > rxq_size = BNX2FC_CQ_WQES_MAX ;
return 0 ;
}
2011-02-04 23:10:34 +03:00
/**
* bnx2fc_ulp_start - cnic callback to initialize & start adapter instance
*
2012-04-24 19:24:16 +04:00
* @ handle : transport handle pointing to adapter structure
2011-02-04 23:10:34 +03:00
*
* 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 ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
2011-07-27 01:51:39 +04:00
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 ) {
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
lport = ctlr - > lp ;
2011-07-27 01:51:39 +04:00
/* 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
{
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr = bnx2fc_to_ctlr ( 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
2012-05-23 06:06:16 +04:00
lport = ctlr - > lp ;
2011-07-27 01:51:39 +04:00
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 ;
2012-05-23 06:06:16 +04:00
fcoe_ctlr_link_down ( ctlr ) ;
2011-07-27 01:51:39 +04:00
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-08-05 04:38:43 +04:00
clear_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
{
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr = bnx2fc_to_ctlr ( 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 ;
}
2012-05-23 06:06:16 +04:00
lport = ctlr - > lp ;
2011-02-04 23:10:34 +03:00
BNX2FC_HBA_DBG ( lport , " calling fc_fabric_login \n " ) ;
2011-08-31 02:54:48 +04:00
if ( ! bnx2fc_link_ok ( lport ) & & interface - > enabled ) {
2011-02-04 23:10:34 +03:00
BNX2FC_HBA_DBG ( lport , " ctlr_link_up \n " ) ;
2012-05-23 06:06:16 +04:00
fcoe_ctlr_link_up ( 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 */
2012-05-23 06:06:16 +04:00
while ( ! 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 ) ;
2012-06-26 05:31:19 +04:00
dev - > fcoe_cap = & hba - > fcoe_cap ;
2011-02-04 23:10:34 +03:00
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 ) ;
}
2013-09-26 09:01:20 +04:00
/* Assumes rtnl_lock and the bnx2fc_dev_lock are already taken */
static int __bnx2fc_disable ( struct fcoe_ctlr * ctlr )
{
struct bnx2fc_interface * interface = fcoe_ctlr_priv ( ctlr ) ;
if ( interface - > enabled = = true ) {
if ( ! ctlr - > lp ) {
pr_err ( PFX " __bnx2fc_disable: lport not found \n " ) ;
return - ENODEV ;
} else {
interface - > enabled = false ;
fcoe_ctlr_link_down ( ctlr ) ;
fcoe_clean_pending_queue ( ctlr - > lp ) ;
}
}
return 0 ;
}
2012-11-27 10:53:40 +04:00
/**
* Deperecated : Use bnx2fc_enabled ( )
*/
2011-02-04 23:10:34 +03:00
static int bnx2fc_disable ( struct net_device * netdev )
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
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 ) ;
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
2013-09-26 09:01:20 +04:00
if ( ! interface ) {
2011-02-04 23:10:34 +03:00
rc = - ENODEV ;
2013-09-26 09:01:20 +04:00
pr_err ( PFX " bnx2fc_disable: interface not found \n " ) ;
2011-02-04 23:10:34 +03:00
} else {
2013-09-26 09:01:20 +04:00
rc = __bnx2fc_disable ( ctlr ) ;
2011-02-04 23:10:34 +03:00
}
mutex_unlock ( & bnx2fc_dev_lock ) ;
rtnl_unlock ( ) ;
return rc ;
}
2013-09-26 09:01:20 +04:00
static int __bnx2fc_enable ( struct fcoe_ctlr * ctlr )
{
struct bnx2fc_interface * interface = fcoe_ctlr_priv ( ctlr ) ;
if ( interface - > enabled = = false ) {
if ( ! ctlr - > lp ) {
pr_err ( PFX " __bnx2fc_enable: lport not found \n " ) ;
return - ENODEV ;
} else if ( ! bnx2fc_link_ok ( ctlr - > lp ) ) {
fcoe_ctlr_link_up ( ctlr ) ;
interface - > enabled = true ;
}
}
return 0 ;
}
2012-11-27 10:53:40 +04:00
/**
* Deprecated : Use bnx2fc_enabled ( )
*/
2011-02-04 23:10:34 +03:00
static int bnx2fc_enable ( struct net_device * netdev )
{
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
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 ) ;
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
2013-09-26 09:01:20 +04:00
if ( ! interface ) {
2011-02-04 23:10:34 +03:00
rc = - ENODEV ;
2013-09-26 09:01:20 +04:00
pr_err ( PFX " bnx2fc_enable: interface not found \n " ) ;
} else {
rc = __bnx2fc_enable ( ctlr ) ;
2011-08-31 02:54:48 +04:00
}
2011-02-04 23:10:34 +03:00
mutex_unlock ( & bnx2fc_dev_lock ) ;
rtnl_unlock ( ) ;
return rc ;
}
/**
2012-11-27 10:53:40 +04:00
* bnx2fc_ctlr_enabled ( ) - Enable or disable an FCoE Controller
* @ cdev : The FCoE Controller that is being enabled or disabled
2011-02-04 23:10:34 +03:00
*
2012-11-27 10:53:40 +04:00
* fcoe_sysfs will ensure that the state of ' enabled ' has
* changed , so no checking is necessary here . This routine simply
* calls fcoe_enable or fcoe_disable , both of which are deprecated .
* When those routines are removed the functionality can be merged
* here .
*/
static int bnx2fc_ctlr_enabled ( struct fcoe_ctlr_device * cdev )
{
struct fcoe_ctlr * ctlr = fcoe_ctlr_device_priv ( cdev ) ;
switch ( cdev - > enabled ) {
case FCOE_CTLR_ENABLED :
2013-09-26 09:01:20 +04:00
return __bnx2fc_enable ( ctlr ) ;
2012-11-27 10:53:40 +04:00
case FCOE_CTLR_DISABLED :
2013-09-26 09:01:20 +04:00
return __bnx2fc_disable ( ctlr ) ;
2012-11-27 10:53:40 +04:00
case FCOE_CTLR_UNUSED :
default :
return - ENOTSUPP ;
} ;
}
enum bnx2fc_create_link_state {
BNX2FC_CREATE_LINK_DOWN ,
BNX2FC_CREATE_LINK_UP ,
} ;
/**
* _bnx2fc_create ( ) - Create bnx2fc FCoE interface
* @ netdev : The net_device object the Ethernet interface to create on
* @ fip_mode : The FIP mode for this creation
* @ link_state : The ctlr link state on creation
2011-02-04 23:10:34 +03:00
*
2012-11-27 10:53:40 +04:00
* Called from either the libfcoe ' create ' module parameter
* via fcoe_create or from fcoe_syfs ' s ctlr_create file .
2011-02-04 23:10:34 +03:00
*
2012-11-27 10:53:40 +04:00
* libfcoe ' s ' create ' module parameter is deprecated so some
* consolidation of code can be done when that interface is
* removed .
2011-02-04 23:10:34 +03:00
*
* Returns : 0 for success
*/
2012-11-27 10:53:40 +04:00
static int _bnx2fc_create ( struct net_device * netdev ,
enum fip_state fip_mode ,
enum bnx2fc_create_link_state link_state )
2011-02-04 23:10:34 +03:00
{
2012-11-27 10:53:40 +04:00
struct fcoe_ctlr_device * cdev ;
2012-05-23 06:06:16 +04:00
struct fcoe_ctlr * ctlr ;
2011-07-27 01:51:39 +04:00
struct bnx2fc_interface * interface ;
2011-02-04 23:10:34 +03:00
struct bnx2fc_hba * hba ;
2012-06-05 03:15:44 +04:00
struct net_device * phys_dev = netdev ;
2011-02-04 23:10:34 +03:00
struct fc_lport * lport ;
struct ethtool_drvinfo drvinfo ;
int rc = 0 ;
2012-06-05 03:15:44 +04:00
int vlan_id = 0 ;
2011-02-04 23:10:34 +03:00
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 */
2012-06-05 03:15:44 +04:00
if ( netdev - > priv_flags & IFF_802_1Q_VLAN )
2011-02-04 23:10:34 +03:00
phys_dev = vlan_dev_real_dev ( netdev ) ;
2012-06-05 03:15:44 +04:00
2011-02-04 23:10:34 +03:00
/* 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 " ) ;
2014-11-04 13:37:59 +03:00
rc = - ENOMEM ;
2011-02-04 23:10:34 +03:00
goto ifput_err ;
}
2012-06-05 03:15:44 +04:00
if ( netdev - > priv_flags & IFF_802_1Q_VLAN ) {
vlan_id = vlan_dev_vlan_id ( netdev ) ;
interface - > vlan_enabled = 1 ;
}
2012-05-23 06:06:16 +04:00
ctlr = bnx2fc_to_ctlr ( interface ) ;
2013-03-25 22:00:26 +04:00
cdev = fcoe_ctlr_to_ctlr_dev ( ctlr ) ;
2011-07-27 01:51:39 +04:00
interface - > vlan_id = vlan_id ;
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 ;
}
2013-03-25 22:00:26 +04:00
lport = bnx2fc_if_create ( interface , & cdev - > dev , 0 ) ;
2011-02-04 23:10:34 +03:00
if ( ! lport ) {
printk ( KERN_ERR PFX " Failed to create interface (%s) \n " ,
netdev - > name ) ;
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 */
2012-05-23 06:06:16 +04:00
ctlr - > lp = lport ;
2011-02-04 23:10:34 +03:00
2012-11-27 10:53:40 +04:00
if ( link_state = = BNX2FC_CREATE_LINK_UP )
cdev - > enabled = FCOE_CTLR_ENABLED ;
else
cdev - > enabled = FCOE_CTLR_DISABLED ;
if ( link_state = = BNX2FC_CREATE_LINK_UP & &
! bnx2fc_link_ok ( lport ) ) {
2012-05-23 06:06:16 +04:00
fcoe_ctlr_link_up ( ctlr ) ;
2011-08-31 02:54:48 +04:00
fc_host_port_type ( lport - > host ) = FC_PORTTYPE_NPORT ;
set_bit ( ADAPTER_STATE_READY , & interface - > hba - > adapter_state ) ;
}
2011-07-27 01:51:39 +04:00
BNX2FC_HBA_DBG ( lport , " create: START DISC \n " ) ;
bnx2fc_start_disc ( interface ) ;
2012-11-27 10:53:40 +04:00
if ( link_state = = BNX2FC_CREATE_LINK_UP )
interface - > enabled = true ;
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-08-31 02:54:52 +04:00
bnx2fc_net_cleanup ( interface ) ;
2011-07-27 01:51:39 +04:00
bnx2fc_interface_put ( interface ) ;
2012-01-24 06:00:48 +04:00
goto mod_err ;
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 ;
}
2012-11-27 10:53:40 +04:00
/**
* bnx2fc_create ( ) - Create a bnx2fc interface
* @ netdev : The net_device object the Ethernet interface to create on
* @ fip_mode : The FIP mode for this creation
*
* Called from fcoe transport
*
* Returns : 0 for success
*/
static int bnx2fc_create ( struct net_device * netdev , enum fip_state fip_mode )
{
return _bnx2fc_create ( netdev , fip_mode , BNX2FC_CREATE_LINK_UP ) ;
}
/**
* bnx2fc_ctlr_alloc ( ) - Allocate a bnx2fc interface from fcoe_sysfs
* @ netdev : The net_device to be used by the allocated FCoE Controller
*
* This routine is called from fcoe_sysfs . It will start the fcoe_ctlr
* in a link_down state . The allows the user an opportunity to configure
* the FCoE Controller from sysfs before enabling the FCoE Controller .
*
* Creating in with this routine starts the FCoE Controller in Fabric
* mode . The user can change to VN2VN or another mode before enabling .
*/
static int bnx2fc_ctlr_alloc ( struct net_device * netdev )
{
return _bnx2fc_create ( netdev , FIP_MODE_FABRIC ,
BNX2FC_CREATE_LINK_DOWN ) ;
}
2011-02-04 23:10:34 +03:00
/**
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 bnx2fc_hba * hba ;
/* Called with bnx2fc_dev_lock held */
2012-06-07 13:19:36 +04:00
list_for_each_entry ( hba , & adapter_list , list ) {
2011-02-04 23:10:34 +03:00
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 ;
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-08-05 04:38:42 +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-08-05 04:38:42 +04:00
if ( interface - > hba = = hba )
2011-08-25 05:56:42 +04:00
__bnx2fc_destroy ( interface ) ;
2011-02-04 23:10:34 +03:00
mutex_unlock ( & bnx2fc_dev_lock ) ;
2013-12-12 03:30:21 +04:00
/* Ensure ALL destroy work has been completed before return */
flush_workqueue ( bnx2fc_wq ) ;
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 ) )
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 )
{
2012-06-05 03:15:44 +04:00
struct net_device * phys_dev = netdev ;
2011-02-04 23:10:34 +03:00
mutex_lock ( & bnx2fc_dev_lock ) ;
2012-06-05 03:15:44 +04:00
if ( netdev - > priv_flags & IFF_802_1Q_VLAN )
phys_dev = vlan_dev_real_dev ( netdev ) ;
2011-02-04 23:10:34 +03:00
2012-06-05 03:15:44 +04:00
if ( bnx2fc_hba_lookup ( phys_dev ) ) {
mutex_unlock ( & bnx2fc_dev_lock ) ;
return true ;
2011-02-04 23:10:34 +03:00
}
2012-06-05 03:15:44 +04:00
2011-02-04 23:10:34 +03:00
mutex_unlock ( & bnx2fc_dev_lock ) ;
return false ;
}
static struct fcoe_transport bnx2fc_transport = {
. name = { " bnx2fc " } ,
. attached = false ,
. list = LIST_HEAD_INIT ( bnx2fc_transport . list ) ,
2012-11-27 10:53:40 +04:00
. alloc = bnx2fc_ctlr_alloc ,
2011-02-04 23:10:34 +03:00
. 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 ) ;
2012-06-05 03:15:42 +04:00
thread = kthread_create_on_node ( bnx2fc_percpu_io_thread ,
( void * ) p , cpu_to_node ( cpu ) ,
" bnx2fc_thread/%d " , cpu ) ;
2011-02-04 23:10:34 +03:00
/* 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 ) ;
}
2014-03-11 00:39:45 +04:00
cpu_notifier_register_begin ( ) ;
2011-02-04 23:10:34 +03:00
for_each_online_cpu ( cpu ) {
bnx2fc_percpu_thread_create ( cpu ) ;
}
/* Initialize per CPU interrupt thread */
2014-03-11 00:39:45 +04:00
__register_hotcpu_notifier ( & bnx2fc_cpu_notifier ) ;
cpu_notifier_register_done ( ) ;
2011-02-04 23:10:34 +03:00
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 ) ;
2014-03-11 00:39:45 +04:00
cpu_notifier_register_begin ( ) ;
2011-02-04 23:10:34 +03:00
/* Destroy per cpu threads */
for_each_online_cpu ( cpu ) {
bnx2fc_percpu_thread_destroy ( cpu ) ;
}
2014-03-11 00:39:45 +04:00
__unregister_hotcpu_notifier ( & bnx2fc_cpu_notifier ) ;
cpu_notifier_register_done ( ) ;
2011-02-04 23:10:34 +03:00
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 ) ;
2012-05-23 06:06:26 +04:00
static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ = {
2012-11-27 10:53:40 +04:00
. set_fcoe_ctlr_enabled = bnx2fc_ctlr_enabled ,
2012-12-06 10:24:59 +04:00
. get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb ,
. get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb ,
. get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb ,
. get_fcoe_ctlr_symb_err = fcoe_ctlr_get_lesb ,
. get_fcoe_ctlr_err_block = fcoe_ctlr_get_lesb ,
. get_fcoe_ctlr_fcs_error = fcoe_ctlr_get_lesb ,
2012-05-23 06:06:26 +04:00
. get_fcoe_fcf_selected = fcoe_fcf_get_selected ,
. get_fcoe_fcf_vlan_id = bnx2fc_fcf_get_vlan_id ,
} ;
2011-02-04 23:10:34 +03:00
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 ,
2014-07-03 16:18:28 +04:00
. name = " QLogic Offload FCoE Initiator " ,
2011-02-04 23:10:34 +03:00
. 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 ,
2014-11-13 17:08:42 +03:00
. change_queue_depth = scsi_change_queue_depth ,
2011-02-04 23:10:34 +03:00
. this_id = - 1 ,
. cmd_per_lun = 3 ,
. use_clustering = ENABLE_CLUSTERING ,
. sg_tablesize = BNX2FC_MAX_BDS_PER_CMD ,
2012-12-22 07:40:33 +04:00
. max_sectors = 1024 ,
2014-11-03 16:09:02 +03:00
. use_blk_tags = 1 ,
2014-11-13 16:25:11 +03:00
. track_queue_depth = 1 ,
2011-02-04 23:10:34 +03:00
} ;
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 ,
2012-12-06 10:24:59 +04:00
. get_lesb = fcoe_get_lesb ,
2011-02-04 23:10:34 +03:00
. 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 ,
2012-06-26 05:31:19 +04:00
. cnic_get_stats = bnx2fc_ulp_get_stats ,
2011-02-04 23:10:34 +03:00
} ;