diff options
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 120 | ||||
-rw-r--r-- | include/scsi/iscsi_if.h | 5 |
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 | ||
931 | inline 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 | |||
936 | enum { | ||
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 | */ |
928 | static int | 950 | int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb, |
929 | iscsi_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 | |
998 | segment_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 | |||
1010 | skb_done: | ||
977 | conn->rxdata_octets += consumed; | 1011 | conn->rxdata_octets += consumed; |
978 | return consumed; | 1012 | return consumed; |
1013 | } | ||
1014 | EXPORT_SYMBOL_GPL(iscsi_tcp_recv_skb); | ||
979 | 1015 | ||
980 | error: | 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 | **/ | ||
1023 | static int | ||
1024 | iscsi_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 | ||
986 | static void | 1044 | static 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 |