Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[pandora-kernel.git] / drivers / net / cnic.c
index 11a92af..94a2e54 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic.c: Broadcom CNIC core network driver.
  *
- * 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
@@ -28,6 +28,7 @@
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
 #include <linux/prefetch.h>
+#include <linux/random.h>
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define BCM_VLAN 1
 #endif
@@ -327,7 +328,7 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
                msleep(100);
                retry++;
        }
-       return 0;
+       return rc;
 }
 
 static void cnic_cm_upcall(struct cnic_local *, struct cnic_sock *, u8);
@@ -605,11 +606,12 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
 }
 EXPORT_SYMBOL(cnic_unregister_driver);
 
-static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id)
+static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id,
+                           u32 next)
 {
        id_tbl->start = start_id;
        id_tbl->max = size;
-       id_tbl->next = 0;
+       id_tbl->next = next;
        spin_lock_init(&id_tbl->lock);
        id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL);
        if (!id_tbl->table)
@@ -835,7 +837,6 @@ static void cnic_free_resc(struct cnic_dev *dev)
        cp->ctx_blks = 0;
 
        cnic_free_dma(dev, &cp->gbl_buf_info);
-       cnic_free_dma(dev, &cp->conn_buf_info);
        cnic_free_dma(dev, &cp->kwq_info);
        cnic_free_dma(dev, &cp->kwq_16_data_info);
        cnic_free_dma(dev, &cp->kcq2.dma);
@@ -899,24 +900,56 @@ static int cnic_alloc_context(struct cnic_dev *dev)
        return 0;
 }
 
-static int cnic_alloc_kcq(struct cnic_dev *dev, struct kcq_info *info)
+static u16 cnic_bnx2_next_idx(u16 idx)
+{
+       return idx + 1;
+}
+
+static u16 cnic_bnx2_hw_idx(u16 idx)
+{
+       return idx;
+}
+
+static u16 cnic_bnx2x_next_idx(u16 idx)
 {
-       int err, i, is_bnx2 = 0;
+       idx++;
+       if ((idx & MAX_KCQE_CNT) == MAX_KCQE_CNT)
+               idx++;
+
+       return idx;
+}
+
+static u16 cnic_bnx2x_hw_idx(u16 idx)
+{
+       if ((idx & MAX_KCQE_CNT) == MAX_KCQE_CNT)
+               idx++;
+       return idx;
+}
+
+static int cnic_alloc_kcq(struct cnic_dev *dev, struct kcq_info *info,
+                         bool use_pg_tbl)
+{
+       int err, i, use_page_tbl = 0;
        struct kcqe **kcq;
 
-       if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags))
-               is_bnx2 = 1;
+       if (use_pg_tbl)
+               use_page_tbl = 1;
 
-       err = cnic_alloc_dma(dev, &info->dma, KCQ_PAGE_CNT, is_bnx2);
+       err = cnic_alloc_dma(dev, &info->dma, KCQ_PAGE_CNT, use_page_tbl);
        if (err)
                return err;
 
        kcq = (struct kcqe **) info->dma.pg_arr;
        info->kcq = kcq;
 
-       if (is_bnx2)
+       info->next_idx = cnic_bnx2_next_idx;
+       info->hw_idx = cnic_bnx2_hw_idx;
+       if (use_pg_tbl)
                return 0;
 
+       info->next_idx = cnic_bnx2x_next_idx;
+       info->hw_idx = cnic_bnx2x_hw_idx;
+
        for (i = 0; i < KCQ_PAGE_CNT; i++) {
                struct bnx2x_bd_chain_next *next =
                        (struct bnx2x_bd_chain_next *) &kcq[i][MAX_KCQE_CNT];
@@ -1059,7 +1092,7 @@ static int cnic_alloc_bnx2_resc(struct cnic_dev *dev)
                goto error;
        cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr;
 
-       ret = cnic_alloc_kcq(dev, &cp->kcq1);
+       ret = cnic_alloc_kcq(dev, &cp->kcq1, true);
        if (ret)
                goto error;
 
@@ -1139,25 +1172,17 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
 
        cp->iro_arr = ethdev->iro_arr;
 
-       cp->max_cid_space = MAX_ISCSI_TBL_SZ + BNX2X_FCOE_NUM_CONNECTIONS;
+       cp->max_cid_space = MAX_ISCSI_TBL_SZ;
        cp->iscsi_start_cid = start_cid;
        cp->fcoe_start_cid = start_cid + MAX_ISCSI_TBL_SZ;
 
-       if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
                cp->max_cid_space += BNX2X_FCOE_NUM_CONNECTIONS;
                cp->fcoe_init_cid = ethdev->fcoe_init_cid;
                if (!cp->fcoe_init_cid)
                        cp->fcoe_init_cid = 0x10;
        }
 
-       if (start_cid < BNX2X_ISCSI_START_CID) {
-               u32 delta = BNX2X_ISCSI_START_CID - start_cid;
-
-               cp->iscsi_start_cid = BNX2X_ISCSI_START_CID;
-               cp->fcoe_start_cid += delta;
-               cp->max_cid_space += delta;
-       }
-
        cp->iscsi_tbl = kzalloc(sizeof(struct cnic_iscsi) * MAX_ISCSI_TBL_SZ,
                                GFP_KERNEL);
        if (!cp->iscsi_tbl)
@@ -1195,22 +1220,16 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
                        j++;
        }
 
-       ret = cnic_alloc_kcq(dev, &cp->kcq1);
+       ret = cnic_alloc_kcq(dev, &cp->kcq1, false);
        if (ret)
                goto error;
 
-       if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
-               ret = cnic_alloc_kcq(dev, &cp->kcq2);
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
+               ret = cnic_alloc_kcq(dev, &cp->kcq2, true);
                if (ret)
                        goto error;
        }
 
-       pages = PAGE_ALIGN(BNX2X_ISCSI_NUM_CONNECTIONS *
-                          BNX2X_ISCSI_CONN_BUF_SIZE) / PAGE_SIZE;
-       ret = cnic_alloc_dma(dev, &cp->conn_buf_info, pages, 1);
-       if (ret)
-               goto error;
-
        pages = PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / PAGE_SIZE;
        ret = cnic_alloc_dma(dev, &cp->gbl_buf_info, pages, 0);
        if (ret)
@@ -1577,6 +1596,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
        struct iscsi_context *ictx;
        struct regpair context_addr;
        int i, j, n = 2, n_max;
+       u8 port = CNIC_PORT(cp);
 
        ctx->ctx_flags = 0;
        if (!req2->num_additional_wqes)
@@ -1628,6 +1648,17 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
                XSTORM_ISCSI_CONTEXT_FLAGS_B_IMMEDIATE_DATA;
        ictx->xstorm_st_context.iscsi.flags.flags |=
                XSTORM_ISCSI_CONTEXT_FLAGS_B_INITIAL_R2T;
+       ictx->xstorm_st_context.common.ethernet.reserved_vlan_type =
+               ETH_P_8021Q;
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id) &&
+               cp->port_mode == CHIP_2_PORT_MODE) {
+
+               port = 0;
+       }
+       ictx->xstorm_st_context.common.flags =
+               1 << XSTORM_COMMON_CONTEXT_SECTION_PHYSQ_INITIALIZED_SHIFT;
+       ictx->xstorm_st_context.common.flags =
+               port << XSTORM_COMMON_CONTEXT_SECTION_PBF_PORT_SHIFT;
 
        ictx->tstorm_st_context.iscsi.hdr_bytes_2_fetch = ISCSI_HEADER_SIZE;
        /* TSTORM requires the base address of RQ DB & not PTE */
@@ -1843,8 +1874,11 @@ static int cnic_bnx2x_destroy_ramrod(struct cnic_dev *dev, u32 l5_cid)
        ret = cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_COMMON_CFC_DEL,
                                  hw_cid, NONE_CONNECTION_TYPE, &l5_data);
 
-       if (ret == 0)
+       if (ret == 0) {
                wait_event(ctx->waitq, ctx->wait_cond);
+               if (unlikely(test_bit(CTX_FL_CID_ERROR, &ctx->ctx_flags)))
+                       return -EBUSY;
+       }
 
        return ret;
 }
@@ -1879,8 +1913,10 @@ static int cnic_bnx2x_iscsi_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
 skip_cfc_delete:
        cnic_free_bnx2x_conn_resc(dev, l5_cid);
 
-       atomic_dec(&cp->iscsi_conn);
-       clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags);
+       if (!ret) {
+               atomic_dec(&cp->iscsi_conn);
+               clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags);
+       }
 
 destroy_reply:
        memset(&kcqe, 0, sizeof(kcqe));
@@ -1939,8 +1975,6 @@ static void cnic_init_storm_conn_bufs(struct cnic_dev *dev,
                tstorm_buf->ka_interval = kwqe3->ka_interval;
                tstorm_buf->ka_max_probe_count = kwqe3->ka_max_probe_count;
        }
-       tstorm_buf->rcv_buf = kwqe3->rcv_buf;
-       tstorm_buf->snd_buf = kwqe3->snd_buf;
        tstorm_buf->max_rt_time = 0xffffffff;
 }
 
@@ -1969,15 +2003,14 @@ static void cnic_init_bnx2x_mac(struct cnic_dev *dev)
                 TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 1,
                 mac[4]);
        CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
-                TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid), mac[3]);
+                TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfid), mac[3]);
        CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
-                TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 1,
+                TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfid) + 1,
                 mac[2]);
        CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
-                TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 2,
-                mac[1]);
+                TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid), mac[1]);
        CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
-                TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 3,
+                TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfid) + 1,
                 mac[0]);
 }
 
@@ -2156,7 +2189,7 @@ static int cnic_bnx2x_fcoe_stat(struct cnic_dev *dev, struct kwqe *kwqe)
        memset(fcoe_stat, 0, sizeof(*fcoe_stat));
        memcpy(&fcoe_stat->stat_kwqe, req, sizeof(*req));
 
-       ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_STAT, cid,
+       ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_STAT_FUNC, cid,
                                  FCOE_CONNECTION_TYPE, &l5_data);
        return ret;
 }
@@ -2201,12 +2234,9 @@ static int cnic_bnx2x_fcoe_init1(struct cnic_dev *dev, struct kwqe *wqes[],
        memcpy(&fcoe_init->init_kwqe1, req1, sizeof(*req1));
        memcpy(&fcoe_init->init_kwqe2, req2, sizeof(*req2));
        memcpy(&fcoe_init->init_kwqe3, req3, sizeof(*req3));
-       fcoe_init->eq_addr.lo = cp->kcq2.dma.pg_map_arr[0] & 0xffffffff;
-       fcoe_init->eq_addr.hi = (u64) cp->kcq2.dma.pg_map_arr[0] >> 32;
-       fcoe_init->eq_next_page_addr.lo =
-               cp->kcq2.dma.pg_map_arr[1] & 0xffffffff;
-       fcoe_init->eq_next_page_addr.hi =
-               (u64) cp->kcq2.dma.pg_map_arr[1] >> 32;
+       fcoe_init->eq_pbl_base.lo = cp->kcq2.dma.pgtbl_map & 0xffffffff;
+       fcoe_init->eq_pbl_base.hi = (u64) cp->kcq2.dma.pgtbl_map >> 32;
+       fcoe_init->eq_pbl_size = cp->kcq2.dma.num_pages;
 
        fcoe_init->sb_num = cp->status_blk_num;
        fcoe_init->eq_prod = MAX_KCQ_IDX;
@@ -2214,7 +2244,7 @@ static int cnic_bnx2x_fcoe_init1(struct cnic_dev *dev, struct kwqe *wqes[],
        cp->kcq2.sw_prod_idx = 0;
 
        cid = BNX2X_HW_CID(cp, cp->fcoe_init_cid);
-       ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_INIT, cid,
+       ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_INIT_FUNC, cid,
                                  FCOE_CONNECTION_TYPE, &l5_data);
        *work = 3;
        return ret;
@@ -2418,6 +2448,30 @@ static int cnic_bnx2x_fcoe_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
        return ret;
 }
 
+static void cnic_bnx2x_delete_wait(struct cnic_dev *dev, u32 start_cid)
+{
+       struct cnic_local *cp = dev->cnic_priv;
+       u32 i;
+
+       for (i = start_cid; i < cp->max_cid_space; i++) {
+               struct cnic_context *ctx = &cp->ctx_tbl[i];
+               int j;
+
+               while (test_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags))
+                       msleep(10);
+
+               for (j = 0; j < 5; j++) {
+                       if (!test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags))
+                               break;
+                       msleep(20);
+               }
+
+               if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags))
+                       netdev_warn(dev->netdev, "CID %x not deleted\n",
+                                  ctx->cid);
+       }
+}
+
 static int cnic_bnx2x_fcoe_fw_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
 {
        struct fcoe_kwqe_destroy *req;
@@ -2426,11 +2480,13 @@ static int cnic_bnx2x_fcoe_fw_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
        int ret;
        u32 cid;
 
+       cnic_bnx2x_delete_wait(dev, MAX_ISCSI_TBL_SZ);
+
        req = (struct fcoe_kwqe_destroy *) kwqe;
        cid = BNX2X_HW_CID(cp, cp->fcoe_init_cid);
 
        memset(&l5_data, 0, sizeof(l5_data));
-       ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_DESTROY, cid,
+       ret = cnic_submit_kwqe_16(dev, FCOE_RAMROD_CMD_ID_DESTROY_FUNC, cid,
                                  FCOE_CONNECTION_TYPE, &l5_data);
        return ret;
 }
@@ -2511,7 +2567,7 @@ static int cnic_submit_bnx2x_fcoe_kwqes(struct cnic_dev *dev,
        if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
                return -EAGAIN;         /* bnx2 is down */
 
-       if (BNX2X_CHIP_NUM(cp->chip_id) == BNX2X_CHIP_NUM_57710)
+       if (!BNX2X_CHIP_IS_E2_PLUS(cp->chip_id))
                return -EINVAL;
 
        for (i = 0; i < num_wqes; ) {
@@ -2651,32 +2707,6 @@ end:
                cnic_spq_completion(dev, DRV_CTL_RET_L5_SPQ_CREDIT_CMD, comp);
 }
 
-static u16 cnic_bnx2_next_idx(u16 idx)
-{
-       return idx + 1;
-}
-
-static u16 cnic_bnx2_hw_idx(u16 idx)
-{
-       return idx;
-}
-
-static u16 cnic_bnx2x_next_idx(u16 idx)
-{
-       idx++;
-       if ((idx & MAX_KCQE_CNT) == MAX_KCQE_CNT)
-               idx++;
-
-       return idx;
-}
-
-static u16 cnic_bnx2x_hw_idx(u16 idx)
-{
-       if ((idx & MAX_KCQE_CNT) == MAX_KCQE_CNT)
-               idx++;
-       return idx;
-}
-
 static int cnic_get_kcqes(struct cnic_dev *dev, struct kcq_info *info)
 {
        struct cnic_local *cp = dev->cnic_priv;
@@ -2687,12 +2717,12 @@ static int cnic_get_kcqes(struct cnic_dev *dev, struct kcq_info *info)
        i = ri = last = info->sw_prod_idx;
        ri &= MAX_KCQ_IDX;
        hw_prod = *info->hw_prod_idx_ptr;
-       hw_prod = cp->hw_idx(hw_prod);
+       hw_prod = info->hw_idx(hw_prod);
 
        while ((i != hw_prod) && (kcqe_cnt < MAX_COMPLETED_KCQE)) {
                kcqe = &info->kcq[KCQ_PG(ri)][KCQ_IDX(ri)];
                cp->completed_kcq[kcqe_cnt++] = kcqe;
-               i = cp->next_idx(i);
+               i = info->next_idx(i);
                ri = i & MAX_KCQ_IDX;
                if (likely(!(kcqe->kcqe_op_flag & KCQE_FLAGS_NEXT))) {
                        last_cnt = kcqe_cnt;
@@ -2778,13 +2808,10 @@ static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
 
                /* Tell compiler that status_blk fields can change. */
                barrier();
-               if (status_idx != *cp->kcq1.status_idx_ptr) {
-                       status_idx = (u16) *cp->kcq1.status_idx_ptr;
-                       /* status block index must be read first */
-                       rmb();
-                       cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
-               } else
-                       break;
+               status_idx = (u16) *cp->kcq1.status_idx_ptr;
+               /* status block index must be read first */
+               rmb();
+               cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
        }
 
        CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx);
@@ -2908,8 +2935,6 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
 
                /* Tell compiler that sblk fields can change. */
                barrier();
-               if (last_status == *info->status_idx_ptr)
-                       break;
 
                last_status = *info->status_idx_ptr;
                /* status block index must be read before reading the KCQ */
@@ -2933,7 +2958,7 @@ static void cnic_service_bnx2x_bh(unsigned long data)
                CNIC_WR16(dev, cp->kcq1.io_addr,
                          cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
 
-               if (!BNX2X_CHIP_IS_E2(cp->chip_id)) {
+               if (!BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
                        cnic_ack_bnx2x_int(dev, cp->bnx2x_igu_sb_id, USTORM_ID,
                                           status_idx, IGU_INT_ENABLE, 1);
                        break;
@@ -3052,13 +3077,21 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info)
                break;
        }
        case CNIC_CTL_COMPLETION_CMD: {
-               u32 cid = BNX2X_SW_CID(info->data.comp.cid);
+               struct cnic_ctl_completion *comp = &info->data.comp;
+               u32 cid = BNX2X_SW_CID(comp->cid);
                u32 l5_cid;
                struct cnic_local *cp = dev->cnic_priv;
 
                if (cnic_get_l5_cid(cp, cid, &l5_cid) == 0) {
                        struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
 
+                       if (unlikely(comp->error)) {
+                               set_bit(CTX_FL_CID_ERROR, &ctx->ctx_flags);
+                               netdev_err(dev->netdev,
+                                          "CID %x CFC delete comp error %x\n",
+                                          cid, comp->error);
+                       }
+
                        ctx->wait_cond = 1;
                        wake_up(&ctx->waitq);
                }
@@ -3772,7 +3805,13 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
                break;
 
        case L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED:
-               cnic_cm_upcall(cp, csk, opcode);
+               /* after we already sent CLOSE_REQ */
+               if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags) &&
+                   !test_bit(SK_F_OFFLD_COMPLETE, &csk->flags) &&
+                   csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)
+                       cp->close_conn(csk, L4_KCQE_OPCODE_VALUE_RESET_COMP);
+               else
+                       cnic_cm_upcall(cp, csk, opcode);
                break;
        }
        csk_put(csk);
@@ -3803,14 +3842,17 @@ static void cnic_cm_free_mem(struct cnic_dev *dev)
 static int cnic_cm_alloc_mem(struct cnic_dev *dev)
 {
        struct cnic_local *cp = dev->cnic_priv;
+       u32 port_id;
 
        cp->csk_tbl = kzalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ,
                              GFP_KERNEL);
        if (!cp->csk_tbl)
                return -ENOMEM;
 
+       port_id = random32();
+       port_id %= CNIC_LOCAL_PORT_RANGE;
        if (cnic_init_id_tbl(&cp->csk_port_tbl, CNIC_LOCAL_PORT_RANGE,
-                            CNIC_LOCAL_PORT_MIN)) {
+                            CNIC_LOCAL_PORT_MIN, port_id)) {
                cnic_cm_free_mem(dev);
                return -ENOMEM;
        }
@@ -3826,12 +3868,14 @@ static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
        }
 
        /* 1. If event opcode matches the expected event in csk->state
-        * 2. If the expected event is CLOSE_COMP, we accept any event
+        * 2. If the expected event is CLOSE_COMP or RESET_COMP, we accept any
+        *    event
         * 3. If the expected event is 0, meaning the connection was never
         *    never established, we accept the opcode from cm_abort.
         */
        if (opcode == csk->state || csk->state == 0 ||
-           csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) {
+           csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP ||
+           csk->state == L4_KCQE_OPCODE_VALUE_RESET_COMP) {
                if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) {
                        if (csk->state == 0)
                                csk->state = opcode;
@@ -3865,7 +3909,7 @@ static int cnic_cm_init_bnx2_hw(struct cnic_dev *dev)
 {
        u32 seed;
 
-       get_random_bytes(&seed, 4);
+       seed = random32();
        cnic_ctx_wr(dev, 45, 0, seed);
        return 0;
 }
@@ -3912,7 +3956,6 @@ static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode)
 static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev)
 {
        struct cnic_local *cp = dev->cnic_priv;
-       int i;
 
        if (!cp->ctx_tbl)
                return;
@@ -3920,16 +3963,7 @@ static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev)
        if (!netif_running(dev->netdev))
                return;
 
-       for (i = 0; i < cp->max_cid_space; i++) {
-               struct cnic_context *ctx = &cp->ctx_tbl[i];
-
-               while (test_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags))
-                       msleep(10);
-
-               if (test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags))
-                       netdev_warn(dev->netdev, "CID %x not deleted\n",
-                                  ctx->cid);
-       }
+       cnic_bnx2x_delete_wait(dev, 0);
 
        cancel_delayed_work(&cp->delete_task);
        flush_workqueue(cnic_wq);
@@ -3992,6 +4026,7 @@ static void cnic_delete_task(struct work_struct *work)
 
        for (i = 0; i < cp->max_cid_space; i++) {
                struct cnic_context *ctx = &cp->ctx_tbl[i];
+               int err;
 
                if (!test_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags) ||
                    !test_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags))
@@ -4005,13 +4040,15 @@ static void cnic_delete_task(struct work_struct *work)
                if (!test_and_clear_bit(CTX_FL_DELETE_WAIT, &ctx->ctx_flags))
                        continue;
 
-               cnic_bnx2x_destroy_ramrod(dev, i);
+               err = cnic_bnx2x_destroy_ramrod(dev, i);
 
                cnic_free_bnx2x_conn_resc(dev, i);
-               if (ctx->ulp_proto_id == CNIC_ULP_ISCSI)
-                       atomic_dec(&cp->iscsi_conn);
+               if (!err) {
+                       if (ctx->ulp_proto_id == CNIC_ULP_ISCSI)
+                               atomic_dec(&cp->iscsi_conn);
 
-               clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags);
+                       clear_bit(CTX_FL_OFFLD_START, &ctx->ctx_flags);
+               }
        }
 
        if (need_resched)
@@ -4218,14 +4255,6 @@ static void cnic_enable_bnx2_int(struct cnic_dev *dev)
                BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
 }
 
-static void cnic_get_bnx2_iscsi_info(struct cnic_dev *dev)
-{
-       u32 max_conn;
-
-       max_conn = cnic_reg_rd_ind(dev, BNX2_FW_MAX_ISCSI_CONN);
-       dev->max_iscsi_conn = max_conn;
-}
-
 static void cnic_disable_bnx2_int_sync(struct cnic_dev *dev)
 {
        struct cnic_local *cp = dev->cnic_priv;
@@ -4291,7 +4320,7 @@ static void cnic_init_bnx2_tx_ring(struct cnic_dev *dev)
        val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
        cnic_ctx_wr(dev, cid_addr, offset1, val);
 
-       txbd = (struct tx_bd *) udev->l2_ring;
+       txbd = udev->l2_ring;
 
        buf_map = udev->l2_buf_map;
        for (i = 0; i < MAX_TX_DESC_CNT; i++, txbd++) {
@@ -4350,7 +4379,7 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
                val = BNX2_L2CTX_L2_STATUSB_NUM(sb_id);
        cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val);
 
-       rxbd = (struct rx_bd *) (udev->l2_ring + BCM_PAGE_SIZE);
+       rxbd = udev->l2_ring + BCM_PAGE_SIZE;
        for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) {
                dma_addr_t buf_map;
                int n = (i % cp->l2_rx_ring_size) + 1;
@@ -4550,8 +4579,6 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
                return err;
        }
 
-       cnic_get_bnx2_iscsi_info(dev);
-
        return 0;
 }
 
@@ -4617,7 +4644,7 @@ static void cnic_enable_bnx2x_int(struct cnic_dev *dev)
                        CSTORM_STATUS_BLOCK_DATA_OFFSET(sb_id) +
                        offsetof(struct hc_status_block_data_e1x, index_data) +
                        sizeof(struct hc_index_data)*HC_INDEX_ISCSI_EQ_CONS +
-                       offsetof(struct hc_index_data, timeout), 64 / 12);
+                       offsetof(struct hc_index_data, timeout), 64 / 4);
        cnic_storm_memset_hc_disable(dev, sb_id, HC_INDEX_ISCSI_EQ_CONS, 0);
 }
 
@@ -4633,7 +4660,6 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev,
        union eth_tx_bd_types *txbd = (union eth_tx_bd_types *) udev->l2_ring;
        dma_addr_t buf_map, ring_map = udev->l2_ring_map;
        struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
-       int port = CNIC_PORT(cp);
        int i;
        u32 cli = cp->ethdev->iscsi_l2_client_id;
        u32 val;
@@ -4674,10 +4700,9 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev,
 
        /* reset xstorm per client statistics */
        if (cli < MAX_STAT_COUNTER_ID) {
-               val = BAR_XSTRORM_INTMEM +
-                     XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
-               for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++)
-                       CNIC_WR(dev, val + i * 4, 0);
+               data->general.statistics_zero_flg = 1;
+               data->general.statistics_en_flg = 1;
+               data->general.statistics_counter_id = cli;
        }
 
        cp->tx_cons_ptr =
@@ -4695,7 +4720,6 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
                                (udev->l2_ring + (2 * BCM_PAGE_SIZE));
        struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
        int i;
-       int port = CNIC_PORT(cp);
        u32 cli = cp->ethdev->iscsi_l2_client_id;
        int cl_qzone_id = BNX2X_CL_QZONE_ID(cp, cli);
        u32 val;
@@ -4703,10 +4727,10 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
 
        /* General data */
        data->general.client_id = cli;
-       data->general.statistics_en_flg = 1;
-       data->general.statistics_counter_id = cli;
        data->general.activate_flg = 1;
        data->general.sp_client_id = cli;
+       data->general.mtu = cpu_to_le16(cp->l2_single_buf_size - 14);
+       data->general.func_id = cp->pfid;
 
        for (i = 0; i < BNX2X_MAX_RX_DESC_CNT; i++, rxbd++) {
                dma_addr_t buf_map;
@@ -4740,23 +4764,12 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
        data->rx.status_block_id = BNX2X_DEF_SB_ID;
 
        data->rx.cache_line_alignment_log_size = L1_CACHE_SHIFT;
-       data->rx.bd_buff_size = cpu_to_le16(cp->l2_single_buf_size);
 
-       data->rx.mtu = cpu_to_le16(cp->l2_single_buf_size - 14);
+       data->rx.max_bytes_on_bd = cpu_to_le16(cp->l2_single_buf_size);
        data->rx.outer_vlan_removal_enable_flg = 1;
-
-       /* reset tstorm and ustorm per client statistics */
-       if (cli < MAX_STAT_COUNTER_ID) {
-               val = BAR_TSTRORM_INTMEM +
-                     TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
-               for (i = 0; i < sizeof(struct tstorm_per_client_stats) / 4; i++)
-                       CNIC_WR(dev, val + i * 4, 0);
-
-               val = BAR_USTRORM_INTMEM +
-                     USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
-               for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++)
-                       CNIC_WR(dev, val + i * 4, 0);
-       }
+       data->rx.silent_vlan_removal_flg = 1;
+       data->rx.silent_vlan_value = 0;
+       data->rx.silent_vlan_mask = 0xffff;
 
        cp->rx_cons_ptr =
                &sb->sp_sb.index_values[HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS];
@@ -4772,7 +4785,7 @@ static void cnic_init_bnx2x_kcq(struct cnic_dev *dev)
                           CSTORM_ISCSI_EQ_PROD_OFFSET(pfid, 0);
        cp->kcq1.sw_prod_idx = 0;
 
-       if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
                struct host_hc_status_block_e2 *sb = cp->status_blk.gen;
 
                cp->kcq1.hw_prod_idx_ptr =
@@ -4788,7 +4801,7 @@ static void cnic_init_bnx2x_kcq(struct cnic_dev *dev)
                        &sb->sb.running_index[SM_RX_ID];
        }
 
-       if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
                struct host_hc_status_block_e2 *sb = cp->status_blk.gen;
 
                cp->kcq2.io_addr = BAR_USTRORM_INTMEM +
@@ -4805,10 +4818,12 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
 {
        struct cnic_local *cp = dev->cnic_priv;
        struct cnic_eth_dev *ethdev = cp->ethdev;
-       int func = CNIC_FUNC(cp), ret, i;
+       int func = CNIC_FUNC(cp), ret;
        u32 pfid;
 
-       if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+       cp->port_mode = CHIP_PORT_MODE_NONE;
+
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
                u32 val = CNIC_RD(dev, MISC_REG_PORT4MODE_EN_OVWR);
 
                if (!(val & 1))
@@ -4816,25 +4831,28 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
                else
                        val = (val >> 1) & 1;
 
-               if (val)
+               if (val) {
+                       cp->port_mode = CHIP_4_PORT_MODE;
                        cp->pfid = func >> 1;
-               else
+               } else {
+                       cp->port_mode = CHIP_2_PORT_MODE;
                        cp->pfid = func & 0x6;
+               }
        } else {
                cp->pfid = func;
        }
        pfid = cp->pfid;
 
        ret = cnic_init_id_tbl(&cp->cid_tbl, MAX_ISCSI_TBL_SZ,
-                              cp->iscsi_start_cid);
+                              cp->iscsi_start_cid, 0);
 
        if (ret)
                return -ENOMEM;
 
-       if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id)) {
                ret = cnic_init_id_tbl(&cp->fcoe_cid_tbl,
                                        BNX2X_FCOE_NUM_CONNECTIONS,
-                                       cp->fcoe_start_cid);
+                                       cp->fcoe_start_cid, 0);
 
                if (ret)
                        return -ENOMEM;
@@ -4868,15 +4886,6 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
                CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfid, 0),
                HC_INDEX_ISCSI_EQ_CONS);
 
-       for (i = 0; i < cp->conn_buf_info.num_pages; i++) {
-               CNIC_WR(dev, BAR_TSTRORM_INTMEM +
-                       TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(pfid, i),
-                       cp->conn_buf_info.pgtbl[2 * i]);
-               CNIC_WR(dev, BAR_TSTRORM_INTMEM +
-                       TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(pfid, i) + 4,
-                       cp->conn_buf_info.pgtbl[(2 * i) + 1]);
-       }
-
        CNIC_WR(dev, BAR_USTRORM_INTMEM +
                USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfid),
                cp->gbl_buf_info.pg_map_arr[0] & 0xffffffff);
@@ -4915,7 +4924,7 @@ static void cnic_init_rings(struct cnic_dev *dev)
                struct client_init_ramrod_data *data;
                union l5cm_specific_data l5_data;
                struct ustorm_eth_rx_producers rx_prods = {0};
-               u32 off, i;
+               u32 off, i, *cid_ptr;
 
                rx_prods.bd_prod = 0;
                rx_prods.cqe_prod = BNX2X_MAX_RCQ_DESC_CNT;
@@ -4924,7 +4933,7 @@ static void cnic_init_rings(struct cnic_dev *dev)
                cl_qzone_id = BNX2X_CL_QZONE_ID(cp, cli);
 
                off = BAR_USTRORM_INTMEM +
-                       (BNX2X_CHIP_IS_E2(cp->chip_id) ?
+                       (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id) ?
                         USTORM_RX_PRODS_E2_OFFSET(cl_qzone_id) :
                         USTORM_RX_PRODS_E1X_OFFSET(CNIC_PORT(cp), cli));
 
@@ -4934,6 +4943,7 @@ static void cnic_init_rings(struct cnic_dev *dev)
                set_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags);
 
                data = udev->l2_buf;
+               cid_ptr = udev->l2_buf + 12;
 
                memset(data, 0, sizeof(*data));
 
@@ -4958,12 +4968,15 @@ static void cnic_init_rings(struct cnic_dev *dev)
                                "iSCSI CLIENT_SETUP did not complete\n");
                cnic_spq_completion(dev, DRV_CTL_RET_L2_SPQ_CREDIT_CMD, 1);
                cnic_ring_ctl(dev, cid, cli, 1);
+               *cid_ptr = cid;
        }
 }
 
 static void cnic_shutdown_rings(struct cnic_dev *dev)
 {
        struct cnic_local *cp = dev->cnic_priv;
+       struct cnic_uio_dev *udev = cp->udev;
+       void *rx_ring;
 
        if (!test_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags))
                return;
@@ -4971,7 +4984,6 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
        if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
                cnic_shutdown_bnx2_rx_ring(dev);
        } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
-               struct cnic_local *cp = dev->cnic_priv;
                u32 cli = cp->ethdev->iscsi_l2_client_id;
                u32 cid = cp->ethdev->iscsi_l2_cid;
                union l5cm_specific_data l5_data;
@@ -5001,6 +5013,8 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
                msleep(10);
        }
        clear_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
+       rx_ring = udev->l2_ring + BCM_PAGE_SIZE;
+       memset(rx_ring, 0, BCM_PAGE_SIZE);
 }
 
 static int cnic_register_netdev(struct cnic_dev *dev)
@@ -5217,6 +5231,8 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev)
        cdev->pcidev = pdev;
        cp->chip_id = ethdev->chip_id;
 
+       cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
+
        cp->cnic_ops = &cnic_bnx2_ops;
        cp->start_hw = cnic_start_bnx2_hw;
        cp->stop_hw = cnic_stop_bnx2_hw;
@@ -5228,8 +5244,6 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev)
        cp->enable_int = cnic_enable_bnx2_int;
        cp->disable_int_sync = cnic_disable_bnx2_int_sync;
        cp->close_conn = cnic_close_bnx2_conn;
-       cp->next_idx = cnic_bnx2_next_idx;
-       cp->hw_idx = cnic_bnx2_hw_idx;
        return cdev;
 
 cnic_err:
@@ -5274,7 +5288,7 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
 
        if (!(ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI))
                cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
-       if (BNX2X_CHIP_IS_E2(cp->chip_id) &&
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id) &&
            !(ethdev->drv_state & CNIC_DRV_STATE_NO_FCOE))
                cdev->max_fcoe_conn = ethdev->max_fcoe_conn;
 
@@ -5290,13 +5304,11 @@ static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
        cp->stop_cm = cnic_cm_stop_bnx2x_hw;
        cp->enable_int = cnic_enable_bnx2x_int;
        cp->disable_int_sync = cnic_disable_bnx2x_int_sync;
-       if (BNX2X_CHIP_IS_E2(cp->chip_id))
+       if (BNX2X_CHIP_IS_E2_PLUS(cp->chip_id))
                cp->ack_int = cnic_ack_bnx2x_e2_msix;
        else
                cp->ack_int = cnic_ack_bnx2x_msix;
        cp->close_conn = cnic_close_bnx2x_conn;
-       cp->next_idx = cnic_bnx2x_next_idx;
-       cp->hw_idx = cnic_bnx2x_hw_idx;
        return cdev;
 }
 
@@ -5322,6 +5334,27 @@ static struct cnic_dev *is_cnic_dev(struct net_device *dev)
        return cdev;
 }
 
+static void cnic_rcv_netevent(struct cnic_local *cp, unsigned long event,
+                             u16 vlan_id)
+{
+       int if_type;
+
+       rcu_read_lock();
+       for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
+               struct cnic_ulp_ops *ulp_ops;
+               void *ctx;
+
+               ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
+               if (!ulp_ops || !ulp_ops->indicate_netevent)
+                       continue;
+
+               ctx = cp->ulp_handle[if_type];
+
+               ulp_ops->indicate_netevent(ctx, event, vlan_id);
+       }
+       rcu_read_unlock();
+}
+
 /**
  * netdev event handler
  */
@@ -5330,12 +5363,11 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
 {
        struct net_device *netdev = ptr;
        struct cnic_dev *dev;
-       int if_type;
        int new_dev = 0;
 
        dev = cnic_from_netdev(netdev);
 
-       if (!dev && (event == NETDEV_REGISTER || event == NETDEV_UP)) {
+       if (!dev && (event == NETDEV_REGISTER || netif_running(netdev))) {
                /* Check for the hot-plug device */
                dev = is_cnic_dev(netdev);
                if (dev) {
@@ -5351,7 +5383,7 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
                else if (event == NETDEV_UNREGISTER)
                        cnic_ulp_exit(dev);
 
-               if (event == NETDEV_UP) {
+               if (event == NETDEV_UP || (new_dev && netif_running(netdev))) {
                        if (cnic_register_netdev(dev) != 0) {
                                cnic_put(dev);
                                goto done;
@@ -5360,20 +5392,7 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
                                cnic_ulp_start(dev);
                }
 
-               rcu_read_lock();
-               for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
-                       struct cnic_ulp_ops *ulp_ops;
-                       void *ctx;
-
-                       ulp_ops = rcu_dereference(cp->ulp_ops[if_type]);
-                       if (!ulp_ops || !ulp_ops->indicate_netevent)
-                               continue;
-
-                       ctx = cp->ulp_handle[if_type];
-
-                       ulp_ops->indicate_netevent(ctx, event);
-               }
-               rcu_read_unlock();
+               cnic_rcv_netevent(cp, event, 0);
 
                if (event == NETDEV_GOING_DOWN) {
                        cnic_ulp_stop(dev);
@@ -5389,6 +5408,19 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
                        goto done;
                }
                cnic_put(dev);
+       } else {
+               struct net_device *realdev;
+               u16 vid;
+
+               vid = cnic_get_vlan(netdev, &realdev);
+               if (realdev) {
+                       dev = cnic_from_netdev(realdev);
+                       if (dev) {
+                               vid |= VLAN_TAG_PRESENT;
+                               cnic_rcv_netevent(dev->cnic_priv, event, vid);
+                               cnic_put(dev);
+                       }
+               }
        }
 done:
        return NOTIFY_DONE;