net/smc: add SMC-D support in CLC messages
authorHans Wippel <hwippel@linux.ibm.com>
Thu, 28 Jun 2018 17:05:09 +0000 (19:05 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 30 Jun 2018 11:42:25 +0000 (20:42 +0900)
There are two types of SMC: SMC-R and SMC-D. These types are signaled
within the CLC messages during the CLC handshake. This patch adds
support for and checks of the SMC type.

Also, SMC-R and SMC-D need to exchange different information during the
CLC handshake. So, this patch extends the current message formats to
support the SMC-D header fields. The Proposal message can contain both
SMC-R and SMC-D information. The Accept and Confirm messages contain
either SMC-R or SMC-D information.

Signed-off-by: Hans Wippel <hwippel@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Suggested-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/smc/af_smc.c
net/smc/smc_clc.c
net/smc/smc_clc.h

index 8ce48799cf68d637d95f5ba655e0f3c693838b7c..20afa94be8bbf3f2891255b80bcb7e00d80d9ed7 100644 (file)
@@ -451,14 +451,14 @@ static int smc_check_rdma(struct smc_sock *smc, struct smc_ib_device **ibdev,
 }
 
 /* CLC handshake during connect */
-static int smc_connect_clc(struct smc_sock *smc,
+static int smc_connect_clc(struct smc_sock *smc, int smc_type,
                           struct smc_clc_msg_accept_confirm *aclc,
                           struct smc_ib_device *ibdev, u8 ibport)
 {
        int rc = 0;
 
        /* do inband token exchange */
-       rc = smc_clc_send_proposal(smc, ibdev, ibport);
+       rc = smc_clc_send_proposal(smc, smc_type, ibdev, ibport, NULL);
        if (rc)
                return rc;
        /* receive SMC Accept CLC message */
@@ -564,7 +564,7 @@ static int __smc_connect(struct smc_sock *smc)
                return smc_connect_decline_fallback(smc, SMC_CLC_DECL_CNFERR);
 
        /* perform CLC handshake */
-       rc = smc_connect_clc(smc, &aclc, ibdev, ibport);
+       rc = smc_connect_clc(smc, SMC_TYPE_R, &aclc, ibdev, ibport);
        if (rc)
                return smc_connect_decline_fallback(smc, rc);
 
@@ -1008,7 +1008,8 @@ static void smc_listen_work(struct work_struct *work)
        smc_tx_init(new_smc);
 
        /* check if RDMA is available */
-       if (smc_check_rdma(new_smc, &ibdev, &ibport) ||
+       if ((pclc->hdr.path != SMC_TYPE_R && pclc->hdr.path != SMC_TYPE_B) ||
+           smc_check_rdma(new_smc, &ibdev, &ibport) ||
            smc_listen_rdma_check(new_smc, pclc) ||
            smc_listen_rdma_init(new_smc, pclc, ibdev, ibport,
                                 &local_contact) ||
index 717449b1da0b73d924488d43cd04ed0871607d1b..038d70ef78923c054283e3a8cef48cbc628335aa 100644 (file)
 #include "smc_core.h"
 #include "smc_clc.h"
 #include "smc_ib.h"
+#include "smc_ism.h"
+
+#define SMCR_CLC_ACCEPT_CONFIRM_LEN 68
+#define SMCD_CLC_ACCEPT_CONFIRM_LEN 48
 
 /* eye catcher "SMCR" EBCDIC for CLC messages */
 static const char SMC_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xd9'};
+/* eye catcher "SMCD" EBCDIC for CLC messages */
+static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
 
 /* check if received message has a correct header length and contains valid
  * heading and trailing eyecatchers
@@ -38,10 +44,14 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm)
        struct smc_clc_msg_decline *dclc;
        struct smc_clc_msg_trail *trl;
 
-       if (memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)))
+       if (memcmp(clcm->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
+           memcmp(clcm->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
                return false;
        switch (clcm->type) {
        case SMC_CLC_PROPOSAL:
+               if (clcm->path != SMC_TYPE_R && clcm->path != SMC_TYPE_D &&
+                   clcm->path != SMC_TYPE_B)
+                       return false;
                pclc = (struct smc_clc_msg_proposal *)clcm;
                pclc_prfx = smc_clc_proposal_get_prefix(pclc);
                if (ntohs(pclc->hdr.length) !=
@@ -56,10 +66,16 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm)
                break;
        case SMC_CLC_ACCEPT:
        case SMC_CLC_CONFIRM:
+               if (clcm->path != SMC_TYPE_R && clcm->path != SMC_TYPE_D)
+                       return false;
                clc = (struct smc_clc_msg_accept_confirm *)clcm;
-               if (ntohs(clc->hdr.length) != sizeof(*clc))
+               if ((clcm->path == SMC_TYPE_R &&
+                    ntohs(clc->hdr.length) != SMCR_CLC_ACCEPT_CONFIRM_LEN) ||
+                   (clcm->path == SMC_TYPE_D &&
+                    ntohs(clc->hdr.length) != SMCD_CLC_ACCEPT_CONFIRM_LEN))
                        return false;
-               trl = &clc->trl;
+               trl = (struct smc_clc_msg_trail *)
+                       ((u8 *)clc + ntohs(clc->hdr.length) - sizeof(*trl));
                break;
        case SMC_CLC_DECLINE:
                dclc = (struct smc_clc_msg_decline *)clcm;
@@ -70,7 +86,8 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm)
        default:
                return false;
        }
-       if (memcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)))
+       if (memcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
+           memcmp(trl->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
                return false;
        return true;
 }
@@ -295,6 +312,9 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
        datlen = ntohs(clcm->length);
        if ((len < sizeof(struct smc_clc_msg_hdr)) ||
            (datlen > buflen) ||
+           (clcm->version != SMC_CLC_V1) ||
+           (clcm->path != SMC_TYPE_R && clcm->path != SMC_TYPE_D &&
+            clcm->path != SMC_TYPE_B) ||
            ((clcm->type != SMC_CLC_DECLINE) &&
             (clcm->type != expected_type))) {
                smc->sk.sk_err = EPROTO;
@@ -356,17 +376,18 @@ int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info)
 }
 
 /* send CLC PROPOSAL message across internal TCP socket */
-int smc_clc_send_proposal(struct smc_sock *smc,
-                         struct smc_ib_device *smcibdev,
-                         u8 ibport)
+int smc_clc_send_proposal(struct smc_sock *smc, int smc_type,
+                         struct smc_ib_device *ibdev, u8 ibport,
+                         struct smcd_dev *ismdev)
 {
        struct smc_clc_ipv6_prefix ipv6_prfx[SMC_CLC_MAX_V6_PREFIX];
        struct smc_clc_msg_proposal_prefix pclc_prfx;
+       struct smc_clc_msg_smcd pclc_smcd;
        struct smc_clc_msg_proposal pclc;
        struct smc_clc_msg_trail trl;
        int len, i, plen, rc;
        int reason_code = 0;
-       struct kvec vec[4];
+       struct kvec vec[5];
        struct msghdr msg;
 
        /* retrieve ip prefixes for CLC proposal msg */
@@ -381,18 +402,34 @@ int smc_clc_send_proposal(struct smc_sock *smc,
        memset(&pclc, 0, sizeof(pclc));
        memcpy(pclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
        pclc.hdr.type = SMC_CLC_PROPOSAL;
-       pclc.hdr.length = htons(plen);
        pclc.hdr.version = SMC_CLC_V1;          /* SMC version */
-       memcpy(pclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
-       memcpy(&pclc.lcl.gid, &smcibdev->gid[ibport - 1], SMC_GID_SIZE);
-       memcpy(&pclc.lcl.mac, &smcibdev->mac[ibport - 1], ETH_ALEN);
-       pclc.iparea_offset = htons(0);
+       pclc.hdr.path = smc_type;
+       if (smc_type == SMC_TYPE_R || smc_type == SMC_TYPE_B) {
+               /* add SMC-R specifics */
+               memcpy(pclc.lcl.id_for_peer, local_systemid,
+                      sizeof(local_systemid));
+               memcpy(&pclc.lcl.gid, &ibdev->gid[ibport - 1], SMC_GID_SIZE);
+               memcpy(&pclc.lcl.mac, &ibdev->mac[ibport - 1], ETH_ALEN);
+               pclc.iparea_offset = htons(0);
+       }
+       if (smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B) {
+               /* add SMC-D specifics */
+               memset(&pclc_smcd, 0, sizeof(pclc_smcd));
+               plen += sizeof(pclc_smcd);
+               pclc.iparea_offset = htons(SMC_CLC_PROPOSAL_MAX_OFFSET);
+               pclc_smcd.gid = ismdev->local_gid;
+       }
+       pclc.hdr.length = htons(plen);
 
        memcpy(trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
        memset(&msg, 0, sizeof(msg));
        i = 0;
        vec[i].iov_base = &pclc;
        vec[i++].iov_len = sizeof(pclc);
+       if (smc_type == SMC_TYPE_D || smc_type == SMC_TYPE_B) {
+               vec[i].iov_base = &pclc_smcd;
+               vec[i++].iov_len = sizeof(pclc_smcd);
+       }
        vec[i].iov_base = &pclc_prfx;
        vec[i++].iov_len = sizeof(pclc_prfx);
        if (pclc_prfx.ipv6_prefixes_cnt > 0) {
@@ -428,35 +465,56 @@ int smc_clc_send_confirm(struct smc_sock *smc)
        struct kvec vec;
        int len;
 
-       link = &conn->lgr->lnk[SMC_SINGLE_LINK];
        /* send SMC Confirm CLC msg */
        memset(&cclc, 0, sizeof(cclc));
-       memcpy(cclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
        cclc.hdr.type = SMC_CLC_CONFIRM;
-       cclc.hdr.length = htons(sizeof(cclc));
        cclc.hdr.version = SMC_CLC_V1;          /* SMC version */
-       memcpy(cclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
-       memcpy(&cclc.lcl.gid, &link->smcibdev->gid[link->ibport - 1],
-              SMC_GID_SIZE);
-       memcpy(&cclc.lcl.mac, &link->smcibdev->mac[link->ibport - 1], ETH_ALEN);
-       hton24(cclc.qpn, link->roce_qp->qp_num);
-       cclc.rmb_rkey =
-               htonl(conn->rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
-       cclc.rmbe_idx = 1; /* for now: 1 RMB = 1 RMBE */
-       cclc.rmbe_alert_token = htonl(conn->alert_token_local);
-       cclc.qp_mtu = min(link->path_mtu, link->peer_mtu);
-       cclc.rmbe_size = conn->rmbe_size_short;
-       cclc.rmb_dma_addr = cpu_to_be64(
-               (u64)sg_dma_address(conn->rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
-       hton24(cclc.psn, link->psn_initial);
-
-       memcpy(cclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
+       if (smc->conn.lgr->is_smcd) {
+               /* SMC-D specific settings */
+               memcpy(cclc.hdr.eyecatcher, SMCD_EYECATCHER,
+                      sizeof(SMCD_EYECATCHER));
+               cclc.hdr.path = SMC_TYPE_D;
+               cclc.hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
+               cclc.gid = conn->lgr->smcd->local_gid;
+               cclc.token = conn->rmb_desc->token;
+               cclc.dmbe_size = conn->rmbe_size_short;
+               cclc.dmbe_idx = 0;
+               memcpy(&cclc.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
+               memcpy(cclc.smcd_trl.eyecatcher, SMCD_EYECATCHER,
+                      sizeof(SMCD_EYECATCHER));
+       } else {
+               /* SMC-R specific settings */
+               link = &conn->lgr->lnk[SMC_SINGLE_LINK];
+               memcpy(cclc.hdr.eyecatcher, SMC_EYECATCHER,
+                      sizeof(SMC_EYECATCHER));
+               cclc.hdr.path = SMC_TYPE_R;
+               cclc.hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
+               memcpy(cclc.lcl.id_for_peer, local_systemid,
+                      sizeof(local_systemid));
+               memcpy(&cclc.lcl.gid, &link->smcibdev->gid[link->ibport - 1],
+                      SMC_GID_SIZE);
+               memcpy(&cclc.lcl.mac, &link->smcibdev->mac[link->ibport - 1],
+                      ETH_ALEN);
+               hton24(cclc.qpn, link->roce_qp->qp_num);
+               cclc.rmb_rkey =
+                       htonl(conn->rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
+               cclc.rmbe_idx = 1; /* for now: 1 RMB = 1 RMBE */
+               cclc.rmbe_alert_token = htonl(conn->alert_token_local);
+               cclc.qp_mtu = min(link->path_mtu, link->peer_mtu);
+               cclc.rmbe_size = conn->rmbe_size_short;
+               cclc.rmb_dma_addr = cpu_to_be64((u64)sg_dma_address
+                               (conn->rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
+               hton24(cclc.psn, link->psn_initial);
+               memcpy(cclc.smcr_trl.eyecatcher, SMC_EYECATCHER,
+                      sizeof(SMC_EYECATCHER));
+       }
 
        memset(&msg, 0, sizeof(msg));
        vec.iov_base = &cclc;
-       vec.iov_len = sizeof(cclc);
-       len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1, sizeof(cclc));
-       if (len < sizeof(cclc)) {
+       vec.iov_len = ntohs(cclc.hdr.length);
+       len = kernel_sendmsg(smc->clcsock, &msg, &vec, 1,
+                            ntohs(cclc.hdr.length));
+       if (len < ntohs(cclc.hdr.length)) {
                if (len >= 0) {
                        reason_code = -ENETUNREACH;
                        smc->sk.sk_err = -reason_code;
@@ -479,35 +537,58 @@ int smc_clc_send_accept(struct smc_sock *new_smc, int srv_first_contact)
        int rc = 0;
        int len;
 
-       link = &conn->lgr->lnk[SMC_SINGLE_LINK];
        memset(&aclc, 0, sizeof(aclc));
-       memcpy(aclc.hdr.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
        aclc.hdr.type = SMC_CLC_ACCEPT;
-       aclc.hdr.length = htons(sizeof(aclc));
        aclc.hdr.version = SMC_CLC_V1;          /* SMC version */
        if (srv_first_contact)
                aclc.hdr.flag = 1;
-       memcpy(aclc.lcl.id_for_peer, local_systemid, sizeof(local_systemid));
-       memcpy(&aclc.lcl.gid, &link->smcibdev->gid[link->ibport - 1],
-              SMC_GID_SIZE);
-       memcpy(&aclc.lcl.mac, link->smcibdev->mac[link->ibport - 1], ETH_ALEN);
-       hton24(aclc.qpn, link->roce_qp->qp_num);
-       aclc.rmb_rkey =
-               htonl(conn->rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
-       aclc.rmbe_idx = 1;                      /* as long as 1 RMB = 1 RMBE */
-       aclc.rmbe_alert_token = htonl(conn->alert_token_local);
-       aclc.qp_mtu = link->path_mtu;
-       aclc.rmbe_size = conn->rmbe_size_short,
-       aclc.rmb_dma_addr = cpu_to_be64(
-               (u64)sg_dma_address(conn->rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
-       hton24(aclc.psn, link->psn_initial);
-       memcpy(aclc.trl.eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER));
+
+       if (new_smc->conn.lgr->is_smcd) {
+               /* SMC-D specific settings */
+               aclc.hdr.length = htons(SMCD_CLC_ACCEPT_CONFIRM_LEN);
+               memcpy(aclc.hdr.eyecatcher, SMCD_EYECATCHER,
+                      sizeof(SMCD_EYECATCHER));
+               aclc.hdr.path = SMC_TYPE_D;
+               aclc.gid = conn->lgr->smcd->local_gid;
+               aclc.token = conn->rmb_desc->token;
+               aclc.dmbe_size = conn->rmbe_size_short;
+               aclc.dmbe_idx = 0;
+               memcpy(&aclc.linkid, conn->lgr->id, SMC_LGR_ID_SIZE);
+               memcpy(aclc.smcd_trl.eyecatcher, SMCD_EYECATCHER,
+                      sizeof(SMCD_EYECATCHER));
+       } else {
+               /* SMC-R specific settings */
+               aclc.hdr.length = htons(SMCR_CLC_ACCEPT_CONFIRM_LEN);
+               memcpy(aclc.hdr.eyecatcher, SMC_EYECATCHER,
+                      sizeof(SMC_EYECATCHER));
+               aclc.hdr.path = SMC_TYPE_R;
+               link = &conn->lgr->lnk[SMC_SINGLE_LINK];
+               memcpy(aclc.lcl.id_for_peer, local_systemid,
+                      sizeof(local_systemid));
+               memcpy(&aclc.lcl.gid, &link->smcibdev->gid[link->ibport - 1],
+                      SMC_GID_SIZE);
+               memcpy(&aclc.lcl.mac, link->smcibdev->mac[link->ibport - 1],
+                      ETH_ALEN);
+               hton24(aclc.qpn, link->roce_qp->qp_num);
+               aclc.rmb_rkey =
+                       htonl(conn->rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
+               aclc.rmbe_idx = 1;              /* as long as 1 RMB = 1 RMBE */
+               aclc.rmbe_alert_token = htonl(conn->alert_token_local);
+               aclc.qp_mtu = link->path_mtu;
+               aclc.rmbe_size = conn->rmbe_size_short,
+               aclc.rmb_dma_addr = cpu_to_be64((u64)sg_dma_address
+                               (conn->rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
+               hton24(aclc.psn, link->psn_initial);
+               memcpy(aclc.smcr_trl.eyecatcher, SMC_EYECATCHER,
+                      sizeof(SMC_EYECATCHER));
+       }
 
        memset(&msg, 0, sizeof(msg));
        vec.iov_base = &aclc;
-       vec.iov_len = sizeof(aclc);
-       len = kernel_sendmsg(new_smc->clcsock, &msg, &vec, 1, sizeof(aclc));
-       if (len < sizeof(aclc)) {
+       vec.iov_len = ntohs(aclc.hdr.length);
+       len = kernel_sendmsg(new_smc->clcsock, &msg, &vec, 1,
+                            ntohs(aclc.hdr.length));
+       if (len < ntohs(aclc.hdr.length)) {
                if (len >= 0)
                        new_smc->sk.sk_err = EPROTO;
                else
index 41ff9ea96139ced3b2a6760af2f310d40e6f58a7..100e988ad1a854941939b830757bbb407ab96f89 100644 (file)
@@ -23,6 +23,9 @@
 #define SMC_CLC_DECLINE                0x04
 
 #define SMC_CLC_V1             0x1             /* SMC version                */
+#define SMC_TYPE_R             0               /* SMC-R only                 */
+#define SMC_TYPE_D             1               /* SMC-D only                 */
+#define SMC_TYPE_B             3               /* SMC-R and SMC-D            */
 #define CLC_WAIT_TIME          (6 * HZ)        /* max. wait time on clcsock  */
 #define SMC_CLC_DECL_MEM       0x01010000  /* insufficient memory resources  */
 #define SMC_CLC_DECL_TIMEOUT   0x02000000  /* timeout                        */
@@ -42,9 +45,11 @@ struct smc_clc_msg_hdr {     /* header1 of clc messages */
 #if defined(__BIG_ENDIAN_BITFIELD)
        u8 version : 4,
           flag    : 1,
-          rsvd    : 3;
+          rsvd    : 1,
+          path    : 2;
 #elif defined(__LITTLE_ENDIAN_BITFIELD)
-       u8 rsvd    : 3,
+       u8 path    : 2,
+          rsvd    : 1,
           flag    : 1,
           version : 4;
 #endif
@@ -77,6 +82,11 @@ struct smc_clc_msg_proposal_prefix { /* prefix part of clc proposal message*/
        u8 ipv6_prefixes_cnt;   /* number of IPv6 prefixes in prefix array */
 } __aligned(4);
 
+struct smc_clc_msg_smcd {      /* SMC-D GID information */
+       u64 gid;                /* ISM GID of requestor */
+       u8 res[32];
+};
+
 struct smc_clc_msg_proposal {  /* clc proposal message sent by Linux */
        struct smc_clc_msg_hdr hdr;
        struct smc_clc_msg_local lcl;
@@ -94,23 +104,45 @@ struct smc_clc_msg_proposal {      /* clc proposal message sent by Linux */
 
 struct smc_clc_msg_accept_confirm {    /* clc accept / confirm message */
        struct smc_clc_msg_hdr hdr;
-       struct smc_clc_msg_local lcl;
-       u8 qpn[3];              /* QP number */
-       __be32 rmb_rkey;        /* RMB rkey */
-       u8 rmbe_idx;            /* Index of RMBE in RMB */
-       __be32 rmbe_alert_token;/* unique connection id */
+       union {
+               struct { /* SMC-R */
+                       struct smc_clc_msg_local lcl;
+                       u8 qpn[3];              /* QP number */
+                       __be32 rmb_rkey;        /* RMB rkey */
+                       u8 rmbe_idx;            /* Index of RMBE in RMB */
+                       __be32 rmbe_alert_token;/* unique connection id */
 #if defined(__BIG_ENDIAN_BITFIELD)
-       u8 rmbe_size : 4,       /* RMBE buf size (compressed notation) */
-          qp_mtu   : 4;        /* QP mtu */
+                       u8 rmbe_size : 4,       /* buf size (compressed) */
+                          qp_mtu   : 4;        /* QP mtu */
 #elif defined(__LITTLE_ENDIAN_BITFIELD)
-       u8 qp_mtu   : 4,
-          rmbe_size : 4;
+                       u8 qp_mtu   : 4,
+                          rmbe_size : 4;
 #endif
-       u8 reserved;
-       __be64 rmb_dma_addr;    /* RMB virtual address */
-       u8 reserved2;
-       u8 psn[3];              /* initial packet sequence number */
-       struct smc_clc_msg_trail trl; /* eye catcher "SMCR" EBCDIC */
+                       u8 reserved;
+                       __be64 rmb_dma_addr;    /* RMB virtual address */
+                       u8 reserved2;
+                       u8 psn[3];              /* packet sequence number */
+                       struct smc_clc_msg_trail smcr_trl;
+                                               /* eye catcher "SMCR" EBCDIC */
+               } __packed;
+               struct { /* SMC-D */
+                       u64 gid;                /* Sender GID */
+                       u64 token;              /* DMB token */
+                       u8 dmbe_idx;            /* DMBE index */
+#if defined(__BIG_ENDIAN_BITFIELD)
+                       u8 dmbe_size : 4,       /* buf size (compressed) */
+                          reserved3 : 4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+                       u8 reserved3 : 4,
+                          dmbe_size : 4;
+#endif
+                       u16 reserved4;
+                       u32 linkid;             /* Link identifier */
+                       u32 reserved5[3];
+                       struct smc_clc_msg_trail smcd_trl;
+                                               /* eye catcher "SMCD" EBCDIC */
+               } __packed;
+       };
 } __packed;                    /* format defined in RFC7609 */
 
 struct smc_clc_msg_decline {   /* clc decline message */
@@ -129,13 +161,26 @@ smc_clc_proposal_get_prefix(struct smc_clc_msg_proposal *pclc)
               ((u8 *)pclc + sizeof(*pclc) + ntohs(pclc->iparea_offset));
 }
 
+/* get SMC-D info from proposal message */
+static inline struct smc_clc_msg_smcd *
+smc_get_clc_msg_smcd(struct smc_clc_msg_proposal *prop)
+{
+       if (ntohs(prop->iparea_offset) != sizeof(struct smc_clc_msg_smcd))
+               return NULL;
+
+       return (struct smc_clc_msg_smcd *)(prop + 1);
+}
+
+struct smcd_dev;
+
 int smc_clc_prfx_match(struct socket *clcsock,
                       struct smc_clc_msg_proposal_prefix *prop);
 int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
                     u8 expected_type);
 int smc_clc_send_decline(struct smc_sock *smc, u32 peer_diag_info);
-int smc_clc_send_proposal(struct smc_sock *smc, struct smc_ib_device *smcibdev,
-                         u8 ibport);
+int smc_clc_send_proposal(struct smc_sock *smc, int smc_type,
+                         struct smc_ib_device *smcibdev, u8 ibport,
+                         struct smcd_dev *ismdev);
 int smc_clc_send_confirm(struct smc_sock *smc);
 int smc_clc_send_accept(struct smc_sock *smc, int srv_first_contact);