Add bnx2i driver.
Subsystems (4)
cover Add bnx2i driver.
James, the next 4 patches are our latest to add the bnx2i driver. We've fixed up all the issues that Mike brought up. Please consider applying them to scsi-misc-2.6.
Thanks.
A message that is not in the archive (sent off-list or not yet received): 1243113110-29635-1-git-send-email-mchan-dY08KVG/lbpWk0Htik3J/[email protected]
PATCH 3/4 cnic: Add new Broadcom CNIC driver.
The CNIC driver controls BNX2 hardware rings and resources used by iSCSI. Most hardware resources for iSCSI are separate from those used for ethernet networking.
iSCSI uses a separate MAC address and IP address. The CNIC driver creates a UIO interface to handle the non-offloaded packets such as ARP, etc in userspace.
--- drivers/net/Kconfig | 11 + drivers/net/Makefile | 1 + drivers/net/cnic.c | 2715 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/cnic.h | 299 ++++++ drivers/net/cnic_defs.h | 580 ++++++++++ drivers/net/cnic_if.h | 299 ++++++ 6 files changed, 3905 insertions(+), 0 deletions(-) create mode 100644 drivers/net/cnic.c create mode 100644 drivers/net/cnic.h create mode 100644 drivers/net/cnic_defs.h create mode 100644 drivers/net/cnic_if.h
drivers/net/Kconfig +11 -0
@@ -2264,6 +2264,17 @@ config BNX2 To compile this driver as a module, choose M here: the module will be called bnx2. This is recommended. +config CNIC + tristate "Broadcom CNIC support" + depends on BNX2 + depends on UIO + help + This driver supports offload features of Broadcom NetXtremeII + gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called cnic. This is recommended. + config SPIDER_NET tristate "Spider Gigabit Ethernet driver" depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
drivers/net/Makefile +1 -0
@@ -73,6 +73,7 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_BNX2) += bnx2.o +obj-$(CONFIG_CNIC) += cnic.o obj-$(CONFIG_BNX2X) += bnx2x.o bnx2x-objs := bnx2x_main.o bnx2x_link.o spidernet-y += spider_net.o spider_net_ethtool.o
drivers/net/cnic.c new file +2715 -0
2,715 lines not on this page · raw message
drivers/net/cnic.h new file +299 -0
261 lines not on this page · raw message
drivers/net/cnic_defs.h new file +580 -0
580 lines not on this page · raw message
drivers/net/cnic_if.h new file +299 -0
299 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.5.6.GIT
Part of the diff is not shown here. View the raw message.
Re: [PATCH 3/4] cnic: Add new Broadcom CNIC driver.
Quoted 15 lines · Michael Chan
The CNIC driver controls BNX2 hardware rings and resources used by iSCSI. Most hardware resources for iSCSI are separate from those used for ethernet networking.
iSCSI uses a separate MAC address and IP address. The CNIC driver creates a UIO interface to handle the non-offloaded packets such as ARP, etc in userspace.
drivers/net/cnic.c new file +6
-0+static int cnic_alloc_context (struct cnic_dev *dev) +{ +struct cnic_local *cp = dev->cnic_priv; + +if (CHIP_NUM (cp) ==CHIP_NUM_5709 ) { +int i, k, arr_size;
drivers/net/cnic.c line 696
Quoted 10 lines
drivers/net/cnic.c new file +10
-0+ + cp->ctx_blk_size =BCM_PAGE_SIZE ; + cp->cids_per_blk =BCM_PAGE_SIZE /128 ; + arr_size =BNX2_MAX_CID / cp->cids_per_blk * +sizeof (struct cnic_ctx ); + cp->ctx_arr =kmalloc (arr_size,GFP_KERNEL ); +if (cp->ctx_arr ==NULL ) +return -ENOMEM ; + +memset (cp->ctx_arr,0 , arr_size);
cp->ctx_arr = kzalloc(arr_size, GFP_KERNEL);
Quoted 1,116 lines
drivers/net/cnic.c new file +121
-0+ k =0 ; +for (i =0 ; i <2 ; i++) { +u32 j, reg, off, lo, hi; + +if (i ==0 ) + off =BNX2_PG_CTX_MAP ; +else + off =BNX2_ISCSI_CTX_MAP ; + + reg =cnic_reg_rd_ind (dev, off); + lo = reg >>16 ; + hi = reg &0xffff ; +for (j = lo; j < hi; j += cp->cids_per_blk, k++) + cp->ctx_arr[k].cid = j; + } + + cp->ctx_blks = k; +if (cp->ctx_blks >= (BNX2_MAX_CID / cp->cids_per_blk)) { + cp->ctx_blks =0 ; +return -ENOMEM ; + } + +for (i =0 ; i < cp->ctx_blks; i++) { + cp->ctx_arr[i].ctx = +pci_alloc_consistent (dev->pcidev,BCM_PAGE_SIZE , + &cp->ctx_arr[i].mapping); +if (cp->ctx_arr[i].ctx ==NULL ) +return -ENOMEM ; + } + } +return 0 ; +} + +static int cnic_alloc_bnx2_resc (struct cnic_dev *dev) +{ +struct cnic_local *cp = dev->cnic_priv; +struct uio_info *uinfo; +int ret; + + ret =cnic_alloc_dma (dev, &cp->kwq_info,KWQ_PAGE_CNT ,1 ); +if (ret) + goto error; + cp->kwq = (struct kwqe **) cp->kwq_info.pg_arr; + + ret =cnic_alloc_dma (dev, &cp->kcq_info,KCQ_PAGE_CNT ,1 ); +if (ret) + goto error; + cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr; + + ret =cnic_alloc_context (dev); +if (ret) + goto error; + + cp->l2_ring_size =2 *BCM_PAGE_SIZE ; + cp->l2_ring =pci_alloc_consistent (dev->pcidev, cp->l2_ring_size, + &cp->l2_ring_map); +if (!cp->l2_ring) + goto error; + + cp->l2_buf_size = (cp->l2_rx_ring_size +1 ) * cp->l2_single_buf_size; + cp->l2_buf_size =PAGE_ALIGN (cp->l2_buf_size); + cp->l2_buf =pci_alloc_consistent (dev->pcidev, cp->l2_buf_size, + &cp->l2_buf_map); +if (!cp->l2_buf) + goto error; + + uinfo =kzalloc (sizeof (*uinfo),GFP_ATOMIC ); +if (!uinfo) + goto error; + + uinfo->mem[0 ].addr = dev->netdev->base_addr; + uinfo->mem[0 ].internal_addr = dev->regview; + uinfo->mem[0 ].size = dev->netdev->mem_end - dev->netdev->mem_start; + uinfo->mem[0 ].memtype =UIO_MEM_PHYS ; + + uinfo->mem[1 ].addr = (unsigned long ) cp->status_blk &PAGE_MASK ; +if (cp->ethdev->drv_state &CNIC_DRV_STATE_USING_MSIX ) + uinfo->mem[1 ].size =BNX2_SBLK_MSIX_ALIGN_SIZE *9 ; +else + uinfo->mem[1 ].size =BNX2_SBLK_MSIX_ALIGN_SIZE ; + uinfo->mem[1 ].memtype =UIO_MEM_LOGICAL ; + + uinfo->mem[2 ].addr = (unsigned long ) cp->l2_ring; + uinfo->mem[2 ].size = cp->l2_ring_size; + uinfo->mem[2 ].memtype =UIO_MEM_LOGICAL ; + + uinfo->mem[3 ].addr = (unsigned long ) cp->l2_buf; + uinfo->mem[3 ].size = cp->l2_buf_size; + uinfo->mem[3 ].memtype =UIO_MEM_LOGICAL ; + + uinfo->name ="bnx2_cnic" ; + uinfo->version =CNIC_MODULE_VERSION ; + uinfo->irq =UIO_IRQ_CUSTOM ; + + uinfo->open = cnic_uio_open; + uinfo->release = cnic_uio_close; + + uinfo->priv = dev; + + ret =uio_register_device (&dev->pcidev->dev, uinfo); +if (ret) { +kfree (uinfo); + goto error; + } + + cp->cnic_uinfo = uinfo; + +return 0 ; + +error: +cnic_free_resc (dev); +return ret; +} + +static inline u32 cnic_kwq_avail (struct cnic_local *cp) +{ +return cp->max_kwq_idx - + ((cp->kwq_prod_idx - cp->kwq_con_idx) & cp->max_kwq_idx); +} + +static int cnic_submit_bnx2_kwqes(struct cnic_dev *dev, struct kwqe*wqes[], + u32
num_wqes)drivers/net/cnic.c new file +707
-0+{ +struct cnic_local *cp = dev->cnic_priv; +struct kwqe *prod_qe; +u16 prod, sw_prod, i; + +if (!test_bit (CNIC_F_CNIC_UP , &dev->flags)) +return -EAGAIN ;/* bnx2 is down */ + +spin_lock_bh (&cp->cnic_ulp_lock); +if (num_wqes >cnic_kwq_avail (cp) && + !(cp->cnic_local_flags &CNIC_LCL_FL_KWQ_INIT )) { +spin_unlock_bh (&cp->cnic_ulp_lock); +return -EAGAIN ; + } + + cp->cnic_local_flags &= ~CNIC_LCL_FL_KWQ_INIT ; + + prod = cp->kwq_prod_idx; + sw_prod = prod &MAX_KWQ_IDX ; +for (i =0 ; i < num_wqes; i++) { + prod_qe = &cp->kwq[KWQ_PG (sw_prod)][KWQ_IDX (sw_prod)]; +memcpy (prod_qe, wqes[i],sizeof (struct kwqe )); + prod++; + sw_prod = prod &MAX_KWQ_IDX ; + } + cp->kwq_prod_idx = prod; + +CNIC_WR16 (dev, cp->kwq_io_addr, cp->kwq_prod_idx); + +spin_unlock_bh (&cp->cnic_ulp_lock); +return 0 ; +} + +static void service_kcqes (struct cnic_dev *dev,int num_cqes) +{ +struct cnic_local *cp = dev->cnic_priv; +int i, j; + + i =0 ; + j =1 ; +while (num_cqes) { +struct cnic_ulp_ops *ulp_ops; +int ulp_type; +u32 kcqe_op_flag = cp->completed_kcq[i]->kcqe_op_flag; +u32 kcqe_layer = kcqe_op_flag &KCQE_FLAGS_LAYER_MASK ; + +if (unlikely (kcqe_op_flag &KCQE_RAMROD_COMPLETION )) +cnic_kwq_completion (dev,1 ); + +while (j < num_cqes) { +u32 next_op = cp->completed_kcq[i + j]->kcqe_op_flag; + +if ((next_op &KCQE_FLAGS_LAYER_MASK ) != kcqe_layer) +break ; + +if (unlikely (next_op &KCQE_RAMROD_COMPLETION )) +cnic_kwq_completion (dev,1 ); + j++; + } + +if (kcqe_layer ==KCQE_FLAGS_LAYER_MASK_L5_RDMA ) + ulp_type =CNIC_ULP_RDMA ; +else if (kcqe_layer ==KCQE_FLAGS_LAYER_MASK_L5_ISCSI ) + ulp_type =CNIC_ULP_ISCSI ; +else if (kcqe_layer ==KCQE_FLAGS_LAYER_MASK_L4 ) + ulp_type =CNIC_ULP_L4 ; +else if (kcqe_layer ==KCQE_FLAGS_LAYER_MASK_L2 ) + goto end; +else { + printk(KERN_ERR PFX "%s: Unknown type of KCQE(0x%x)\n", + dev->netdev->name, kcqe_op_flag); + goto end; + } + +rcu_read_lock (); + ulp_ops =rcu_dereference (cp->ulp_ops[ulp_type]); +if (likely (ulp_ops)) { + ulp_ops->indicate_kcqes (cp->ulp_handle[ulp_type], + cp->completed_kcq + i, j); + } +rcu_read_unlock (); +end: + num_cqes -= j; + i += j; + j =1 ; + } +return ; +} + +static u16 cnic_bnx2_next_idx (u16 idx) +{ +return idx +1 ; +} + +static u16 cnic_bnx2_hw_idx (u16 idx) +{ +return idx; +} + +static int cnic_get_kcqes (struct cnic_dev *dev,u16 hw_prod,u16 *sw_prod) +{ +struct cnic_local *cp = dev->cnic_priv; +u16 i, ri, last; +struct kcqe *kcqe; +int kcqe_cnt =0 , last_cnt =0 ; + + i = ri = last = *sw_prod; + ri &=MAX_KCQ_IDX ; + +while ((i != hw_prod) && (kcqe_cnt <MAX_COMPLETED_KCQE )) { + kcqe = &cp->kcq[KCQ_PG (ri)][KCQ_IDX (ri)]; + cp->completed_kcq[kcqe_cnt++] = kcqe; + i = cp->next_idx (i); + ri = i &MAX_KCQ_IDX ; +if (likely (!(kcqe->kcqe_op_flag &KCQE_FLAGS_NEXT ))) { + last_cnt = kcqe_cnt; + last = i; + } + } + + *sw_prod = last; +return last_cnt; +} + +static void cnic_chk_bnx2_pkt_rings (struct cnic_local *cp) +{ +u16 rx_cons = *cp->rx_cons_ptr; +u16 tx_cons = *cp->tx_cons_ptr; + +if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) { + cp->tx_cons = tx_cons; + cp->rx_cons = rx_cons; +uio_event_notify (cp->cnic_uinfo); + } +} + +static int cnic_service_bnx2 (void *data,void *status_blk) +{ +struct cnic_dev *dev = data; +struct status_block *sblk = status_blk; +struct cnic_local *cp = dev->cnic_priv; +u32 status_idx = sblk->status_idx; +u16 hw_prod, sw_prod; +int kcqe_cnt; + +if (unlikely (!test_bit (CNIC_F_CNIC_UP , &dev->flags))) +return status_idx; + + cp->kwq_con_idx = *cp->kwq_con_idx_ptr; + + hw_prod = sblk->status_completion_producer_index; + sw_prod = cp->kcq_prod_idx; +while (sw_prod != hw_prod) { + kcqe_cnt =cnic_get_kcqes (dev, hw_prod, &sw_prod); +if (kcqe_cnt ==0 ) + goto done; + +service_kcqes (dev, kcqe_cnt); + +/* Tell compiler that status_blk fields can change. */ +barrier (); +if (status_idx != sblk->status_idx) { + status_idx = sblk->status_idx; + cp->kwq_con_idx = *cp->kwq_con_idx_ptr; + hw_prod = sblk->status_completion_producer_index; + }else +break ; + } + +done: +CNIC_WR16 (dev, cp->kcq_io_addr, sw_prod); + + cp->kcq_prod_idx = sw_prod; + +cnic_chk_bnx2_pkt_rings (cp); +return status_idx; +} + +static void cnic_service_bnx2_msix (unsigned long data) +{ +struct cnic_dev *dev = (struct cnic_dev *) data; +struct cnic_local *cp = dev->cnic_priv; +struct status_block_msix *status_blk = cp->bnx2_status_blk; +u32 status_idx = status_blk->status_idx; +u16 hw_prod, sw_prod; +int kcqe_cnt; + + cp->kwq_con_idx = status_blk->status_cmd_consumer_index; + + hw_prod = status_blk->status_completion_producer_index; + sw_prod = cp->kcq_prod_idx; +while (sw_prod != hw_prod) { + kcqe_cnt =cnic_get_kcqes (dev, hw_prod, &sw_prod); +if (kcqe_cnt ==0 ) + goto done; + +service_kcqes (dev, kcqe_cnt); + +/* Tell compiler that status_blk fields can change. */ +barrier (); +if (status_idx != status_blk->status_idx) { + status_idx = status_blk->status_idx; + cp->kwq_con_idx = status_blk->status_cmd_consumer_index; + hw_prod = status_blk->status_completion_producer_index; + }else +break ; + } + +done: +CNIC_WR16 (dev, cp->kcq_io_addr, sw_prod); + cp->kcq_prod_idx = sw_prod; + +cnic_chk_bnx2_pkt_rings (cp); + + cp->last_status_idx = status_idx; +CNIC_WR (dev,BNX2_PCICFG_INT_ACK_CMD , cp->int_num | +BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx); +} + +static irqreturn_t cnic_irq (int irq,void *dev_instance) +{ +struct cnic_dev *dev = dev_instance; +struct cnic_local *cp = dev->cnic_priv; +u16 prod = cp->kcq_prod_idx &MAX_KCQ_IDX ; + +if (cp->ack_int) + cp->ack_int (dev); + +prefetch (cp->status_blk); +prefetch (&cp->kcq[KCQ_PG (prod)][KCQ_IDX (prod)]); + +if (likely (test_bit (CNIC_F_CNIC_UP , &dev->flags))) +tasklet_schedule (&cp->cnic_irq_task); + +return IRQ_HANDLED ; +} + +static void cnic_ulp_stop (struct cnic_dev *dev) +{ +struct cnic_local *cp = dev->cnic_priv; +int if_type; + +rcu_read_lock (); +for (if_type =0 ; if_type <MAX_CNIC_ULP_TYPE ; if_type++) { +struct cnic_ulp_ops *ulp_ops; + + ulp_ops =rcu_dereference (cp->ulp_ops[if_type]); +if (!ulp_ops) +continue ; + +if (test_and_clear_bit (ULP_F_START , &cp->ulp_flags[if_type])) + ulp_ops->cnic_stop (cp->ulp_handle[if_type]); + } +rcu_read_unlock (); +} + +static void cnic_ulp_start (struct cnic_dev *dev) +{ +struct cnic_local *cp = dev->cnic_priv; +int if_type; + +rcu_read_lock (); +for (if_type =0 ; if_type <MAX_CNIC_ULP_TYPE ; if_type++) { +struct cnic_ulp_ops *ulp_ops; + + ulp_ops =rcu_dereference (cp->ulp_ops[if_type]); +if (!ulp_ops || !ulp_ops->cnic_start) +continue ; + +if (!test_and_set_bit (ULP_F_START , &cp->ulp_flags[if_type])) + ulp_ops->cnic_start (cp->ulp_handle[if_type]); + } +rcu_read_unlock (); +} + +static int cnic_ctl (void *data,struct cnic_ctl_info *info) +{ +struct cnic_dev *dev = data; + +switch (info->cmd) { +case CNIC_CTL_STOP_CMD : +cnic_hold (dev); +mutex_lock (&cnic_lock); + +cnic_ulp_stop (dev); +cnic_stop_hw (dev); + +mutex_unlock (&cnic_lock); +cnic_put (dev); +break ; +case CNIC_CTL_START_CMD : +cnic_hold (dev); +mutex_lock (&cnic_lock); + +if (!cnic_start_hw (dev)) +cnic_ulp_start (dev); + +mutex_unlock (&cnic_lock); +cnic_put (dev); +break ; +default : +return -EINVAL ; + } +return 0 ; +} + +static void cnic_ulp_init (struct cnic_dev *dev) +{ +int i; +struct cnic_local *cp = dev->cnic_priv; + +rcu_read_lock (); +for (i =0 ; i <MAX_CNIC_ULP_TYPE_EXT ; i++) { +struct cnic_ulp_ops *ulp_ops; + + ulp_ops =rcu_dereference (cnic_ulp_tbl[i]); +if (!ulp_ops || !ulp_ops->cnic_init) +continue ; + +if (!test_and_set_bit (ULP_F_INIT , &cp->ulp_flags[i])) + ulp_ops->cnic_init (dev); + + } +rcu_read_unlock (); +} + +static void cnic_ulp_exit (struct cnic_dev *dev) +{ +int i; +struct cnic_local *cp = dev->cnic_priv; + +rcu_read_lock (); +for (i =0 ; i <MAX_CNIC_ULP_TYPE_EXT ; i++) { +struct cnic_ulp_ops *ulp_ops; + + ulp_ops =rcu_dereference (cnic_ulp_tbl[i]); +if (!ulp_ops || !ulp_ops->cnic_exit) +continue ; + +if (test_and_clear_bit (ULP_F_INIT , &cp->ulp_flags[i])) + ulp_ops->cnic_exit (dev); + + } +rcu_read_unlock (); +} + +static int cnic_cm_offload_pg (struct cnic_sock *csk) +{ +struct cnic_dev *dev = csk->dev; +struct l4_kwq_offload_pg *l4kwqe; +struct kwqe *wqes[1 ]; + + l4kwqe = (struct l4_kwq_offload_pg *) &csk->kwqe1; +memset (l4kwqe,0 ,sizeof (*l4kwqe)); + wqes[0 ] = (struct kwqe *) l4kwqe; + + l4kwqe->op_code =L4_KWQE_OPCODE_VALUE_OFFLOAD_PG ; + l4kwqe->flags = +L4_LAYER_CODE <<L4_KWQ_OFFLOAD_PG_LAYER_CODE_SHIFT ; + l4kwqe->l2hdr_nbytes =ETH_HLEN ; + + l4kwqe->da0 = csk->ha[0 ]; + l4kwqe->da1 = csk->ha[1 ]; + l4kwqe->da2 = csk->ha[2 ]; + l4kwqe->da3 = csk->ha[3 ]; + l4kwqe->da4 = csk->ha[4 ]; + l4kwqe->da5 = csk->ha[5 ]; + + l4kwqe->sa0 = dev->mac_addr[0 ]; + l4kwqe->sa1 = dev->mac_addr[1 ]; + l4kwqe->sa2 = dev->mac_addr[2 ]; + l4kwqe->sa3 = dev->mac_addr[3 ]; + l4kwqe->sa4 = dev->mac_addr[4 ]; + l4kwqe->sa5 = dev->mac_addr[5 ]; + + l4kwqe->etype =ETH_P_IP ; + l4kwqe->ipid_count =DEF_IPID_COUNT ; + l4kwqe->host_opaque = csk->l5_cid; + +if (csk->vlan_id) { + l4kwqe->pg_flags |=L4_KWQ_OFFLOAD_PG_VLAN_TAGGING ; + l4kwqe->vlan_tag = csk->vlan_id; + l4kwqe->l2hdr_nbytes +=4 ; + } + +return dev->submit_kwqes (dev, wqes,1 ); +} + +static int cnic_cm_update_pg (struct cnic_sock *csk) +{ +struct cnic_dev *dev = csk->dev; +struct l4_kwq_update_pg *l4kwqe; +struct kwqe *wqes[1 ]; + + l4kwqe = (struct l4_kwq_update_pg *) &csk->kwqe1; +memset (l4kwqe,0 ,sizeof (*l4kwqe)); + wqes[0 ] = (struct kwqe *) l4kwqe; + + l4kwqe->opcode =L4_KWQE_OPCODE_VALUE_UPDATE_PG ; + l4kwqe->flags = +L4_LAYER_CODE <<L4_KWQ_UPDATE_PG_LAYER_CODE_SHIFT ; + l4kwqe->pg_cid = csk->pg_cid; + + l4kwqe->da0 = csk->ha[0 ]; + l4kwqe->da1 = csk->ha[1 ]; + l4kwqe->da2 = csk->ha[2 ]; + l4kwqe->da3 = csk->ha[3 ]; + l4kwqe->da4 = csk->ha[4 ]; + l4kwqe->da5 = csk->ha[5 ]; + + l4kwqe->pg_host_opaque = csk->l5_cid; + l4kwqe->pg_valids =L4_KWQ_UPDATE_PG_VALIDS_DA ; + +return dev->submit_kwqes (dev, wqes,1 ); +} + +static int cnic_cm_upload_pg (struct cnic_sock *csk) +{ +struct cnic_dev *dev = csk->dev; +struct l4_kwq_upload *l4kwqe; +struct kwqe *wqes[1 ]; + + l4kwqe = (struct l4_kwq_upload *) &csk->kwqe1; +memset (l4kwqe,0 ,sizeof (*l4kwqe)); + wqes[0 ] = (struct kwqe *) l4kwqe; + + l4kwqe->opcode =L4_KWQE_OPCODE_VALUE_UPLOAD_PG ; + l4kwqe->flags = +L4_LAYER_CODE <<L4_KWQ_UPLOAD_LAYER_CODE_SHIFT ; + l4kwqe->cid = csk->pg_cid; + +return dev->submit_kwqes (dev, wqes,1 ); +} + +static int cnic_cm_conn_req (struct cnic_sock *csk) +{ +struct cnic_dev *dev = csk->dev; +struct l4_kwq_connect_req1 *l4kwqe1; +struct l4_kwq_connect_req2 *l4kwqe2; +struct l4_kwq_connect_req3 *l4kwqe3; +struct kwqe *wqes[3 ]; +u8 tcp_flags =0 ; +int num_wqes =2 ; + + l4kwqe1 = (struct l4_kwq_connect_req1 *) &csk->kwqe1; + l4kwqe2 = (struct l4_kwq_connect_req2 *) &csk->kwqe2; + l4kwqe3 = (struct l4_kwq_connect_req3 *) &csk->kwqe3; +memset (l4kwqe1,0 ,sizeof (*l4kwqe1)); +memset (l4kwqe2,0 ,sizeof (*l4kwqe2)); +memset (l4kwqe3,0 ,sizeof (*l4kwqe3)); + + l4kwqe3->op_code =L4_KWQE_OPCODE_VALUE_CONNECT3 ; + l4kwqe3->flags = +L4_LAYER_CODE <<L4_KWQ_CONNECT_REQ3_LAYER_CODE_SHIFT ; + l4kwqe3->ka_timeout = csk->ka_timeout; + l4kwqe3->ka_interval = csk->ka_interval; + l4kwqe3->ka_max_probe_count = csk->ka_max_probe_count; + l4kwqe3->tos = csk->tos; + l4kwqe3->ttl = csk->ttl; + l4kwqe3->snd_seq_scale = csk->snd_seq_scale; + l4kwqe3->pmtu = csk->mtu; + l4kwqe3->rcv_buf = csk->rcv_buf; + l4kwqe3->snd_buf = csk->snd_buf; + l4kwqe3->seed = csk->seed; + + wqes[0 ] = (struct kwqe *) l4kwqe1; +if (test_bit (SK_F_IPV6 , &csk->flags)) { + wqes[1 ] = (struct kwqe *) l4kwqe2; + wqes[2 ] = (struct kwqe *) l4kwqe3; + num_wqes =3 ; + + l4kwqe1->conn_flags =L4_KWQ_CONNECT_REQ1_IP_V6 ; + l4kwqe2->op_code =L4_KWQE_OPCODE_VALUE_CONNECT2 ; + l4kwqe2->flags = +L4_KWQ_CONNECT_REQ2_LINKED_WITH_NEXT | +L4_LAYER_CODE <<L4_KWQ_CONNECT_REQ2_LAYER_CODE_SHIFT ; + l4kwqe2->src_ip_v6_2 =be32_to_cpu (csk->src_ip[1 ]); + l4kwqe2->src_ip_v6_3 =be32_to_cpu (csk->src_ip[2 ]); + l4kwqe2->src_ip_v6_4 =be32_to_cpu (csk->src_ip[3 ]); + l4kwqe2->dst_ip_v6_2 =be32_to_cpu (csk->dst_ip[1 ]); + l4kwqe2->dst_ip_v6_3 =be32_to_cpu (csk->dst_ip[2 ]); + l4kwqe2->dst_ip_v6_4 =be32_to_cpu (csk->dst_ip[3 ]); + l4kwqe3->mss = l4kwqe3->pmtu -sizeof (struct ipv6hdr ) - +sizeof (struct tcphdr ); + }else { + wqes[1 ] = (struct kwqe *) l4kwqe3; + l4kwqe3->mss = l4kwqe3->pmtu -sizeof (struct iphdr ) - +sizeof (struct tcphdr ); + } + + l4kwqe1->op_code =L4_KWQE_OPCODE_VALUE_CONNECT1 ; + l4kwqe1->flags = + (L4_LAYER_CODE <<L4_KWQ_CONNECT_REQ1_LAYER_CODE_SHIFT ) | +L4_KWQ_CONNECT_REQ3_LINKED_WITH_NEXT ; + l4kwqe1->cid = csk->cid; + l4kwqe1->pg_cid = csk->pg_cid; + l4kwqe1->src_ip =be32_to_cpu (csk->src_ip[0 ]); + l4kwqe1->dst_ip =be32_to_cpu (csk->dst_ip[0 ]); + l4kwqe1->src_port =be16_to_cpu (csk->src_port); + l4kwqe1->dst_port =be16_to_cpu (csk->dst_port); +if (csk->tcp_flags &SK_TCP_NO_DELAY_ACK ) + tcp_flags |=L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK ; +if (csk->tcp_flags &SK_TCP_KEEP_ALIVE ) + tcp_flags |=L4_KWQ_CONNECT_REQ1_KEEP_ALIVE ; +if (csk->tcp_flags &SK_TCP_NAGLE ) + tcp_flags |=L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE ; +if (csk->tcp_flags &SK_TCP_TIMESTAMP ) + tcp_flags |=L4_KWQ_CONNECT_REQ1_TIME_STAMP ; +if (csk->tcp_flags &SK_TCP_SACK ) + tcp_flags |=L4_KWQ_CONNECT_REQ1_SACK ; +if (csk->tcp_flags &SK_TCP_SEG_SCALING ) + tcp_flags |=L4_KWQ_CONNECT_REQ1_SEG_SCALING ; + + l4kwqe1->tcp_flags = tcp_flags; + +return dev->submit_kwqes (dev, wqes, num_wqes); +} + +static int cnic_cm_close_req (struct cnic_sock *csk) +{ +struct cnic_dev *dev = csk->dev; +struct l4_kwq_close_req *l4kwqe; +struct kwqe *wqes[1 ]; + + l4kwqe = (struct l4_kwq_close_req *) &csk->kwqe2; +memset (l4kwqe,0 ,sizeof (*l4kwqe)); + wqes[0 ] = (struct kwqe *) l4kwqe; + + l4kwqe->op_code =L4_KWQE_OPCODE_VALUE_CLOSE ; + l4kwqe->flags =L4_LAYER_CODE <<L4_KWQ_CLOSE_REQ_LAYER_CODE_SHIFT ; + l4kwqe->cid = csk->cid; + +return dev->submit_kwqes (dev, wqes,1 ); +} + +static int cnic_cm_abort_req (struct cnic_sock *csk) +{ +struct cnic_dev *dev = csk->dev; +struct l4_kwq_reset_req *l4kwqe; +struct kwqe *wqes[1 ]; + + l4kwqe = (struct l4_kwq_reset_req *) &csk->kwqe2; +memset (l4kwqe,0 ,sizeof (*l4kwqe)); + wqes[0 ] = (struct kwqe *) l4kwqe; + + l4kwqe->op_code =L4_KWQE_OPCODE_VALUE_RESET ; + l4kwqe->flags =L4_LAYER_CODE <<L4_KWQ_RESET_REQ_LAYER_CODE_SHIFT ; + l4kwqe->cid = csk->cid; + +return dev->submit_kwqes (dev, wqes,1 ); +} + +static int cnic_cm_create (struct cnic_dev *dev,int ulp_type,u32 cid, +u32 l5_cid,struct cnic_sock **csk,void *context) +{ +struct cnic_local *cp = dev->cnic_priv; +struct cnic_sock *csk1; + +if (l5_cid >=MAX_CM_SK_TBL_SZ ) +return -EINVAL ; + + csk1 = &cp->csk_tbl[l5_cid]; +if (atomic_read (&csk1->ref_count)) +return -EAGAIN ; + +if (test_and_set_bit (SK_F_INUSE , &csk1->flags)) +return -EBUSY ; + + csk1->dev = dev; + csk1->cid = cid; + csk1->l5_cid = l5_cid; + csk1->ulp_type = ulp_type; + csk1->context = context; + + csk1->ka_timeout =DEF_KA_TIMEOUT ; + csk1->ka_interval =DEF_KA_INTERVAL ; + csk1->ka_max_probe_count =DEF_KA_MAX_PROBE_COUNT ; + csk1->tos =DEF_TOS ; + csk1->ttl =DEF_TTL ; + csk1->snd_seq_scale =DEF_SND_SEQ_SCALE ; + csk1->rcv_buf =DEF_RCV_BUF ; + csk1->snd_buf =DEF_SND_BUF ; + csk1->seed =DEF_SEED ; + + *csk = csk1; +return 0 ; +} + +static void cnic_cm_cleanup (struct cnic_sock *csk) +{ +if (csk->src_port) { +struct cnic_dev *dev = csk->dev; +struct cnic_local *cp = dev->cnic_priv; + +cnic_free_id (&cp->csk_port_tbl, csk->src_port); + csk->src_port =0 ; + } +} + +static void cnic_close_conn (struct cnic_sock *csk) +{ +if (test_bit (SK_F_PG_OFFLD_COMPLETE , &csk->flags)) { +cnic_cm_upload_pg (csk); +clear_bit (SK_F_PG_OFFLD_COMPLETE , &csk->flags); + } +cnic_cm_cleanup (csk); +} + +static int cnic_cm_destroy (struct cnic_sock *csk) +{ +if (!cnic_in_use (csk)) +return -EINVAL ; + +csk_hold (csk); +clear_bit (SK_F_INUSE , &csk->flags); +smp_mb__after_clear_bit (); +while (atomic_read (&csk->ref_count) !=1 ) +msleep (1 ); +cnic_cm_cleanup (csk); + + csk->flags =0 ; +csk_put (csk); +return 0 ; +} + +static inline u16 cnic_get_vlan (struct net_device *dev, +struct net_device **vlan_dev) +{ +if (dev->priv_flags &IFF_802_1Q_VLAN ) { + *vlan_dev =vlan_dev_real_dev (dev); +return vlan_dev_vlan_id (dev); + } + *vlan_dev = dev; +return 0 ; +} + +static int cnic_get_v4_route (struct sockaddr_in *dst_addr, +struct dst_entry **dst) +{ +struct flowi fl; +int err; +struct rtable *rt; + +memset (&fl,0 ,sizeof (fl)); + fl.nl_u.ip4_u.daddr = dst_addr->sin_addr.s_addr; + + err =ip_route_output_key (&init_net, &rt, &fl); +if (!err) + *dst = &rt->u.dst; +return err; +} + +static int cnic_get_v6_route (struct sockaddr_in6 *dst_addr, +struct dst_entry **dst) +{ +#if defined(CONFIG_IPV6 ) || defined(CONFIG_IPV6_MODULE ) +struct flowi fl; + +memset (&fl,0 ,sizeof (fl)); +ipv6_addr_copy (&fl.fl6_dst, &dst_addr->sin6_addr); +if (ipv6_addr_type (&fl.fl6_dst) &IPV6_ADDR_LINKLOCAL ) + fl.oif = dst_addr->sin6_scope_id; + + *dst =ip6_route_output (&init_net,NULL , &fl); +if (*dst) +return 0 ; +#endif + +return -ENETUNREACH ; +} + +static struct cnic_dev *cnic_cm_select_dev (struct sockaddr_in *dst_addr, +int ulp_type) +{ +struct cnic_dev *dev =NULL ; +struct dst_entry *dst; +struct net_device *netdev =NULL ; +int err = -ENETUNREACH ; + +if (dst_addr->sin_family ==AF_INET ) + err =cnic_get_v4_route (dst_addr, &dst); +else if (dst_addr->sin_family ==AF_INET6 ) { +struct sockaddr_in6 *dst_addr6 = + (struct sockaddr_in6 *) dst_addr; + + err =cnic_get_v6_route (dst_addr6, &dst); + }else +return NULL ; + +if (err) +return NULL ; + +if (!dst->dev) + goto done; + +cnic_get_vlan (dst->dev, &netdev); + + dev =cnic_from_netdev (netdev); + +done: +dst_release (dst); +if (dev) +cnic_put (dev); +return dev; +} + +static int cnic_resolve_addr(struct cnic_sock *csk, struct cnic_sockaddr*saddr) +{
drivers/net/cnic.c new file +7
-0+struct cnic_dev *dev = csk->dev; +struct cnic_local *cp = dev->cnic_priv; + +return cnic_send_nlmsg (cp,ISCSI_KEVENT_PATH_REQ , csk); +} + +static int cnic_get_route(struct cnic_sock *csk, struct cnic_sockaddr*saddr) +{
drivers/net/cnic.c new file +85
-0+struct cnic_dev *dev = csk->dev; +struct cnic_local *cp = dev->cnic_priv; +int is_v6, err, rc = -ENETUNREACH ; +struct dst_entry *dst; +struct net_device *realdev; +u32 local_port; + +if (saddr->local.v6.sin6_family ==AF_INET6 && + saddr->remote.v6.sin6_family ==AF_INET6 ) + is_v6 =1 ; +else if (saddr->local.v4.sin_family ==AF_INET && + saddr->remote.v4.sin_family ==AF_INET ) + is_v6 =0 ; +else +return -EINVAL ; + +clear_bit (SK_F_IPV6 , &csk->flags); + +if (is_v6) { +#if defined(CONFIG_IPV6 ) || defined(CONFIG_IPV6_MODULE ) +set_bit (SK_F_IPV6 , &csk->flags); + err =cnic_get_v6_route (&saddr->remote.v6, &dst); +if (err) +return err; + +if (!dst || dst->error || !dst->dev) + goto err_out; + +memcpy (&csk->dst_ip[0 ], &saddr->remote.v6.sin6_addr, +sizeof (struct in6_addr )); + csk->dst_port = saddr->remote.v6.sin6_port; + local_port = saddr->local.v6.sin6_port; +#else +return rc; +#endif + + }else { + err =cnic_get_v4_route (&saddr->remote.v4, &dst); +if (err) +return err; + +if (!dst || dst->error || !dst->dev) + goto err_out; + + csk->dst_ip[0 ] = saddr->remote.v4.sin_addr.s_addr; + csk->dst_port = saddr->remote.v4.sin_port; + local_port = saddr->local.v4.sin_port; + } + + csk->vlan_id =cnic_get_vlan (dst->dev, &realdev); +if (realdev != dev->netdev) + goto err_out; + +if (local_port >=CNIC_LOCAL_PORT_MIN && + local_port <CNIC_LOCAL_PORT_MAX ) { +if (cnic_alloc_id (&cp->csk_port_tbl, local_port)) + local_port =0 ; + }else + local_port =0 ; + +if (!local_port) { + local_port =cnic_alloc_new_id (&cp->csk_port_tbl); +if (local_port ==-1 ) { + rc = -ENOMEM ; + goto err_out; + } + } + csk->src_port = local_port; + + csk->mtu =dst_mtu (dst); + rc =0 ; + +err_out: +dst_release (dst); +return rc; +} + +static void cnic_init_csk_state (struct cnic_sock *csk) +{ + csk->state =0 ; +clear_bit (SK_F_OFFLD_SCHED , &csk->flags); +clear_bit (SK_F_CLOSING , &csk->flags); +} + +static int cnic_cm_connect(struct cnic_sock *csk, struct cnic_sockaddr*saddr) +{
drivers/net/cnic.c new file +95
-0+int err =0 ; + +if (!cnic_in_use (csk)) +return -EINVAL ; + +if (test_and_set_bit (SK_F_CONNECT_START , &csk->flags)) +return -EINVAL ; + +cnic_init_csk_state (csk); + + err =cnic_get_route (csk, saddr); +if (err) + goto err_out; + + err =cnic_resolve_addr (csk, saddr); +if (!err) +return 0 ; + +err_out: +clear_bit (SK_F_CONNECT_START , &csk->flags); +return err; +} + +static int cnic_cm_abort (struct cnic_sock *csk) +{ +struct cnic_local *cp = csk->dev->cnic_priv; +u32 opcode; + +if (!cnic_in_use (csk)) +return -EINVAL ; + +if (cnic_abort_prep (csk)) +return cnic_cm_abort_req (csk); + +/* Getting here means that we haven't started connect, or +* connect was not successful. +*/ + + csk->state =L4_KCQE_OPCODE_VALUE_RESET_COMP ; +if (test_bit (SK_F_PG_OFFLD_COMPLETE , &csk->flags)) + opcode = csk->state; +else + opcode =L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD ; + cp->close_conn (csk, opcode); + +return 0 ; +} + +static int cnic_cm_close (struct cnic_sock *csk) +{ +if (!cnic_in_use (csk)) +return -EINVAL ; + +if (cnic_close_prep (csk)) { + csk->state =L4_KCQE_OPCODE_VALUE_CLOSE_COMP ; +return cnic_cm_close_req (csk); + } +return 0 ; +} + +static void cnic_cm_upcall (struct cnic_local *cp,struct cnic_sock *csk, +u8 opcode) +{ +struct cnic_ulp_ops *ulp_ops; +int ulp_type = csk->ulp_type; + +rcu_read_lock (); + ulp_ops =rcu_dereference (cp->ulp_ops[ulp_type]); +if (ulp_ops) { +if (opcode ==L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE ) + ulp_ops->cm_connect_complete (csk); +else if (opcode ==L4_KCQE_OPCODE_VALUE_CLOSE_COMP ) + ulp_ops->cm_close_complete (csk); +else if (opcode ==L4_KCQE_OPCODE_VALUE_RESET_RECEIVED ) + ulp_ops->cm_remote_abort (csk); +else if (opcode ==L4_KCQE_OPCODE_VALUE_RESET_COMP ) + ulp_ops->cm_abort_complete (csk); +else if (opcode ==L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED ) + ulp_ops->cm_remote_close (csk); + } +rcu_read_unlock (); +} + +static int cnic_cm_set_pg (struct cnic_sock *csk) +{ +if (cnic_offld_prep (csk)) { +if (test_bit (SK_F_PG_OFFLD_COMPLETE , &csk->flags)) +cnic_cm_update_pg (csk); +else +cnic_cm_offload_pg (csk); + } +return 0 ; +} + +static void cnic_cm_process_offld_pg(struct cnic_dev *dev, struct l4_kcq*kcqe) +{
drivers/net/cnic.c new file +76
-0+struct cnic_local *cp = dev->cnic_priv; +u32 l5_cid = kcqe->pg_host_opaque; +u8 opcode = kcqe->op_code; +struct cnic_sock *csk = &cp->csk_tbl[l5_cid]; + +csk_hold (csk); +if (!cnic_in_use (csk)) + goto done; + +if (opcode ==L4_KCQE_OPCODE_VALUE_UPDATE_PG ) { +clear_bit (SK_F_OFFLD_SCHED , &csk->flags); + goto done; + } + csk->pg_cid = kcqe->pg_cid; +set_bit (SK_F_PG_OFFLD_COMPLETE , &csk->flags); +cnic_cm_conn_req (csk); + +done: +csk_put (csk); +} + +static void cnic_cm_process_kcqe (struct cnic_dev *dev,struct kcqe *kcqe) +{ +struct cnic_local *cp = dev->cnic_priv; +struct l4_kcq *l4kcqe = (struct l4_kcq *) kcqe; +u8 opcode = l4kcqe->op_code; +u32 l5_cid; +struct cnic_sock *csk; + +if (opcode ==L4_KCQE_OPCODE_VALUE_OFFLOAD_PG || + opcode ==L4_KCQE_OPCODE_VALUE_UPDATE_PG ) { +cnic_cm_process_offld_pg (dev, l4kcqe); +return ; + } + + l5_cid = l4kcqe->conn_id; +if (opcode &0x80 ) + l5_cid = l4kcqe->cid; +if (l5_cid >=MAX_CM_SK_TBL_SZ ) +return ; + + csk = &cp->csk_tbl[l5_cid]; +csk_hold (csk); + +if (!cnic_in_use (csk)) { +csk_put (csk); +return ; + } + +switch (opcode) { +case L4_KCQE_OPCODE_VALUE_CONNECT_COMPLETE : +if (l4kcqe->status ==0 ) +set_bit (SK_F_OFFLD_COMPLETE , &csk->flags); + +smp_mb__before_clear_bit (); +clear_bit (SK_F_OFFLD_SCHED , &csk->flags); +cnic_cm_upcall (cp, csk, opcode); +break ; + +case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED : +if (test_and_clear_bit (SK_F_OFFLD_COMPLETE , &csk->flags)) + csk->state = opcode; +/* fall through */ +case L4_KCQE_OPCODE_VALUE_CLOSE_COMP : +case L4_KCQE_OPCODE_VALUE_RESET_COMP : + cp->close_conn (csk, opcode); +break ; + +case L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED : +cnic_cm_upcall (cp, csk, opcode); +break ; + } +csk_put (csk); +} + +static void cnic_cm_indicate_kcqe(void *data, struct kcqe *kcqe[], u32num) +{
drivers/net/cnic.c new file +19
-0+struct cnic_dev *dev = data; +int i; + +for (i =0 ; i < num; i++) +cnic_cm_process_kcqe (dev, kcqe[i]); +} + +static struct cnic_ulp_ops cm_ulp_ops = { + .indicate_kcqes = cnic_cm_indicate_kcqe, +}; + +static void cnic_cm_free_mem (struct cnic_dev *dev) +{ +struct cnic_local *cp = dev->cnic_priv; + +kfree (cp->csk_tbl); + cp->csk_tbl =NULL ; +cnic_free_id_tbl (&cp->csk_port_tbl); +}
drivers/net/cnic.c line 1823
Quoted 10 lines
drivers/net/cnic.c new file +10
-0+ +static int cnic_cm_alloc_mem (struct cnic_dev *dev) +{ +struct cnic_local *cp = dev->cnic_priv; + + cp->csk_tbl =kmalloc (sizeof (struct cnic_sock ) *MAX_CM_SK_TBL_SZ , +GFP_KERNEL ); +if (!cp->csk_tbl) +return -ENOMEM ; +memset (cp->csk_tbl,0 ,sizeof (struct cnic_sock ) *MAX_CM_SK_TBL_SZ );
cp->csk_tbl = kzalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ,
GFP_KERNEL);
There are some more of these.
Greetings,
Eike
Michael Chan
Acked-by David S. MillerRe: [PATCH 3/4] cnic: Add new Broadcom CNIC driver.
Quoted 5 lines · Rolf Eike Beer
cp->csk_tbl= kzalloc(sizeof(structcnic_sock) *MAX_CM_SK_TBL_SZ,GFP_KERNEL);There are some more of these.
Thanks. I've changed all of these to kzalloc().
Quoted 1 line
From
e7cbc3df66fb0b9c7036478be292f2db7be78153Mon Sep 17 00:00:00 2001
From: Michael Chan <[email protected]>
Date: Mon, 25 May 2009 22:28:35 -0700
Subject: [PATCH 3/4] cnic: Add new Broadcom CNIC driver.
The CNIC driver controls BNX2 hardware rings and resources used by iSCSI. Most hardware resources for iSCSI are separate from those used for ethernet networking.
iSCSI uses a separate MAC address and IP address. The CNIC driver creates a UIO interface to handle the non-offloaded packets such as ARP, etc in userspace.
--- drivers/net/Kconfig | 11 + drivers/net/Makefile | 1 + drivers/net/cnic.c | 2711 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/cnic.h | 299 ++++++ drivers/net/cnic_defs.h | 580 ++++++++++ drivers/net/cnic_if.h | 299 ++++++ 6 files changed, 3901 insertions(+), 0 deletions(-) create mode 100644 drivers/net/cnic.c create mode 100644 drivers/net/cnic.h create mode 100644 drivers/net/cnic_defs.h create mode 100644 drivers/net/cnic_if.h
drivers/net/Kconfig +11 -0
@@ -2264,6 +2264,17 @@ config BNX2 To compile this driver as a module, choose M here: the module will be called bnx2. This is recommended. +config CNIC + tristate "Broadcom CNIC support" + depends on BNX2 + depends on UIO + help + This driver supports offload features of Broadcom NetXtremeII + gigabit Ethernet cards. + + To compile this driver as a module, choose M here: the module + will be called cnic. This is recommended. + config SPIDER_NET tristate "Spider Gigabit Ethernet driver" depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
drivers/net/Makefile +1 -0
@@ -73,6 +73,7 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_BNX2) += bnx2.o +obj-$(CONFIG_CNIC) += cnic.o obj-$(CONFIG_BNX2X) += bnx2x.o bnx2x-objs := bnx2x_main.o bnx2x_link.o spidernet-y += spider_net.o spider_net_ethtool.o
drivers/net/cnic.c new file +2711 -0
2,711 lines not on this page · raw message
drivers/net/cnic.h new file +299 -0
265 lines not on this page · raw message
drivers/net/cnic_defs.h new file +580 -0
580 lines not on this page · raw message
drivers/net/cnic_if.h new file +299 -0
299 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.5.6.GIT
Part of the diff is not shown here. View the raw message.
Quoted 5 lines · Michael Chan
James, the next 4 patches are our latest to add the bnx2i driver. We've fixed up all the issues that Mike brought up. Please consider applying them to scsi-misc-2.6.
Hey James,
We forgot to cc you and the linux list on some other postings. Dave Miller had ackd the drivers/net parts of the patches here:
http://marc.info/?l=linux-netdev&m=124082705613349&w=2
and in the mail had said it was ok to send through the scsi tree.
There is just some tiny comment issue in one of the patches that I think is probably ok to fix up after the merge into scsi-misc. A code snippet got commented out when it should have got removed.
PATCH 1/4 iscsi class: Add new NETLINK_ISCSI messages for cnic/bnx2i driver.
In reply to Michael ChanAdd ISCSI_NETLINK messages for iSCSI NICs to get information such as path from userspace. Original iscsid messages are now always sent as multicast to group 1. The new messages are sent to group 2.
The multicast changes were made by Mike Christie.
--- drivers/scsi/scsi_transport_iscsi.c | 122 ++++++++++++++++++++++++---------- include/scsi/iscsi_if.h | 42 ++++++++++++ include/scsi/scsi_transport_iscsi.h | 5 ++ 3 files changed, 133 insertions(+), 36 deletions(-)
drivers/scsi/scsi_transport_iscsi.c +86 -36
@@ -37,7 +37,6 @@#define ISCSI_TRANSPORT_VERSION "2.0-870"struct iscsi_internal { -int daemon_pid;struct scsi_transport_template t;struct iscsi_transport *iscsi_transport;struct list_head list;
@@ -938,23 +937,9 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt) }static int -iscsi_broadcast_skb (struct sk_buff *skb,gfp_t gfp) +iscsi_multicast_skb (struct sk_buff *skb,uint32_t group,gfp_t gfp) { -return netlink_broadcast (nls, skb,0 ,1 , gfp); -} - -static int -iscsi_unicast_skb (struct sk_buff *skb,int pid) -{ -int rc; - - rc =netlink_unicast (nls, skb, pid,MSG_DONTWAIT ); -if (rc <0 ) { -printk (KERN_ERR "iscsi: can not unicast skb (%d)\n" , rc); -return rc; - } - -return 0 ; +return nlmsg_multicast (nls, skb,0 , group, gfp); } int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
@@ -980,7 +965,7 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,return -ENOMEM ; } - nlh =__nlmsg_put (skb, priv->daemon_pid,0 ,0 , (len -sizeof (*nlh)),0 ); + nlh =__nlmsg_put (skb,0 ,0 ,0 , (len -sizeof (*nlh)),0 ); ev =NLMSG_DATA (nlh);memset (ev,0 ,sizeof (*ev)); ev->transport_handle =iscsi_handle (conn->transport);
@@ -991,10 +976,45 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,memcpy (pdu, hdr,sizeof (struct iscsi_hdr ));memcpy (pdu +sizeof (struct iscsi_hdr ), data, data_size); -return iscsi_unicast_skb (skb, priv->daemon_pid); +return iscsi_multicast_skb (skb,ISCSI_NL_GRP_ISCSID ,GFP_ATOMIC ); }EXPORT_SYMBOL_GPL (iscsi_recv_pdu); +int iscsi_offload_mesg (struct Scsi_Host *shost, +struct iscsi_transport *transport,uint32_t type, +char *data,uint16_t data_size) +{ +struct nlmsghdr *nlh; +struct sk_buff *skb; +struct iscsi_uevent *ev; +int len =NLMSG_SPACE (sizeof (*ev) + data_size); + + skb =alloc_skb (len,GFP_NOIO ); +if (!skb) { +printk (KERN_ERR "can not deliver iscsi offload message:OOM\n" ); +return -ENOMEM ; + } + + nlh =__nlmsg_put (skb,0 ,0 ,0 , (len -sizeof (*nlh)),0 ); + ev =NLMSG_DATA (nlh); +memset (ev,0 ,sizeof (*ev)); + ev->type = type; + ev->transport_handle =iscsi_handle (transport); +switch (type) { +case ISCSI_KEVENT_PATH_REQ : + ev->r.req_path.host_no = shost->host_no; +break ; +case ISCSI_KEVENT_IF_DOWN : + ev->r.notify_if_down.host_no = shost->host_no; +break ; + } + +memcpy ((char *)ev +sizeof (*ev), data, data_size); + +return iscsi_multicast_skb (skb,ISCSI_NL_GRP_UIP ,GFP_NOIO ); +} +EXPORT_SYMBOL_GPL (iscsi_offload_mesg); +void iscsi_conn_error_event (struct iscsi_cls_conn *conn,enum iscsi_err error) {struct nlmsghdr *nlh;
@@ -1014,7 +1034,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)return ; } - nlh =__nlmsg_put (skb, priv->daemon_pid,0 ,0 , (len -sizeof (*nlh)),0 ); + nlh =__nlmsg_put (skb,0 ,0 ,0 , (len -sizeof (*nlh)),0 ); ev =NLMSG_DATA (nlh); ev->transport_handle =iscsi_handle (conn->transport); ev->type =ISCSI_KEVENT_CONN_ERROR ;
@@ -1022,7 +1042,7 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) ev->r.connerror.cid = conn->cid; ev->r.connerror.sid =iscsi_conn_get_sid (conn); -iscsi_broadcast_skb (skb,GFP_ATOMIC ); +iscsi_multicast_skb (skb,ISCSI_NL_GRP_ISCSID ,GFP_ATOMIC );iscsi_cls_conn_printk (KERN_INFO , conn,"detected conn error (%d)\n" , error);
@@ -1030,8 +1050,8 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)EXPORT_SYMBOL_GPL (iscsi_conn_error_event);static int -iscsi_if_send_reply (int pid,int seq,int type,int done,int multi, -void *payload,int size) +iscsi_if_send_reply (uint32_t group,int seq,int type,int done,int multi, +void *payload,int size) {struct sk_buff *skb;struct nlmsghdr *nlh;
@@ -1045,10 +1065,10 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,return -ENOMEM ; } - nlh =__nlmsg_put (skb, pid, seq, t, (len -sizeof (*nlh)),0 ); + nlh =__nlmsg_put (skb,0 ,0 , t, (len -sizeof (*nlh)),0 ); nlh->nlmsg_flags = flags;memcpy (NLMSG_DATA (nlh), payload, size); -return iscsi_unicast_skb (skb, pid); +return iscsi_multicast_skb (skb, group,GFP_ATOMIC ); } static int
@@ -1085,7 +1105,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)return -ENOMEM ; } - nlhstat =__nlmsg_put (skbstat, priv->daemon_pid,0 ,0 , + nlhstat =__nlmsg_put (skbstat,0 ,0 ,0 , (len -sizeof (*nlhstat)),0 ); evstat =NLMSG_DATA (nlhstat);memset (evstat,0 ,sizeof (*evstat));
@@ -1109,7 +1129,8 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)skb_trim (skbstat,NLMSG_ALIGN (actual_size)); nlhstat->nlmsg_len = actual_size; - err =iscsi_unicast_skb (skbstat, priv->daemon_pid); + err =iscsi_multicast_skb (skbstat,ISCSI_NL_GRP_ISCSID , +GFP_ATOMIC ); }while (err <0 && err != -ECONNREFUSED );return err;
@@ -1143,7 +1164,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,return -ENOMEM ; } - nlh =__nlmsg_put (skb, priv->daemon_pid,0 ,0 , (len -sizeof (*nlh)),0 ); + nlh =__nlmsg_put (skb,0 ,0 ,0 , (len -sizeof (*nlh)),0 ); ev =NLMSG_DATA (nlh); ev->transport_handle =iscsi_handle (session->transport);
@@ -1172,7 +1193,7 @@ int iscsi_session_event(struct iscsi_cls_session *session,* this will occur if the daemon is not up, so we just warn * the user and when the daemon is restarted it will handle it */ - rc =iscsi_broadcast_skb (skb,GFP_KERNEL ); + rc =iscsi_multicast_skb (skb,ISCSI_NL_GRP_ISCSID ,GFP_KERNEL );if (rc == -ESRCH )iscsi_cls_session_printk (KERN_ERR , session, "Cannot notify userspace of session "
@@ -1393,7 +1414,31 @@ iscsi_set_host_param(struct iscsi_transport *transport, }static int -iscsi_if_recv_msg (struct sk_buff *skb,struct nlmsghdr *nlh) +iscsi_set_path (struct iscsi_transport *transport,struct iscsi_uevent *ev) +{ +struct Scsi_Host *shost; +struct iscsi_path *params; +int err; + +if (!transport->set_path) +return -ENOSYS ; + + shost =scsi_host_lookup (ev->u.set_path.host_no); +if (!shost) { +printk (KERN_ERR "set path could not find host no %u\n" , + ev->u.set_path.host_no); +return -ENODEV ; + } + + params = (struct iscsi_path *)((char *)ev +sizeof (*ev)); + err = transport->set_path (shost, params); + +scsi_host_put (shost); +return err; +} + +static int +iscsi_if_recv_msg (struct sk_buff *skb,struct nlmsghdr *nlh,uint32_t *group) {int err =0 ;struct iscsi_uevent *ev =NLMSG_DATA (nlh);
@@ -1403,6 +1448,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)struct iscsi_cls_conn *conn;struct iscsi_endpoint *ep =NULL ; +if (nlh->nlmsg_type ==ISCSI_UEVENT_PATH_UPDATE ) + *group =ISCSI_NL_GRP_UIP ; +else + *group =ISCSI_NL_GRP_ISCSID ; + priv =iscsi_if_transport_lookup (iscsi_ptr (ev->transport_handle));if (!priv)return -EINVAL ;
@@ -1411,8 +1461,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)if (!try_module_get (transport->owner))return -EINVAL ; - priv->daemon_pid =NETLINK_CREDS (skb)->pid; -switch (nlh->nlmsg_type) {case ISCSI_UEVENT_CREATE_SESSION : err = iscsi_if_create_session(priv, ep, ev,
@@ -1506,6 +1554,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)case ISCSI_UEVENT_SET_HOST_PARAM : err =iscsi_set_host_param (transport, ev);break ; +case ISCSI_UEVENT_PATH_UPDATE : + err =iscsi_set_path (transport, ev); +break ;default : err = -ENOSYS ;break ;
@@ -1528,6 +1579,7 @@ iscsi_if_rx(struct sk_buff *skb)uint32_t rlen;struct nlmsghdr *nlh;struct iscsi_uevent *ev; +uint32_t group; nlh =nlmsg_hdr (skb); if (nlh->nlmsg_len < sizeof(*nlh) ||
@@ -1540,7 +1592,7 @@ iscsi_if_rx(struct sk_buff *skb)if (rlen > skb->len) rlen = skb->len; - err =iscsi_if_recv_msg (skb, nlh); + err =iscsi_if_recv_msg (skb, nlh, &group);if (err) { ev->type =ISCSI_KEVENT_IF_ERROR ; ev->iferror = err;
@@ -1554,8 +1606,7 @@ iscsi_if_rx(struct sk_buff *skb)*/ if (ev->type ==ISCSI_UEVENT_GET_STATS && !err)break ; - err =iscsi_if_send_reply ( -NETLINK_CREDS (skb)->pid, nlh->nlmsg_seq, + err =iscsi_if_send_reply (group, nlh->nlmsg_seq, nlh->nlmsg_type,0 ,0 , ev,sizeof (*ev)); }while (err <0 && err != -ECONNREFUSED );skb_pull (skb, rlen);
@@ -1803,7 +1854,6 @@ iscsi_register_transport(struct iscsi_transport *tt)if (!priv)return NULL ;INIT_LIST_HEAD (&priv->list); - priv->daemon_pid =-1 ; priv->iscsi_transport = tt; priv->t.user_scan = iscsi_user_scan; priv->t.create_work_queue =1 ;
include/scsi/iscsi_if.h +42 -0
76 lines not on this page · raw message
include/scsi/scsi_transport_iscsi.h +5 -0
@@ -133,6 +133,7 @@ struct iscsi_transport {void (*ep_disconnect) (struct iscsi_endpoint *ep);int (*tgt_dscvr) (struct Scsi_Host *shost,enum iscsi_tgt_dscvr type,uint32_t enable,struct sockaddr *dst_addr); +int (*set_path) (struct Scsi_Host *shost,struct iscsi_path *params); };/*
@@ -149,6 +150,10 @@ extern void iscsi_conn_error_event(struct iscsi_cls_conn *conn,extern int iscsi_recv_pdu (struct iscsi_cls_conn *conn,struct iscsi_hdr *hdr,char *data,uint32_t data_size); +extern int iscsi_offload_mesg (struct Scsi_Host *shost, +struct iscsi_transport *transport,uint32_t type, +char *data,uint16_t data_size); +struct iscsi_cls_conn {struct list_head conn_list;/* item in connlist */ void *dd_data;/* LLD private data */
Signature · 1 line
1.5.6.GIT
PATCH 2/4 bnx2: Add support for CNIC driver.
In reply to Michael ChanAdd interface and functions to support a new CNIC driver to drive the Broadcom bnx2 hardware for iSCSI offload.
--- drivers/net/bnx2.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++- drivers/net/bnx2.h | 18 +++++ 2 files changed, 208 insertions(+), 3 deletions(-)
drivers/net/bnx2.c +190 -3
@@ -49,6 +49,10 @@#include <linux/firmware.h> #include <linux/log2.h> +#if defined(CONFIG_CNIC ) || defined(CONFIG_CNIC_MODULE ) +#define BCM_CNIC 1 +#include "cnic_if.h" +#endif #include "bnx2.h" #include "bnx2_fw.h"
@@ -315,6 +319,158 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)spin_unlock_bh (&bp->indirect_lock); } +#ifdef BCM_CNIC +static int +bnx2_drv_ctl (struct net_device *dev,struct drv_ctl_info *info) +{ +struct bnx2 *bp =netdev_priv (dev); +struct drv_ctl_io *io = &info->data.io; + +switch (info->cmd) { +case DRV_CTL_IO_WR_CMD : +bnx2_reg_wr_ind (bp, io->offset, io->data); +break ; +case DRV_CTL_IO_RD_CMD : + io->data =bnx2_reg_rd_ind (bp, io->offset); +break ; +case DRV_CTL_CTX_WR_CMD : +bnx2_ctx_wr (bp, io->cid_addr, io->offset, io->data); +break ; +default : +return -EINVAL ; + } +return 0 ; +} + +static void bnx2_setup_cnic_irq_info (struct bnx2 *bp) +{ +struct cnic_eth_dev *cp = &bp->cnic_eth_dev; +struct bnx2_napi *bnapi = &bp->bnx2_napi[0 ]; +int sb_id; + +if (bp->flags &BNX2_FLAG_USING_MSIX ) { + cp->drv_state |=CNIC_DRV_STATE_USING_MSIX ; + bnapi->cnic_present =0 ; + sb_id = bp->irq_nvecs; + cp->irq_arr[0 ].irq_flags |=CNIC_IRQ_FL_MSIX ; + }else { + cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX ; + bnapi->cnic_tag = bnapi->last_status_idx; + bnapi->cnic_present =1 ; + sb_id =0 ; + cp->irq_arr[0 ].irq_flags &= ~CNIC_IRQ_FL_MSIX ; + } + + cp->irq_arr[0 ].vector = bp->irq_tbl[sb_id].vector; + cp->irq_arr[0 ].status_blk = (void *) + ((unsigned long ) bnapi->status_blk.msi + + (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id)); + cp->irq_arr[0 ].status_blk_num = sb_id; + cp->num_irq =1 ; +} + +static int bnx2_register_cnic (struct net_device *dev,struct cnic_ops *ops, +void *data) +{ +struct bnx2 *bp =netdev_priv (dev); +struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + +if (ops ==NULL ) +return -EINVAL ; + +if (cp->drv_state &CNIC_DRV_STATE_REGD ) +return -EBUSY ; + + bp->cnic_data = data; +rcu_assign_pointer (bp->cnic_ops, ops); + + cp->num_irq =0 ; + cp->drv_state =CNIC_DRV_STATE_REGD ; + +bnx2_setup_cnic_irq_info (bp); + +return 0 ; +} + +static int bnx2_unregister_cnic (struct net_device *dev) +{ +struct bnx2 *bp =netdev_priv (dev); +struct bnx2_napi *bnapi = &bp->bnx2_napi[0 ]; +struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + cp->drv_state =0 ; + bnapi->cnic_present =0 ; +rcu_assign_pointer (bp->cnic_ops,NULL ); +synchronize_rcu (); +return 0 ; +} + +struct cnic_eth_dev *bnx2_cnic_probe (struct net_device *dev) +{ +struct bnx2 *bp =netdev_priv (dev); +struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + cp->drv_owner =THIS_MODULE ; + cp->chip_id = bp->chip_id; + cp->pdev = bp->pdev; + cp->io_base = bp->regview; + cp->drv_ctl = bnx2_drv_ctl; + cp->drv_register_cnic = bnx2_register_cnic; + cp->drv_unregister_cnic = bnx2_unregister_cnic; + +return cp; +} +EXPORT_SYMBOL (bnx2_cnic_probe); + +static void +bnx2_cnic_stop (struct bnx2 *bp) +{ +struct cnic_ops *c_ops; +struct cnic_ctl_info info; + +rcu_read_lock (); + c_ops =rcu_dereference (bp->cnic_ops); +if (c_ops) { + info.cmd =CNIC_CTL_STOP_CMD ; + c_ops->cnic_ctl (bp->cnic_data, &info); + } +rcu_read_unlock (); +} + +static void +bnx2_cnic_start (struct bnx2 *bp) +{ +struct cnic_ops *c_ops; +struct cnic_ctl_info info; + +rcu_read_lock (); + c_ops =rcu_dereference (bp->cnic_ops); +if (c_ops) { +if (!(bp->flags &BNX2_FLAG_USING_MSIX )) { +struct bnx2_napi *bnapi = &bp->bnx2_napi[0 ]; + + bnapi->cnic_tag = bnapi->last_status_idx; + } + info.cmd =CNIC_CTL_START_CMD ; + c_ops->cnic_ctl (bp->cnic_data, &info); + } +rcu_read_unlock (); +} + +#else + +static void +bnx2_cnic_stop (struct bnx2 *bp) +{ +} + +static void +bnx2_cnic_start (struct bnx2 *bp) +{ +} + +#endif +static int bnx2_read_phy (struct bnx2 *bp,u32 reg,u32 *val) {
@@ -488,6 +644,7 @@ bnx2_napi_enable(struct bnx2 *bp)static void bnx2_netif_stop (struct bnx2 *bp) { +bnx2_cnic_stop (bp);bnx2_disable_int_sync (bp);if (netif_running (bp->dev)) {bnx2_napi_disable (bp);
@@ -504,6 +661,7 @@ bnx2_netif_start(struct bnx2 *bp)netif_tx_wake_all_queues (bp->dev);bnx2_napi_enable (bp);bnx2_enable_int (bp); +bnx2_cnic_start (bp); } } }
@@ -3164,6 +3322,11 @@ bnx2_has_work(struct bnx2_napi *bnapi)if (bnx2_has_fast_work (bnapi))return 1 ; +#ifdef BCM_CNIC +if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx)) +return 1 ; +#endif +if ((sblk->status_attn_bits &STATUS_ATTN_EVENTS ) != (sblk->status_attn_bits_ack &STATUS_ATTN_EVENTS ))return 1 ;
@@ -3193,6 +3356,23 @@ bnx2_chk_missed_msi(struct bnx2 *bp) bp->idle_chk_status_idx = bnapi->last_status_idx; } +#ifdef BCM_CNIC +static void bnx2_poll_cnic (struct bnx2 *bp,struct bnx2_napi *bnapi) +{ +struct cnic_ops *c_ops; + +if (!bnapi->cnic_present) +return ; + +rcu_read_lock (); + c_ops =rcu_dereference (bp->cnic_ops); +if (c_ops) + bnapi->cnic_tag = c_ops->cnic_handler (bp->cnic_data, + bnapi->status_blk.msi); +rcu_read_unlock (); +} +#endif +static void bnx2_poll_link (struct bnx2 *bp,struct bnx2_napi *bnapi) {struct status_block *sblk = bnapi->status_blk.msi;
@@ -3267,6 +3447,10 @@ static int bnx2_poll(struct napi_struct *napi, int budget) work_done =bnx2_poll_work (bp, bnapi, work_done, budget); +#ifdef BCM_CNIC +bnx2_poll_cnic (bp, bnapi); +#endif +/* bnapi->last_status_idx is used below to tell the hw how * much work has been processed, so we must read it before * checking for more work.
@@ -4632,8 +4816,11 @@ bnx2_init_chip(struct bnx2 *bp) val =REG_RD (bp,BNX2_MQ_CONFIG ); val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE ; val |=BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256 ; -if (CHIP_ID (bp) ==CHIP_ID_5709_A0 ||CHIP_ID (bp) ==CHIP_ID_5709_A1 ) - val |=BNX2_MQ_CONFIG_HALT_DIS ; +if (CHIP_NUM (bp) ==CHIP_NUM_5709 ) { + val |=BNX2_MQ_CONFIG_BIN_MQ_MODE ; +if (CHIP_REV (bp) == CHIP_REV_Ax) + val |=BNX2_MQ_CONFIG_HALT_DIS ; + }REG_WR (bp,BNX2_MQ_CONFIG , val);
@@ -7471,7 +7658,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)INIT_WORK (&bp->reset_task, bnx2_reset_task); dev->base_addr = dev->mem_start =pci_resource_start (pdev,0 ); - mem_len =MB_GET_CID_ADDR (TX_TSS_CID +TX_MAX_TSS_RINGS ); + mem_len =MB_GET_CID_ADDR (TX_TSS_CID +TX_MAX_TSS_RINGS +1 ); dev->mem_end = dev->mem_start + mem_len; dev->irq = pdev->irq;
drivers/net/bnx2.h +18 -0
@@ -361,6 +361,9 @@ struct l2_fhdr {#define BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE (1<<28)#define BNX2_L2CTX_HOST_BDIDX 0x00000004 +#define BNX2_L2CTX_STATUSB_NUM_SHIFT 16 +#define BNX2_L2CTX_STATUSB_NUM (sb_id) \ + (((sb_id) > 0) ? (((sb_id) + 7) << BNX2_L2CTX_STATUSB_NUM_SHIFT) : 0)#define BNX2_L2CTX_HOST_BSEQ 0x00000008#define BNX2_L2CTX_NX_BSEQ 0x0000000c#define BNX2_L2CTX_NX_BDHADDR_HI 0x00000010
@@ -5900,6 +5903,7 @@ struct l2_fhdr {#define BNX2_RXP_FTQ_CTL_CUR_DEPTH (0x3ffL<<22)#define BNX2_RXP_SCRATCH 0x000e0000 +#define BNX2_RXP_SCRATCH_RXP_FLOOD 0x000e0024#define BNX2_RXP_SCRATCH_RSS_TBL_SZ 0x000e0038#define BNX2_RXP_SCRATCH_RSS_TBL 0x000e003c#define BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES 128
@@ -6678,6 +6682,11 @@ struct bnx2_napi {u32 last_status_idx;u32 int_num; +#ifdef BCM_CNIC +u32 cnic_tag; +int cnic_present; +#endif +struct bnx2_rx_ring_info rx_ring;struct bnx2_tx_ring_info tx_ring; };
@@ -6727,6 +6736,11 @@ struct bnx2 {int tx_ring_size;u32 tx_wake_thresh; +#ifdef BCM_CNIC +struct cnic_ops *cnic_ops; +void *cnic_data; +#endif +/* End of fields used in the performance code paths. */ unsigned int current_interval;
@@ -6885,6 +6899,10 @@ struct bnx2 {u32 idle_chk_status_idx; +#ifdef BCM_CNIC +struct cnic_eth_dev cnic_eth_dev; +#endif +const struct firmware *mips_firmware;const struct firmware *rv2p_firmware; };
Signature · 1 line
1.5.6.GIT
PATCH 4/4 bnx2i: Add bnx2i iSCSI driver.
In reply to Michael ChanNew iSCSI driver for Broadcom BNX2 devices. The driver interfaces with the CNIC driver to access the hardware.
--- drivers/scsi/Kconfig | 1 + drivers/scsi/Makefile | 1 + drivers/scsi/bnx2i/57xx_iscsi_constants.h | 155 ++ drivers/scsi/bnx2i/57xx_iscsi_hsi.h | 1509 ++++++++++++++++++ drivers/scsi/bnx2i/Kconfig | 7 + drivers/scsi/bnx2i/Makefile | 3 + drivers/scsi/bnx2i/bnx2i.h | 776 ++++++++++ drivers/scsi/bnx2i/bnx2i_hwi.c | 2412 +++++++++++++++++++++++++++++ drivers/scsi/bnx2i/bnx2i_init.c | 434 ++++++ drivers/scsi/bnx2i/bnx2i_iscsi.c | 2082 +++++++++++++++++++++++++ drivers/scsi/bnx2i/bnx2i_sysfs.c | 142 ++ 11 files changed, 7522 insertions(+), 0 deletions(-) create mode 100644 drivers/scsi/bnx2i/57xx_iscsi_constants.h create mode 100644 drivers/scsi/bnx2i/57xx_iscsi_hsi.h create mode 100644 drivers/scsi/bnx2i/Kconfig create mode 100644 drivers/scsi/bnx2i/Makefile create mode 100644 drivers/scsi/bnx2i/bnx2i.h create mode 100644 drivers/scsi/bnx2i/bnx2i_hwi.c create mode 100644 drivers/scsi/bnx2i/bnx2i_init.c create mode 100644 drivers/scsi/bnx2i/bnx2i_iscsi.c create mode 100644 drivers/scsi/bnx2i/bnx2i_sysfs.c
drivers/scsi/Kconfig +1 -0
@@ -354,6 +354,7 @@ config ISCSI_TCP http://open-iscsi.org source "drivers/scsi/cxgb3i/Kconfig" +source "drivers/scsi/bnx2i/Kconfig" config SGIWD93_SCSI tristate "SGI WD93C93 SCSI Driver"
drivers/scsi/Makefile +1 -0
@@ -129,6 +129,7 @@ obj-$(CONFIG_SCSI_STEX) += stex.o obj-$(CONFIG_SCSI_MVSAS) += mvsas/ obj-$(CONFIG_PS3_ROM) += ps3rom.o obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/ +obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/ obj-$(CONFIG_ARM) += arm/
drivers/scsi/bnx2i/57xx_iscsi_constants.h new file +155 -0
155 lines not on this page · raw message
drivers/scsi/bnx2i/57xx_iscsi_hsi.h new file +1509 -0
1,509 lines not on this page · raw message
drivers/scsi/bnx2i/Kconfig new file +7 -0
@@ -0,0 +1,7 @@ +config SCSI_BNX2_ISCSI + tristate "Broadcom NetXtreme II iSCSI support" + select SCSI_ISCSI_ATTRS + select CNIC + ---help--- + This driver supports iSCSI offload for the Broadcom NetXtreme II + devices.
drivers/scsi/bnx2i/Makefile new file +3 -0
@@ -0,0 +1,3 @@ +bnx2i-y := bnx2i_init.o bnx2i_hwi.o bnx2i_iscsi.o bnx2i_sysfs.o + +obj-$(CONFIG_SCSI_BNX2_ISCSI) += bnx2i.o
drivers/scsi/bnx2i/bnx2i.h new file +776 -0
776 lines not on this page · raw message
drivers/scsi/bnx2i/bnx2i_hwi.c new file +2412 -0
536 lines not on this page · raw message
drivers/scsi/bnx2i/bnx2i_init.c new file +434 -0
434 lines not on this page · raw message
drivers/scsi/bnx2i/bnx2i_iscsi.c new file +2082 -0
2,082 lines not on this page · raw message
drivers/scsi/bnx2i/bnx2i_sysfs.c new file +142 -0
142 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.5.6.GIT
Part of the diff is not shown here. View the raw message.
Re: [PATCH 4/4] bnx2i: Add bnx2i iSCSI driver.
Quoted 1 line · Michael Chan
New iSCSI driver for Broadcom BNX2 devices.
...
Quoted 4 lines
drivers/scsi/bnx2i/57xx_iscsi_hsi.h new file +4
-0+/* +* iSCSI Async CQE +*/ +struct bnx2i_async_msg {
...
drivers/scsi/bnx2i/57xx_iscsi_hsi.h line 50
Quoted 9 lines
drivers/scsi/bnx2i/57xx_iscsi_hsi.h new file +9
-0+#if defined(__BIG_ENDIAN) +u8 async_event; +u8 async_vcode; +u16 param1; +#elif defined(__LITTLE_ENDIAN) +u16 param1; +u8 async_vcode; +u8 async_event; +#endif
...
Michael,
I'm feeling a bit dense and am not seeing why byte data would have to worry about the 32-bit word endianess of the CPU. Can you give an example of why defined(__BIG_ENDIAN) is needed?
Normally the _*ENDIAN defines are used for bit fields, not byte fields.
Byte data addressable by the CPU (e.g. host memory) is at the same offset regardless of endianness of the CPU. I feel like I'm missing something that should be obvious.
thanks,
grant
Re: [PATCH 4/4] bnx2i: Add bnx2i iSCSI driver.
Quoted 24 lines · Grant Grundler
Quoted 1 line · Michael Chan
New iSCSI driver for Broadcom BNX2 devices.
...
Quoted 4 lines
drivers/scsi/bnx2i/57xx_iscsi_hsi.h new file +4
-0+/* +* iSCSI Async CQE +*/ +struct bnx2i_async_msg {...
drivers/scsi/bnx2i/57xx_iscsi_hsi.h line 50
Quoted 9 lines
drivers/scsi/bnx2i/57xx_iscsi_hsi.h new file +9
-0+#if defined(__BIG_ENDIAN) +u8 async_event; +u8 async_vcode; +u16 param1; +#elif defined(__LITTLE_ENDIAN) +u16 param1; +u8 async_vcode; +u8 async_event; +#endif ...
Michael,
I'm feeling a bit dense and am not seeing why byte data would have to worry about the 32-bit word endianess of the CPU. Can you give an example of whydefined(__BIG_ENDIAN)is needed?
Quoted 5 lines
Normally the _*ENDIAN defines are used for bit fields, not byte fields.
Byte data addressable by the CPU (e.g. host memory) is at the same offset regardless of endianness of the CPU. I feel like I'm missing something that should be obvious.
Hi Grant, these are what we call "DMA control structures" as opposed to DMA packet data. Our chips are configured to do an additional 32-bit endian swap on all DMA control structures. This way, all 32-bit control fields (such as length, status, etc) will come out right when the driver reads these fields.
If everything was defined as u32 in all these control structures, we wouldn't have to add the #ifdef. u8 and u16 fields have to be defined this way or else big endian CPUs would read the wrong offset.
If you look at some of the control structures in tg3.h, you'll see the same thing.
Thanks.
Re: [PATCH 4/4] bnx2i: Add bnx2i iSCSI driver.
On Tue, May 26, 2009 at 9:49 AM, Michael Chan <[email protected]> wrote:
...
Quoted 6 lines
Hi Grant, these are what we call "DMA control structures" as opposed to DMA packet data. Our chips are configured to do an additional 32-bit endian swap on all DMA control structures. This way, all 32-bit control fields (such as length, status, etc) will come out right when the driver reads these fields.
Quoted 6 lines
If everything was defined as u32 in all these control structures, we wouldn't have to add the #ifdef. u8 and u16 fields have to be defined this way or else big endian CPUs would read the wrong offset.
If you look at some of the control structures in
tg3.h, you'll see the same thing.
Ah ok...so the chip is programmed configured to know about host endianess. I'm familiar with tg3 having that and just hadn't noticed it here yet.
thanks,
grant
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html