aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2008-12-02 01:32:04 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-12-29 12:24:20 -0500
commit63c62f1cb980241513c82cacd5b9f878527c6647 (patch)
tree929f7609d410db8654ed1e262725ca2d3203f199
parentb29f841378460c37e99a2398d0015d9bd7901a09 (diff)
[SCSI] iscsi_tcp: prepare helpers for LLDs that can offload some operations
cxgb3i is unlike qla4xxx and bnx2i in that it does not offload entire scsi commands or iscsi sequences. Instead it only offloads the transfer of a ISCSI DATA_IN pdu's data, the digests and padding. This patch fixes up the iscsi tcp recv path so that it exports its skb recv processing so cxgb3i and other drivers can call them. All they have to do is pass the function the skb with the hdr or data pdu header and this function will do the rest. 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.c120
-rw-r--r--include/scsi/iscsi_if.h5
2 files changed, 92 insertions, 33 deletions
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index e11bce6ab63c..464de780d953 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -486,7 +486,8 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
486 struct iscsi_conn *conn = tcp_conn->iscsi_conn; 486 struct iscsi_conn *conn = tcp_conn->iscsi_conn;
487 struct hash_desc *rx_hash = NULL; 487 struct hash_desc *rx_hash = NULL;
488 488
489 if (conn->datadgst_en) 489 if (conn->datadgst_en &
490 !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
490 rx_hash = &tcp_conn->rx_hash; 491 rx_hash = &tcp_conn->rx_hash;
491 492
492 iscsi_segment_init_linear(&tcp_conn->in.segment, 493 iscsi_segment_init_linear(&tcp_conn->in.segment,
@@ -774,7 +775,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
774 * we move on to the next scatterlist entry and 775 * we move on to the next scatterlist entry and
775 * update the digest per-entry. 776 * update the digest per-entry.
776 */ 777 */
777 if (conn->datadgst_en) 778 if (conn->datadgst_en &&
779 !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
778 rx_hash = &tcp_conn->rx_hash; 780 rx_hash = &tcp_conn->rx_hash;
779 781
780 debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, " 782 debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, "
@@ -902,34 +904,52 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
902 * and go back for more. */ 904 * and go back for more. */
903 if (conn->hdrdgst_en) { 905 if (conn->hdrdgst_en) {
904 if (segment->digest_len == 0) { 906 if (segment->digest_len == 0) {
907 /*
908 * Even if we offload the digest processing we
909 * splice it in so we can increment the skb/segment
910 * counters in preparation for the data segment.
911 */
905 iscsi_tcp_segment_splice_digest(segment, 912 iscsi_tcp_segment_splice_digest(segment,
906 segment->recv_digest); 913 segment->recv_digest);
907 return 0; 914 return 0;
908 } 915 }
909 iscsi_tcp_dgst_header(&tcp_conn->rx_hash, hdr,
910 segment->total_copied - ISCSI_DIGEST_SIZE,
911 segment->digest);
912 916
913 if (!iscsi_tcp_dgst_verify(tcp_conn, segment)) 917 if (!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) {
914 return ISCSI_ERR_HDR_DGST; 918 iscsi_tcp_dgst_header(&tcp_conn->rx_hash, hdr,
919 segment->total_copied - ISCSI_DIGEST_SIZE,
920 segment->digest);
921
922 if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
923 return ISCSI_ERR_HDR_DGST;
924 }
915 } 925 }
916 926
917 tcp_conn->in.hdr = hdr; 927 tcp_conn->in.hdr = hdr;
918 return iscsi_tcp_hdr_dissect(conn, hdr); 928 return iscsi_tcp_hdr_dissect(conn, hdr);
919} 929}
920 930
931inline int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn)
932{
933 return tcp_conn->in.segment.done == iscsi_tcp_hdr_recv_done;
934}
935
936enum {
937 ISCSI_TCP_SEGMENT_DONE, /* curr seg has been processed */
938 ISCSI_TCP_SKB_DONE, /* skb is out of data */
939 ISCSI_TCP_CONN_ERR, /* iscsi layer has fired a conn err */
940 ISCSI_TCP_SUSPENDED, /* conn is suspended */
941};
942
921/** 943/**
922 * iscsi_tcp_recv - TCP receive in sendfile fashion 944 * iscsi_tcp_recv_skb - Process skb
923 * @rd_desc: read descriptor 945 * @conn: iscsi connection
924 * @skb: socket buffer 946 * @skb: network buffer with header and/or data segment
925 * @offset: offset in skb 947 * @offset: offset in skb
926 * @len: skb->len - offset 948 * @offload: bool indicating if transfer was offloaded
927 **/ 949 */
928static int 950int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
929iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, 951 unsigned int offset, bool offloaded, int *status)
930 unsigned int offset, size_t len)
931{ 952{
932 struct iscsi_conn *conn = rd_desc->arg.data;
933 struct iscsi_tcp_conn *tcp_conn = conn->dd_data; 953 struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
934 struct iscsi_segment *segment = &tcp_conn->in.segment; 954 struct iscsi_segment *segment = &tcp_conn->in.segment;
935 struct skb_seq_state seq; 955 struct skb_seq_state seq;
@@ -940,9 +960,15 @@ iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
940 960
941 if (unlikely(conn->suspend_rx)) { 961 if (unlikely(conn->suspend_rx)) {
942 debug_tcp("conn %d Rx suspended!\n", conn->id); 962 debug_tcp("conn %d Rx suspended!\n", conn->id);
963 *status = ISCSI_TCP_SUSPENDED;
943 return 0; 964 return 0;
944 } 965 }
945 966
967 if (offloaded) {
968 segment->total_copied = segment->total_size;
969 goto segment_done;
970 }
971
946 skb_prepare_seq_read(skb, offset, skb->len, &seq); 972 skb_prepare_seq_read(skb, offset, skb->len, &seq);
947 while (1) { 973 while (1) {
948 unsigned int avail; 974 unsigned int avail;
@@ -952,7 +978,9 @@ iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
952 if (avail == 0) { 978 if (avail == 0) {
953 debug_tcp("no more data avail. Consumed %d\n", 979 debug_tcp("no more data avail. Consumed %d\n",
954 consumed); 980 consumed);
955 break; 981 *status = ISCSI_TCP_SKB_DONE;
982 skb_abort_seq_read(&seq);
983 goto skb_done;
956 } 984 }
957 BUG_ON(segment->copied >= segment->size); 985 BUG_ON(segment->copied >= segment->size);
958 986
@@ -962,25 +990,55 @@ iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
962 consumed += rc; 990 consumed += rc;
963 991
964 if (segment->total_copied >= segment->total_size) { 992 if (segment->total_copied >= segment->total_size) {
965 debug_tcp("segment done\n"); 993 skb_abort_seq_read(&seq);
966 rc = segment->done(tcp_conn, segment); 994 goto segment_done;
967 if (rc != 0) {
968 skb_abort_seq_read(&seq);
969 goto error;
970 }
971
972 /* The done() functions sets up the
973 * next segment. */
974 } 995 }
975 } 996 }
976 skb_abort_seq_read(&seq); 997
998segment_done:
999 *status = ISCSI_TCP_SEGMENT_DONE;
1000 debug_tcp("segment done\n");
1001 rc = segment->done(tcp_conn, segment);
1002 if (rc != 0) {
1003 *status = ISCSI_TCP_CONN_ERR;
1004 debug_tcp("Error receiving PDU, errno=%d\n", rc);
1005 iscsi_conn_failure(conn, rc);
1006 return 0;
1007 }
1008 /* The done() functions sets up the next segment. */
1009
1010skb_done:
977 conn->rxdata_octets += consumed; 1011 conn->rxdata_octets += consumed;
978 return consumed; 1012 return consumed;
1013}
1014EXPORT_SYMBOL_GPL(iscsi_tcp_recv_skb);
979 1015
980error: 1016/**
981 debug_tcp("Error receiving PDU, errno=%d\n", rc); 1017 * iscsi_tcp_recv - TCP receive in sendfile fashion
982 iscsi_conn_failure(conn, rc); 1018 * @rd_desc: read descriptor
983 return 0; 1019 * @skb: socket buffer
1020 * @offset: offset in skb
1021 * @len: skb->len - offset
1022 **/
1023static int
1024iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
1025 unsigned int offset, size_t len)
1026{
1027 struct iscsi_conn *conn = rd_desc->arg.data;
1028 unsigned int consumed, total_consumed = 0;
1029 int status;
1030
1031 debug_tcp("in %d bytes\n", skb->len - offset);
1032
1033 do {
1034 status = 0;
1035 consumed = iscsi_tcp_recv_skb(conn, skb, offset, 0, &status);
1036 offset += consumed;
1037 total_consumed += consumed;
1038 } while (consumed != 0 && status != ISCSI_TCP_SKB_DONE);
1039
1040 debug_tcp("read %d bytes status %d\n", skb->len - offset, status);
1041 return total_consumed;
984} 1042}
985 1043
986static void 1044static void
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 0c9514de5df7..8e008c96e795 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -333,8 +333,9 @@ enum iscsi_host_param {
333#define CAP_TEXT_NEGO 0x80 333#define CAP_TEXT_NEGO 0x80
334#define CAP_MARKERS 0x100 334#define CAP_MARKERS 0x100
335#define CAP_FW_DB 0x200 335#define CAP_FW_DB 0x200
336#define CAP_SENDTARGETS_OFFLOAD 0x400 336#define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */
337#define CAP_DATA_PATH_OFFLOAD 0x800 337#define CAP_DATA_PATH_OFFLOAD 0x800 /* offload entire IO path */
338#define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */
338 339
339/* 340/*
340 * These flags describes reason of stop_conn() call 341 * These flags describes reason of stop_conn() call