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 143*555da9afSKarsten Graul struct smc_llc_qentry *smc_llc_flow_qentry_clr(struct smc_llc_flow *flow) 144*555da9afSKarsten Graul { 145*555da9afSKarsten Graul struct smc_llc_qentry *qentry = flow->qentry; 146*555da9afSKarsten Graul 147*555da9afSKarsten Graul flow->qentry = NULL; 148*555da9afSKarsten Graul return qentry; 149*555da9afSKarsten Graul } 150*555da9afSKarsten Graul 151*555da9afSKarsten Graul void smc_llc_flow_qentry_del(struct smc_llc_flow *flow) 152*555da9afSKarsten Graul { 153*555da9afSKarsten Graul struct smc_llc_qentry *qentry; 154*555da9afSKarsten Graul 155*555da9afSKarsten Graul if (flow->qentry) { 156*555da9afSKarsten Graul qentry = flow->qentry; 157*555da9afSKarsten Graul flow->qentry = NULL; 158*555da9afSKarsten Graul kfree(qentry); 159*555da9afSKarsten Graul } 160*555da9afSKarsten Graul } 161*555da9afSKarsten Graul 162*555da9afSKarsten Graul static inline void smc_llc_flow_qentry_set(struct smc_llc_flow *flow, 163*555da9afSKarsten Graul struct smc_llc_qentry *qentry) 164*555da9afSKarsten Graul { 165*555da9afSKarsten Graul flow->qentry = qentry; 166*555da9afSKarsten Graul } 167*555da9afSKarsten Graul 168*555da9afSKarsten Graul /* try to start a new llc flow, initiated by an incoming llc msg */ 169*555da9afSKarsten Graul static bool smc_llc_flow_start(struct smc_llc_flow *flow, 170*555da9afSKarsten Graul struct smc_llc_qentry *qentry) 171*555da9afSKarsten Graul { 172*555da9afSKarsten Graul struct smc_link_group *lgr = qentry->link->lgr; 173*555da9afSKarsten Graul 174*555da9afSKarsten Graul spin_lock_bh(&lgr->llc_flow_lock); 175*555da9afSKarsten Graul if (flow->type) { 176*555da9afSKarsten Graul /* a flow is already active */ 177*555da9afSKarsten Graul if ((qentry->msg.raw.hdr.common.type == SMC_LLC_ADD_LINK || 178*555da9afSKarsten Graul qentry->msg.raw.hdr.common.type == SMC_LLC_DELETE_LINK) && 179*555da9afSKarsten Graul !lgr->delayed_event) { 180*555da9afSKarsten Graul lgr->delayed_event = qentry; 181*555da9afSKarsten Graul } else { 182*555da9afSKarsten Graul /* forget this llc request */ 183*555da9afSKarsten Graul kfree(qentry); 184*555da9afSKarsten Graul } 185*555da9afSKarsten Graul spin_unlock_bh(&lgr->llc_flow_lock); 186*555da9afSKarsten Graul return false; 187*555da9afSKarsten Graul } 188*555da9afSKarsten Graul switch (qentry->msg.raw.hdr.common.type) { 189*555da9afSKarsten Graul case SMC_LLC_ADD_LINK: 190*555da9afSKarsten Graul flow->type = SMC_LLC_FLOW_ADD_LINK; 191*555da9afSKarsten Graul break; 192*555da9afSKarsten Graul case SMC_LLC_DELETE_LINK: 193*555da9afSKarsten Graul flow->type = SMC_LLC_FLOW_DEL_LINK; 194*555da9afSKarsten Graul break; 195*555da9afSKarsten Graul case SMC_LLC_CONFIRM_RKEY: 196*555da9afSKarsten Graul case SMC_LLC_DELETE_RKEY: 197*555da9afSKarsten Graul flow->type = SMC_LLC_FLOW_RKEY; 198*555da9afSKarsten Graul break; 199*555da9afSKarsten Graul default: 200*555da9afSKarsten Graul flow->type = SMC_LLC_FLOW_NONE; 201*555da9afSKarsten Graul } 202*555da9afSKarsten Graul if (qentry == lgr->delayed_event) 203*555da9afSKarsten Graul lgr->delayed_event = NULL; 204*555da9afSKarsten Graul spin_unlock_bh(&lgr->llc_flow_lock); 205*555da9afSKarsten Graul smc_llc_flow_qentry_set(flow, qentry); 206*555da9afSKarsten Graul return true; 207*555da9afSKarsten Graul } 208*555da9afSKarsten Graul 209*555da9afSKarsten Graul /* start a new local llc flow, wait till current flow finished */ 210*555da9afSKarsten Graul int smc_llc_flow_initiate(struct smc_link_group *lgr, 211*555da9afSKarsten Graul enum smc_llc_flowtype type) 212*555da9afSKarsten Graul { 213*555da9afSKarsten Graul enum smc_llc_flowtype allowed_remote = SMC_LLC_FLOW_NONE; 214*555da9afSKarsten Graul int rc; 215*555da9afSKarsten Graul 216*555da9afSKarsten Graul /* all flows except confirm_rkey and delete_rkey are exclusive, 217*555da9afSKarsten Graul * confirm/delete rkey flows can run concurrently (local and remote) 218*555da9afSKarsten Graul */ 219*555da9afSKarsten Graul if (type == SMC_LLC_FLOW_RKEY) 220*555da9afSKarsten Graul allowed_remote = SMC_LLC_FLOW_RKEY; 221*555da9afSKarsten Graul again: 222*555da9afSKarsten Graul if (list_empty(&lgr->list)) 223*555da9afSKarsten Graul return -ENODEV; 224*555da9afSKarsten Graul spin_lock_bh(&lgr->llc_flow_lock); 225*555da9afSKarsten Graul if (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_NONE && 226*555da9afSKarsten Graul (lgr->llc_flow_rmt.type == SMC_LLC_FLOW_NONE || 227*555da9afSKarsten Graul lgr->llc_flow_rmt.type == allowed_remote)) { 228*555da9afSKarsten Graul lgr->llc_flow_lcl.type = type; 229*555da9afSKarsten Graul spin_unlock_bh(&lgr->llc_flow_lock); 230*555da9afSKarsten Graul return 0; 231*555da9afSKarsten Graul } 232*555da9afSKarsten Graul spin_unlock_bh(&lgr->llc_flow_lock); 233*555da9afSKarsten Graul rc = wait_event_interruptible_timeout(lgr->llc_waiter, 234*555da9afSKarsten Graul (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_NONE && 235*555da9afSKarsten Graul (lgr->llc_flow_rmt.type == SMC_LLC_FLOW_NONE || 236*555da9afSKarsten Graul lgr->llc_flow_rmt.type == allowed_remote)), 237*555da9afSKarsten Graul SMC_LLC_WAIT_TIME); 238*555da9afSKarsten Graul if (!rc) 239*555da9afSKarsten Graul return -ETIMEDOUT; 240*555da9afSKarsten Graul goto again; 241*555da9afSKarsten Graul } 242*555da9afSKarsten Graul 243*555da9afSKarsten Graul /* finish the current llc flow */ 244*555da9afSKarsten Graul void smc_llc_flow_stop(struct smc_link_group *lgr, struct smc_llc_flow *flow) 245*555da9afSKarsten Graul { 246*555da9afSKarsten Graul spin_lock_bh(&lgr->llc_flow_lock); 247*555da9afSKarsten Graul memset(flow, 0, sizeof(*flow)); 248*555da9afSKarsten Graul flow->type = SMC_LLC_FLOW_NONE; 249*555da9afSKarsten Graul spin_unlock_bh(&lgr->llc_flow_lock); 250*555da9afSKarsten Graul if (!list_empty(&lgr->list) && lgr->delayed_event && 251*555da9afSKarsten Graul flow == &lgr->llc_flow_lcl) 252*555da9afSKarsten Graul schedule_work(&lgr->llc_event_work); 253*555da9afSKarsten Graul else 254*555da9afSKarsten Graul wake_up_interruptible(&lgr->llc_waiter); 255*555da9afSKarsten Graul } 256*555da9afSKarsten Graul 257*555da9afSKarsten Graul /* lnk is optional and used for early wakeup when link goes down, useful in 258*555da9afSKarsten Graul * cases where we wait for a response on the link after we sent a request 259*555da9afSKarsten Graul */ 260*555da9afSKarsten Graul struct smc_llc_qentry *smc_llc_wait(struct smc_link_group *lgr, 261*555da9afSKarsten Graul struct smc_link *lnk, 262*555da9afSKarsten Graul int time_out, u8 exp_msg) 263*555da9afSKarsten Graul { 264*555da9afSKarsten Graul struct smc_llc_flow *flow = &lgr->llc_flow_lcl; 265*555da9afSKarsten Graul 266*555da9afSKarsten Graul wait_event_interruptible_timeout(lgr->llc_waiter, 267*555da9afSKarsten Graul (flow->qentry || 268*555da9afSKarsten Graul (lnk && !smc_link_usable(lnk)) || 269*555da9afSKarsten Graul list_empty(&lgr->list)), 270*555da9afSKarsten Graul time_out); 271*555da9afSKarsten Graul if (!flow->qentry || 272*555da9afSKarsten Graul (lnk && !smc_link_usable(lnk)) || list_empty(&lgr->list)) { 273*555da9afSKarsten Graul smc_llc_flow_qentry_del(flow); 274*555da9afSKarsten Graul goto out; 275*555da9afSKarsten Graul } 276*555da9afSKarsten Graul if (exp_msg && flow->qentry->msg.raw.hdr.common.type != exp_msg) { 277*555da9afSKarsten Graul if (exp_msg == SMC_LLC_ADD_LINK && 278*555da9afSKarsten Graul flow->qentry->msg.raw.hdr.common.type == 279*555da9afSKarsten Graul SMC_LLC_DELETE_LINK) { 280*555da9afSKarsten Graul /* flow_start will delay the unexpected msg */ 281*555da9afSKarsten Graul smc_llc_flow_start(&lgr->llc_flow_lcl, 282*555da9afSKarsten Graul smc_llc_flow_qentry_clr(flow)); 283*555da9afSKarsten Graul return NULL; 284*555da9afSKarsten Graul } 285*555da9afSKarsten Graul smc_llc_flow_qentry_del(flow); 286*555da9afSKarsten Graul } 287*555da9afSKarsten Graul out: 288*555da9afSKarsten Graul return flow->qentry; 289*555da9afSKarsten Graul } 290*555da9afSKarsten Graul 2919bf9abeaSUrsula Braun /********************************** send *************************************/ 2929bf9abeaSUrsula Braun 2939bf9abeaSUrsula Braun struct smc_llc_tx_pend { 2949bf9abeaSUrsula Braun }; 2959bf9abeaSUrsula Braun 2969bf9abeaSUrsula Braun /* handler for send/transmission completion of an LLC msg */ 2979bf9abeaSUrsula Braun static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv *pend, 2989bf9abeaSUrsula Braun struct smc_link *link, 2999bf9abeaSUrsula Braun enum ib_wc_status wc_status) 3009bf9abeaSUrsula Braun { 3019bf9abeaSUrsula Braun /* future work: handle wc_status error for recovery and failover */ 3029bf9abeaSUrsula Braun } 3039bf9abeaSUrsula Braun 3049bf9abeaSUrsula Braun /** 3059bf9abeaSUrsula Braun * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits 3069bf9abeaSUrsula Braun * @link: Pointer to SMC link used for sending LLC control message. 3079bf9abeaSUrsula Braun * @wr_buf: Out variable returning pointer to work request payload buffer. 3089bf9abeaSUrsula Braun * @pend: Out variable returning pointer to private pending WR tracking. 3099bf9abeaSUrsula Braun * It's the context the transmit complete handler will get. 3109bf9abeaSUrsula Braun * 3119bf9abeaSUrsula Braun * Reserves and pre-fills an entry for a pending work request send/tx. 3129bf9abeaSUrsula Braun * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx. 3139bf9abeaSUrsula Braun * Can sleep due to smc_get_ctrl_buf (if not in softirq context). 3149bf9abeaSUrsula Braun * 3159bf9abeaSUrsula Braun * Return: 0 on success, otherwise an error value. 3169bf9abeaSUrsula Braun */ 3179bf9abeaSUrsula Braun static int smc_llc_add_pending_send(struct smc_link *link, 3189bf9abeaSUrsula Braun struct smc_wr_buf **wr_buf, 3199bf9abeaSUrsula Braun struct smc_wr_tx_pend_priv **pend) 3209bf9abeaSUrsula Braun { 3219bf9abeaSUrsula Braun int rc; 3229bf9abeaSUrsula Braun 323ad6f317fSUrsula Braun rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, NULL, 324ad6f317fSUrsula Braun pend); 3259bf9abeaSUrsula Braun if (rc < 0) 3269bf9abeaSUrsula Braun return rc; 3279bf9abeaSUrsula Braun BUILD_BUG_ON_MSG( 3289bf9abeaSUrsula Braun sizeof(union smc_llc_msg) > SMC_WR_BUF_SIZE, 3299bf9abeaSUrsula Braun "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)"); 3309bf9abeaSUrsula Braun BUILD_BUG_ON_MSG( 3319bf9abeaSUrsula Braun sizeof(union smc_llc_msg) != SMC_WR_TX_SIZE, 3329bf9abeaSUrsula 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()"); 3339bf9abeaSUrsula Braun BUILD_BUG_ON_MSG( 3349bf9abeaSUrsula Braun sizeof(struct smc_llc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE, 3359bf9abeaSUrsula Braun "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)"); 3369bf9abeaSUrsula Braun return 0; 3379bf9abeaSUrsula Braun } 3389bf9abeaSUrsula Braun 3399bf9abeaSUrsula Braun /* high-level API to send LLC confirm link */ 340947541f3SUrsula Braun int smc_llc_send_confirm_link(struct smc_link *link, 3419bf9abeaSUrsula Braun enum smc_llc_reqresp reqresp) 3429bf9abeaSUrsula Braun { 34300e5fb26SStefan Raspl struct smc_link_group *lgr = smc_get_lgr(link); 3449bf9abeaSUrsula Braun struct smc_llc_msg_confirm_link *confllc; 3459bf9abeaSUrsula Braun struct smc_wr_tx_pend_priv *pend; 3469bf9abeaSUrsula Braun struct smc_wr_buf *wr_buf; 3479bf9abeaSUrsula Braun int rc; 3489bf9abeaSUrsula Braun 3499bf9abeaSUrsula Braun rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 3509bf9abeaSUrsula Braun if (rc) 3519bf9abeaSUrsula Braun return rc; 3529bf9abeaSUrsula Braun confllc = (struct smc_llc_msg_confirm_link *)wr_buf; 3539bf9abeaSUrsula Braun memset(confllc, 0, sizeof(*confllc)); 3549bf9abeaSUrsula Braun confllc->hd.common.type = SMC_LLC_CONFIRM_LINK; 3559bf9abeaSUrsula Braun confllc->hd.length = sizeof(struct smc_llc_msg_confirm_link); 35675d320d6SKarsten Graul confllc->hd.flags |= SMC_LLC_FLAG_NO_RMBE_EYEC; 3579bf9abeaSUrsula Braun if (reqresp == SMC_LLC_RESP) 3589bf9abeaSUrsula Braun confllc->hd.flags |= SMC_LLC_FLAG_RESP; 359947541f3SUrsula Braun memcpy(confllc->sender_mac, link->smcibdev->mac[link->ibport - 1], 360947541f3SUrsula Braun ETH_ALEN); 3617005ada6SUrsula Braun memcpy(confllc->sender_gid, link->gid, SMC_GID_SIZE); 3629bf9abeaSUrsula Braun hton24(confllc->sender_qp_num, link->roce_qp->qp_num); 3632be922f3SKarsten Graul confllc->link_num = link->link_id; 3649bf9abeaSUrsula Braun memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE); 36552bedf37SKarsten Graul confllc->max_links = SMC_LLC_ADD_LNK_MAX_LINKS; /* enforce peer resp. */ 36652bedf37SKarsten Graul /* send llc message */ 36752bedf37SKarsten Graul rc = smc_wr_tx_send(link, pend); 36852bedf37SKarsten Graul return rc; 36952bedf37SKarsten Graul } 37052bedf37SKarsten Graul 37144aa81ceSKarsten Graul /* send LLC confirm rkey request */ 37244aa81ceSKarsten Graul static int smc_llc_send_confirm_rkey(struct smc_link *link, 37344aa81ceSKarsten Graul struct smc_buf_desc *rmb_desc) 37444aa81ceSKarsten Graul { 37544aa81ceSKarsten Graul struct smc_llc_msg_confirm_rkey *rkeyllc; 37644aa81ceSKarsten Graul struct smc_wr_tx_pend_priv *pend; 37744aa81ceSKarsten Graul struct smc_wr_buf *wr_buf; 37844aa81ceSKarsten Graul int rc; 37944aa81ceSKarsten Graul 38044aa81ceSKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 38144aa81ceSKarsten Graul if (rc) 38244aa81ceSKarsten Graul return rc; 38344aa81ceSKarsten Graul rkeyllc = (struct smc_llc_msg_confirm_rkey *)wr_buf; 38444aa81ceSKarsten Graul memset(rkeyllc, 0, sizeof(*rkeyllc)); 38544aa81ceSKarsten Graul rkeyllc->hd.common.type = SMC_LLC_CONFIRM_RKEY; 38644aa81ceSKarsten Graul rkeyllc->hd.length = sizeof(struct smc_llc_msg_confirm_rkey); 38744aa81ceSKarsten Graul rkeyllc->rtoken[0].rmb_key = 388387707fdSKarsten Graul htonl(rmb_desc->mr_rx[link->link_idx]->rkey); 38944aa81ceSKarsten Graul rkeyllc->rtoken[0].rmb_vaddr = cpu_to_be64( 390387707fdSKarsten Graul (u64)sg_dma_address(rmb_desc->sgt[link->link_idx].sgl)); 39144aa81ceSKarsten Graul /* send llc message */ 39244aa81ceSKarsten Graul rc = smc_wr_tx_send(link, pend); 39344aa81ceSKarsten Graul return rc; 39444aa81ceSKarsten Graul } 39544aa81ceSKarsten Graul 39660e03c62SKarsten Graul /* send LLC delete rkey request */ 39760e03c62SKarsten Graul static int smc_llc_send_delete_rkey(struct smc_link *link, 39860e03c62SKarsten Graul struct smc_buf_desc *rmb_desc) 39960e03c62SKarsten Graul { 40060e03c62SKarsten Graul struct smc_llc_msg_delete_rkey *rkeyllc; 40160e03c62SKarsten Graul struct smc_wr_tx_pend_priv *pend; 40260e03c62SKarsten Graul struct smc_wr_buf *wr_buf; 40360e03c62SKarsten Graul int rc; 40460e03c62SKarsten Graul 40560e03c62SKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 40660e03c62SKarsten Graul if (rc) 40760e03c62SKarsten Graul return rc; 40860e03c62SKarsten Graul rkeyllc = (struct smc_llc_msg_delete_rkey *)wr_buf; 40960e03c62SKarsten Graul memset(rkeyllc, 0, sizeof(*rkeyllc)); 41060e03c62SKarsten Graul rkeyllc->hd.common.type = SMC_LLC_DELETE_RKEY; 41160e03c62SKarsten Graul rkeyllc->hd.length = sizeof(struct smc_llc_msg_delete_rkey); 41260e03c62SKarsten Graul rkeyllc->num_rkeys = 1; 413387707fdSKarsten Graul rkeyllc->rkey[0] = htonl(rmb_desc->mr_rx[link->link_idx]->rkey); 41460e03c62SKarsten Graul /* send llc message */ 41560e03c62SKarsten Graul rc = smc_wr_tx_send(link, pend); 41660e03c62SKarsten Graul return rc; 41760e03c62SKarsten Graul } 41860e03c62SKarsten Graul 4192a4c57a9SKarsten Graul /* prepare an add link message */ 4202a4c57a9SKarsten Graul static void smc_llc_prep_add_link(struct smc_llc_msg_add_link *addllc, 4217005ada6SUrsula Braun struct smc_link *link, u8 mac[], u8 gid[], 4222a4c57a9SKarsten Graul enum smc_llc_reqresp reqresp) 4232a4c57a9SKarsten Graul { 4242a4c57a9SKarsten Graul memset(addllc, 0, sizeof(*addllc)); 4252a4c57a9SKarsten Graul addllc->hd.common.type = SMC_LLC_ADD_LINK; 4262a4c57a9SKarsten Graul addllc->hd.length = sizeof(struct smc_llc_msg_add_link); 4272a4c57a9SKarsten Graul if (reqresp == SMC_LLC_RESP) { 4282a4c57a9SKarsten Graul addllc->hd.flags |= SMC_LLC_FLAG_RESP; 4292a4c57a9SKarsten Graul /* always reject more links for now */ 4302a4c57a9SKarsten Graul addllc->hd.flags |= SMC_LLC_FLAG_ADD_LNK_REJ; 4312a4c57a9SKarsten Graul addllc->hd.add_link_rej_rsn = SMC_LLC_REJ_RSN_NO_ALT_PATH; 4322a4c57a9SKarsten Graul } 4332a4c57a9SKarsten Graul memcpy(addllc->sender_mac, mac, ETH_ALEN); 4342a4c57a9SKarsten Graul memcpy(addllc->sender_gid, gid, SMC_GID_SIZE); 4352a4c57a9SKarsten Graul } 4362a4c57a9SKarsten Graul 43752bedf37SKarsten Graul /* send ADD LINK request or response */ 4387005ada6SUrsula Braun int smc_llc_send_add_link(struct smc_link *link, u8 mac[], u8 gid[], 43952bedf37SKarsten Graul enum smc_llc_reqresp reqresp) 44052bedf37SKarsten Graul { 44152bedf37SKarsten Graul struct smc_llc_msg_add_link *addllc; 44252bedf37SKarsten Graul struct smc_wr_tx_pend_priv *pend; 44352bedf37SKarsten Graul struct smc_wr_buf *wr_buf; 44452bedf37SKarsten Graul int rc; 44552bedf37SKarsten Graul 44652bedf37SKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 44752bedf37SKarsten Graul if (rc) 44852bedf37SKarsten Graul return rc; 44952bedf37SKarsten Graul addllc = (struct smc_llc_msg_add_link *)wr_buf; 4502a4c57a9SKarsten Graul smc_llc_prep_add_link(addllc, link, mac, gid, reqresp); 45152bedf37SKarsten Graul /* send llc message */ 45252bedf37SKarsten Graul rc = smc_wr_tx_send(link, pend); 45352bedf37SKarsten Graul return rc; 45452bedf37SKarsten Graul } 45552bedf37SKarsten Graul 4562a4c57a9SKarsten Graul /* prepare a delete link message */ 4572a4c57a9SKarsten Graul static void smc_llc_prep_delete_link(struct smc_llc_msg_del_link *delllc, 4582a4c57a9SKarsten Graul struct smc_link *link, 4590d18a0cbSKarsten Graul enum smc_llc_reqresp reqresp, bool orderly) 4602a4c57a9SKarsten Graul { 4612a4c57a9SKarsten Graul memset(delllc, 0, sizeof(*delllc)); 4622a4c57a9SKarsten Graul delllc->hd.common.type = SMC_LLC_DELETE_LINK; 4632a4c57a9SKarsten Graul delllc->hd.length = sizeof(struct smc_llc_msg_add_link); 4642a4c57a9SKarsten Graul if (reqresp == SMC_LLC_RESP) 4652a4c57a9SKarsten Graul delllc->hd.flags |= SMC_LLC_FLAG_RESP; 4662a4c57a9SKarsten Graul /* DEL_LINK_ALL because only 1 link supported */ 4672a4c57a9SKarsten Graul delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ALL; 4680d18a0cbSKarsten Graul if (orderly) 4692a4c57a9SKarsten Graul delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY; 4702a4c57a9SKarsten Graul delllc->link_num = link->link_id; 4712a4c57a9SKarsten Graul } 4722a4c57a9SKarsten Graul 47352bedf37SKarsten Graul /* send DELETE LINK request or response */ 47452bedf37SKarsten Graul int smc_llc_send_delete_link(struct smc_link *link, 4750d18a0cbSKarsten Graul enum smc_llc_reqresp reqresp, bool orderly) 47652bedf37SKarsten Graul { 47752bedf37SKarsten Graul struct smc_llc_msg_del_link *delllc; 47852bedf37SKarsten Graul struct smc_wr_tx_pend_priv *pend; 47952bedf37SKarsten Graul struct smc_wr_buf *wr_buf; 48052bedf37SKarsten Graul int rc; 48152bedf37SKarsten Graul 48252bedf37SKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 48352bedf37SKarsten Graul if (rc) 48452bedf37SKarsten Graul return rc; 48552bedf37SKarsten Graul delllc = (struct smc_llc_msg_del_link *)wr_buf; 4860d18a0cbSKarsten Graul smc_llc_prep_delete_link(delllc, link, reqresp, orderly); 4879bf9abeaSUrsula Braun /* send llc message */ 4889bf9abeaSUrsula Braun rc = smc_wr_tx_send(link, pend); 4899bf9abeaSUrsula Braun return rc; 4909bf9abeaSUrsula Braun } 4919bf9abeaSUrsula Braun 492d97935faSKarsten Graul /* send LLC test link request */ 493d97935faSKarsten Graul static int smc_llc_send_test_link(struct smc_link *link, u8 user_data[16]) 494313164daSKarsten Graul { 495313164daSKarsten Graul struct smc_llc_msg_test_link *testllc; 496313164daSKarsten Graul struct smc_wr_tx_pend_priv *pend; 497313164daSKarsten Graul struct smc_wr_buf *wr_buf; 498313164daSKarsten Graul int rc; 499313164daSKarsten Graul 500313164daSKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 501313164daSKarsten Graul if (rc) 502313164daSKarsten Graul return rc; 503313164daSKarsten Graul testllc = (struct smc_llc_msg_test_link *)wr_buf; 504313164daSKarsten Graul memset(testllc, 0, sizeof(*testllc)); 505313164daSKarsten Graul testllc->hd.common.type = SMC_LLC_TEST_LINK; 506313164daSKarsten Graul testllc->hd.length = sizeof(struct smc_llc_msg_test_link); 507313164daSKarsten Graul memcpy(testllc->user_data, user_data, sizeof(testllc->user_data)); 508313164daSKarsten Graul /* send llc message */ 509313164daSKarsten Graul rc = smc_wr_tx_send(link, pend); 510313164daSKarsten Graul return rc; 511313164daSKarsten Graul } 512313164daSKarsten Graul 5136c8968c4SKarsten Graul /* schedule an llc send on link, may wait for buffers */ 5146c8968c4SKarsten Graul static int smc_llc_send_message(struct smc_link *link, void *llcbuf) 5154ed75de5SKarsten Graul { 5164ed75de5SKarsten Graul struct smc_wr_tx_pend_priv *pend; 5174ed75de5SKarsten Graul struct smc_wr_buf *wr_buf; 5184ed75de5SKarsten Graul int rc; 5194ed75de5SKarsten Graul 5206c8968c4SKarsten Graul if (!smc_link_usable(link)) 5216c8968c4SKarsten Graul return -ENOLINK; 5226c8968c4SKarsten Graul rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 5234ed75de5SKarsten Graul if (rc) 5246c8968c4SKarsten Graul return rc; 5256c8968c4SKarsten Graul memcpy(wr_buf, llcbuf, sizeof(union smc_llc_msg)); 5266c8968c4SKarsten Graul return smc_wr_tx_send(link, pend); 5274ed75de5SKarsten Graul } 5284ed75de5SKarsten Graul 5299bf9abeaSUrsula Braun /********************************* receive ***********************************/ 5309bf9abeaSUrsula Braun 5319bf9abeaSUrsula Braun static void smc_llc_rx_confirm_link(struct smc_link *link, 5329bf9abeaSUrsula Braun struct smc_llc_msg_confirm_link *llc) 5339bf9abeaSUrsula Braun { 53400e5fb26SStefan Raspl struct smc_link_group *lgr = smc_get_lgr(link); 535ef79d439SKarsten Graul int conf_rc = 0; 5369bf9abeaSUrsula Braun 53775d320d6SKarsten Graul /* RMBE eyecatchers are not supported */ 538ef79d439SKarsten Graul if (!(llc->hd.flags & SMC_LLC_FLAG_NO_RMBE_EYEC)) 53975d320d6SKarsten Graul conf_rc = ENOTSUPP; 54075d320d6SKarsten Graul 54152bedf37SKarsten Graul if (lgr->role == SMC_CLNT && 54252bedf37SKarsten Graul link->state == SMC_LNK_ACTIVATING) { 54375d320d6SKarsten Graul link->llc_confirm_rc = conf_rc; 5449bf9abeaSUrsula Braun link->link_id = llc->link_num; 5459bf9abeaSUrsula Braun complete(&link->llc_confirm); 5469bf9abeaSUrsula Braun } 5479bf9abeaSUrsula Braun } 5489bf9abeaSUrsula Braun 54952bedf37SKarsten Graul static void smc_llc_rx_add_link(struct smc_link *link, 55052bedf37SKarsten Graul struct smc_llc_msg_add_link *llc) 55152bedf37SKarsten Graul { 55200e5fb26SStefan Raspl struct smc_link_group *lgr = smc_get_lgr(link); 55352bedf37SKarsten Graul 55452bedf37SKarsten Graul if (link->state == SMC_LNK_ACTIVATING) { 55552bedf37SKarsten Graul complete(&link->llc_add); 55652bedf37SKarsten Graul return; 55752bedf37SKarsten Graul } 55852bedf37SKarsten Graul 55952bedf37SKarsten Graul if (lgr->role == SMC_SERV) { 5602a4c57a9SKarsten Graul smc_llc_prep_add_link(llc, link, 56152bedf37SKarsten Graul link->smcibdev->mac[link->ibport - 1], 5627005ada6SUrsula Braun link->gid, SMC_LLC_REQ); 56352bedf37SKarsten Graul 56452bedf37SKarsten Graul } else { 5652a4c57a9SKarsten Graul smc_llc_prep_add_link(llc, link, 56652bedf37SKarsten Graul link->smcibdev->mac[link->ibport - 1], 5677005ada6SUrsula Braun link->gid, SMC_LLC_RESP); 56852bedf37SKarsten Graul } 5696c8968c4SKarsten Graul smc_llc_send_message(link, llc); 57052bedf37SKarsten Graul } 57152bedf37SKarsten Graul 57252bedf37SKarsten Graul static void smc_llc_rx_delete_link(struct smc_link *link, 57352bedf37SKarsten Graul struct smc_llc_msg_del_link *llc) 57452bedf37SKarsten Graul { 57500e5fb26SStefan Raspl struct smc_link_group *lgr = smc_get_lgr(link); 57652bedf37SKarsten Graul 5779651b934SKarsten Graul smc_lgr_forget(lgr); 5780d18a0cbSKarsten Graul smc_llc_link_deleting(link); 5790d18a0cbSKarsten Graul if (lgr->role == SMC_SERV) { 5800d18a0cbSKarsten Graul /* client asks to delete this link, send request */ 5810d18a0cbSKarsten Graul smc_llc_prep_delete_link(llc, link, SMC_LLC_REQ, true); 58252bedf37SKarsten Graul } else { 5830d18a0cbSKarsten Graul /* server requests to delete this link, send response */ 5840d18a0cbSKarsten Graul smc_llc_prep_delete_link(llc, link, SMC_LLC_RESP, true); 58552bedf37SKarsten Graul } 5866c8968c4SKarsten Graul smc_llc_send_message(link, llc); 587f528ba24SUrsula Braun smc_lgr_terminate_sched(lgr); 58852bedf37SKarsten Graul } 58952bedf37SKarsten Graul 590313164daSKarsten Graul static void smc_llc_rx_test_link(struct smc_link *link, 591313164daSKarsten Graul struct smc_llc_msg_test_link *llc) 592313164daSKarsten Graul { 593d97935faSKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RESP; 5946c8968c4SKarsten Graul smc_llc_send_message(link, llc); 595313164daSKarsten Graul } 596313164daSKarsten Graul 5974ed75de5SKarsten Graul static void smc_llc_rx_confirm_rkey(struct smc_link *link, 5984ed75de5SKarsten Graul struct smc_llc_msg_confirm_rkey *llc) 5994ed75de5SKarsten Graul { 6004ed75de5SKarsten Graul int rc; 6014ed75de5SKarsten Graul 602387707fdSKarsten Graul rc = smc_rtoken_add(link, 6034ed75de5SKarsten Graul llc->rtoken[0].rmb_vaddr, 6044ed75de5SKarsten Graul llc->rtoken[0].rmb_key); 6054ed75de5SKarsten Graul 6064ed75de5SKarsten Graul /* ignore rtokens for other links, we have only one link */ 6074ed75de5SKarsten Graul 6084ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RESP; 6094ed75de5SKarsten Graul if (rc < 0) 6104ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG; 6116c8968c4SKarsten Graul smc_llc_send_message(link, llc); 6124ed75de5SKarsten Graul } 6134ed75de5SKarsten Graul 6144ed75de5SKarsten Graul static void smc_llc_rx_confirm_rkey_cont(struct smc_link *link, 6154ed75de5SKarsten Graul struct smc_llc_msg_confirm_rkey_cont *llc) 6164ed75de5SKarsten Graul { 6174ed75de5SKarsten Graul /* ignore rtokens for other links, we have only one link */ 6184ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RESP; 6196c8968c4SKarsten Graul smc_llc_send_message(link, llc); 6204ed75de5SKarsten Graul } 6214ed75de5SKarsten Graul 6224ed75de5SKarsten Graul static void smc_llc_rx_delete_rkey(struct smc_link *link, 6234ed75de5SKarsten Graul struct smc_llc_msg_delete_rkey *llc) 6244ed75de5SKarsten Graul { 6254ed75de5SKarsten Graul u8 err_mask = 0; 6264ed75de5SKarsten Graul int i, max; 6274ed75de5SKarsten Graul 6284ed75de5SKarsten Graul max = min_t(u8, llc->num_rkeys, SMC_LLC_DEL_RKEY_MAX); 6294ed75de5SKarsten Graul for (i = 0; i < max; i++) { 630387707fdSKarsten Graul if (smc_rtoken_delete(link, llc->rkey[i])) 6314ed75de5SKarsten Graul err_mask |= 1 << (SMC_LLC_DEL_RKEY_MAX - 1 - i); 6324ed75de5SKarsten Graul } 6334ed75de5SKarsten Graul 6344ed75de5SKarsten Graul if (err_mask) { 6354ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG; 6364ed75de5SKarsten Graul llc->err_mask = err_mask; 6374ed75de5SKarsten Graul } 6384ed75de5SKarsten Graul 6394ed75de5SKarsten Graul llc->hd.flags |= SMC_LLC_FLAG_RESP; 6406c8968c4SKarsten Graul smc_llc_send_message(link, llc); 6414ed75de5SKarsten Graul } 6424ed75de5SKarsten Graul 6436c8968c4SKarsten Graul /* flush the llc event queue */ 64400a049cfSKarsten Graul static void smc_llc_event_flush(struct smc_link_group *lgr) 6459bf9abeaSUrsula Braun { 6466c8968c4SKarsten Graul struct smc_llc_qentry *qentry, *q; 6479bf9abeaSUrsula Braun 6486c8968c4SKarsten Graul spin_lock_bh(&lgr->llc_event_q_lock); 6496c8968c4SKarsten Graul list_for_each_entry_safe(qentry, q, &lgr->llc_event_q, list) { 6506c8968c4SKarsten Graul list_del_init(&qentry->list); 6516c8968c4SKarsten Graul kfree(qentry); 6526c8968c4SKarsten Graul } 6536c8968c4SKarsten Graul spin_unlock_bh(&lgr->llc_event_q_lock); 6546c8968c4SKarsten Graul } 6556c8968c4SKarsten Graul 6566c8968c4SKarsten Graul static void smc_llc_event_handler(struct smc_llc_qentry *qentry) 6576c8968c4SKarsten Graul { 6586c8968c4SKarsten Graul union smc_llc_msg *llc = &qentry->msg; 6596c8968c4SKarsten Graul struct smc_link *link = qentry->link; 6606c8968c4SKarsten Graul 661d854fcbfSKarsten Graul if (!smc_link_usable(link)) 6626c8968c4SKarsten Graul goto out; 663313164daSKarsten Graul 664313164daSKarsten Graul switch (llc->raw.hdr.common.type) { 665313164daSKarsten Graul case SMC_LLC_TEST_LINK: 666313164daSKarsten Graul smc_llc_rx_test_link(link, &llc->test_link); 667313164daSKarsten Graul break; 668313164daSKarsten Graul case SMC_LLC_CONFIRM_LINK: 6699bf9abeaSUrsula Braun smc_llc_rx_confirm_link(link, &llc->confirm_link); 670313164daSKarsten Graul break; 67152bedf37SKarsten Graul case SMC_LLC_ADD_LINK: 67252bedf37SKarsten Graul smc_llc_rx_add_link(link, &llc->add_link); 67352bedf37SKarsten Graul break; 67452bedf37SKarsten Graul case SMC_LLC_DELETE_LINK: 67552bedf37SKarsten Graul smc_llc_rx_delete_link(link, &llc->delete_link); 67652bedf37SKarsten Graul break; 6774ed75de5SKarsten Graul case SMC_LLC_CONFIRM_RKEY: 6784ed75de5SKarsten Graul smc_llc_rx_confirm_rkey(link, &llc->confirm_rkey); 6794ed75de5SKarsten Graul break; 6804ed75de5SKarsten Graul case SMC_LLC_CONFIRM_RKEY_CONT: 6814ed75de5SKarsten Graul smc_llc_rx_confirm_rkey_cont(link, &llc->confirm_rkey_cont); 6824ed75de5SKarsten Graul break; 6834ed75de5SKarsten Graul case SMC_LLC_DELETE_RKEY: 6844ed75de5SKarsten Graul smc_llc_rx_delete_rkey(link, &llc->delete_rkey); 6854ed75de5SKarsten Graul break; 686313164daSKarsten Graul } 6876c8968c4SKarsten Graul out: 6886c8968c4SKarsten Graul kfree(qentry); 6896c8968c4SKarsten Graul } 6906c8968c4SKarsten Graul 6916c8968c4SKarsten Graul /* worker to process llc messages on the event queue */ 6926c8968c4SKarsten Graul static void smc_llc_event_work(struct work_struct *work) 6936c8968c4SKarsten Graul { 6946c8968c4SKarsten Graul struct smc_link_group *lgr = container_of(work, struct smc_link_group, 6956c8968c4SKarsten Graul llc_event_work); 6966c8968c4SKarsten Graul struct smc_llc_qentry *qentry; 6976c8968c4SKarsten Graul 698*555da9afSKarsten Graul if (!lgr->llc_flow_lcl.type && lgr->delayed_event) { 699*555da9afSKarsten Graul if (smc_link_usable(lgr->delayed_event->link)) { 700*555da9afSKarsten Graul smc_llc_event_handler(lgr->delayed_event); 701*555da9afSKarsten Graul } else { 702*555da9afSKarsten Graul qentry = lgr->delayed_event; 703*555da9afSKarsten Graul lgr->delayed_event = NULL; 704*555da9afSKarsten Graul kfree(qentry); 705*555da9afSKarsten Graul } 706*555da9afSKarsten Graul } 707*555da9afSKarsten Graul 7086c8968c4SKarsten Graul again: 7096c8968c4SKarsten Graul spin_lock_bh(&lgr->llc_event_q_lock); 7106c8968c4SKarsten Graul if (!list_empty(&lgr->llc_event_q)) { 7116c8968c4SKarsten Graul qentry = list_first_entry(&lgr->llc_event_q, 7126c8968c4SKarsten Graul struct smc_llc_qentry, list); 7136c8968c4SKarsten Graul list_del_init(&qentry->list); 7146c8968c4SKarsten Graul spin_unlock_bh(&lgr->llc_event_q_lock); 7156c8968c4SKarsten Graul smc_llc_event_handler(qentry); 7166c8968c4SKarsten Graul goto again; 7176c8968c4SKarsten Graul } 7186c8968c4SKarsten Graul spin_unlock_bh(&lgr->llc_event_q_lock); 7196c8968c4SKarsten Graul } 7206c8968c4SKarsten Graul 721ef79d439SKarsten Graul /* process llc responses in tasklet context */ 722ef79d439SKarsten Graul static void smc_llc_rx_response(struct smc_link *link, union smc_llc_msg *llc) 723ef79d439SKarsten Graul { 724ef79d439SKarsten Graul int rc = 0; 725ef79d439SKarsten Graul 726ef79d439SKarsten Graul switch (llc->raw.hdr.common.type) { 727ef79d439SKarsten Graul case SMC_LLC_TEST_LINK: 728ef79d439SKarsten Graul if (link->state == SMC_LNK_ACTIVE) 729ef79d439SKarsten Graul complete(&link->llc_testlink_resp); 730ef79d439SKarsten Graul break; 731ef79d439SKarsten Graul case SMC_LLC_CONFIRM_LINK: 732ef79d439SKarsten Graul if (!(llc->raw.hdr.flags & SMC_LLC_FLAG_NO_RMBE_EYEC)) 733ef79d439SKarsten Graul rc = ENOTSUPP; 734ef79d439SKarsten Graul if (link->lgr->role == SMC_SERV && 735ef79d439SKarsten Graul link->state == SMC_LNK_ACTIVATING) { 736ef79d439SKarsten Graul link->llc_confirm_resp_rc = rc; 737ef79d439SKarsten Graul complete(&link->llc_confirm_resp); 738ef79d439SKarsten Graul } 739ef79d439SKarsten Graul break; 740ef79d439SKarsten Graul case SMC_LLC_ADD_LINK: 741ef79d439SKarsten Graul if (link->state == SMC_LNK_ACTIVATING) 742ef79d439SKarsten Graul complete(&link->llc_add_resp); 743ef79d439SKarsten Graul break; 744ef79d439SKarsten Graul case SMC_LLC_DELETE_LINK: 745ef79d439SKarsten Graul if (link->lgr->role == SMC_SERV) 746ef79d439SKarsten Graul smc_lgr_schedule_free_work_fast(link->lgr); 747ef79d439SKarsten Graul break; 748ef79d439SKarsten Graul case SMC_LLC_CONFIRM_RKEY: 749ef79d439SKarsten Graul link->llc_confirm_rkey_resp_rc = llc->raw.hdr.flags & 750ef79d439SKarsten Graul SMC_LLC_FLAG_RKEY_NEG; 751ef79d439SKarsten Graul complete(&link->llc_confirm_rkey_resp); 752ef79d439SKarsten Graul break; 753ef79d439SKarsten Graul case SMC_LLC_CONFIRM_RKEY_CONT: 754ef79d439SKarsten Graul /* unused as long as we don't send this type of msg */ 755ef79d439SKarsten Graul break; 756ef79d439SKarsten Graul case SMC_LLC_DELETE_RKEY: 757ef79d439SKarsten Graul link->llc_delete_rkey_resp_rc = llc->raw.hdr.flags & 758ef79d439SKarsten Graul SMC_LLC_FLAG_RKEY_NEG; 759ef79d439SKarsten Graul complete(&link->llc_delete_rkey_resp); 760ef79d439SKarsten Graul break; 761ef79d439SKarsten Graul } 762ef79d439SKarsten Graul } 763ef79d439SKarsten Graul 7646c8968c4SKarsten Graul /* copy received msg and add it to the event queue */ 7656c8968c4SKarsten Graul static void smc_llc_rx_handler(struct ib_wc *wc, void *buf) 7666c8968c4SKarsten Graul { 7676c8968c4SKarsten Graul struct smc_link *link = (struct smc_link *)wc->qp->qp_context; 7686c8968c4SKarsten Graul struct smc_link_group *lgr = link->lgr; 7696c8968c4SKarsten Graul struct smc_llc_qentry *qentry; 7706c8968c4SKarsten Graul union smc_llc_msg *llc = buf; 7716c8968c4SKarsten Graul unsigned long flags; 7726c8968c4SKarsten Graul 7736c8968c4SKarsten Graul if (wc->byte_len < sizeof(*llc)) 7746c8968c4SKarsten Graul return; /* short message */ 7756c8968c4SKarsten Graul if (llc->raw.hdr.length != sizeof(*llc)) 7766c8968c4SKarsten Graul return; /* invalid message */ 7776c8968c4SKarsten Graul 778ef79d439SKarsten Graul /* process responses immediately */ 779ef79d439SKarsten Graul if (llc->raw.hdr.flags & SMC_LLC_FLAG_RESP) { 780ef79d439SKarsten Graul smc_llc_rx_response(link, llc); 781ef79d439SKarsten Graul return; 782ef79d439SKarsten Graul } 783ef79d439SKarsten Graul 7846c8968c4SKarsten Graul qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC); 7856c8968c4SKarsten Graul if (!qentry) 7866c8968c4SKarsten Graul return; 7876c8968c4SKarsten Graul qentry->link = link; 7886c8968c4SKarsten Graul INIT_LIST_HEAD(&qentry->list); 7896c8968c4SKarsten Graul memcpy(&qentry->msg, llc, sizeof(union smc_llc_msg)); 7906c8968c4SKarsten Graul spin_lock_irqsave(&lgr->llc_event_q_lock, flags); 7916c8968c4SKarsten Graul list_add_tail(&qentry->list, &lgr->llc_event_q); 7926c8968c4SKarsten Graul spin_unlock_irqrestore(&lgr->llc_event_q_lock, flags); 7936c8968c4SKarsten Graul schedule_work(&link->lgr->llc_event_work); 7949bf9abeaSUrsula Braun } 7959bf9abeaSUrsula Braun 79644aa81ceSKarsten Graul /***************************** worker, utils *********************************/ 797877ae5beSKarsten Graul 798877ae5beSKarsten Graul static void smc_llc_testlink_work(struct work_struct *work) 799877ae5beSKarsten Graul { 800877ae5beSKarsten Graul struct smc_link *link = container_of(to_delayed_work(work), 801877ae5beSKarsten Graul struct smc_link, llc_testlink_wrk); 802877ae5beSKarsten Graul unsigned long next_interval; 803877ae5beSKarsten Graul unsigned long expire_time; 804877ae5beSKarsten Graul u8 user_data[16] = { 0 }; 805877ae5beSKarsten Graul int rc; 806877ae5beSKarsten Graul 807877ae5beSKarsten Graul if (link->state != SMC_LNK_ACTIVE) 808877ae5beSKarsten Graul return; /* don't reschedule worker */ 809877ae5beSKarsten Graul expire_time = link->wr_rx_tstamp + link->llc_testlink_time; 810877ae5beSKarsten Graul if (time_is_after_jiffies(expire_time)) { 811877ae5beSKarsten Graul next_interval = expire_time - jiffies; 812877ae5beSKarsten Graul goto out; 813877ae5beSKarsten Graul } 814877ae5beSKarsten Graul reinit_completion(&link->llc_testlink_resp); 815d97935faSKarsten Graul smc_llc_send_test_link(link, user_data); 816877ae5beSKarsten Graul /* receive TEST LINK response over RoCE fabric */ 817877ae5beSKarsten Graul rc = wait_for_completion_interruptible_timeout(&link->llc_testlink_resp, 818877ae5beSKarsten Graul SMC_LLC_WAIT_TIME); 8191020e1efSKarsten Graul if (link->state != SMC_LNK_ACTIVE) 8201020e1efSKarsten Graul return; /* link state changed */ 821877ae5beSKarsten Graul if (rc <= 0) { 8225f78fe96SKarsten Graul smc_lgr_terminate_sched(smc_get_lgr(link)); 823877ae5beSKarsten Graul return; 824877ae5beSKarsten Graul } 825877ae5beSKarsten Graul next_interval = link->llc_testlink_time; 826877ae5beSKarsten Graul out: 8271020e1efSKarsten Graul schedule_delayed_work(&link->llc_testlink_wrk, next_interval); 828877ae5beSKarsten Graul } 829877ae5beSKarsten Graul 83000a049cfSKarsten Graul void smc_llc_lgr_init(struct smc_link_group *lgr, struct smc_sock *smc) 83100a049cfSKarsten Graul { 83200a049cfSKarsten Graul struct net *net = sock_net(smc->clcsock->sk); 83300a049cfSKarsten Graul 83400a049cfSKarsten Graul INIT_WORK(&lgr->llc_event_work, smc_llc_event_work); 83500a049cfSKarsten Graul INIT_LIST_HEAD(&lgr->llc_event_q); 83600a049cfSKarsten Graul spin_lock_init(&lgr->llc_event_q_lock); 837*555da9afSKarsten Graul spin_lock_init(&lgr->llc_flow_lock); 838*555da9afSKarsten Graul init_waitqueue_head(&lgr->llc_waiter); 83900a049cfSKarsten Graul lgr->llc_testlink_time = net->ipv4.sysctl_tcp_keepalive_time; 84000a049cfSKarsten Graul } 84100a049cfSKarsten Graul 84200a049cfSKarsten Graul /* called after lgr was removed from lgr_list */ 84300a049cfSKarsten Graul void smc_llc_lgr_clear(struct smc_link_group *lgr) 84400a049cfSKarsten Graul { 84500a049cfSKarsten Graul smc_llc_event_flush(lgr); 846*555da9afSKarsten Graul wake_up_interruptible_all(&lgr->llc_waiter); 84700a049cfSKarsten Graul cancel_work_sync(&lgr->llc_event_work); 848*555da9afSKarsten Graul if (lgr->delayed_event) { 849*555da9afSKarsten Graul kfree(lgr->delayed_event); 850*555da9afSKarsten Graul lgr->delayed_event = NULL; 851*555da9afSKarsten Graul } 85200a049cfSKarsten Graul } 85300a049cfSKarsten Graul 8542a4c57a9SKarsten Graul int smc_llc_link_init(struct smc_link *link) 855877ae5beSKarsten Graul { 856b32cf4abSKarsten Graul init_completion(&link->llc_confirm); 857b32cf4abSKarsten Graul init_completion(&link->llc_confirm_resp); 858b32cf4abSKarsten Graul init_completion(&link->llc_add); 859b32cf4abSKarsten Graul init_completion(&link->llc_add_resp); 860ef79d439SKarsten Graul init_completion(&link->llc_confirm_rkey_resp); 861ef79d439SKarsten Graul init_completion(&link->llc_delete_rkey_resp); 86260e03c62SKarsten Graul mutex_init(&link->llc_delete_rkey_mutex); 863877ae5beSKarsten Graul init_completion(&link->llc_testlink_resp); 864877ae5beSKarsten Graul INIT_DELAYED_WORK(&link->llc_testlink_wrk, smc_llc_testlink_work); 8652a4c57a9SKarsten Graul return 0; 866b32cf4abSKarsten Graul } 867b32cf4abSKarsten Graul 86800a049cfSKarsten Graul void smc_llc_link_active(struct smc_link *link) 869b32cf4abSKarsten Graul { 870877ae5beSKarsten Graul link->state = SMC_LNK_ACTIVE; 87100a049cfSKarsten Graul if (link->lgr->llc_testlink_time) { 87200a049cfSKarsten Graul link->llc_testlink_time = link->lgr->llc_testlink_time * HZ; 8731020e1efSKarsten Graul schedule_delayed_work(&link->llc_testlink_wrk, 874877ae5beSKarsten Graul link->llc_testlink_time); 875877ae5beSKarsten Graul } 876877ae5beSKarsten Graul } 877877ae5beSKarsten Graul 8780d18a0cbSKarsten Graul void smc_llc_link_deleting(struct smc_link *link) 8790d18a0cbSKarsten Graul { 8800d18a0cbSKarsten Graul link->state = SMC_LNK_DELETING; 88115e1b99aSUrsula Braun smc_wr_wakeup_tx_wait(link); 8820d18a0cbSKarsten Graul } 8830d18a0cbSKarsten Graul 884877ae5beSKarsten Graul /* called in worker context */ 8852a4c57a9SKarsten Graul void smc_llc_link_clear(struct smc_link *link) 886877ae5beSKarsten Graul { 8872140ac26SKarsten Graul complete(&link->llc_testlink_resp); 8882140ac26SKarsten Graul cancel_delayed_work_sync(&link->llc_testlink_wrk); 8892140ac26SKarsten Graul smc_wr_wakeup_reg_wait(link); 8902140ac26SKarsten Graul smc_wr_wakeup_tx_wait(link); 891877ae5beSKarsten Graul } 892877ae5beSKarsten Graul 89344aa81ceSKarsten Graul /* register a new rtoken at the remote peer */ 89444aa81ceSKarsten Graul int smc_llc_do_confirm_rkey(struct smc_link *link, 89544aa81ceSKarsten Graul struct smc_buf_desc *rmb_desc) 89644aa81ceSKarsten Graul { 89744aa81ceSKarsten Graul int rc; 89844aa81ceSKarsten Graul 89960e03c62SKarsten Graul /* protected by mutex smc_create_lgr_pending */ 900ef79d439SKarsten Graul reinit_completion(&link->llc_confirm_rkey_resp); 9014600cfc3SKarsten Graul rc = smc_llc_send_confirm_rkey(link, rmb_desc); 9024600cfc3SKarsten Graul if (rc) 9034600cfc3SKarsten Graul return rc; 90444aa81ceSKarsten Graul /* receive CONFIRM RKEY response from server over RoCE fabric */ 905ef79d439SKarsten Graul rc = wait_for_completion_interruptible_timeout( 906ef79d439SKarsten Graul &link->llc_confirm_rkey_resp, SMC_LLC_WAIT_TIME); 907ef79d439SKarsten Graul if (rc <= 0 || link->llc_confirm_rkey_resp_rc) 90844aa81ceSKarsten Graul return -EFAULT; 90944aa81ceSKarsten Graul return 0; 91044aa81ceSKarsten Graul } 91144aa81ceSKarsten Graul 91260e03c62SKarsten Graul /* unregister an rtoken at the remote peer */ 91360e03c62SKarsten Graul int smc_llc_do_delete_rkey(struct smc_link *link, 91460e03c62SKarsten Graul struct smc_buf_desc *rmb_desc) 91560e03c62SKarsten Graul { 9160b29ec64SUrsula Braun int rc = 0; 91760e03c62SKarsten Graul 91860e03c62SKarsten Graul mutex_lock(&link->llc_delete_rkey_mutex); 9190b29ec64SUrsula Braun if (link->state != SMC_LNK_ACTIVE) 9200b29ec64SUrsula Braun goto out; 921ef79d439SKarsten Graul reinit_completion(&link->llc_delete_rkey_resp); 92260e03c62SKarsten Graul rc = smc_llc_send_delete_rkey(link, rmb_desc); 92360e03c62SKarsten Graul if (rc) 92460e03c62SKarsten Graul goto out; 92560e03c62SKarsten Graul /* receive DELETE RKEY response from server over RoCE fabric */ 926ef79d439SKarsten Graul rc = wait_for_completion_interruptible_timeout( 927ef79d439SKarsten Graul &link->llc_delete_rkey_resp, SMC_LLC_WAIT_TIME); 928ef79d439SKarsten Graul if (rc <= 0 || link->llc_delete_rkey_resp_rc) 92960e03c62SKarsten Graul rc = -EFAULT; 93060e03c62SKarsten Graul else 93160e03c62SKarsten Graul rc = 0; 93260e03c62SKarsten Graul out: 93360e03c62SKarsten Graul mutex_unlock(&link->llc_delete_rkey_mutex); 93460e03c62SKarsten Graul return rc; 93560e03c62SKarsten Graul } 93660e03c62SKarsten Graul 9379bf9abeaSUrsula Braun /***************************** init, exit, misc ******************************/ 9389bf9abeaSUrsula Braun 9399bf9abeaSUrsula Braun static struct smc_wr_rx_handler smc_llc_rx_handlers[] = { 9409bf9abeaSUrsula Braun { 9419bf9abeaSUrsula Braun .handler = smc_llc_rx_handler, 9429bf9abeaSUrsula Braun .type = SMC_LLC_CONFIRM_LINK 9439bf9abeaSUrsula Braun }, 9449bf9abeaSUrsula Braun { 945313164daSKarsten Graul .handler = smc_llc_rx_handler, 946313164daSKarsten Graul .type = SMC_LLC_TEST_LINK 947313164daSKarsten Graul }, 948313164daSKarsten Graul { 9494ed75de5SKarsten Graul .handler = smc_llc_rx_handler, 95052bedf37SKarsten Graul .type = SMC_LLC_ADD_LINK 95152bedf37SKarsten Graul }, 95252bedf37SKarsten Graul { 95352bedf37SKarsten Graul .handler = smc_llc_rx_handler, 95452bedf37SKarsten Graul .type = SMC_LLC_DELETE_LINK 95552bedf37SKarsten Graul }, 95652bedf37SKarsten Graul { 95752bedf37SKarsten Graul .handler = smc_llc_rx_handler, 9584ed75de5SKarsten Graul .type = SMC_LLC_CONFIRM_RKEY 9594ed75de5SKarsten Graul }, 9604ed75de5SKarsten Graul { 9614ed75de5SKarsten Graul .handler = smc_llc_rx_handler, 9624ed75de5SKarsten Graul .type = SMC_LLC_CONFIRM_RKEY_CONT 9634ed75de5SKarsten Graul }, 9644ed75de5SKarsten Graul { 9654ed75de5SKarsten Graul .handler = smc_llc_rx_handler, 9664ed75de5SKarsten Graul .type = SMC_LLC_DELETE_RKEY 9674ed75de5SKarsten Graul }, 9684ed75de5SKarsten Graul { 9699bf9abeaSUrsula Braun .handler = NULL, 9709bf9abeaSUrsula Braun } 9719bf9abeaSUrsula Braun }; 9729bf9abeaSUrsula Braun 9739bf9abeaSUrsula Braun int __init smc_llc_init(void) 9749bf9abeaSUrsula Braun { 9759bf9abeaSUrsula Braun struct smc_wr_rx_handler *handler; 9769bf9abeaSUrsula Braun int rc = 0; 9779bf9abeaSUrsula Braun 9789bf9abeaSUrsula Braun for (handler = smc_llc_rx_handlers; handler->handler; handler++) { 9799bf9abeaSUrsula Braun INIT_HLIST_NODE(&handler->list); 9809bf9abeaSUrsula Braun rc = smc_wr_rx_register_handler(handler); 9819bf9abeaSUrsula Braun if (rc) 9829bf9abeaSUrsula Braun break; 9839bf9abeaSUrsula Braun } 9849bf9abeaSUrsula Braun return rc; 9859bf9abeaSUrsula Braun } 986