+++ /dev/null
-From: Karen Xie <kxie@chelsio.com>
-Subject: cxgb3i - added pdu size check and fixed ddp page setup
-References: bnc#449519
-
-- Added documentation for cxgb3i driver, decribing how to use it to offload
- open-iscsi initaitor.
-- limit the transmit pdu size to be 4K aligned.
-- added check for pdu size, if the negotiated pdu size if too big, print error
- message to dmesg, and close the connection.
-- fixed ddp page size setup when both header and data digests are off.
-
-Signed-off-by: Karen Xie <kxie@chelsio.com>
-Acked-by: John Jolly <jjolly@novell.com>
----
-
-diff -uNr linux-2.6.27.7-4.orig/Documentation/scsi/cxgb3i.txt linux-2.6.27.7-4.new/Documentation/scsi/cxgb3i.txt
---- linux-2.6.27.7-4.orig/Documentation/scsi/cxgb3i.txt 1969-12-31 18:00:00.000000000 -0600
-+++ linux-2.6.27.7-4.new/Documentation/scsi/cxgb3i.txt 2008-12-01 18:32:21.000000000 -0600
-@@ -0,0 +1,51 @@
-+Chelsio S3 iSCSI Driver for Linux
-+
-+Introduction
-+============
-+
-+The Chelsio T3 ASIC based Adapters (S310, S320, S302, S304, Mezz cards, etc.
-+series of products) supports iSCSI acceleration and iSCSI Direct Data Placement
-+(DDP) where the hardware handles the expensive byte touching operations, such
-+as CRC computation and verification, and direct DMA to the final host memory
-+destination.
-+
-+The cxgb3i driver interfaces with open-iscsi initiator and provides the iSCSI
-+acceleration through Chelsio hardware wherever applicable.
-+
-+Using the cxgb3i Driver
-+=======================
-+
-+The following steps need to be taken to accelerates the open-iscsi initiator:
-+
-+1. a new transport class "cxgb3i" need to be specified. This is done by
-+ creating a new interface file in /etc/iscsi/ifaces.
-+
-+ The content of the file should be in the following format:
-+ iface.transport_name = cxgb3i
-+ iface.net_ifacename = <ethX>
-+ iface.ipaddress = <iscsi ip address>
-+
-+ * iface.ipaddress is optional, <iscsi ip address> can be either the same as
-+ the ethX's ip address or an address on the same subnet. Make sure the
-+ address is unique in the network.
-+
-+2. edit /etc/iscsi/iscsid.conf
-+ The default setting for MaxRecvDataSegmentLength (131072) is too big, search
-+ and replace all occurances of "xxx.iscsi.MaxRecvDataSegmentLength" to be a
-+ smaller value (8192 is recommended):
-+
-+ discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 8192
-+ node.conn[0].iscsi.MaxRecvDataSegmentLength = 8192
-+
-+3. Load the cxgb3i driver: "modprobe cxgb3i"
-+
-+ * in the case of recompiling the kernel, the cxgb3i selection is located at
-+ Device Drivers
-+ SCSI device support --->
-+ [*] SCSI low-level drivers --->
-+ <M> Chelsio S3xx iSCSI support
-+
-+4. To direct open-iscsi traffic to go through cxgb3i's accelerated path,
-+ "-I <iface file name>" option needs to be specified with most of the
-+ iscsiadm command. <iface file name> is the transport interface file created
-+ in step 1.
-diff -uNr linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_iscsi.c linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
---- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_iscsi.c 2008-11-25 09:16:10.000000000 -0600
-+++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_iscsi.c 2008-12-01 18:32:55.000000000 -0600
-@@ -22,6 +22,12 @@
- #include <scsi/scsi_transport_iscsi.h>
-
- #include "cxgb3i.h"
-+#include "cxgb3i_ulp2.h"
-+
-+#define align_to_4k_boundary(n) \
-+ do { \
-+ n = (n) & ~((1 << 12) - 1); \
-+ } while(0)
-
- static struct scsi_transport_template *cxgb3i_scsi_transport;
- static struct scsi_host_template cxgb3i_host_template;
-@@ -370,36 +376,59 @@
- *
- * Creates a new iSCSI connection instance for a given session
- */
--static inline void cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn)
-+static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn)
- {
- struct cxgb3i_conn *cconn = conn->dd_data;
-+ unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE,
-+ cconn->hba->snic->tx_max_size -
-+ ISCSI_PDU_HEADER_MAX);
-+
-+ cxgb3i_log_debug("conn 0x%p, max xmit %u.\n",
-+ conn, conn->max_xmit_dlength);
-
- if (conn->max_xmit_dlength)
- conn->max_xmit_dlength = min_t(unsigned int,
-- conn->max_xmit_dlength,
-- cconn->hba->snic->tx_max_size -
-- ISCSI_PDU_HEADER_MAX);
-+ conn->max_xmit_dlength, max);
- else
-- conn->max_xmit_dlength = cconn->hba->snic->tx_max_size -
-- ISCSI_PDU_HEADER_MAX;
-- cxgb3i_log_debug("conn 0x%p, max xmit %u.\n",
-+ conn->max_xmit_dlength = max;
-+
-+ align_to_4k_boundary(conn->max_xmit_dlength);
-+
-+ cxgb3i_log_debug("conn 0x%p, set max xmit %u.\n",
- conn, conn->max_xmit_dlength);
-+
-+ return 0;
- }
-
--static inline void cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn)
-+static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn)
- {
- struct cxgb3i_conn *cconn = conn->dd_data;
-+ unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE,
-+ cconn->hba->snic->rx_max_size -
-+ ISCSI_PDU_HEADER_MAX);
-
-- if (conn->max_recv_dlength)
-- conn->max_recv_dlength = min_t(unsigned int,
-- conn->max_recv_dlength,
-- cconn->hba->snic->rx_max_size -
-- ISCSI_PDU_HEADER_MAX);
-- else
-- conn->max_recv_dlength = cconn->hba->snic->rx_max_size -
-- ISCSI_PDU_HEADER_MAX;
- cxgb3i_log_debug("conn 0x%p, max recv %u.\n",
- conn, conn->max_recv_dlength);
-+
-+ align_to_4k_boundary(max);
-+
-+ if (conn->max_recv_dlength) {
-+ if (conn->max_recv_dlength > max) {
-+ cxgb3i_log_error("MaxRecvDataSegmentLength %u, not supported."
-+ "Need to be <= %u.\n",
-+ conn->max_recv_dlength, max);
-+ return -EINVAL;
-+ }
-+ conn->max_recv_dlength = min_t(unsigned int,
-+ conn->max_recv_dlength, max);
-+ align_to_4k_boundary(conn->max_recv_dlength);
-+ } else
-+ conn->max_recv_dlength = max;
-+
-+ cxgb3i_log_debug("conn 0x%p, set max recv %u.\n",
-+ conn, conn->max_recv_dlength);
-+
-+ return 0;
- }
-
- static struct iscsi_cls_conn *cxgb3i_conn_create(struct iscsi_cls_session
-@@ -546,13 +575,13 @@
- switch (param) {
- case ISCSI_PARAM_HDRDGST_EN:
- err = iscsi_set_param(cls_conn, param, buf, buflen);
-- if (!err && conn->hdrdgst_en)
-+ if (!err)
- cxgb3i_conn_ulp_setup(cconn, conn->hdrdgst_en,
- conn->datadgst_en);
- break;
- case ISCSI_PARAM_DATADGST_EN:
- err = iscsi_set_param(cls_conn, param, buf, buflen);
-- if (!err && conn->datadgst_en)
-+ if (!err)
- cxgb3i_conn_ulp_setup(cconn, conn->hdrdgst_en,
- conn->datadgst_en);
- break;
-@@ -568,11 +597,11 @@
- return -ENOMEM;
- case ISCSI_PARAM_MAX_RECV_DLENGTH:
- err = iscsi_set_param(cls_conn, param, buf, buflen);
-- cxgb3i_conn_max_recv_dlength(conn);
-+ err = cxgb3i_conn_max_recv_dlength(conn);
- break;
- case ISCSI_PARAM_MAX_XMIT_DLENGTH:
- err = iscsi_set_param(cls_conn, param, buf, buflen);
-- cxgb3i_conn_max_xmit_dlength(conn);
-+ err = cxgb3i_conn_max_xmit_dlength(conn);
- break;
- default:
- return iscsi_set_param(cls_conn, param, buf, buflen);
-diff -uNr linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_offload.c linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_offload.c
---- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_offload.c 2008-11-25 09:16:10.000000000 -0600
-+++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_offload.c 2008-12-01 18:32:55.000000000 -0600
-@@ -45,6 +45,12 @@
- #define c3cn_tx_debug(fmt...)
- #endif
-
-+#ifdef __DEBUG_C3CN_RX__
-+#define c3cn_rx_debug cxgb3i_log_debug
-+#else
-+#define c3cn_rx_debug(fmt...)
-+#endif
-+
- /* connection flags */
- static inline void c3cn_set_flag(struct s3_conn *c3cn, enum c3cn_flags flag)
- {
-@@ -1577,6 +1583,9 @@
- skb_ulp_ddigest(skb) = ntohl(ddp_cpl.ulp_crc);
- status = ntohl(ddp_cpl.ddp_status);
-
-+ c3cn_rx_debug("skb 0x%p, len %u, pdulen %u, ddp status 0x%x.\n",
-+ skb, skb->len, skb_ulp_pdulen(skb), status);
-+
- if (status & (1 << RX_DDP_STATUS_HCRC_SHIFT))
- skb_ulp_mode(skb) |= ULP2_FLAG_HCRC_ERROR;
- if (status & (1 << RX_DDP_STATUS_DCRC_SHIFT))
-diff -uNr linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.c linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.c
---- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.c 2008-11-25 09:16:10.000000000 -0600
-+++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.c 2008-12-01 18:32:55.000000000 -0600
-@@ -145,6 +145,9 @@
- PAGE_SHIFT;
- int i = 1, j = 0;
-
-+ if (sgoffset)
-+ return NULL;
-+
- gl = kzalloc(sizeof(struct cxgb3i_gather_list) +
- npages * (sizeof(dma_addr_t) + sizeof(struct page *)),
- gfp);
-@@ -173,7 +176,7 @@
- goto error_out;
-
- j++;
-- if (j == gl->nelem)
-+ if (j == gl->nelem || sg->offset)
- goto error_out;
- gl->pages[j] = page;
- sglen = sg->length;
-@@ -303,7 +306,8 @@
- int idx = -1, idx_max;
- u32 tag;
-
-- if (page_idx || !ddp || !sgcnt || xferlen < ULP2_DDP_THRESHOLD) {
-+ if (page_idx >= ULP2_PGIDX_MAX || !ddp || !sgcnt ||
-+ xferlen < ULP2_DDP_THRESHOLD) {
- cxgb3i_tag_debug("pgidx %u, sgcnt %u, xfer %u/%u, NO ddp.\n",
- page_idx, sgcnt, xferlen, ULP2_DDP_THRESHOLD);
- return RESERVED_ITT;
-@@ -330,10 +334,9 @@
- npods, gl);
- }
- if (idx < 0) {
-- kfree(gl);
- cxgb3i_tag_debug("sgcnt %u, xferlen %u, npods %u NO DDP.\n",
- sgcnt, xferlen, npods);
-- return RESERVED_ITT;
-+ goto free_gl;
- }
-
- if (ddp_alloc_gl_skb(ddp, idx, npods, gfp) < 0)
-@@ -341,7 +344,7 @@
-
- if (ddp_gl_map(snic->pdev, gl) < 0)
- goto unmap_sgl;
--
-+
- tag = sw_tag | (idx << snic->tag_format.rsvd_shift);
-
- hdr.rsvd = 0;
-@@ -363,6 +366,8 @@
- ddp_free_gl_skb(ddp, idx, npods);
- unmark_entries:
- ddp_unmark_entries(ddp, idx, npods);
-+free_gl:
-+ kfree(gl);
- return RESERVED_ITT;
- }
-
-@@ -393,8 +398,10 @@
- struct sk_buff *skb = alloc_skb(sizeof(struct cpl_set_tcb_field),
- GFP_KERNEL | __GFP_NOFAIL);
- struct cpl_set_tcb_field *req;
-- u32 submode = (hcrc ? 1 : 0) | (dcrc ? 2 : 0);
-- u32 pgcode = page_idx < ULP2_PGIDX_MAX ? page_idx : 0;
-+ u64 val = (hcrc ? 1 : 0) | (dcrc ? 2 : 0);
-+
-+ if (page_idx < ULP2_PGIDX_MAX)
-+ val |= page_idx << 4;
-
- /* set up ulp submode and page size */
- req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
-@@ -404,7 +411,7 @@
- req->cpu_idx = 0;
- req->word = htons(31);
- req->mask = cpu_to_be64(0xFF000000);
-- req->val = cpu_to_be64(((pgcode << 4) | submode) << 24);
-+ req->val = cpu_to_be64(val << 24);
- skb->priority = CPL_PRIORITY_CONTROL;
-
- cxgb3_ofld_send(c3cn->cdev, skb);
-@@ -461,12 +468,16 @@
- segment->status = (conn->datadgst_en &&
- (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) ?
- ISCSI_SEGMENT_DGST_ERR : 0;
-- if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED)
-+ if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) {
-+ cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, ddp'ed, "
-+ "itt 0x%x.\n",
-+ skb, hdr->opcode & ISCSI_OPCODE_MASK,
-+ tcp_conn->in.datalen, hdr->itt);
- segment->total_copied = segment->total_size;
-- else {
-- cxgb3i_ddp_debug("opcode 0x%x, data %u, NOT ddp'ed, "
-+ } else {
-+ cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, not ddp'ed, "
- "itt 0x%x.\n",
-- hdr->opcode & ISCSI_OPCODE_MASK,
-+ skb, hdr->opcode & ISCSI_OPCODE_MASK,
- tcp_conn->in.datalen, hdr->itt);
- offset += sizeof(struct cpl_iscsi_hdr_norss);
- }
-diff -uNr linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.h linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.h
---- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.h 2008-11-25 09:16:10.000000000 -0600
-+++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.h 2008-12-01 18:32:55.000000000 -0600
-@@ -101,6 +101,7 @@
- #define ULP2_FLAG_PAD_ERROR 0x40
-
- #define ULP2_MAX_PKT_SIZE 16224
-+#define ULP2_MAX_PDU_SIZE 8192
-
- void cxgb3i_conn_closing(struct s3_conn *);
- void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn);