iscsi-target: Initial traditional TCP conversion to iscsit_transport
authorNicholas Bellinger <nab@linux-iscsi.org>
Thu, 7 Mar 2013 05:54:13 +0000 (21:54 -0800)
committerNicholas Bellinger <nab@linux-iscsi.org>
Thu, 25 Apr 2013 08:05:26 +0000 (01:05 -0700)
This patch performs the initial conversion of existing traditional iscsi
to use iscsit_transport API callers.  This includes:

- iscsi-np cleanups for iscsit_transport_type
- Add iscsi-np transport calls w/ ->iscsit_setup_up() and ->iscsit_free_np()
- Convert login thread process context to use ->iscsit_accept_np() for
  connections with pre-allocated struct iscsi_conn
- Convert existing socket accept code to iscsit_accept_np()
- Convert login RX/TX callers to use ->iscsit_get_login_rx() and
  ->iscsit_put_login_tx() to exchange request/response PDUs
- Convert existing socket login RX/TX calls into iscsit_get_login_rx()
  and iscsit_put_login_tx()
- Change iscsit_close_connection() to invoke ->iscsit_free_conn() +
  iscsit_put_transport() calls.
- Add iscsit_register_transport() + iscsit_unregister_transport() calls
  to module init/exit

v4 changes:

- Add missing iscsit_put_transport() call in iscsi_target_setup_login_socket()
  failure case

v2 changes:

- Update module init/exit to use register_transport() + unregister_transport()

Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_core.h
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_login.h
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_nego.h
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/iscsi/iscsi_target_util.c

index 7ea246a..8203bf3 100644 (file)
@@ -49,6 +49,8 @@
 #include "iscsi_target_device.h"
 #include "iscsi_target_stat.h"
 
+#include <target/iscsi/iscsi_transport.h>
+
 static LIST_HEAD(g_tiqn_list);
 static LIST_HEAD(g_np_list);
 static DEFINE_SPINLOCK(tiqn_lock);
@@ -401,8 +403,7 @@ struct iscsi_np *iscsit_add_np(
        spin_unlock_bh(&np_lock);
 
        pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
-               np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
-               "TCP" : "SCTP");
+               np->np_ip, np->np_port, np->np_transport->name);
 
        return np;
 }
@@ -441,11 +442,10 @@ int iscsit_reset_np_thread(
        return 0;
 }
 
-static int iscsit_del_np_comm(struct iscsi_np *np)
+static void iscsit_free_np(struct iscsi_np *np)
 {
        if (np->np_socket)
                sock_release(np->np_socket);
-       return 0;
 }
 
 int iscsit_del_np(struct iscsi_np *np)
@@ -467,20 +467,32 @@ int iscsit_del_np(struct iscsi_np *np)
                send_sig(SIGINT, np->np_thread, 1);
                kthread_stop(np->np_thread);
        }
-       iscsit_del_np_comm(np);
+
+       np->np_transport->iscsit_free_np(np);
 
        spin_lock_bh(&np_lock);
        list_del(&np->np_list);
        spin_unlock_bh(&np_lock);
 
        pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
-               np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ?
-               "TCP" : "SCTP");
+               np->np_ip, np->np_port, np->np_transport->name);
 
+       iscsit_put_transport(np->np_transport);
        kfree(np);
        return 0;
 }
 
+static struct iscsit_transport iscsi_target_transport = {
+       .name                   = "iSCSI/TCP",
+       .transport_type         = ISCSI_TCP,
+       .owner                  = NULL,
+       .iscsit_setup_np        = iscsit_setup_np,
+       .iscsit_accept_np       = iscsit_accept_np,
+       .iscsit_free_np         = iscsit_free_np,
+       .iscsit_get_login_rx    = iscsit_get_login_rx,
+       .iscsit_put_login_tx    = iscsit_put_login_tx,
+};
+
 static int __init iscsi_target_init_module(void)
 {
        int ret = 0;
@@ -557,6 +569,8 @@ static int __init iscsi_target_init_module(void)
                goto ooo_out;
        }
 
+       iscsit_register_transport(&iscsi_target_transport);
+
        if (iscsit_load_discovery_tpg() < 0)
                goto r2t_out;
 
@@ -587,6 +601,7 @@ static void __exit iscsi_target_cleanup_module(void)
        iscsi_deallocate_thread_sets();
        iscsi_thread_set_free();
        iscsit_release_discovery_tpg();
+       iscsit_unregister_transport(&iscsi_target_transport);
        kmem_cache_destroy(lio_cmd_cache);
        kmem_cache_destroy(lio_qr_cache);
        kmem_cache_destroy(lio_dr_cache);
@@ -4053,6 +4068,12 @@ int iscsit_close_connection(
 
        if (conn->sock)
                sock_release(conn->sock);
+
+       if (conn->conn_transport->iscsit_free_conn)
+               conn->conn_transport->iscsit_free_conn(conn);
+
+       iscsit_put_transport(conn->conn_transport);
+
        conn->thread_set = NULL;
 
        pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
index 7a333d2..2587677 100644 (file)
@@ -60,7 +60,7 @@
 
 #define ISCSI_IOV_DATA_BUFFER          5
 
-enum tpg_np_network_transport_table {
+enum iscsit_transport_type {
        ISCSI_TCP                               = 0,
        ISCSI_SCTP_TCP                          = 1,
        ISCSI_SCTP_UDP                          = 2,
@@ -503,6 +503,7 @@ struct iscsi_conn {
        u16                     login_port;
        u16                     local_port;
        int                     net_size;
+       int                     login_family;
        u32                     auth_id;
        u32                     conn_flags;
        /* Used for iscsi_tx_login_rsp() */
@@ -562,9 +563,12 @@ struct iscsi_conn {
        struct list_head        immed_queue_list;
        struct list_head        response_queue_list;
        struct iscsi_conn_ops   *conn_ops;
+       struct iscsi_login      *conn_login;
+       struct iscsit_transport *conn_transport;
        struct iscsi_param_list *param_list;
        /* Used for per connection auth state machine */
        void                    *auth_protocol;
+       void                    *context;
        struct iscsi_login_thread_s *login_thread;
        struct iscsi_portal_group *tpg;
        /* Pointer to parent session */
@@ -663,6 +667,8 @@ struct iscsi_login {
        u8 first_request;
        u8 version_min;
        u8 version_max;
+       u8 login_complete;
+       u8 login_failed;
        char isid[6];
        u32 cmd_sn;
        itt_t init_task_tag;
@@ -670,10 +676,11 @@ struct iscsi_login {
        u32 rsp_length;
        u16 cid;
        u16 tsih;
-       char *req;
-       char *rsp;
+       char req[ISCSI_HDR_LEN];
+       char rsp[ISCSI_HDR_LEN];
        char *req_buf;
        char *rsp_buf;
+       struct iscsi_conn *conn;
 } ____cacheline_aligned;
 
 struct iscsi_node_attrib {
@@ -754,6 +761,8 @@ struct iscsi_np {
        struct task_struct      *np_thread;
        struct timer_list       np_login_timer;
        struct iscsi_portal_group *np_login_tpg;
+       void                    *np_context;
+       struct iscsit_transport *np_transport;
        struct list_head        np_list;
 } ____cacheline_aligned;
 
index 2535d4d..0de5c47 100644 (file)
 #include "iscsi_target.h"
 #include "iscsi_target_parameters.h"
 
-static int iscsi_login_init_conn(struct iscsi_conn *conn)
+#include <target/iscsi/iscsi_transport.h>
+
+static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
 {
+       struct iscsi_login *login;
+
+       login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
+       if (!login) {
+               pr_err("Unable to allocate memory for struct iscsi_login.\n");
+               return NULL;
+       }
+       login->conn = conn;
+       login->first_request = 1;
+
+       login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+       if (!login->req_buf) {
+               pr_err("Unable to allocate memory for response buffer.\n");
+               goto out_login;
+       }
+
+       login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
+       if (!login->rsp_buf) {
+               pr_err("Unable to allocate memory for request buffer.\n");
+               goto out_req_buf;
+       }
+
+       conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
+       if (!conn->conn_ops) {
+               pr_err("Unable to allocate memory for"
+                       " struct iscsi_conn_ops.\n");
+               goto out_rsp_buf;
+       }
+
        init_waitqueue_head(&conn->queues_wq);
        INIT_LIST_HEAD(&conn->conn_list);
        INIT_LIST_HEAD(&conn->conn_cmd_list);
@@ -62,10 +93,21 @@ static int iscsi_login_init_conn(struct iscsi_conn *conn)
 
        if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) {
                pr_err("Unable to allocate conn->conn_cpumask\n");
-               return -ENOMEM;
+               goto out_conn_ops;
        }
+       conn->conn_login = login;
 
-       return 0;
+       return login;
+
+out_conn_ops:
+       kfree(conn->conn_ops);
+out_rsp_buf:
+       kfree(login->rsp_buf);
+out_req_buf:
+       kfree(login->req_buf);
+out_login:
+       kfree(login);
+       return NULL;
 }
 
 /*
@@ -573,10 +615,13 @@ int iscsi_login_post_auth_non_zero_tsih(
 
 static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
 {
+#warning FIXME: Reenable iscsit_start_nopin_timer
+#if 0
        struct iscsi_session *sess = conn->sess;
 
        if (!sess->sess_ops->SessionType)
                iscsit_start_nopin_timer(conn);
+#endif
 }
 
 static int iscsi_post_login_handler(
@@ -632,7 +677,13 @@ static int iscsi_post_login_handler(
                spin_unlock_bh(&sess->conn_lock);
 
                iscsi_post_login_start_timers(conn);
-               iscsi_activate_thread_set(conn, ts);
+
+               if (conn->conn_transport == ISCSI_TCP) {
+                       iscsi_activate_thread_set(conn, ts);
+               } else {
+                       printk("Not calling iscsi_activate_thread_set....\n");
+                       dump_stack();
+               }
                /*
                 * Determine CPU mask to ensure connection's RX and TX kthreads
                 * are scheduled on the same CPU.
@@ -761,11 +812,11 @@ static void iscsi_stop_login_thread_timer(struct iscsi_np *np)
        spin_unlock_bh(&np->np_thread_lock);
 }
 
-int iscsi_target_setup_login_socket(
+int iscsit_setup_np(
        struct iscsi_np *np,
        struct __kernel_sockaddr_storage *sockaddr)
 {
-       struct socket *sock;
+       struct socket *sock = NULL;
        int backlog = 5, ret, opt = 0, len;
 
        switch (np->np_network_transport) {
@@ -781,15 +832,15 @@ int iscsi_target_setup_login_socket(
                np->np_ip_proto = IPPROTO_SCTP;
                np->np_sock_type = SOCK_SEQPACKET;
                break;
-       case ISCSI_IWARP_TCP:
-       case ISCSI_IWARP_SCTP:
-       case ISCSI_INFINIBAND:
        default:
                pr_err("Unsupported network_transport: %d\n",
                                np->np_network_transport);
                return -EINVAL;
        }
 
+       np->np_ip_proto = IPPROTO_TCP;
+       np->np_sock_type = SOCK_STREAM;
+
        ret = sock_create(sockaddr->ss_family, np->np_sock_type,
                        np->np_ip_proto, &sock);
        if (ret < 0) {
@@ -853,7 +904,6 @@ int iscsi_target_setup_login_socket(
        }
 
        return 0;
-
 fail:
        np->np_socket = NULL;
        if (sock)
@@ -861,21 +911,170 @@ fail:
        return ret;
 }
 
+int iscsi_target_setup_login_socket(
+       struct iscsi_np *np,
+       struct __kernel_sockaddr_storage *sockaddr)
+{
+       struct iscsit_transport *t;
+       int rc;
+
+       t = iscsit_get_transport(np->np_network_transport);
+       if (!t)
+               return -EINVAL;
+
+       rc = t->iscsit_setup_np(np, sockaddr);
+       if (rc < 0) {
+               iscsit_put_transport(t);
+               return rc;
+       }
+
+       np->np_transport = t;
+       printk("Set np->np_transport to %p -> %s\n", np->np_transport,
+                               np->np_transport->name);
+       return 0;
+}
+
+int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
+{
+       struct socket *new_sock, *sock = np->np_socket;
+       struct sockaddr_in sock_in;
+       struct sockaddr_in6 sock_in6;
+       int rc, err;
+
+       rc = kernel_accept(sock, &new_sock, 0);
+       if (rc < 0)
+               return rc;
+
+       conn->sock = new_sock;
+       conn->login_family = np->np_sockaddr.ss_family;
+       printk("iSCSI/TCP: Setup conn->sock from new_sock: %p\n", new_sock);
+
+       if (np->np_sockaddr.ss_family == AF_INET6) {
+               memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
+
+               rc = conn->sock->ops->getname(conn->sock,
+                               (struct sockaddr *)&sock_in6, &err, 1);
+               if (!rc) {
+                       snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
+                               &sock_in6.sin6_addr.in6_u);
+                       conn->login_port = ntohs(sock_in6.sin6_port);
+               }
+
+               rc = conn->sock->ops->getname(conn->sock,
+                               (struct sockaddr *)&sock_in6, &err, 0);
+               if (!rc) {
+                       snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
+                               &sock_in6.sin6_addr.in6_u);
+                       conn->local_port = ntohs(sock_in6.sin6_port);
+               }
+       } else {
+               memset(&sock_in, 0, sizeof(struct sockaddr_in));
+
+               rc = conn->sock->ops->getname(conn->sock,
+                               (struct sockaddr *)&sock_in, &err, 1);
+               if (!rc) {
+                       sprintf(conn->login_ip, "%pI4",
+                                       &sock_in.sin_addr.s_addr);
+                       conn->login_port = ntohs(sock_in.sin_port);
+               }
+
+               rc = conn->sock->ops->getname(conn->sock,
+                               (struct sockaddr *)&sock_in, &err, 0);
+               if (!rc) {
+                       sprintf(conn->local_ip, "%pI4",
+                                       &sock_in.sin_addr.s_addr);
+                       conn->local_port = ntohs(sock_in.sin_port);
+               }
+       }
+
+       return 0;
+}
+
+int iscsit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+       struct iscsi_login_req *login_req;
+       u32 padding = 0, payload_length;
+
+       if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
+               return -1;
+
+       login_req = (struct iscsi_login_req *)login->req;
+       payload_length  = ntoh24(login_req->dlength);
+       padding = ((-payload_length) & 3);
+
+       pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
+               " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
+               login_req->flags, login_req->itt, login_req->cmdsn,
+               login_req->exp_statsn, login_req->cid, payload_length);
+       /*
+        * Setup the initial iscsi_login values from the leading
+        * login request PDU.
+        */
+       if (login->first_request) {
+               login_req = (struct iscsi_login_req *)login->req;
+               login->leading_connection = (!login_req->tsih) ? 1 : 0;
+               login->current_stage    =
+                       (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
+               login->version_min      = login_req->min_version;
+               login->version_max      = login_req->max_version;
+               memcpy(login->isid, login_req->isid, 6);
+               login->cmd_sn           = be32_to_cpu(login_req->cmdsn);
+               login->init_task_tag    = login_req->itt;
+               login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn);
+               login->cid              = be16_to_cpu(login_req->cid);
+               login->tsih             = be16_to_cpu(login_req->tsih);
+       }
+
+       if (iscsi_target_check_login_request(conn, login) < 0)
+               return -1;
+
+       memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
+       if (iscsi_login_rx_data(conn, login->req_buf,
+                               payload_length + padding) < 0)
+               return -1;
+
+       return 0;
+}
+
+int iscsit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login,
+                       u32 length)
+{
+       if (iscsi_login_tx_data(conn, login->rsp, login->rsp_buf, length) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int
+iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t)
+{
+       int rc;
+
+       if (!t->owner) {
+               conn->conn_transport = t;
+               return 0;
+       }
+
+       rc = try_module_get(t->owner);
+       if (!rc) {
+               pr_err("try_module_get() failed for %s\n", t->name);
+               return -EINVAL;
+       }
+
+       conn->conn_transport = t;
+       return 0;
+}
+
 static int __iscsi_target_login_thread(struct iscsi_np *np)
 {
-       u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0;
-       int err, ret = 0, stop;
+       u8 *buffer, zero_tsih = 0;
+       int ret = 0, rc, stop;
        struct iscsi_conn *conn = NULL;
        struct iscsi_login *login;
        struct iscsi_portal_group *tpg = NULL;
-       struct socket *new_sock, *sock;
-       struct kvec iov;
        struct iscsi_login_req *pdu;
-       struct sockaddr_in sock_in;
-       struct sockaddr_in6 sock_in6;
 
        flush_signals(current);
-       sock = np->np_socket;
 
        spin_lock_bh(&np->np_thread_lock);
        if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
@@ -886,75 +1085,76 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        }
        spin_unlock_bh(&np->np_thread_lock);
 
-       if (kernel_accept(sock, &new_sock, 0) < 0) {
-               spin_lock_bh(&np->np_thread_lock);
-               if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
-                       spin_unlock_bh(&np->np_thread_lock);
-                       complete(&np->np_restart_comp);
-                       /* Get another socket */
-                       return 1;
-               }
-               spin_unlock_bh(&np->np_thread_lock);
-               goto out;
-       }
-       iscsi_start_login_thread_timer(np);
-
        conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
        if (!conn) {
                pr_err("Could not allocate memory for"
                        " new connection\n");
-               sock_release(new_sock);
                /* Get another socket */
                return 1;
        }
-
        pr_debug("Moving to TARG_CONN_STATE_FREE.\n");
        conn->conn_state = TARG_CONN_STATE_FREE;
-       conn->sock = new_sock;
 
-       pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
-       conn->conn_state = TARG_CONN_STATE_XPT_UP;
+       if (iscsit_conn_set_transport(conn, np->np_transport) < 0) {
+               kfree(conn);
+               return 1;
+       }
 
-       /*
-        * Allocate conn->conn_ops early as a failure calling
-        * iscsit_tx_login_rsp() below will call tx_data().
-        */
-       conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL);
-       if (!conn->conn_ops) {
-               pr_err("Unable to allocate memory for"
-                       " struct iscsi_conn_ops.\n");
-               goto new_sess_out;
+       rc = np->np_transport->iscsit_accept_np(np, conn);
+       if (rc == -ENOSYS) {
+               complete(&np->np_restart_comp);
+               iscsit_put_transport(conn->conn_transport);
+               kfree(conn);
+               conn = NULL;
+               goto exit;
+       } else if (rc < 0) {
+               spin_lock_bh(&np->np_thread_lock);
+               if (np->np_thread_state == ISCSI_NP_THREAD_RESET) {
+                       spin_unlock_bh(&np->np_thread_lock);
+                       complete(&np->np_restart_comp);
+                       if (ret == -ENODEV) {
+                               iscsit_put_transport(conn->conn_transport);
+                               kfree(conn);
+                               conn = NULL;
+                               goto out;
+                       }
+                       /* Get another socket */
+                       return 1;
+               }
+               spin_unlock_bh(&np->np_thread_lock);
+               iscsit_put_transport(conn->conn_transport);
+               kfree(conn);
+               conn = NULL;
+               goto out;
        }
        /*
         * Perform the remaining iSCSI connection initialization items..
         */
-       if (iscsi_login_init_conn(conn) < 0)
-               goto new_sess_out;
-
-       memset(buffer, 0, ISCSI_HDR_LEN);
-       memset(&iov, 0, sizeof(struct kvec));
-       iov.iov_base    = buffer;
-       iov.iov_len     = ISCSI_HDR_LEN;
-
-       if (rx_data(conn, &iov, 1, ISCSI_HDR_LEN) <= 0) {
-               pr_err("rx_data() returned an error.\n");
+       login = iscsi_login_init_conn(conn);
+       if (!login) {
                goto new_sess_out;
        }
 
-       iscsi_opcode = (buffer[0] & ISCSI_OPCODE_MASK);
-       if (!(iscsi_opcode & ISCSI_OP_LOGIN)) {
-               pr_err("First opcode is not login request,"
-                       " failing login request.\n");
-               goto new_sess_out;
-       }
+       iscsi_start_login_thread_timer(np);
 
-       pdu                     = (struct iscsi_login_req *) buffer;
+       pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
+       conn->conn_state = TARG_CONN_STATE_XPT_UP;
+       /*
+        * This will process the first login request + payload..
+        */
+       rc = np->np_transport->iscsit_get_login_rx(conn, login);
+       if (rc == 1)
+               return 1;
+       else if (rc < 0)
+               goto new_sess_out;
 
+       buffer = &login->req[0];
+       pdu = (struct iscsi_login_req *)buffer;
        /*
         * Used by iscsit_tx_login_rsp() for Login Resonses PDUs
         * when Status-Class != 0.
        */
-       conn->login_itt         = pdu->itt;
+       conn->login_itt = pdu->itt;
 
        spin_lock_bh(&np->np_thread_lock);
        if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
@@ -967,61 +1167,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        }
        spin_unlock_bh(&np->np_thread_lock);
 
-       if (np->np_sockaddr.ss_family == AF_INET6) {
-               memset(&sock_in6, 0, sizeof(struct sockaddr_in6));
-
-               if (conn->sock->ops->getname(conn->sock,
-                               (struct sockaddr *)&sock_in6, &err, 1) < 0) {
-                       pr_err("sock_ops->getname() failed.\n");
-                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
-                                       ISCSI_LOGIN_STATUS_TARGET_ERROR);
-                       goto new_sess_out;
-               }
-               snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
-                               &sock_in6.sin6_addr.in6_u);
-               conn->login_port = ntohs(sock_in6.sin6_port);
-
-               if (conn->sock->ops->getname(conn->sock,
-                               (struct sockaddr *)&sock_in6, &err, 0) < 0) {
-                       pr_err("sock_ops->getname() failed.\n");
-                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
-                                       ISCSI_LOGIN_STATUS_TARGET_ERROR);
-                       goto new_sess_out;
-               }
-               snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
-                               &sock_in6.sin6_addr.in6_u);
-               conn->local_port = ntohs(sock_in6.sin6_port);
-
-       } else {
-               memset(&sock_in, 0, sizeof(struct sockaddr_in));
-
-               if (conn->sock->ops->getname(conn->sock,
-                               (struct sockaddr *)&sock_in, &err, 1) < 0) {
-                       pr_err("sock_ops->getname() failed.\n");
-                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
-                                       ISCSI_LOGIN_STATUS_TARGET_ERROR);
-                       goto new_sess_out;
-               }
-               sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr);
-               conn->login_port = ntohs(sock_in.sin_port);
-
-               if (conn->sock->ops->getname(conn->sock,
-                               (struct sockaddr *)&sock_in, &err, 0) < 0) {
-                       pr_err("sock_ops->getname() failed.\n");
-                       iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
-                                       ISCSI_LOGIN_STATUS_TARGET_ERROR);
-                       goto new_sess_out;
-               }
-               sprintf(conn->local_ip, "%pI4", &sock_in.sin_addr.s_addr);
-               conn->local_port = ntohs(sock_in.sin_port);
-       }
-
        conn->network_transport = np->np_network_transport;
 
        pr_debug("Received iSCSI login request from %s on %s Network"
-                       " Portal %s:%hu\n", conn->login_ip,
-               (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP",
-                       conn->local_ip, conn->local_port);
+               " Portal %s:%hu\n", conn->login_ip, np->np_transport->name,
+               conn->local_ip, conn->local_port);
 
        pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n");
        conn->conn_state        = TARG_CONN_STATE_IN_LOGIN;
@@ -1050,13 +1200,17 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
                if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0)
                        goto new_sess_out;
        }
-
        /*
-        * This will process the first login request, and call
-        * iscsi_target_locate_portal(), and return a valid struct iscsi_login.
+        * SessionType: Discovery
+        *
+        *      Locates Default Portal
+        *
+        * SessionType: Normal
+        *
+        *      Locates Target Portal from NP -> Target IQN
         */
-       login = iscsi_target_init_negotiation(np, conn, buffer);
-       if (!login) {
+       rc = iscsi_target_locate_portal(np, conn, login);
+       if (rc < 0) {
                tpg = conn->tpg;
                goto new_sess_out;
        }
@@ -1068,15 +1222,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        }
 
        if (zero_tsih) {
-               if (iscsi_login_zero_tsih_s2(conn) < 0) {
-                       iscsi_target_nego_release(login, conn);
+               if (iscsi_login_zero_tsih_s2(conn) < 0)
                        goto new_sess_out;
-               }
        } else {
-               if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) {
-                       iscsi_target_nego_release(login, conn);
+               if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0)
                        goto old_sess_out;
-               }
        }
 
        if (iscsi_target_start_negotiation(login, conn) < 0)
@@ -1153,8 +1303,18 @@ old_sess_out:
                iscsi_release_param_list(conn->param_list);
                conn->param_list = NULL;
        }
-       if (conn->sock)
+       iscsi_target_nego_release(conn);
+
+       if (conn->sock) {
                sock_release(conn->sock);
+               conn->sock = NULL;
+       }
+
+       if (conn->conn_transport->iscsit_free_conn)
+               conn->conn_transport->iscsit_free_conn(conn);
+
+       iscsit_put_transport(conn->conn_transport);
+
        kfree(conn);
 
        if (tpg) {
@@ -1172,11 +1332,13 @@ out:
        /* Wait for another socket.. */
        if (!stop)
                return 1;
-
+exit:
        iscsi_stop_login_thread_timer(np);
        spin_lock_bh(&np->np_thread_lock);
        np->np_thread_state = ISCSI_NP_THREAD_EXIT;
+       np->np_thread = NULL;
        spin_unlock_bh(&np->np_thread_lock);
+
        return 0;
 }
 
index 091dcae..63efd28 100644 (file)
@@ -4,8 +4,14 @@
 extern int iscsi_login_setup_crypto(struct iscsi_conn *);
 extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *);
 extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32);
+extern int iscsit_setup_np(struct iscsi_np *,
+                               struct __kernel_sockaddr_storage *);
 extern int iscsi_target_setup_login_socket(struct iscsi_np *,
                                struct __kernel_sockaddr_storage *);
+extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *);
+extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
+extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
+extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
 extern int iscsi_target_login_thread(void *);
 extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *);
 
index 3cbdccd..879a0cb 100644 (file)
@@ -22,6 +22,7 @@
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
+#include <target/iscsi/iscsi_transport.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_parameters.h"
@@ -169,7 +170,7 @@ static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn)
        kfree(conn->auth_protocol);
 }
 
-static int iscsi_target_check_login_request(
+int iscsi_target_check_login_request(
        struct iscsi_conn *conn,
        struct iscsi_login *login)
 {
@@ -352,11 +353,8 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
 
        padding = ((-login->rsp_length) & 3);
 
-       if (iscsi_login_tx_data(
-                       conn,
-                       login->rsp,
-                       login->rsp_buf,
-                       login->rsp_length + padding) < 0)
+       if (conn->conn_transport->iscsit_put_login_tx(conn, login,
+                                       login->rsp_length + padding) < 0)
                return -1;
 
        login->rsp_length               = 0;
@@ -368,72 +366,12 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
        return 0;
 }
 
-static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
-{
-       u32 padding = 0, payload_length;
-       struct iscsi_login_req *login_req;
-
-       if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0)
-               return -1;
-
-       login_req = (struct iscsi_login_req *) login->req;
-       payload_length                  = ntoh24(login_req->dlength);
-
-       pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
-               " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n",
-                login_req->flags, login_req->itt, login_req->cmdsn,
-                login_req->exp_statsn, login_req->cid, payload_length);
-
-       if (iscsi_target_check_login_request(conn, login) < 0)
-               return -1;
-
-       padding = ((-payload_length) & 3);
-       memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS);
-
-       if (iscsi_login_rx_data(
-                       conn,
-                       login->req_buf,
-                       payload_length + padding) < 0)
-               return -1;
-
-       return 0;
-}
-
 static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
 {
        if (iscsi_target_do_tx_login_io(conn, login) < 0)
                return -1;
 
-       if (iscsi_target_do_rx_login_io(conn, login) < 0)
-               return -1;
-
-       return 0;
-}
-
-static int iscsi_target_get_initial_payload(
-       struct iscsi_conn *conn,
-       struct iscsi_login *login)
-{
-       u32 padding = 0, payload_length;
-       struct iscsi_login_req *login_req;
-
-       login_req = (struct iscsi_login_req *) login->req;
-       payload_length = ntoh24(login_req->dlength);
-
-       pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x,"
-               " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n",
-               login_req->flags, login_req->itt, login_req->cmdsn,
-               login_req->exp_statsn, payload_length);
-
-       if (iscsi_target_check_login_request(conn, login) < 0)
-               return -1;
-
-       padding = ((-payload_length) & 3);
-
-       if (iscsi_login_rx_data(
-                       conn,
-                       login->req_buf,
-                       payload_length + padding) < 0)
+       if (conn->conn_transport->iscsit_get_login_rx(conn, login) < 0)
                return -1;
 
        return 0;
@@ -693,6 +631,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo
                                return -1;
                        if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
                                login->tsih = conn->sess->tsih;
+                               login->login_complete = 1;
                                if (iscsi_target_do_tx_login_io(conn,
                                                login) < 0)
                                        return -1;
@@ -736,7 +675,7 @@ static void iscsi_initiatorname_tolower(
 /*
  * Processes the first Login Request..
  */
-static int iscsi_target_locate_portal(
+int iscsi_target_locate_portal(
        struct iscsi_np *np,
        struct iscsi_conn *conn,
        struct iscsi_login *login)
@@ -798,6 +737,8 @@ static int iscsi_target_locate_portal(
                start += strlen(key) + strlen(value) + 2;
        }
 
+       printk("i_buf: %s, s_buf: %s, t_buf: %s\n", i_buf, s_buf, t_buf);
+
        /*
         * See 5.3.  Login Phase.
         */
@@ -956,100 +897,30 @@ out:
        return ret;
 }
 
-struct iscsi_login *iscsi_target_init_negotiation(
-       struct iscsi_np *np,
-       struct iscsi_conn *conn,
-       char *login_pdu)
-{
-       struct iscsi_login *login;
-
-       login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL);
-       if (!login) {
-               pr_err("Unable to allocate memory for struct iscsi_login.\n");
-               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
-                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
-               return NULL;
-       }
-
-       login->req = kmemdup(login_pdu, ISCSI_HDR_LEN, GFP_KERNEL);
-       if (!login->req) {
-               pr_err("Unable to allocate memory for Login Request.\n");
-               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
-                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
-               goto out;
-       }
-
-       login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
-       if (!login->req_buf) {
-               pr_err("Unable to allocate memory for response buffer.\n");
-               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
-                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
-               goto out;
-       }
-       /*
-        * SessionType: Discovery
-        *
-        *      Locates Default Portal
-        *
-        * SessionType: Normal
-        *
-        *      Locates Target Portal from NP -> Target IQN
-        */
-       if (iscsi_target_locate_portal(np, conn, login) < 0) {
-               goto out;
-       }
-
-       return login;
-out:
-       kfree(login->req);
-       kfree(login->req_buf);
-       kfree(login);
-
-       return NULL;
-}
-
 int iscsi_target_start_negotiation(
        struct iscsi_login *login,
        struct iscsi_conn *conn)
 {
-       int ret = -1;
-
-       login->rsp = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL);
-       if (!login->rsp) {
-               pr_err("Unable to allocate memory for"
-                               " Login Response.\n");
-               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
-                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
-               ret = -1;
-               goto out;
-       }
-
-       login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL);
-       if (!login->rsp_buf) {
-               pr_err("Unable to allocate memory for"
-                       " request buffer.\n");
-               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
-                               ISCSI_LOGIN_STATUS_NO_RESOURCES);
-               ret = -1;
-               goto out;
-       }
+       int ret;
 
        ret = iscsi_target_do_login(conn, login);
-out:
        if (ret != 0)
                iscsi_remove_failed_auth_entry(conn);
 
-       iscsi_target_nego_release(login, conn);
+       iscsi_target_nego_release(conn);
        return ret;
 }
 
-void iscsi_target_nego_release(
-       struct iscsi_login *login,
-       struct iscsi_conn *conn)
+void iscsi_target_nego_release(struct iscsi_conn *conn)
 {
-       kfree(login->req);
-       kfree(login->rsp);
+       struct iscsi_login *login = conn->conn_login;
+
+       if (!login)
+               return;
+
        kfree(login->req_buf);
        kfree(login->rsp_buf);
        kfree(login);
+
+       conn->conn_login = NULL;
 }
index 92e133a..f021cbd 100644 (file)
@@ -7,11 +7,14 @@
 extern void convert_null_to_semi(char *, int);
 extern int extract_param(const char *, const char *, unsigned int, char *,
                unsigned char *);
-extern struct iscsi_login *iscsi_target_init_negotiation(
-               struct iscsi_np *, struct iscsi_conn *, char *);
+extern int iscsi_target_check_login_request(struct iscsi_conn *,
+               struct iscsi_login *);
+extern int iscsi_target_get_initial_payload(struct iscsi_conn *,
+               struct iscsi_login *);
+extern int iscsi_target_locate_portal(struct iscsi_np *, struct iscsi_conn *,
+               struct iscsi_login *);
 extern int iscsi_target_start_negotiation(
                struct iscsi_login *, struct iscsi_conn *);
-extern void iscsi_target_nego_release(
-               struct iscsi_login *, struct iscsi_conn *);
+extern void iscsi_target_nego_release(struct iscsi_conn *);
 
 #endif /* ISCSI_TARGET_NEGO_H */
index ca2be40..84ce94a 100644 (file)
@@ -59,7 +59,7 @@ int iscsi_login_tx_data(
        char *text_buf,
        int text_length)
 {
-       int length, tx_sent;
+       int length, tx_sent, iov_cnt = 1;
        struct kvec iov[2];
 
        length = (ISCSI_HDR_LEN + text_length);
@@ -67,8 +67,12 @@ int iscsi_login_tx_data(
        memset(&iov[0], 0, 2 * sizeof(struct kvec));
        iov[0].iov_len          = ISCSI_HDR_LEN;
        iov[0].iov_base         = pdu_buf;
-       iov[1].iov_len          = text_length;
-       iov[1].iov_base         = text_buf;
+
+       if (text_buf && text_length) {
+               iov[1].iov_len  = text_length;
+               iov[1].iov_base = text_buf;
+               iov_cnt++;
+       }
 
        /*
         * Initial Marker-less Interval.
@@ -77,7 +81,7 @@ int iscsi_login_tx_data(
         */
        conn->if_marker += length;
 
-       tx_sent = tx_data(conn, &iov[0], 2, length);
+       tx_sent = tx_data(conn, &iov[0], iov_cnt, length);
        if (tx_sent != length) {
                pr_err("tx_data returned %d, expecting %d.\n",
                                tx_sent, length);
index ee8f8c6..439260b 100644 (file)
@@ -31,6 +31,8 @@
 #include "iscsi_target.h"
 #include "iscsi_target_parameters.h"
 
+#include <target/iscsi/iscsi_transport.h>
+
 struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt)
 {
        struct iscsi_portal_group *tpg;
@@ -508,7 +510,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
 
        pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n",
                tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
-               (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
+               np->np_transport->name);
 
        return tpg_np;
 }
@@ -522,7 +524,7 @@ static int iscsit_tpg_release_np(
 
        pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n",
                tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
-               (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP");
+               np->np_transport->name);
 
        tpg_np->tpg_np = NULL;
        tpg_np->tpg = NULL;
index 7ce3505..4cf1e7f 100644 (file)
@@ -24,6 +24,7 @@
 #include <target/target_core_base.h>
 #include <target/target_core_fabric.h>
 #include <target/target_core_configfs.h>
+#include <target/iscsi/iscsi_transport.h>
 
 #include "iscsi_target_core.h"
 #include "iscsi_target_parameters.h"
@@ -1226,34 +1227,19 @@ send_datacrc:
  */
 int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail)
 {
-       u8 iscsi_hdr[ISCSI_HDR_LEN];
-       int err;
-       struct kvec iov;
        struct iscsi_login_rsp *hdr;
+       struct iscsi_login *login = conn->conn_login;
 
+       login->login_failed = 1;
        iscsit_collect_login_stats(conn, status_class, status_detail);
 
-       memset(&iov, 0, sizeof(struct kvec));
-       memset(&iscsi_hdr, 0x0, ISCSI_HDR_LEN);
-
-       hdr     = (struct iscsi_login_rsp *)&iscsi_hdr;
+       hdr     = (struct iscsi_login_rsp *)&login->rsp[0];
        hdr->opcode             = ISCSI_OP_LOGIN_RSP;
        hdr->status_class       = status_class;
        hdr->status_detail      = status_detail;
        hdr->itt                = conn->login_itt;
 
-       iov.iov_base            = &iscsi_hdr;
-       iov.iov_len             = ISCSI_HDR_LEN;
-
-       PRINT_BUFF(iscsi_hdr, ISCSI_HDR_LEN);
-
-       err = tx_data(conn, &iov, 1, ISCSI_HDR_LEN);
-       if (err != ISCSI_HDR_LEN) {
-               pr_err("tx_data returned less than expected\n");
-               return -1;
-       }
-
-       return 0;
+       return conn->conn_transport->iscsit_put_login_tx(conn, login, 0);
 }
 
 void iscsit_print_session_params(struct iscsi_session *sess)
@@ -1432,7 +1418,8 @@ void iscsit_collect_login_stats(
                strcpy(ls->last_intr_fail_name,
                       (intrname ? intrname->value : "Unknown"));
 
-               ls->last_intr_fail_ip_family = conn->sock->sk->sk_family;
+               ls->last_intr_fail_ip_family = conn->login_family;
+
                snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE,
                                "%s", conn->login_ip);
                ls->last_fail_time = get_jiffies_64();