Merge tag 'gpio-updates-for-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / net / smc / af_smc.c
index 5dd4faa..47340b3 100644 (file)
@@ -45,6 +45,7 @@
 #include "smc_ib.h"
 #include "smc_ism.h"
 #include "smc_pnet.h"
+#include "smc_netlink.h"
 #include "smc_tx.h"
 #include "smc_rx.h"
 #include "smc_close.h"
@@ -552,8 +553,7 @@ static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code,
        return smc_connect_fallback(smc, reason_code);
 }
 
-/* abort connecting */
-static void smc_connect_abort(struct smc_sock *smc, int local_first)
+static void smc_conn_abort(struct smc_sock *smc, int local_first)
 {
        if (local_first)
                smc_lgr_cleanup_early(&smc->conn);
@@ -669,7 +669,7 @@ static int smc_find_proposal_devices(struct smc_sock *smc,
                                ini->smc_type_v1 = SMC_TYPE_N;
                } /* else RDMA is supported for this connection */
        }
-       if (smc_ism_v2_capable && smc_find_ism_v2_device_clnt(smc, ini))
+       if (smc_ism_is_v2_capable() && smc_find_ism_v2_device_clnt(smc, ini))
                ini->smc_type_v2 = SMC_TYPE_N;
 
        /* if neither ISM nor RDMA are supported, fallback */
@@ -814,7 +814,7 @@ static int smc_connect_rdma(struct smc_sock *smc,
 
        return 0;
 connect_abort:
-       smc_connect_abort(smc, ini->first_contact_local);
+       smc_conn_abort(smc, ini->first_contact_local);
        mutex_unlock(&smc_client_lgr_pending);
        smc->connect_nonblock = 0;
 
@@ -893,7 +893,7 @@ static int smc_connect_ism(struct smc_sock *smc,
 
        return 0;
 connect_abort:
-       smc_connect_abort(smc, ini->first_contact_local);
+       smc_conn_abort(smc, ini->first_contact_local);
        mutex_unlock(&smc_server_lgr_pending);
        smc->connect_nonblock = 0;
 
@@ -921,7 +921,7 @@ static int smc_connect_check_aclc(struct smc_init_info *ini,
 /* perform steps before actually connecting */
 static int __smc_connect(struct smc_sock *smc)
 {
-       u8 version = smc_ism_v2_capable ? SMC_V2 : SMC_V1;
+       u8 version = smc_ism_is_v2_capable() ? SMC_V2 : SMC_V1;
        struct smc_clc_msg_accept_confirm_v2 *aclc2;
        struct smc_clc_msg_accept_confirm *aclc;
        struct smc_init_info *ini = NULL;
@@ -946,9 +946,9 @@ static int __smc_connect(struct smc_sock *smc)
                                                    version);
 
        ini->smcd_version = SMC_V1;
-       ini->smcd_version |= smc_ism_v2_capable ? SMC_V2 : 0;
+       ini->smcd_version |= smc_ism_is_v2_capable() ? SMC_V2 : 0;
        ini->smc_type_v1 = SMC_TYPE_B;
-       ini->smc_type_v2 = smc_ism_v2_capable ? SMC_TYPE_D : SMC_TYPE_N;
+       ini->smc_type_v2 = smc_ism_is_v2_capable() ? SMC_TYPE_D : SMC_TYPE_N;
 
        /* get vlan id from IP device */
        if (smc_vlan_by_tcpsk(smc->clcsock, ini)) {
@@ -1321,10 +1321,7 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
                               int local_first, u8 version)
 {
        /* RDMA setup failed, switch back to TCP */
-       if (local_first)
-               smc_lgr_cleanup_early(&new_smc->conn);
-       else
-               smc_conn_free(&new_smc->conn);
+       smc_conn_abort(new_smc, local_first);
        if (reason_code < 0) { /* error, no fallback possible */
                smc_listen_out_err(new_smc);
                return;
@@ -1347,6 +1344,7 @@ static int smc_listen_v2_check(struct smc_sock *new_smc,
 {
        struct smc_clc_smcd_v2_extension *pclc_smcd_v2_ext;
        struct smc_clc_v2_extension *pclc_v2_ext;
+       int rc = SMC_CLC_DECL_PEERNOSMC;
 
        ini->smc_type_v1 = pclc->hdr.typev1;
        ini->smc_type_v2 = pclc->hdr.typev2;
@@ -1354,29 +1352,30 @@ static int smc_listen_v2_check(struct smc_sock *new_smc,
        if (pclc->hdr.version > SMC_V1)
                ini->smcd_version |=
                                ini->smc_type_v2 != SMC_TYPE_N ? SMC_V2 : 0;
-       if (!smc_ism_v2_capable) {
+       if (!(ini->smcd_version & SMC_V2)) {
+               rc = SMC_CLC_DECL_PEERNOSMC;
+               goto out;
+       }
+       if (!smc_ism_is_v2_capable()) {
                ini->smcd_version &= ~SMC_V2;
+               rc = SMC_CLC_DECL_NOISM2SUPP;
                goto out;
        }
        pclc_v2_ext = smc_get_clc_v2_ext(pclc);
        if (!pclc_v2_ext) {
                ini->smcd_version &= ~SMC_V2;
+               rc = SMC_CLC_DECL_NOV2EXT;
                goto out;
        }
        pclc_smcd_v2_ext = smc_get_clc_smcd_v2_ext(pclc_v2_ext);
-       if (!pclc_smcd_v2_ext)
+       if (!pclc_smcd_v2_ext) {
                ini->smcd_version &= ~SMC_V2;
+               rc = SMC_CLC_DECL_NOV2DEXT;
+       }
 
 out:
-       if (!ini->smcd_version) {
-               if (pclc->hdr.typev1 == SMC_TYPE_B ||
-                   pclc->hdr.typev2 == SMC_TYPE_B)
-                       return SMC_CLC_DECL_NOSMCDEV;
-               if (pclc->hdr.typev1 == SMC_TYPE_D ||
-                   pclc->hdr.typev2 == SMC_TYPE_D)
-                       return SMC_CLC_DECL_NOSMCDDEV;
-               return SMC_CLC_DECL_NOSMCRDEV;
-       }
+       if (!ini->smcd_version)
+               return rc;
 
        return 0;
 }
@@ -1428,10 +1427,7 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
        /* Create send and receive buffers */
        rc = smc_buf_create(new_smc, true);
        if (rc) {
-               if (ini->first_contact_local)
-                       smc_lgr_cleanup_early(&new_smc->conn);
-               else
-                       smc_conn_free(&new_smc->conn);
+               smc_conn_abort(new_smc, ini->first_contact_local);
                return (rc == -ENOSPC) ? SMC_CLC_DECL_MAX_DMB :
                                         SMC_CLC_DECL_MEM;
        }
@@ -1474,6 +1470,12 @@ static void smc_check_ism_v2_match(struct smc_init_info *ini,
        }
 }
 
+static void smc_find_ism_store_rc(u32 rc, struct smc_init_info *ini)
+{
+       if (!ini->rc)
+               ini->rc = rc;
+}
+
 static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
                                        struct smc_clc_msg_proposal *pclc,
                                        struct smc_init_info *ini)
@@ -1484,7 +1486,7 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
        unsigned int matches = 0;
        u8 smcd_version;
        u8 *eid = NULL;
-       int i;
+       int i, rc;
 
        if (!(ini->smcd_version & SMC_V2) || !smcd_indicated(ini->smc_type_v2))
                goto not_found;
@@ -1493,8 +1495,10 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
        smc_v2_ext = smc_get_clc_v2_ext(pclc);
        smcd_v2_ext = smc_get_clc_smcd_v2_ext(smc_v2_ext);
        if (!smcd_v2_ext ||
-           !smc_v2_ext->hdr.flag.seid) /* no system EID support for SMCD */
+           !smc_v2_ext->hdr.flag.seid) { /* no system EID support for SMCD */
+               smc_find_ism_store_rc(SMC_CLC_DECL_NOSEID, ini);
                goto not_found;
+       }
 
        mutex_lock(&smcd_dev_list.mutex);
        if (pclc_smcd->ism.chid)
@@ -1526,9 +1530,12 @@ static void smc_find_ism_v2_device_serv(struct smc_sock *new_smc,
                ini->smcd_version = SMC_V2;
                ini->is_smcd = true;
                ini->ism_selected = i;
-               if (smc_listen_ism_init(new_smc, ini))
+               rc = smc_listen_ism_init(new_smc, ini);
+               if (rc) {
+                       smc_find_ism_store_rc(rc, ini);
                        /* try next active ISM device */
                        continue;
+               }
                return; /* matching and usable V2 ISM device found */
        }
        /* no V2 ISM device could be initialized */
@@ -1545,19 +1552,23 @@ static void smc_find_ism_v1_device_serv(struct smc_sock *new_smc,
                                        struct smc_init_info *ini)
 {
        struct smc_clc_msg_smcd *pclc_smcd = smc_get_clc_msg_smcd(pclc);
+       int rc = 0;
 
        /* check if ISM V1 is available */
        if (!(ini->smcd_version & SMC_V1) || !smcd_indicated(ini->smc_type_v1))
                goto not_found;
        ini->is_smcd = true; /* prepare ISM check */
        ini->ism_peer_gid[0] = ntohll(pclc_smcd->ism.gid);
-       if (smc_find_ism_device(new_smc, ini))
+       rc = smc_find_ism_device(new_smc, ini);
+       if (rc)
                goto not_found;
        ini->ism_selected = 0;
-       if (!smc_listen_ism_init(new_smc, ini))
+       rc = smc_listen_ism_init(new_smc, ini);
+       if (!rc)
                return;         /* V1 ISM device found */
 
 not_found:
+       smc_find_ism_store_rc(rc, ini);
        ini->ism_dev[0] = NULL;
        ini->is_smcd = false;
 }
@@ -1614,16 +1625,16 @@ static int smc_listen_find_device(struct smc_sock *new_smc,
                return 0;
 
        if (!(ini->smcd_version & SMC_V1))
-               return SMC_CLC_DECL_NOSMCDEV;
+               return ini->rc ?: SMC_CLC_DECL_NOSMCD2DEV;
 
        /* check for matching IP prefix and subnet length */
        rc = smc_listen_prfx_check(new_smc, pclc);
        if (rc)
-               return rc;
+               return ini->rc ?: rc;
 
        /* get vlan id from IP device */
        if (smc_vlan_by_tcpsk(new_smc->clcsock, ini))
-               return SMC_CLC_DECL_GETVLANERR;
+               return ini->rc ?: SMC_CLC_DECL_GETVLANERR;
 
        /* check for ISM device matching V1 proposed device */
        smc_find_ism_v1_device_serv(new_smc, pclc, ini);
@@ -1631,10 +1642,14 @@ static int smc_listen_find_device(struct smc_sock *new_smc,
                return 0;
 
        if (pclc->hdr.typev1 == SMC_TYPE_D)
-               return SMC_CLC_DECL_NOSMCDDEV; /* skip RDMA and decline */
+               /* skip RDMA and decline */
+               return ini->rc ?: SMC_CLC_DECL_NOSMCDDEV;
 
        /* check if RDMA is available */
-       return smc_find_rdma_v1_device_serv(new_smc, pclc, ini);
+       rc = smc_find_rdma_v1_device_serv(new_smc, pclc, ini);
+       smc_find_ism_store_rc(rc, ini);
+
+       return (!rc) ? 0 : ini->rc;
 }
 
 /* listen worker: finish RDMA setup */
@@ -1667,7 +1682,7 @@ static void smc_listen_work(struct work_struct *work)
 {
        struct smc_sock *new_smc = container_of(work, struct smc_sock,
                                                smc_listen_work);
-       u8 version = smc_ism_v2_capable ? SMC_V2 : SMC_V1;
+       u8 version = smc_ism_is_v2_capable() ? SMC_V2 : SMC_V1;
        struct socket *newclcsock = new_smc->clcsock;
        struct smc_clc_msg_accept_confirm *cclc;
        struct smc_clc_msg_proposal_area *buf;
@@ -2481,10 +2496,14 @@ static int __init smc_init(void)
        smc_ism_init();
        smc_clc_init();
 
-       rc = smc_pnet_init();
+       rc = smc_nl_init();
        if (rc)
                goto out_pernet_subsys;
 
+       rc = smc_pnet_init();
+       if (rc)
+               goto out_nl;
+
        rc = -ENOMEM;
        smc_hs_wq = alloc_workqueue("smc_hs_wq", 0, 0);
        if (!smc_hs_wq)
@@ -2555,6 +2574,8 @@ out_alloc_hs_wq:
        destroy_workqueue(smc_hs_wq);
 out_pnet:
        smc_pnet_exit();
+out_nl:
+       smc_nl_exit();
 out_pernet_subsys:
        unregister_pernet_subsys(&smc_net_ops);
 
@@ -2572,6 +2593,7 @@ static void __exit smc_exit(void)
        proto_unregister(&smc_proto6);
        proto_unregister(&smc_proto);
        smc_pnet_exit();
+       smc_nl_exit();
        unregister_pernet_subsys(&smc_net_ops);
        rcu_barrier();
 }