1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 29bf9abeaSUrsula Braun /* 39bf9abeaSUrsula Braun * Shared Memory Communications over RDMA (SMC-R) and RoCE 49bf9abeaSUrsula Braun * 59bf9abeaSUrsula Braun * Link Layer Control (LLC) 69bf9abeaSUrsula Braun * 79bf9abeaSUrsula Braun * Copyright IBM Corp. 2016 89bf9abeaSUrsula Braun * 99bf9abeaSUrsula Braun * Author(s): Klaus Wacker <Klaus.Wacker@de.ibm.com> 109bf9abeaSUrsula Braun * Ursula Braun <ubraun@linux.vnet.ibm.com> 119bf9abeaSUrsula Braun */ 129bf9abeaSUrsula Braun 139bf9abeaSUrsula Braun #include <net/tcp.h> 149bf9abeaSUrsula Braun #include <rdma/ib_verbs.h> 159bf9abeaSUrsula Braun 169bf9abeaSUrsula Braun #include "smc.h" 179bf9abeaSUrsula Braun #include "smc_core.h" 189bf9abeaSUrsula Braun #include "smc_clc.h" 199bf9abeaSUrsula Braun #include "smc_llc.h" 209bf9abeaSUrsula Braun 210f627126SStefan Raspl #define SMC_LLC_DATA_LEN 40 220f627126SStefan Raspl 230f627126SStefan Raspl struct smc_llc_hdr { 240f627126SStefan Raspl struct smc_wr_rx_hdr common; 250f627126SStefan Raspl u8 length; /* 44 */ 2652bedf37SKarsten Graul #if defined(__BIG_ENDIAN_BITFIELD) 2752bedf37SKarsten Graul u8 reserved:4, 2852bedf37SKarsten Graul add_link_rej_rsn:4; 2952bedf37SKarsten Graul #elif defined(__LITTLE_ENDIAN_BITFIELD) 3052bedf37SKarsten Graul u8 add_link_rej_rsn:4, 3152bedf37SKarsten Graul reserved:4; 3252bedf37SKarsten Graul #endif 330f627126SStefan Raspl u8 flags; 340f627126SStefan Raspl }; 350f627126SStefan Raspl 3675d320d6SKarsten Graul #define SMC_LLC_FLAG_NO_RMBE_EYEC 0x03 3775d320d6SKarsten Graul 380f627126SStefan Raspl struct smc_llc_msg_confirm_link { /* type 0x01 */ 390f627126SStefan Raspl struct smc_llc_hdr hd; 400f627126SStefan Raspl u8 sender_mac[ETH_ALEN]; 410f627126SStefan Raspl u8 sender_gid[SMC_GID_SIZE]; 420f627126SStefan Raspl u8 sender_qp_num[3]; 430f627126SStefan Raspl u8 link_num; 440f627126SStefan Raspl u8 link_uid[SMC_LGR_ID_SIZE]; 450f627126SStefan Raspl u8 max_links; 460f627126SStefan Raspl u8 reserved[9]; 470f627126SStefan Raspl }; 480f627126SStefan Raspl 4952bedf37SKarsten Graul #define SMC_LLC_FLAG_ADD_LNK_REJ 0x40 5052bedf37SKarsten Graul #define SMC_LLC_REJ_RSN_NO_ALT_PATH 1 5152bedf37SKarsten Graul 5252bedf37SKarsten Graul #define SMC_LLC_ADD_LNK_MAX_LINKS 2 5352bedf37SKarsten Graul 5452bedf37SKarsten Graul struct smc_llc_msg_add_link { /* type 0x02 */ 5552bedf37SKarsten Graul struct smc_llc_hdr hd; 5652bedf37SKarsten Graul u8 sender_mac[ETH_ALEN]; 5752bedf37SKarsten Graul u8 reserved2[2]; 5852bedf37SKarsten Graul u8 sender_gid[SMC_GID_SIZE]; 5952bedf37SKarsten Graul u8 sender_qp_num[3]; 6052bedf37SKarsten Graul u8 link_num; 6152bedf37SKarsten Graul u8 flags2; /* QP mtu */ 6252bedf37SKarsten Graul u8 initial_psn[3]; 6352bedf37SKarsten Graul u8 reserved[8]; 6452bedf37SKarsten Graul }; 6552bedf37SKarsten Graul 6652bedf37SKarsten Graul #define SMC_LLC_FLAG_DEL_LINK_ALL 0x40 6752bedf37SKarsten Graul #define SMC_LLC_FLAG_DEL_LINK_ORDERLY 0x20 6852bedf37SKarsten Graul 6952bedf37SKarsten Graul struct smc_llc_msg_del_link { /* type 0x04 */ 7052bedf37SKarsten Graul struct smc_llc_hdr hd; 7152bedf37SKarsten Graul u8 link_num; 7252bedf37SKarsten Graul __be32 reason; 7352bedf37SKarsten Graul u8 reserved[35]; 7452bedf37SKarsten Graul } __packed; /* format defined in RFC7609 */ 7552bedf37SKarsten Graul 76313164daSKarsten Graul struct smc_llc_msg_test_link { /* type 0x07 */ 77313164daSKarsten Graul struct smc_llc_hdr hd; 78313164daSKarsten Graul u8 user_data[16]; 79313164daSKarsten Graul u8 reserved[24]; 80313164daSKarsten Graul }; 81313164daSKarsten Graul 824ed75de5SKarsten Graul struct smc_rmb_rtoken { 834ed75de5SKarsten Graul union { 844ed75de5SKarsten Graul u8 num_rkeys; /* first rtoken byte of CONFIRM LINK msg */ 854ed75de5SKarsten Graul /* is actually the num of rtokens, first */ 864ed75de5SKarsten Graul /* rtoken is always for the current link */ 874ed75de5SKarsten Graul u8 link_id; /* link id of the rtoken */ 884ed75de5SKarsten Graul }; 894ed75de5SKarsten Graul __be32 rmb_key; 904ed75de5SKarsten Graul __be64 rmb_vaddr; 914ed75de5SKarsten Graul } __packed; /* format defined in RFC7609 */ 924ed75de5SKarsten Graul 934ed75de5SKarsten Graul #define SMC_LLC_RKEYS_PER_MSG 3 944ed75de5SKarsten Graul 954ed75de5SKarsten Graul struct smc_llc_msg_confirm_rkey { /* type 0x06 */ 964ed75de5SKarsten Graul struct smc_llc_hdr hd; 974ed75de5SKarsten Graul struct smc_rmb_rtoken rtoken[SMC_LLC_RKEYS_PER_MSG]; 984ed75de5SKarsten Graul u8 reserved; 994ed75de5SKarsten Graul }; 1004ed75de5SKarsten Graul 1014ed75de5SKarsten Graul struct smc_llc_msg_confirm_rkey_cont { /* type 0x08 */ 1024ed75de5SKarsten Graul struct smc_llc_hdr hd; 1034ed75de5SKarsten Graul u8 num_rkeys; 1044ed75de5SKarsten Graul struct smc_rmb_rtoken rtoken[SMC_LLC_RKEYS_PER_MSG]; 1054ed75de5SKarsten Graul }; 1064ed75de5SKarsten Graul 1074ed75de5SKarsten Graul #define SMC_LLC_DEL_RKEY_MAX 8 1084ed75de5SKarsten Graul #define SMC_LLC_FLAG_RKEY_NEG 0x20 1094ed75de5SKarsten Graul 1104ed75de5SKarsten Graul struct smc_llc_msg_delete_rkey { /* type 0x09 */ 1114ed75de5SKarsten Graul struct smc_llc_hdr hd; 1124ed75de5SKarsten Graul u8 num_rkeys; 1134ed75de5SKarsten Graul u8 err_mask; 1144ed75de5SKarsten Graul u8 reserved[2]; 1154ed75de5SKarsten Graul __be32 rkey[8]; 1164ed75de5SKarsten Graul u8 reserved2[4]; 1174ed75de5SKarsten Graul }; 1184ed75de5SKarsten Graul 1190f627126SStefan Raspl union smc_llc_msg { 1200f627126SStefan Raspl struct smc_llc_msg_confirm_link confirm_link; 12152bedf37SKarsten Graul struct smc_llc_msg_add_link add_link; 12252bedf37SKarsten Graul struct smc_llc_msg_del_link delete_link; 1234ed75de5SKarsten Graul 1244ed75de5SKarsten Graul struct smc_llc_msg_confirm_rkey confirm_rkey; 1254ed75de5SKarsten Graul struct smc_llc_msg_confirm_rkey_cont confirm_rkey_cont; 1264ed75de5SKarsten Graul struct smc_llc_msg_delete_rkey delete_rkey; 1274ed75de5SKarsten Graul 128313164daSKarsten Graul struct smc_llc_msg_test_link test_link; 1290f627126SStefan Raspl struct { 1300f627126SStefan Raspl struct smc_llc_hdr hdr; 1310f627126SStefan Raspl u8 data[SMC_LLC_DATA_LEN]; 1320f627126SStefan Raspl } raw; 1330f627126SStefan Raspl }; 1340f627126SStefan Raspl 1350f627126SStefan Raspl #define SMC_LLC_FLAG_RESP 0x80 1360f627126SStefan Raspl 1376c8968c4SKarsten Graul struct smc_llc_qentry { 1386c8968c4SKarsten Graul struct list_head list; 1396c8968c4SKarsten Graul struct smc_link *link; 1406c8968c4SKarsten Graul union smc_llc_msg msg; 1416c8968c4SKarsten Graul }; 1426c8968c4SKarsten Graul 1439bf9abeaSUrsula Braun /********************************** send *************************************/ 1449bf9abeaSUrsula Braun 1459bf9abeaSUrsula Braun struct smc_llc_tx_pend { 1469bf9abeaSUrsula Braun }; 1479bf9abeaSUrsula Braun 1489bf9abeaSUrsula Braun /* handler for send/transmission completion of an LLC msg */ 1499bf9abeaSUrsula Braun static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv *pend, 1509bf9abeaSUrsula Braun struct smc_link *link, 1519bf9abeaSUrsula Braun enum ib_wc_status wc_status) 1529bf9abeaSUrsula Braun { 1539bf9abeaSUrsula Braun /* future work: handle wc_status error for recovery and failover */ 1549bf9abeaSUrsula Braun } 1559bf9abeaSUrsula Braun 1569bf9abeaSUrsula Braun /** 1579bf9abeaSUrsula Braun * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits 1589bf9abeaSUrsula Braun * @link: Pointer to SMC link used for sending LLC control message. 1599bf9abeaSUrsula Braun * @wr_buf: Out variable returning pointer to work request payload buffer. 1609bf9abeaSUrsula Braun * @pend: Out variable returning pointer to private pending WR tracking. 1619bf9abeaSUrsula Braun * It's the context the transmit complete handler will get. 1629bf9abeaSUrsula Braun * 1639bf9abeaSUrsula Braun * Reserves and pre-fills an entry for a pending work request send/tx. 1649bf9abeaSUrsula Braun * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx. 1659bf9abeaSUrsula Braun * Can sleep due to smc_get_ctrl_buf (if not in softirq context). 1669bf9abeaSUrsula Braun * 1679bf9abeaSUrsula Braun * Return: 0 on success, otherwise an error value. 1689bf9abeaSUrsula Braun */ 1699bf9abeaSUrsula Braun static int smc_llc_add_pending_send(struct smc_link *link, 1709bf9abeaSUrsula Braun struct smc_wr_buf **wr_buf, 1719bf9abeaSUrsula Braun struct smc_wr_tx_pend_priv **pend) 1729bf9abeaSUrsula Braun { 1739bf9abeaSUrsula Braun int rc; 1749bf9abeaSUrsula Braun 175ad6f317fSUrsula Braun rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, NULL, 176ad6f317fSUrsula Braun pend); 1779bf9abeaSUrsula Braun if (rc < 0) 1789bf9abeaSUrsula Braun return rc; 1799bf9abeaSUrsula Braun BUILD_BUG_ON_MSG( 1809bf9abeaSUrsula Braun sizeof(union smc_llc_msg) > SMC_WR_BUF_SIZE, 1819bf9abeaSUrsula Braun "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)"); 1829bf9abeaSUrsula Braun BUILD_BUG_ON_MSG( 1839bf9abeaSUrsula Braun sizeof(union smc_llc_msg) != SMC_WR_TX_SIZE, 1849bf9abeaSUrsula Braun "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()"); 1859bf9abeaSUrsula Braun BUILD_BUG_ON_MSG( 1869bf9abeaSUrsula Braun sizeof(struct smc_llc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE, 1879bf9abeaSUrsula Braun "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)"); 1889bf9abeaSUrsula Braun return 0; 1899bf9abeaSUrsula Braun } 1909bf9abeaSUrsula Braun 1919bf9abeaSUrsula Braun /* high-level API to send LLC confirm link */ 192947541f3SUrsula Braun int smc_llc_send_confirm_link(struct smc_link *link, 1939bf9abeaSUrsula Braun enum smc_llc_reqresp reqresp) 1949bf9abeaSUrsula Braun { 19500e5fb26SStefan Raspl struct smc_link_group *lgr = smc_get_lgr(link); 1969bf9abeaSUrsula Braun struct smc_llc_msg_confirm_link *confllc; 1979bf9abeaSUrsula Braun struct smc_wr_tx_pend_priv *pend; 1989bf9abeaSUrsula Braun struct smc_wr_buf *wr_buf; 1999bf9abeaSUrsula Braun int rc; 2009bf9abeaSUrsula Braun 2019bf9abeaSUrsula Braun rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 2029bf9abeaSUrsula Braun if (rc) 2039bf9abeaSUrsula Braun return rc; 2049bf9abeaSUrsula Braun confllc = (struct smc_llc_msg_confirm_link *)wr_buf; 2059bf9abeaSUrsula Braun memset(confllc, 0, sizeof(*confllc)); 2069bf9abeaSUrsula Braun confllc->hd.common.type = SMC_LLC_CONFIRM_LINK; 2079bf9abeaSUrsula Braun confllc->hd.length = sizeof(struct smc_llc_msg_confirm_link); 20875d320d6SKarsten Graul confllc->hd.flags |= SMC_LLC_FLAG_NO_RMBE_EYEC; 2099bf9abeaSUrsula Braun if (reqresp == SMC_LLC_RESP) 2109bf9abeaSUrsula Braun confllc->hd.flags |= SMC_LLC_FLAG_RESP; 211947541f3SUrsula Braun memcpy(confllc->sender_mac, link->smcibdev->mac[link->ibport - 1], 212947541f3SUrsula Braun ETH_ALEN); 2137005ada6SUrsula Braun memcpy(confllc->sender_gid, link->gid, SMC_GID_SIZE); 2149bf9abeaSUrsula Braun hton24(confllc->sender_qp_num, link->roce_qp->qp_num); 2152be922f3SKarsten Graul confllc->link_num = link->link_id; 2169bf9abeaSUrsula Braun memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE); 21752bedf37SKarsten Graul confllc->max_links = SMC_LLC_ADD_LNK_MAX_LINKS; /* enforce peer resp. */ 21852bedf37SKarsten Graul /* send llc message */ 21952bedf37SKarsten Graul rc = smc_wr_tx_send(link, pend); 22052bedf37SKarsten Graul return rc; 22152bedf37SKarsten Graul } 22252bedf37SKarsten Graul 22344aa81ceSKarsten Graul /* send LLC confirm rkey request */ 22444aa81ceSKarsten Graul static int smc_llc_send_confirm_rkey(struct smc_link *link, 22544aa81ceSKarsten Graul struct smc_buf_desc *rmb_desc) 22644aa81ceSKarsten Graul { 22744aa81ceSKarsten Graul struct smc_llc_msg_confirm_rkey *rkeyllc; 22844aa81ceSKarsten Graul struct smc_wr_tx_pend_priv *pend; 22944aa81ceSKarsten Graul struct smc_wr_buf *wr_buf; 23044aa81ceSKarsten Graul int rc; 23144aa81ceSKarsten Graul 23244aa81ceSKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 23344aa81ceSKarsten Graul if (rc) 23444aa81ceSKarsten Graul return rc; 23544aa81ceSKarsten Graul rkeyllc = (struct smc_llc_msg_confirm_rkey *)wr_buf; 23644aa81ceSKarsten Graul memset(rkeyllc, 0, sizeof(*rkeyllc)); 23744aa81ceSKarsten Graul rkeyllc->hd.common.type = SMC_LLC_CONFIRM_RKEY; 23844aa81ceSKarsten Graul rkeyllc->hd.length = sizeof(struct smc_llc_msg_confirm_rkey); 23944aa81ceSKarsten Graul rkeyllc->rtoken[0].rmb_key = 240387707fdSKarsten Graul htonl(rmb_desc->mr_rx[link->link_idx]->rkey); 24144aa81ceSKarsten Graul rkeyllc->rtoken[0].rmb_vaddr = cpu_to_be64( 242387707fdSKarsten Graul (u64)sg_dma_address(rmb_desc->sgt[link->link_idx].sgl)); 24344aa81ceSKarsten Graul /* send llc message */ 24444aa81ceSKarsten Graul rc = smc_wr_tx_send(link, pend); 24544aa81ceSKarsten Graul return rc; 24644aa81ceSKarsten Graul } 24744aa81ceSKarsten Graul 24860e03c62SKarsten Graul /* send LLC delete rkey request */ 24960e03c62SKarsten Graul static int smc_llc_send_delete_rkey(struct smc_link *link, 25060e03c62SKarsten Graul struct smc_buf_desc *rmb_desc) 25160e03c62SKarsten Graul { 25260e03c62SKarsten Graul struct smc_llc_msg_delete_rkey *rkeyllc; 25360e03c62SKarsten Graul struct smc_wr_tx_pend_priv *pend; 25460e03c62SKarsten Graul struct smc_wr_buf *wr_buf; 25560e03c62SKarsten Graul int rc; 25660e03c62SKarsten Graul 25760e03c62SKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 25860e03c62SKarsten Graul if (rc) 25960e03c62SKarsten Graul return rc; 26060e03c62SKarsten Graul rkeyllc = (struct smc_llc_msg_delete_rkey *)wr_buf; 26160e03c62SKarsten Graul memset(rkeyllc, 0, sizeof(*rkeyllc)); 26260e03c62SKarsten Graul rkeyllc->hd.common.type = SMC_LLC_DELETE_RKEY; 26360e03c62SKarsten Graul rkeyllc->hd.length = sizeof(struct smc_llc_msg_delete_rkey); 26460e03c62SKarsten Graul rkeyllc->num_rkeys = 1; 265387707fdSKarsten Graul rkeyllc->rkey[0] = htonl(rmb_desc->mr_rx[link->link_idx]->rkey); 26660e03c62SKarsten Graul /* send llc message */ 26760e03c62SKarsten Graul rc = smc_wr_tx_send(link, pend); 26860e03c62SKarsten Graul return rc; 26960e03c62SKarsten Graul } 27060e03c62SKarsten Graul 2712a4c57a9SKarsten Graul /* prepare an add link message */ 2722a4c57a9SKarsten Graul static void smc_llc_prep_add_link(struct smc_llc_msg_add_link *addllc, 2737005ada6SUrsula Braun struct smc_link *link, u8 mac[], u8 gid[], 2742a4c57a9SKarsten Graul enum smc_llc_reqresp reqresp) 2752a4c57a9SKarsten Graul { 2762a4c57a9SKarsten Graul memset(addllc, 0, sizeof(*addllc)); 2772a4c57a9SKarsten Graul addllc->hd.common.type = SMC_LLC_ADD_LINK; 2782a4c57a9SKarsten Graul addllc->hd.length = sizeof(struct smc_llc_msg_add_link); 2792a4c57a9SKarsten Graul if (reqresp == SMC_LLC_RESP) { 2802a4c57a9SKarsten Graul addllc->hd.flags |= SMC_LLC_FLAG_RESP; 2812a4c57a9SKarsten Graul /* always reject more links for now */ 2822a4c57a9SKarsten Graul addllc->hd.flags |= SMC_LLC_FLAG_ADD_LNK_REJ; 2832a4c57a9SKarsten Graul addllc->hd.add_link_rej_rsn = SMC_LLC_REJ_RSN_NO_ALT_PATH; 2842a4c57a9SKarsten Graul } 2852a4c57a9SKarsten Graul memcpy(addllc->sender_mac, mac, ETH_ALEN); 2862a4c57a9SKarsten Graul memcpy(addllc->sender_gid, gid, SMC_GID_SIZE); 2872a4c57a9SKarsten Graul } 2882a4c57a9SKarsten Graul 28952bedf37SKarsten Graul /* send ADD LINK request or response */ 2907005ada6SUrsula Braun int smc_llc_send_add_link(struct smc_link *link, u8 mac[], u8 gid[], 29152bedf37SKarsten Graul enum smc_llc_reqresp reqresp) 29252bedf37SKarsten Graul { 29352bedf37SKarsten Graul struct smc_llc_msg_add_link *addllc; 29452bedf37SKarsten Graul struct smc_wr_tx_pend_priv *pend; 29552bedf37SKarsten Graul struct smc_wr_buf *wr_buf; 29652bedf37SKarsten Graul int rc; 29752bedf37SKarsten Graul 29852bedf37SKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 29952bedf37SKarsten Graul if (rc) 30052bedf37SKarsten Graul return rc; 30152bedf37SKarsten Graul addllc = (struct smc_llc_msg_add_link *)wr_buf; 3022a4c57a9SKarsten Graul smc_llc_prep_add_link(addllc, link, mac, gid, reqresp); 30352bedf37SKarsten Graul /* send llc message */ 30452bedf37SKarsten Graul rc = smc_wr_tx_send(link, pend); 30552bedf37SKarsten Graul return rc; 30652bedf37SKarsten Graul } 30752bedf37SKarsten Graul 3082a4c57a9SKarsten Graul /* prepare a delete link message */ 3092a4c57a9SKarsten Graul static void smc_llc_prep_delete_link(struct smc_llc_msg_del_link *delllc, 3102a4c57a9SKarsten Graul struct smc_link *link, 3110d18a0cbSKarsten Graul enum smc_llc_reqresp reqresp, bool orderly) 3122a4c57a9SKarsten Graul { 3132a4c57a9SKarsten Graul memset(delllc, 0, sizeof(*delllc)); 3142a4c57a9SKarsten Graul delllc->hd.common.type = SMC_LLC_DELETE_LINK; 3152a4c57a9SKarsten Graul delllc->hd.length = sizeof(struct smc_llc_msg_add_link); 3162a4c57a9SKarsten Graul if (reqresp == SMC_LLC_RESP) 3172a4c57a9SKarsten Graul delllc->hd.flags |= SMC_LLC_FLAG_RESP; 3182a4c57a9SKarsten Graul /* DEL_LINK_ALL because only 1 link supported */ 3192a4c57a9SKarsten Graul delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ALL; 3200d18a0cbSKarsten Graul if (orderly) 3212a4c57a9SKarsten Graul delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY; 3222a4c57a9SKarsten Graul delllc->link_num = link->link_id; 3232a4c57a9SKarsten Graul } 3242a4c57a9SKarsten Graul 32552bedf37SKarsten Graul /* send DELETE LINK request or response */ 32652bedf37SKarsten Graul int smc_llc_send_delete_link(struct smc_link *link, 3270d18a0cbSKarsten Graul enum smc_llc_reqresp reqresp, bool orderly) 32852bedf37SKarsten Graul { 32952bedf37SKarsten Graul struct smc_llc_msg_del_link *delllc; 33052bedf37SKarsten Graul struct smc_wr_tx_pend_priv *pend; 33152bedf37SKarsten Graul struct smc_wr_buf *wr_buf; 33252bedf37SKarsten Graul int rc; 33352bedf37SKarsten Graul 33452bedf37SKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 33552bedf37SKarsten Graul if (rc) 33652bedf37SKarsten Graul return rc; 33752bedf37SKarsten Graul delllc = (struct smc_llc_msg_del_link *)wr_buf; 3380d18a0cbSKarsten Graul smc_llc_prep_delete_link(delllc, link, reqresp, orderly); 3399bf9abeaSUrsula Braun /* send llc message */ 3409bf9abeaSUrsula Braun rc = smc_wr_tx_send(link, pend); 3419bf9abeaSUrsula Braun return rc; 3429bf9abeaSUrsula Braun } 3439bf9abeaSUrsula Braun 344d97935faSKarsten Graul /* send LLC test link request */ 345d97935faSKarsten Graul static int smc_llc_send_test_link(struct smc_link *link, u8 user_data[16]) 346313164daSKarsten Graul { 347313164daSKarsten Graul struct smc_llc_msg_test_link *testllc; 348313164daSKarsten Graul struct smc_wr_tx_pend_priv *pend; 349313164daSKarsten Graul struct smc_wr_buf *wr_buf; 350313164daSKarsten Graul int rc; 351313164daSKarsten Graul 352313164daSKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 353313164daSKarsten Graul if (rc) 354313164daSKarsten Graul return rc; 355313164daSKarsten Graul testllc = (struct smc_llc_msg_test_link *)wr_buf; 356313164daSKarsten Graul memset(testllc, 0, sizeof(*testllc)); 357313164daSKarsten Graul testllc->hd.common.type = SMC_LLC_TEST_LINK; 358313164daSKarsten Graul testllc->hd.length = sizeof(struct smc_llc_msg_test_link); 359313164daSKarsten Graul memcpy(testllc->user_data, user_data, sizeof(testllc->user_data)); 360313164daSKarsten Graul /* send llc message */ 361313164daSKarsten Graul rc = smc_wr_tx_send(link, pend); 362313164daSKarsten Graul return rc; 363313164daSKarsten Graul } 364313164daSKarsten Graul 3656c8968c4SKarsten Graul /* schedule an llc send on link, may wait for buffers */ 3666c8968c4SKarsten Graul static int smc_llc_send_message(struct smc_link *link, void *llcbuf) 3674ed75de5SKarsten Graul { 3684ed75de5SKarsten Graul struct smc_wr_tx_pend_priv *pend; 3694ed75de5SKarsten Graul struct smc_wr_buf *wr_buf; 3704ed75de5SKarsten Graul int rc; 3714ed75de5SKarsten Graul 3726c8968c4SKarsten Graul if (!smc_link_usable(link)) 3736c8968c4SKarsten Graul return -ENOLINK; 3746c8968c4SKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 3754ed75de5SKarsten Graul if (rc) 3766c8968c4SKarsten Graul return rc; 3776c8968c4SKarsten Graul memcpy(wr_buf, llcbuf, sizeof(union smc_llc_msg)); 3786c8968c4SKarsten Graul return smc_wr_tx_send(link, pend); 3794ed75de5SKarsten Graul } 3804ed75de5SKarsten Graul 3819bf9abeaSUrsula Braun /********************************* receive ***********************************/ 3829bf9abeaSUrsula Braun 3839bf9abeaSUrsula Braun static void smc_llc_rx_confirm_link(struct smc_link *link, 3849bf9abeaSUrsula Braun struct smc_llc_msg_confirm_link *llc) 3859bf9abeaSUrsula Braun { 38600e5fb26SStefan Raspl struct smc_link_group *lgr = smc_get_lgr(link); 387ef79d439SKarsten Graul int conf_rc = 0; 3889bf9abeaSUrsula Braun 38975d320d6SKarsten Graul /* RMBE eyecatchers are not supported */ 390ef79d439SKarsten Graul if (!(llc->hd.flags & SMC_LLC_FLAG_NO_RMBE_EYEC)) 39175d320d6SKarsten Graul conf_rc = ENOTSUPP; 39275d320d6SKarsten Graul 39352bedf37SKarsten Graul if (lgr->role == SMC_CLNT && 39452bedf37SKarsten Graul link->state == SMC_LNK_ACTIVATING) { 39575d320d6SKarsten Graul link->llc_confirm_rc = conf_rc; 3969bf9abeaSUrsula Braun link->link_id = llc->link_num; 3979bf9abeaSUrsula Braun complete(&link->llc_confirm); 3989bf9abeaSUrsula Braun } 3999bf9abeaSUrsula Braun } 4009bf9abeaSUrsula Braun 40152bedf37SKarsten Graul static void smc_llc_rx_add_link(struct smc_link *link, 40252bedf37SKarsten Graul struct smc_llc_msg_add_link *llc) 40352bedf37SKarsten Graul { 40400e5fb26SStefan Raspl struct smc_link_group *lgr = smc_get_lgr(link); 40552bedf37SKarsten Graul 40652bedf37SKarsten Graul if (link->state == SMC_LNK_ACTIVATING) { 40752bedf37SKarsten Graul complete(&link->llc_add); 40852bedf37SKarsten Graul return; 40952bedf37SKarsten Graul } 41052bedf37SKarsten Graul 41152bedf37SKarsten Graul if (lgr->role == SMC_SERV) { 4122a4c57a9SKarsten Graul smc_llc_prep_add_link(llc, link, 41352bedf37SKarsten Graul link->smcibdev->mac[link->ibport - 1], 4147005ada6SUrsula Braun link->gid, SMC_LLC_REQ); 41552bedf37SKarsten Graul 41652bedf37SKarsten Graul } else { 4172a4c57a9SKarsten Graul smc_llc_prep_add_link(llc, link, 41852bedf37SKarsten Graul link->smcibdev->mac[link->ibport - 1], 4197005ada6SUrsula Braun link->gid, SMC_LLC_RESP); 42052bedf37SKarsten Graul } 4216c8968c4SKarsten Graul smc_llc_send_message(link, llc); 42252bedf37SKarsten Graul } 42352bedf37SKarsten Graul 42452bedf37SKarsten Graul static void smc_llc_rx_delete_link(struct smc_link *link, 42552bedf37SKarsten Graul struct smc_llc_msg_del_link *llc) 42652bedf37SKarsten Graul { 42700e5fb26SStefan Raspl struct smc_link_group *lgr = smc_get_lgr(link); 42852bedf37SKarsten Graul 4299651b934SKarsten Graul smc_lgr_forget(lgr); 4300d18a0cbSKarsten Graul smc_llc_link_deleting(link); 4310d18a0cbSKarsten Graul if (lgr->role == SMC_SERV) { 4320d18a0cbSKarsten Graul /* client asks to delete this link, send request */ 4330d18a0cbSKarsten Graul smc_llc_prep_delete_link(llc, link, SMC_LLC_REQ, true); 43452bedf37SKarsten Graul } else { 4350d18a0cbSKarsten Graul /* server requests to delete this link, send response */ 4360d18a0cbSKarsten Graul smc_llc_prep_delete_link(llc, link, SMC_LLC_RESP, true); 43752bedf37SKarsten Graul } 4386c8968c4SKarsten Graul smc_llc_send_message(link, llc); 439f528ba24SUrsula Braun smc_lgr_terminate_sched(lgr); 44052bedf37SKarsten Graul } 44152bedf37SKarsten Graul 442313164daSKarsten Graul static void smc_llc_rx_test_link(struct smc_link *link, 443313164daSKarsten Graul struct smc_llc_msg_test_link *llc) 444313164daSKarsten Graul { 445d97935faSKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RESP; 4466c8968c4SKarsten Graul smc_llc_send_message(link, llc); 447313164daSKarsten Graul } 448313164daSKarsten Graul 4494ed75de5SKarsten Graul static void smc_llc_rx_confirm_rkey(struct smc_link *link, 4504ed75de5SKarsten Graul struct smc_llc_msg_confirm_rkey *llc) 4514ed75de5SKarsten Graul { 4524ed75de5SKarsten Graul int rc; 4534ed75de5SKarsten Graul 454387707fdSKarsten Graul rc = smc_rtoken_add(link, 4554ed75de5SKarsten Graul llc->rtoken[0].rmb_vaddr, 4564ed75de5SKarsten Graul llc->rtoken[0].rmb_key); 4574ed75de5SKarsten Graul 4584ed75de5SKarsten Graul /* ignore rtokens for other links, we have only one link */ 4594ed75de5SKarsten Graul 4604ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RESP; 4614ed75de5SKarsten Graul if (rc < 0) 4624ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG; 4636c8968c4SKarsten Graul smc_llc_send_message(link, llc); 4644ed75de5SKarsten Graul } 4654ed75de5SKarsten Graul 4664ed75de5SKarsten Graul static void smc_llc_rx_confirm_rkey_cont(struct smc_link *link, 4674ed75de5SKarsten Graul struct smc_llc_msg_confirm_rkey_cont *llc) 4684ed75de5SKarsten Graul { 4694ed75de5SKarsten Graul /* ignore rtokens for other links, we have only one link */ 4704ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RESP; 4716c8968c4SKarsten Graul smc_llc_send_message(link, llc); 4724ed75de5SKarsten Graul } 4734ed75de5SKarsten Graul 4744ed75de5SKarsten Graul static void smc_llc_rx_delete_rkey(struct smc_link *link, 4754ed75de5SKarsten Graul struct smc_llc_msg_delete_rkey *llc) 4764ed75de5SKarsten Graul { 4774ed75de5SKarsten Graul u8 err_mask = 0; 4784ed75de5SKarsten Graul int i, max; 4794ed75de5SKarsten Graul 4804ed75de5SKarsten Graul max = min_t(u8, llc->num_rkeys, SMC_LLC_DEL_RKEY_MAX); 4814ed75de5SKarsten Graul for (i = 0; i < max; i++) { 482387707fdSKarsten Graul if (smc_rtoken_delete(link, llc->rkey[i])) 4834ed75de5SKarsten Graul err_mask |= 1 << (SMC_LLC_DEL_RKEY_MAX - 1 - i); 4844ed75de5SKarsten Graul } 4854ed75de5SKarsten Graul 4864ed75de5SKarsten Graul if (err_mask) { 4874ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG; 4884ed75de5SKarsten Graul llc->err_mask = err_mask; 4894ed75de5SKarsten Graul } 4904ed75de5SKarsten Graul 4914ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RESP; 4926c8968c4SKarsten Graul smc_llc_send_message(link, llc); 4934ed75de5SKarsten Graul } 4944ed75de5SKarsten Graul 4956c8968c4SKarsten Graul /* flush the llc event queue */ 496*00a049cfSKarsten Graul static void smc_llc_event_flush(struct smc_link_group *lgr) 4979bf9abeaSUrsula Braun { 4986c8968c4SKarsten Graul struct smc_llc_qentry *qentry, *q; 4999bf9abeaSUrsula Braun 5006c8968c4SKarsten Graul spin_lock_bh(&lgr->llc_event_q_lock); 5016c8968c4SKarsten Graul list_for_each_entry_safe(qentry, q, &lgr->llc_event_q, list) { 5026c8968c4SKarsten Graul list_del_init(&qentry->list); 5036c8968c4SKarsten Graul kfree(qentry); 5046c8968c4SKarsten Graul } 5056c8968c4SKarsten Graul spin_unlock_bh(&lgr->llc_event_q_lock); 5066c8968c4SKarsten Graul } 5076c8968c4SKarsten Graul 5086c8968c4SKarsten Graul static void smc_llc_event_handler(struct smc_llc_qentry *qentry) 5096c8968c4SKarsten Graul { 5106c8968c4SKarsten Graul union smc_llc_msg *llc = &qentry->msg; 5116c8968c4SKarsten Graul struct smc_link *link = qentry->link; 5126c8968c4SKarsten Graul 513d854fcbfSKarsten Graul if (!smc_link_usable(link)) 5146c8968c4SKarsten Graul goto out; 515313164daSKarsten Graul 516313164daSKarsten Graul switch (llc->raw.hdr.common.type) { 517313164daSKarsten Graul case SMC_LLC_TEST_LINK: 518313164daSKarsten Graul smc_llc_rx_test_link(link, &llc->test_link); 519313164daSKarsten Graul break; 520313164daSKarsten Graul case SMC_LLC_CONFIRM_LINK: 5219bf9abeaSUrsula Braun smc_llc_rx_confirm_link(link, &llc->confirm_link); 522313164daSKarsten Graul break; 52352bedf37SKarsten Graul case SMC_LLC_ADD_LINK: 52452bedf37SKarsten Graul smc_llc_rx_add_link(link, &llc->add_link); 52552bedf37SKarsten Graul break; 52652bedf37SKarsten Graul case SMC_LLC_DELETE_LINK: 52752bedf37SKarsten Graul smc_llc_rx_delete_link(link, &llc->delete_link); 52852bedf37SKarsten Graul break; 5294ed75de5SKarsten Graul case SMC_LLC_CONFIRM_RKEY: 5304ed75de5SKarsten Graul smc_llc_rx_confirm_rkey(link, &llc->confirm_rkey); 5314ed75de5SKarsten Graul break; 5324ed75de5SKarsten Graul case SMC_LLC_CONFIRM_RKEY_CONT: 5334ed75de5SKarsten Graul smc_llc_rx_confirm_rkey_cont(link, &llc->confirm_rkey_cont); 5344ed75de5SKarsten Graul break; 5354ed75de5SKarsten Graul case SMC_LLC_DELETE_RKEY: 5364ed75de5SKarsten Graul smc_llc_rx_delete_rkey(link, &llc->delete_rkey); 5374ed75de5SKarsten Graul break; 538313164daSKarsten Graul } 5396c8968c4SKarsten Graul out: 5406c8968c4SKarsten Graul kfree(qentry); 5416c8968c4SKarsten Graul } 5426c8968c4SKarsten Graul 5436c8968c4SKarsten Graul /* worker to process llc messages on the event queue */ 5446c8968c4SKarsten Graul static void smc_llc_event_work(struct work_struct *work) 5456c8968c4SKarsten Graul { 5466c8968c4SKarsten Graul struct smc_link_group *lgr = container_of(work, struct smc_link_group, 5476c8968c4SKarsten Graul llc_event_work); 5486c8968c4SKarsten Graul struct smc_llc_qentry *qentry; 5496c8968c4SKarsten Graul 5506c8968c4SKarsten Graul again: 5516c8968c4SKarsten Graul spin_lock_bh(&lgr->llc_event_q_lock); 5526c8968c4SKarsten Graul if (!list_empty(&lgr->llc_event_q)) { 5536c8968c4SKarsten Graul qentry = list_first_entry(&lgr->llc_event_q, 5546c8968c4SKarsten Graul struct smc_llc_qentry, list); 5556c8968c4SKarsten Graul list_del_init(&qentry->list); 5566c8968c4SKarsten Graul spin_unlock_bh(&lgr->llc_event_q_lock); 5576c8968c4SKarsten Graul smc_llc_event_handler(qentry); 5586c8968c4SKarsten Graul goto again; 5596c8968c4SKarsten Graul } 5606c8968c4SKarsten Graul spin_unlock_bh(&lgr->llc_event_q_lock); 5616c8968c4SKarsten Graul } 5626c8968c4SKarsten Graul 563ef79d439SKarsten Graul /* process llc responses in tasklet context */ 564ef79d439SKarsten Graul static void smc_llc_rx_response(struct smc_link *link, union smc_llc_msg *llc) 565ef79d439SKarsten Graul { 566ef79d439SKarsten Graul int rc = 0; 567ef79d439SKarsten Graul 568ef79d439SKarsten Graul switch (llc->raw.hdr.common.type) { 569ef79d439SKarsten Graul case SMC_LLC_TEST_LINK: 570ef79d439SKarsten Graul if (link->state == SMC_LNK_ACTIVE) 571ef79d439SKarsten Graul complete(&link->llc_testlink_resp); 572ef79d439SKarsten Graul break; 573ef79d439SKarsten Graul case SMC_LLC_CONFIRM_LINK: 574ef79d439SKarsten Graul if (!(llc->raw.hdr.flags & SMC_LLC_FLAG_NO_RMBE_EYEC)) 575ef79d439SKarsten Graul rc = ENOTSUPP; 576ef79d439SKarsten Graul if (link->lgr->role == SMC_SERV && 577ef79d439SKarsten Graul link->state == SMC_LNK_ACTIVATING) { 578ef79d439SKarsten Graul link->llc_confirm_resp_rc = rc; 579ef79d439SKarsten Graul complete(&link->llc_confirm_resp); 580ef79d439SKarsten Graul } 581ef79d439SKarsten Graul break; 582ef79d439SKarsten Graul case SMC_LLC_ADD_LINK: 583ef79d439SKarsten Graul if (link->state == SMC_LNK_ACTIVATING) 584ef79d439SKarsten Graul complete(&link->llc_add_resp); 585ef79d439SKarsten Graul break; 586ef79d439SKarsten Graul case SMC_LLC_DELETE_LINK: 587ef79d439SKarsten Graul if (link->lgr->role == SMC_SERV) 588ef79d439SKarsten Graul smc_lgr_schedule_free_work_fast(link->lgr); 589ef79d439SKarsten Graul break; 590ef79d439SKarsten Graul case SMC_LLC_CONFIRM_RKEY: 591ef79d439SKarsten Graul link->llc_confirm_rkey_resp_rc = llc->raw.hdr.flags & 592ef79d439SKarsten Graul SMC_LLC_FLAG_RKEY_NEG; 593ef79d439SKarsten Graul complete(&link->llc_confirm_rkey_resp); 594ef79d439SKarsten Graul break; 595ef79d439SKarsten Graul case SMC_LLC_CONFIRM_RKEY_CONT: 596ef79d439SKarsten Graul /* unused as long as we don't send this type of msg */ 597ef79d439SKarsten Graul break; 598ef79d439SKarsten Graul case SMC_LLC_DELETE_RKEY: 599ef79d439SKarsten Graul link->llc_delete_rkey_resp_rc = llc->raw.hdr.flags & 600ef79d439SKarsten Graul SMC_LLC_FLAG_RKEY_NEG; 601ef79d439SKarsten Graul complete(&link->llc_delete_rkey_resp); 602ef79d439SKarsten Graul break; 603ef79d439SKarsten Graul } 604ef79d439SKarsten Graul } 605ef79d439SKarsten Graul 6066c8968c4SKarsten Graul /* copy received msg and add it to the event queue */ 6076c8968c4SKarsten Graul static void smc_llc_rx_handler(struct ib_wc *wc, void *buf) 6086c8968c4SKarsten Graul { 6096c8968c4SKarsten Graul struct smc_link *link = (struct smc_link *)wc->qp->qp_context; 6106c8968c4SKarsten Graul struct smc_link_group *lgr = link->lgr; 6116c8968c4SKarsten Graul struct smc_llc_qentry *qentry; 6126c8968c4SKarsten Graul union smc_llc_msg *llc = buf; 6136c8968c4SKarsten Graul unsigned long flags; 6146c8968c4SKarsten Graul 6156c8968c4SKarsten Graul if (wc->byte_len < sizeof(*llc)) 6166c8968c4SKarsten Graul return; /* short message */ 6176c8968c4SKarsten Graul if (llc->raw.hdr.length != sizeof(*llc)) 6186c8968c4SKarsten Graul return; /* invalid message */ 6196c8968c4SKarsten Graul 620ef79d439SKarsten Graul /* process responses immediately */ 621ef79d439SKarsten Graul if (llc->raw.hdr.flags & SMC_LLC_FLAG_RESP) { 622ef79d439SKarsten Graul smc_llc_rx_response(link, llc); 623ef79d439SKarsten Graul return; 624ef79d439SKarsten Graul } 625ef79d439SKarsten Graul 6266c8968c4SKarsten Graul qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC); 6276c8968c4SKarsten Graul if (!qentry) 6286c8968c4SKarsten Graul return; 6296c8968c4SKarsten Graul qentry->link = link; 6306c8968c4SKarsten Graul INIT_LIST_HEAD(&qentry->list); 6316c8968c4SKarsten Graul memcpy(&qentry->msg, llc, sizeof(union smc_llc_msg)); 6326c8968c4SKarsten Graul spin_lock_irqsave(&lgr->llc_event_q_lock, flags); 6336c8968c4SKarsten Graul list_add_tail(&qentry->list, &lgr->llc_event_q); 6346c8968c4SKarsten Graul spin_unlock_irqrestore(&lgr->llc_event_q_lock, flags); 6356c8968c4SKarsten Graul schedule_work(&link->lgr->llc_event_work); 6369bf9abeaSUrsula Braun } 6379bf9abeaSUrsula Braun 63844aa81ceSKarsten Graul /***************************** worker, utils *********************************/ 639877ae5beSKarsten Graul 640877ae5beSKarsten Graul static void smc_llc_testlink_work(struct work_struct *work) 641877ae5beSKarsten Graul { 642877ae5beSKarsten Graul struct smc_link *link = container_of(to_delayed_work(work), 643877ae5beSKarsten Graul struct smc_link, llc_testlink_wrk); 644877ae5beSKarsten Graul unsigned long next_interval; 645877ae5beSKarsten Graul unsigned long expire_time; 646877ae5beSKarsten Graul u8 user_data[16] = { 0 }; 647877ae5beSKarsten Graul int rc; 648877ae5beSKarsten Graul 649877ae5beSKarsten Graul if (link->state != SMC_LNK_ACTIVE) 650877ae5beSKarsten Graul return; /* don't reschedule worker */ 651877ae5beSKarsten Graul expire_time = link->wr_rx_tstamp + link->llc_testlink_time; 652877ae5beSKarsten Graul if (time_is_after_jiffies(expire_time)) { 653877ae5beSKarsten Graul next_interval = expire_time - jiffies; 654877ae5beSKarsten Graul goto out; 655877ae5beSKarsten Graul } 656877ae5beSKarsten Graul reinit_completion(&link->llc_testlink_resp); 657d97935faSKarsten Graul smc_llc_send_test_link(link, user_data); 658877ae5beSKarsten Graul /* receive TEST LINK response over RoCE fabric */ 659877ae5beSKarsten Graul rc = wait_for_completion_interruptible_timeout(&link->llc_testlink_resp, 660877ae5beSKarsten Graul SMC_LLC_WAIT_TIME); 6611020e1efSKarsten Graul if (link->state != SMC_LNK_ACTIVE) 6621020e1efSKarsten Graul return; /* link state changed */ 663877ae5beSKarsten Graul if (rc <= 0) { 6645f78fe96SKarsten Graul smc_lgr_terminate_sched(smc_get_lgr(link)); 665877ae5beSKarsten Graul return; 666877ae5beSKarsten Graul } 667877ae5beSKarsten Graul next_interval = link->llc_testlink_time; 668877ae5beSKarsten Graul out: 6691020e1efSKarsten Graul schedule_delayed_work(&link->llc_testlink_wrk, next_interval); 670877ae5beSKarsten Graul } 671877ae5beSKarsten Graul 672*00a049cfSKarsten Graul void smc_llc_lgr_init(struct smc_link_group *lgr, struct smc_sock *smc) 673*00a049cfSKarsten Graul { 674*00a049cfSKarsten Graul struct net *net = sock_net(smc->clcsock->sk); 675*00a049cfSKarsten Graul 676*00a049cfSKarsten Graul INIT_WORK(&lgr->llc_event_work, smc_llc_event_work); 677*00a049cfSKarsten Graul INIT_LIST_HEAD(&lgr->llc_event_q); 678*00a049cfSKarsten Graul spin_lock_init(&lgr->llc_event_q_lock); 679*00a049cfSKarsten Graul lgr->llc_testlink_time = net->ipv4.sysctl_tcp_keepalive_time; 680*00a049cfSKarsten Graul } 681*00a049cfSKarsten Graul 682*00a049cfSKarsten Graul /* called after lgr was removed from lgr_list */ 683*00a049cfSKarsten Graul void smc_llc_lgr_clear(struct smc_link_group *lgr) 684*00a049cfSKarsten Graul { 685*00a049cfSKarsten Graul smc_llc_event_flush(lgr); 686*00a049cfSKarsten Graul cancel_work_sync(&lgr->llc_event_work); 687*00a049cfSKarsten Graul } 688*00a049cfSKarsten Graul 6892a4c57a9SKarsten Graul int smc_llc_link_init(struct smc_link *link) 690877ae5beSKarsten Graul { 691b32cf4abSKarsten Graul init_completion(&link->llc_confirm); 692b32cf4abSKarsten Graul init_completion(&link->llc_confirm_resp); 693b32cf4abSKarsten Graul init_completion(&link->llc_add); 694b32cf4abSKarsten Graul init_completion(&link->llc_add_resp); 695ef79d439SKarsten Graul init_completion(&link->llc_confirm_rkey_resp); 696ef79d439SKarsten Graul init_completion(&link->llc_delete_rkey_resp); 69760e03c62SKarsten Graul mutex_init(&link->llc_delete_rkey_mutex); 698877ae5beSKarsten Graul init_completion(&link->llc_testlink_resp); 699877ae5beSKarsten Graul INIT_DELAYED_WORK(&link->llc_testlink_wrk, smc_llc_testlink_work); 7002a4c57a9SKarsten Graul return 0; 701b32cf4abSKarsten Graul } 702b32cf4abSKarsten Graul 703*00a049cfSKarsten Graul void smc_llc_link_active(struct smc_link *link) 704b32cf4abSKarsten Graul { 705877ae5beSKarsten Graul link->state = SMC_LNK_ACTIVE; 706*00a049cfSKarsten Graul if (link->lgr->llc_testlink_time) { 707*00a049cfSKarsten Graul link->llc_testlink_time = link->lgr->llc_testlink_time * HZ; 7081020e1efSKarsten Graul schedule_delayed_work(&link->llc_testlink_wrk, 709877ae5beSKarsten Graul link->llc_testlink_time); 710877ae5beSKarsten Graul } 711877ae5beSKarsten Graul } 712877ae5beSKarsten Graul 7130d18a0cbSKarsten Graul void smc_llc_link_deleting(struct smc_link *link) 7140d18a0cbSKarsten Graul { 7150d18a0cbSKarsten Graul link->state = SMC_LNK_DELETING; 71615e1b99aSUrsula Braun smc_wr_wakeup_tx_wait(link); 7170d18a0cbSKarsten Graul } 7180d18a0cbSKarsten Graul 719877ae5beSKarsten Graul /* called in worker context */ 7202a4c57a9SKarsten Graul void smc_llc_link_clear(struct smc_link *link) 721877ae5beSKarsten Graul { 7222140ac26SKarsten Graul complete(&link->llc_testlink_resp); 7232140ac26SKarsten Graul cancel_delayed_work_sync(&link->llc_testlink_wrk); 7242140ac26SKarsten Graul smc_wr_wakeup_reg_wait(link); 7252140ac26SKarsten Graul smc_wr_wakeup_tx_wait(link); 726877ae5beSKarsten Graul } 727877ae5beSKarsten Graul 72844aa81ceSKarsten Graul /* register a new rtoken at the remote peer */ 72944aa81ceSKarsten Graul int smc_llc_do_confirm_rkey(struct smc_link *link, 73044aa81ceSKarsten Graul struct smc_buf_desc *rmb_desc) 73144aa81ceSKarsten Graul { 73244aa81ceSKarsten Graul int rc; 73344aa81ceSKarsten Graul 73460e03c62SKarsten Graul /* protected by mutex smc_create_lgr_pending */ 735ef79d439SKarsten Graul reinit_completion(&link->llc_confirm_rkey_resp); 7364600cfc3SKarsten Graul rc = smc_llc_send_confirm_rkey(link, rmb_desc); 7374600cfc3SKarsten Graul if (rc) 7384600cfc3SKarsten Graul return rc; 73944aa81ceSKarsten Graul /* receive CONFIRM RKEY response from server over RoCE fabric */ 740ef79d439SKarsten Graul rc = wait_for_completion_interruptible_timeout( 741ef79d439SKarsten Graul &link->llc_confirm_rkey_resp, SMC_LLC_WAIT_TIME); 742ef79d439SKarsten Graul if (rc <= 0 || link->llc_confirm_rkey_resp_rc) 74344aa81ceSKarsten Graul return -EFAULT; 74444aa81ceSKarsten Graul return 0; 74544aa81ceSKarsten Graul } 74644aa81ceSKarsten Graul 74760e03c62SKarsten Graul /* unregister an rtoken at the remote peer */ 74860e03c62SKarsten Graul int smc_llc_do_delete_rkey(struct smc_link *link, 74960e03c62SKarsten Graul struct smc_buf_desc *rmb_desc) 75060e03c62SKarsten Graul { 7510b29ec64SUrsula Braun int rc = 0; 75260e03c62SKarsten Graul 75360e03c62SKarsten Graul mutex_lock(&link->llc_delete_rkey_mutex); 7540b29ec64SUrsula Braun if (link->state != SMC_LNK_ACTIVE) 7550b29ec64SUrsula Braun goto out; 756ef79d439SKarsten Graul reinit_completion(&link->llc_delete_rkey_resp); 75760e03c62SKarsten Graul rc = smc_llc_send_delete_rkey(link, rmb_desc); 75860e03c62SKarsten Graul if (rc) 75960e03c62SKarsten Graul goto out; 76060e03c62SKarsten Graul /* receive DELETE RKEY response from server over RoCE fabric */ 761ef79d439SKarsten Graul rc = wait_for_completion_interruptible_timeout( 762ef79d439SKarsten Graul &link->llc_delete_rkey_resp, SMC_LLC_WAIT_TIME); 763ef79d439SKarsten Graul if (rc <= 0 || link->llc_delete_rkey_resp_rc) 76460e03c62SKarsten Graul rc = -EFAULT; 76560e03c62SKarsten Graul else 76660e03c62SKarsten Graul rc = 0; 76760e03c62SKarsten Graul out: 76860e03c62SKarsten Graul mutex_unlock(&link->llc_delete_rkey_mutex); 76960e03c62SKarsten Graul return rc; 77060e03c62SKarsten Graul } 77160e03c62SKarsten Graul 7729bf9abeaSUrsula Braun /***************************** init, exit, misc ******************************/ 7739bf9abeaSUrsula Braun 7749bf9abeaSUrsula Braun static struct smc_wr_rx_handler smc_llc_rx_handlers[] = { 7759bf9abeaSUrsula Braun { 7769bf9abeaSUrsula Braun .handler = smc_llc_rx_handler, 7779bf9abeaSUrsula Braun .type = SMC_LLC_CONFIRM_LINK 7789bf9abeaSUrsula Braun }, 7799bf9abeaSUrsula Braun { 780313164daSKarsten Graul .handler = smc_llc_rx_handler, 781313164daSKarsten Graul .type = SMC_LLC_TEST_LINK 782313164daSKarsten Graul }, 783313164daSKarsten Graul { 7844ed75de5SKarsten Graul .handler = smc_llc_rx_handler, 78552bedf37SKarsten Graul .type = SMC_LLC_ADD_LINK 78652bedf37SKarsten Graul }, 78752bedf37SKarsten Graul { 78852bedf37SKarsten Graul .handler = smc_llc_rx_handler, 78952bedf37SKarsten Graul .type = SMC_LLC_DELETE_LINK 79052bedf37SKarsten Graul }, 79152bedf37SKarsten Graul { 79252bedf37SKarsten Graul .handler = smc_llc_rx_handler, 7934ed75de5SKarsten Graul .type = SMC_LLC_CONFIRM_RKEY 7944ed75de5SKarsten Graul }, 7954ed75de5SKarsten Graul { 7964ed75de5SKarsten Graul .handler = smc_llc_rx_handler, 7974ed75de5SKarsten Graul .type = SMC_LLC_CONFIRM_RKEY_CONT 7984ed75de5SKarsten Graul }, 7994ed75de5SKarsten Graul { 8004ed75de5SKarsten Graul .handler = smc_llc_rx_handler, 8014ed75de5SKarsten Graul .type = SMC_LLC_DELETE_RKEY 8024ed75de5SKarsten Graul }, 8034ed75de5SKarsten Graul { 8049bf9abeaSUrsula Braun .handler = NULL, 8059bf9abeaSUrsula Braun } 8069bf9abeaSUrsula Braun }; 8079bf9abeaSUrsula Braun 8089bf9abeaSUrsula Braun int __init smc_llc_init(void) 8099bf9abeaSUrsula Braun { 8109bf9abeaSUrsula Braun struct smc_wr_rx_handler *handler; 8119bf9abeaSUrsula Braun int rc = 0; 8129bf9abeaSUrsula Braun 8139bf9abeaSUrsula Braun for (handler = smc_llc_rx_handlers; handler->handler; handler++) { 8149bf9abeaSUrsula Braun INIT_HLIST_NODE(&handler->list); 8159bf9abeaSUrsula Braun rc = smc_wr_rx_register_handler(handler); 8169bf9abeaSUrsula Braun if (rc) 8179bf9abeaSUrsula Braun break; 8189bf9abeaSUrsula Braun } 8199bf9abeaSUrsula Braun return rc; 8209bf9abeaSUrsula Braun } 821