Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
Linus Torvalds [Sat, 23 Jul 2011 18:13:11 +0000 (11:13 -0700)]
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (77 commits)
  [SCSI] fix crash in scsi_dispatch_cmd()
  [SCSI] sr: check_events() ignore GET_EVENT when TUR says otherwise
  [SCSI] bnx2i: Fixed kernel panic due to illegal usage of sc->request->cpu
  [SCSI] bfa: Update the driver version to 3.0.2.1
  [SCSI] bfa: Driver and BSG enhancements.
  [SCSI] bfa: Added support to query PHY.
  [SCSI] bfa: Added HBA diagnostics support.
  [SCSI] bfa: Added support for flash configuration
  [SCSI] bfa: Added support to obtain SFP info.
  [SCSI] bfa: Added support for CEE info and stats query.
  [SCSI] bfa: Extend BSG interface.
  [SCSI] bfa: FCS bug fixes.
  [SCSI] bfa: DMA memory allocation enhancement.
  [SCSI] bfa: Brocade-1860 Fabric Adapter vHBA support.
  [SCSI] bfa: Brocade-1860 Fabric Adapter PLL init fixes.
  [SCSI] bfa: Added Fabric Assigned Address(FAA) support
  [SCSI] bfa: IOC bug fixes.
  [SCSI] bfa: Enable ASIC block configuration and query.
  [SCSI] bnx2i: Updated copyright and bump version
  [SCSI] bnx2i: Modified to skip CNIC registration if iSCSI is not supported
  ...

Fix up some trivial conflicts in:
 - drivers/scsi/bnx2fc/{bnx2fc.h,bnx2fc_fcoe.c}:
Crazy broadcom version number conflicts
 - drivers/target/tcm_fc/tfc_cmd.c
Just trivial cleanups done on adjacent lines

13 files changed:
1  2 
MAINTAINERS
drivers/scsi/bnx2fc/bnx2fc.h
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2fc/bnx2fc_hwi.c
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/bnx2i/57xx_iscsi_constants.h
drivers/scsi/bnx2i/57xx_iscsi_hsi.h
drivers/scsi/bnx2i/bnx2i.h
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/bnx2i/bnx2i_init.c
drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
drivers/scsi/libfc/fc_rport.c
drivers/target/tcm_fc/tfc_cmd.c

diff --combined MAINTAINERS
@@@ -1,5 -1,4 +1,5 @@@
  
 +
        List of maintainers and how to submit kernel changes
  
  Please try to follow the guidelines below.  This will make things
@@@ -534,8 -533,6 +534,8 @@@ L: device-drivers-devel@blackfin.uclinu
  L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
  W:    http://wiki.analog.com/
  S:    Supported
 +F:    sound/soc/codecs/adau*
 +F:    sound/soc/codecs/adav*
  F:    sound/soc/codecs/ad1*
  F:    sound/soc/codecs/ssm*
  
@@@ -1553,6 -1550,12 +1553,12 @@@ L:    linux-wireless@vger.kernel.or
  S:    Supported
  F:    drivers/staging/brcm80211/
  
+ BROADCOM BNX2FC 10 GIGABIT FCOE DRIVER
+ M:    Bhanu Prakash Gollapudi <bprakash@broadcom.com>
+ L:    linux-scsi@vger.kernel.org
+ S:    Supported
+ F:    drivers/scsi/bnx2fc/
  BROCADE BFA FC SCSI DRIVER
  M:    Jing Huang <huangj@brocade.com>
  L:    linux-scsi@vger.kernel.org
@@@ -1775,7 -1778,8 +1781,8 @@@ F:      include/linux/clk.
  
  CISCO FCOE HBA DRIVER
  M:    Abhijeet Joglekar <abjoglek@cisco.com>
- M:    Joe Eykholt <jeykholt@cisco.com>
+ M:    Venkata Siva Vijayendra Bhamidipati <vbhamidi@cisco.com>
+ M:    Brian Uchino <buchino@cisco.com>
  L:    linux-scsi@vger.kernel.org
  S:    Supported
  F:    drivers/scsi/fnic/
@@@ -3428,9 -3432,10 +3435,9 @@@ S:     Maintaine
  F:    drivers/net/ipg.*
  
  IPATH DRIVER
 -M:    Ralph Campbell <infinipath@qlogic.com>
 +M:    Mike Marciniszyn <infinipath@qlogic.com>
  L:    linux-rdma@vger.kernel.org
 -T:    git git://git.qlogic.com/ipath-linux-2.6
 -S:    Supported
 +S:    Maintained
  F:    drivers/infiniband/hw/ipath/
  
  IPMI SUBSYSTEM
@@@ -4291,8 -4296,8 +4298,8 @@@ S:      Maintaine
  F:    drivers/usb/musb/
  
  MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
 +M:    Jon Mason <mason@myri.com>
  M:    Andrew Gallatin <gallatin@myri.com>
 -M:    Brice Goglin <brice@myri.com>
  L:    netdev@vger.kernel.org
  W:    http://www.myri.com/scs/download-Myri10GE.html
  S:    Supported
@@@ -4586,8 -4591,9 +4593,8 @@@ S:      Maintaine
  F:    drivers/mmc/host/omap.c
  
  OMAP HS MMC SUPPORT
 -M:    Madhusudhan Chikkature <madhu.cr@ti.com>
  L:    linux-omap@vger.kernel.org
 -S:    Maintained
 +S:    Orphan
  F:    drivers/mmc/host/omap_hsmmc.c
  
  OMAP RANDOM NUMBER GENERATOR SUPPORT
@@@ -5153,12 -5159,6 +5160,12 @@@ M:    Robert Jarzmik <robert.jarzmik@free.
  L:    rtc-linux@googlegroups.com
  S:    Maintained
  
 +QIB DRIVER
 +M:    Mike Marciniszyn <infinipath@qlogic.com>
 +L:    linux-rdma@vger.kernel.org
 +S:    Supported
 +F:    drivers/infiniband/hw/qib/
 +
  QLOGIC QLA1280 SCSI DRIVER
  M:    Michael Reed <mdr@sgi.com>
  L:    linux-scsi@vger.kernel.org
@@@ -6249,14 -6249,9 +6256,14 @@@ F:    drivers/char/toshiba.
  F:    include/linux/toshiba.h
  
  TMIO MMC DRIVER
 +M:    Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  M:    Ian Molton <ian@mnementh.co.uk>
 +L:    linux-mmc@vger.kernel.org
  S:    Maintained
 -F:    drivers/mmc/host/tmio_mmc.*
 +F:    drivers/mmc/host/tmio_mmc*
 +F:    drivers/mmc/host/sh_mobile_sdhi.c
 +F:    include/linux/mmc/tmio.h
 +F:    include/linux/mmc/sh_mobile_sdhi.h
  
  TMPFS (SHMEM FILESYSTEM)
  M:    Hugh Dickins <hughd@google.com>
@@@ -6333,7 -6328,7 +6340,7 @@@ F:      drivers/scsi/u14-34f.
  
  UBI FILE SYSTEM (UBIFS)
  M:    Artem Bityutskiy <dedekind1@gmail.com>
 -M:    Adrian Hunter <adrian.hunter@nokia.com>
 +M:    Adrian Hunter <adrian.hunter@intel.com>
  L:    linux-mtd@lists.infradead.org
  T:    git git://git.infradead.org/ubifs-2.6.git
  W:    http://www.linux-mtd.infradead.org/doc/ubifs.html
@@@ -62,7 -62,7 +62,7 @@@
  #include "bnx2fc_constants.h"
  
  #define BNX2FC_NAME           "bnx2fc"
 -#define BNX2FC_VERSION                "1.0.2"
 +#define BNX2FC_VERSION                "1.0.3"
  
  #define PFX                   "bnx2fc: "
  
@@@ -152,7 -152,6 +152,6 @@@ struct bnx2fc_percpu_s 
        spinlock_t fp_work_lock;
  };
  
  struct bnx2fc_hba {
        struct list_head link;
        struct cnic_dev *cnic;
                #define BNX2FC_CTLR_INIT_DONE           1
                #define BNX2FC_CREATE_DONE              2
        struct fcoe_ctlr ctlr;
+       struct list_head vports;
        u8 vlan_enabled;
        int vlan_id;
        u32 next_conn_id;
  
  #define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_hba, ctlr)
  
+ struct bnx2fc_lport {
+       struct list_head list;
+       struct fc_lport *lport;
+ };
  struct bnx2fc_cmd_mgr {
        struct bnx2fc_hba *hba;
        u16 next_idx;
@@@ -262,14 -267,9 +267,14 @@@ struct bnx2fc_rport 
  #define BNX2FC_FLAG_UPLD_REQ_COMPL    0x8
  #define BNX2FC_FLAG_EXPL_LOGO         0x9
  
 +      u8 src_addr[ETH_ALEN];
        u32 max_sqes;
        u32 max_rqes;
        u32 max_cqes;
 +      atomic_t free_sqes;
 +
 +      struct b577xx_doorbell_set_prod sq_db;
 +      struct b577xx_fcoe_rx_doorbell rx_db;
  
        struct fcoe_sqe *sq;
        dma_addr_t sq_dma;
  
        struct fcoe_cqe *cq;
        dma_addr_t cq_dma;
 -      u32 cq_cons_idx;
 +      u16 cq_cons_idx;
        u8 cq_curr_toggle_bit;
        u32 cq_mem_size;
  
@@@ -428,6 -428,7 +433,7 @@@ struct bnx2fc_work 
  struct bnx2fc_unsol_els {
        struct fc_lport *lport;
        struct fc_frame *fp;
+       struct bnx2fc_hba *hba;
        struct work_struct unsol_els_work;
  };
  
@@@ -510,7 -511,6 +516,7 @@@ struct fc_seq *bnx2fc_elsct_send(struc
                                                   struct fc_frame *,
                                                   void *),
                                      void *arg, u32 timeout);
 +void bnx2fc_arm_cq(struct bnx2fc_rport *tgt);
  int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt);
  void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe);
  struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port,
@@@ -21,7 -21,7 +21,7 @@@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, 
  
  #define DRV_MODULE_NAME               "bnx2fc"
  #define DRV_MODULE_VERSION    BNX2FC_VERSION
 -#define DRV_MODULE_RELDATE    "May 27, 2011"
 +#define DRV_MODULE_RELDATE    "Jun 10, 2011"
  
  
  static char version[] __devinitdata =
@@@ -612,7 -612,7 +612,7 @@@ static struct fc_host_statistics *bnx2f
                BNX2FC_HBA_DBG(lport, "FW stat req timed out\n");
                return bnx2fc_stats;
        }
 -      bnx2fc_stats->invalid_crc_count += fw_stats->rx_stat1.fc_crc_cnt;
 +      bnx2fc_stats->invalid_crc_count += fw_stats->rx_stat2.fc_crc_cnt;
        bnx2fc_stats->tx_frames += fw_stats->tx_stat.fcoe_tx_pkt_cnt;
        bnx2fc_stats->tx_words += (fw_stats->tx_stat.fcoe_tx_byte_cnt) / 4;
        bnx2fc_stats->rx_frames += fw_stats->rx_stat0.fcoe_rx_pkt_cnt;
@@@ -679,6 -679,9 +679,9 @@@ static void bnx2fc_link_speed_update(st
                case SPEED_1000:
                        lport->link_speed = FC_PORTSPEED_1GBIT;
                        break;
+               case SPEED_2500:
+                       lport->link_speed = FC_PORTSPEED_2GBIT;
+                       break;
                case SPEED_10000:
                        lport->link_speed = FC_PORTSPEED_10GBIT;
                        break;
@@@ -767,23 -770,17 +770,23 @@@ static void bnx2fc_destroy_timer(unsign
   *
   * @context:  adapter structure pointer
   * @event:    event type
 + * @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
   */
 -static void bnx2fc_indicate_netevent(void *context, unsigned long event)
 +static void bnx2fc_indicate_netevent(void *context, unsigned long event,
 +                                   u16 vlan_id)
  {
        struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context;
        struct fc_lport *lport = hba->ctlr.lp;
        struct fc_lport *vport;
        u32 link_possible = 1;
  
 +      /* Ignore vlans for now */
 +      if (vlan_id != 0)
 +              return;
 +
        if (!test_bit(BNX2FC_CREATE_DONE, &hba->init_done)) {
                BNX2FC_MISC_DBG("driver not ready. event=%s %ld\n",
                           hba->netdev->name, event);
@@@ -1231,6 -1228,7 +1234,7 @@@ static int bnx2fc_interface_setup(struc
        hba->ctlr.get_src_addr = bnx2fc_get_src_mac;
        set_bit(BNX2FC_CTLR_INIT_DONE, &hba->init_done);
  
+       INIT_LIST_HEAD(&hba->vports);
        rc = bnx2fc_netdev_setup(hba);
        if (rc)
                goto setup_err;
@@@ -1267,8 -1265,15 +1271,15 @@@ static struct fc_lport *bnx2fc_if_creat
        struct fcoe_port        *port;
        struct Scsi_Host        *shost;
        struct fc_vport         *vport = dev_to_vport(parent);
+       struct bnx2fc_lport     *blport;
        int                     rc = 0;
  
+       blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL);
+       if (!blport) {
+               BNX2FC_HBA_DBG(hba->ctlr.lp, "Unable to alloc bnx2fc_lport\n");
+               return NULL;
+       }
        /* Allocate Scsi_Host structure */
        if (!npiv)
                lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port));
  
        if (!lport) {
                printk(KERN_ERR PFX "could not allocate scsi host structure\n");
-               return NULL;
+               goto free_blport;
        }
        shost = lport->host;
        port = lport_priv(lport);
        }
  
        bnx2fc_interface_get(hba);
+       spin_lock_bh(&hba->hba_lock);
+       blport->lport = lport;
+       list_add_tail(&blport->list, &hba->vports);
+       spin_unlock_bh(&hba->hba_lock);
        return lport;
  
  shost_err:
        scsi_remove_host(shost);
  lp_config_err:
        scsi_host_put(lport->host);
+ free_blport:
+       kfree(blport);
        return NULL;
  }
  
@@@ -1354,6 -1367,7 +1373,7 @@@ static void bnx2fc_if_destroy(struct fc
  {
        struct fcoe_port *port = lport_priv(lport);
        struct bnx2fc_hba *hba = port->priv;
+       struct bnx2fc_lport *blport, *tmp;
  
        BNX2FC_HBA_DBG(hba->ctlr.lp, "ENTERED bnx2fc_if_destroy\n");
        /* Stop the transmit retry timer */
        /* 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);
  
@@@ -100,9 -100,6 +100,9 @@@ int bnx2fc_send_fw_fcoe_init_msg(struc
        fcoe_init2.hdr.flags = (FCOE_KWQE_LAYER_CODE <<
                                        FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
  
 +      fcoe_init2.hsi_major_version = FCOE_HSI_MAJOR_VERSION;
 +      fcoe_init2.hsi_minor_version = FCOE_HSI_MINOR_VERSION;
 +
        fcoe_init2.hash_tbl_pbl_addr_lo = (u32) hba->hash_tbl_pbl_dma;
        fcoe_init2.hash_tbl_pbl_addr_hi = (u32)
                                           ((u64) hba->hash_tbl_pbl_dma >> 32);
        fcoe_init3.error_bit_map_lo = 0xffffffff;
        fcoe_init3.error_bit_map_hi = 0xffffffff;
  
 +      fcoe_init3.perf_config = 1;
  
        kwqe_arr[0] = (struct kwqe *) &fcoe_init1;
        kwqe_arr[1] = (struct kwqe *) &fcoe_init2;
@@@ -293,19 -289,19 +293,19 @@@ int bnx2fc_send_session_ofld_req(struc
        ofld_req4.e_d_tov_timer_val = lport->e_d_tov / 20;
  
  
 -      ofld_req4.src_mac_addr_lo32[0] =  port->data_src_addr[5];
 +      ofld_req4.src_mac_addr_lo[0] =  port->data_src_addr[5];
                                                        /* local mac */
 -      ofld_req4.src_mac_addr_lo32[1] =  port->data_src_addr[4];
 -      ofld_req4.src_mac_addr_lo32[2] =  port->data_src_addr[3];
 -      ofld_req4.src_mac_addr_lo32[3] =  port->data_src_addr[2];
 -      ofld_req4.src_mac_addr_hi16[0] =  port->data_src_addr[1];
 -      ofld_req4.src_mac_addr_hi16[1] =  port->data_src_addr[0];
 -      ofld_req4.dst_mac_addr_lo32[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
 -      ofld_req4.dst_mac_addr_lo32[1] =  hba->ctlr.dest_addr[4];
 -      ofld_req4.dst_mac_addr_lo32[2] =  hba->ctlr.dest_addr[3];
 -      ofld_req4.dst_mac_addr_lo32[3] =  hba->ctlr.dest_addr[2];
 -      ofld_req4.dst_mac_addr_hi16[0] =  hba->ctlr.dest_addr[1];
 -      ofld_req4.dst_mac_addr_hi16[1] =  hba->ctlr.dest_addr[0];
 +      ofld_req4.src_mac_addr_lo[1] =  port->data_src_addr[4];
 +      ofld_req4.src_mac_addr_mid[0] =  port->data_src_addr[3];
 +      ofld_req4.src_mac_addr_mid[1] =  port->data_src_addr[2];
 +      ofld_req4.src_mac_addr_hi[0] =  port->data_src_addr[1];
 +      ofld_req4.src_mac_addr_hi[1] =  port->data_src_addr[0];
 +      ofld_req4.dst_mac_addr_lo[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
 +      ofld_req4.dst_mac_addr_lo[1] =  hba->ctlr.dest_addr[4];
 +      ofld_req4.dst_mac_addr_mid[0] =  hba->ctlr.dest_addr[3];
 +      ofld_req4.dst_mac_addr_mid[1] =  hba->ctlr.dest_addr[2];
 +      ofld_req4.dst_mac_addr_hi[0] =  hba->ctlr.dest_addr[1];
 +      ofld_req4.dst_mac_addr_hi[1] =  hba->ctlr.dest_addr[0];
  
        ofld_req4.lcq_addr_lo = (u32) tgt->lcq_dma;
        ofld_req4.lcq_addr_hi = (u32)((u64) tgt->lcq_dma >> 32);
@@@ -349,21 -345,20 +349,21 @@@ static int bnx2fc_send_session_enable_r
        enbl_req.hdr.flags =
                (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
  
 -      enbl_req.src_mac_addr_lo32[0] =  port->data_src_addr[5];
 +      enbl_req.src_mac_addr_lo[0] =  port->data_src_addr[5];
                                                        /* local mac */
 -      enbl_req.src_mac_addr_lo32[1] =  port->data_src_addr[4];
 -      enbl_req.src_mac_addr_lo32[2] =  port->data_src_addr[3];
 -      enbl_req.src_mac_addr_lo32[3] =  port->data_src_addr[2];
 -      enbl_req.src_mac_addr_hi16[0] =  port->data_src_addr[1];
 -      enbl_req.src_mac_addr_hi16[1] =  port->data_src_addr[0];
 -
 -      enbl_req.dst_mac_addr_lo32[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
 -      enbl_req.dst_mac_addr_lo32[1] =  hba->ctlr.dest_addr[4];
 -      enbl_req.dst_mac_addr_lo32[2] =  hba->ctlr.dest_addr[3];
 -      enbl_req.dst_mac_addr_lo32[3] =  hba->ctlr.dest_addr[2];
 -      enbl_req.dst_mac_addr_hi16[0] =  hba->ctlr.dest_addr[1];
 -      enbl_req.dst_mac_addr_hi16[1] =  hba->ctlr.dest_addr[0];
 +      enbl_req.src_mac_addr_lo[1] =  port->data_src_addr[4];
 +      enbl_req.src_mac_addr_mid[0] =  port->data_src_addr[3];
 +      enbl_req.src_mac_addr_mid[1] =  port->data_src_addr[2];
 +      enbl_req.src_mac_addr_hi[0] =  port->data_src_addr[1];
 +      enbl_req.src_mac_addr_hi[1] =  port->data_src_addr[0];
 +      memcpy(tgt->src_addr, port->data_src_addr, ETH_ALEN);
 +
 +      enbl_req.dst_mac_addr_lo[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
 +      enbl_req.dst_mac_addr_lo[1] =  hba->ctlr.dest_addr[4];
 +      enbl_req.dst_mac_addr_mid[0] =  hba->ctlr.dest_addr[3];
 +      enbl_req.dst_mac_addr_mid[1] =  hba->ctlr.dest_addr[2];
 +      enbl_req.dst_mac_addr_hi[0] =  hba->ctlr.dest_addr[1];
 +      enbl_req.dst_mac_addr_hi[1] =  hba->ctlr.dest_addr[0];
  
        port_id = fc_host_port_id(lport->host);
        if (port_id != tgt->sid) {
@@@ -416,19 -411,18 +416,19 @@@ int bnx2fc_send_session_disable_req(str
        disable_req.hdr.flags =
                (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT);
  
 -      disable_req.src_mac_addr_lo32[0] =  port->data_src_addr[5];
 -      disable_req.src_mac_addr_lo32[2] =  port->data_src_addr[3];
 -      disable_req.src_mac_addr_lo32[3] =  port->data_src_addr[2];
 -      disable_req.src_mac_addr_hi16[0] =  port->data_src_addr[1];
 -      disable_req.src_mac_addr_hi16[1] =  port->data_src_addr[0];
 +      disable_req.src_mac_addr_lo[0] =  tgt->src_addr[5];
 +      disable_req.src_mac_addr_lo[1] =  tgt->src_addr[4];
 +      disable_req.src_mac_addr_mid[0] =  tgt->src_addr[3];
 +      disable_req.src_mac_addr_mid[1] =  tgt->src_addr[2];
 +      disable_req.src_mac_addr_hi[0] =  tgt->src_addr[1];
 +      disable_req.src_mac_addr_hi[1] =  tgt->src_addr[0];
  
 -      disable_req.dst_mac_addr_lo32[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
 -      disable_req.dst_mac_addr_lo32[1] =  hba->ctlr.dest_addr[4];
 -      disable_req.dst_mac_addr_lo32[2] =  hba->ctlr.dest_addr[3];
 -      disable_req.dst_mac_addr_lo32[3] =  hba->ctlr.dest_addr[2];
 -      disable_req.dst_mac_addr_hi16[0] =  hba->ctlr.dest_addr[1];
 -      disable_req.dst_mac_addr_hi16[1] =  hba->ctlr.dest_addr[0];
 +      disable_req.dst_mac_addr_lo[0] =  hba->ctlr.dest_addr[5];/* fcf mac */
 +      disable_req.dst_mac_addr_lo[1] =  hba->ctlr.dest_addr[4];
 +      disable_req.dst_mac_addr_mid[0] =  hba->ctlr.dest_addr[3];
 +      disable_req.dst_mac_addr_mid[1] =  hba->ctlr.dest_addr[2];
 +      disable_req.dst_mac_addr_hi[0] =  hba->ctlr.dest_addr[1];
 +      disable_req.dst_mac_addr_hi[1] =  hba->ctlr.dest_addr[0];
  
        port_id = tgt->sid;
        disable_req.s_id[0] = (port_id & 0x000000FF);
@@@ -486,16 -480,36 +486,36 @@@ int bnx2fc_send_session_destroy_req(str
        return rc;
  }
  
+ static bool is_valid_lport(struct bnx2fc_hba *hba, struct fc_lport *lport)
+ {
+       struct bnx2fc_lport *blport;
+       spin_lock_bh(&hba->hba_lock);
+       list_for_each_entry(blport, &hba->vports, list) {
+               if (blport->lport == lport) {
+                       spin_unlock_bh(&hba->hba_lock);
+                       return true;
+               }
+       }
+       spin_unlock_bh(&hba->hba_lock);
+       return false;
+ }
  static void bnx2fc_unsol_els_work(struct work_struct *work)
  {
        struct bnx2fc_unsol_els *unsol_els;
        struct fc_lport *lport;
+       struct bnx2fc_hba *hba;
        struct fc_frame *fp;
  
        unsol_els = container_of(work, struct bnx2fc_unsol_els, unsol_els_work);
        lport = unsol_els->lport;
        fp = unsol_els->fp;
-       fc_exch_recv(lport, fp);
+       hba = unsol_els->hba;
+       if (is_valid_lport(hba, lport))
+               fc_exch_recv(lport, fp);
        kfree(unsol_els);
  }
  
@@@ -505,6 -519,7 +525,7 @@@ void bnx2fc_process_l2_frame_compl(stru
  {
        struct fcoe_port *port = tgt->port;
        struct fc_lport *lport = port->lport;
+       struct bnx2fc_hba *hba = port->priv;
        struct bnx2fc_unsol_els *unsol_els;
        struct fc_frame_header *fh;
        struct fc_frame *fp;
                fr_eof(fp) = FC_EOF_T;
                fr_crc(fp) = cpu_to_le32(~crc);
                unsol_els->lport = lport;
+               unsol_els->hba = hba;
                unsol_els->fp = fp;
                INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work);
                queue_work(bnx2fc_wq, &unsol_els->unsol_els_work);
@@@ -646,10 -662,10 +668,10 @@@ static void bnx2fc_process_unsol_compl(
                xid = err_entry->fc_hdr.ox_id;
                BNX2FC_TGT_DBG(tgt, "Unsol Error Frame OX_ID = 0x%x\n", xid);
                BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x\n",
 -                      err_entry->err_warn_bitmap_hi,
 -                      err_entry->err_warn_bitmap_lo);
 +                      err_entry->data.err_warn_bitmap_hi,
 +                      err_entry->data.err_warn_bitmap_lo);
                BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n",
 -                      err_entry->tx_buf_off, err_entry->rx_buf_off);
 +                      err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
  
                bnx2fc_return_rqe(tgt, 1);
  
                xid = cpu_to_be16(err_entry->fc_hdr.ox_id);
                BNX2FC_TGT_DBG(tgt, "Unsol Warning Frame OX_ID = 0x%x\n", xid);
                BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x",
 -                      err_entry->err_warn_bitmap_hi,
 -                      err_entry->err_warn_bitmap_lo);
 +                      err_entry->data.err_warn_bitmap_hi,
 +                      err_entry->data.err_warn_bitmap_lo);
                BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x",
 -                      err_entry->tx_buf_off, err_entry->rx_buf_off);
 +                      err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
  
                bnx2fc_return_rqe(tgt, 1);
                spin_unlock_bh(&tgt->tgt_lock);
@@@ -768,9 -784,9 +790,9 @@@ void bnx2fc_process_cq_compl(struct bnx
        task_page = (struct fcoe_task_ctx_entry *)hba->task_ctx[task_idx];
        task = &(task_page[index]);
  
 -      num_rq = ((task->rx_wr_tx_rd.rx_flags &
 -                 FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE) >>
 -                 FCOE_TASK_CTX_ENTRY_RXWR_TXRD_NUM_RQ_WQE_SHIFT);
 +      num_rq = ((task->rxwr_txrd.var_ctx.rx_flags &
 +                 FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE) >>
 +                 FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT);
  
        io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
  
        /* Timestamp IO completion time */
        cmd_type = io_req->cmd_type;
  
 -      /* optimized completion path */
 -      if (cmd_type == BNX2FC_SCSI_CMD) {
 -              rx_state = ((task->rx_wr_tx_rd.rx_flags &
 -                          FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE) >>
 -                          FCOE_TASK_CTX_ENTRY_RXWR_TXRD_RX_STATE_SHIFT);
 +      rx_state = ((task->rxwr_txrd.var_ctx.rx_flags &
 +                  FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE) >>
 +                  FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE_SHIFT);
  
 +      /* Process other IO completion types */
 +      switch (cmd_type) {
 +      case BNX2FC_SCSI_CMD:
                if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) {
                        bnx2fc_process_scsi_cmd_compl(io_req, task, num_rq);
                        spin_unlock_bh(&tgt->tgt_lock);
                        return;
                }
 -      }
  
 -      /* Process other IO completion types */
 -      switch (cmd_type) {
 -      case BNX2FC_SCSI_CMD:
                if (rx_state == FCOE_TASK_RX_STATE_ABTS_COMPLETED)
                        bnx2fc_process_abts_compl(io_req, task, num_rq);
                else if (rx_state ==
                break;
  
        case BNX2FC_ELS:
 -              BNX2FC_IO_DBG(io_req, "cq_compl - call process_els_compl\n");
 -              bnx2fc_process_els_compl(io_req, task, num_rq);
 +              if (rx_state == FCOE_TASK_RX_STATE_COMPLETED)
 +                      bnx2fc_process_els_compl(io_req, task, num_rq);
 +              else if (rx_state == FCOE_TASK_RX_STATE_ABTS_COMPLETED)
 +                      bnx2fc_process_abts_compl(io_req, task, num_rq);
 +              else if (rx_state ==
 +                       FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED)
 +                      bnx2fc_process_cleanup_compl(io_req, task, num_rq);
 +              else
 +                      printk(KERN_ERR PFX "Invalid rx state =  %d\n",
 +                              rx_state);
                break;
  
        case BNX2FC_CLEANUP:
        spin_unlock_bh(&tgt->tgt_lock);
  }
  
 +void bnx2fc_arm_cq(struct bnx2fc_rport *tgt)
 +{
 +      struct b577xx_fcoe_rx_doorbell *rx_db = &tgt->rx_db;
 +      u32 msg;
 +
 +      wmb();
 +      rx_db->doorbell_cq_cons = tgt->cq_cons_idx | (tgt->cq_curr_toggle_bit <<
 +                      FCOE_CQE_TOGGLE_BIT_SHIFT);
 +      msg = *((u32 *)rx_db);
 +      writel(cpu_to_le32(msg), tgt->ctx_base);
 +      mmiowb();
 +
 +}
 +
  struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe)
  {
        struct bnx2fc_work *work;
@@@ -878,8 -875,8 +900,8 @@@ int bnx2fc_process_new_cqes(struct bnx2
        struct fcoe_cqe *cq;
        u32 cq_cons;
        struct fcoe_cqe *cqe;
 +      u32 num_free_sqes = 0;
        u16 wqe;
 -      bool more_cqes_found = false;
  
        /*
         * cq_lock is a low contention lock used to protect
        cq_cons = tgt->cq_cons_idx;
        cqe = &cq[cq_cons];
  
 -      do {
 -              more_cqes_found ^= true;
 -
 -              while (((wqe = cqe->wqe) & FCOE_CQE_TOGGLE_BIT) ==
 -                     (tgt->cq_curr_toggle_bit <<
 -                     FCOE_CQE_TOGGLE_BIT_SHIFT)) {
 +      while (((wqe = cqe->wqe) & FCOE_CQE_TOGGLE_BIT) ==
 +             (tgt->cq_curr_toggle_bit <<
 +             FCOE_CQE_TOGGLE_BIT_SHIFT)) {
  
 -                      /* new entry on the cq */
 -                      if (wqe & FCOE_CQE_CQE_TYPE) {
 -                              /* Unsolicited event notification */
 -                              bnx2fc_process_unsol_compl(tgt, wqe);
 -                      } else {
 -                              struct bnx2fc_work *work = NULL;
 -                              struct bnx2fc_percpu_s *fps = NULL;
 -                              unsigned int cpu = wqe % num_possible_cpus();
 -
 -                              fps = &per_cpu(bnx2fc_percpu, cpu);
 -                              spin_lock_bh(&fps->fp_work_lock);
 -                              if (unlikely(!fps->iothread))
 -                                      goto unlock;
 -
 -                              work = bnx2fc_alloc_work(tgt, wqe);
 -                              if (work)
 -                                      list_add_tail(&work->list,
 -                                                      &fps->work_list);
 +              /* new entry on the cq */
 +              if (wqe & FCOE_CQE_CQE_TYPE) {
 +                      /* Unsolicited event notification */
 +                      bnx2fc_process_unsol_compl(tgt, wqe);
 +              } else {
 +                      /* Pending work request completion */
 +                      struct bnx2fc_work *work = NULL;
 +                      struct bnx2fc_percpu_s *fps = NULL;
 +                      unsigned int cpu = wqe % num_possible_cpus();
 +
 +                      fps = &per_cpu(bnx2fc_percpu, cpu);
 +                      spin_lock_bh(&fps->fp_work_lock);
 +                      if (unlikely(!fps->iothread))
 +                              goto unlock;
 +
 +                      work = bnx2fc_alloc_work(tgt, wqe);
 +                      if (work)
 +                              list_add_tail(&work->list,
 +                                            &fps->work_list);
  unlock:
 -                              spin_unlock_bh(&fps->fp_work_lock);
 +                      spin_unlock_bh(&fps->fp_work_lock);
  
 -                              /* Pending work request completion */
 -                              if (fps->iothread && work)
 -                                      wake_up_process(fps->iothread);
 -                              else
 -                                      bnx2fc_process_cq_compl(tgt, wqe);
 -                      }
 -                      cqe++;
 -                      tgt->cq_cons_idx++;
 -
 -                      if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) {
 -                              tgt->cq_cons_idx = 0;
 -                              cqe = cq;
 -                              tgt->cq_curr_toggle_bit =
 -                                      1 - tgt->cq_curr_toggle_bit;
 -                      }
 +                      /* Pending work request completion */
 +                      if (fps->iothread && work)
 +                              wake_up_process(fps->iothread);
 +                      else
 +                              bnx2fc_process_cq_compl(tgt, wqe);
                }
 -              /* Re-arm CQ */
 -              if (more_cqes_found) {
 -                      tgt->conn_db->cq_arm.lo = -1;
 -                      wmb();
 +              cqe++;
 +              tgt->cq_cons_idx++;
 +              num_free_sqes++;
 +
 +              if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) {
 +                      tgt->cq_cons_idx = 0;
 +                      cqe = cq;
 +                      tgt->cq_curr_toggle_bit =
 +                              1 - tgt->cq_curr_toggle_bit;
                }
 -      } while (more_cqes_found);
 -
 -      /*
 -       * Commit tgt->cq_cons_idx change to the memory
 -       * spin_lock implies full memory barrier, no need to smp_wmb
 -       */
 -
 +      }
 +      bnx2fc_arm_cq(tgt);
 +      atomic_add(num_free_sqes, &tgt->free_sqes);
        spin_unlock_bh(&tgt->cq_lock);
        return 0;
  }
@@@ -1155,11 -1163,7 +1177,11 @@@ static void bnx2fc_init_failure(struct 
        case FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR:
                printk(KERN_ERR PFX "init_failure due to NIC error\n");
                break;
 -
 +      case FCOE_KCQE_COMPLETION_STATUS_ERROR:
 +              printk(KERN_ERR PFX "init failure due to compl status err\n");
 +              break;
 +      case FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION:
 +              printk(KERN_ERR PFX "init failure due to HSI mismatch\n");
        default:
                printk(KERN_ERR PFX "Unknown Error code %d\n", err_code);
        }
@@@ -1265,14 -1269,21 +1287,14 @@@ void bnx2fc_add_2_sq(struct bnx2fc_rpor
  
  void bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt)
  {
 -      struct b577xx_doorbell_set_prod ev_doorbell;
 +      struct b577xx_doorbell_set_prod *sq_db = &tgt->sq_db;
        u32 msg;
  
        wmb();
 -
 -      memset(&ev_doorbell, 0, sizeof(struct b577xx_doorbell_set_prod));
 -      ev_doorbell.header.header = B577XX_DOORBELL_HDR_DB_TYPE;
 -
 -      ev_doorbell.prod = tgt->sq_prod_idx |
 +      sq_db->prod = tgt->sq_prod_idx |
                                (tgt->sq_curr_toggle_bit << 15);
 -      ev_doorbell.header.header |= B577XX_FCOE_CONNECTION_TYPE <<
 -                                      B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT;
 -      msg = *((u32 *)&ev_doorbell);
 +      msg = *((u32 *)sq_db);
        writel(cpu_to_le32(msg), tgt->ctx_base);
 -
        mmiowb();
  
  }
@@@ -1333,26 -1344,18 +1355,26 @@@ void bnx2fc_init_cleanup_task(struct bn
        memset(task, 0, sizeof(struct fcoe_task_ctx_entry));
  
        /* Tx Write Rx Read */
 -      task->tx_wr_rx_rd.tx_flags = FCOE_TASK_TX_STATE_EXCHANGE_CLEANUP <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT;
 -      task->tx_wr_rx_rd.init_flags = task_type <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT;
 -      task->tx_wr_rx_rd.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT;
 -      /* Common */
 -      task->cmn.common_flags = context_id <<
 -                              FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID_SHIFT;
 -      task->cmn.general.cleanup_info.task_id = orig_xid;
 -
 -
 +      /* init flags */
 +      task->txwr_rxrd.const_ctx.init_flags = task_type <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
 +      task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT;
 +      task->txwr_rxrd.const_ctx.init_flags |=
 +                              FCOE_TASK_DEV_TYPE_DISK <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
 +      task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid;
 +
 +      /* Tx flags */
 +      task->txwr_rxrd.const_ctx.tx_flags =
 +                              FCOE_TASK_TX_STATE_EXCHANGE_CLEANUP <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT;
 +
 +      /* Rx Read Tx Write */
 +      task->rxwr_txrd.const_ctx.init_flags = context_id <<
 +                              FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT;
 +      task->rxwr_txrd.var_ctx.rx_flags |= 1 <<
 +                              FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT;
  }
  
  void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req,
        struct bnx2fc_mp_req *mp_req = &(io_req->mp_req);
        struct bnx2fc_rport *tgt = io_req->tgt;
        struct fc_frame_header *fc_hdr;
 +      struct fcoe_ext_mul_sges_ctx *sgl;
        u8 task_type = 0;
        u64 *hdr;
        u64 temp_hdr[3];
        /* Tx only */
        if ((task_type == FCOE_TASK_TYPE_MIDPATH) ||
            (task_type == FCOE_TASK_TYPE_UNSOLICITED)) {
 -              task->tx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.lo =
 +              task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo =
                                (u32)mp_req->mp_req_bd_dma;
 -              task->tx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.hi =
 +              task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi =
                                (u32)((u64)mp_req->mp_req_bd_dma >> 32);
 -              task->tx_wr_only.sgl_ctx.mul_sges.sgl_size = 1;
 -              BNX2FC_IO_DBG(io_req, "init_mp_task - bd_dma = 0x%llx\n",
 -                            (unsigned long long)mp_req->mp_req_bd_dma);
 +              task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = 1;
        }
  
        /* Tx Write Rx Read */
 -      task->tx_wr_rx_rd.tx_flags = FCOE_TASK_TX_STATE_INIT <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT;
 -      task->tx_wr_rx_rd.init_flags = task_type <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT;
 -      task->tx_wr_rx_rd.init_flags |= FCOE_TASK_DEV_TYPE_DISK <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE_SHIFT;
 -      task->tx_wr_rx_rd.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT;
 -
 -      /* Common */
 -      task->cmn.data_2_trns = io_req->data_xfer_len;
 -      context_id = tgt->context_id;
 -      task->cmn.common_flags = context_id <<
 -                              FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID_SHIFT;
 -      task->cmn.common_flags |= 1 <<
 -                              FCOE_TASK_CTX_ENTRY_TX_RX_CMN_VALID_SHIFT;
 -      task->cmn.common_flags |= 1 <<
 -                      FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME_SHIFT;
 +      /* init flags */
 +      task->txwr_rxrd.const_ctx.init_flags = task_type <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
 +      task->txwr_rxrd.const_ctx.init_flags |=
 +                              FCOE_TASK_DEV_TYPE_DISK <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
 +      task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT;
 +
 +      /* tx flags */
 +      task->txwr_rxrd.const_ctx.tx_flags = FCOE_TASK_TX_STATE_INIT <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT;
  
        /* Rx Write Tx Read */
 +      task->rxwr_txrd.const_ctx.data_2_trns = io_req->data_xfer_len;
 +
 +      /* rx flags */
 +      task->rxwr_txrd.var_ctx.rx_flags |= 1 <<
 +                              FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT;
 +
 +      context_id = tgt->context_id;
 +      task->rxwr_txrd.const_ctx.init_flags = context_id <<
 +                              FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT;
 +
        fc_hdr = &(mp_req->req_fc_hdr);
        if (task_type == FCOE_TASK_TYPE_MIDPATH) {
                fc_hdr->fh_ox_id = cpu_to_be16(io_req->xid);
                fc_hdr->fh_rx_id = htons(0xffff);
 -              task->rx_wr_tx_rd.rx_id = 0xffff;
 +              task->rxwr_txrd.var_ctx.rx_id = 0xffff;
        } else if (task_type == FCOE_TASK_TYPE_UNSOLICITED) {
                fc_hdr->fh_rx_id = cpu_to_be16(io_req->xid);
        }
  
        /* Fill FC Header into middle path buffer */
 -      hdr = (u64 *) &task->cmn.general.cmd_info.mp_fc_frame.fc_hdr;
 +      hdr = (u64 *) &task->txwr_rxrd.union_ctx.tx_frame.fc_hdr;
        memcpy(temp_hdr, fc_hdr, sizeof(temp_hdr));
        hdr[0] = cpu_to_be64(temp_hdr[0]);
        hdr[1] = cpu_to_be64(temp_hdr[1]);
  
        /* Rx Only */
        if (task_type == FCOE_TASK_TYPE_MIDPATH) {
 +              sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl;
  
 -              task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.lo =
 -                              (u32)mp_req->mp_resp_bd_dma;
 -              task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.hi =
 +              sgl->mul_sgl.cur_sge_addr.lo = (u32)mp_req->mp_resp_bd_dma;
 +              sgl->mul_sgl.cur_sge_addr.hi =
                                (u32)((u64)mp_req->mp_resp_bd_dma >> 32);
 -              task->rx_wr_only.sgl_ctx.mul_sges.sgl_size = 1;
 +              sgl->mul_sgl.sgl_size = 1;
        }
  }
  
@@@ -1453,8 -1453,6 +1475,8 @@@ void bnx2fc_init_task(struct bnx2fc_cm
        struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
        struct io_bdt *bd_tbl = io_req->bd_tbl;
        struct bnx2fc_rport *tgt = io_req->tgt;
 +      struct fcoe_cached_sge_ctx *cached_sge;
 +      struct fcoe_ext_mul_sges_ctx *sgl;
        u64 *fcp_cmnd;
        u64 tmp_fcp_cmnd[4];
        u32 context_id;
  
        /* Tx only */
        if (task_type == FCOE_TASK_TYPE_WRITE) {
 -              task->tx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.lo =
 +              task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo =
                                (u32)bd_tbl->bd_tbl_dma;
 -              task->tx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.hi =
 +              task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi =
                                (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
 -              task->tx_wr_only.sgl_ctx.mul_sges.sgl_size =
 +              task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size =
                                bd_tbl->bd_valid;
        }
  
        /*Tx Write Rx Read */
        /* Init state to NORMAL */
 -      task->tx_wr_rx_rd.tx_flags = FCOE_TASK_TX_STATE_NORMAL <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TX_STATE_SHIFT;
 -      task->tx_wr_rx_rd.init_flags = task_type <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_TASK_TYPE_SHIFT;
 -      task->tx_wr_rx_rd.init_flags |= FCOE_TASK_DEV_TYPE_DISK <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_DEV_TYPE_SHIFT;
 -      task->tx_wr_rx_rd.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_CLASS_TYPE_SHIFT;
 -
 -      /* Common */
 -      task->cmn.data_2_trns = io_req->data_xfer_len;
 -      context_id = tgt->context_id;
 -      task->cmn.common_flags = context_id <<
 -                              FCOE_TASK_CTX_ENTRY_TX_RX_CMN_CID_SHIFT;
 -      task->cmn.common_flags |= 1 <<
 -                              FCOE_TASK_CTX_ENTRY_TX_RX_CMN_VALID_SHIFT;
 -      task->cmn.common_flags |= 1 <<
 -                      FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME_SHIFT;
 -
 -      /* Set initiative ownership */
 -      task->cmn.common_flags |= FCOE_TASK_CTX_ENTRY_TX_RX_CMN_SEQ_INIT;
 +      task->txwr_rxrd.const_ctx.init_flags = task_type <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT;
 +      task->txwr_rxrd.const_ctx.init_flags |=
 +                              FCOE_TASK_DEV_TYPE_DISK <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT;
 +      task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT;
 +      /* tx flags */
 +      task->txwr_rxrd.const_ctx.tx_flags = FCOE_TASK_TX_STATE_NORMAL <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT;
  
        /* Set initial seq counter */
 -      task->cmn.tx_low_seq_cnt = 1;
 -
 -      /* Set state to "waiting for the first packet" */
 -      task->cmn.common_flags |= FCOE_TASK_CTX_ENTRY_TX_RX_CMN_EXP_FIRST_FRAME;
 +      task->txwr_rxrd.union_ctx.tx_seq.ctx.seq_cnt = 1;
  
        /* Fill FCP_CMND IU */
        fcp_cmnd = (u64 *)
 -                  task->cmn.general.cmd_info.fcp_cmd_payload.opaque;
 +                  task->txwr_rxrd.union_ctx.fcp_cmd.opaque;
        bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)&tmp_fcp_cmnd);
  
        /* swap fcp_cmnd */
        }
  
        /* Rx Write Tx Read */
 -      task->rx_wr_tx_rd.rx_id = 0xffff;
 +      task->rxwr_txrd.const_ctx.data_2_trns = io_req->data_xfer_len;
 +
 +      context_id = tgt->context_id;
 +      task->rxwr_txrd.const_ctx.init_flags = context_id <<
 +                              FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT;
 +
 +      /* rx flags */
 +      /* Set state to "waiting for the first packet" */
 +      task->rxwr_txrd.var_ctx.rx_flags |= 1 <<
 +                              FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT;
 +
 +      task->rxwr_txrd.var_ctx.rx_id = 0xffff;
  
        /* Rx Only */
 +      cached_sge = &task->rxwr_only.union_ctx.read_info.sgl_ctx.cached_sge;
 +      sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl;
 +      bd_count = bd_tbl->bd_valid;
        if (task_type == FCOE_TASK_TYPE_READ) {
 -
 -              bd_count = bd_tbl->bd_valid;
                if (bd_count == 1) {
  
                        struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl;
  
 -                      task->rx_wr_only.sgl_ctx.single_sge.cur_buf_addr.lo =
 -                                      fcoe_bd_tbl->buf_addr_lo;
 -                      task->rx_wr_only.sgl_ctx.single_sge.cur_buf_addr.hi =
 -                                      fcoe_bd_tbl->buf_addr_hi;
 -                      task->rx_wr_only.sgl_ctx.single_sge.cur_buf_rem =
 -                                      fcoe_bd_tbl->buf_len;
 -                      task->tx_wr_rx_rd.init_flags |= 1 <<
 -                              FCOE_TASK_CTX_ENTRY_TXWR_RXRD_SINGLE_SGE_SHIFT;
 +                      cached_sge->cur_buf_addr.lo = fcoe_bd_tbl->buf_addr_lo;
 +                      cached_sge->cur_buf_addr.hi = fcoe_bd_tbl->buf_addr_hi;
 +                      cached_sge->cur_buf_rem = fcoe_bd_tbl->buf_len;
 +                      task->txwr_rxrd.const_ctx.init_flags |= 1 <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT;
 +              } else if (bd_count == 2) {
 +                      struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl;
 +
 +                      cached_sge->cur_buf_addr.lo = fcoe_bd_tbl->buf_addr_lo;
 +                      cached_sge->cur_buf_addr.hi = fcoe_bd_tbl->buf_addr_hi;
 +                      cached_sge->cur_buf_rem = fcoe_bd_tbl->buf_len;
 +
 +                      fcoe_bd_tbl++;
 +                      cached_sge->second_buf_addr.lo =
 +                                               fcoe_bd_tbl->buf_addr_lo;
 +                      cached_sge->second_buf_addr.hi =
 +                                              fcoe_bd_tbl->buf_addr_hi;
 +                      cached_sge->second_buf_rem = fcoe_bd_tbl->buf_len;
 +                      task->txwr_rxrd.const_ctx.init_flags |= 1 <<
 +                              FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT;
                } else {
  
 -                      task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.lo =
 -                                      (u32)bd_tbl->bd_tbl_dma;
 -                      task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_addr.hi =
 +                      sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma;
 +                      sgl->mul_sgl.cur_sge_addr.hi =
                                        (u32)((u64)bd_tbl->bd_tbl_dma >> 32);
 -                      task->rx_wr_only.sgl_ctx.mul_sges.sgl_size =
 -                                      bd_tbl->bd_valid;
 +                      sgl->mul_sgl.sgl_size = bd_count;
                }
        }
  }
@@@ -425,7 -425,6 +425,7 @@@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(s
        struct list_head *listp;
        struct io_bdt *bd_tbl;
        int index = RESERVE_FREE_LIST_INDEX;
 +      u32 free_sqes;
        u32 max_sqes;
        u16 xid;
  
         * cmgr lock
         */
        spin_lock_bh(&cmd_mgr->free_list_lock[index]);
 +      free_sqes = atomic_read(&tgt->free_sqes);
        if ((list_empty(&(cmd_mgr->free_list[index]))) ||
 -          (tgt->num_active_ios.counter  >= max_sqes)) {
 +          (tgt->num_active_ios.counter  >= max_sqes) ||
 +          (free_sqes + max_sqes <= BNX2FC_SQ_WQES_MAX)) {
                BNX2FC_TGT_DBG(tgt, "No free els_tm cmds available "
                        "ios(%d):sqes(%d)\n",
                        tgt->num_active_ios.counter, tgt->max_sqes);
        xid = io_req->xid;
        cmd_mgr->cmds[xid] = io_req;
        atomic_inc(&tgt->num_active_ios);
 +      atomic_dec(&tgt->free_sqes);
        spin_unlock_bh(&cmd_mgr->free_list_lock[index]);
  
        INIT_LIST_HEAD(&io_req->link);
@@@ -493,7 -489,6 +493,7 @@@ static struct bnx2fc_cmd *bnx2fc_cmd_al
        struct bnx2fc_cmd *io_req;
        struct list_head *listp;
        struct io_bdt *bd_tbl;
 +      u32 free_sqes;
        u32 max_sqes;
        u16 xid;
        int index = get_cpu();
         * cmgr lock
         */
        spin_lock_bh(&cmd_mgr->free_list_lock[index]);
 +      free_sqes = atomic_read(&tgt->free_sqes);
        if ((list_empty(&cmd_mgr->free_list[index])) ||
 -          (tgt->num_active_ios.counter  >= max_sqes)) {
 +          (tgt->num_active_ios.counter  >= max_sqes) ||
 +          (free_sqes + max_sqes <= BNX2FC_SQ_WQES_MAX)) {
                spin_unlock_bh(&cmd_mgr->free_list_lock[index]);
                put_cpu();
                return NULL;
        xid = io_req->xid;
        cmd_mgr->cmds[xid] = io_req;
        atomic_inc(&tgt->num_active_ios);
 +      atomic_dec(&tgt->free_sqes);
        spin_unlock_bh(&cmd_mgr->free_list_lock[index]);
        put_cpu();
  
@@@ -881,7 -873,7 +881,7 @@@ int bnx2fc_initiate_abts(struct bnx2fc_
  
        /* Obtain oxid and rxid for the original exchange to be aborted */
        fc_hdr->fh_ox_id = htons(io_req->xid);
 -      fc_hdr->fh_rx_id = htons(io_req->task->rx_wr_tx_rd.rx_id);
 +      fc_hdr->fh_rx_id = htons(io_req->task->rxwr_txrd.var_ctx.rx_id);
  
        sid = tgt->sid;
        did = rport->port_id;
@@@ -1197,7 -1189,7 +1197,7 @@@ void bnx2fc_process_abts_compl(struct b
                        kref_put(&io_req->refcount,
                                 bnx2fc_cmd_release); /* drop timer hold */
  
 -      r_ctl = task->cmn.general.rsp_info.abts_rsp.r_ctl;
 +      r_ctl = (u8)task->rxwr_only.union_ctx.comp_info.abts_rsp.r_ctl;
  
        switch (r_ctl) {
        case FC_RCTL_BA_ACC:
@@@ -1352,13 -1344,12 +1352,13 @@@ void bnx2fc_process_tm_compl(struct bnx
        fc_hdr = &(tm_req->resp_fc_hdr);
        hdr = (u64 *)fc_hdr;
        temp_hdr = (u64 *)
 -              &task->cmn.general.cmd_info.mp_fc_frame.fc_hdr;
 +              &task->rxwr_only.union_ctx.comp_info.mp_rsp.fc_hdr;
        hdr[0] = cpu_to_be64(temp_hdr[0]);
        hdr[1] = cpu_to_be64(temp_hdr[1]);
        hdr[2] = cpu_to_be64(temp_hdr[2]);
  
 -      tm_req->resp_len = task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_off;
 +      tm_req->resp_len =
 +              task->rxwr_only.union_ctx.comp_info.mp_rsp.mp_payload_len;
  
        rsp_buf = tm_req->resp_buf;
  
@@@ -1733,7 -1724,7 +1733,7 @@@ void bnx2fc_process_scsi_cmd_compl(stru
  
        /* Fetch fcp_rsp from task context and perform cmd completion */
        fcp_rsp = (struct fcoe_fcp_rsp_payload *)
 -                 &(task->cmn.general.rsp_info.fcp_rsp.payload);
 +                 &(task->rxwr_only.union_ctx.comp_info.fcp_rsp.payload);
  
        /* parse fcp_rsp and obtain sense data from RQ if available */
        bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq);
                printk(KERN_ERR PFX "SCp.ptr is NULL\n");
                return;
        }
-       io_req->sc_cmd = NULL;
  
        if (io_req->on_active_queue) {
                list_del_init(&io_req->link);
        }
  
        bnx2fc_unmap_sg_list(io_req);
+       io_req->sc_cmd = NULL;
  
        switch (io_req->fcp_status) {
        case FC_GOOD:
@@@ -1,6 -1,6 +1,6 @@@
  /* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI
   *
-  * Copyright (c) 2006 - 2010 Broadcom Corporation
+  * Copyright (c) 2006 - 2011 Broadcom Corporation
   *
   * 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
  
  /* SQ/RQ/CQ DB structure sizes */
  #define ISCSI_SQ_DB_SIZE    (16)
 -#define ISCSI_RQ_DB_SIZE    (16)
 +#define ISCSI_RQ_DB_SIZE    (64)
  #define ISCSI_CQ_DB_SIZE    (80)
  
  #define ISCSI_SQN_TO_NOTIFY_NOT_VALID                                   0xFFFF
@@@ -1,6 -1,6 +1,6 @@@
  /* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI.
   *
-  * Copyright (c) 2006 - 2010 Broadcom Corporation
+  * Copyright (c) 2006 - 2011 Broadcom Corporation
   *
   * 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
@@@ -707,10 -707,8 +707,10 @@@ struct iscsi_kwqe_conn_update 
  #define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2
  #define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3)
  #define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3
 -#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4)
 -#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4
 +#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE (0x3<<4)
 +#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE_SHIFT 4
 +#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0x3<<6)
 +#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 6
  #elif defined(__LITTLE_ENDIAN)
        u8 conn_flags;
  #define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0)
  #define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2
  #define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3)
  #define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3
 -#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0xF<<4)
 -#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 4
 +#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE (0x3<<4)
 +#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE_SHIFT 4
 +#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0x3<<6)
 +#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 6
        u8 reserved2;
        u8 max_outstanding_r2ts;
        u8 session_error_recovery_level;
@@@ -1,6 -1,6 +1,6 @@@
  /* bnx2i.h: Broadcom NetXtreme II iSCSI driver.
   *
-  * Copyright (c) 2006 - 2010 Broadcom Corporation
+  * Copyright (c) 2006 - 2011 Broadcom Corporation
   * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
   * Copyright (c) 2007, 2008 Mike Christie
   *
  #include <linux/pci.h>
  #include <linux/spinlock.h>
  #include <linux/interrupt.h>
+ #include <linux/delay.h>
  #include <linux/sched.h>
  #include <linux/in.h>
  #include <linux/kfifo.h>
  #include <linux/netdevice.h>
  #include <linux/completion.h>
+ #include <linux/kthread.h>
+ #include <linux/cpu.h>
  
  #include <scsi/scsi_cmnd.h>
  #include <scsi/scsi_device.h>
@@@ -202,10 -205,13 +205,13 @@@ struct io_bdt 
  /**
   * bnx2i_cmd - iscsi command structure
   *
+  * @hdr:                iSCSI header
+  * @conn:               iscsi_conn pointer
   * @scsi_cmd:           SCSI-ML task pointer corresponding to this iscsi cmd
   * @sg:                 SG list
   * @io_tbl:             buffer descriptor (BD) table
   * @bd_tbl_dma:         buffer descriptor (BD) table's dma address
+  * @req:                bnx2i specific command request struct
   */
  struct bnx2i_cmd {
        struct iscsi_hdr hdr;
   * @gen_pdu:               login/nopout/logout pdu resources
   * @violation_notified:    bit mask used to track iscsi error/warning messages
   *                         already printed out
+  * @work_cnt:              keeps track of the number of outstanding work
   *
   * iSCSI connection structure
   */
@@@ -252,6 -259,8 +259,8 @@@ struct bnx2i_conn 
         */
        struct generic_pdu_resc gen_pdu;
        u64 violation_notified;
+       atomic_t work_cnt;
  };
  
  
@@@ -478,7 -487,7 +487,7 @@@ struct bnx2i_5771x_cq_db 
  
  struct bnx2i_5771x_sq_rq_db {
        u16 prod_idx;
 -      u8 reserved0[14]; /* Pad structure size to 16 bytes */
 +      u8 reserved0[62]; /* Pad structure size to 64 bytes */
  };
  
  
@@@ -661,7 -670,6 +670,6 @@@ enum 
   * @hba:                adapter to which this connection belongs
   * @conn:               iscsi connection this EP is linked to
   * @cls_ep:             associated iSCSI endpoint pointer
-  * @sess:               iscsi session this EP is linked to
   * @cm_sk:              cnic sock struct
   * @hba_age:            age to detect if 'iscsid' issues ep_disconnect()
   *                      after HBA reset is completed by bnx2i/cnic/bnx2
@@@ -687,7 -695,7 +695,7 @@@ struct bnx2i_endpoint 
        u32 hba_age;
        u32 state;
        unsigned long timestamp;
-       int num_active_cmds;
+       atomic_t num_active_cmds;
        u32 ec_shift;
  
        struct qp_info qp;
  };
  
  
+ struct bnx2i_work {
+       struct list_head list;
+       struct iscsi_session *session;
+       struct bnx2i_conn *bnx2i_conn;
+       struct cqe cqe;
+ };
+ struct bnx2i_percpu_s {
+       struct task_struct *iothread;
+       struct list_head work_list;
+       spinlock_t p_work_lock;
+ };
  
  /* Global variables */
  extern unsigned int error_mask1, error_mask2;
@@@ -783,7 -804,7 +804,7 @@@ extern struct bnx2i_endpoint *bnx2i_fin
                struct bnx2i_hba *hba, u32 iscsi_cid);
  
  extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep);
- extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);
+ extern int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action);
  
  extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep);
  
@@@ -793,4 -814,8 +814,8 @@@ extern void bnx2i_print_active_cmd_queu
  extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn);
  extern void bnx2i_print_recv_state(struct bnx2i_conn *conn);
  
+ extern int bnx2i_percpu_io_thread(void *arg);
+ extern int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
+                                      struct bnx2i_conn *bnx2i_conn,
+                                      struct cqe *cqe);
  #endif
@@@ -1,6 -1,6 +1,6 @@@
  /* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver.
   *
-  * Copyright (c) 2006 - 2010 Broadcom Corporation
+  * Copyright (c) 2006 - 2011 Broadcom Corporation
   * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
   * Copyright (c) 2007, 2008 Mike Christie
   *
@@@ -17,6 -17,8 +17,8 @@@
  #include <scsi/libiscsi.h>
  #include "bnx2i.h"
  
+ DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
  /**
   * bnx2i_get_cid_num - get cid from ep
   * @ep:       endpoint pointer
@@@ -131,16 -133,16 +133,16 @@@ static void bnx2i_iscsi_license_error(s
   *    the driver. EQ event is generated CQ index is hit or at least 1 CQ is
   *    outstanding and on chip timer expires
   */
- void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
+ int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action)
  {
        struct bnx2i_5771x_cq_db *cq_db;
        u16 cq_index;
-       u16 next_index;
+       u16 next_index = 0;
        u32 num_active_cmds;
  
        /* Coalesce CQ entries only on 10G devices */
        if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type))
-               return;
+               return 0;
  
        /* Do not update CQ DB multiple times before firmware writes
         * '0xFFFF' to CQDB->SQN field. Deviation may cause spurious
  
        if (action != CNIC_ARM_CQE_FP)
                if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF)
-                       return;
+                       return 0;
  
        if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) {
-               num_active_cmds = ep->num_active_cmds;
+               num_active_cmds = atomic_read(&ep->num_active_cmds);
                if (num_active_cmds <= event_coal_min)
                        next_index = 1;
-               else
-                       next_index = event_coal_min +
-                                    ((num_active_cmds - event_coal_min) >>
-                                    ep->ec_shift);
+               else {
+                       next_index = num_active_cmds >> ep->ec_shift;
+                       if (next_index > num_active_cmds - event_coal_min)
+                               next_index = num_active_cmds - event_coal_min;
+               }
                if (!next_index)
                        next_index = 1;
                cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1;
  
                cq_db->sqn[0] = cq_index;
        }
+       return next_index;
  }
  
  
@@@ -265,7 -269,7 +269,7 @@@ static void bnx2i_ring_sq_dbell(struct 
        struct bnx2i_5771x_sq_rq_db *sq_db;
        struct bnx2i_endpoint *ep = bnx2i_conn->ep;
  
-       ep->num_active_cmds++;
+       atomic_inc(&ep->num_active_cmds);
        wmb();  /* flush SQ WQE memory before the doorbell is rung */
        if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
                sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt;
@@@ -430,7 -434,7 +434,7 @@@ int bnx2i_send_iscsi_tmf(struct bnx2i_c
        default:
                tmfabort_wqe->ref_itt = RESERVED_ITT;
        }
-       memcpy(scsi_lun, tmfabort_hdr->lun, sizeof(struct scsi_lun));
+       memcpy(scsi_lun, &tmfabort_hdr->lun, sizeof(struct scsi_lun));
        tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]);
        tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]);
  
@@@ -547,7 -551,7 +551,7 @@@ int bnx2i_send_iscsi_nopout(struct bnx2
  
        nopout_wqe->op_code = nopout_hdr->opcode;
        nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL;
-       memcpy(nopout_wqe->lun, nopout_hdr->lun, 8);
+       memcpy(nopout_wqe->lun, &nopout_hdr->lun, 8);
  
        if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
                u32 tmp = nopout_wqe->lun[0];
@@@ -1331,14 -1335,15 +1335,15 @@@ int bnx2i_send_fw_iscsi_init_msg(struc
  
  /**
   * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion.
-  * @conn:     iscsi connection
+  * @session:  iscsi session
+  * @bnx2i_conn:       bnx2i connection
   * @cqe:      pointer to newly DMA'ed CQE entry for processing
   *
   * process SCSI CMD Response CQE & complete the request to SCSI-ML
   */
- static int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
-                                      struct bnx2i_conn *bnx2i_conn,
-                                      struct cqe *cqe)
+ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session,
+                               struct bnx2i_conn *bnx2i_conn,
+                               struct cqe *cqe)
  {
        struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
        struct bnx2i_cmd_response *resp_cqe;
        u32 datalen = 0;
  
        resp_cqe = (struct bnx2i_cmd_response *)cqe;
-       spin_lock(&session->lock);
+       spin_lock_bh(&session->lock);
        task = iscsi_itt_to_task(conn,
                                 resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
        if (!task)
@@@ -1409,7 -1414,7 +1414,7 @@@ done
        __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
                             conn->data, datalen);
  fail:
-       spin_unlock(&session->lock);
+       spin_unlock_bh(&session->lock);
        return 0;
  }
  
@@@ -1711,7 -1716,7 +1716,7 @@@ static int bnx2i_process_nopin_mesg(str
                hdr->flags = ISCSI_FLAG_CMD_FINAL;
                hdr->itt = task->hdr->itt;
                hdr->ttt = cpu_to_be32(nop_in->ttt);
-               memcpy(hdr->lun, nop_in->lun, 8);
+               memcpy(&hdr->lun, nop_in->lun, 8);
        }
  done:
        __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
@@@ -1754,7 -1759,7 +1759,7 @@@ static void bnx2i_process_async_mesg(st
        resp_hdr->opcode = async_cqe->op_code;
        resp_hdr->flags = 0x80;
  
-       memcpy(resp_hdr->lun, async_cqe->lun, 8);
+       memcpy(&resp_hdr->lun, async_cqe->lun, 8);
        resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn);
        resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn);
  
@@@ -1836,21 -1841,136 +1841,136 @@@ static void bnx2i_process_cmd_cleanup_r
  }
  
  
+ /**
+  * bnx2i_percpu_io_thread - thread per cpu for ios
+  *
+  * @arg:      ptr to bnx2i_percpu_info structure
+  */
+ int bnx2i_percpu_io_thread(void *arg)
+ {
+       struct bnx2i_percpu_s *p = arg;
+       struct bnx2i_work *work, *tmp;
+       LIST_HEAD(work_list);
+       set_user_nice(current, -20);
+       while (!kthread_should_stop()) {
+               spin_lock_bh(&p->p_work_lock);
+               while (!list_empty(&p->work_list)) {
+                       list_splice_init(&p->work_list, &work_list);
+                       spin_unlock_bh(&p->p_work_lock);
+                       list_for_each_entry_safe(work, tmp, &work_list, list) {
+                               list_del_init(&work->list);
+                               /* work allocated in the bh, freed here */
+                               bnx2i_process_scsi_cmd_resp(work->session,
+                                                           work->bnx2i_conn,
+                                                           &work->cqe);
+                               atomic_dec(&work->bnx2i_conn->work_cnt);
+                               kfree(work);
+                       }
+                       spin_lock_bh(&p->p_work_lock);
+               }
+               set_current_state(TASK_INTERRUPTIBLE);
+               spin_unlock_bh(&p->p_work_lock);
+               schedule();
+       }
+       __set_current_state(TASK_RUNNING);
+       return 0;
+ }
+ /**
+  * bnx2i_queue_scsi_cmd_resp - queue cmd completion to the percpu thread
+  * @bnx2i_conn:               bnx2i connection
+  *
+  * this function is called by generic KCQ handler to queue all pending cmd
+  * completion CQEs
+  *
+  * The implementation is to queue the cmd response based on the
+  * last recorded command for the given connection.  The
+  * cpu_id gets recorded upon task_xmit.  No out-of-order completion!
+  */
+ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session,
+                                    struct bnx2i_conn *bnx2i_conn,
+                                    struct bnx2i_nop_in_msg *cqe)
+ {
+       struct bnx2i_work *bnx2i_work = NULL;
+       struct bnx2i_percpu_s *p = NULL;
+       struct iscsi_task *task;
+       struct scsi_cmnd *sc;
+       int rc = 0;
+       int cpu;
+       spin_lock(&session->lock);
+       task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data,
+                                cqe->itt & ISCSI_CMD_RESPONSE_INDEX);
+       if (!task) {
+               spin_unlock(&session->lock);
+               return -EINVAL;
+       }
+       sc = task->sc;
+       spin_unlock(&session->lock);
+       if (!blk_rq_cpu_valid(sc->request))
+               cpu = smp_processor_id();
+       else
+               cpu = sc->request->cpu;
+       p = &per_cpu(bnx2i_percpu, cpu);
+       spin_lock(&p->p_work_lock);
+       if (unlikely(!p->iothread)) {
+               rc = -EINVAL;
+               goto err;
+       }
+       /* Alloc and copy to the cqe */
+       bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC);
+       if (bnx2i_work) {
+               INIT_LIST_HEAD(&bnx2i_work->list);
+               bnx2i_work->session = session;
+               bnx2i_work->bnx2i_conn = bnx2i_conn;
+               memcpy(&bnx2i_work->cqe, cqe, sizeof(struct cqe));
+               list_add_tail(&bnx2i_work->list, &p->work_list);
+               atomic_inc(&bnx2i_conn->work_cnt);
+               wake_up_process(p->iothread);
+               spin_unlock(&p->p_work_lock);
+               goto done;
+       } else
+               rc = -ENOMEM;
+ err:
+       spin_unlock(&p->p_work_lock);
+       bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, (struct cqe *)cqe);
+ done:
+       return rc;
+ }
  
  /**
   * bnx2i_process_new_cqes - process newly DMA'ed CQE's
-  * @bnx2i_conn:               iscsi connection
+  * @bnx2i_conn:               bnx2i connection
   *
   * this function is called by generic KCQ handler to process all pending CQE's
   */
- static void bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
+ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
  {
        struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
-       struct qp_info *qp = &bnx2i_conn->ep->qp;
+       struct qp_info *qp;
        struct bnx2i_nop_in_msg *nopin;
        int tgt_async_msg;
+       int cqe_cnt = 0;
  
+       if (bnx2i_conn->ep == NULL)
+               return 0;
+       qp = &bnx2i_conn->ep->qp;
+       if (!qp->cq_virt) {
+               printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!",
+                       bnx2i_conn->hba->netdev->name);
+               goto out;
+       }
        while (1) {
                nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe;
                if (nopin->cq_req_sn != qp->cqe_exp_seq_sn)
                switch (nopin->op_code) {
                case ISCSI_OP_SCSI_CMD_RSP:
                case ISCSI_OP_SCSI_DATA_IN:
-                       bnx2i_process_scsi_cmd_resp(session, bnx2i_conn,
-                                                   qp->cq_cons_qe);
+                       /* Run the kthread engine only for data cmds
+                          All other cmds will be completed in this bh! */
+                       bnx2i_queue_scsi_cmd_resp(session, bnx2i_conn, nopin);
                        break;
                case ISCSI_OP_LOGIN_RSP:
                        bnx2i_process_login_resp(session, bnx2i_conn,
                        printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n",
                                          nopin->op_code);
                }
-               if (!tgt_async_msg)
-                       bnx2i_conn->ep->num_active_cmds--;
+               if (!tgt_async_msg) {
+                       if (!atomic_read(&bnx2i_conn->ep->num_active_cmds))
+                               printk(KERN_ALERT "bnx2i (%s): no active cmd! "
+                                      "op 0x%x\n",
+                                      bnx2i_conn->hba->netdev->name,
+                                      nopin->op_code);
+                       else
+                               atomic_dec(&bnx2i_conn->ep->num_active_cmds);
+               }
  cqe_out:
                /* clear out in production version only, till beta keep opcode
                 * field intact, will be helpful in debugging (context dump)
                 * nopin->op_code = 0;
                 */
+               cqe_cnt++;
                qp->cqe_exp_seq_sn++;
                if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1))
                        qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN;
                        qp->cq_cons_idx++;
                }
        }
+ out:
+       return cqe_cnt;
  }
  
  /**
@@@ -1952,6 -2083,7 +2083,7 @@@ static void bnx2i_fastpath_notification
  {
        struct bnx2i_conn *bnx2i_conn;
        u32 iscsi_cid;
+       int nxt_idx;
  
        iscsi_cid = new_cqe_kcqe->iscsi_conn_id;
        bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid);
                printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid);
                return;
        }
        bnx2i_process_new_cqes(bnx2i_conn);
-       bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP);
-       bnx2i_process_new_cqes(bnx2i_conn);
+       nxt_idx = bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep,
+                                               CNIC_ARM_CQE_FP);
+       if (nxt_idx && nxt_idx == bnx2i_process_new_cqes(bnx2i_conn))
+               bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP);
  }
  
  
@@@ -2312,7 -2447,7 +2447,7 @@@ static void bnx2i_process_ofld_cmpl(str
                        printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid "
                                "opcode\n", hba->netdev->name);
                else if (ofld_kcqe->completion_status ==
-                       ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY)
+                        ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY)
                        /* error status code valid only for 5771x chipset */
                        ep->state = EP_STATE_OFLD_FAILED_CID_BUSY;
                else
@@@ -2386,20 -2521,14 +2521,20 @@@ static void bnx2i_indicate_kcqe(void *c
   * bnx2i_indicate_netevent - Generic netdev event handler
   * @context:  adapter structure pointer
   * @event:    event type
 + * @vlan_id:  vlans id - associated vlan id with this event
   *
   * Handles four netdev events, NETDEV_UP, NETDEV_DOWN,
   *    NETDEV_GOING_DOWN and NETDEV_CHANGE
   */
 -static void bnx2i_indicate_netevent(void *context, unsigned long event)
 +static void bnx2i_indicate_netevent(void *context, unsigned long event,
 +                                  u16 vlan_id)
  {
        struct bnx2i_hba *hba = context;
  
 +      /* Ignore all netevent coming from vlans */
 +      if (vlan_id != 0)
 +              return;
 +
        switch (event) {
        case NETDEV_UP:
                if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state))
@@@ -2517,7 -2646,7 +2652,7 @@@ static void bnx2i_cm_remote_abort(struc
  
  
  static int bnx2i_send_nl_mesg(void *context, u32 msg_type,
-                              char *buf, u16 buflen)
+                             char *buf, u16 buflen)
  {
        struct bnx2i_hba *hba = context;
        int rc;
@@@ -1,6 -1,6 +1,6 @@@
  /* bnx2i.c: Broadcom NetXtreme II iSCSI driver.
   *
-  * Copyright (c) 2006 - 2010 Broadcom Corporation
+  * Copyright (c) 2006 - 2011 Broadcom Corporation
   * Copyright (c) 2007, 2008 Red Hat, Inc.  All rights reserved.
   * Copyright (c) 2007, 2008 Mike Christie
   *
@@@ -18,8 -18,8 +18,8 @@@ static struct list_head adapter_list = 
  static u32 adapter_count;
  
  #define DRV_MODULE_NAME               "bnx2i"
- #define DRV_MODULE_VERSION    "2.6.2.3"
- #define DRV_MODULE_RELDATE    "Dec 31, 2010"
+ #define DRV_MODULE_VERSION    "2.7.0.3"
+ #define DRV_MODULE_RELDATE    "Jun 15, 2011"
  
  static char version[] __devinitdata =
                "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \
@@@ -30,7 -30,7 +30,7 @@@ MODULE_AUTHOR("Anil Veerabhadrappa <ani
              "Eddie Wai <eddie.wai@broadcom.com>");
  
  MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711/57712"
 -                 " iSCSI Driver");
 +                 "/57800/57810/57840 iSCSI Driver");
  MODULE_LICENSE("GPL");
  MODULE_VERSION(DRV_MODULE_VERSION);
  
@@@ -40,7 -40,7 +40,7 @@@ unsigned int event_coal_min = 24
  module_param(event_coal_min, int, 0664);
  MODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands");
  
- unsigned int event_coal_div = 1;
+ unsigned int event_coal_div = 2;
  module_param(event_coal_div, int, 0664);
  MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor");
  
@@@ -66,6 -66,15 +66,15 @@@ MODULE_PARM_DESC(rq_size, "Configure R
  
  u64 iscsi_error_mask = 0x00;
  
+ DEFINE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu);
+ static int bnx2i_cpu_callback(struct notifier_block *nfb,
+                             unsigned long action, void *hcpu);
+ /* notification function for CPU hotplug events */
+ static struct notifier_block bnx2i_cpu_notifier = {
+       .notifier_call = bnx2i_cpu_callback,
+ };
  
  /**
   * bnx2i_identify_device - identifies NetXtreme II device type
@@@ -88,20 -97,11 +97,20 @@@ void bnx2i_identify_device(struct bnx2i
            (hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) {
                set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type);
                hba->mail_queue_access = BNX2I_MQ_BIN_MODE;
 -      } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710  ||
 -                 hba->pci_did == PCI_DEVICE_ID_NX2_57711  ||
 -                 hba->pci_did == PCI_DEVICE_ID_NX2_57711E ||
 -                 hba->pci_did == PCI_DEVICE_ID_NX2_57712  ||
 -                 hba->pci_did == PCI_DEVICE_ID_NX2_57712E)
 +      } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710    ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57711    ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57711E   ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57712    ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57712E   ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57800    ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57800_MF ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57800_VF ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57810    ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57810_MF ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57810_VF ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57840    ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57840_MF ||
 +                 hba->pci_did == PCI_DEVICE_ID_NX2_57840_VF)
                set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type);
        else
                printk(KERN_ALERT "bnx2i: unknown device, 0x%x\n",
@@@ -172,21 -172,14 +181,14 @@@ void bnx2i_start(void *handle
        struct bnx2i_hba *hba = handle;
        int i = HZ;
  
-       if (!hba->cnic->max_iscsi_conn) {
-               printk(KERN_ALERT "bnx2i: dev %s does not support "
-                       "iSCSI\n", hba->netdev->name);
+       /*
+        * We should never register devices that don't support iSCSI
+        * (see bnx2i_init_one), so something is wrong if we try to
+        * start a iSCSI adapter on hardware with 0 supported iSCSI
+        * connections
+        */
+       BUG_ON(!hba->cnic->max_iscsi_conn);
  
-               if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) {
-                       mutex_lock(&bnx2i_dev_lock);
-                       list_del_init(&hba->link);
-                       adapter_count--;
-                       hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI);
-                       clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic);
-                       mutex_unlock(&bnx2i_dev_lock);
-                       bnx2i_free_hba(hba);
-               }
-               return;
-       }
        bnx2i_send_fw_iscsi_init_msg(hba);
        while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--)
                msleep(BNX2I_INIT_POLL_TIME);
@@@ -290,6 -283,13 +292,13 @@@ static int bnx2i_init_one(struct bnx2i_
        int rc;
  
        mutex_lock(&bnx2i_dev_lock);
+       if (!cnic->max_iscsi_conn) {
+               printk(KERN_ALERT "bnx2i: dev %s does not support "
+                       "iSCSI\n", hba->netdev->name);
+               rc = -EOPNOTSUPP;
+               goto out;
+       }
        hba->cnic = cnic;
        rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba);
        if (!rc) {
        else
                printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc);
  
+ out:
        mutex_unlock(&bnx2i_dev_lock);
  
        return rc;
@@@ -371,6 -372,91 +381,91 @@@ void bnx2i_ulp_exit(struct cnic_dev *de
  
  
  /**
+  * bnx2i_percpu_thread_create - Create a receive thread for an
+  *                            online CPU
+  *
+  * @cpu:      cpu index for the online cpu
+  */
+ static void bnx2i_percpu_thread_create(unsigned int cpu)
+ {
+       struct bnx2i_percpu_s *p;
+       struct task_struct *thread;
+       p = &per_cpu(bnx2i_percpu, cpu);
+       thread = kthread_create(bnx2i_percpu_io_thread, (void *)p,
+                               "bnx2i_thread/%d", cpu);
+       /* bind thread to the cpu */
+       if (likely(!IS_ERR(thread))) {
+               kthread_bind(thread, cpu);
+               p->iothread = thread;
+               wake_up_process(thread);
+       }
+ }
+ static void bnx2i_percpu_thread_destroy(unsigned int cpu)
+ {
+       struct bnx2i_percpu_s *p;
+       struct task_struct *thread;
+       struct bnx2i_work *work, *tmp;
+       /* Prevent any new work from being queued for this CPU */
+       p = &per_cpu(bnx2i_percpu, cpu);
+       spin_lock_bh(&p->p_work_lock);
+       thread = p->iothread;
+       p->iothread = NULL;
+       /* Free all work in the list */
+       list_for_each_entry_safe(work, tmp, &p->work_list, list) {
+               list_del_init(&work->list);
+               bnx2i_process_scsi_cmd_resp(work->session,
+                                           work->bnx2i_conn, &work->cqe);
+               kfree(work);
+       }
+       spin_unlock_bh(&p->p_work_lock);
+       if (thread)
+               kthread_stop(thread);
+ }
+ /**
+  * bnx2i_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 iSCSI
+  *
+  * Returns NOTIFY_OK always.
+  */
+ static int bnx2i_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(KERN_INFO "bnx2i: CPU %x online: Create Rx thread\n",
+                       cpu);
+               bnx2i_percpu_thread_create(cpu);
+               break;
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               printk(KERN_INFO "CPU %x offline: Remove Rx thread\n", cpu);
+               bnx2i_percpu_thread_destroy(cpu);
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+ }
+ /**
   * bnx2i_mod_init - module init entry point
   *
   * initialize any driver wide global data structures such as endpoint pool,
  static int __init bnx2i_mod_init(void)
  {
        int err;
+       unsigned cpu = 0;
+       struct bnx2i_percpu_s *p;
  
        printk(KERN_INFO "%s", version);
  
                goto unreg_xport;
        }
  
+       /* Create percpu kernel threads to handle iSCSI I/O completions */
+       for_each_possible_cpu(cpu) {
+               p = &per_cpu(bnx2i_percpu, cpu);
+               INIT_LIST_HEAD(&p->work_list);
+               spin_lock_init(&p->p_work_lock);
+               p->iothread = NULL;
+       }
+       for_each_online_cpu(cpu)
+               bnx2i_percpu_thread_create(cpu);
+       /* Initialize per CPU interrupt thread */
+       register_hotcpu_notifier(&bnx2i_cpu_notifier);
        return 0;
  
  unreg_xport:
@@@ -422,6 -524,7 +533,7 @@@ out
  static void __exit bnx2i_mod_exit(void)
  {
        struct bnx2i_hba *hba;
+       unsigned cpu = 0;
  
        mutex_lock(&bnx2i_dev_lock);
        while (!list_empty(&adapter_list)) {
        }
        mutex_unlock(&bnx2i_dev_lock);
  
+       unregister_hotcpu_notifier(&bnx2i_cpu_notifier);
+       for_each_online_cpu(cpu)
+               bnx2i_percpu_thread_destroy(cpu);
        iscsi_unregister_transport(&bnx2i_iscsi_transport);
        cnic_unregister_driver(CNIC_ULP_ISCSI);
  }
@@@ -985,7 -985,7 +985,7 @@@ static int init_act_open(struct cxgbi_s
                csk->saddr.sin_addr.s_addr = chba->ipv4addr;
  
        csk->rss_qid = 0;
 -      csk->l2t = t3_l2t_get(t3dev, dst->neighbour, ndev);
 +      csk->l2t = t3_l2t_get(t3dev, dst_get_neighbour(dst), ndev);
        if (!csk->l2t) {
                pr_err("NO l2t available.\n");
                return -EINVAL;
@@@ -1245,7 -1245,7 +1245,7 @@@ static int cxgb3i_ddp_init(struct cxgbi
        struct cxgbi_ddp_info *ddp = tdev->ulp_iscsi;
        struct ulp_iscsi_info uinfo;
        unsigned int pgsz_factor[4];
-       int err;
+       int i, err;
  
        if (ddp) {
                kref_get(&ddp->refcnt);
  
        uinfo.tagmask = ddp->idx_mask << PPOD_IDX_SHIFT;
        cxgbi_ddp_page_size_factor(pgsz_factor);
+       for (i = 0; i < 4; i++)
+               uinfo.pgsz_factor[i] = pgsz_factor[i];
        uinfo.ulimit = uinfo.llimit + (ddp->nppods << PPOD_SIZE_SHIFT);
  
        err = tdev->ctl(tdev, ULP_ISCSI_SET_PARAMS, &uinfo);
@@@ -153,6 -153,18 +153,6 @@@ static struct fc_rport_priv *fc_rport_c
  }
  
  /**
 - * fc_rport_free_rcu() - Free a remote port
 - * @rcu: The rcu_head structure inside the remote port
 - */
 -static void fc_rport_free_rcu(struct rcu_head *rcu)
 -{
 -      struct fc_rport_priv *rdata;
 -
 -      rdata = container_of(rcu, struct fc_rport_priv, rcu);
 -      kfree(rdata);
 -}
 -
 -/**
   * fc_rport_destroy() - Free a remote port after last reference is released
   * @kref: The remote port's kref
   */
@@@ -161,7 -173,7 +161,7 @@@ static void fc_rport_destroy(struct kre
        struct fc_rport_priv *rdata;
  
        rdata = container_of(kref, struct fc_rport_priv, kref);
 -      call_rcu(&rdata->rcu, fc_rport_free_rcu);
 +      kfree_rcu(rdata, rcu);
  }
  
  /**
@@@ -789,6 -801,20 +789,20 @@@ static void fc_rport_recv_flogi_req(str
  
        switch (rdata->rp_state) {
        case RPORT_ST_INIT:
+               /*
+                * If received the FLOGI request on RPORT which is INIT state
+                * (means not transition to FLOGI either fc_rport timeout
+                * function didn;t trigger or this end hasn;t received
+                * beacon yet from other end. In that case only, allow RPORT
+                * state machine to continue, otherwise fall through which
+                * causes the code to send reject response.
+                * NOTE; Not checking for FIP->state such as VNMP_UP or
+                * VNMP_CLAIM because if FIP state is not one of those,
+                * RPORT wouldn;t have created and 'rport_lookup' would have
+                * failed anyway in that case.
+                */
+               if (lport->point_to_multipoint)
+                       break;
        case RPORT_ST_DELETE:
                mutex_unlock(&rdata->rp_mutex);
                rjt_data.reason = ELS_RJT_FIP;
@@@ -59,30 -59,33 +59,30 @@@ void ft_dump_cmd(struct ft_cmd *cmd, co
        struct fc_exch *ep;
        struct fc_seq *sp;
        struct se_cmd *se_cmd;
 -      struct se_mem *mem;
 -      struct se_transport_task *task;
 -
 -      if (!(ft_debug_logging & FT_DEBUG_IO))
 -              return;
 +      struct scatterlist *sg;
 +      int count;
  
        se_cmd = &cmd->se_cmd;
 -      printk(KERN_INFO "%s: cmd %p state %d sess %p seq %p se_cmd %p\n",
 +      pr_debug("%s: cmd %p state %d sess %p seq %p se_cmd %p\n",
                caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd);
 -      printk(KERN_INFO "%s: cmd %p cdb %p\n",
 +      pr_debug("%s: cmd %p cdb %p\n",
                caller, cmd, cmd->cdb);
 -      printk(KERN_INFO "%s: cmd %p lun %d\n", caller, cmd, cmd->lun);
 -
 -      task = T_TASK(se_cmd);
 -      printk(KERN_INFO "%s: cmd %p task %p se_num %u buf %p len %u se_cmd_flags <0x%x>\n",
 -             caller, cmd, task, task->t_tasks_se_num,
 -             task->t_task_buf, se_cmd->data_length, se_cmd->se_cmd_flags);
 -      if (task->t_mem_list)
 -              list_for_each_entry(mem, task->t_mem_list, se_list)
 -                      printk(KERN_INFO "%s: cmd %p mem %p page %p "
 -                             "len 0x%x off 0x%x\n",
 -                             caller, cmd, mem,
 -                             mem->se_page, mem->se_len, mem->se_off);
 +      pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun);
 +
 +      pr_debug("%s: cmd %p data_nents %u len %u se_cmd_flags <0x%x>\n",
 +              caller, cmd, se_cmd->t_data_nents,
 +             se_cmd->data_length, se_cmd->se_cmd_flags);
 +
 +      for_each_sg(se_cmd->t_data_sg, sg, se_cmd->t_data_nents, count)
 +              pr_debug("%s: cmd %p sg %p page %p "
 +                      "len 0x%x off 0x%x\n",
 +                      caller, cmd, sg,
 +                      sg_page(sg), sg->length, sg->offset);
 +
        sp = cmd->seq;
        if (sp) {
                ep = fc_seq_exch(sp);
 -              printk(KERN_INFO "%s: cmd %p sid %x did %x "
 +              pr_debug("%s: cmd %p sid %x did %x "
                        "ox_id %x rx_id %x seq_id %x e_stat %x\n",
                        caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid,
                        sp->id, ep->esb_stat);
  
  static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd)
  {
 -      struct se_queue_obj *qobj;
 +      struct ft_tpg *tpg = sess->tport->tpg;
 +      struct se_queue_obj *qobj = &tpg->qobj;
        unsigned long flags;
  
        qobj = &sess->tport->tpg->qobj;
        spin_lock_irqsave(&qobj->cmd_queue_lock, flags);
        list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list);
 -      spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
        atomic_inc(&qobj->queue_cnt);
 -      wake_up_interruptible(&qobj->thread_wq);
 +      spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags);
 +
 +      wake_up_process(tpg->thread);
  }
  
  static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj)
@@@ -148,7 -149,7 +148,7 @@@ void ft_release_cmd(struct se_cmd *se_c
  
  void ft_check_stop_free(struct se_cmd *se_cmd)
  {
 -      transport_generic_free_cmd(se_cmd, 0, 1, 0);
 +      transport_generic_free_cmd(se_cmd, 0, 0);
  }
  
  /*
@@@ -255,17 -256,19 +255,18 @@@ int ft_write_pending(struct se_cmd *se_
                    (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) {
                        if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
                                /*
 -                               * Map se_mem list to scatterlist, so that
 -                               * DDP can be setup. DDP setup function require
 -                               * scatterlist. se_mem_list is internal to
 -                               * TCM/LIO target
 +                               * cmd may have been broken up into multiple
 +                               * tasks. Link their sgs together so we can
 +                               * operate on them all at once.
                                 */
                                transport_do_task_sg_chain(se_cmd);
 -                              cmd->sg = T_TASK(se_cmd)->t_tasks_sg_chained;
 +                              cmd->sg = se_cmd->t_tasks_sg_chained;
                                cmd->sg_cnt =
 -                                      T_TASK(se_cmd)->t_tasks_sg_chained_no;
 +                                      se_cmd->t_tasks_sg_chained_no;
                        }
-                       if (cmd->sg && lport->tt.ddp_setup(lport, ep->xid,
-                                                   cmd->sg, cmd->sg_cnt))
+                       if (cmd->sg && lport->tt.ddp_target(lport, ep->xid,
+                                                           cmd->sg,
+                                                           cmd->sg_cnt))
                                cmd->was_ddp_setup = 1;
                }
        }
@@@ -292,6 -295,12 +293,6 @@@ int ft_is_state_remove(struct se_cmd *s
        return 0;       /* XXX TBD */
  }
  
 -void ft_new_cmd_failure(struct se_cmd *se_cmd)
 -{
 -      /* XXX TBD */
 -      printk(KERN_INFO "%s: se_cmd %p\n", __func__, se_cmd);
 -}
 -
  /*
   * FC sequence response handler for follow-on sequences (data) and aborts.
   */
@@@ -304,7 -313,7 +305,7 @@@ static void ft_recv_seq(struct fc_seq *
                /* XXX need to find cmd if queued */
                cmd->se_cmd.t_state = TRANSPORT_REMOVE;
                cmd->seq = NULL;
 -              transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0);
 +              transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
                return;
        }
  
        case FC_RCTL_DD_SOL_CTL:        /* transfer ready */
        case FC_RCTL_DD_DATA_DESC:      /* transfer ready */
        default:
 -              printk(KERN_INFO "%s: unhandled frame r_ctl %x\n",
 +              pr_debug("%s: unhandled frame r_ctl %x\n",
                       __func__, fh->fh_r_ctl);
                fc_frame_free(fp);
 -              transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0);
 +              transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
                break;
        }
  }
@@@ -343,7 -352,7 +344,7 @@@ static void ft_send_resp_status(struct 
        struct fcp_resp_rsp_info *info;
  
        fh = fc_frame_header_get(rx_fp);
 -      FT_IO_DBG("FCP error response: did %x oxid %x status %x code %x\n",
 +      pr_debug("FCP error response: did %x oxid %x status %x code %x\n",
                  ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), status, code);
        len = sizeof(*fcp);
        if (status == SAM_STAT_GOOD)
  
  /*
   * Send error or task management response.
-  * Always frees the cmd and associated state.
   */
- static void ft_send_resp_code(struct ft_cmd *cmd, enum fcp_resp_rsp_codes code)
+ static void ft_send_resp_code(struct ft_cmd *cmd,
+                             enum fcp_resp_rsp_codes code)
  {
        ft_send_resp_status(cmd->sess->tport->lport,
                            cmd->req_frame, SAM_STAT_GOOD, code);
+ }
+ /*
+  * Send error or task management response.
+  * Always frees the cmd and associated state.
+  */
+ static void ft_send_resp_code_and_free(struct ft_cmd *cmd,
+                                     enum fcp_resp_rsp_codes code)
+ {
+       ft_send_resp_code(cmd, code);
        ft_free_cmd(cmd);
  }
  
@@@ -413,16 -433,16 +425,16 @@@ static void ft_send_tm(struct ft_cmd *c
                 * FCP4r01 indicates having a combination of
                 * tm_flags set is invalid.
                 */
 -              FT_TM_DBG("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
 +              pr_debug("invalid FCP tm_flags %x\n", fcp->fc_tm_flags);
-               ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID);
+               ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
                return;
        }
  
 -      FT_TM_DBG("alloc tm cmd fn %d\n", tm_func);
 +      pr_debug("alloc tm cmd fn %d\n", tm_func);
        tmr = core_tmr_alloc_req(&cmd->se_cmd, cmd, tm_func);
        if (!tmr) {
 -              FT_TM_DBG("alloc failed\n");
 +              pr_debug("alloc failed\n");
-               ft_send_resp_code(cmd, FCP_TMF_FAILED);
+               ft_send_resp_code_and_free(cmd, FCP_TMF_FAILED);
                return;
        }
        cmd->se_cmd.se_tmr_req = tmr;
        switch (fcp->fc_tm_flags) {
        case FCP_TMF_LUN_RESET:
                cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
 -              if (transport_get_lun_for_tmr(&cmd->se_cmd, cmd->lun) < 0) {
 +              if (transport_lookup_tmr_lun(&cmd->se_cmd, cmd->lun) < 0) {
                        /*
                         * Make sure to clean up newly allocated TMR request
                         * since "unable to  handle TMR request because failed
                         * to get to LUN"
                         */
 -                      FT_TM_DBG("Failed to get LUN for TMR func %d, "
 +                      pr_debug("Failed to get LUN for TMR func %d, "
                                  "se_cmd %p, unpacked_lun %d\n",
                                  tm_func, &cmd->se_cmd, cmd->lun);
                        ft_dump_cmd(cmd, __func__);
                        sess = cmd->sess;
                        transport_send_check_condition_and_sense(&cmd->se_cmd,
                                cmd->se_cmd.scsi_sense_reason, 0);
 -                      transport_generic_free_cmd(&cmd->se_cmd, 0, 1, 0);
 +                      transport_generic_free_cmd(&cmd->se_cmd, 0, 0);
                        ft_sess_put(sess);
                        return;
                }
@@@ -487,7 -507,7 +499,7 @@@ int ft_queue_tm_resp(struct se_cmd *se_
                code = FCP_TMF_FAILED;
                break;
        }
 -      FT_TM_DBG("tmr fn %d resp %d fcp code %d\n",
 +      pr_debug("tmr fn %d resp %d fcp code %d\n",
                  tmr->function, tmr->response, code);
        ft_send_resp_code(cmd, code);
        return 0;
@@@ -515,7 -535,7 +527,7 @@@ static void ft_recv_cmd(struct ft_sess 
        return;
  
  busy:
 -      FT_IO_DBG("cmd or seq allocation failure - sending BUSY\n");
 +      pr_debug("cmd or seq allocation failure - sending BUSY\n");
        ft_send_resp_status(lport, fp, SAM_STAT_BUSY, 0);
        fc_frame_free(fp);
        ft_sess_put(sess);              /* undo get from lookup */
@@@ -540,7 -560,7 +552,7 @@@ void ft_recv_req(struct ft_sess *sess, 
        case FC_RCTL_DD_DATA_DESC:      /* transfer ready */
        case FC_RCTL_ELS4_REQ:          /* SRR, perhaps */
        default:
 -              printk(KERN_INFO "%s: unhandled frame r_ctl %x\n",
 +              pr_debug("%s: unhandled frame r_ctl %x\n",
                       __func__, fh->fh_r_ctl);
                fc_frame_free(fp);
                ft_sess_put(sess);      /* undo get from lookup */
@@@ -629,7 -649,7 +641,7 @@@ static void ft_send_cmd(struct ft_cmd *
        fc_seq_exch(cmd->seq)->lp->tt.seq_set_resp(cmd->seq, ft_recv_seq, cmd);
  
        cmd->lun = scsilun_to_int((struct scsi_lun *)fcp->fc_lun);
 -      ret = transport_get_lun_for_cmd(&cmd->se_cmd, NULL, cmd->lun);
 +      ret = transport_lookup_cmd_lun(&cmd->se_cmd, cmd->lun);
        if (ret < 0) {
                ft_dump_cmd(cmd, __func__);
                transport_send_check_condition_and_sense(&cmd->se_cmd,
  
        ret = transport_generic_allocate_tasks(se_cmd, cmd->cdb);
  
 -      FT_IO_DBG("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret);
 +      pr_debug("r_ctl %x alloc task ret %d\n", fh->fh_r_ctl, ret);
        ft_dump_cmd(cmd, __func__);
  
 -      if (ret == -1) {
 +      if (ret == -ENOMEM) {
                transport_send_check_condition_and_sense(se_cmd,
                                TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
 -              transport_generic_free_cmd(se_cmd, 0, 1, 0);
 +              transport_generic_free_cmd(se_cmd, 0, 0);
                return;
        }
 -      if (ret == -2) {
 +      if (ret == -EINVAL) {
                if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
                        ft_queue_status(se_cmd);
                else
                        transport_send_check_condition_and_sense(se_cmd,
                                        se_cmd->scsi_sense_reason, 0);
 -              transport_generic_free_cmd(se_cmd, 0, 1, 0);
 +              transport_generic_free_cmd(se_cmd, 0, 0);
                return;
        }
        transport_generic_handle_cdb(se_cmd);
        return;
  
  err:
-       ft_send_resp_code(cmd, FCP_CMND_FIELDS_INVALID);
+       ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID);
 -      return;
  }
  
  /*
   */
  static void ft_exec_req(struct ft_cmd *cmd)
  {
 -      FT_IO_DBG("cmd state %x\n", cmd->state);
 +      pr_debug("cmd state %x\n", cmd->state);
        switch (cmd->state) {
        case FC_CMD_ST_NEW:
                ft_send_cmd(cmd);
@@@ -688,12 -709,15 +700,12 @@@ int ft_thread(void *arg
        struct ft_tpg *tpg = arg;
        struct se_queue_obj *qobj = &tpg->qobj;
        struct ft_cmd *cmd;
 -      int ret;
 -
 -      set_user_nice(current, -20);
  
        while (!kthread_should_stop()) {
 -              ret = wait_event_interruptible(qobj->thread_wq,
 -                      atomic_read(&qobj->queue_cnt) || kthread_should_stop());
 -              if (ret < 0 || kthread_should_stop())
 +              schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
 +              if (kthread_should_stop())
                        goto out;
 +
                cmd = ft_dequeue_cmd(qobj);
                if (cmd)
                        ft_exec_req(cmd);