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;
51 struct smc_llc_msg_confirm_link confirm_link;
52 struct smc_llc_msg_test_link test_link;
54 struct smc_llc_hdr hdr;
55 u8 data[SMC_LLC_DATA_LEN];
59 #define SMC_LLC_FLAG_RESP 0x80
61 /********************************** send *************************************/
63 struct smc_llc_tx_pend {
66 /* handler for send/transmission completion of an LLC msg */
67 static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv *pend,
68 struct smc_link *link,
69 enum ib_wc_status wc_status)
71 /* future work: handle wc_status error for recovery and failover */
75 * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits
76 * @link: Pointer to SMC link used for sending LLC control message.
77 * @wr_buf: Out variable returning pointer to work request payload buffer.
78 * @pend: Out variable returning pointer to private pending WR tracking.
79 * It's the context the transmit complete handler will get.
81 * Reserves and pre-fills an entry for a pending work request send/tx.
82 * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx.
83 * Can sleep due to smc_get_ctrl_buf (if not in softirq context).
85 * Return: 0 on success, otherwise an error value.
87 static int smc_llc_add_pending_send(struct smc_link *link,
88 struct smc_wr_buf **wr_buf,
89 struct smc_wr_tx_pend_priv **pend)
93 rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, pend);
97 sizeof(union smc_llc_msg) > SMC_WR_BUF_SIZE,
98 "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)");
100 sizeof(union smc_llc_msg) != SMC_WR_TX_SIZE,
101 "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()");
103 sizeof(struct smc_llc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE,
104 "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)");
108 /* high-level API to send LLC confirm link */
109 int smc_llc_send_confirm_link(struct smc_link *link, u8 mac[],
111 enum smc_llc_reqresp reqresp)
113 struct smc_link_group *lgr = container_of(link, struct smc_link_group,
114 lnk[SMC_SINGLE_LINK]);
115 struct smc_llc_msg_confirm_link *confllc;
116 struct smc_wr_tx_pend_priv *pend;
117 struct smc_wr_buf *wr_buf;
120 rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
123 confllc = (struct smc_llc_msg_confirm_link *)wr_buf;
124 memset(confllc, 0, sizeof(*confllc));
125 confllc->hd.common.type = SMC_LLC_CONFIRM_LINK;
126 confllc->hd.length = sizeof(struct smc_llc_msg_confirm_link);
127 if (reqresp == SMC_LLC_RESP)
128 confllc->hd.flags |= SMC_LLC_FLAG_RESP;
129 memcpy(confllc->sender_mac, mac, ETH_ALEN);
130 memcpy(confllc->sender_gid, gid, SMC_GID_SIZE);
131 hton24(confllc->sender_qp_num, link->roce_qp->qp_num);
132 /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */
133 memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE);
134 confllc->max_links = SMC_LINKS_PER_LGR_MAX;
135 /* send llc message */
136 rc = smc_wr_tx_send(link, pend);
140 /* send LLC test link request or response */
141 int smc_llc_send_test_link(struct smc_link *link, u8 user_data[16],
142 enum smc_llc_reqresp reqresp)
144 struct smc_llc_msg_test_link *testllc;
145 struct smc_wr_tx_pend_priv *pend;
146 struct smc_wr_buf *wr_buf;
149 rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
152 testllc = (struct smc_llc_msg_test_link *)wr_buf;
153 memset(testllc, 0, sizeof(*testllc));
154 testllc->hd.common.type = SMC_LLC_TEST_LINK;
155 testllc->hd.length = sizeof(struct smc_llc_msg_test_link);
156 if (reqresp == SMC_LLC_RESP)
157 testllc->hd.flags |= SMC_LLC_FLAG_RESP;
158 memcpy(testllc->user_data, user_data, sizeof(testllc->user_data));
159 /* send llc message */
160 rc = smc_wr_tx_send(link, pend);
164 /********************************* receive ***********************************/
166 static void smc_llc_rx_confirm_link(struct smc_link *link,
167 struct smc_llc_msg_confirm_link *llc)
169 struct smc_link_group *lgr;
171 lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
172 if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
173 if (lgr->role == SMC_SERV)
174 complete(&link->llc_confirm_resp);
176 if (lgr->role == SMC_CLNT) {
177 link->link_id = llc->link_num;
178 complete(&link->llc_confirm);
183 static void smc_llc_rx_test_link(struct smc_link *link,
184 struct smc_llc_msg_test_link *llc)
186 if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
187 /* unused as long as we don't send this type of msg */
189 smc_llc_send_test_link(link, llc->user_data, SMC_LLC_RESP);
193 static void smc_llc_rx_handler(struct ib_wc *wc, void *buf)
195 struct smc_link *link = (struct smc_link *)wc->qp->qp_context;
196 union smc_llc_msg *llc = buf;
198 if (wc->byte_len < sizeof(*llc))
199 return; /* short message */
200 if (llc->raw.hdr.length != sizeof(*llc))
201 return; /* invalid message */
203 switch (llc->raw.hdr.common.type) {
204 case SMC_LLC_TEST_LINK:
205 smc_llc_rx_test_link(link, &llc->test_link);
207 case SMC_LLC_CONFIRM_LINK:
208 smc_llc_rx_confirm_link(link, &llc->confirm_link);
213 /***************************** init, exit, misc ******************************/
215 static struct smc_wr_rx_handler smc_llc_rx_handlers[] = {
217 .handler = smc_llc_rx_handler,
218 .type = SMC_LLC_CONFIRM_LINK
221 .handler = smc_llc_rx_handler,
222 .type = SMC_LLC_TEST_LINK
229 int __init smc_llc_init(void)
231 struct smc_wr_rx_handler *handler;
234 for (handler = smc_llc_rx_handlers; handler->handler; handler++) {
235 INIT_HLIST_NODE(&handler->list);
236 rc = smc_wr_rx_register_handler(handler);