1 // SPDX-License-Identifier: GPL-2.0
3 * Shared Memory Communications over RDMA (SMC-R) and RoCE
5 * Link Layer Control (LLC)
7 * For now, we only support the necessary "confirm link" functionality
8 * which happens for the first RoCE link after successful CLC handshake.
10 * Copyright IBM Corp. 2016
12 * Author(s): Klaus Wacker <Klaus.Wacker@de.ibm.com>
13 * Ursula Braun <ubraun@linux.vnet.ibm.com>
17 #include <rdma/ib_verbs.h>
24 /********************************** send *************************************/
26 struct smc_llc_tx_pend
{
29 /* handler for send/transmission completion of an LLC msg */
30 static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv
*pend
,
31 struct smc_link
*link
,
32 enum ib_wc_status wc_status
)
34 /* future work: handle wc_status error for recovery and failover */
38 * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits
39 * @link: Pointer to SMC link used for sending LLC control message.
40 * @wr_buf: Out variable returning pointer to work request payload buffer.
41 * @pend: Out variable returning pointer to private pending WR tracking.
42 * It's the context the transmit complete handler will get.
44 * Reserves and pre-fills an entry for a pending work request send/tx.
45 * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx.
46 * Can sleep due to smc_get_ctrl_buf (if not in softirq context).
48 * Return: 0 on success, otherwise an error value.
50 static int smc_llc_add_pending_send(struct smc_link
*link
,
51 struct smc_wr_buf
**wr_buf
,
52 struct smc_wr_tx_pend_priv
**pend
)
56 rc
= smc_wr_tx_get_free_slot(link
, smc_llc_tx_handler
, wr_buf
, pend
);
60 sizeof(union smc_llc_msg
) > SMC_WR_BUF_SIZE
,
61 "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)");
63 sizeof(union smc_llc_msg
) != SMC_WR_TX_SIZE
,
64 "must adapt SMC_WR_TX_SIZE to sizeof(struct smc_llc_msg); if not all smc_wr upper layer protocols use the same message size any more, must start to set link->wr_tx_sges[i].length on each individual smc_wr_tx_send()");
66 sizeof(struct smc_llc_tx_pend
) > SMC_WR_TX_PEND_PRIV_SIZE
,
67 "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)");
71 /* high-level API to send LLC confirm link */
72 int smc_llc_send_confirm_link(struct smc_link
*link
, u8 mac
[],
74 enum smc_llc_reqresp reqresp
)
76 struct smc_link_group
*lgr
= container_of(link
, struct smc_link_group
,
77 lnk
[SMC_SINGLE_LINK
]);
78 struct smc_llc_msg_confirm_link
*confllc
;
79 struct smc_wr_tx_pend_priv
*pend
;
80 struct smc_wr_buf
*wr_buf
;
83 rc
= smc_llc_add_pending_send(link
, &wr_buf
, &pend
);
86 confllc
= (struct smc_llc_msg_confirm_link
*)wr_buf
;
87 memset(confllc
, 0, sizeof(*confllc
));
88 confllc
->hd
.common
.type
= SMC_LLC_CONFIRM_LINK
;
89 confllc
->hd
.length
= sizeof(struct smc_llc_msg_confirm_link
);
90 if (reqresp
== SMC_LLC_RESP
)
91 confllc
->hd
.flags
|= SMC_LLC_FLAG_RESP
;
92 memcpy(confllc
->sender_mac
, mac
, ETH_ALEN
);
93 memcpy(confllc
->sender_gid
, gid
, SMC_GID_SIZE
);
94 hton24(confllc
->sender_qp_num
, link
->roce_qp
->qp_num
);
95 /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */
96 memcpy(confllc
->link_uid
, lgr
->id
, SMC_LGR_ID_SIZE
);
97 confllc
->max_links
= SMC_LINKS_PER_LGR_MAX
;
98 /* send llc message */
99 rc
= smc_wr_tx_send(link
, pend
);
103 /********************************* receive ***********************************/
105 static void smc_llc_rx_confirm_link(struct smc_link
*link
,
106 struct smc_llc_msg_confirm_link
*llc
)
108 struct smc_link_group
*lgr
;
110 lgr
= container_of(link
, struct smc_link_group
, lnk
[SMC_SINGLE_LINK
]);
111 if (llc
->hd
.flags
& SMC_LLC_FLAG_RESP
) {
112 if (lgr
->role
== SMC_SERV
)
113 complete(&link
->llc_confirm_resp
);
115 if (lgr
->role
== SMC_CLNT
) {
116 link
->link_id
= llc
->link_num
;
117 complete(&link
->llc_confirm
);
122 static void smc_llc_rx_handler(struct ib_wc
*wc
, void *buf
)
124 struct smc_link
*link
= (struct smc_link
*)wc
->qp
->qp_context
;
125 union smc_llc_msg
*llc
= buf
;
127 if (wc
->byte_len
< sizeof(*llc
))
128 return; /* short message */
129 if (llc
->raw
.hdr
.length
!= sizeof(*llc
))
130 return; /* invalid message */
131 if (llc
->raw
.hdr
.common
.type
== SMC_LLC_CONFIRM_LINK
)
132 smc_llc_rx_confirm_link(link
, &llc
->confirm_link
);
135 /***************************** init, exit, misc ******************************/
137 static struct smc_wr_rx_handler smc_llc_rx_handlers
[] = {
139 .handler
= smc_llc_rx_handler
,
140 .type
= SMC_LLC_CONFIRM_LINK
147 int __init
smc_llc_init(void)
149 struct smc_wr_rx_handler
*handler
;
152 for (handler
= smc_llc_rx_handlers
; handler
->handler
; handler
++) {
153 INIT_HLIST_NODE(&handler
->list
);
154 rc
= smc_wr_rx_register_handler(handler
);