2005-08-05 02:30:31 +00:00
|
|
|
/*
|
|
|
|
* iSCSI Initiator TCP Transport
|
|
|
|
* Copyright (C) 2004 Dmitry Yusupov
|
|
|
|
* Copyright (C) 2004 Alex Aizman
|
2006-04-07 02:26:46 +00:00
|
|
|
* Copyright (C) 2005 - 2006 Mike Christie
|
|
|
|
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
|
2005-08-05 02:30:31 +00:00
|
|
|
* maintained by open-iscsi@googlegroups.com
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published
|
|
|
|
* by the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* See the file COPYING included with this distribution for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef ISCSI_TCP_H
|
|
|
|
#define ISCSI_TCP_H
|
|
|
|
|
2006-04-07 02:26:46 +00:00
|
|
|
#include <scsi/libiscsi.h>
|
2005-08-05 02:30:31 +00:00
|
|
|
|
|
|
|
/* xmit state machine */
|
2007-12-13 18:43:20 +00:00
|
|
|
#define XMSTATE_IDLE 0x0
|
|
|
|
#define XMSTATE_CMD_HDR_INIT 0x1
|
|
|
|
#define XMSTATE_CMD_HDR_XMIT 0x2
|
|
|
|
#define XMSTATE_IMM_HDR 0x4
|
|
|
|
#define XMSTATE_IMM_DATA 0x8
|
|
|
|
#define XMSTATE_UNS_INIT 0x10
|
|
|
|
#define XMSTATE_UNS_HDR 0x20
|
|
|
|
#define XMSTATE_UNS_DATA 0x40
|
|
|
|
#define XMSTATE_SOL_HDR 0x80
|
|
|
|
#define XMSTATE_SOL_DATA 0x100
|
|
|
|
#define XMSTATE_W_PAD 0x200
|
|
|
|
#define XMSTATE_W_RESEND_PAD 0x400
|
|
|
|
#define XMSTATE_W_RESEND_DATA_DIGEST 0x800
|
|
|
|
#define XMSTATE_IMM_HDR_INIT 0x1000
|
|
|
|
#define XMSTATE_SOL_HDR_INIT 0x2000
|
[SCSI] iscsi_tcp: fix padding, data digests, and IO at weird offsets
iscsi_tcp calculates padding by using the expected transfer length. This
has the problem where if we have immediate data = no and initial R2T =
yes, and the transfer length ended up needing padding then we send:
1. header
2. padding which should have gone after data
3. data
Besides this bug, we also assume the target will always ask for nice
transfer lengths and the first burst length will always be a nice value.
As far as I can tell form the RFC this is not a requirement. It would be
silly to do this, but if someone did it we will end doing bad things.
Finally the last bug in that bit of code is in our handling of the
recalculation of data digests when we do not send a whole iscsi_buf in
one try. The bug here is that we call crypto_digest_final on a
iscsi_sendpage error, then when we send the rest of the iscsi_buf, we
doiscsi_data_digest_init and this causes the previous data digest to be
lost.
And to make matters worse, some of these bugs are replicated over and
over and over again for immediate data, solicited data and unsolicited
data. So the attached patch made over the iscsi git tree (see
kernel.org/git for details) which I updated today to include the patches
I said I merged, consolidates the sending of data, padding and digests
and calculation of data digests and fixes the above bugs.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2006-08-31 22:09:27 +00:00
|
|
|
|
2005-08-05 02:30:31 +00:00
|
|
|
#define ISCSI_SG_TABLESIZE SG_ALL
|
|
|
|
#define ISCSI_TCP_MAX_CMD_LEN 16
|
|
|
|
|
2006-08-24 08:45:50 +00:00
|
|
|
struct crypto_hash;
|
2006-04-07 02:26:46 +00:00
|
|
|
struct socket;
|
2007-12-13 18:43:21 +00:00
|
|
|
struct iscsi_tcp_conn;
|
|
|
|
struct iscsi_chunk;
|
|
|
|
|
|
|
|
typedef int iscsi_chunk_done_fn_t(struct iscsi_tcp_conn *,
|
|
|
|
struct iscsi_chunk *);
|
|
|
|
|
|
|
|
struct iscsi_chunk {
|
|
|
|
unsigned char *data;
|
|
|
|
unsigned int size;
|
|
|
|
unsigned int copied;
|
|
|
|
unsigned int total_size;
|
|
|
|
unsigned int total_copied;
|
|
|
|
|
|
|
|
struct hash_desc *hash;
|
|
|
|
unsigned char recv_digest[ISCSI_DIGEST_SIZE];
|
|
|
|
unsigned char digest[ISCSI_DIGEST_SIZE];
|
|
|
|
unsigned int digest_len;
|
|
|
|
|
|
|
|
struct scatterlist *sg;
|
|
|
|
void *sg_mapped;
|
|
|
|
unsigned int sg_offset;
|
|
|
|
unsigned int sg_index;
|
|
|
|
unsigned int sg_count;
|
|
|
|
|
|
|
|
iscsi_chunk_done_fn_t *done;
|
|
|
|
};
|
2005-08-05 02:30:31 +00:00
|
|
|
|
|
|
|
/* Socket connection recieve helper */
|
|
|
|
struct iscsi_tcp_recv {
|
|
|
|
struct iscsi_hdr *hdr;
|
2007-12-13 18:43:21 +00:00
|
|
|
struct iscsi_chunk chunk;
|
|
|
|
|
|
|
|
/* Allocate buffer for BHS + AHS */
|
|
|
|
uint32_t hdr_buf[64];
|
2005-08-05 02:30:31 +00:00
|
|
|
|
|
|
|
/* copied and flipped values */
|
|
|
|
int datalen;
|
2007-12-13 18:43:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Socket connection send helper */
|
|
|
|
struct iscsi_tcp_send {
|
|
|
|
struct iscsi_hdr *hdr;
|
|
|
|
struct iscsi_chunk chunk;
|
|
|
|
struct iscsi_chunk data_chunk;
|
|
|
|
|
|
|
|
/* Allocate buffer for BHS + AHS */
|
|
|
|
uint32_t hdr_buf[64];
|
2005-08-05 02:30:31 +00:00
|
|
|
};
|
|
|
|
|
2006-04-07 02:26:46 +00:00
|
|
|
struct iscsi_tcp_conn {
|
|
|
|
struct iscsi_conn *iscsi_conn;
|
|
|
|
struct socket *sock;
|
2005-08-05 02:30:31 +00:00
|
|
|
int stop_stage; /* conn_stop() flag: *
|
|
|
|
* stop to recover, *
|
|
|
|
* stop to terminate */
|
|
|
|
/* control data */
|
|
|
|
struct iscsi_tcp_recv in; /* TCP receive context */
|
2007-12-13 18:43:21 +00:00
|
|
|
struct iscsi_tcp_send out; /* TCP send context */
|
2005-08-05 02:30:31 +00:00
|
|
|
|
|
|
|
/* old values for socket callbacks */
|
|
|
|
void (*old_data_ready)(struct sock *, int);
|
|
|
|
void (*old_state_change)(struct sock *);
|
|
|
|
void (*old_write_space)(struct sock *);
|
|
|
|
|
2006-08-31 22:09:28 +00:00
|
|
|
/* data and header digests */
|
2006-09-23 20:33:43 +00:00
|
|
|
struct hash_desc tx_hash; /* CRC32C (Tx) */
|
|
|
|
struct hash_desc rx_hash; /* CRC32C (Rx) */
|
2005-08-05 02:30:31 +00:00
|
|
|
|
2006-04-07 02:26:46 +00:00
|
|
|
/* MIB custom statistics */
|
2005-08-05 02:30:31 +00:00
|
|
|
uint32_t sendpage_failures_cnt;
|
|
|
|
uint32_t discontiguous_hdr_cnt;
|
2006-01-14 00:05:44 +00:00
|
|
|
|
|
|
|
ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
|
2005-08-05 02:30:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct iscsi_buf {
|
|
|
|
struct scatterlist sg;
|
|
|
|
unsigned int sent;
|
2006-01-14 00:05:47 +00:00
|
|
|
char use_sendmsg;
|
2005-08-05 02:30:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct iscsi_data_task {
|
|
|
|
struct iscsi_data hdr; /* PDU */
|
2007-12-13 18:43:23 +00:00
|
|
|
char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */
|
2005-08-05 02:30:31 +00:00
|
|
|
struct iscsi_buf digestbuf; /* digest buffer */
|
|
|
|
uint32_t digest; /* data digest */
|
|
|
|
};
|
|
|
|
|
2006-04-07 02:26:46 +00:00
|
|
|
struct iscsi_tcp_mgmt_task {
|
|
|
|
struct iscsi_hdr hdr;
|
2007-12-13 18:43:23 +00:00
|
|
|
char hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */
|
2007-12-13 18:43:20 +00:00
|
|
|
int xmstate; /* mgmt xmit progress */
|
2005-08-05 02:30:31 +00:00
|
|
|
struct iscsi_buf headbuf; /* header buffer */
|
|
|
|
struct iscsi_buf sendbuf; /* in progress buffer */
|
|
|
|
int sent;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct iscsi_r2t_info {
|
|
|
|
__be32 ttt; /* copied from R2T */
|
|
|
|
__be32 exp_statsn; /* copied from R2T */
|
|
|
|
uint32_t data_length; /* copied from R2T */
|
|
|
|
uint32_t data_offset; /* copied from R2T */
|
|
|
|
struct iscsi_buf headbuf; /* Data-Out Header Buffer */
|
|
|
|
struct iscsi_buf sendbuf; /* Data-Out in progress buffer*/
|
|
|
|
int sent; /* R2T sequence progress */
|
|
|
|
int data_count; /* DATA-Out payload progress */
|
|
|
|
struct scatterlist *sg; /* per-R2T SG list */
|
|
|
|
int solicit_datasn;
|
2006-05-19 01:31:36 +00:00
|
|
|
struct iscsi_data_task dtask; /* which data task */
|
2005-08-05 02:30:31 +00:00
|
|
|
};
|
|
|
|
|
2006-04-07 02:26:46 +00:00
|
|
|
struct iscsi_tcp_cmd_task {
|
2007-12-13 18:43:23 +00:00
|
|
|
struct iscsi_hdr_buff {
|
|
|
|
struct iscsi_cmd cmd_hdr;
|
|
|
|
char hdrextbuf[ISCSI_MAX_AHS_SIZE +
|
|
|
|
ISCSI_DIGEST_SIZE];
|
|
|
|
} hdr;
|
2005-08-05 02:30:31 +00:00
|
|
|
char pad[ISCSI_PAD_LEN];
|
2006-04-07 02:26:46 +00:00
|
|
|
int pad_count; /* padded bytes */
|
2005-08-05 02:30:31 +00:00
|
|
|
struct iscsi_buf headbuf; /* header buf (xmit) */
|
|
|
|
struct iscsi_buf sendbuf; /* in progress buffer*/
|
2007-12-13 18:43:20 +00:00
|
|
|
int xmstate; /* xmit xtate machine */
|
2005-08-05 02:30:31 +00:00
|
|
|
int sent;
|
|
|
|
struct scatterlist *sg; /* per-cmd SG list */
|
|
|
|
struct scatterlist *bad_sg; /* assert statement */
|
|
|
|
int sg_count; /* SG's to process */
|
2007-05-30 17:57:14 +00:00
|
|
|
uint32_t exp_datasn; /* expected target's R2TSN/DataSN */
|
2005-08-05 02:30:31 +00:00
|
|
|
int data_offset;
|
|
|
|
struct iscsi_r2t_info *r2t; /* in progress R2T */
|
2007-12-13 18:43:25 +00:00
|
|
|
struct iscsi_pool r2tpool;
|
2005-08-05 02:30:31 +00:00
|
|
|
struct kfifo *r2tqueue;
|
|
|
|
int digest_count;
|
|
|
|
uint32_t immdigest; /* for imm data */
|
|
|
|
struct iscsi_buf immbuf; /* for imm data digest */
|
2006-05-19 01:31:36 +00:00
|
|
|
struct iscsi_data_task unsol_dtask; /* unsol data task */
|
2005-08-05 02:30:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* ISCSI_H */
|