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 #define SMC_LLC_DATA_LEN 40
27 struct smc_wr_rx_hdr common;
33 struct smc_llc_msg_confirm_link { /* type 0x01 */
34 struct smc_llc_hdr hd;
35 u8 sender_mac[ETH_ALEN];
36 u8 sender_gid[SMC_GID_SIZE];
39 u8 link_uid[SMC_LGR_ID_SIZE];
44 struct smc_llc_msg_test_link { /* type 0x07 */
45 struct smc_llc_hdr hd;
50 struct smc_rmb_rtoken {
52 u8 num_rkeys; /* first rtoken byte of CONFIRM LINK msg */
53 /* is actually the num of rtokens, first */
54 /* rtoken is always for the current link */
55 u8 link_id; /* link id of the rtoken */
59 } __packed; /* format defined in RFC7609 */
61 #define SMC_LLC_RKEYS_PER_MSG 3
63 struct smc_llc_msg_confirm_rkey { /* type 0x06 */
64 struct smc_llc_hdr hd;
65 struct smc_rmb_rtoken rtoken[SMC_LLC_RKEYS_PER_MSG];
69 struct smc_llc_msg_confirm_rkey_cont { /* type 0x08 */
70 struct smc_llc_hdr hd;
72 struct smc_rmb_rtoken rtoken[SMC_LLC_RKEYS_PER_MSG];
75 #define SMC_LLC_DEL_RKEY_MAX 8
76 #define SMC_LLC_FLAG_RKEY_NEG 0x20
78 struct smc_llc_msg_delete_rkey { /* type 0x09 */
79 struct smc_llc_hdr hd;
88 struct smc_llc_msg_confirm_link confirm_link;
90 struct smc_llc_msg_confirm_rkey confirm_rkey;
91 struct smc_llc_msg_confirm_rkey_cont confirm_rkey_cont;
92 struct smc_llc_msg_delete_rkey delete_rkey;
94 struct smc_llc_msg_test_link test_link;
96 struct smc_llc_hdr hdr;
97 u8 data[SMC_LLC_DATA_LEN];
101 #define SMC_LLC_FLAG_RESP 0x80
103 /********************************** send *************************************/
105 struct smc_llc_tx_pend {
108 /* handler for send/transmission completion of an LLC msg */
109 static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv *pend,
110 struct smc_link *link,
111 enum ib_wc_status wc_status)
113 /* future work: handle wc_status error for recovery and failover */
117 * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits
118 * @link: Pointer to SMC link used for sending LLC control message.
119 * @wr_buf: Out variable returning pointer to work request payload buffer.
120 * @pend: Out variable returning pointer to private pending WR tracking.
121 * It's the context the transmit complete handler will get.
123 * Reserves and pre-fills an entry for a pending work request send/tx.
124 * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx.
125 * Can sleep due to smc_get_ctrl_buf (if not in softirq context).
127 * Return: 0 on success, otherwise an error value.
129 static int smc_llc_add_pending_send(struct smc_link *link,
130 struct smc_wr_buf **wr_buf,
131 struct smc_wr_tx_pend_priv **pend)
135 rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, pend);
139 sizeof(union smc_llc_msg) > SMC_WR_BUF_SIZE,
140 "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)");
142 sizeof(union smc_llc_msg) != SMC_WR_TX_SIZE,
143 "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()");
145 sizeof(struct smc_llc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE,
146 "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)");
150 /* high-level API to send LLC confirm link */
151 int smc_llc_send_confirm_link(struct smc_link *link, u8 mac[],
153 enum smc_llc_reqresp reqresp)
155 struct smc_link_group *lgr = container_of(link, struct smc_link_group,
156 lnk[SMC_SINGLE_LINK]);
157 struct smc_llc_msg_confirm_link *confllc;
158 struct smc_wr_tx_pend_priv *pend;
159 struct smc_wr_buf *wr_buf;
162 rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
165 confllc = (struct smc_llc_msg_confirm_link *)wr_buf;
166 memset(confllc, 0, sizeof(*confllc));
167 confllc->hd.common.type = SMC_LLC_CONFIRM_LINK;
168 confllc->hd.length = sizeof(struct smc_llc_msg_confirm_link);
169 if (reqresp == SMC_LLC_RESP)
170 confllc->hd.flags |= SMC_LLC_FLAG_RESP;
171 memcpy(confllc->sender_mac, mac, ETH_ALEN);
172 memcpy(confllc->sender_gid, gid, SMC_GID_SIZE);
173 hton24(confllc->sender_qp_num, link->roce_qp->qp_num);
174 /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */
175 memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE);
176 confllc->max_links = SMC_LINKS_PER_LGR_MAX;
177 /* send llc message */
178 rc = smc_wr_tx_send(link, pend);
182 /* send LLC test link request or response */
183 int smc_llc_send_test_link(struct smc_link *link, u8 user_data[16],
184 enum smc_llc_reqresp reqresp)
186 struct smc_llc_msg_test_link *testllc;
187 struct smc_wr_tx_pend_priv *pend;
188 struct smc_wr_buf *wr_buf;
191 rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
194 testllc = (struct smc_llc_msg_test_link *)wr_buf;
195 memset(testllc, 0, sizeof(*testllc));
196 testllc->hd.common.type = SMC_LLC_TEST_LINK;
197 testllc->hd.length = sizeof(struct smc_llc_msg_test_link);
198 if (reqresp == SMC_LLC_RESP)
199 testllc->hd.flags |= SMC_LLC_FLAG_RESP;
200 memcpy(testllc->user_data, user_data, sizeof(testllc->user_data));
201 /* send llc message */
202 rc = smc_wr_tx_send(link, pend);
206 /* send a prepared message */
207 static int smc_llc_send_message(struct smc_link *link, void *llcbuf, int llclen)
209 struct smc_wr_tx_pend_priv *pend;
210 struct smc_wr_buf *wr_buf;
213 rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
216 memcpy(wr_buf, llcbuf, llclen);
217 /* send llc message */
218 rc = smc_wr_tx_send(link, pend);
222 /********************************* receive ***********************************/
224 static void smc_llc_rx_confirm_link(struct smc_link *link,
225 struct smc_llc_msg_confirm_link *llc)
227 struct smc_link_group *lgr;
229 lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
230 if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
231 if (lgr->role == SMC_SERV)
232 complete(&link->llc_confirm_resp);
234 if (lgr->role == SMC_CLNT) {
235 link->link_id = llc->link_num;
236 complete(&link->llc_confirm);
241 static void smc_llc_rx_test_link(struct smc_link *link,
242 struct smc_llc_msg_test_link *llc)
244 if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
245 /* unused as long as we don't send this type of msg */
247 smc_llc_send_test_link(link, llc->user_data, SMC_LLC_RESP);
251 static void smc_llc_rx_confirm_rkey(struct smc_link *link,
252 struct smc_llc_msg_confirm_rkey *llc)
254 struct smc_link_group *lgr;
257 lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
259 if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
260 /* unused as long as we don't send this type of msg */
262 rc = smc_rtoken_add(lgr,
263 llc->rtoken[0].rmb_vaddr,
264 llc->rtoken[0].rmb_key);
266 /* ignore rtokens for other links, we have only one link */
268 llc->hd.flags |= SMC_LLC_FLAG_RESP;
270 llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG;
271 smc_llc_send_message(link, (void *)llc, sizeof(*llc));
275 static void smc_llc_rx_confirm_rkey_cont(struct smc_link *link,
276 struct smc_llc_msg_confirm_rkey_cont *llc)
278 if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
279 /* unused as long as we don't send this type of msg */
281 /* ignore rtokens for other links, we have only one link */
282 llc->hd.flags |= SMC_LLC_FLAG_RESP;
283 smc_llc_send_message(link, (void *)llc, sizeof(*llc));
287 static void smc_llc_rx_delete_rkey(struct smc_link *link,
288 struct smc_llc_msg_delete_rkey *llc)
290 struct smc_link_group *lgr;
294 lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
296 if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
297 /* unused as long as we don't send this type of msg */
299 max = min_t(u8, llc->num_rkeys, SMC_LLC_DEL_RKEY_MAX);
300 for (i = 0; i < max; i++) {
301 if (smc_rtoken_delete(lgr, llc->rkey[i]))
302 err_mask |= 1 << (SMC_LLC_DEL_RKEY_MAX - 1 - i);
306 llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG;
307 llc->err_mask = err_mask;
310 llc->hd.flags |= SMC_LLC_FLAG_RESP;
311 smc_llc_send_message(link, (void *)llc, sizeof(*llc));
315 static void smc_llc_rx_handler(struct ib_wc *wc, void *buf)
317 struct smc_link *link = (struct smc_link *)wc->qp->qp_context;
318 union smc_llc_msg *llc = buf;
320 if (wc->byte_len < sizeof(*llc))
321 return; /* short message */
322 if (llc->raw.hdr.length != sizeof(*llc))
323 return; /* invalid message */
325 switch (llc->raw.hdr.common.type) {
326 case SMC_LLC_TEST_LINK:
327 smc_llc_rx_test_link(link, &llc->test_link);
329 case SMC_LLC_CONFIRM_LINK:
330 smc_llc_rx_confirm_link(link, &llc->confirm_link);
332 case SMC_LLC_CONFIRM_RKEY:
333 smc_llc_rx_confirm_rkey(link, &llc->confirm_rkey);
335 case SMC_LLC_CONFIRM_RKEY_CONT:
336 smc_llc_rx_confirm_rkey_cont(link, &llc->confirm_rkey_cont);
338 case SMC_LLC_DELETE_RKEY:
339 smc_llc_rx_delete_rkey(link, &llc->delete_rkey);
344 /***************************** init, exit, misc ******************************/
346 static struct smc_wr_rx_handler smc_llc_rx_handlers[] = {
348 .handler = smc_llc_rx_handler,
349 .type = SMC_LLC_CONFIRM_LINK
352 .handler = smc_llc_rx_handler,
353 .type = SMC_LLC_TEST_LINK
356 .handler = smc_llc_rx_handler,
357 .type = SMC_LLC_CONFIRM_RKEY
360 .handler = smc_llc_rx_handler,
361 .type = SMC_LLC_CONFIRM_RKEY_CONT
364 .handler = smc_llc_rx_handler,
365 .type = SMC_LLC_DELETE_RKEY
372 int __init smc_llc_init(void)
374 struct smc_wr_rx_handler *handler;
377 for (handler = smc_llc_rx_handlers; handler->handler; handler++) {
378 INIT_HLIST_NODE(&handler->list);
379 rc = smc_wr_rx_register_handler(handler);