Skip to content

Commit

Permalink
[SCSI] iscsi_tcp: prepare helpers for LLDs that can offload some oper…
Browse files Browse the repository at this point in the history
…ations

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>
  • Loading branch information
Mike Christie authored and James Bottomley committed Dec 29, 2008
1 parent b29f841 commit 63c62f1
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 33 deletions.
120 changes: 89 additions & 31 deletions drivers/scsi/iscsi_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,8 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn)
struct iscsi_conn *conn = tcp_conn->iscsi_conn;
struct hash_desc *rx_hash = NULL;

if (conn->datadgst_en)
if (conn->datadgst_en &
!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
rx_hash = &tcp_conn->rx_hash;

iscsi_segment_init_linear(&tcp_conn->in.segment,
Expand Down Expand Up @@ -774,7 +775,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
* we move on to the next scatterlist entry and
* update the digest per-entry.
*/
if (conn->datadgst_en)
if (conn->datadgst_en &&
!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD))
rx_hash = &tcp_conn->rx_hash;

debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, "
Expand Down Expand Up @@ -902,34 +904,52 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
* and go back for more. */
if (conn->hdrdgst_en) {
if (segment->digest_len == 0) {
/*
* Even if we offload the digest processing we
* splice it in so we can increment the skb/segment
* counters in preparation for the data segment.
*/
iscsi_tcp_segment_splice_digest(segment,
segment->recv_digest);
return 0;
}
iscsi_tcp_dgst_header(&tcp_conn->rx_hash, hdr,
segment->total_copied - ISCSI_DIGEST_SIZE,
segment->digest);

if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
return ISCSI_ERR_HDR_DGST;
if (!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) {
iscsi_tcp_dgst_header(&tcp_conn->rx_hash, hdr,
segment->total_copied - ISCSI_DIGEST_SIZE,
segment->digest);

if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
return ISCSI_ERR_HDR_DGST;
}
}

tcp_conn->in.hdr = hdr;
return iscsi_tcp_hdr_dissect(conn, hdr);
}

inline int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn)
{
return tcp_conn->in.segment.done == iscsi_tcp_hdr_recv_done;
}

enum {
ISCSI_TCP_SEGMENT_DONE, /* curr seg has been processed */
ISCSI_TCP_SKB_DONE, /* skb is out of data */
ISCSI_TCP_CONN_ERR, /* iscsi layer has fired a conn err */
ISCSI_TCP_SUSPENDED, /* conn is suspended */
};

/**
* iscsi_tcp_recv - TCP receive in sendfile fashion
* @rd_desc: read descriptor
* @skb: socket buffer
* iscsi_tcp_recv_skb - Process skb
* @conn: iscsi connection
* @skb: network buffer with header and/or data segment
* @offset: offset in skb
* @len: skb->len - offset
**/
static int
iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
unsigned int offset, size_t len)
* @offload: bool indicating if transfer was offloaded
*/
int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
unsigned int offset, bool offloaded, int *status)
{
struct iscsi_conn *conn = rd_desc->arg.data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_segment *segment = &tcp_conn->in.segment;
struct skb_seq_state seq;
Expand All @@ -940,9 +960,15 @@ iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,

if (unlikely(conn->suspend_rx)) {
debug_tcp("conn %d Rx suspended!\n", conn->id);
*status = ISCSI_TCP_SUSPENDED;
return 0;
}

if (offloaded) {
segment->total_copied = segment->total_size;
goto segment_done;
}

skb_prepare_seq_read(skb, offset, skb->len, &seq);
while (1) {
unsigned int avail;
Expand All @@ -952,7 +978,9 @@ iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
if (avail == 0) {
debug_tcp("no more data avail. Consumed %d\n",
consumed);
break;
*status = ISCSI_TCP_SKB_DONE;
skb_abort_seq_read(&seq);
goto skb_done;
}
BUG_ON(segment->copied >= segment->size);

Expand All @@ -962,25 +990,55 @@ iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
consumed += rc;

if (segment->total_copied >= segment->total_size) {
debug_tcp("segment done\n");
rc = segment->done(tcp_conn, segment);
if (rc != 0) {
skb_abort_seq_read(&seq);
goto error;
}

/* The done() functions sets up the
* next segment. */
skb_abort_seq_read(&seq);
goto segment_done;
}
}
skb_abort_seq_read(&seq);

segment_done:
*status = ISCSI_TCP_SEGMENT_DONE;
debug_tcp("segment done\n");
rc = segment->done(tcp_conn, segment);
if (rc != 0) {
*status = ISCSI_TCP_CONN_ERR;
debug_tcp("Error receiving PDU, errno=%d\n", rc);
iscsi_conn_failure(conn, rc);
return 0;
}
/* The done() functions sets up the next segment. */

skb_done:
conn->rxdata_octets += consumed;
return consumed;
}
EXPORT_SYMBOL_GPL(iscsi_tcp_recv_skb);

error:
debug_tcp("Error receiving PDU, errno=%d\n", rc);
iscsi_conn_failure(conn, rc);
return 0;
/**
* iscsi_tcp_recv - TCP receive in sendfile fashion
* @rd_desc: read descriptor
* @skb: socket buffer
* @offset: offset in skb
* @len: skb->len - offset
**/
static int
iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
unsigned int offset, size_t len)
{
struct iscsi_conn *conn = rd_desc->arg.data;
unsigned int consumed, total_consumed = 0;
int status;

debug_tcp("in %d bytes\n", skb->len - offset);

do {
status = 0;
consumed = iscsi_tcp_recv_skb(conn, skb, offset, 0, &status);
offset += consumed;
total_consumed += consumed;
} while (consumed != 0 && status != ISCSI_TCP_SKB_DONE);

debug_tcp("read %d bytes status %d\n", skb->len - offset, status);
return total_consumed;
}

static void
Expand Down
5 changes: 3 additions & 2 deletions include/scsi/iscsi_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,9 @@ enum iscsi_host_param {
#define CAP_TEXT_NEGO 0x80
#define CAP_MARKERS 0x100
#define CAP_FW_DB 0x200
#define CAP_SENDTARGETS_OFFLOAD 0x400
#define CAP_DATA_PATH_OFFLOAD 0x800
#define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */
#define CAP_DATA_PATH_OFFLOAD 0x800 /* offload entire IO path */
#define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */

/*
* These flags describes reason of stop_conn() call
Expand Down

0 comments on commit 63c62f1

Please sign in to comment.