diff options
Diffstat (limited to 'drivers/scsi/bnx2fc')
-rw-r--r-- | drivers/scsi/bnx2fc/Kconfig | 3 | ||||
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc.h | 10 | ||||
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_els.c | 49 | ||||
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 232 | ||||
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_hwi.c | 16 | ||||
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_io.c | 69 | ||||
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_tgt.c | 23 |
7 files changed, 278 insertions, 124 deletions
diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig index 6a38080e35e..cfcad8bde7c 100644 --- a/drivers/scsi/bnx2fc/Kconfig +++ b/drivers/scsi/bnx2fc/Kconfig @@ -2,7 +2,8 @@ config SCSI_BNX2X_FCOE tristate "Broadcom NetXtreme II FCoE support" depends on PCI select NETDEVICES - select NETDEV_1000 + select ETHERNET + select NET_VENDOR_BROADCOM select LIBFC select LIBFCOE select CNIC diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 42228ca5a9d..049ea907e04 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -58,11 +58,11 @@ #include "57xx_hsi_bnx2fc.h" #include "bnx2fc_debug.h" -#include "../../net/cnic_if.h" +#include "../../net/ethernet/broadcom/cnic_if.h" #include "bnx2fc_constants.h" #define BNX2FC_NAME "bnx2fc" -#define BNX2FC_VERSION "1.0.4" +#define BNX2FC_VERSION "1.0.9" #define PFX "bnx2fc: " @@ -81,7 +81,7 @@ #define BNX2FC_RQ_WQES_MAX 16 #define BNX2FC_CQ_WQES_MAX (BNX2FC_SQ_WQES_MAX + BNX2FC_RQ_WQES_MAX) -#define BNX2FC_NUM_MAX_SESS 128 +#define BNX2FC_NUM_MAX_SESS 1024 #define BNX2FC_NUM_MAX_SESS_LOG (ilog2(BNX2FC_NUM_MAX_SESS)) #define BNX2FC_MAX_OUTSTANDING_CMNDS 2048 @@ -145,6 +145,9 @@ #define REC_RETRY_COUNT 1 #define BNX2FC_NUM_ERR_BITS 63 +#define BNX2FC_RELOGIN_WAIT_TIME 200 +#define BNX2FC_RELOGIN_WAIT_CNT 10 + /* bnx2fc driver uses only one instance of fcoe_percpu_s */ extern struct fcoe_percpu_s bnx2fc_global; @@ -224,6 +227,7 @@ struct bnx2fc_interface { struct fcoe_ctlr ctlr; u8 vlan_enabled; int vlan_id; + bool enabled; }; #define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_interface, ctlr) diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index d66dcbd0df1..ce0ce3e32f3 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -268,17 +268,6 @@ void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg) orig_io_req = cb_arg->aborted_io_req; srr_req = cb_arg->io_req; - if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(srr_req, "srr_compl: xid - 0x%x completed", - orig_io_req->xid); - goto srr_compl_done; - } - if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(srr_req, "rec abts in prog " - "orig_io - 0x%x\n", - orig_io_req->xid); - goto srr_compl_done; - } if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &srr_req->req_flags)) { /* SRR timedout */ BNX2FC_IO_DBG(srr_req, "srr timed out, abort " @@ -290,6 +279,12 @@ void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg) "failed. issue cleanup\n"); bnx2fc_initiate_cleanup(srr_req); } + if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || + test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { + BNX2FC_IO_DBG(srr_req, "srr_compl:xid 0x%x flags = %lx", + orig_io_req->xid, orig_io_req->req_flags); + goto srr_compl_done; + } orig_io_req->srr_retry++; if (orig_io_req->srr_retry <= SRR_RETRY_COUNT) { struct bnx2fc_rport *tgt = orig_io_req->tgt; @@ -311,6 +306,12 @@ void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg) } goto srr_compl_done; } + if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || + test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { + BNX2FC_IO_DBG(srr_req, "srr_compl:xid - 0x%x flags = %lx", + orig_io_req->xid, orig_io_req->req_flags); + goto srr_compl_done; + } mp_req = &(srr_req->mp_req); fc_hdr = &(mp_req->resp_fc_hdr); resp_len = mp_req->resp_len; @@ -391,18 +392,6 @@ void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg) BNX2FC_IO_DBG(rec_req, "rec_compl: orig xid = 0x%x", orig_io_req->xid); tgt = orig_io_req->tgt; - if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(rec_req, "completed" - "orig_io - 0x%x\n", - orig_io_req->xid); - goto rec_compl_done; - } - if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(rec_req, "abts in prog " - "orig_io - 0x%x\n", - orig_io_req->xid); - goto rec_compl_done; - } /* Handle REC timeout case */ if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rec_req->req_flags)) { BNX2FC_IO_DBG(rec_req, "timed out, abort " @@ -433,6 +422,20 @@ void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg) } goto rec_compl_done; } + + if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) { + BNX2FC_IO_DBG(rec_req, "completed" + "orig_io - 0x%x\n", + orig_io_req->xid); + goto rec_compl_done; + } + if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { + BNX2FC_IO_DBG(rec_req, "abts in prog " + "orig_io - 0x%x\n", + orig_io_req->xid); + goto rec_compl_done; + } + mp_req = &(rec_req->mp_req); fc_hdr = &(mp_req->resp_fc_hdr); resp_len = mp_req->resp_len; diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 7cb2cd48b17..8c6156a10d9 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -22,7 +22,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); #define DRV_MODULE_NAME "bnx2fc" #define DRV_MODULE_VERSION BNX2FC_VERSION -#define DRV_MODULE_RELDATE "Jun 23, 2011" +#define DRV_MODULE_RELDATE "Oct 21, 2011" static char version[] __devinitdata = @@ -56,6 +56,7 @@ static struct scsi_host_template bnx2fc_shost_template; static struct fc_function_template bnx2fc_transport_function; static struct fc_function_template bnx2fc_vport_xport_function; static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); +static void __bnx2fc_destroy(struct bnx2fc_interface *interface); 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); @@ -64,7 +65,6 @@ static void bnx2fc_recv_frame(struct sk_buff *skb); static void bnx2fc_start_disc(struct bnx2fc_interface *interface); static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev); -static int bnx2fc_net_config(struct fc_lport *lp); static int bnx2fc_lport_config(struct fc_lport *lport); static int bnx2fc_em_config(struct fc_lport *lport); static int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba); @@ -78,6 +78,7 @@ static void bnx2fc_destroy_work(struct work_struct *work); static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev); static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device *phys_dev); +static inline void bnx2fc_interface_put(struct bnx2fc_interface *interface); static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic); static int bnx2fc_fw_init(struct bnx2fc_hba *hba); @@ -98,6 +99,25 @@ static struct notifier_block bnx2fc_cpu_notifier = { .notifier_call = bnx2fc_cpu_callback, }; +static inline struct net_device *bnx2fc_netdev(const struct fc_lport *lport) +{ + return ((struct bnx2fc_interface *) + ((struct fcoe_port *)lport_priv(lport))->priv)->netdev; +} + +/** + * bnx2fc_get_lesb() - Fill the FCoE Link Error Status Block + * @lport: the local port + * @fc_lesb: the link error status block + */ +static void bnx2fc_get_lesb(struct fc_lport *lport, + struct fc_els_lesb *fc_lesb) +{ + struct net_device *netdev = bnx2fc_netdev(lport); + + __fcoe_get_lesb(lport, fc_lesb, netdev); +} + static void bnx2fc_clean_rx_queue(struct fc_lport *lp) { struct fcoe_percpu_s *bg; @@ -302,7 +322,7 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) return -ENOMEM; } frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; - cp = kmap_atomic(frag->page, KM_SKB_DATA_SOFTIRQ) + cp = kmap_atomic(skb_frag_page(frag), KM_SKB_DATA_SOFTIRQ) + frag->page_offset; } else { cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); @@ -545,6 +565,14 @@ static void bnx2fc_recv_frame(struct sk_buff *skb) break; } } + + if (fh->fh_r_ctl == FC_RCTL_BA_ABTS) { + /* Drop incoming ABTS */ + put_cpu(); + kfree_skb(skb); + return; + } + if (le32_to_cpu(fr_crc(fp)) != ~crc32(~0, skb->data, fr_len)) { if (stats->InvalidCRCCount < 5) @@ -673,7 +701,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport) struct net_device *netdev = interface->netdev; struct ethtool_cmd ecmd; - if (!dev_ethtool_get_settings(netdev, &ecmd)) { + if (!__ethtool_get_settings(netdev, &ecmd)) { lport->link_supported_speeds &= ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); if (ecmd.supported & (SUPPORTED_1000baseT_Half | @@ -727,7 +755,7 @@ void bnx2fc_get_link_state(struct bnx2fc_hba *hba) clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); } -static int bnx2fc_net_config(struct fc_lport *lport) +static int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev) { struct bnx2fc_hba *hba; struct bnx2fc_interface *interface; @@ -753,11 +781,16 @@ static int bnx2fc_net_config(struct fc_lport *lport) bnx2fc_link_speed_update(lport); if (!lport->vport) { - wwnn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, 1, 0); + if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) + wwnn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, + 1, 0); BNX2FC_HBA_DBG(lport, "WWNN = 0x%llx\n", wwnn); fc_set_wwnn(lport, wwnn); - wwpn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, 2, 0); + if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) + wwpn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, + 2, 0); + BNX2FC_HBA_DBG(lport, "WWPN = 0x%llx\n", wwpn); fc_set_wwpn(lport, wwpn); } @@ -769,8 +802,8 @@ static void bnx2fc_destroy_timer(unsigned long data) { struct bnx2fc_hba *hba = (struct bnx2fc_hba *)data; - BNX2FC_MISC_DBG("ERROR:bnx2fc_destroy_timer - " - "Destroy compl not received!!\n"); + printk(KERN_ERR PFX "ERROR:bnx2fc_destroy_timer - " + "Destroy compl not received!!\n"); set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); wake_up_interruptible(&hba->destroy_wait); } @@ -783,7 +816,7 @@ static void bnx2fc_destroy_timer(unsigned long data) * @vlan_id: vlan id - associated vlan id with this event * * Handles NETDEV_UP, NETDEV_DOWN, NETDEV_GOING_DOWN,NETDEV_CHANGE and - * NETDEV_CHANGE_MTU events + * NETDEV_CHANGE_MTU events. Handle NETDEV_UNREGISTER only for vlans. */ static void bnx2fc_indicate_netevent(void *context, unsigned long event, u16 vlan_id) @@ -791,12 +824,11 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context; struct fc_lport *lport; struct fc_lport *vport; - struct bnx2fc_interface *interface; + struct bnx2fc_interface *interface, *tmp; int wait_for_upload = 0; u32 link_possible = 1; - /* Ignore vlans for now */ - if (vlan_id != 0) + if (vlan_id != 0 && event != NETDEV_UNREGISTER) return; switch (event) { @@ -820,6 +852,18 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, case NETDEV_CHANGE: break; + case NETDEV_UNREGISTER: + if (!vlan_id) + return; + mutex_lock(&bnx2fc_dev_lock); + list_for_each_entry_safe(interface, tmp, &if_list, list) { + if (interface->hba == hba && + interface->vlan_id == (vlan_id & VLAN_VID_MASK)) + __bnx2fc_destroy(interface); + } + mutex_unlock(&bnx2fc_dev_lock); + return; + default: printk(KERN_ERR PFX "Unkonwn netevent %ld", event); return; @@ -838,8 +882,15 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, bnx2fc_link_speed_update(lport); if (link_possible && !bnx2fc_link_ok(lport)) { - printk(KERN_ERR "indicate_netevent: ctlr_link_up\n"); - fcoe_ctlr_link_up(&interface->ctlr); + /* 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(&interface->ctlr); } else if (fcoe_ctlr_link_down(&interface->ctlr)) { mutex_lock(&lport->lp_mutex); list_for_each_entry(vport, &lport->vports, list) @@ -995,15 +1046,28 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled) struct bnx2fc_interface *interface = port->priv; struct net_device *netdev = interface->netdev; struct fc_lport *vn_port; + 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; + } if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) { printk(KERN_ERR PFX "vn ports cannot be created on" "this interface\n"); return -EIO; } + rtnl_lock(); mutex_lock(&bnx2fc_dev_lock); vn_port = bnx2fc_if_create(interface, &vport->dev, 1); mutex_unlock(&bnx2fc_dev_lock); + rtnl_unlock(); if (IS_ERR(vn_port)) { printk(KERN_ERR PFX "bnx2fc_vport_create (%s) failed\n", @@ -1022,16 +1086,46 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled) return 0; } +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); +} + 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); + struct bnx2fc_interface *interface = port->priv; + struct fc_lport *v_port; + bool found = false; mutex_lock(&n_port->lp_mutex); + 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; + } list_del(&vn_port->list); mutex_unlock(&n_port->lp_mutex); + bnx2fc_free_vport(interface->hba, port->lport); + bnx2fc_port_shutdown(port->lport); + bnx2fc_interface_put(interface); queue_work(bnx2fc_wq, &port->destroy_work); return 0; } @@ -1052,7 +1146,7 @@ static int bnx2fc_vport_disable(struct fc_vport *vport, bool disable) } -static int bnx2fc_netdev_setup(struct bnx2fc_interface *interface) +static int bnx2fc_interface_setup(struct bnx2fc_interface *interface) { struct net_device *netdev = interface->netdev; struct net_device *physdev = interface->hba->phys_dev; @@ -1250,7 +1344,7 @@ struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba, interface->ctlr.get_src_addr = bnx2fc_get_src_mac; set_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags); - rc = bnx2fc_netdev_setup(interface); + rc = bnx2fc_interface_setup(interface); if (!rc) return interface; @@ -1316,7 +1410,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, fc_set_wwpn(lport, vport->port_name); } /* Configure netdev and networking properties of the lport */ - rc = bnx2fc_net_config(lport); + rc = bnx2fc_net_config(lport, interface->netdev); if (rc) { printk(KERN_ERR PFX "Error on bnx2fc_net_config\n"); goto lp_config_err; @@ -1370,7 +1464,7 @@ free_blport: return NULL; } -static void bnx2fc_netdev_cleanup(struct bnx2fc_interface *interface) +static void bnx2fc_net_cleanup(struct bnx2fc_interface *interface) { /* Dont listen for Ethernet packets anymore */ __dev_remove_pack(&interface->fcoe_packet_type); @@ -1378,10 +1472,11 @@ static void bnx2fc_netdev_cleanup(struct bnx2fc_interface *interface) synchronize_net(); } -static void bnx2fc_if_destroy(struct fc_lport *lport, struct bnx2fc_hba *hba) +static void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) { + struct fc_lport *lport = interface->ctlr.lp; struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_lport *blport, *tmp; + struct bnx2fc_hba *hba = interface->hba; /* Stop the transmit retry timer */ del_timer_sync(&port->timer); @@ -1389,6 +1484,14 @@ static void bnx2fc_if_destroy(struct fc_lport *lport, struct bnx2fc_hba *hba) /* Free existing transmit skbs */ fcoe_clean_pending_queue(lport); + bnx2fc_net_cleanup(interface); + + bnx2fc_free_vport(hba, lport); +} + +static void bnx2fc_if_destroy(struct fc_lport *lport) +{ + /* Free queued packets for the receive thread */ bnx2fc_clean_rx_queue(lport); @@ -1405,19 +1508,22 @@ static void bnx2fc_if_destroy(struct fc_lport *lport, struct bnx2fc_hba *hba) /* Free memory used by statistical counters */ fc_lport_free_stats(lport); - 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); - /* Release Scsi_Host */ scsi_host_put(lport->host); } +static void __bnx2fc_destroy(struct bnx2fc_interface *interface) +{ + struct fc_lport *lport = interface->ctlr.lp; + struct fcoe_port *port = lport_priv(lport); + + bnx2fc_interface_cleanup(interface); + bnx2fc_stop(interface); + list_del(&interface->list); + bnx2fc_interface_put(interface); + queue_work(bnx2fc_wq, &port->destroy_work); +} + /** * bnx2fc_destroy - Destroy a bnx2fc FCoE interface * @@ -1431,8 +1537,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport, struct bnx2fc_hba *hba) static int bnx2fc_destroy(struct net_device *netdev) { struct bnx2fc_interface *interface = NULL; - struct bnx2fc_hba *hba; - struct fc_lport *lport; int rc = 0; rtnl_lock(); @@ -1445,15 +1549,9 @@ static int bnx2fc_destroy(struct net_device *netdev) goto netdev_err; } - hba = interface->hba; - bnx2fc_netdev_cleanup(interface); - lport = interface->ctlr.lp; - bnx2fc_stop(interface); - list_del(&interface->list); destroy_workqueue(interface->timer_work_queue); - bnx2fc_interface_put(interface); - bnx2fc_if_destroy(lport, hba); + __bnx2fc_destroy(interface); netdev_err: mutex_unlock(&bnx2fc_dev_lock); @@ -1465,22 +1563,13 @@ static void bnx2fc_destroy_work(struct work_struct *work) { struct fcoe_port *port; struct fc_lport *lport; - struct bnx2fc_interface *interface; - struct bnx2fc_hba *hba; port = container_of(work, struct fcoe_port, destroy_work); lport = port->lport; - interface = port->priv; - hba = interface->hba; BNX2FC_HBA_DBG(lport, "Entered bnx2fc_destroy_work\n"); - bnx2fc_port_shutdown(lport); - rtnl_lock(); - mutex_lock(&bnx2fc_dev_lock); - bnx2fc_if_destroy(lport, hba); - mutex_unlock(&bnx2fc_dev_lock); - rtnl_unlock(); + bnx2fc_if_destroy(lport); } static void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba) @@ -1659,6 +1748,7 @@ static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba) wait_event_interruptible(hba->destroy_wait, test_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags)); + clear_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); /* This should never happen */ if (signal_pending(current)) flush_signals(current); @@ -1721,7 +1811,7 @@ static void bnx2fc_start_disc(struct bnx2fc_interface *interface) lport = interface->ctlr.lp; BNX2FC_HBA_DBG(lport, "calling fc_fabric_login\n"); - if (!bnx2fc_link_ok(lport)) { + if (!bnx2fc_link_ok(lport) && interface->enabled) { BNX2FC_HBA_DBG(lport, "ctlr_link_up\n"); fcoe_ctlr_link_up(&interface->ctlr); fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; @@ -1735,6 +1825,11 @@ static void bnx2fc_start_disc(struct bnx2fc_interface *interface) if (++wait_cnt > 12) break; } + + /* Reset max receive frame size to default */ + if (fc_set_mfs(lport, BNX2FC_MFS)) + return; + fc_lport_init(lport); fc_fabric_login(lport); } @@ -1798,6 +1893,7 @@ static int bnx2fc_disable(struct net_device *netdev) rc = -ENODEV; printk(KERN_ERR PFX "bnx2fc_disable: interface or lport not found\n"); } else { + interface->enabled = false; fcoe_ctlr_link_down(&interface->ctlr); fcoe_clean_pending_queue(interface->ctlr.lp); } @@ -1820,8 +1916,10 @@ static int bnx2fc_enable(struct net_device *netdev) if (!interface || !interface->ctlr.lp) { rc = -ENODEV; printk(KERN_ERR PFX "bnx2fc_enable: interface or lport not found\n"); - } else if (!bnx2fc_link_ok(interface->ctlr.lp)) + } else if (!bnx2fc_link_ok(interface->ctlr.lp)) { fcoe_ctlr_link_up(&interface->ctlr); + interface->enabled = true; + } mutex_unlock(&bnx2fc_dev_lock); rtnl_unlock(); @@ -1921,7 +2019,6 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) if (!lport) { printk(KERN_ERR PFX "Failed to create interface (%s)\n", netdev->name); - bnx2fc_netdev_cleanup(interface); rc = -EINVAL; goto if_create_err; } @@ -1934,8 +2031,15 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) /* Make this master N_port */ interface->ctlr.lp = lport; + if (!bnx2fc_link_ok(lport)) { + fcoe_ctlr_link_up(&interface->ctlr); + fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; + set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state); + } + BNX2FC_HBA_DBG(lport, "create: START DISC\n"); bnx2fc_start_disc(interface); + interface->enabled = true; /* * Release from kref_init in bnx2fc_interface_setup, on success * lport should be holding a reference taken in bnx2fc_if_create @@ -1949,6 +2053,7 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) if_create_err: destroy_workqueue(interface->timer_work_queue); ifput_err: + bnx2fc_net_cleanup(interface); bnx2fc_interface_put(interface); netdev_err: module_put(THIS_MODULE); @@ -2015,7 +2120,6 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev) { struct bnx2fc_hba *hba; struct bnx2fc_interface *interface, *tmp; - struct fc_lport *lport; BNX2FC_MISC_DBG("Entered bnx2fc_ulp_exit\n"); @@ -2037,18 +2141,10 @@ static void bnx2fc_ulp_exit(struct cnic_dev *dev) list_del_init(&hba->list); adapter_count--; - list_for_each_entry_safe(interface, tmp, &if_list, list) { + list_for_each_entry_safe(interface, tmp, &if_list, list) /* destroy not called yet, move to quiesced list */ - if (interface->hba == hba) { - bnx2fc_netdev_cleanup(interface); - bnx2fc_stop(interface); - - list_del(&interface->list); - lport = interface->ctlr.lp; - bnx2fc_interface_put(interface); - bnx2fc_if_destroy(lport, hba); - } - } + if (interface->hba == hba) + __bnx2fc_destroy(interface); mutex_unlock(&bnx2fc_dev_lock); bnx2fc_ulp_stop(hba); @@ -2117,7 +2213,7 @@ static void bnx2fc_percpu_thread_create(unsigned int cpu) (void *)p, "bnx2fc_thread/%d", cpu); /* bind thread to the cpu */ - if (likely(!IS_ERR(p->iothread))) { + if (likely(!IS_ERR(thread))) { kthread_bind(thread, cpu); p->iothread = thread; wake_up_process(thread); @@ -2129,7 +2225,6 @@ static void bnx2fc_percpu_thread_destroy(unsigned int cpu) struct bnx2fc_percpu_s *p; struct task_struct *thread; struct bnx2fc_work *work, *tmp; - LIST_HEAD(work_list); BNX2FC_MISC_DBG("destroying io thread for CPU %d\n", cpu); @@ -2141,7 +2236,7 @@ static void bnx2fc_percpu_thread_destroy(unsigned int cpu) /* Free all work in the list */ - list_for_each_entry_safe(work, tmp, &work_list, list) { + list_for_each_entry_safe(work, tmp, &p->work_list, list) { list_del_init(&work->list); bnx2fc_process_cq_compl(work->tgt, work->wqe); kfree(work); @@ -2374,6 +2469,7 @@ static struct fc_function_template bnx2fc_transport_function = { .vport_create = bnx2fc_vport_create, .vport_delete = bnx2fc_vport_destroy, .vport_disable = bnx2fc_vport_disable, + .bsg_request = fc_lport_bsg_request, }; static struct fc_function_template bnx2fc_vport_xport_function = { @@ -2407,6 +2503,7 @@ static struct fc_function_template bnx2fc_vport_xport_function = { .get_fc_host_stats = fc_get_host_stats, .issue_fc_host_lip = bnx2fc_fcoe_reset, .terminate_rport_io = fc_rport_terminate_io, + .bsg_request = fc_lport_bsg_request, }; /** @@ -2436,6 +2533,7 @@ static struct libfc_function_template bnx2fc_libfc_fcn_templ = { .elsct_send = bnx2fc_elsct_send, .fcp_abort_io = bnx2fc_abort_io, .fcp_cleanup = bnx2fc_cleanup, + .get_lesb = bnx2fc_get_lesb, .rport_event_callback = bnx2fc_rport_event_handler, }; diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 72cfb14acd3..1923a25cb6a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -1009,6 +1009,7 @@ int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt) u32 cq_cons; struct fcoe_cqe *cqe; u32 num_free_sqes = 0; + u32 num_cqes = 0; u16 wqe; /* @@ -1058,10 +1059,11 @@ unlock: wake_up_process(fps->iothread); else bnx2fc_process_cq_compl(tgt, wqe); + num_free_sqes++; } cqe++; tgt->cq_cons_idx++; - num_free_sqes++; + num_cqes++; if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) { tgt->cq_cons_idx = 0; @@ -1070,8 +1072,10 @@ unlock: 1 - tgt->cq_curr_toggle_bit; } } - if (num_free_sqes) { - bnx2fc_arm_cq(tgt); + if (num_cqes) { + /* Arm CQ only if doorbell is mapped */ + if (tgt->ctx_base) + bnx2fc_arm_cq(tgt); atomic_add(num_free_sqes, &tgt->free_sqes); } spin_unlock_bh(&tgt->cq_lock); @@ -1739,11 +1743,13 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req, /* Init state to NORMAL */ task->txwr_rxrd.const_ctx.init_flags |= task_type << FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; - if (dev_type == TYPE_TAPE) + if (dev_type == TYPE_TAPE) { task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_DEV_TYPE_TAPE << FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; - else + io_req->rec_retry = 0; + io_req->rec_retry = 0; + } else task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_DEV_TYPE_DISK << FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 6cc3789075b..84a78af83f9 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -17,7 +17,7 @@ static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len, int bd_index); static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req); -static void bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req); +static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req); static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req); static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req); static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, @@ -1103,7 +1103,10 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) struct fc_rport_libfc_priv *rp = rport->dd_data; struct bnx2fc_cmd *io_req; struct fc_lport *lport; + struct fc_rport_priv *rdata; struct bnx2fc_rport *tgt; + int logo_issued; + int wait_cnt = 0; int rc = FAILED; @@ -1192,8 +1195,40 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) } else { printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " "already in abts processing\n", io_req->xid); + if (cancel_delayed_work(&io_req->timeout_work)) + kref_put(&io_req->refcount, + bnx2fc_cmd_release); /* drop timer hold */ + bnx2fc_initiate_cleanup(io_req); + + spin_unlock_bh(&tgt->tgt_lock); + + wait_for_completion(&io_req->tm_done); + + spin_lock_bh(&tgt->tgt_lock); + io_req->wait_for_comp = 0; + rdata = io_req->tgt->rdata; + logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, + &tgt->flags); kref_put(&io_req->refcount, bnx2fc_cmd_release); spin_unlock_bh(&tgt->tgt_lock); + + if (!logo_issued) { + BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", + tgt->flags); + mutex_lock(&lport->disc.disc_mutex); + lport->tt.rport_logoff(rdata); + mutex_unlock(&lport->disc.disc_mutex); + do { + msleep(BNX2FC_RELOGIN_WAIT_TIME); + /* + * If session not recovered, let SCSI-ml + * escalate error recovery. + */ + if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) + return FAILED; + } while (!test_bit(BNX2FC_FLAG_SESSION_READY, + &tgt->flags)); + } return SUCCESS; } if (rc == FAILED) { @@ -1251,7 +1286,6 @@ void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnp_req, seq_clnp_req->xid); goto free_cb_arg; } - kref_get(&orig_io_req->refcount); spin_unlock_bh(&tgt->tgt_lock); rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl); @@ -1276,6 +1310,8 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, io_req->refcount.refcount.counter, io_req->cmd_type); bnx2fc_scsi_done(io_req, DID_ERROR); kref_put(&io_req->refcount, bnx2fc_cmd_release); + if (io_req->wait_for_comp) + complete(&io_req->tm_done); } void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, @@ -1569,6 +1605,8 @@ static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len, static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) { + struct bnx2fc_interface *interface = io_req->port->priv; + struct bnx2fc_hba *hba = interface->hba; struct scsi_cmnd *sc = io_req->sc_cmd; struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl; struct scatterlist *sg; @@ -1580,7 +1618,8 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) u64 addr; int i; - sg_count = scsi_dma_map(sc); + sg_count = dma_map_sg(&hba->pcidev->dev, scsi_sglist(sc), + scsi_sg_count(sc), sc->sc_data_direction); scsi_for_each_sg(sc, sg, sg_count, i) { sg_len = sg_dma_len(sg); addr = sg_dma_address(sg); @@ -1605,20 +1644,24 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) return bd_count; } -static void bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req) +static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req) { struct scsi_cmnd *sc = io_req->sc_cmd; struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl; int bd_count; - if (scsi_sg_count(sc)) + if (scsi_sg_count(sc)) { bd_count = bnx2fc_map_sg(io_req); - else { + if (bd_count == 0) + return -ENOMEM; + } else { bd_count = 0; bd[0].buf_addr_lo = bd[0].buf_addr_hi = 0; bd[0].buf_len = bd[0].flags = 0; } io_req->bd_tbl->bd_valid = bd_count; + + return 0; } static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req) @@ -1790,12 +1833,6 @@ int bnx2fc_queuecommand(struct Scsi_Host *host, tgt = (struct bnx2fc_rport *)&rp[1]; if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { - if (test_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags)) { - sc_cmd->result = DID_NO_CONNECT << 16; - sc_cmd->scsi_done(sc_cmd); - return 0; - - } /* * Session is not offloaded yet. Let SCSI-ml retry * the command. @@ -1946,7 +1983,13 @@ int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, xid = io_req->xid; /* Build buffer descriptor list for firmware from sg list */ - bnx2fc_build_bd_list_from_sg(io_req); + if (bnx2fc_build_bd_list_from_sg(io_req)) { + printk(KERN_ERR PFX "BD list creation failed\n"); + spin_lock_bh(&tgt->tgt_lock); + kref_put(&io_req->refcount, bnx2fc_cmd_release); + spin_unlock_bh(&tgt->tgt_lock); + return -EAGAIN; + } task_idx = xid / BNX2FC_TASKS_PER_PAGE; index = xid % BNX2FC_TASKS_PER_PAGE; diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index d5311b577cc..c1800b53127 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -76,7 +76,7 @@ static void bnx2fc_offload_session(struct fcoe_port *port, if (rval) { printk(KERN_ERR PFX "Failed to allocate conn id for " "port_id (%6x)\n", rport->port_id); - goto ofld_err; + goto tgt_init_err; } /* Allocate session resources */ @@ -134,18 +134,17 @@ retry_ofld: /* upload will take care of cleaning up sess resc */ lport->tt.rport_logoff(rdata); } - /* Arm CQ */ - bnx2fc_arm_cq(tgt); return; ofld_err: /* couldn't offload the session. log off from this rport */ BNX2FC_TGT_DBG(tgt, "bnx2fc_offload_session - offload error\n"); - lport->tt.rport_logoff(rdata); /* Free session resources */ bnx2fc_free_session_resc(hba, tgt); +tgt_init_err: if (tgt->fcoe_conn_id != -1) bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id); + lport->tt.rport_logoff(rdata); } void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) @@ -624,7 +623,6 @@ static void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id) /* called with hba mutex held */ spin_lock_bh(&hba->hba_lock); hba->tgt_ofld_list[conn_id] = NULL; - hba->next_conn_id = conn_id; spin_unlock_bh(&hba->hba_lock); } @@ -791,8 +789,6 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, return 0; mem_alloc_failure: - bnx2fc_free_session_resc(hba, tgt); - bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id); return -ENOMEM; } @@ -807,14 +803,14 @@ mem_alloc_failure: static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba, struct bnx2fc_rport *tgt) { - BNX2FC_TGT_DBG(tgt, "Freeing up session resources\n"); + void __iomem *ctx_base_ptr; - if (tgt->ctx_base) { - iounmap(tgt->ctx_base); - tgt->ctx_base = NULL; - } + BNX2FC_TGT_DBG(tgt, "Freeing up session resources\n"); spin_lock_bh(&tgt->cq_lock); + ctx_base_ptr = tgt->ctx_base; + tgt->ctx_base = NULL; + /* Free LCQ */ if (tgt->lcq) { dma_free_coherent(&hba->pcidev->dev, tgt->lcq_mem_size, @@ -868,4 +864,7 @@ static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba, tgt->sq = NULL; } spin_unlock_bh(&tgt->cq_lock); + + if (ctx_base_ptr) + iounmap(ctx_base_ptr); } |