smc_llc.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  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,
  158. enum smc_llc_reqresp reqresp)
  159. {
  160. struct smc_link_group *lgr = smc_get_lgr(link);
  161. struct smc_llc_msg_confirm_link *confllc;
  162. struct smc_wr_tx_pend_priv *pend;
  163. struct smc_wr_buf *wr_buf;
  164. int rc;
  165. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  166. if (rc)
  167. return rc;
  168. confllc = (struct smc_llc_msg_confirm_link *)wr_buf;
  169. memset(confllc, 0, sizeof(*confllc));
  170. confllc->hd.common.type = SMC_LLC_CONFIRM_LINK;
  171. confllc->hd.length = sizeof(struct smc_llc_msg_confirm_link);
  172. confllc->hd.flags |= SMC_LLC_FLAG_NO_RMBE_EYEC;
  173. if (reqresp == SMC_LLC_RESP)
  174. confllc->hd.flags |= SMC_LLC_FLAG_RESP;
  175. memcpy(confllc->sender_mac, link->smcibdev->mac[link->ibport - 1],
  176. ETH_ALEN);
  177. memcpy(confllc->sender_gid, link->gid, SMC_GID_SIZE);
  178. hton24(confllc->sender_qp_num, link->roce_qp->qp_num);
  179. confllc->link_num = link->link_id;
  180. memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE);
  181. confllc->max_links = SMC_LLC_ADD_LNK_MAX_LINKS; /* enforce peer resp. */
  182. /* send llc message */
  183. rc = smc_wr_tx_send(link, pend);
  184. return rc;
  185. }
  186. /* send LLC confirm rkey request */
  187. static int smc_llc_send_confirm_rkey(struct smc_link *link,
  188. struct smc_buf_desc *rmb_desc)
  189. {
  190. struct smc_llc_msg_confirm_rkey *rkeyllc;
  191. struct smc_wr_tx_pend_priv *pend;
  192. struct smc_wr_buf *wr_buf;
  193. int rc;
  194. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  195. if (rc)
  196. return rc;
  197. rkeyllc = (struct smc_llc_msg_confirm_rkey *)wr_buf;
  198. memset(rkeyllc, 0, sizeof(*rkeyllc));
  199. rkeyllc->hd.common.type = SMC_LLC_CONFIRM_RKEY;
  200. rkeyllc->hd.length = sizeof(struct smc_llc_msg_confirm_rkey);
  201. rkeyllc->rtoken[0].rmb_key =
  202. htonl(rmb_desc->mr_rx[SMC_SINGLE_LINK]->rkey);
  203. rkeyllc->rtoken[0].rmb_vaddr = cpu_to_be64(
  204. (u64)sg_dma_address(rmb_desc->sgt[SMC_SINGLE_LINK].sgl));
  205. /* send llc message */
  206. rc = smc_wr_tx_send(link, pend);
  207. return rc;
  208. }
  209. /* prepare an add link message */
  210. static void smc_llc_prep_add_link(struct smc_llc_msg_add_link *addllc,
  211. struct smc_link *link, u8 mac[], u8 gid[],
  212. enum smc_llc_reqresp reqresp)
  213. {
  214. memset(addllc, 0, sizeof(*addllc));
  215. addllc->hd.common.type = SMC_LLC_ADD_LINK;
  216. addllc->hd.length = sizeof(struct smc_llc_msg_add_link);
  217. if (reqresp == SMC_LLC_RESP) {
  218. addllc->hd.flags |= SMC_LLC_FLAG_RESP;
  219. /* always reject more links for now */
  220. addllc->hd.flags |= SMC_LLC_FLAG_ADD_LNK_REJ;
  221. addllc->hd.add_link_rej_rsn = SMC_LLC_REJ_RSN_NO_ALT_PATH;
  222. }
  223. memcpy(addllc->sender_mac, mac, ETH_ALEN);
  224. memcpy(addllc->sender_gid, gid, SMC_GID_SIZE);
  225. }
  226. /* send ADD LINK request or response */
  227. int smc_llc_send_add_link(struct smc_link *link, u8 mac[], u8 gid[],
  228. enum smc_llc_reqresp reqresp)
  229. {
  230. struct smc_llc_msg_add_link *addllc;
  231. struct smc_wr_tx_pend_priv *pend;
  232. struct smc_wr_buf *wr_buf;
  233. int rc;
  234. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  235. if (rc)
  236. return rc;
  237. addllc = (struct smc_llc_msg_add_link *)wr_buf;
  238. smc_llc_prep_add_link(addllc, link, mac, gid, reqresp);
  239. /* send llc message */
  240. rc = smc_wr_tx_send(link, pend);
  241. return rc;
  242. }
  243. /* prepare a delete link message */
  244. static void smc_llc_prep_delete_link(struct smc_llc_msg_del_link *delllc,
  245. struct smc_link *link,
  246. enum smc_llc_reqresp reqresp, bool orderly)
  247. {
  248. memset(delllc, 0, sizeof(*delllc));
  249. delllc->hd.common.type = SMC_LLC_DELETE_LINK;
  250. delllc->hd.length = sizeof(struct smc_llc_msg_add_link);
  251. if (reqresp == SMC_LLC_RESP)
  252. delllc->hd.flags |= SMC_LLC_FLAG_RESP;
  253. /* DEL_LINK_ALL because only 1 link supported */
  254. delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ALL;
  255. if (orderly)
  256. delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY;
  257. delllc->link_num = link->link_id;
  258. }
  259. /* send DELETE LINK request or response */
  260. int smc_llc_send_delete_link(struct smc_link *link,
  261. enum smc_llc_reqresp reqresp, bool orderly)
  262. {
  263. struct smc_llc_msg_del_link *delllc;
  264. struct smc_wr_tx_pend_priv *pend;
  265. struct smc_wr_buf *wr_buf;
  266. int rc;
  267. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  268. if (rc)
  269. return rc;
  270. delllc = (struct smc_llc_msg_del_link *)wr_buf;
  271. smc_llc_prep_delete_link(delllc, link, reqresp, orderly);
  272. /* send llc message */
  273. rc = smc_wr_tx_send(link, pend);
  274. return rc;
  275. }
  276. /* send LLC test link request */
  277. static int smc_llc_send_test_link(struct smc_link *link, u8 user_data[16])
  278. {
  279. struct smc_llc_msg_test_link *testllc;
  280. struct smc_wr_tx_pend_priv *pend;
  281. struct smc_wr_buf *wr_buf;
  282. int rc;
  283. rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  284. if (rc)
  285. return rc;
  286. testllc = (struct smc_llc_msg_test_link *)wr_buf;
  287. memset(testllc, 0, sizeof(*testllc));
  288. testllc->hd.common.type = SMC_LLC_TEST_LINK;
  289. testllc->hd.length = sizeof(struct smc_llc_msg_test_link);
  290. memcpy(testllc->user_data, user_data, sizeof(testllc->user_data));
  291. /* send llc message */
  292. rc = smc_wr_tx_send(link, pend);
  293. return rc;
  294. }
  295. struct smc_llc_send_work {
  296. struct work_struct work;
  297. struct smc_link *link;
  298. int llclen;
  299. union smc_llc_msg llcbuf;
  300. };
  301. /* worker that sends a prepared message */
  302. static void smc_llc_send_message_work(struct work_struct *work)
  303. {
  304. struct smc_llc_send_work *llcwrk = container_of(work,
  305. struct smc_llc_send_work, work);
  306. struct smc_wr_tx_pend_priv *pend;
  307. struct smc_wr_buf *wr_buf;
  308. int rc;
  309. if (llcwrk->link->state == SMC_LNK_INACTIVE)
  310. goto out;
  311. rc = smc_llc_add_pending_send(llcwrk->link, &wr_buf, &pend);
  312. if (rc)
  313. goto out;
  314. memcpy(wr_buf, &llcwrk->llcbuf, llcwrk->llclen);
  315. smc_wr_tx_send(llcwrk->link, pend);
  316. out:
  317. kfree(llcwrk);
  318. }
  319. /* copy llcbuf and schedule an llc send on link */
  320. static int smc_llc_send_message(struct smc_link *link, void *llcbuf, int llclen)
  321. {
  322. struct smc_llc_send_work *wrk = kmalloc(sizeof(*wrk), GFP_ATOMIC);
  323. if (!wrk)
  324. return -ENOMEM;
  325. INIT_WORK(&wrk->work, smc_llc_send_message_work);
  326. wrk->link = link;
  327. wrk->llclen = llclen;
  328. memcpy(&wrk->llcbuf, llcbuf, llclen);
  329. queue_work(link->llc_wq, &wrk->work);
  330. return 0;
  331. }
  332. /********************************* receive ***********************************/
  333. static void smc_llc_rx_confirm_link(struct smc_link *link,
  334. struct smc_llc_msg_confirm_link *llc)
  335. {
  336. struct smc_link_group *lgr = smc_get_lgr(link);
  337. int conf_rc;
  338. /* RMBE eyecatchers are not supported */
  339. if (llc->hd.flags & SMC_LLC_FLAG_NO_RMBE_EYEC)
  340. conf_rc = 0;
  341. else
  342. conf_rc = ENOTSUPP;
  343. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  344. if (lgr->role == SMC_SERV &&
  345. link->state == SMC_LNK_ACTIVATING) {
  346. link->llc_confirm_resp_rc = conf_rc;
  347. complete(&link->llc_confirm_resp);
  348. }
  349. } else {
  350. if (lgr->role == SMC_CLNT &&
  351. link->state == SMC_LNK_ACTIVATING) {
  352. link->llc_confirm_rc = conf_rc;
  353. link->link_id = llc->link_num;
  354. complete(&link->llc_confirm);
  355. }
  356. }
  357. }
  358. static void smc_llc_rx_add_link(struct smc_link *link,
  359. struct smc_llc_msg_add_link *llc)
  360. {
  361. struct smc_link_group *lgr = smc_get_lgr(link);
  362. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  363. if (link->state == SMC_LNK_ACTIVATING)
  364. complete(&link->llc_add_resp);
  365. } else {
  366. if (link->state == SMC_LNK_ACTIVATING) {
  367. complete(&link->llc_add);
  368. return;
  369. }
  370. if (lgr->role == SMC_SERV) {
  371. smc_llc_prep_add_link(llc, link,
  372. link->smcibdev->mac[link->ibport - 1],
  373. link->gid, SMC_LLC_REQ);
  374. } else {
  375. smc_llc_prep_add_link(llc, link,
  376. link->smcibdev->mac[link->ibport - 1],
  377. link->gid, SMC_LLC_RESP);
  378. }
  379. smc_llc_send_message(link, llc, sizeof(*llc));
  380. }
  381. }
  382. static void smc_llc_rx_delete_link(struct smc_link *link,
  383. struct smc_llc_msg_del_link *llc)
  384. {
  385. struct smc_link_group *lgr = smc_get_lgr(link);
  386. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  387. if (lgr->role == SMC_SERV)
  388. smc_lgr_schedule_free_work_fast(lgr);
  389. } else {
  390. smc_lgr_forget(lgr);
  391. smc_llc_link_deleting(link);
  392. if (lgr->role == SMC_SERV) {
  393. /* client asks to delete this link, send request */
  394. smc_llc_prep_delete_link(llc, link, SMC_LLC_REQ, true);
  395. } else {
  396. /* server requests to delete this link, send response */
  397. smc_llc_prep_delete_link(llc, link, SMC_LLC_RESP, true);
  398. }
  399. smc_llc_send_message(link, llc, sizeof(*llc));
  400. smc_lgr_schedule_free_work_fast(lgr);
  401. }
  402. }
  403. static void smc_llc_rx_test_link(struct smc_link *link,
  404. struct smc_llc_msg_test_link *llc)
  405. {
  406. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  407. if (link->state == SMC_LNK_ACTIVE)
  408. complete(&link->llc_testlink_resp);
  409. } else {
  410. llc->hd.flags |= SMC_LLC_FLAG_RESP;
  411. smc_llc_send_message(link, llc, sizeof(*llc));
  412. }
  413. }
  414. static void smc_llc_rx_confirm_rkey(struct smc_link *link,
  415. struct smc_llc_msg_confirm_rkey *llc)
  416. {
  417. int rc;
  418. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  419. link->llc_confirm_rkey_rc = llc->hd.flags &
  420. SMC_LLC_FLAG_RKEY_NEG;
  421. complete(&link->llc_confirm_rkey);
  422. } else {
  423. rc = smc_rtoken_add(smc_get_lgr(link),
  424. llc->rtoken[0].rmb_vaddr,
  425. llc->rtoken[0].rmb_key);
  426. /* ignore rtokens for other links, we have only one link */
  427. llc->hd.flags |= SMC_LLC_FLAG_RESP;
  428. if (rc < 0)
  429. llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG;
  430. smc_llc_send_message(link, llc, sizeof(*llc));
  431. }
  432. }
  433. static void smc_llc_rx_confirm_rkey_cont(struct smc_link *link,
  434. struct smc_llc_msg_confirm_rkey_cont *llc)
  435. {
  436. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  437. /* unused as long as we don't send this type of msg */
  438. } else {
  439. /* ignore rtokens for other links, we have only one link */
  440. llc->hd.flags |= SMC_LLC_FLAG_RESP;
  441. smc_llc_send_message(link, llc, sizeof(*llc));
  442. }
  443. }
  444. static void smc_llc_rx_delete_rkey(struct smc_link *link,
  445. struct smc_llc_msg_delete_rkey *llc)
  446. {
  447. u8 err_mask = 0;
  448. int i, max;
  449. if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
  450. /* unused as long as we don't send this type of msg */
  451. } else {
  452. max = min_t(u8, llc->num_rkeys, SMC_LLC_DEL_RKEY_MAX);
  453. for (i = 0; i < max; i++) {
  454. if (smc_rtoken_delete(smc_get_lgr(link), llc->rkey[i]))
  455. err_mask |= 1 << (SMC_LLC_DEL_RKEY_MAX - 1 - i);
  456. }
  457. if (err_mask) {
  458. llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG;
  459. llc->err_mask = err_mask;
  460. }
  461. llc->hd.flags |= SMC_LLC_FLAG_RESP;
  462. smc_llc_send_message(link, llc, sizeof(*llc));
  463. }
  464. }
  465. static void smc_llc_rx_handler(struct ib_wc *wc, void *buf)
  466. {
  467. struct smc_link *link = (struct smc_link *)wc->qp->qp_context;
  468. union smc_llc_msg *llc = buf;
  469. if (wc->byte_len < sizeof(*llc))
  470. return; /* short message */
  471. if (llc->raw.hdr.length != sizeof(*llc))
  472. return; /* invalid message */
  473. if (link->state == SMC_LNK_INACTIVE)
  474. return; /* link not active, drop msg */
  475. switch (llc->raw.hdr.common.type) {
  476. case SMC_LLC_TEST_LINK:
  477. smc_llc_rx_test_link(link, &llc->test_link);
  478. break;
  479. case SMC_LLC_CONFIRM_LINK:
  480. smc_llc_rx_confirm_link(link, &llc->confirm_link);
  481. break;
  482. case SMC_LLC_ADD_LINK:
  483. smc_llc_rx_add_link(link, &llc->add_link);
  484. break;
  485. case SMC_LLC_DELETE_LINK:
  486. smc_llc_rx_delete_link(link, &llc->delete_link);
  487. break;
  488. case SMC_LLC_CONFIRM_RKEY:
  489. smc_llc_rx_confirm_rkey(link, &llc->confirm_rkey);
  490. break;
  491. case SMC_LLC_CONFIRM_RKEY_CONT:
  492. smc_llc_rx_confirm_rkey_cont(link, &llc->confirm_rkey_cont);
  493. break;
  494. case SMC_LLC_DELETE_RKEY:
  495. smc_llc_rx_delete_rkey(link, &llc->delete_rkey);
  496. break;
  497. }
  498. }
  499. /***************************** worker, utils *********************************/
  500. static void smc_llc_testlink_work(struct work_struct *work)
  501. {
  502. struct smc_link *link = container_of(to_delayed_work(work),
  503. struct smc_link, llc_testlink_wrk);
  504. unsigned long next_interval;
  505. unsigned long expire_time;
  506. u8 user_data[16] = { 0 };
  507. int rc;
  508. if (link->state != SMC_LNK_ACTIVE)
  509. return; /* don't reschedule worker */
  510. expire_time = link->wr_rx_tstamp + link->llc_testlink_time;
  511. if (time_is_after_jiffies(expire_time)) {
  512. next_interval = expire_time - jiffies;
  513. goto out;
  514. }
  515. reinit_completion(&link->llc_testlink_resp);
  516. smc_llc_send_test_link(link, user_data);
  517. /* receive TEST LINK response over RoCE fabric */
  518. rc = wait_for_completion_interruptible_timeout(&link->llc_testlink_resp,
  519. SMC_LLC_WAIT_TIME);
  520. if (rc <= 0) {
  521. smc_lgr_terminate(smc_get_lgr(link));
  522. return;
  523. }
  524. next_interval = link->llc_testlink_time;
  525. out:
  526. queue_delayed_work(link->llc_wq, &link->llc_testlink_wrk,
  527. next_interval);
  528. }
  529. int smc_llc_link_init(struct smc_link *link)
  530. {
  531. struct smc_link_group *lgr = smc_get_lgr(link);
  532. link->llc_wq = alloc_ordered_workqueue("llc_wq-%x:%x)", WQ_MEM_RECLAIM,
  533. *((u32 *)lgr->id),
  534. link->link_id);
  535. if (!link->llc_wq)
  536. return -ENOMEM;
  537. init_completion(&link->llc_confirm);
  538. init_completion(&link->llc_confirm_resp);
  539. init_completion(&link->llc_add);
  540. init_completion(&link->llc_add_resp);
  541. init_completion(&link->llc_confirm_rkey);
  542. init_completion(&link->llc_testlink_resp);
  543. INIT_DELAYED_WORK(&link->llc_testlink_wrk, smc_llc_testlink_work);
  544. return 0;
  545. }
  546. void smc_llc_link_active(struct smc_link *link, int testlink_time)
  547. {
  548. link->state = SMC_LNK_ACTIVE;
  549. if (testlink_time) {
  550. link->llc_testlink_time = testlink_time * HZ;
  551. queue_delayed_work(link->llc_wq, &link->llc_testlink_wrk,
  552. link->llc_testlink_time);
  553. }
  554. }
  555. void smc_llc_link_deleting(struct smc_link *link)
  556. {
  557. link->state = SMC_LNK_DELETING;
  558. }
  559. /* called in tasklet context */
  560. void smc_llc_link_inactive(struct smc_link *link)
  561. {
  562. link->state = SMC_LNK_INACTIVE;
  563. cancel_delayed_work(&link->llc_testlink_wrk);
  564. }
  565. /* called in worker context */
  566. void smc_llc_link_clear(struct smc_link *link)
  567. {
  568. flush_workqueue(link->llc_wq);
  569. destroy_workqueue(link->llc_wq);
  570. }
  571. /* register a new rtoken at the remote peer */
  572. int smc_llc_do_confirm_rkey(struct smc_link *link,
  573. struct smc_buf_desc *rmb_desc)
  574. {
  575. int rc;
  576. reinit_completion(&link->llc_confirm_rkey);
  577. smc_llc_send_confirm_rkey(link, rmb_desc);
  578. /* receive CONFIRM RKEY response from server over RoCE fabric */
  579. rc = wait_for_completion_interruptible_timeout(&link->llc_confirm_rkey,
  580. SMC_LLC_WAIT_TIME);
  581. if (rc <= 0 || link->llc_confirm_rkey_rc)
  582. return -EFAULT;
  583. return 0;
  584. }
  585. /***************************** init, exit, misc ******************************/
  586. static struct smc_wr_rx_handler smc_llc_rx_handlers[] = {
  587. {
  588. .handler = smc_llc_rx_handler,
  589. .type = SMC_LLC_CONFIRM_LINK
  590. },
  591. {
  592. .handler = smc_llc_rx_handler,
  593. .type = SMC_LLC_TEST_LINK
  594. },
  595. {
  596. .handler = smc_llc_rx_handler,
  597. .type = SMC_LLC_ADD_LINK
  598. },
  599. {
  600. .handler = smc_llc_rx_handler,
  601. .type = SMC_LLC_DELETE_LINK
  602. },
  603. {
  604. .handler = smc_llc_rx_handler,
  605. .type = SMC_LLC_CONFIRM_RKEY
  606. },
  607. {
  608. .handler = smc_llc_rx_handler,
  609. .type = SMC_LLC_CONFIRM_RKEY_CONT
  610. },
  611. {
  612. .handler = smc_llc_rx_handler,
  613. .type = SMC_LLC_DELETE_RKEY
  614. },
  615. {
  616. .handler = NULL,
  617. }
  618. };
  619. int __init smc_llc_init(void)
  620. {
  621. struct smc_wr_rx_handler *handler;
  622. int rc = 0;
  623. for (handler = smc_llc_rx_handlers; handler->handler; handler++) {
  624. INIT_HLIST_NODE(&handler->list);
  625. rc = smc_wr_rx_register_handler(handler);
  626. if (rc)
  627. break;
  628. }
  629. return rc;
  630. }