]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.25/patches.drivers/cxgb3i_ddp.patch
Reenabled linux-xen and xen-image build
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.drivers / cxgb3i_ddp.patch
CommitLineData
00e5a55c
BS
1From: Karen Xie <kxie@chelsio.com>
2Subject: cxgb3i - added pdu size check and fixed ddp page setup
3References: bnc#449519
4
5- Added documentation for cxgb3i driver, decribing how to use it to offload
6 open-iscsi initaitor.
7- limit the transmit pdu size to be 4K aligned.
8- added check for pdu size, if the negotiated pdu size if too big, print error
9 message to dmesg, and close the connection.
10- fixed ddp page size setup when both header and data digests are off.
11
12Signed-off-by: Karen Xie <kxie@chelsio.com>
13Acked-by: John Jolly <jjolly@novell.com>
14---
15
16diff -uNr linux-2.6.27.7-4.orig/Documentation/scsi/cxgb3i.txt linux-2.6.27.7-4.new/Documentation/scsi/cxgb3i.txt
17--- linux-2.6.27.7-4.orig/Documentation/scsi/cxgb3i.txt 1969-12-31 18:00:00.000000000 -0600
18+++ linux-2.6.27.7-4.new/Documentation/scsi/cxgb3i.txt 2008-12-01 18:32:21.000000000 -0600
19@@ -0,0 +1,51 @@
20+Chelsio S3 iSCSI Driver for Linux
21+
22+Introduction
23+============
24+
25+The Chelsio T3 ASIC based Adapters (S310, S320, S302, S304, Mezz cards, etc.
26+series of products) supports iSCSI acceleration and iSCSI Direct Data Placement
27+(DDP) where the hardware handles the expensive byte touching operations, such
28+as CRC computation and verification, and direct DMA to the final host memory
29+destination.
30+
31+The cxgb3i driver interfaces with open-iscsi initiator and provides the iSCSI
32+acceleration through Chelsio hardware wherever applicable.
33+
34+Using the cxgb3i Driver
35+=======================
36+
37+The following steps need to be taken to accelerates the open-iscsi initiator:
38+
39+1. a new transport class "cxgb3i" need to be specified. This is done by
40+ creating a new interface file in /etc/iscsi/ifaces.
41+
42+ The content of the file should be in the following format:
43+ iface.transport_name = cxgb3i
44+ iface.net_ifacename = <ethX>
45+ iface.ipaddress = <iscsi ip address>
46+
47+ * iface.ipaddress is optional, <iscsi ip address> can be either the same as
48+ the ethX's ip address or an address on the same subnet. Make sure the
49+ address is unique in the network.
50+
51+2. edit /etc/iscsi/iscsid.conf
52+ The default setting for MaxRecvDataSegmentLength (131072) is too big, search
53+ and replace all occurances of "xxx.iscsi.MaxRecvDataSegmentLength" to be a
54+ smaller value (8192 is recommended):
55+
56+ discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 8192
57+ node.conn[0].iscsi.MaxRecvDataSegmentLength = 8192
58+
59+3. Load the cxgb3i driver: "modprobe cxgb3i"
60+
61+ * in the case of recompiling the kernel, the cxgb3i selection is located at
62+ Device Drivers
63+ SCSI device support --->
64+ [*] SCSI low-level drivers --->
65+ <M> Chelsio S3xx iSCSI support
66+
67+4. To direct open-iscsi traffic to go through cxgb3i's accelerated path,
68+ "-I <iface file name>" option needs to be specified with most of the
69+ iscsiadm command. <iface file name> is the transport interface file created
70+ in step 1.
71diff -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
72--- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_iscsi.c 2008-11-25 09:16:10.000000000 -0600
73+++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_iscsi.c 2008-12-01 18:32:55.000000000 -0600
74@@ -22,6 +22,12 @@
75 #include <scsi/scsi_transport_iscsi.h>
76
77 #include "cxgb3i.h"
78+#include "cxgb3i_ulp2.h"
79+
80+#define align_to_4k_boundary(n) \
81+ do { \
82+ n = (n) & ~((1 << 12) - 1); \
83+ } while(0)
84
85 static struct scsi_transport_template *cxgb3i_scsi_transport;
86 static struct scsi_host_template cxgb3i_host_template;
87@@ -370,36 +376,59 @@
88 *
89 * Creates a new iSCSI connection instance for a given session
90 */
91-static inline void cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn)
92+static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn)
93 {
94 struct cxgb3i_conn *cconn = conn->dd_data;
95+ unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE,
96+ cconn->hba->snic->tx_max_size -
97+ ISCSI_PDU_HEADER_MAX);
98+
99+ cxgb3i_log_debug("conn 0x%p, max xmit %u.\n",
100+ conn, conn->max_xmit_dlength);
101
102 if (conn->max_xmit_dlength)
103 conn->max_xmit_dlength = min_t(unsigned int,
104- conn->max_xmit_dlength,
105- cconn->hba->snic->tx_max_size -
106- ISCSI_PDU_HEADER_MAX);
107+ conn->max_xmit_dlength, max);
108 else
109- conn->max_xmit_dlength = cconn->hba->snic->tx_max_size -
110- ISCSI_PDU_HEADER_MAX;
111- cxgb3i_log_debug("conn 0x%p, max xmit %u.\n",
112+ conn->max_xmit_dlength = max;
113+
114+ align_to_4k_boundary(conn->max_xmit_dlength);
115+
116+ cxgb3i_log_debug("conn 0x%p, set max xmit %u.\n",
117 conn, conn->max_xmit_dlength);
118+
119+ return 0;
120 }
121
122-static inline void cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn)
123+static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn)
124 {
125 struct cxgb3i_conn *cconn = conn->dd_data;
126+ unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_SIZE,
127+ cconn->hba->snic->rx_max_size -
128+ ISCSI_PDU_HEADER_MAX);
129
130- if (conn->max_recv_dlength)
131- conn->max_recv_dlength = min_t(unsigned int,
132- conn->max_recv_dlength,
133- cconn->hba->snic->rx_max_size -
134- ISCSI_PDU_HEADER_MAX);
135- else
136- conn->max_recv_dlength = cconn->hba->snic->rx_max_size -
137- ISCSI_PDU_HEADER_MAX;
138 cxgb3i_log_debug("conn 0x%p, max recv %u.\n",
139 conn, conn->max_recv_dlength);
140+
141+ align_to_4k_boundary(max);
142+
143+ if (conn->max_recv_dlength) {
144+ if (conn->max_recv_dlength > max) {
145+ cxgb3i_log_error("MaxRecvDataSegmentLength %u, not supported."
146+ "Need to be <= %u.\n",
147+ conn->max_recv_dlength, max);
148+ return -EINVAL;
149+ }
150+ conn->max_recv_dlength = min_t(unsigned int,
151+ conn->max_recv_dlength, max);
152+ align_to_4k_boundary(conn->max_recv_dlength);
153+ } else
154+ conn->max_recv_dlength = max;
155+
156+ cxgb3i_log_debug("conn 0x%p, set max recv %u.\n",
157+ conn, conn->max_recv_dlength);
158+
159+ return 0;
160 }
161
162 static struct iscsi_cls_conn *cxgb3i_conn_create(struct iscsi_cls_session
163@@ -546,13 +575,13 @@
164 switch (param) {
165 case ISCSI_PARAM_HDRDGST_EN:
166 err = iscsi_set_param(cls_conn, param, buf, buflen);
167- if (!err && conn->hdrdgst_en)
168+ if (!err)
169 cxgb3i_conn_ulp_setup(cconn, conn->hdrdgst_en,
170 conn->datadgst_en);
171 break;
172 case ISCSI_PARAM_DATADGST_EN:
173 err = iscsi_set_param(cls_conn, param, buf, buflen);
174- if (!err && conn->datadgst_en)
175+ if (!err)
176 cxgb3i_conn_ulp_setup(cconn, conn->hdrdgst_en,
177 conn->datadgst_en);
178 break;
179@@ -568,11 +597,11 @@
180 return -ENOMEM;
181 case ISCSI_PARAM_MAX_RECV_DLENGTH:
182 err = iscsi_set_param(cls_conn, param, buf, buflen);
183- cxgb3i_conn_max_recv_dlength(conn);
184+ err = cxgb3i_conn_max_recv_dlength(conn);
185 break;
186 case ISCSI_PARAM_MAX_XMIT_DLENGTH:
187 err = iscsi_set_param(cls_conn, param, buf, buflen);
188- cxgb3i_conn_max_xmit_dlength(conn);
189+ err = cxgb3i_conn_max_xmit_dlength(conn);
190 break;
191 default:
192 return iscsi_set_param(cls_conn, param, buf, buflen);
193diff -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
194--- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_offload.c 2008-11-25 09:16:10.000000000 -0600
195+++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_offload.c 2008-12-01 18:32:55.000000000 -0600
196@@ -45,6 +45,12 @@
197 #define c3cn_tx_debug(fmt...)
198 #endif
199
200+#ifdef __DEBUG_C3CN_RX__
201+#define c3cn_rx_debug cxgb3i_log_debug
202+#else
203+#define c3cn_rx_debug(fmt...)
204+#endif
205+
206 /* connection flags */
207 static inline void c3cn_set_flag(struct s3_conn *c3cn, enum c3cn_flags flag)
208 {
209@@ -1577,6 +1583,9 @@
210 skb_ulp_ddigest(skb) = ntohl(ddp_cpl.ulp_crc);
211 status = ntohl(ddp_cpl.ddp_status);
212
213+ c3cn_rx_debug("skb 0x%p, len %u, pdulen %u, ddp status 0x%x.\n",
214+ skb, skb->len, skb_ulp_pdulen(skb), status);
215+
216 if (status & (1 << RX_DDP_STATUS_HCRC_SHIFT))
217 skb_ulp_mode(skb) |= ULP2_FLAG_HCRC_ERROR;
218 if (status & (1 << RX_DDP_STATUS_DCRC_SHIFT))
219diff -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
220--- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.c 2008-11-25 09:16:10.000000000 -0600
221+++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.c 2008-12-01 18:32:55.000000000 -0600
222@@ -145,6 +145,9 @@
223 PAGE_SHIFT;
224 int i = 1, j = 0;
225
226+ if (sgoffset)
227+ return NULL;
228+
229 gl = kzalloc(sizeof(struct cxgb3i_gather_list) +
230 npages * (sizeof(dma_addr_t) + sizeof(struct page *)),
231 gfp);
232@@ -173,7 +176,7 @@
233 goto error_out;
234
235 j++;
236- if (j == gl->nelem)
237+ if (j == gl->nelem || sg->offset)
238 goto error_out;
239 gl->pages[j] = page;
240 sglen = sg->length;
241@@ -303,7 +306,8 @@
242 int idx = -1, idx_max;
243 u32 tag;
244
245- if (page_idx || !ddp || !sgcnt || xferlen < ULP2_DDP_THRESHOLD) {
246+ if (page_idx >= ULP2_PGIDX_MAX || !ddp || !sgcnt ||
247+ xferlen < ULP2_DDP_THRESHOLD) {
248 cxgb3i_tag_debug("pgidx %u, sgcnt %u, xfer %u/%u, NO ddp.\n",
249 page_idx, sgcnt, xferlen, ULP2_DDP_THRESHOLD);
250 return RESERVED_ITT;
251@@ -330,10 +334,9 @@
252 npods, gl);
253 }
254 if (idx < 0) {
255- kfree(gl);
256 cxgb3i_tag_debug("sgcnt %u, xferlen %u, npods %u NO DDP.\n",
257 sgcnt, xferlen, npods);
258- return RESERVED_ITT;
259+ goto free_gl;
260 }
261
262 if (ddp_alloc_gl_skb(ddp, idx, npods, gfp) < 0)
263@@ -341,7 +344,7 @@
264
265 if (ddp_gl_map(snic->pdev, gl) < 0)
266 goto unmap_sgl;
267-
268+
269 tag = sw_tag | (idx << snic->tag_format.rsvd_shift);
270
271 hdr.rsvd = 0;
272@@ -363,6 +366,8 @@
273 ddp_free_gl_skb(ddp, idx, npods);
274 unmark_entries:
275 ddp_unmark_entries(ddp, idx, npods);
276+free_gl:
277+ kfree(gl);
278 return RESERVED_ITT;
279 }
280
281@@ -393,8 +398,10 @@
282 struct sk_buff *skb = alloc_skb(sizeof(struct cpl_set_tcb_field),
283 GFP_KERNEL | __GFP_NOFAIL);
284 struct cpl_set_tcb_field *req;
285- u32 submode = (hcrc ? 1 : 0) | (dcrc ? 2 : 0);
286- u32 pgcode = page_idx < ULP2_PGIDX_MAX ? page_idx : 0;
287+ u64 val = (hcrc ? 1 : 0) | (dcrc ? 2 : 0);
288+
289+ if (page_idx < ULP2_PGIDX_MAX)
290+ val |= page_idx << 4;
291
292 /* set up ulp submode and page size */
293 req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
294@@ -404,7 +411,7 @@
295 req->cpu_idx = 0;
296 req->word = htons(31);
297 req->mask = cpu_to_be64(0xFF000000);
298- req->val = cpu_to_be64(((pgcode << 4) | submode) << 24);
299+ req->val = cpu_to_be64(val << 24);
300 skb->priority = CPL_PRIORITY_CONTROL;
301
302 cxgb3_ofld_send(c3cn->cdev, skb);
303@@ -461,12 +468,16 @@
304 segment->status = (conn->datadgst_en &&
305 (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) ?
306 ISCSI_SEGMENT_DGST_ERR : 0;
307- if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED)
308+ if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) {
309+ cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, ddp'ed, "
310+ "itt 0x%x.\n",
311+ skb, hdr->opcode & ISCSI_OPCODE_MASK,
312+ tcp_conn->in.datalen, hdr->itt);
313 segment->total_copied = segment->total_size;
314- else {
315- cxgb3i_ddp_debug("opcode 0x%x, data %u, NOT ddp'ed, "
316+ } else {
317+ cxgb3i_ddp_debug("skb 0x%p, opcode 0x%x, data %u, not ddp'ed, "
318 "itt 0x%x.\n",
319- hdr->opcode & ISCSI_OPCODE_MASK,
320+ skb, hdr->opcode & ISCSI_OPCODE_MASK,
321 tcp_conn->in.datalen, hdr->itt);
322 offset += sizeof(struct cpl_iscsi_hdr_norss);
323 }
324diff -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
325--- linux-2.6.27.7-4.orig/drivers/scsi/cxgb3i/cxgb3i_ulp2.h 2008-11-25 09:16:10.000000000 -0600
326+++ linux-2.6.27.7-4.new/drivers/scsi/cxgb3i/cxgb3i_ulp2.h 2008-12-01 18:32:55.000000000 -0600
327@@ -101,6 +101,7 @@
328 #define ULP2_FLAG_PAD_ERROR 0x40
329
330 #define ULP2_MAX_PKT_SIZE 16224
331+#define ULP2_MAX_PDU_SIZE 8192
332
333 void cxgb3i_conn_closing(struct s3_conn *);
334 void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn);