aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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