smc_llc.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Shared Memory Communications over RDMA (SMC-R) and RoCE
  4. *
  5. * Link Layer Control (LLC)
  6. *
  7. * Copyright IBM Corp. 2016
  8. *
  9. * Author(s): Klaus Wacker <Klaus.Wacker@de.ibm.com>
  10. * Ursula Braun <ubraun@linux.vnet.ibm.com>
  11. */
  12. #include <net/tcp.h>
  13. #include <rdma/ib_verbs.h>
  14. #include "smc.h"
  15. #include "smc_core.h"
  16. #include "smc_clc.h"
  17. #include "smc_llc.h"
  18. #define SMC_LLC_DATA_LEN 40
  19. struct smc_llc_hdr {
  20. struct smc_wr_rx_hdr common;
  21. u8 length; /* 44 */
  22. #if defined(__BIG_ENDIAN_BITFIELD)
  23. u8 reserved:4,
  24. add_link_rej_rsn:4;
  25. #elif defined(__LITTLE_ENDIAN_BITFIELD)
  26. u8 add_link_rej_rsn:4,
  27. reserved:4;
  28. #endif
  29. u8 flags;
  30. };
  31. #define SMC_LLC_FLAG_NO_RMBE_EYEC 0x03
  32. struct smc_llc_msg_confirm_link { /* type 0x01 */
  33. struct smc_llc_hdr hd;
  34. u8 sender_mac[ETH_ALEN];
  35. u8 sender_gid[SMC_GID_SIZE];
  36. u8 sender_qp_num[3];
  37. u8 link_num;
  38. u8 link_uid[SMC_LGR_ID_SIZE];
  39. u8 max_links;
  40. u8 reserved[9];
  41. };
  42. #define SMC_LLC_FLAG_ADD_LNK_REJ 0x40
  43. #define SMC_LLC_REJ_RSN_NO_ALT_PATH 1
  44. #define SMC_LLC_ADD_LNK_MAX_LINKS 2
  45. struct smc_llc_msg_add_link { /* type 0x02 */
  46. struct smc_llc_hdr hd;
  47. u8 sender_mac[ETH_ALEN];
  48. u8 reserved2[2];
  49. u8 sender_gid[SMC_GID_SIZE];
  50. u8 sender_qp_num[3];
  51. u8 link_num;
  52. u8 flags2; /* QP mtu */
  53. u8 initial_psn[3];
  54. u8 reserved[8];
  55. };
  56. #define SMC_LLC_FLAG_DEL_LINK_ALL 0x40
  57. #define SMC_LLC_FLAG_DEL_LINK_ORDERLY 0x20
  58. struct smc_llc_msg_del_link { /* type 0x04 */
  59. struct smc_llc_hdr hd;
  60. u8 link_num;
  61. __be32 reason;
  62. u8 reserved[35];
  63. } __packed; /* format defined in RFC7609 */
  64. struct smc_llc_msg_test_link { /* type 0x07 */
  65. struct smc_llc_hdr hd;
  66. u8 user_data[16];
  67. u8 reserved[24];
  68. };
  69. struct smc_rmb_rtoken {
  70. union {
  71. u8 num_rkeys; /* first rtoken byte of CONFIRM LINK msg */
  72. /* is actually the num of rtokens, first */
  73. /* rtoken is always for the current link */
  74. u8 link_id; /* link id of the rtoken */
  75. };
  76. __be32 rmb_key;
  77. __be64 rmb_vaddr;
  78. } __packed; /* format defined in RFC7609 */
  79. #define SMC_LLC_RKEYS_PER_MSG 3
  80. struct smc_llc_msg_confirm_rkey { /* type 0x06 */
  81. struct smc_llc_hdr hd;
  82. struct smc_rmb_rtoken rtoken[SMC_LLC_RKEYS_PER_MSG];
  83. u8 reserved;
  84. };
  85. struct smc_llc_msg_confirm_rkey_cont { /* type 0x08 */
  86. struct smc_llc_hdr hd;
  87. u8 num_rkeys;
  88. struct smc_rmb_rtoken rtoken[SMC_LLC_RKEYS_PER_MSG];
  89. };
  90. #define SMC_LLC_DEL_RKEY_MAX 8
  91. #define SMC_LLC_FLAG_RKEY_NEG 0x20
  92. struct smc_llc_msg_delete_rkey { /* type 0x09 */
  93. struct smc_llc_hdr hd;
  94. u8 num_rkeys;
  95. u8 err_mask;
  96. u8 reserved[2];
  97. __be32 rkey[8];
  98. u8 reserved2[4];
  99. };
  100. union smc_llc_msg {
  101. struct smc_llc_msg_confirm_link confirm_link;
  102. struct smc_llc_msg_add_link add_link;
  103. struct smc_llc_msg_del_link delete_link;
  104. struct smc_llc_msg_confirm_rkey confirm_rkey;
  105. struct smc_llc_msg_confirm_rkey_cont confirm_rkey_cont;
  106. struct smc_llc_msg_delete_rkey delete_rkey;
  107. struct smc_llc_msg_test_link test_link;
  108. struct {
  109. struct smc_llc_hdr hdr;
  110. u8 data[SMC_LLC_DATA_LEN];
  111. } raw;
  112. };
  113. #define SMC_LLC_FLAG_RESP 0x80
  114. /********************************** send *************************************/
  115. struct smc_llc_tx_pend {
  116. };
  117. /* handler for send/transmission completion of an LLC msg */
  118. static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv *pend,
  119. struct smc_link *link,
  120. enum ib_wc_status wc_status)
  121. {
  122. /* future work: handle wc_status error for recovery and failover */
  123. }
  124. /**
  125. * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits
  126. * @link: Pointer to SMC link used for sending LLC control message.
  127. * @wr_buf: Out variable returning pointer to work request payload buffer.
  128. * @pend: Out variable returning pointer to private pending WR tracking.
  129. * It's the context the transmit complete handler will get.
  130. *
  131. * Reserves and pre-fills an entry for a pending work request send/tx.
  132. * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx.
  133. * Can sleep due to smc_get_ctrl_buf (if not in softirq context).
  134. *
  135. * Return: 0 on success, otherwise an error value.
  136. */
  137. static int smc_llc_add_pending_send(struct smc_link *link,
  138. struct smc_wr_buf **wr_buf,
  139. struct smc_wr_tx_pend_priv **pend)
  140. {
  141. int rc;
  142. rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, pend);
  143. if (rc < 0)
  144. return rc;
  145. BUILD_BUG_ON_MSG(
  146. sizeof(union smc_llc_msg) > SMC_WR_BUF_SIZE,
  147. "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)");
  148. BUILD_BUG_ON_MSG(
  149. sizeof(union smc_llc_msg) != SMC_WR_TX_SIZE,
  150. "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()");
  151. BUILD_BUG_ON_MSG(
  152. sizeof(struct smc_llc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE,
  153. "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)");
  154. return 0;
  155. }
  156. /* high-level API to send LLC confirm link */
  157. int smc_llc_send_confirm_link(struct smc_link *link, u8 mac[],
  158. union ib_gid *gid,
  159. enum smc_llc_reqresp reqresp)
  160. {
  161. struct smc_link_group *lgr = container_of(link, struct smc_link_group,
  162. lnk[SMC_SINGLE_LINK]);
  163. struct smc_llc_msg_confirm_link *confllc;
  164. struct smc_wr_tx_pend_priv *pend;
  165. struct smc_wr_buf *wr_buf;
  166. int rc;
  167. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  168. if (rc)
  169. return rc;
  170. confllc = (struct smc_llc_msg_confirm_link *)wr_buf;
  171. memset(confllc, 0, sizeof(*confllc));
  172. confllc->hd.common.type = SMC_LLC_CONFIRM_LINK;
  173. confllc->hd.length = sizeof(struct smc_llc_msg_confirm_link);
  174. confllc->hd.flags |= SMC_LLC_FLAG_NO_RMBE_EYEC;
  175. if (reqresp == SMC_LLC_RESP)
  176. confllc->hd.flags |= SMC_LLC_FLAG_RESP;
  177. memcpy(confllc->sender_mac, mac, ETH_ALEN);
  178. memcpy(confllc->sender_gid, gid, SMC_GID_SIZE);
  179. hton24(confllc->sender_qp_num, link->roce_qp->qp_num);
  180. confllc->link_num = link->link_id;
  181. memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE);
  182. confllc->max_links = SMC_LLC_ADD_LNK_MAX_LINKS; /* enforce peer resp. */
  183. /* send llc message */
  184. rc = smc_wr_tx_send(link, pend);
  185. return rc;
  186. }
  187. /* send LLC confirm rkey request */
  188. static int smc_llc_send_confirm_rkey(struct smc_link *link,
  189. struct smc_buf_desc *rmb_desc)
  190. {
  191. struct smc_llc_msg_confirm_rkey *rkeyllc;
  192. struct smc_wr_tx_pend_priv *pend;
  193. struct smc_wr_buf *wr_buf;
  194. int rc;
  195. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  196. if (rc)
  197. return rc;
  198. rkeyllc = (struct smc_llc_msg_confirm_rkey *)wr_buf;
  199. memset(rkeyllc, 0, sizeof(*rkeyllc));
  200. rkeyllc->hd.common.type = SMC_LLC_CONFIRM_RKEY;
  201. rkeyllc->hd.length = sizeof(struct smc_llc_msg_confirm_rkey);
  202. rkeyllc->rtoken[0].rmb_key =
  203. htonl(rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
  204. rkeyllc->rtoken[0].rmb_vaddr = cpu_to_be64(
  205. (u64)sg_dma_address(rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
  206. /* send llc message */
  207. rc = smc_wr_tx_send(link, pend);
  208. return rc;
  209. }
  210. /* prepare an add link message */
  211. static void smc_llc_prep_add_link(struct smc_llc_msg_add_link *addllc,
  212. struct smc_link *link, u8 mac[],
  213. union ib_gid *gid,
  214. enum smc_llc_reqresp reqresp)
  215. {
  216. memset(addllc, 0, sizeof(*addllc));
  217. addllc->hd.common.type = SMC_LLC_ADD_LINK;
  218. addllc->hd.length = sizeof(struct smc_llc_msg_add_link);
  219. if (reqresp == SMC_LLC_RESP) {
  220. addllc->hd.flags |= SMC_LLC_FLAG_RESP;
  221. /* always reject more links for now */
  222. addllc->hd.flags |= SMC_LLC_FLAG_ADD_LNK_REJ;
  223. addllc->hd.add_link_rej_rsn = SMC_LLC_REJ_RSN_NO_ALT_PATH;
  224. }
  225. memcpy(addllc->sender_mac, mac, ETH_ALEN);
  226. memcpy(addllc->sender_gid, gid, SMC_GID_SIZE);
  227. }
  228. /* send ADD LINK request or response */
  229. int smc_llc_send_add_link(struct smc_link *link, u8 mac[],
  230. union ib_gid *gid,
  231. enum smc_llc_reqresp reqresp)
  232. {
  233. struct smc_llc_msg_add_link *addllc;
  234. struct smc_wr_tx_pend_priv *pend;
  235. struct smc_wr_buf *wr_buf;
  236. int rc;
  237. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  238. if (rc)
  239. return rc;
  240. addllc = (struct smc_llc_msg_add_link *)wr_buf;
  241. smc_llc_prep_add_link(addllc, link, mac, gid, reqresp);
  242. /* send llc message */
  243. rc = smc_wr_tx_send(link, pend);
  244. return rc;
  245. }
  246. /* prepare a delete link message */
  247. static void smc_llc_prep_delete_link(struct smc_llc_msg_del_link *delllc,
  248. struct smc_link *link,
  249. enum smc_llc_reqresp reqresp)
  250. {
  251. memset(delllc, 0, sizeof(*delllc));
  252. delllc->hd.common.type = SMC_LLC_DELETE_LINK;
  253. delllc->hd.length = sizeof(struct smc_llc_msg_add_link);
  254. if (reqresp == SMC_LLC_RESP)
  255. delllc->hd.flags |= SMC_LLC_FLAG_RESP;
  256. /* DEL_LINK_ALL because only 1 link supported */
  257. delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ALL;
  258. delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY;
  259. delllc->link_num = link->link_id;
  260. }
  261. /* send DELETE LINK request or response */
  262. int smc_llc_send_delete_link(struct smc_link *link,
  263. enum smc_llc_reqresp reqresp)
  264. {
  265. struct smc_llc_msg_del_link *delllc;
  266. struct smc_wr_tx_pend_priv *pend;
  267. struct smc_wr_buf *wr_buf;
  268. int rc;
  269. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  270. if (rc)
  271. return rc;
  272. delllc = (struct smc_llc_msg_del_link *)wr_buf;
  273. smc_llc_prep_delete_link(delllc, link, reqresp);
  274. /* send llc message */
  275. rc = smc_wr_tx_send(link, pend);
  276. return rc;
  277. }
  278. /* send LLC test link request */
  279. static int smc_llc_send_test_link(struct smc_link *link, u8 user_data[16])
  280. {
  281. struct smc_llc_msg_test_link *testllc;
  282. struct smc_wr_tx_pend_priv *pend;
  283. struct smc_wr_buf *wr_buf;
  284. int rc;
  285. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  286. if (rc)
  287. return rc;
  288. testllc = (struct smc_llc_msg_test_link *)wr_buf;
  289. memset(testllc, 0, sizeof(*testllc));
  290. testllc->hd.common.type = SMC_LLC_TEST_LINK;
  291. testllc->hd.length = sizeof(struct smc_llc_msg_test_link);
  292. memcpy(testllc->user_data, user_data, sizeof(testllc->user_data));
  293. /* send llc message */
  294. rc = smc_wr_tx_send(link, pend);
  295. return rc;
  296. }
  297. struct smc_llc_send_work {
  298. struct work_struct work;
  299. struct smc_link *link;
  300. int llclen;
  301. union smc_llc_msg llcbuf;
  302. };
  303. /* worker that sends a prepared message */
  304. static void smc_llc_send_message_work(struct work_struct *work)
  305. {
  306. struct smc_llc_send_work *llcwrk = container_of(work,
  307. struct smc_llc_send_work, work);
  308. struct smc_wr_tx_pend_priv *pend;
  309. struct smc_wr_buf *wr_buf;
  310. int rc;
  311. if (llcwrk->link->state == SMC_LNK_INACTIVE)
  312. goto out;
  313. rc = smc_llc_add_pending_send(llcwrk->link, &wr_buf, &pend);
  314. if (rc)
  315. goto out;
  316. memcpy(wr_buf, &llcwrk->llcbuf, llcwrk->llclen);
  317. smc_wr_tx_send(llcwrk->link, pend);
  318. out:
  319. kfree(llcwrk);
  320. }
  321. /* copy llcbuf and schedule an llc send on link */
  322. static int smc_llc_send_message(struct smc_link *link, void *llcbuf, int llclen)
  323. {
  324. struct smc_llc_send_work *wrk = kmalloc(sizeof(*wrk), GFP_ATOMIC);
  325. if (!wrk)
  326. return -ENOMEM;
  327. INIT_WORK(&wrk->work, smc_llc_send_message_work);
  328. wrk->link = link;
  329. wrk->llclen = llclen;
  330. memcpy(&wrk->llcbuf, llcbuf, llclen);
  331. queue_work(link->llc_wq, &wrk->work);
  332. return 0;
  333. }
  334. /********************************* receive ***********************************/
  335. static void smc_llc_rx_confirm_link(struct smc_link *link,
  336. struct smc_llc_msg_confirm_link *llc)
  337. {
  338. struct smc_link_group *lgr;
  339. int conf_rc;
  340. lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
  341. /* RMBE eyecatchers are not supported */
  342. if (llc->hd.flags & SMC_LLC_FLAG_NO_RMBE_EYEC)
  343. conf_rc = 0;
  344. else
  345. conf_rc = ENOTSUPP;
  346. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  347. if (lgr->role == SMC_SERV &&
  348. link->state == SMC_LNK_ACTIVATING) {
  349. link->llc_confirm_resp_rc = conf_rc;
  350. complete(&link->llc_confirm_resp);
  351. }
  352. } else {
  353. if (lgr->role == SMC_CLNT &&
  354. link->state == SMC_LNK_ACTIVATING) {
  355. link->llc_confirm_rc = conf_rc;
  356. link->link_id = llc->link_num;
  357. complete(&link->llc_confirm);
  358. }
  359. }
  360. }
  361. static void smc_llc_rx_add_link(struct smc_link *link,
  362. struct smc_llc_msg_add_link *llc)
  363. {
  364. struct smc_link_group *lgr = container_of(link, struct smc_link_group,
  365. lnk[SMC_SINGLE_LINK]);
  366. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  367. if (link->state == SMC_LNK_ACTIVATING)
  368. complete(&link->llc_add_resp);
  369. } else {
  370. if (link->state == SMC_LNK_ACTIVATING) {
  371. complete(&link->llc_add);
  372. return;
  373. }
  374. if (lgr->role == SMC_SERV) {
  375. smc_llc_prep_add_link(llc, link,
  376. link->smcibdev->mac[link->ibport - 1],
  377. &link->smcibdev->gid[link->ibport - 1],
  378. SMC_LLC_REQ);
  379. } else {
  380. smc_llc_prep_add_link(llc, link,
  381. link->smcibdev->mac[link->ibport - 1],
  382. &link->smcibdev->gid[link->ibport - 1],
  383. SMC_LLC_RESP);
  384. }
  385. smc_llc_send_message(link, llc, sizeof(*llc));
  386. }
  387. }
  388. static void smc_llc_rx_delete_link(struct smc_link *link,
  389. struct smc_llc_msg_del_link *llc)
  390. {
  391. struct smc_link_group *lgr = container_of(link, struct smc_link_group,
  392. lnk[SMC_SINGLE_LINK]);
  393. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  394. if (lgr->role == SMC_SERV)
  395. smc_lgr_terminate(lgr);
  396. } else {
  397. if (lgr->role == SMC_SERV) {
  398. smc_lgr_forget(lgr);
  399. smc_llc_prep_delete_link(llc, link, SMC_LLC_REQ);
  400. smc_llc_send_message(link, llc, sizeof(*llc));
  401. } else {
  402. smc_llc_prep_delete_link(llc, link, SMC_LLC_RESP);
  403. smc_llc_send_message(link, llc, sizeof(*llc));
  404. smc_lgr_terminate(lgr);
  405. }
  406. }
  407. }
  408. static void smc_llc_rx_test_link(struct smc_link *link,
  409. struct smc_llc_msg_test_link *llc)
  410. {
  411. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  412. if (link->state == SMC_LNK_ACTIVE)
  413. complete(&link->llc_testlink_resp);
  414. } else {
  415. llc->hd.flags |= SMC_LLC_FLAG_RESP;
  416. smc_llc_send_message(link, llc, sizeof(*llc));
  417. }
  418. }
  419. static void smc_llc_rx_confirm_rkey(struct smc_link *link,
  420. struct smc_llc_msg_confirm_rkey *llc)
  421. {
  422. struct smc_link_group *lgr;
  423. int rc;
  424. lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
  425. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  426. link->llc_confirm_rkey_rc = llc->hd.flags &
  427. SMC_LLC_FLAG_RKEY_NEG;
  428. complete(&link->llc_confirm_rkey);
  429. } else {
  430. rc = smc_rtoken_add(lgr,
  431. llc->rtoken[0].rmb_vaddr,
  432. llc->rtoken[0].rmb_key);
  433. /* ignore rtokens for other links, we have only one link */
  434. llc->hd.flags |= SMC_LLC_FLAG_RESP;
  435. if (rc < 0)
  436. llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG;
  437. smc_llc_send_message(link, llc, sizeof(*llc));
  438. }
  439. }
  440. static void smc_llc_rx_confirm_rkey_cont(struct smc_link *link,
  441. struct smc_llc_msg_confirm_rkey_cont *llc)
  442. {
  443. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  444. /* unused as long as we don't send this type of msg */
  445. } else {
  446. /* ignore rtokens for other links, we have only one link */
  447. llc->hd.flags |= SMC_LLC_FLAG_RESP;
  448. smc_llc_send_message(link, llc, sizeof(*llc));
  449. }
  450. }
  451. static void smc_llc_rx_delete_rkey(struct smc_link *link,
  452. struct smc_llc_msg_delete_rkey *llc)
  453. {
  454. struct smc_link_group *lgr;
  455. u8 err_mask = 0;
  456. int i, max;
  457. lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
  458. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  459. /* unused as long as we don't send this type of msg */
  460. } else {
  461. max = min_t(u8, llc->num_rkeys, SMC_LLC_DEL_RKEY_MAX);
  462. for (i = 0; i < max; i++) {
  463. if (smc_rtoken_delete(lgr, llc->rkey[i]))
  464. err_mask |= 1 << (SMC_LLC_DEL_RKEY_MAX - 1 - i);
  465. }
  466. if (err_mask) {
  467. llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG;
  468. llc->err_mask = err_mask;
  469. }
  470. llc->hd.flags |= SMC_LLC_FLAG_RESP;
  471. smc_llc_send_message(link, llc, sizeof(*llc));
  472. }
  473. }
  474. static void smc_llc_rx_handler(struct ib_wc *wc, void *buf)
  475. {
  476. struct smc_link *link = (struct smc_link *)wc->qp->qp_context;
  477. union smc_llc_msg *llc = buf;
  478. if (wc->byte_len < sizeof(*llc))
  479. return; /* short message */
  480. if (llc->raw.hdr.length != sizeof(*llc))
  481. return; /* invalid message */
  482. if (link->state == SMC_LNK_INACTIVE)
  483. return; /* link not active, drop msg */
  484. switch (llc->raw.hdr.common.type) {
  485. case SMC_LLC_TEST_LINK:
  486. smc_llc_rx_test_link(link, &llc->test_link);
  487. break;
  488. case SMC_LLC_CONFIRM_LINK:
  489. smc_llc_rx_confirm_link(link, &llc->confirm_link);
  490. break;
  491. case SMC_LLC_ADD_LINK:
  492. smc_llc_rx_add_link(link, &llc->add_link);
  493. break;
  494. case SMC_LLC_DELETE_LINK:
  495. smc_llc_rx_delete_link(link, &llc->delete_link);
  496. break;
  497. case SMC_LLC_CONFIRM_RKEY:
  498. smc_llc_rx_confirm_rkey(link, &llc->confirm_rkey);
  499. break;
  500. case SMC_LLC_CONFIRM_RKEY_CONT:
  501. smc_llc_rx_confirm_rkey_cont(link, &llc->confirm_rkey_cont);
  502. break;
  503. case SMC_LLC_DELETE_RKEY:
  504. smc_llc_rx_delete_rkey(link, &llc->delete_rkey);
  505. break;
  506. }
  507. }
  508. /***************************** worker, utils *********************************/
  509. static void smc_llc_testlink_work(struct work_struct *work)
  510. {
  511. struct smc_link *link = container_of(to_delayed_work(work),
  512. struct smc_link, llc_testlink_wrk);
  513. unsigned long next_interval;
  514. struct smc_link_group *lgr;
  515. unsigned long expire_time;
  516. u8 user_data[16] = { 0 };
  517. int rc;
  518. lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
  519. if (link->state != SMC_LNK_ACTIVE)
  520. return; /* don't reschedule worker */
  521. expire_time = link->wr_rx_tstamp + link->llc_testlink_time;
  522. if (time_is_after_jiffies(expire_time)) {
  523. next_interval = expire_time - jiffies;
  524. goto out;
  525. }
  526. reinit_completion(&link->llc_testlink_resp);
  527. smc_llc_send_test_link(link, user_data);
  528. /* receive TEST LINK response over RoCE fabric */
  529. rc = wait_for_completion_interruptible_timeout(&link->llc_testlink_resp,
  530. SMC_LLC_WAIT_TIME);
  531. if (rc <= 0) {
  532. smc_lgr_terminate(lgr);
  533. return;
  534. }
  535. next_interval = link->llc_testlink_time;
  536. out:
  537. queue_delayed_work(link->llc_wq, &link->llc_testlink_wrk,
  538. next_interval);
  539. }
  540. int smc_llc_link_init(struct smc_link *link)
  541. {
  542. struct smc_link_group *lgr = container_of(link, struct smc_link_group,
  543. lnk[SMC_SINGLE_LINK]);
  544. link->llc_wq = alloc_ordered_workqueue("llc_wq-%x:%x)", WQ_MEM_RECLAIM,
  545. *((u32 *)lgr->id),
  546. link->link_id);
  547. if (!link->llc_wq)
  548. return -ENOMEM;
  549. init_completion(&link->llc_confirm);
  550. init_completion(&link->llc_confirm_resp);
  551. init_completion(&link->llc_add);
  552. init_completion(&link->llc_add_resp);
  553. init_completion(&link->llc_confirm_rkey);
  554. init_completion(&link->llc_testlink_resp);
  555. INIT_DELAYED_WORK(&link->llc_testlink_wrk, smc_llc_testlink_work);
  556. return 0;
  557. }
  558. void smc_llc_link_active(struct smc_link *link, int testlink_time)
  559. {
  560. link->state = SMC_LNK_ACTIVE;
  561. if (testlink_time) {
  562. link->llc_testlink_time = testlink_time * HZ;
  563. queue_delayed_work(link->llc_wq, &link->llc_testlink_wrk,
  564. link->llc_testlink_time);
  565. }
  566. }
  567. /* called in tasklet context */
  568. void smc_llc_link_inactive(struct smc_link *link)
  569. {
  570. link->state = SMC_LNK_INACTIVE;
  571. cancel_delayed_work(&link->llc_testlink_wrk);
  572. }
  573. /* called in worker context */
  574. void smc_llc_link_clear(struct smc_link *link)
  575. {
  576. flush_workqueue(link->llc_wq);
  577. destroy_workqueue(link->llc_wq);
  578. }
  579. /* register a new rtoken at the remote peer */
  580. int smc_llc_do_confirm_rkey(struct smc_link *link,
  581. struct smc_buf_desc *rmb_desc)
  582. {
  583. int rc;
  584. reinit_completion(&link->llc_confirm_rkey);
  585. smc_llc_send_confirm_rkey(link, rmb_desc);
  586. /* receive CONFIRM RKEY response from server over RoCE fabric */
  587. rc = wait_for_completion_interruptible_timeout(&link->llc_confirm_rkey,
  588. SMC_LLC_WAIT_TIME);
  589. if (rc <= 0 || link->llc_confirm_rkey_rc)
  590. return -EFAULT;
  591. return 0;
  592. }
  593. /***************************** init, exit, misc ******************************/
  594. static struct smc_wr_rx_handler smc_llc_rx_handlers[] = {
  595. {
  596. .handler = smc_llc_rx_handler,
  597. .type = SMC_LLC_CONFIRM_LINK
  598. },
  599. {
  600. .handler = smc_llc_rx_handler,
  601. .type = SMC_LLC_TEST_LINK
  602. },
  603. {
  604. .handler = smc_llc_rx_handler,
  605. .type = SMC_LLC_ADD_LINK
  606. },
  607. {
  608. .handler = smc_llc_rx_handler,
  609. .type = SMC_LLC_DELETE_LINK
  610. },
  611. {
  612. .handler = smc_llc_rx_handler,
  613. .type = SMC_LLC_CONFIRM_RKEY
  614. },
  615. {
  616. .handler = smc_llc_rx_handler,
  617. .type = SMC_LLC_CONFIRM_RKEY_CONT
  618. },
  619. {
  620. .handler = smc_llc_rx_handler,
  621. .type = SMC_LLC_DELETE_RKEY
  622. },
  623. {
  624. .handler = NULL,
  625. }
  626. };
  627. int __init smc_llc_init(void)
  628. {
  629. struct smc_wr_rx_handler *handler;
  630. int rc = 0;
  631. for (handler = smc_llc_rx_handlers; handler->handler; handler++) {
  632. INIT_HLIST_NODE(&handler->list);
  633. rc = smc_wr_rx_register_handler(handler);
  634. if (rc)
  635. break;
  636. }
  637. return rc;
  638. }