2 * Shared Memory Communications over RDMA (SMC-R) and RoCE
4 * Link Layer Control (LLC)
6 * For now, we only support the necessary "confirm link" functionality
7 * which happens for the first RoCE link after successful CLC handshake.
9 * Copyright IBM Corp. 2016
11 * Author(s): Klaus Wacker <Klaus.Wacker@de.ibm.com>
12 * Ursula Braun <ubraun@linux.vnet.ibm.com>
16 #include <rdma/ib_verbs.h>
23 /********************************** send *************************************/
25 struct smc_llc_tx_pend
{
28 /* handler for send/transmission completion of an LLC msg */
29 static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv
*pend
,
30 struct smc_link
*link
,
31 enum ib_wc_status wc_status
)
33 /* future work: handle wc_status error for recovery and failover */
37 * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits
38 * @link: Pointer to SMC link used for sending LLC control message.
39 * @wr_buf: Out variable returning pointer to work request payload buffer.
40 * @pend: Out variable returning pointer to private pending WR tracking.
41 * It's the context the transmit complete handler will get.
43 * Reserves and pre-fills an entry for a pending work request send/tx.
44 * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx.
45 * Can sleep due to smc_get_ctrl_buf (if not in softirq context).
47 * Return: 0 on success, otherwise an error value.
49 static int smc_llc_add_pending_send(struct smc_link
*link
,
50 struct smc_wr_buf
**wr_buf
,
51 struct smc_wr_tx_pend_priv
**pend
)
55 rc
= smc_wr_tx_get_free_slot(link
, smc_llc_tx_handler
, wr_buf
, pend
);
59 sizeof(union smc_llc_msg
) > SMC_WR_BUF_SIZE
,
60 "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)");
62 sizeof(union smc_llc_msg
) != SMC_WR_TX_SIZE
,
63 "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()");
65 sizeof(struct smc_llc_tx_pend
) > SMC_WR_TX_PEND_PRIV_SIZE
,
66 "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)");
70 /* high-level API to send LLC confirm link */
71 int smc_llc_send_confirm_link(struct smc_link
*link
, u8 mac
[],
73 enum smc_llc_reqresp reqresp
)
75 struct smc_link_group
*lgr
= container_of(link
, struct smc_link_group
,
76 lnk
[SMC_SINGLE_LINK
]);
77 struct smc_llc_msg_confirm_link
*confllc
;
78 struct smc_wr_tx_pend_priv
*pend
;
79 struct smc_wr_buf
*wr_buf
;
82 rc
= smc_llc_add_pending_send(link
, &wr_buf
, &pend
);
85 confllc
= (struct smc_llc_msg_confirm_link
*)wr_buf
;
86 memset(confllc
, 0, sizeof(*confllc
));
87 confllc
->hd
.common
.type
= SMC_LLC_CONFIRM_LINK
;
88 confllc
->hd
.length
= sizeof(struct smc_llc_msg_confirm_link
);
89 if (reqresp
== SMC_LLC_RESP
)
90 confllc
->hd
.flags
|= SMC_LLC_FLAG_RESP
;
91 memcpy(confllc
->sender_mac
, mac
, ETH_ALEN
);
92 memcpy(confllc
->sender_gid
, gid
, SMC_GID_SIZE
);
93 hton24(confllc
->sender_qp_num
, link
->roce_qp
->qp_num
);
94 /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */
95 memcpy(confllc
->link_uid
, lgr
->id
, SMC_LGR_ID_SIZE
);
96 confllc
->max_links
= SMC_LINKS_PER_LGR_MAX
;
97 /* send llc message */
98 rc
= smc_wr_tx_send(link
, pend
);
102 /********************************* receive ***********************************/
104 static void smc_llc_rx_confirm_link(struct smc_link
*link
,
105 struct smc_llc_msg_confirm_link
*llc
)
107 struct smc_link_group
*lgr
;
109 lgr
= container_of(link
, struct smc_link_group
, lnk
[SMC_SINGLE_LINK
]);
110 if (llc
->hd
.flags
& SMC_LLC_FLAG_RESP
) {
111 if (lgr
->role
== SMC_SERV
)
112 complete(&link
->llc_confirm_resp
);
114 if (lgr
->role
== SMC_CLNT
) {
115 link
->link_id
= llc
->link_num
;
116 complete(&link
->llc_confirm
);
121 static void smc_llc_rx_handler(struct ib_wc
*wc
, void *buf
)
123 struct smc_link
*link
= (struct smc_link
*)wc
->qp
->qp_context
;
124 union smc_llc_msg
*llc
= buf
;
126 if (wc
->byte_len
< sizeof(*llc
))
127 return; /* short message */
128 if (llc
->raw
.hdr
.length
!= sizeof(*llc
))
129 return; /* invalid message */
130 if (llc
->raw
.hdr
.common
.type
== SMC_LLC_CONFIRM_LINK
)
131 smc_llc_rx_confirm_link(link
, &llc
->confirm_link
);
134 /***************************** init, exit, misc ******************************/
136 static struct smc_wr_rx_handler smc_llc_rx_handlers
[] = {
138 .handler
= smc_llc_rx_handler
,
139 .type
= SMC_LLC_CONFIRM_LINK
146 int __init
smc_llc_init(void)
148 struct smc_wr_rx_handler
*handler
;
151 for (handler
= smc_llc_rx_handlers
; handler
->handler
; handler
++) {
152 INIT_HLIST_NODE(&handler
->list
);
153 rc
= smc_wr_rx_register_handler(handler
);