Merge tag 'media/v5.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[linux-2.6-microblaze.git] / net / smc / af_smc.c
index 6fd44bd..9033215 100644 (file)
@@ -337,50 +337,61 @@ static void smc_copy_sock_settings_to_smc(struct smc_sock *smc)
        smc_copy_sock_settings(&smc->sk, smc->clcsock->sk, SK_FLAGS_CLC_TO_SMC);
 }
 
-/* register a new rmb, send confirm_rkey msg to register with peer */
-static int smc_reg_rmb(struct smc_link *link, struct smc_buf_desc *rmb_desc,
-                      bool conf_rkey)
-{
-       if (!rmb_desc->wr_reg) {
-               /* register memory region for new rmb */
-               if (smc_wr_reg_send(link, rmb_desc->mr_rx[SMC_SINGLE_LINK])) {
-                       rmb_desc->regerr = 1;
-                       return -EFAULT;
-               }
-               rmb_desc->wr_reg = 1;
+/* register the new rmb on all links */
+static int smcr_lgr_reg_rmbs(struct smc_link *link,
+                            struct smc_buf_desc *rmb_desc)
+{
+       struct smc_link_group *lgr = link->lgr;
+       int i, rc = 0;
+
+       rc = smc_llc_flow_initiate(lgr, SMC_LLC_FLOW_RKEY);
+       if (rc)
+               return rc;
+       /* protect against parallel smc_llc_cli_rkey_exchange() and
+        * parallel smcr_link_reg_rmb()
+        */
+       mutex_lock(&lgr->llc_conf_mutex);
+       for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
+               if (lgr->lnk[i].state != SMC_LNK_ACTIVE)
+                       continue;
+               rc = smcr_link_reg_rmb(&lgr->lnk[i], rmb_desc);
+               if (rc)
+                       goto out;
        }
-       if (!conf_rkey)
-               return 0;
+
        /* exchange confirm_rkey msg with peer */
-       if (smc_llc_do_confirm_rkey(link, rmb_desc)) {
-               rmb_desc->regerr = 1;
-               return -EFAULT;
+       rc = smc_llc_do_confirm_rkey(link, rmb_desc);
+       if (rc) {
+               rc = -EFAULT;
+               goto out;
        }
-       return 0;
+       rmb_desc->is_conf_rkey = true;
+out:
+       mutex_unlock(&lgr->llc_conf_mutex);
+       smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl);
+       return rc;
 }
 
-static int smc_clnt_conf_first_link(struct smc_sock *smc)
+static int smcr_clnt_conf_first_link(struct smc_sock *smc)
 {
-       struct net *net = sock_net(smc->clcsock->sk);
-       struct smc_link_group *lgr = smc->conn.lgr;
-       struct smc_link *link;
-       int rest;
+       struct smc_link *link = smc->conn.lnk;
+       struct smc_llc_qentry *qentry;
        int rc;
 
-       link = &lgr->lnk[SMC_SINGLE_LINK];
        /* receive CONFIRM LINK request from server over RoCE fabric */
-       rest = wait_for_completion_interruptible_timeout(
-               &link->llc_confirm,
-               SMC_LLC_WAIT_FIRST_TIME);
-       if (rest <= 0) {
+       qentry = smc_llc_wait(link->lgr, NULL, SMC_LLC_WAIT_TIME,
+                             SMC_LLC_CONFIRM_LINK);
+       if (!qentry) {
                struct smc_clc_msg_decline dclc;
 
                rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
                                      SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT);
                return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_CL : rc;
        }
-
-       if (link->llc_confirm_rc)
+       smc_llc_save_peer_uid(qentry);
+       rc = smc_llc_eval_conf_link(qentry, SMC_LLC_REQ);
+       smc_llc_flow_qentry_del(&link->lgr->llc_flow_lcl);
+       if (rc)
                return SMC_CLC_DECL_RMBE_EC;
 
        rc = smc_ib_modify_qp_rts(link);
@@ -389,34 +400,34 @@ static int smc_clnt_conf_first_link(struct smc_sock *smc)
 
        smc_wr_remember_qp_attr(link);
 
-       if (smc_reg_rmb(link, smc->conn.rmb_desc, false))
+       if (smcr_link_reg_rmb(link, smc->conn.rmb_desc))
                return SMC_CLC_DECL_ERR_REGRMB;
 
+       /* confirm_rkey is implicit on 1st contact */
+       smc->conn.rmb_desc->is_conf_rkey = true;
+
        /* send CONFIRM LINK response over RoCE fabric */
        rc = smc_llc_send_confirm_link(link, SMC_LLC_RESP);
        if (rc < 0)
                return SMC_CLC_DECL_TIMEOUT_CL;
 
-       /* receive ADD LINK request from server over RoCE fabric */
-       rest = wait_for_completion_interruptible_timeout(&link->llc_add,
-                                                        SMC_LLC_WAIT_TIME);
-       if (rest <= 0) {
+       smc_llc_link_active(link);
+       smcr_lgr_set_type(link->lgr, SMC_LGR_SINGLE);
+
+       /* optional 2nd link, receive ADD LINK request from server */
+       qentry = smc_llc_wait(link->lgr, NULL, SMC_LLC_WAIT_TIME,
+                             SMC_LLC_ADD_LINK);
+       if (!qentry) {
                struct smc_clc_msg_decline dclc;
 
                rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
                                      SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT);
-               return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_AL : rc;
+               if (rc == -EAGAIN)
+                       rc = 0; /* no DECLINE received, go with one link */
+               return rc;
        }
-
-       /* send add link reject message, only one link supported for now */
-       rc = smc_llc_send_add_link(link,
-                                  link->smcibdev->mac[link->ibport - 1],
-                                  link->gid, SMC_LLC_RESP);
-       if (rc < 0)
-               return SMC_CLC_DECL_TIMEOUT_AL;
-
-       smc_llc_link_active(link, net->ipv4.sysctl_tcp_keepalive_time);
-
+       smc_llc_flow_qentry_clr(&link->lgr->llc_flow_lcl);
+       smc_llc_cli_add_link(link, qentry);
        return 0;
 }
 
@@ -596,8 +607,8 @@ static int smc_connect_rdma(struct smc_sock *smc,
                            struct smc_clc_msg_accept_confirm *aclc,
                            struct smc_init_info *ini)
 {
+       int i, reason_code = 0;
        struct smc_link *link;
-       int reason_code = 0;
 
        ini->is_smcd = false;
        ini->ib_lcl = &aclc->lcl;
@@ -610,10 +621,28 @@ static int smc_connect_rdma(struct smc_sock *smc,
                mutex_unlock(&smc_client_lgr_pending);
                return reason_code;
        }
-       link = &smc->conn.lgr->lnk[SMC_SINGLE_LINK];
 
        smc_conn_save_peer_info(smc, aclc);
 
+       if (ini->cln_first_contact == SMC_FIRST_CONTACT) {
+               link = smc->conn.lnk;
+       } else {
+               /* set link that was assigned by server */
+               link = NULL;
+               for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) {
+                       struct smc_link *l = &smc->conn.lgr->lnk[i];
+
+                       if (l->peer_qpn == ntoh24(aclc->qpn)) {
+                               link = l;
+                               break;
+                       }
+               }
+               if (!link)
+                       return smc_connect_abort(smc, SMC_CLC_DECL_NOSRVLINK,
+                                                ini->cln_first_contact);
+               smc->conn.lnk = link;
+       }
+
        /* create send buffer and rmb */
        if (smc_buf_create(smc, false))
                return smc_connect_abort(smc, SMC_CLC_DECL_MEM,
@@ -622,7 +651,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
        if (ini->cln_first_contact == SMC_FIRST_CONTACT)
                smc_link_save_peer_info(link, aclc);
 
-       if (smc_rmb_rtoken_handling(&smc->conn, aclc))
+       if (smc_rmb_rtoken_handling(&smc->conn, link, aclc))
                return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RTOK,
                                         ini->cln_first_contact);
 
@@ -634,7 +663,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
                        return smc_connect_abort(smc, SMC_CLC_DECL_ERR_RDYLNK,
                                                 ini->cln_first_contact);
        } else {
-               if (smc_reg_rmb(link, smc->conn.rmb_desc, true))
+               if (smcr_lgr_reg_rmbs(link, smc->conn.rmb_desc))
                        return smc_connect_abort(smc, SMC_CLC_DECL_ERR_REGRMB,
                                                 ini->cln_first_contact);
        }
@@ -649,7 +678,9 @@ static int smc_connect_rdma(struct smc_sock *smc,
 
        if (ini->cln_first_contact == SMC_FIRST_CONTACT) {
                /* QP confirmation over RoCE fabric */
-               reason_code = smc_clnt_conf_first_link(smc);
+               smc_llc_flow_initiate(link->lgr, SMC_LLC_FLOW_ADD_LINK);
+               reason_code = smcr_clnt_conf_first_link(smc);
+               smc_llc_flow_stop(link->lgr, &link->lgr->llc_flow_lcl);
                if (reason_code)
                        return smc_connect_abort(smc, reason_code,
                                                 ini->cln_first_contact);
@@ -999,17 +1030,13 @@ void smc_close_non_accepted(struct sock *sk)
        sock_put(sk); /* final sock_put */
 }
 
-static int smc_serv_conf_first_link(struct smc_sock *smc)
+static int smcr_serv_conf_first_link(struct smc_sock *smc)
 {
-       struct net *net = sock_net(smc->clcsock->sk);
-       struct smc_link_group *lgr = smc->conn.lgr;
-       struct smc_link *link;
-       int rest;
+       struct smc_link *link = smc->conn.lnk;
+       struct smc_llc_qentry *qentry;
        int rc;
 
-       link = &lgr->lnk[SMC_SINGLE_LINK];
-
-       if (smc_reg_rmb(link, smc->conn.rmb_desc, false))
+       if (smcr_link_reg_rmb(link, smc->conn.rmb_desc))
                return SMC_CLC_DECL_ERR_REGRMB;
 
        /* send CONFIRM LINK request to client over the RoCE fabric */
@@ -1018,40 +1045,29 @@ static int smc_serv_conf_first_link(struct smc_sock *smc)
                return SMC_CLC_DECL_TIMEOUT_CL;
 
        /* receive CONFIRM LINK response from client over the RoCE fabric */
-       rest = wait_for_completion_interruptible_timeout(
-               &link->llc_confirm_resp,
-               SMC_LLC_WAIT_FIRST_TIME);
-       if (rest <= 0) {
+       qentry = smc_llc_wait(link->lgr, link, SMC_LLC_WAIT_TIME,
+                             SMC_LLC_CONFIRM_LINK);
+       if (!qentry) {
                struct smc_clc_msg_decline dclc;
 
                rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
                                      SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT);
                return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_CL : rc;
        }
-
-       if (link->llc_confirm_resp_rc)
+       smc_llc_save_peer_uid(qentry);
+       rc = smc_llc_eval_conf_link(qentry, SMC_LLC_RESP);
+       smc_llc_flow_qentry_del(&link->lgr->llc_flow_lcl);
+       if (rc)
                return SMC_CLC_DECL_RMBE_EC;
 
-       /* send ADD LINK request to client over the RoCE fabric */
-       rc = smc_llc_send_add_link(link,
-                                  link->smcibdev->mac[link->ibport - 1],
-                                  link->gid, SMC_LLC_REQ);
-       if (rc < 0)
-               return SMC_CLC_DECL_TIMEOUT_AL;
-
-       /* receive ADD LINK response from client over the RoCE fabric */
-       rest = wait_for_completion_interruptible_timeout(&link->llc_add_resp,
-                                                        SMC_LLC_WAIT_TIME);
-       if (rest <= 0) {
-               struct smc_clc_msg_decline dclc;
-
-               rc = smc_clc_wait_msg(smc, &dclc, sizeof(dclc),
-                                     SMC_CLC_DECLINE, CLC_WAIT_TIME_SHORT);
-               return rc == -EAGAIN ? SMC_CLC_DECL_TIMEOUT_AL : rc;
-       }
+       /* confirm_rkey is implicit on 1st contact */
+       smc->conn.rmb_desc->is_conf_rkey = true;
 
-       smc_llc_link_active(link, net->ipv4.sysctl_tcp_keepalive_time);
+       smc_llc_link_active(link);
+       smcr_lgr_set_type(link->lgr, SMC_LGR_SINGLE);
 
+       /* initial contact - try to establish second link */
+       smc_llc_srv_add_link(link);
        return 0;
 }
 
@@ -1194,10 +1210,10 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
 /* listen worker: register buffers */
 static int smc_listen_rdma_reg(struct smc_sock *new_smc, int local_contact)
 {
-       struct smc_link *link = &new_smc->conn.lgr->lnk[SMC_SINGLE_LINK];
+       struct smc_connection *conn = &new_smc->conn;
 
        if (local_contact != SMC_FIRST_CONTACT) {
-               if (smc_reg_rmb(link, new_smc->conn.rmb_desc, true))
+               if (smcr_lgr_reg_rmbs(conn->lnk, conn->rmb_desc))
                        return SMC_CLC_DECL_ERR_REGRMB;
        }
        smc_rmb_sync_sg_for_device(&new_smc->conn);
@@ -1210,13 +1226,13 @@ static int smc_listen_rdma_finish(struct smc_sock *new_smc,
                                  struct smc_clc_msg_accept_confirm *cclc,
                                  int local_contact)
 {
-       struct smc_link *link = &new_smc->conn.lgr->lnk[SMC_SINGLE_LINK];
+       struct smc_link *link = new_smc->conn.lnk;
        int reason_code = 0;
 
        if (local_contact == SMC_FIRST_CONTACT)
                smc_link_save_peer_info(link, cclc);
 
-       if (smc_rmb_rtoken_handling(&new_smc->conn, cclc)) {
+       if (smc_rmb_rtoken_handling(&new_smc->conn, link, cclc)) {
                reason_code = SMC_CLC_DECL_ERR_RTOK;
                goto decline;
        }
@@ -1227,7 +1243,9 @@ static int smc_listen_rdma_finish(struct smc_sock *new_smc,
                        goto decline;
                }
                /* QP confirmation over RoCE fabric */
-               reason_code = smc_serv_conf_first_link(new_smc);
+               smc_llc_flow_initiate(link->lgr, SMC_LLC_FLOW_ADD_LINK);
+               reason_code = smcr_serv_conf_first_link(new_smc);
+               smc_llc_flow_stop(link->lgr, &link->lgr->llc_flow_lcl);
                if (reason_code)
                        goto decline;
        }