[PATCH] libata: use dummy port for stolen legacy ports
[safe/jmp/linux-2.6] / drivers / scsi / iscsi_tcp.c
index 7c2ed7b..848fb2a 100644 (file)
 
 #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
 
@@ -67,9 +69,6 @@ MODULE_VERSION("0:4.445");
 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)
 {
@@ -195,16 +194,6 @@ __iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        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;
 }
@@ -286,14 +275,10 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
                        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);
@@ -319,8 +304,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
        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;
@@ -352,8 +335,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
                iscsi_buf_init_iov(&tcp_ctask->sendbuf,
                            (char*)sc->request_buffer + r2t->data_offset,
                            r2t->data_count);
-
-       list_add(&dtask->item, &tcp_ctask->dataqueue);
 }
 
 /**
@@ -1025,7 +1006,6 @@ iscsi_write_space(struct sock *sk)
 
        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);
 }
 
@@ -1075,7 +1055,7 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
 {
        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
@@ -1086,10 +1066,22 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
         * 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;
 }
 
 /**
@@ -1104,7 +1096,6 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
 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;
 
@@ -1116,17 +1107,10 @@ iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
        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;
 }
@@ -1145,7 +1129,6 @@ static inline int
 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;
 
@@ -1160,19 +1143,12 @@ iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
        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;
 }
@@ -1229,14 +1205,10 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
 {
        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);
@@ -1260,8 +1232,6 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
        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);
@@ -1270,8 +1240,6 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
                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
@@ -1280,17 +1248,11 @@ iscsi_unsolicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        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;
 }
 
 /**
@@ -1375,6 +1337,7 @@ static int
 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);
@@ -1388,12 +1351,13 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
                    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;
                }
        }
 
@@ -1404,10 +1368,13 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
                 * 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);
        }
@@ -1429,16 +1396,19 @@ static inline int
 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
@@ -1446,16 +1416,16 @@ handle_xmstate_w_hdr(struct iscsi_conn *conn,
                     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
@@ -1463,17 +1433,19 @@ handle_xmstate_data_digest(struct iscsi_conn *conn,
                           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
@@ -1481,6 +1453,7 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
        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;
@@ -1491,8 +1464,9 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        }
 
        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,
@@ -1500,7 +1474,7 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
                                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,
@@ -1513,11 +1487,12 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        }
 
        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);
        }
@@ -1530,21 +1505,23 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
        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",
@@ -1558,6 +1535,7 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        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;
@@ -1570,8 +1548,9 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        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.. */
@@ -1581,7 +1560,7 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
                                debug_tcp("tx uns data fail 0x%x\n",
                                          dtask->digest);
                        }
-                       return -EAGAIN;
+                       return rc;
                }
 
                BUG_ON(tcp_ctask->sent > ctask->total_length);
@@ -1608,12 +1587,13 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
         */
        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);
@@ -1623,12 +1603,13 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        }
 
        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);
        }
@@ -1643,8 +1624,8 @@ handle_xmstate_sol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        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;
@@ -1660,7 +1641,8 @@ solicit_again:
        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) {
@@ -1668,7 +1650,7 @@ solicit_again:
                                          (u8 *)&dtask->digest);
                        debug_tcp("r2t data send fail 0x%x\n", dtask->digest);
                }
-               return -EAGAIN;
+               return rc;
        }
 
        BUG_ON(r2t->data_count < 0);
@@ -1695,12 +1677,13 @@ data_out_done:
        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);
@@ -1717,11 +1700,12 @@ data_out_done:
         */
        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);
        }
@@ -1747,15 +1731,16 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        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) {
@@ -1763,22 +1748,24 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
                                     &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);
@@ -1803,10 +1790,8 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        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);
@@ -1857,11 +1842,12 @@ solicit_head_again:
                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",
@@ -1989,30 +1975,28 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
        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;
 }
@@ -2113,21 +2097,6 @@ iscsi_r2tpool_alloc(struct iscsi_session *session)
                                        (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;
@@ -2137,7 +2106,6 @@ r2t_alloc_fail:
                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);
@@ -2154,7 +2122,6 @@ iscsi_r2tpool_free(struct iscsi_session *session)
                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);
@@ -2163,19 +2130,21 @@ iscsi_r2tpool_free(struct iscsi_session *session)
 
 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;
                }
 
@@ -2198,15 +2167,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
                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);
@@ -2230,7 +2196,7 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
                }
                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 =
@@ -2253,121 +2219,36 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
                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) {
@@ -2376,30 +2257,9 @@ iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
                }
 
                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) {
@@ -2421,7 +2281,7 @@ iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn,
                mutex_unlock(&conn->xmitmutex);
                break;
        default:
-               return -EINVAL;
+               return iscsi_conn_get_param(cls_conn, param, buf);
        }
 
        return len;
@@ -2496,28 +2356,13 @@ r2tpool_alloc_fail:
 
 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,
@@ -2549,7 +2394,11 @@ static struct iscsi_transport iscsi_tcp_transport = {
                                  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,
@@ -2562,8 +2411,7 @@ static struct iscsi_transport iscsi_tcp_transport = {
        .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,
@@ -2592,14 +2440,8 @@ iscsi_tcp_init(void)
        }
        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;
 }
@@ -2608,7 +2450,6 @@ static void __exit
 iscsi_tcp_exit(void)
 {
        iscsi_unregister_transport(&iscsi_tcp_transport);
-       kmem_cache_destroy(taskcache);
 }
 
 module_init(iscsi_tcp_init);