Blob Blame History Raw
From: Stefan Raspl <raspl@linux.ibm.com>
Subject: net/smc: add SMC-D support in CLC messages
Patch-mainline: v4.19-rc1
Git-commit: c758dfddc1b5b1c9b8c64e5e4bb9bf24b74f4a59
References: FATE#325698, LTC#167867, bsc#1113481

Summary:     net/smc: Add support for SMC-D
Description: Add support for SMC-D to the existing AF_SMC address family.
             Also includes the ISM device driver as required by SMC-D.

Upstream-Description:

             net/smc: add SMC-D support in CLC messages

             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>

Signed-off-by: Stefan Raspl <raspl@linux.ibm.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 net/smc/af_smc.c  |    9 +-
 net/smc/smc_clc.c |  193 ++++++++++++++++++++++++++++++++++++++----------------
 net/smc/smc_clc.h |   81 +++++++++++++++++-----
 3 files changed, 205 insertions(+), 78 deletions(-)

--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -464,14 +464,14 @@ static int smc_check_rdma(struct smc_soc
 }
 
 /* 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 */
@@ -577,7 +577,7 @@ static int __smc_connect(struct smc_sock
 		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);
 
@@ -1067,7 +1067,8 @@ static void smc_listen_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) ||
--- a/net/smc/smc_clc.c
+++ b/net/smc/smc_clc.c
@@ -22,9 +22,15 @@
 #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
@@ -37,10 +43,14 @@ static bool smc_clc_msg_hdr_valid(struct
 	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) !=
@@ -55,10 +65,16 @@ static bool smc_clc_msg_hdr_valid(struct
 		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;
@@ -69,7 +85,8 @@ static bool smc_clc_msg_hdr_valid(struct
 	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 *sm
 	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
 }
 
 /* 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_soc
 	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
 	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
 	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
--- a/net/smc/smc_clc.h
+++ b/net/smc/smc_clc.h
@@ -22,6 +22,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                        */
@@ -41,9 +44,11 @@ struct smc_clc_msg_hdr {	/* header1 of c
 #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
@@ -76,6 +81,11 @@ struct smc_clc_msg_proposal_prefix {	/*
 	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;
@@ -93,23 +103,45 @@ struct smc_clc_msg_proposal {	/* clc pro
 
 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 */
@@ -128,13 +160,26 @@ smc_clc_proposal_get_prefix(struct smc_c
 	       ((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);