diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2008-12-02 01:32:16 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-12-29 12:24:23 -0500 |
commit | 6df19a791bdd5d820cccd8c7a12679888ae62099 (patch) | |
tree | 5afebc101c362d0a41275337dced617fb06f8a89 | |
parent | ae15f80172d95f978b60d40408353943d5bc099b (diff) |
[SCSI] libiscsi_tcp: support padding offload
cxgb3i does not offload the processing of the header,
but it will always process the padding. This patch
adds a padding offload flag to detect when the LLD
supports this.
The patch also modifies the header processing so that
we do not try to read/bypass the header dugest in the
skb. cxgb3i will not include it with the header like
with other offload cards.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 9 | ||||
-rw-r--r-- | drivers/scsi/libiscsi_tcp.c | 37 | ||||
-rw-r--r-- | include/scsi/iscsi_if.h | 2 | ||||
-rw-r--r-- | include/scsi/libiscsi_tcp.h | 3 |
4 files changed, 29 insertions, 22 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index de5c9b3e51fb..23808dfe22ba 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -194,7 +194,7 @@ iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_sw_tcp_conn *tcp_sw_conn) | |||
194 | 194 | ||
195 | /** | 195 | /** |
196 | * iscsi_sw_tcp_xmit_segment - transmit segment | 196 | * iscsi_sw_tcp_xmit_segment - transmit segment |
197 | * @tcp_sw_conn: the iSCSI TCP connection | 197 | * @tcp_conn: the iSCSI TCP connection |
198 | * @segment: the buffer to transmnit | 198 | * @segment: the buffer to transmnit |
199 | * | 199 | * |
200 | * This function transmits as much of the buffer as | 200 | * This function transmits as much of the buffer as |
@@ -205,14 +205,15 @@ iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_sw_tcp_conn *tcp_sw_conn) | |||
205 | * hash as it goes. When the entire segment has been transmitted, | 205 | * hash as it goes. When the entire segment has been transmitted, |
206 | * it will retrieve the hash value and send it as well. | 206 | * it will retrieve the hash value and send it as well. |
207 | */ | 207 | */ |
208 | static int iscsi_sw_tcp_xmit_segment(struct iscsi_sw_tcp_conn *tcp_sw_conn, | 208 | static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn, |
209 | struct iscsi_segment *segment) | 209 | struct iscsi_segment *segment) |
210 | { | 210 | { |
211 | struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; | ||
211 | struct socket *sk = tcp_sw_conn->sock; | 212 | struct socket *sk = tcp_sw_conn->sock; |
212 | unsigned int copied = 0; | 213 | unsigned int copied = 0; |
213 | int r = 0; | 214 | int r = 0; |
214 | 215 | ||
215 | while (!iscsi_tcp_segment_done(segment, 0, r)) { | 216 | while (!iscsi_tcp_segment_done(tcp_conn, segment, 0, r)) { |
216 | struct scatterlist *sg; | 217 | struct scatterlist *sg; |
217 | unsigned int offset, copy; | 218 | unsigned int offset, copy; |
218 | int flags = 0; | 219 | int flags = 0; |
@@ -263,7 +264,7 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn) | |||
263 | int rc = 0; | 264 | int rc = 0; |
264 | 265 | ||
265 | while (1) { | 266 | while (1) { |
266 | rc = iscsi_sw_tcp_xmit_segment(tcp_sw_conn, segment); | 267 | rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment); |
267 | if (rc < 0) { | 268 | if (rc < 0) { |
268 | rc = ISCSI_ERR_XMIT_FAILED; | 269 | rc = ISCSI_ERR_XMIT_FAILED; |
269 | goto error; | 270 | goto error; |
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 9df6b3436e4a..a745f91d2928 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c | |||
@@ -159,6 +159,7 @@ iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest) | |||
159 | 159 | ||
160 | /** | 160 | /** |
161 | * iscsi_tcp_segment_done - check whether the segment is complete | 161 | * iscsi_tcp_segment_done - check whether the segment is complete |
162 | * @tcp_conn: iscsi tcp connection | ||
162 | * @segment: iscsi segment to check | 163 | * @segment: iscsi segment to check |
163 | * @recv: set to one of this is called from the recv path | 164 | * @recv: set to one of this is called from the recv path |
164 | * @copied: number of bytes copied | 165 | * @copied: number of bytes copied |
@@ -172,7 +173,8 @@ iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest) | |||
172 | * | 173 | * |
173 | * This function must be re-entrant. | 174 | * This function must be re-entrant. |
174 | */ | 175 | */ |
175 | int iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv, | 176 | int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, |
177 | struct iscsi_segment *segment, int recv, | ||
176 | unsigned copied) | 178 | unsigned copied) |
177 | { | 179 | { |
178 | static unsigned char padbuf[ISCSI_PAD_LEN]; | 180 | static unsigned char padbuf[ISCSI_PAD_LEN]; |
@@ -225,13 +227,15 @@ int iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv, | |||
225 | } | 227 | } |
226 | 228 | ||
227 | /* Do we need to handle padding? */ | 229 | /* Do we need to handle padding? */ |
228 | pad = iscsi_padding(segment->total_copied); | 230 | if (!(tcp_conn->iscsi_conn->session->tt->caps & CAP_PADDING_OFFLOAD)) { |
229 | if (pad != 0) { | 231 | pad = iscsi_padding(segment->total_copied); |
230 | debug_tcp("consume %d pad bytes\n", pad); | 232 | if (pad != 0) { |
231 | segment->total_size += pad; | 233 | debug_tcp("consume %d pad bytes\n", pad); |
232 | segment->size = pad; | 234 | segment->total_size += pad; |
233 | segment->data = padbuf; | 235 | segment->size = pad; |
234 | return 0; | 236 | segment->data = padbuf; |
237 | return 0; | ||
238 | } | ||
235 | } | 239 | } |
236 | 240 | ||
237 | /* | 241 | /* |
@@ -273,7 +277,7 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn, | |||
273 | { | 277 | { |
274 | unsigned int copy = 0, copied = 0; | 278 | unsigned int copy = 0, copied = 0; |
275 | 279 | ||
276 | while (!iscsi_tcp_segment_done(segment, 1, copy)) { | 280 | while (!iscsi_tcp_segment_done(tcp_conn, segment, 1, copy)) { |
277 | if (copied == len) { | 281 | if (copied == len) { |
278 | debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n", | 282 | debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n", |
279 | len); | 283 | len); |
@@ -794,7 +798,8 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, | |||
794 | /* We're done processing the header. See if we're doing | 798 | /* We're done processing the header. See if we're doing |
795 | * header digests; if so, set up the recv_digest buffer | 799 | * header digests; if so, set up the recv_digest buffer |
796 | * and go back for more. */ | 800 | * and go back for more. */ |
797 | if (conn->hdrdgst_en) { | 801 | if (conn->hdrdgst_en && |
802 | !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) { | ||
798 | if (segment->digest_len == 0) { | 803 | if (segment->digest_len == 0) { |
799 | /* | 804 | /* |
800 | * Even if we offload the digest processing we | 805 | * Even if we offload the digest processing we |
@@ -806,14 +811,12 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, | |||
806 | return 0; | 811 | return 0; |
807 | } | 812 | } |
808 | 813 | ||
809 | if (!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) { | 814 | iscsi_tcp_dgst_header(tcp_conn->rx_hash, hdr, |
810 | iscsi_tcp_dgst_header(tcp_conn->rx_hash, hdr, | 815 | segment->total_copied - ISCSI_DIGEST_SIZE, |
811 | segment->total_copied - ISCSI_DIGEST_SIZE, | 816 | segment->digest); |
812 | segment->digest); | ||
813 | 817 | ||
814 | if (!iscsi_tcp_dgst_verify(tcp_conn, segment)) | 818 | if (!iscsi_tcp_dgst_verify(tcp_conn, segment)) |
815 | return ISCSI_ERR_HDR_DGST; | 819 | return ISCSI_ERR_HDR_DGST; |
816 | } | ||
817 | } | 820 | } |
818 | 821 | ||
819 | tcp_conn->in.hdr = hdr; | 822 | tcp_conn->in.hdr = hdr; |
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 8e008c96e795..d0ed5226f8c4 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h | |||
@@ -336,6 +336,8 @@ enum iscsi_host_param { | |||
336 | #define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */ | 336 | #define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */ |
337 | #define CAP_DATA_PATH_OFFLOAD 0x800 /* offload entire IO path */ | 337 | #define CAP_DATA_PATH_OFFLOAD 0x800 /* offload entire IO path */ |
338 | #define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */ | 338 | #define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */ |
339 | #define CAP_PADDING_OFFLOAD 0x2000 /* offload padding insertion, removal, | ||
340 | and verification */ | ||
339 | 341 | ||
340 | /* | 342 | /* |
341 | * These flags describes reason of stop_conn() call | 343 | * These flags describes reason of stop_conn() call |
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h index e6bf8ef276bb..83e32f6d7859 100644 --- a/include/scsi/libiscsi_tcp.h +++ b/include/scsi/libiscsi_tcp.h | |||
@@ -99,7 +99,8 @@ extern int iscsi_tcp_task_xmit(struct iscsi_task *task); | |||
99 | 99 | ||
100 | /* segment helpers */ | 100 | /* segment helpers */ |
101 | extern int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn); | 101 | extern int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn); |
102 | extern int iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv, | 102 | extern int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, |
103 | struct iscsi_segment *segment, int recv, | ||
103 | unsigned copied); | 104 | unsigned copied); |
104 | extern void iscsi_tcp_segment_unmap(struct iscsi_segment *segment); | 105 | extern void iscsi_tcp_segment_unmap(struct iscsi_segment *segment); |
105 | 106 | ||