Commit 71f7a00b authored by Varun Prakash's avatar Varun Prakash Committed by David S. Miller

cxgb4i,libcxgbi: add iSCSI DDP support

Add iSCSI DDP support in cxgb4i driver
using common iSCSI DDP Page Pod Manager.
Signed-off-by: default avatarVarun Prakash <varun@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5999299f
ccflags-y += -Idrivers/net/ethernet/chelsio/libcxgb
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libcxgbi.o cxgb3i/
obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libcxgbi.o cxgb4i/
ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3
ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/libcxgb
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o
......@@ -5,6 +5,7 @@ config SCSI_CXGB3_ISCSI
select ETHERNET
select NET_VENDOR_CHELSIO
select CHELSIO_T3
select CHELSIO_LIB
select SCSI_ISCSI_ATTRS
---help---
This driver supports iSCSI offload for the Chelsio T3 devices.
ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4
ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/libcxgb
obj-$(CONFIG_SCSI_CXGB4_ISCSI) += cxgb4i.o
......@@ -5,6 +5,7 @@ config SCSI_CXGB4_ISCSI
select ETHERNET
select NET_VENDOR_CHELSIO
select CHELSIO_T4
select CHELSIO_LIB
select SCSI_ISCSI_ATTRS
---help---
This driver supports iSCSI offload for the Chelsio T4 devices.
......@@ -1543,6 +1543,115 @@ int cxgb4i_ofld_init(struct cxgbi_device *cdev)
return 0;
}
static inline void
ulp_mem_io_set_hdr(struct cxgbi_device *cdev,
struct ulp_mem_io *req,
unsigned int wr_len, unsigned int dlen,
unsigned int pm_addr,
int tid)
{
struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev);
struct ulptx_idata *idata = (struct ulptx_idata *)(req + 1);
INIT_ULPTX_WR(req, wr_len, 0, tid);
req->wr.wr_hi = htonl(FW_WR_OP_V(FW_ULPTX_WR) |
FW_WR_ATOMIC_V(0));
req->cmd = htonl(ULPTX_CMD_V(ULP_TX_MEM_WRITE) |
ULP_MEMIO_ORDER_V(is_t4(lldi->adapter_type)) |
T5_ULP_MEMIO_IMM_V(!is_t4(lldi->adapter_type)));
req->dlen = htonl(ULP_MEMIO_DATA_LEN_V(dlen >> 5));
req->lock_addr = htonl(ULP_MEMIO_ADDR_V(pm_addr >> 5));
req->len16 = htonl(DIV_ROUND_UP(wr_len - sizeof(req->wr), 16));
idata->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_IMM));
idata->len = htonl(dlen);
}
static struct sk_buff *
ddp_ppod_init_idata(struct cxgbi_device *cdev,
struct cxgbi_ppm *ppm,
unsigned int idx, unsigned int npods,
unsigned int tid)
{
unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ppm->llimit;
unsigned int dlen = npods << PPOD_SIZE_SHIFT;
unsigned int wr_len = roundup(sizeof(struct ulp_mem_io) +
sizeof(struct ulptx_idata) + dlen, 16);
struct sk_buff *skb = alloc_wr(wr_len, 0, GFP_ATOMIC);
if (!skb) {
pr_err("%s: %s idx %u, npods %u, OOM.\n",
__func__, ppm->ndev->name, idx, npods);
return NULL;
}
ulp_mem_io_set_hdr(cdev, (struct ulp_mem_io *)skb->head, wr_len, dlen,
pm_addr, tid);
return skb;
}
static int ddp_ppod_write_idata(struct cxgbi_ppm *ppm, struct cxgbi_sock *csk,
struct cxgbi_task_tag_info *ttinfo,
unsigned int idx, unsigned int npods,
struct scatterlist **sg_pp,
unsigned int *sg_off)
{
struct cxgbi_device *cdev = csk->cdev;
struct sk_buff *skb = ddp_ppod_init_idata(cdev, ppm, idx, npods,
csk->tid);
struct ulp_mem_io *req;
struct ulptx_idata *idata;
struct cxgbi_pagepod *ppod;
int i;
if (!skb)
return -ENOMEM;
req = (struct ulp_mem_io *)skb->head;
idata = (struct ulptx_idata *)(req + 1);
ppod = (struct cxgbi_pagepod *)(idata + 1);
for (i = 0; i < npods; i++, ppod++)
cxgbi_ddp_set_one_ppod(ppod, ttinfo, sg_pp, sg_off);
cxgbi_skcb_set_flag(skb, SKCBF_TX_MEM_WRITE);
cxgbi_skcb_set_flag(skb, SKCBF_TX_FLAG_COMPL);
set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id);
spin_lock_bh(&csk->lock);
cxgbi_sock_skb_entail(csk, skb);
spin_unlock_bh(&csk->lock);
return 0;
}
static int ddp_set_map(struct cxgbi_ppm *ppm, struct cxgbi_sock *csk,
struct cxgbi_task_tag_info *ttinfo)
{
unsigned int pidx = ttinfo->idx;
unsigned int npods = ttinfo->npods;
unsigned int i, cnt;
int err = 0;
struct scatterlist *sg = ttinfo->sgl;
unsigned int offset = 0;
ttinfo->cid = csk->port_id;
for (i = 0; i < npods; i += cnt, pidx += cnt) {
cnt = npods - i;
if (cnt > ULPMEM_IDATA_MAX_NPPODS)
cnt = ULPMEM_IDATA_MAX_NPPODS;
err = ddp_ppod_write_idata(ppm, csk, ttinfo, pidx, cnt,
&sg, &offset);
if (err < 0)
break;
}
return err;
}
static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid,
int pg_idx, bool reply)
{
......@@ -1606,10 +1715,46 @@ static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid,
return 0;
}
static struct cxgbi_ppm *cdev2ppm(struct cxgbi_device *cdev)
{
return (struct cxgbi_ppm *)(*((struct cxgb4_lld_info *)
(cxgbi_cdev_priv(cdev)))->iscsi_ppm);
}
static int cxgb4i_ddp_init(struct cxgbi_device *cdev)
{
struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev);
struct net_device *ndev = cdev->ports[0];
struct cxgbi_tag_format tformat;
unsigned int ppmax;
int i;
if (!lldi->vr->iscsi.size) {
pr_warn("%s, iscsi NOT enabled, check config!\n", ndev->name);
return -EACCES;
}
cdev->flags |= CXGBI_FLAG_USE_PPOD_OFLDQ;
ppmax = lldi->vr->iscsi.size >> PPOD_SIZE_SHIFT;
memset(&tformat, 0, sizeof(struct cxgbi_tag_format));
for (i = 0; i < 4; i++)
tformat.pgsz_order[i] = (lldi->iscsi_pgsz_order >> (i << 3))
& 0xF;
cxgbi_tagmask_check(lldi->iscsi_tagmask, &tformat);
cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat, ppmax,
lldi->iscsi_llimit, lldi->vr->iscsi.start, 2);
cdev->csk_ddp_setup_digest = ddp_setup_conn_digest;
cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx;
cdev->csk_ddp_set_map = ddp_set_map;
cdev->tx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
lldi->iscsi_iolen - ISCSI_PDU_NONPAYLOAD_LEN);
cdev->rx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
lldi->iscsi_iolen - ISCSI_PDU_NONPAYLOAD_LEN);
cdev->cdev2ppm = cdev2ppm;
return 0;
}
......
This diff is collapsed.
......@@ -24,9 +24,12 @@
#include <linux/scatterlist.h>
#include <linux/skbuff.h>
#include <linux/vmalloc.h>
#include <linux/version.h>
#include <scsi/scsi_device.h>
#include <scsi/libiscsi_tcp.h>
#include <libcxgb_ppm.h>
enum cxgbi_dbg_flag {
CXGBI_DBG_ISCSI,
CXGBI_DBG_DDP,
......@@ -89,8 +92,6 @@ static inline unsigned int cxgbi_ulp_extra_len(int submode)
#define CPL_RX_DDP_STATUS_HCRC_SHIFT 20 /* hcrc error */
#define CPL_RX_DDP_STATUS_DCRC_SHIFT 21 /* dcrc error */
#define DDP_PGIDX_MAX 4
/*
* sge_opaque_hdr -
* Opaque version of structure the SGE stores at skb->head of TX_DATA packets
......@@ -200,6 +201,8 @@ struct cxgbi_skb_tx_cb {
enum cxgbi_skcb_flags {
SKCBF_TX_NEED_HDR, /* packet needs a header */
SKCBF_TX_MEM_WRITE, /* memory write */
SKCBF_TX_FLAG_COMPL, /* wr completion flag */
SKCBF_RX_COALESCED, /* received whole pdu */
SKCBF_RX_HDR, /* received pdu header */
SKCBF_RX_DATA, /* received pdu payload */
......@@ -448,6 +451,9 @@ struct cxgbi_ports_map {
#define CXGBI_FLAG_DEV_T4 0x2
#define CXGBI_FLAG_ADAPTER_RESET 0x4
#define CXGBI_FLAG_IPV4_SET 0x10
#define CXGBI_FLAG_USE_PPOD_OFLDQ 0x40
#define CXGBI_FLAG_DDP_OFF 0x100
struct cxgbi_device {
struct list_head list_head;
struct list_head rcu_node;
......@@ -471,6 +477,12 @@ struct cxgbi_device {
struct cxgbi_ports_map pmap;
void (*dev_ddp_cleanup)(struct cxgbi_device *);
struct cxgbi_ppm* (*cdev2ppm)(struct cxgbi_device *);
int (*csk_ddp_set_map)(struct cxgbi_ppm *, struct cxgbi_sock *,
struct cxgbi_task_tag_info *);
void (*csk_ddp_clear_map)(struct cxgbi_device *cdev,
struct cxgbi_ppm *,
struct cxgbi_task_tag_info *);
int (*csk_ddp_setup_digest)(struct cxgbi_sock *,
unsigned int, int, int, int);
int (*csk_ddp_setup_pgidx)(struct cxgbi_sock *,
......@@ -494,6 +506,8 @@ struct cxgbi_conn {
struct iscsi_conn *iconn;
struct cxgbi_hba *chba;
u32 task_idx_bits;
unsigned int ddp_full;
unsigned int ddp_tag_full;
};
struct cxgbi_endpoint {
......@@ -507,9 +521,11 @@ struct cxgbi_task_data {
unsigned short nr_frags;
struct page_frag frags[MAX_PDU_FRAGS];
struct sk_buff *skb;
unsigned int dlen;
unsigned int offset;
unsigned int count;
unsigned int sgoffset;
struct cxgbi_task_tag_info ttinfo;
};
#define iscsi_task_cxgbi_data(task) \
((task)->dd_data + sizeof(struct iscsi_tcp_task))
......@@ -591,4 +607,11 @@ int cxgbi_ddp_init(struct cxgbi_device *, unsigned int, unsigned int,
unsigned int, unsigned int);
int cxgbi_ddp_cleanup(struct cxgbi_device *);
void cxgbi_ddp_page_size_factor(int *);
void cxgbi_ddp_set_one_ppod(struct cxgbi_pagepod *,
struct cxgbi_task_tag_info *,
struct scatterlist **sg_pp, unsigned int *sg_off);
void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *,
struct cxgbi_tag_format *, unsigned int ppmax,
unsigned int llimit, unsigned int start,
unsigned int rsvd_factor);
#endif /*__LIBCXGBI_H__*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment