#include "iscsi_tcp.h"
+#define ISCSI_TCP_VERSION "1.0-595"
+
MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, "
"Alex Aizman <itn780@yahoo.com>");
MODULE_DESCRIPTION("iSCSI/TCP data-path");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0:4.445");
+MODULE_VERSION(ISCSI_TCP_VERSION);
/* #define DEBUG_TCP */
#define DEBUG_ASSERT
static unsigned int iscsi_max_lun = 512;
module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
-/* global data */
-static kmem_cache_t *taskcache;
-
static inline void
iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
{
if (unlikely(!sc))
return;
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
- struct iscsi_data_task *dtask, *n;
-
- /* WRITE: cleanup Data-Out's if any */
- list_for_each_entry_safe(dtask, n, &tcp_ctask->dataqueue,
- item) {
- list_del(&dtask->item);
- mempool_free(dtask, tcp_ctask->datapool);
- }
- }
tcp_ctask->xmstate = XMSTATE_IDLE;
tcp_ctask->r2t = NULL;
}
struct iscsi_r2t_info *r2t)
{
struct iscsi_data *hdr;
- struct iscsi_data_task *dtask;
struct scsi_cmnd *sc = ctask->sc;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- dtask = mempool_alloc(tcp_ctask->datapool, GFP_ATOMIC);
- BUG_ON(!dtask);
- INIT_LIST_HEAD(&dtask->item);
- hdr = &dtask->hdr;
+ hdr = &r2t->dtask.hdr;
memset(hdr, 0, sizeof(struct iscsi_data));
hdr->ttt = r2t->ttt;
hdr->datasn = cpu_to_be32(r2t->solicit_datasn);
iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
sizeof(struct iscsi_hdr));
- r2t->dtask = dtask;
-
if (sc->use_sg) {
int i, sg_count = 0;
struct scatterlist *sg = sc->request_buffer;
iscsi_buf_init_iov(&tcp_ctask->sendbuf,
(char*)sc->request_buffer + r2t->data_offset,
r2t->data_count);
-
- list_add(&dtask->item, &tcp_ctask->dataqueue);
}
/**
tcp_conn->old_write_space(sk);
debug_tcp("iscsi_write_space: cid %d\n", conn->id);
- clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
scsi_queue_work(conn->session->host, &conn->xmitwork);
}
{
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct socket *sk = tcp_conn->sock;
- int offset = buf->sg.offset + buf->sent;
+ int offset = buf->sg.offset + buf->sent, res;
/*
* if we got use_sg=0 or are sending something we kmallocd
* slab case.
*/
if (buf->use_sendmsg)
- return sock_no_sendpage(sk, buf->sg.page, offset, size, flags);
+ res = sock_no_sendpage(sk, buf->sg.page, offset, size, flags);
+ else
+ res = tcp_conn->sendpage(sk, buf->sg.page, offset, size, flags);
+
+ if (res >= 0) {
+ conn->txdata_octets += res;
+ buf->sent += res;
+ return res;
+ }
+
+ tcp_conn->sendpage_failures_cnt++;
+ if (res == -EAGAIN)
+ res = -ENOBUFS;
else
- return tcp_conn->sendpage(sk, buf->sg.page, offset, size,
- flags);
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ return res;
}
/**
static inline int
iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
{
- struct iscsi_tcp_conn *tcp_conn;
int flags = 0; /* MSG_DONTWAIT; */
int res, size;
res = iscsi_send(conn, buf, size, flags);
debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
if (res >= 0) {
- conn->txdata_octets += res;
- buf->sent += res;
if (size != res)
return -EAGAIN;
return 0;
- } else if (res == -EAGAIN) {
- tcp_conn = conn->dd_data;
- tcp_conn->sendpage_failures_cnt++;
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- } else if (res == -EPIPE)
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ }
return res;
}
iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
int *count, int *sent)
{
- struct iscsi_tcp_conn *tcp_conn;
int flags = 0; /* MSG_DONTWAIT; */
int res, size;
debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n",
size, buf->sent, *count, *sent, res);
if (res >= 0) {
- conn->txdata_octets += res;
- buf->sent += res;
*count -= res;
*sent += res;
if (size != res)
return -EAGAIN;
return 0;
- } else if (res == -EAGAIN) {
- tcp_conn = conn->dd_data;
- tcp_conn->sendpage_failures_cnt++;
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- } else if (res == -EPIPE)
- iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ }
return res;
}
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data *hdr;
- struct iscsi_data_task *dtask;
struct scsi_cmnd *sc = ctask->sc;
int new_offset;
- dtask = mempool_alloc(tcp_ctask->datapool, GFP_ATOMIC);
- BUG_ON(!dtask);
- INIT_LIST_HEAD(&dtask->item);
- hdr = &dtask->hdr;
+ hdr = &r2t->dtask.hdr;
memset(hdr, 0, sizeof(struct iscsi_data));
hdr->ttt = r2t->ttt;
hdr->datasn = cpu_to_be32(r2t->solicit_datasn);
iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
sizeof(struct iscsi_hdr));
- r2t->dtask = dtask;
-
if (sc->use_sg && !iscsi_buf_left(&r2t->sendbuf)) {
BUG_ON(tcp_ctask->bad_sg == r2t->sg);
iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
iscsi_buf_init_iov(&tcp_ctask->sendbuf,
(char*)sc->request_buffer + new_offset,
r2t->data_count);
-
- list_add(&dtask->item, &tcp_ctask->dataqueue);
}
static void
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data_task *dtask;
- dtask = mempool_alloc(tcp_ctask->datapool, GFP_ATOMIC);
- BUG_ON(!dtask);
- INIT_LIST_HEAD(&dtask->item);
-
+ dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask;
iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr,
tcp_ctask->r2t_data_count);
iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
sizeof(struct iscsi_hdr));
-
- list_add(&dtask->item, &tcp_ctask->dataqueue);
- tcp_ctask->dtask = dtask;
}
/**
iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
{
struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
+ int rc;
debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
conn->id, tcp_mtask->xmstate, mtask->itt);
conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_mtask->headbuf,
(u8*)tcp_mtask->hdrext);
- if (iscsi_sendhdr(conn, &tcp_mtask->headbuf,
- mtask->data_count)) {
+ rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf,
+ mtask->data_count);
+ if (rc) {
tcp_mtask->xmstate |= XMSTATE_IMM_HDR;
if (mtask->data_count)
tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA;
- return -EAGAIN;
+ return rc;
}
}
* Virtual buffer could be spreaded across multiple pages...
*/
do {
- if (iscsi_sendpage(conn, &tcp_mtask->sendbuf,
- &mtask->data_count, &tcp_mtask->sent)) {
+ int rc;
+
+ rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf,
+ &mtask->data_count, &tcp_mtask->sent);
+ if (rc) {
tcp_mtask->xmstate |= XMSTATE_IMM_DATA;
- return -EAGAIN;
+ return rc;
}
} while (mtask->data_count);
}
handle_xmstate_r_hdr(struct iscsi_conn *conn,
struct iscsi_tcp_cmd_task *tcp_ctask)
{
+ int rc;
+
tcp_ctask->xmstate &= ~XMSTATE_R_HDR;
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)tcp_ctask->hdrext);
- if (!iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0)) {
+ rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0);
+ if (!rc) {
BUG_ON(tcp_ctask->xmstate != XMSTATE_IDLE);
return 0; /* wait for Data-In */
}
tcp_ctask->xmstate |= XMSTATE_R_HDR;
- return -EAGAIN;
+ return rc;
}
static inline int
struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ int rc;
tcp_ctask->xmstate &= ~XMSTATE_W_HDR;
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)tcp_ctask->hdrext);
- if (iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count)) {
+ rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
+ if (rc)
tcp_ctask->xmstate |= XMSTATE_W_HDR;
- return -EAGAIN;
- }
- return 0;
+ return rc;
}
static inline int
struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ int rc;
tcp_ctask->xmstate &= ~XMSTATE_DATA_DIGEST;
debug_tcp("resent data digest 0x%x\n", tcp_ctask->datadigest);
- if (iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
- &tcp_ctask->datadigest, 0)) {
+ rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
+ &tcp_ctask->datadigest, 0);
+ if (rc) {
tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST;
debug_tcp("resent data digest 0x%x fail!\n",
tcp_ctask->datadigest);
- return -EAGAIN;
}
- return 0;
+
+ return rc;
}
static inline int
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int rc;
BUG_ON(!ctask->imm_count);
tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA;
}
for (;;) {
- if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, &ctask->imm_count,
- &tcp_ctask->sent)) {
+ rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf,
+ &ctask->imm_count, &tcp_ctask->sent);
+ if (rc) {
tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
if (conn->datadgst_en) {
crypto_digest_final(tcp_conn->data_tx_tfm,
debug_tcp("tx imm sendpage fail 0x%x\n",
tcp_ctask->datadigest);
}
- return -EAGAIN;
+ return rc;
}
if (conn->datadgst_en)
crypto_digest_update(tcp_conn->data_tx_tfm,
}
if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
- if (iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
- &tcp_ctask->immdigest, 1)) {
+ rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
+ &tcp_ctask->immdigest, 1);
+ if (rc) {
debug_tcp("sending imm digest 0x%x fail!\n",
tcp_ctask->immdigest);
- return -EAGAIN;
+ return rc;
}
debug_tcp("sending imm digest 0x%x\n", tcp_ctask->immdigest);
}
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data_task *dtask;
+ int rc;
tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) {
iscsi_unsolicit_data_init(conn, ctask);
- BUG_ON(!tcp_ctask->dtask);
dtask = tcp_ctask->dtask;
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)dtask->hdrext);
tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT;
}
- if (iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count)) {
+
+ rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
+ if (rc) {
tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
tcp_ctask->xmstate |= XMSTATE_UNS_HDR;
- return -EAGAIN;
+ return rc;
}
debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data_task *dtask = tcp_ctask->dtask;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int rc;
BUG_ON(!ctask->data_count);
tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
for (;;) {
int start = tcp_ctask->sent;
- if (iscsi_sendpage(conn, &tcp_ctask->sendbuf,
- &ctask->data_count, &tcp_ctask->sent)) {
+ rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf,
+ &ctask->data_count, &tcp_ctask->sent);
+ if (rc) {
ctask->unsol_count -= tcp_ctask->sent - start;
tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
/* will continue with this ctask later.. */
debug_tcp("tx uns data fail 0x%x\n",
dtask->digest);
}
- return -EAGAIN;
+ return rc;
}
BUG_ON(tcp_ctask->sent > ctask->total_length);
*/
if (ctask->unsol_count) {
if (conn->datadgst_en) {
- if (iscsi_digest_final_send(conn, ctask,
+ rc = iscsi_digest_final_send(conn, ctask,
&dtask->digestbuf,
- &dtask->digest, 1)) {
+ &dtask->digest, 1);
+ if (rc) {
debug_tcp("send uns digest 0x%x fail\n",
dtask->digest);
- return -EAGAIN;
+ return rc;
}
debug_tcp("sending uns digest 0x%x, more uns\n",
dtask->digest);
}
if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
- if (iscsi_digest_final_send(conn, ctask,
+ rc = iscsi_digest_final_send(conn, ctask,
&dtask->digestbuf,
- &dtask->digest, 1)) {
+ &dtask->digest, 1);
+ if (rc) {
debug_tcp("send last uns digest 0x%x fail\n",
dtask->digest);
- return -EAGAIN;
+ return rc;
}
debug_tcp("sending uns digest 0x%x\n",dtask->digest);
}
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_r2t_info *r2t = tcp_ctask->r2t;
- struct iscsi_data_task *dtask = r2t->dtask;
- int left;
+ struct iscsi_data_task *dtask = &r2t->dtask;
+ int left, rc;
tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
tcp_ctask->dtask = dtask;
if (!r2t->data_count)
goto data_out_done;
- if (iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent)) {
+ rc = iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent);
+ if (rc) {
tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
/* will continue with this ctask later.. */
if (conn->datadgst_en) {
(u8 *)&dtask->digest);
debug_tcp("r2t data send fail 0x%x\n", dtask->digest);
}
- return -EAGAIN;
+ return rc;
}
BUG_ON(r2t->data_count < 0);
left = r2t->data_length - r2t->sent;
if (left) {
if (conn->datadgst_en) {
- if (iscsi_digest_final_send(conn, ctask,
+ rc = iscsi_digest_final_send(conn, ctask,
&dtask->digestbuf,
- &dtask->digest, 1)) {
+ &dtask->digest, 1);
+ if (rc) {
debug_tcp("send r2t data digest 0x%x"
"fail\n", dtask->digest);
- return -EAGAIN;
+ return rc;
}
debug_tcp("r2t data send digest 0x%x\n",
dtask->digest);
*/
BUG_ON(tcp_ctask->r2t_data_count - r2t->data_length < 0);
if (conn->datadgst_en) {
- if (iscsi_digest_final_send(conn, ctask, &dtask->digestbuf,
- &dtask->digest, 1)) {
+ rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf,
+ &dtask->digest, 1);
+ if (rc) {
debug_tcp("send last r2t data digest 0x%x"
"fail\n", dtask->digest);
- return -EAGAIN;
+ return rc;
}
debug_tcp("r2t done dout digest 0x%x\n", dtask->digest);
}
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_data_task *dtask = tcp_ctask->dtask;
- int sent;
+ int sent, rc;
tcp_ctask->xmstate &= ~XMSTATE_W_PAD;
iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
tcp_ctask->pad_count);
- if (iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
- &sent)) {
+ rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
+ &sent);
+ if (rc) {
tcp_ctask->xmstate |= XMSTATE_W_PAD;
- return -EAGAIN;
+ return rc;
}
if (conn->datadgst_en) {
&tcp_ctask->sendbuf.sg, 1);
/* imm data? */
if (!dtask) {
- if (iscsi_digest_final_send(conn, ctask,
+ rc = iscsi_digest_final_send(conn, ctask,
&tcp_ctask->immbuf,
- &tcp_ctask->immdigest, 1)) {
+ &tcp_ctask->immdigest, 1);
+ if (rc) {
debug_tcp("send padding digest 0x%x"
"fail!\n", tcp_ctask->immdigest);
- return -EAGAIN;
+ return rc;
}
debug_tcp("done with padding, digest 0x%x\n",
tcp_ctask->datadigest);
} else {
- if (iscsi_digest_final_send(conn, ctask,
+ rc = iscsi_digest_final_send(conn, ctask,
&dtask->digestbuf,
- &dtask->digest, 1)) {
+ &dtask->digest, 1);
+ if (rc) {
debug_tcp("send padding digest 0x%x"
"fail\n", dtask->digest);
- return -EAGAIN;
+ return rc;
}
debug_tcp("done with padding, digest 0x%x\n",
dtask->digest);
if (ctask->mtask)
return rc;
- if (tcp_ctask->xmstate & XMSTATE_R_HDR) {
- rc = handle_xmstate_r_hdr(conn, tcp_ctask);
- return rc;
- }
+ if (tcp_ctask->xmstate & XMSTATE_R_HDR)
+ return handle_xmstate_r_hdr(conn, tcp_ctask);
if (tcp_ctask->xmstate & XMSTATE_W_HDR) {
rc = handle_xmstate_w_hdr(conn, ctask);
r2t = tcp_ctask->r2t;
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &r2t->headbuf,
- (u8*)r2t->dtask->hdrext);
- if (iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count)) {
+ (u8*)r2t->dtask.hdrext);
+ rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
+ if (rc) {
tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
- return -EAGAIN;
+ return rc;
}
debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
if (err)
return err;
- if (conn->stop_stage != STOP_CONN_SUSPEND) {
- /* bind iSCSI connection and socket */
- tcp_conn->sock = sock;
+ /* bind iSCSI connection and socket */
+ tcp_conn->sock = sock;
- /* setup Socket parameters */
- sk = sock->sk;
- sk->sk_reuse = 1;
- sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
- sk->sk_allocation = GFP_ATOMIC;
+ /* setup Socket parameters */
+ sk = sock->sk;
+ sk->sk_reuse = 1;
+ sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */
+ sk->sk_allocation = GFP_ATOMIC;
- /* FIXME: disable Nagle's algorithm */
+ /* FIXME: disable Nagle's algorithm */
- /*
- * Intercept TCP callbacks for sendfile like receive
- * processing.
- */
- conn->recv_lock = &sk->sk_callback_lock;
- iscsi_conn_set_callbacks(conn);
- tcp_conn->sendpage = tcp_conn->sock->ops->sendpage;
- /*
- * set receive state machine into initial state
- */
- tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
- }
+ /*
+ * Intercept TCP callbacks for sendfile like receive
+ * processing.
+ */
+ conn->recv_lock = &sk->sk_callback_lock;
+ iscsi_conn_set_callbacks(conn);
+ tcp_conn->sendpage = tcp_conn->sock->ops->sendpage;
+ /*
+ * set receive state machine into initial state
+ */
+ tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
return 0;
}
(void**)tcp_ctask->r2ts);
goto r2t_alloc_fail;
}
-
- /*
- * number of
- * Data-Out PDU's within R2T-sequence can be quite big;
- * using mempool
- */
- tcp_ctask->datapool = mempool_create_slab_pool(ISCSI_DTASK_DEFAULT_MAX,
- taskcache);
- if (tcp_ctask->datapool == NULL) {
- kfifo_free(tcp_ctask->r2tqueue);
- iscsi_pool_free(&tcp_ctask->r2tpool,
- (void**)tcp_ctask->r2ts);
- goto r2t_alloc_fail;
- }
- INIT_LIST_HEAD(&tcp_ctask->dataqueue);
}
return 0;
struct iscsi_cmd_task *ctask = session->cmds[i];
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- mempool_destroy(tcp_ctask->datapool);
kfifo_free(tcp_ctask->r2tqueue);
iscsi_pool_free(&tcp_ctask->r2tpool,
(void**)tcp_ctask->r2ts);
struct iscsi_cmd_task *ctask = session->cmds[i];
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- mempool_destroy(tcp_ctask->datapool);
kfifo_free(tcp_ctask->r2tqueue);
iscsi_pool_free(&tcp_ctask->r2tpool,
(void**)tcp_ctask->r2ts);
static int
iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
- uint32_t value)
+ char *buf, int buflen)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_session *session = conn->session;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int value;
switch(param) {
case ISCSI_PARAM_MAX_RECV_DLENGTH: {
char *saveptr = tcp_conn->data;
gfp_t flags = GFP_KERNEL;
+ sscanf(buf, "%d", &value);
if (tcp_conn->data_size >= value) {
- conn->max_recv_dlength = value;
+ iscsi_set_param(cls_conn, param, buf, buflen);
break;
}
else
free_pages((unsigned long)saveptr,
get_order(tcp_conn->data_size));
- conn->max_recv_dlength = value;
+ iscsi_set_param(cls_conn, param, buf, buflen);
tcp_conn->data_size = value;
- }
- break;
- case ISCSI_PARAM_MAX_XMIT_DLENGTH:
- conn->max_xmit_dlength = value;
break;
+ }
case ISCSI_PARAM_HDRDGST_EN:
- conn->hdrdgst_en = value;
+ iscsi_set_param(cls_conn, param, buf, buflen);
tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
if (conn->hdrdgst_en) {
tcp_conn->hdr_size += sizeof(__u32);
}
break;
case ISCSI_PARAM_DATADGST_EN:
- conn->datadgst_en = value;
+ iscsi_set_param(cls_conn, param, buf, buflen);
if (conn->datadgst_en) {
if (!tcp_conn->data_tx_tfm)
tcp_conn->data_tx_tfm =
tcp_conn->sendpage = conn->datadgst_en ?
sock_no_sendpage : tcp_conn->sock->ops->sendpage;
break;
- case ISCSI_PARAM_INITIAL_R2T_EN:
- session->initial_r2t_en = value;
- break;
case ISCSI_PARAM_MAX_R2T:
+ sscanf(buf, "%d", &value);
if (session->max_r2t == roundup_pow_of_two(value))
break;
iscsi_r2tpool_free(session);
- session->max_r2t = value;
+ iscsi_set_param(cls_conn, param, buf, buflen);
if (session->max_r2t & (session->max_r2t - 1))
session->max_r2t = roundup_pow_of_two(session->max_r2t);
if (iscsi_r2tpool_alloc(session))
return -ENOMEM;
break;
- case ISCSI_PARAM_IMM_DATA_EN:
- session->imm_data_en = value;
- break;
- case ISCSI_PARAM_FIRST_BURST:
- session->first_burst = value;
- break;
- case ISCSI_PARAM_MAX_BURST:
- session->max_burst = value;
- break;
- case ISCSI_PARAM_PDU_INORDER_EN:
- session->pdu_inorder_en = value;
- break;
- case ISCSI_PARAM_DATASEQ_INORDER_EN:
- session->dataseq_inorder_en = value;
- break;
- case ISCSI_PARAM_ERL:
- session->erl = value;
- break;
- case ISCSI_PARAM_IFMARKER_EN:
- BUG_ON(value);
- session->ifmarker_en = value;
- break;
- case ISCSI_PARAM_OFMARKER_EN:
- BUG_ON(value);
- session->ofmarker_en = value;
- break;
- case ISCSI_PARAM_EXP_STATSN:
- conn->exp_statsn = value;
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int
-iscsi_session_get_param(struct iscsi_cls_session *cls_session,
- enum iscsi_param param, uint32_t *value)
-{
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
-
- switch(param) {
- case ISCSI_PARAM_INITIAL_R2T_EN:
- *value = session->initial_r2t_en;
- break;
- case ISCSI_PARAM_MAX_R2T:
- *value = session->max_r2t;
- break;
- case ISCSI_PARAM_IMM_DATA_EN:
- *value = session->imm_data_en;
- break;
- case ISCSI_PARAM_FIRST_BURST:
- *value = session->first_burst;
- break;
- case ISCSI_PARAM_MAX_BURST:
- *value = session->max_burst;
- break;
- case ISCSI_PARAM_PDU_INORDER_EN:
- *value = session->pdu_inorder_en;
- break;
- case ISCSI_PARAM_DATASEQ_INORDER_EN:
- *value = session->dataseq_inorder_en;
- break;
- case ISCSI_PARAM_ERL:
- *value = session->erl;
- break;
- case ISCSI_PARAM_IFMARKER_EN:
- *value = session->ifmarker_en;
- break;
- case ISCSI_PARAM_OFMARKER_EN:
- *value = session->ofmarker_en;
- break;
default:
- return -EINVAL;
+ return iscsi_set_param(cls_conn, param, buf, buflen);
}
return 0;
}
static int
-iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, uint32_t *value)
+iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct inet_sock *inet;
+ struct ipv6_pinfo *np;
+ struct sock *sk;
+ int len;
switch(param) {
- case ISCSI_PARAM_MAX_RECV_DLENGTH:
- *value = conn->max_recv_dlength;
- break;
- case ISCSI_PARAM_MAX_XMIT_DLENGTH:
- *value = conn->max_xmit_dlength;
- break;
- case ISCSI_PARAM_HDRDGST_EN:
- *value = conn->hdrdgst_en;
- break;
- case ISCSI_PARAM_DATADGST_EN:
- *value = conn->datadgst_en;
- break;
case ISCSI_PARAM_CONN_PORT:
mutex_lock(&conn->xmitmutex);
if (!tcp_conn->sock) {
}
inet = inet_sk(tcp_conn->sock->sk);
- *value = be16_to_cpu(inet->dport);
+ len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport));
mutex_unlock(&conn->xmitmutex);
- case ISCSI_PARAM_EXP_STATSN:
- *value = conn->exp_statsn;
break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int
-iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct sock *sk;
- struct inet_sock *inet;
- struct ipv6_pinfo *np;
- int len = 0;
-
- switch (param) {
case ISCSI_PARAM_CONN_ADDRESS:
mutex_lock(&conn->xmitmutex);
if (!tcp_conn->sock) {
mutex_unlock(&conn->xmitmutex);
break;
default:
- return -EINVAL;
+ return iscsi_conn_get_param(cls_conn, param, buf);
}
return len;
static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session)
{
- struct iscsi_session *session = class_to_transport_session(cls_session);
- struct iscsi_data_task *dtask, *n;
- int cmd_i;
-
- for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
- struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-
- list_for_each_entry_safe(dtask, n, &tcp_ctask->dataqueue,
- item) {
- list_del(&dtask->item);
- mempool_free(dtask, tcp_ctask->datapool);
- }
- }
-
iscsi_r2tpool_free(class_to_transport_session(cls_session));
iscsi_session_teardown(cls_session);
}
static struct scsi_host_template iscsi_sht = {
- .name = "iSCSI Initiator over TCP/IP, v."
- ISCSI_VERSION_STR,
+ .name = "iSCSI Initiator over TCP/IP, v"
+ ISCSI_TCP_VERSION,
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
.can_queue = ISCSI_XMIT_CMDS_MAX - 1,
ISCSI_ERL |
ISCSI_CONN_PORT |
ISCSI_CONN_ADDRESS |
- ISCSI_EXP_STATSN,
+ ISCSI_EXP_STATSN |
+ ISCSI_PERSISTENT_PORT |
+ ISCSI_PERSISTENT_ADDRESS |
+ ISCSI_TARGET_NAME |
+ ISCSI_TPGT,
.host_template = &iscsi_sht,
.conndata_size = sizeof(struct iscsi_conn),
.max_conn = 1,
.bind_conn = iscsi_tcp_conn_bind,
.destroy_conn = iscsi_tcp_conn_destroy,
.set_param = iscsi_conn_set_param,
- .get_conn_param = iscsi_conn_get_param,
- .get_conn_str_param = iscsi_conn_get_str_param,
+ .get_conn_param = iscsi_tcp_conn_get_param,
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_conn_start,
.stop_conn = iscsi_conn_stop,
}
iscsi_tcp_transport.max_lun = iscsi_max_lun;
- taskcache = kmem_cache_create("iscsi_taskcache",
- sizeof(struct iscsi_data_task), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
- if (!taskcache)
- return -ENOMEM;
-
if (!iscsi_register_transport(&iscsi_tcp_transport))
- kmem_cache_destroy(taskcache);
+ return -ENODEV;
return 0;
}
iscsi_tcp_exit(void)
{
iscsi_unregister_transport(&iscsi_tcp_transport);
- kmem_cache_destroy(taskcache);
}
module_init(iscsi_tcp_init);