[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>
This commit is contained in:
committed by
James Bottomley
parent
ae15f80172
commit
6df19a791b
@@ -194,7 +194,7 @@ iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_sw_tcp_conn *tcp_sw_conn)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* iscsi_sw_tcp_xmit_segment - transmit segment
|
* iscsi_sw_tcp_xmit_segment - transmit segment
|
||||||
* @tcp_sw_conn: the iSCSI TCP connection
|
* @tcp_conn: the iSCSI TCP connection
|
||||||
* @segment: the buffer to transmnit
|
* @segment: the buffer to transmnit
|
||||||
*
|
*
|
||||||
* This function transmits as much of the buffer as
|
* 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)
|
|||||||
* hash as it goes. When the entire segment has been transmitted,
|
* hash as it goes. When the entire segment has been transmitted,
|
||||||
* it will retrieve the hash value and send it as well.
|
* it will retrieve the hash value and send it as well.
|
||||||
*/
|
*/
|
||||||
static int iscsi_sw_tcp_xmit_segment(struct iscsi_sw_tcp_conn *tcp_sw_conn,
|
static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn,
|
||||||
struct iscsi_segment *segment)
|
struct iscsi_segment *segment)
|
||||||
{
|
{
|
||||||
|
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
|
||||||
struct socket *sk = tcp_sw_conn->sock;
|
struct socket *sk = tcp_sw_conn->sock;
|
||||||
unsigned int copied = 0;
|
unsigned int copied = 0;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
while (!iscsi_tcp_segment_done(segment, 0, r)) {
|
while (!iscsi_tcp_segment_done(tcp_conn, segment, 0, r)) {
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
unsigned int offset, copy;
|
unsigned int offset, copy;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
@@ -263,7 +264,7 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn)
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
rc = iscsi_sw_tcp_xmit_segment(tcp_sw_conn, segment);
|
rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
rc = ISCSI_ERR_XMIT_FAILED;
|
rc = ISCSI_ERR_XMIT_FAILED;
|
||||||
goto error;
|
goto error;
|
||||||
|
@@ -159,6 +159,7 @@ iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* iscsi_tcp_segment_done - check whether the segment is complete
|
* iscsi_tcp_segment_done - check whether the segment is complete
|
||||||
|
* @tcp_conn: iscsi tcp connection
|
||||||
* @segment: iscsi segment to check
|
* @segment: iscsi segment to check
|
||||||
* @recv: set to one of this is called from the recv path
|
* @recv: set to one of this is called from the recv path
|
||||||
* @copied: number of bytes copied
|
* @copied: number of bytes copied
|
||||||
@@ -172,7 +173,8 @@ iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest)
|
|||||||
*
|
*
|
||||||
* This function must be re-entrant.
|
* This function must be re-entrant.
|
||||||
*/
|
*/
|
||||||
int iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv,
|
int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
|
||||||
|
struct iscsi_segment *segment, int recv,
|
||||||
unsigned copied)
|
unsigned copied)
|
||||||
{
|
{
|
||||||
static unsigned char padbuf[ISCSI_PAD_LEN];
|
static unsigned char padbuf[ISCSI_PAD_LEN];
|
||||||
@@ -225,13 +227,15 @@ int iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Do we need to handle padding? */
|
/* Do we need to handle padding? */
|
||||||
pad = iscsi_padding(segment->total_copied);
|
if (!(tcp_conn->iscsi_conn->session->tt->caps & CAP_PADDING_OFFLOAD)) {
|
||||||
if (pad != 0) {
|
pad = iscsi_padding(segment->total_copied);
|
||||||
debug_tcp("consume %d pad bytes\n", pad);
|
if (pad != 0) {
|
||||||
segment->total_size += pad;
|
debug_tcp("consume %d pad bytes\n", pad);
|
||||||
segment->size = pad;
|
segment->total_size += pad;
|
||||||
segment->data = padbuf;
|
segment->size = pad;
|
||||||
return 0;
|
segment->data = padbuf;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -273,7 +277,7 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn,
|
|||||||
{
|
{
|
||||||
unsigned int copy = 0, copied = 0;
|
unsigned int copy = 0, copied = 0;
|
||||||
|
|
||||||
while (!iscsi_tcp_segment_done(segment, 1, copy)) {
|
while (!iscsi_tcp_segment_done(tcp_conn, segment, 1, copy)) {
|
||||||
if (copied == len) {
|
if (copied == len) {
|
||||||
debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n",
|
debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n",
|
||||||
len);
|
len);
|
||||||
@@ -794,7 +798,8 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
|
|||||||
/* We're done processing the header. See if we're doing
|
/* We're done processing the header. See if we're doing
|
||||||
* header digests; if so, set up the recv_digest buffer
|
* header digests; if so, set up the recv_digest buffer
|
||||||
* and go back for more. */
|
* and go back for more. */
|
||||||
if (conn->hdrdgst_en) {
|
if (conn->hdrdgst_en &&
|
||||||
|
!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) {
|
||||||
if (segment->digest_len == 0) {
|
if (segment->digest_len == 0) {
|
||||||
/*
|
/*
|
||||||
* Even if we offload the digest processing we
|
* Even if we offload the digest processing we
|
||||||
@@ -806,14 +811,12 @@ iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) {
|
iscsi_tcp_dgst_header(tcp_conn->rx_hash, hdr,
|
||||||
iscsi_tcp_dgst_header(tcp_conn->rx_hash, hdr,
|
segment->total_copied - ISCSI_DIGEST_SIZE,
|
||||||
segment->total_copied - ISCSI_DIGEST_SIZE,
|
segment->digest);
|
||||||
segment->digest);
|
|
||||||
|
|
||||||
if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
|
if (!iscsi_tcp_dgst_verify(tcp_conn, segment))
|
||||||
return ISCSI_ERR_HDR_DGST;
|
return ISCSI_ERR_HDR_DGST;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tcp_conn->in.hdr = hdr;
|
tcp_conn->in.hdr = hdr;
|
||||||
|
@@ -336,6 +336,8 @@ enum iscsi_host_param {
|
|||||||
#define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */
|
#define CAP_SENDTARGETS_OFFLOAD 0x400 /* offload discovery process */
|
||||||
#define CAP_DATA_PATH_OFFLOAD 0x800 /* offload entire IO path */
|
#define CAP_DATA_PATH_OFFLOAD 0x800 /* offload entire IO path */
|
||||||
#define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */
|
#define CAP_DIGEST_OFFLOAD 0x1000 /* offload hdr and data digests */
|
||||||
|
#define CAP_PADDING_OFFLOAD 0x2000 /* offload padding insertion, removal,
|
||||||
|
and verification */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These flags describes reason of stop_conn() call
|
* These flags describes reason of stop_conn() call
|
||||||
|
@@ -99,7 +99,8 @@ extern int iscsi_tcp_task_xmit(struct iscsi_task *task);
|
|||||||
|
|
||||||
/* segment helpers */
|
/* segment helpers */
|
||||||
extern int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn);
|
extern int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn);
|
||||||
extern int iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv,
|
extern int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
|
||||||
|
struct iscsi_segment *segment, int recv,
|
||||||
unsigned copied);
|
unsigned copied);
|
||||||
extern void iscsi_tcp_segment_unmap(struct iscsi_segment *segment);
|
extern void iscsi_tcp_segment_unmap(struct iscsi_segment *segment);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user