smc_llc.c (66015B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Shared Memory Communications over RDMA (SMC-R) and RoCE 4 * 5 * Link Layer Control (LLC) 6 * 7 * Copyright IBM Corp. 2016 8 * 9 * Author(s): Klaus Wacker <Klaus.Wacker@de.ibm.com> 10 * Ursula Braun <ubraun@linux.vnet.ibm.com> 11 */ 12 13#include <net/tcp.h> 14#include <rdma/ib_verbs.h> 15 16#include "smc.h" 17#include "smc_core.h" 18#include "smc_clc.h" 19#include "smc_llc.h" 20#include "smc_pnet.h" 21 22#define SMC_LLC_DATA_LEN 40 23 24struct smc_llc_hdr { 25 struct smc_wr_rx_hdr common; 26 union { 27 struct { 28 u8 length; /* 44 */ 29 #if defined(__BIG_ENDIAN_BITFIELD) 30 u8 reserved:4, 31 add_link_rej_rsn:4; 32#elif defined(__LITTLE_ENDIAN_BITFIELD) 33 u8 add_link_rej_rsn:4, 34 reserved:4; 35#endif 36 }; 37 u16 length_v2; /* 44 - 8192*/ 38 }; 39 u8 flags; 40} __packed; /* format defined in 41 * IBM Shared Memory Communications Version 2 42 * (https://www.ibm.com/support/pages/node/6326337) 43 */ 44 45#define SMC_LLC_FLAG_NO_RMBE_EYEC 0x03 46 47struct smc_llc_msg_confirm_link { /* type 0x01 */ 48 struct smc_llc_hdr hd; 49 u8 sender_mac[ETH_ALEN]; 50 u8 sender_gid[SMC_GID_SIZE]; 51 u8 sender_qp_num[3]; 52 u8 link_num; 53 u8 link_uid[SMC_LGR_ID_SIZE]; 54 u8 max_links; 55 u8 reserved[9]; 56}; 57 58#define SMC_LLC_FLAG_ADD_LNK_REJ 0x40 59#define SMC_LLC_REJ_RSN_NO_ALT_PATH 1 60 61#define SMC_LLC_ADD_LNK_MAX_LINKS 2 62 63struct smc_llc_msg_add_link { /* type 0x02 */ 64 struct smc_llc_hdr hd; 65 u8 sender_mac[ETH_ALEN]; 66 u8 reserved2[2]; 67 u8 sender_gid[SMC_GID_SIZE]; 68 u8 sender_qp_num[3]; 69 u8 link_num; 70#if defined(__BIG_ENDIAN_BITFIELD) 71 u8 reserved3 : 4, 72 qp_mtu : 4; 73#elif defined(__LITTLE_ENDIAN_BITFIELD) 74 u8 qp_mtu : 4, 75 reserved3 : 4; 76#endif 77 u8 initial_psn[3]; 78 u8 reserved[8]; 79}; 80 81struct smc_llc_msg_add_link_cont_rt { 82 __be32 rmb_key; 83 __be32 rmb_key_new; 84 __be64 rmb_vaddr_new; 85}; 86 87struct smc_llc_msg_add_link_v2_ext { 88#if defined(__BIG_ENDIAN_BITFIELD) 89 u8 v2_direct : 1, 90 reserved : 7; 91#elif defined(__LITTLE_ENDIAN_BITFIELD) 92 u8 reserved : 7, 93 v2_direct : 1; 94#endif 95 u8 reserved2; 96 u8 client_target_gid[SMC_GID_SIZE]; 97 u8 reserved3[8]; 98 u16 num_rkeys; 99 struct smc_llc_msg_add_link_cont_rt rt[]; 100} __packed; /* format defined in 101 * IBM Shared Memory Communications Version 2 102 * (https://www.ibm.com/support/pages/node/6326337) 103 */ 104 105struct smc_llc_msg_req_add_link_v2 { 106 struct smc_llc_hdr hd; 107 u8 reserved[20]; 108 u8 gid_cnt; 109 u8 reserved2[3]; 110 u8 gid[][SMC_GID_SIZE]; 111}; 112 113#define SMC_LLC_RKEYS_PER_CONT_MSG 2 114 115struct smc_llc_msg_add_link_cont { /* type 0x03 */ 116 struct smc_llc_hdr hd; 117 u8 link_num; 118 u8 num_rkeys; 119 u8 reserved2[2]; 120 struct smc_llc_msg_add_link_cont_rt rt[SMC_LLC_RKEYS_PER_CONT_MSG]; 121 u8 reserved[4]; 122} __packed; /* format defined in RFC7609 */ 123 124#define SMC_LLC_FLAG_DEL_LINK_ALL 0x40 125#define SMC_LLC_FLAG_DEL_LINK_ORDERLY 0x20 126 127struct smc_llc_msg_del_link { /* type 0x04 */ 128 struct smc_llc_hdr hd; 129 u8 link_num; 130 __be32 reason; 131 u8 reserved[35]; 132} __packed; /* format defined in RFC7609 */ 133 134struct smc_llc_msg_test_link { /* type 0x07 */ 135 struct smc_llc_hdr hd; 136 u8 user_data[16]; 137 u8 reserved[24]; 138}; 139 140struct smc_rmb_rtoken { 141 union { 142 u8 num_rkeys; /* first rtoken byte of CONFIRM LINK msg */ 143 /* is actually the num of rtokens, first */ 144 /* rtoken is always for the current link */ 145 u8 link_id; /* link id of the rtoken */ 146 }; 147 __be32 rmb_key; 148 __be64 rmb_vaddr; 149} __packed; /* format defined in RFC7609 */ 150 151#define SMC_LLC_RKEYS_PER_MSG 3 152#define SMC_LLC_RKEYS_PER_MSG_V2 255 153 154struct smc_llc_msg_confirm_rkey { /* type 0x06 */ 155 struct smc_llc_hdr hd; 156 struct smc_rmb_rtoken rtoken[SMC_LLC_RKEYS_PER_MSG]; 157 u8 reserved; 158}; 159 160#define SMC_LLC_DEL_RKEY_MAX 8 161#define SMC_LLC_FLAG_RKEY_RETRY 0x10 162#define SMC_LLC_FLAG_RKEY_NEG 0x20 163 164struct smc_llc_msg_delete_rkey { /* type 0x09 */ 165 struct smc_llc_hdr hd; 166 u8 num_rkeys; 167 u8 err_mask; 168 u8 reserved[2]; 169 __be32 rkey[8]; 170 u8 reserved2[4]; 171}; 172 173struct smc_llc_msg_delete_rkey_v2 { /* type 0x29 */ 174 struct smc_llc_hdr hd; 175 u8 num_rkeys; 176 u8 num_inval_rkeys; 177 u8 reserved[2]; 178 __be32 rkey[]; 179}; 180 181union smc_llc_msg { 182 struct smc_llc_msg_confirm_link confirm_link; 183 struct smc_llc_msg_add_link add_link; 184 struct smc_llc_msg_req_add_link_v2 req_add_link; 185 struct smc_llc_msg_add_link_cont add_link_cont; 186 struct smc_llc_msg_del_link delete_link; 187 188 struct smc_llc_msg_confirm_rkey confirm_rkey; 189 struct smc_llc_msg_delete_rkey delete_rkey; 190 191 struct smc_llc_msg_test_link test_link; 192 struct { 193 struct smc_llc_hdr hdr; 194 u8 data[SMC_LLC_DATA_LEN]; 195 } raw; 196}; 197 198#define SMC_LLC_FLAG_RESP 0x80 199 200struct smc_llc_qentry { 201 struct list_head list; 202 struct smc_link *link; 203 union smc_llc_msg msg; 204}; 205 206static void smc_llc_enqueue(struct smc_link *link, union smc_llc_msg *llc); 207 208struct smc_llc_qentry *smc_llc_flow_qentry_clr(struct smc_llc_flow *flow) 209{ 210 struct smc_llc_qentry *qentry = flow->qentry; 211 212 flow->qentry = NULL; 213 return qentry; 214} 215 216void smc_llc_flow_qentry_del(struct smc_llc_flow *flow) 217{ 218 struct smc_llc_qentry *qentry; 219 220 if (flow->qentry) { 221 qentry = flow->qentry; 222 flow->qentry = NULL; 223 kfree(qentry); 224 } 225} 226 227static inline void smc_llc_flow_qentry_set(struct smc_llc_flow *flow, 228 struct smc_llc_qentry *qentry) 229{ 230 flow->qentry = qentry; 231} 232 233static void smc_llc_flow_parallel(struct smc_link_group *lgr, u8 flow_type, 234 struct smc_llc_qentry *qentry) 235{ 236 u8 msg_type = qentry->msg.raw.hdr.common.llc_type; 237 238 if ((msg_type == SMC_LLC_ADD_LINK || msg_type == SMC_LLC_DELETE_LINK) && 239 flow_type != msg_type && !lgr->delayed_event) { 240 lgr->delayed_event = qentry; 241 return; 242 } 243 /* drop parallel or already-in-progress llc requests */ 244 if (flow_type != msg_type) 245 pr_warn_once("smc: SMC-R lg %*phN net %llu dropped parallel " 246 "LLC msg: msg %d flow %d role %d\n", 247 SMC_LGR_ID_SIZE, &lgr->id, 248 lgr->net->net_cookie, 249 qentry->msg.raw.hdr.common.type, 250 flow_type, lgr->role); 251 kfree(qentry); 252} 253 254/* try to start a new llc flow, initiated by an incoming llc msg */ 255static bool smc_llc_flow_start(struct smc_llc_flow *flow, 256 struct smc_llc_qentry *qentry) 257{ 258 struct smc_link_group *lgr = qentry->link->lgr; 259 260 spin_lock_bh(&lgr->llc_flow_lock); 261 if (flow->type) { 262 /* a flow is already active */ 263 smc_llc_flow_parallel(lgr, flow->type, qentry); 264 spin_unlock_bh(&lgr->llc_flow_lock); 265 return false; 266 } 267 switch (qentry->msg.raw.hdr.common.llc_type) { 268 case SMC_LLC_ADD_LINK: 269 flow->type = SMC_LLC_FLOW_ADD_LINK; 270 break; 271 case SMC_LLC_DELETE_LINK: 272 flow->type = SMC_LLC_FLOW_DEL_LINK; 273 break; 274 case SMC_LLC_CONFIRM_RKEY: 275 case SMC_LLC_DELETE_RKEY: 276 flow->type = SMC_LLC_FLOW_RKEY; 277 break; 278 default: 279 flow->type = SMC_LLC_FLOW_NONE; 280 } 281 smc_llc_flow_qentry_set(flow, qentry); 282 spin_unlock_bh(&lgr->llc_flow_lock); 283 return true; 284} 285 286/* start a new local llc flow, wait till current flow finished */ 287int smc_llc_flow_initiate(struct smc_link_group *lgr, 288 enum smc_llc_flowtype type) 289{ 290 enum smc_llc_flowtype allowed_remote = SMC_LLC_FLOW_NONE; 291 int rc; 292 293 /* all flows except confirm_rkey and delete_rkey are exclusive, 294 * confirm/delete rkey flows can run concurrently (local and remote) 295 */ 296 if (type == SMC_LLC_FLOW_RKEY) 297 allowed_remote = SMC_LLC_FLOW_RKEY; 298again: 299 if (list_empty(&lgr->list)) 300 return -ENODEV; 301 spin_lock_bh(&lgr->llc_flow_lock); 302 if (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_NONE && 303 (lgr->llc_flow_rmt.type == SMC_LLC_FLOW_NONE || 304 lgr->llc_flow_rmt.type == allowed_remote)) { 305 lgr->llc_flow_lcl.type = type; 306 spin_unlock_bh(&lgr->llc_flow_lock); 307 return 0; 308 } 309 spin_unlock_bh(&lgr->llc_flow_lock); 310 rc = wait_event_timeout(lgr->llc_flow_waiter, (list_empty(&lgr->list) || 311 (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_NONE && 312 (lgr->llc_flow_rmt.type == SMC_LLC_FLOW_NONE || 313 lgr->llc_flow_rmt.type == allowed_remote))), 314 SMC_LLC_WAIT_TIME * 10); 315 if (!rc) 316 return -ETIMEDOUT; 317 goto again; 318} 319 320/* finish the current llc flow */ 321void smc_llc_flow_stop(struct smc_link_group *lgr, struct smc_llc_flow *flow) 322{ 323 spin_lock_bh(&lgr->llc_flow_lock); 324 memset(flow, 0, sizeof(*flow)); 325 flow->type = SMC_LLC_FLOW_NONE; 326 spin_unlock_bh(&lgr->llc_flow_lock); 327 if (!list_empty(&lgr->list) && lgr->delayed_event && 328 flow == &lgr->llc_flow_lcl) 329 schedule_work(&lgr->llc_event_work); 330 else 331 wake_up(&lgr->llc_flow_waiter); 332} 333 334/* lnk is optional and used for early wakeup when link goes down, useful in 335 * cases where we wait for a response on the link after we sent a request 336 */ 337struct smc_llc_qentry *smc_llc_wait(struct smc_link_group *lgr, 338 struct smc_link *lnk, 339 int time_out, u8 exp_msg) 340{ 341 struct smc_llc_flow *flow = &lgr->llc_flow_lcl; 342 u8 rcv_msg; 343 344 wait_event_timeout(lgr->llc_msg_waiter, 345 (flow->qentry || 346 (lnk && !smc_link_usable(lnk)) || 347 list_empty(&lgr->list)), 348 time_out); 349 if (!flow->qentry || 350 (lnk && !smc_link_usable(lnk)) || list_empty(&lgr->list)) { 351 smc_llc_flow_qentry_del(flow); 352 goto out; 353 } 354 rcv_msg = flow->qentry->msg.raw.hdr.common.llc_type; 355 if (exp_msg && rcv_msg != exp_msg) { 356 if (exp_msg == SMC_LLC_ADD_LINK && 357 rcv_msg == SMC_LLC_DELETE_LINK) { 358 /* flow_start will delay the unexpected msg */ 359 smc_llc_flow_start(&lgr->llc_flow_lcl, 360 smc_llc_flow_qentry_clr(flow)); 361 return NULL; 362 } 363 pr_warn_once("smc: SMC-R lg %*phN net %llu dropped unexpected LLC msg: " 364 "msg %d exp %d flow %d role %d flags %x\n", 365 SMC_LGR_ID_SIZE, &lgr->id, lgr->net->net_cookie, 366 rcv_msg, exp_msg, 367 flow->type, lgr->role, 368 flow->qentry->msg.raw.hdr.flags); 369 smc_llc_flow_qentry_del(flow); 370 } 371out: 372 return flow->qentry; 373} 374 375/********************************** send *************************************/ 376 377struct smc_llc_tx_pend { 378}; 379 380/* handler for send/transmission completion of an LLC msg */ 381static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv *pend, 382 struct smc_link *link, 383 enum ib_wc_status wc_status) 384{ 385 /* future work: handle wc_status error for recovery and failover */ 386} 387 388/** 389 * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits 390 * @link: Pointer to SMC link used for sending LLC control message. 391 * @wr_buf: Out variable returning pointer to work request payload buffer. 392 * @pend: Out variable returning pointer to private pending WR tracking. 393 * It's the context the transmit complete handler will get. 394 * 395 * Reserves and pre-fills an entry for a pending work request send/tx. 396 * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx. 397 * Can sleep due to smc_get_ctrl_buf (if not in softirq context). 398 * 399 * Return: 0 on success, otherwise an error value. 400 */ 401static int smc_llc_add_pending_send(struct smc_link *link, 402 struct smc_wr_buf **wr_buf, 403 struct smc_wr_tx_pend_priv **pend) 404{ 405 int rc; 406 407 rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, NULL, 408 pend); 409 if (rc < 0) 410 return rc; 411 BUILD_BUG_ON_MSG( 412 sizeof(union smc_llc_msg) > SMC_WR_BUF_SIZE, 413 "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)"); 414 BUILD_BUG_ON_MSG( 415 sizeof(union smc_llc_msg) != SMC_WR_TX_SIZE, 416 "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()"); 417 BUILD_BUG_ON_MSG( 418 sizeof(struct smc_llc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE, 419 "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)"); 420 return 0; 421} 422 423static int smc_llc_add_pending_send_v2(struct smc_link *link, 424 struct smc_wr_v2_buf **wr_buf, 425 struct smc_wr_tx_pend_priv **pend) 426{ 427 int rc; 428 429 rc = smc_wr_tx_get_v2_slot(link, smc_llc_tx_handler, wr_buf, pend); 430 if (rc < 0) 431 return rc; 432 return 0; 433} 434 435static void smc_llc_init_msg_hdr(struct smc_llc_hdr *hdr, 436 struct smc_link_group *lgr, size_t len) 437{ 438 if (lgr->smc_version == SMC_V2) { 439 hdr->common.llc_version = SMC_V2; 440 hdr->length_v2 = len; 441 } else { 442 hdr->common.llc_version = 0; 443 hdr->length = len; 444 } 445} 446 447/* high-level API to send LLC confirm link */ 448int smc_llc_send_confirm_link(struct smc_link *link, 449 enum smc_llc_reqresp reqresp) 450{ 451 struct smc_llc_msg_confirm_link *confllc; 452 struct smc_wr_tx_pend_priv *pend; 453 struct smc_wr_buf *wr_buf; 454 int rc; 455 456 if (!smc_wr_tx_link_hold(link)) 457 return -ENOLINK; 458 rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 459 if (rc) 460 goto put_out; 461 confllc = (struct smc_llc_msg_confirm_link *)wr_buf; 462 memset(confllc, 0, sizeof(*confllc)); 463 confllc->hd.common.llc_type = SMC_LLC_CONFIRM_LINK; 464 smc_llc_init_msg_hdr(&confllc->hd, link->lgr, sizeof(*confllc)); 465 confllc->hd.flags |= SMC_LLC_FLAG_NO_RMBE_EYEC; 466 if (reqresp == SMC_LLC_RESP) 467 confllc->hd.flags |= SMC_LLC_FLAG_RESP; 468 memcpy(confllc->sender_mac, link->smcibdev->mac[link->ibport - 1], 469 ETH_ALEN); 470 memcpy(confllc->sender_gid, link->gid, SMC_GID_SIZE); 471 hton24(confllc->sender_qp_num, link->roce_qp->qp_num); 472 confllc->link_num = link->link_id; 473 memcpy(confllc->link_uid, link->link_uid, SMC_LGR_ID_SIZE); 474 confllc->max_links = SMC_LLC_ADD_LNK_MAX_LINKS; 475 /* send llc message */ 476 rc = smc_wr_tx_send(link, pend); 477put_out: 478 smc_wr_tx_link_put(link); 479 return rc; 480} 481 482/* send LLC confirm rkey request */ 483static int smc_llc_send_confirm_rkey(struct smc_link *send_link, 484 struct smc_buf_desc *rmb_desc) 485{ 486 struct smc_llc_msg_confirm_rkey *rkeyllc; 487 struct smc_wr_tx_pend_priv *pend; 488 struct smc_wr_buf *wr_buf; 489 struct smc_link *link; 490 int i, rc, rtok_ix; 491 492 if (!smc_wr_tx_link_hold(send_link)) 493 return -ENOLINK; 494 rc = smc_llc_add_pending_send(send_link, &wr_buf, &pend); 495 if (rc) 496 goto put_out; 497 rkeyllc = (struct smc_llc_msg_confirm_rkey *)wr_buf; 498 memset(rkeyllc, 0, sizeof(*rkeyllc)); 499 rkeyllc->hd.common.llc_type = SMC_LLC_CONFIRM_RKEY; 500 smc_llc_init_msg_hdr(&rkeyllc->hd, send_link->lgr, sizeof(*rkeyllc)); 501 502 rtok_ix = 1; 503 for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 504 link = &send_link->lgr->lnk[i]; 505 if (smc_link_active(link) && link != send_link) { 506 rkeyllc->rtoken[rtok_ix].link_id = link->link_id; 507 rkeyllc->rtoken[rtok_ix].rmb_key = 508 htonl(rmb_desc->mr_rx[link->link_idx]->rkey); 509 rkeyllc->rtoken[rtok_ix].rmb_vaddr = cpu_to_be64( 510 (u64)sg_dma_address( 511 rmb_desc->sgt[link->link_idx].sgl)); 512 rtok_ix++; 513 } 514 } 515 /* rkey of send_link is in rtoken[0] */ 516 rkeyllc->rtoken[0].num_rkeys = rtok_ix - 1; 517 rkeyllc->rtoken[0].rmb_key = 518 htonl(rmb_desc->mr_rx[send_link->link_idx]->rkey); 519 rkeyllc->rtoken[0].rmb_vaddr = cpu_to_be64( 520 (u64)sg_dma_address(rmb_desc->sgt[send_link->link_idx].sgl)); 521 /* send llc message */ 522 rc = smc_wr_tx_send(send_link, pend); 523put_out: 524 smc_wr_tx_link_put(send_link); 525 return rc; 526} 527 528/* send LLC delete rkey request */ 529static int smc_llc_send_delete_rkey(struct smc_link *link, 530 struct smc_buf_desc *rmb_desc) 531{ 532 struct smc_llc_msg_delete_rkey *rkeyllc; 533 struct smc_wr_tx_pend_priv *pend; 534 struct smc_wr_buf *wr_buf; 535 int rc; 536 537 if (!smc_wr_tx_link_hold(link)) 538 return -ENOLINK; 539 rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 540 if (rc) 541 goto put_out; 542 rkeyllc = (struct smc_llc_msg_delete_rkey *)wr_buf; 543 memset(rkeyllc, 0, sizeof(*rkeyllc)); 544 rkeyllc->hd.common.llc_type = SMC_LLC_DELETE_RKEY; 545 smc_llc_init_msg_hdr(&rkeyllc->hd, link->lgr, sizeof(*rkeyllc)); 546 rkeyllc->num_rkeys = 1; 547 rkeyllc->rkey[0] = htonl(rmb_desc->mr_rx[link->link_idx]->rkey); 548 /* send llc message */ 549 rc = smc_wr_tx_send(link, pend); 550put_out: 551 smc_wr_tx_link_put(link); 552 return rc; 553} 554 555/* return first buffer from any of the next buf lists */ 556static struct smc_buf_desc *_smc_llc_get_next_rmb(struct smc_link_group *lgr, 557 int *buf_lst) 558{ 559 struct smc_buf_desc *buf_pos; 560 561 while (*buf_lst < SMC_RMBE_SIZES) { 562 buf_pos = list_first_entry_or_null(&lgr->rmbs[*buf_lst], 563 struct smc_buf_desc, list); 564 if (buf_pos) 565 return buf_pos; 566 (*buf_lst)++; 567 } 568 return NULL; 569} 570 571/* return next rmb from buffer lists */ 572static struct smc_buf_desc *smc_llc_get_next_rmb(struct smc_link_group *lgr, 573 int *buf_lst, 574 struct smc_buf_desc *buf_pos) 575{ 576 struct smc_buf_desc *buf_next; 577 578 if (!buf_pos || list_is_last(&buf_pos->list, &lgr->rmbs[*buf_lst])) { 579 (*buf_lst)++; 580 return _smc_llc_get_next_rmb(lgr, buf_lst); 581 } 582 buf_next = list_next_entry(buf_pos, list); 583 return buf_next; 584} 585 586static struct smc_buf_desc *smc_llc_get_first_rmb(struct smc_link_group *lgr, 587 int *buf_lst) 588{ 589 *buf_lst = 0; 590 return smc_llc_get_next_rmb(lgr, buf_lst, NULL); 591} 592 593static int smc_llc_fill_ext_v2(struct smc_llc_msg_add_link_v2_ext *ext, 594 struct smc_link *link, struct smc_link *link_new) 595{ 596 struct smc_link_group *lgr = link->lgr; 597 struct smc_buf_desc *buf_pos; 598 int prim_lnk_idx, lnk_idx, i; 599 struct smc_buf_desc *rmb; 600 int len = sizeof(*ext); 601 int buf_lst; 602 603 ext->v2_direct = !lgr->uses_gateway; 604 memcpy(ext->client_target_gid, link_new->gid, SMC_GID_SIZE); 605 606 prim_lnk_idx = link->link_idx; 607 lnk_idx = link_new->link_idx; 608 mutex_lock(&lgr->rmbs_lock); 609 ext->num_rkeys = lgr->conns_num; 610 if (!ext->num_rkeys) 611 goto out; 612 buf_pos = smc_llc_get_first_rmb(lgr, &buf_lst); 613 for (i = 0; i < ext->num_rkeys; i++) { 614 if (!buf_pos) 615 break; 616 rmb = buf_pos; 617 ext->rt[i].rmb_key = htonl(rmb->mr_rx[prim_lnk_idx]->rkey); 618 ext->rt[i].rmb_key_new = htonl(rmb->mr_rx[lnk_idx]->rkey); 619 ext->rt[i].rmb_vaddr_new = 620 cpu_to_be64((u64)sg_dma_address(rmb->sgt[lnk_idx].sgl)); 621 buf_pos = smc_llc_get_next_rmb(lgr, &buf_lst, buf_pos); 622 while (buf_pos && !(buf_pos)->used) 623 buf_pos = smc_llc_get_next_rmb(lgr, &buf_lst, buf_pos); 624 } 625 len += i * sizeof(ext->rt[0]); 626out: 627 mutex_unlock(&lgr->rmbs_lock); 628 return len; 629} 630 631/* send ADD LINK request or response */ 632int smc_llc_send_add_link(struct smc_link *link, u8 mac[], u8 gid[], 633 struct smc_link *link_new, 634 enum smc_llc_reqresp reqresp) 635{ 636 struct smc_llc_msg_add_link_v2_ext *ext = NULL; 637 struct smc_llc_msg_add_link *addllc; 638 struct smc_wr_tx_pend_priv *pend; 639 int len = sizeof(*addllc); 640 int rc; 641 642 if (!smc_wr_tx_link_hold(link)) 643 return -ENOLINK; 644 if (link->lgr->smc_version == SMC_V2) { 645 struct smc_wr_v2_buf *wr_buf; 646 647 rc = smc_llc_add_pending_send_v2(link, &wr_buf, &pend); 648 if (rc) 649 goto put_out; 650 addllc = (struct smc_llc_msg_add_link *)wr_buf; 651 ext = (struct smc_llc_msg_add_link_v2_ext *) 652 &wr_buf->raw[sizeof(*addllc)]; 653 memset(ext, 0, SMC_WR_TX_SIZE); 654 } else { 655 struct smc_wr_buf *wr_buf; 656 657 rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 658 if (rc) 659 goto put_out; 660 addllc = (struct smc_llc_msg_add_link *)wr_buf; 661 } 662 663 memset(addllc, 0, sizeof(*addllc)); 664 addllc->hd.common.llc_type = SMC_LLC_ADD_LINK; 665 if (reqresp == SMC_LLC_RESP) 666 addllc->hd.flags |= SMC_LLC_FLAG_RESP; 667 memcpy(addllc->sender_mac, mac, ETH_ALEN); 668 memcpy(addllc->sender_gid, gid, SMC_GID_SIZE); 669 if (link_new) { 670 addllc->link_num = link_new->link_id; 671 hton24(addllc->sender_qp_num, link_new->roce_qp->qp_num); 672 hton24(addllc->initial_psn, link_new->psn_initial); 673 if (reqresp == SMC_LLC_REQ) 674 addllc->qp_mtu = link_new->path_mtu; 675 else 676 addllc->qp_mtu = min(link_new->path_mtu, 677 link_new->peer_mtu); 678 } 679 if (ext && link_new) 680 len += smc_llc_fill_ext_v2(ext, link, link_new); 681 smc_llc_init_msg_hdr(&addllc->hd, link->lgr, len); 682 /* send llc message */ 683 if (link->lgr->smc_version == SMC_V2) 684 rc = smc_wr_tx_v2_send(link, pend, len); 685 else 686 rc = smc_wr_tx_send(link, pend); 687put_out: 688 smc_wr_tx_link_put(link); 689 return rc; 690} 691 692/* send DELETE LINK request or response */ 693int smc_llc_send_delete_link(struct smc_link *link, u8 link_del_id, 694 enum smc_llc_reqresp reqresp, bool orderly, 695 u32 reason) 696{ 697 struct smc_llc_msg_del_link *delllc; 698 struct smc_wr_tx_pend_priv *pend; 699 struct smc_wr_buf *wr_buf; 700 int rc; 701 702 if (!smc_wr_tx_link_hold(link)) 703 return -ENOLINK; 704 rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 705 if (rc) 706 goto put_out; 707 delllc = (struct smc_llc_msg_del_link *)wr_buf; 708 709 memset(delllc, 0, sizeof(*delllc)); 710 delllc->hd.common.llc_type = SMC_LLC_DELETE_LINK; 711 smc_llc_init_msg_hdr(&delllc->hd, link->lgr, sizeof(*delllc)); 712 if (reqresp == SMC_LLC_RESP) 713 delllc->hd.flags |= SMC_LLC_FLAG_RESP; 714 if (orderly) 715 delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY; 716 if (link_del_id) 717 delllc->link_num = link_del_id; 718 else 719 delllc->hd.flags |= SMC_LLC_FLAG_DEL_LINK_ALL; 720 delllc->reason = htonl(reason); 721 /* send llc message */ 722 rc = smc_wr_tx_send(link, pend); 723put_out: 724 smc_wr_tx_link_put(link); 725 return rc; 726} 727 728/* send LLC test link request */ 729static int smc_llc_send_test_link(struct smc_link *link, u8 user_data[16]) 730{ 731 struct smc_llc_msg_test_link *testllc; 732 struct smc_wr_tx_pend_priv *pend; 733 struct smc_wr_buf *wr_buf; 734 int rc; 735 736 if (!smc_wr_tx_link_hold(link)) 737 return -ENOLINK; 738 rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 739 if (rc) 740 goto put_out; 741 testllc = (struct smc_llc_msg_test_link *)wr_buf; 742 memset(testllc, 0, sizeof(*testllc)); 743 testllc->hd.common.llc_type = SMC_LLC_TEST_LINK; 744 smc_llc_init_msg_hdr(&testllc->hd, link->lgr, sizeof(*testllc)); 745 memcpy(testllc->user_data, user_data, sizeof(testllc->user_data)); 746 /* send llc message */ 747 rc = smc_wr_tx_send(link, pend); 748put_out: 749 smc_wr_tx_link_put(link); 750 return rc; 751} 752 753/* schedule an llc send on link, may wait for buffers */ 754static int smc_llc_send_message(struct smc_link *link, void *llcbuf) 755{ 756 struct smc_wr_tx_pend_priv *pend; 757 struct smc_wr_buf *wr_buf; 758 int rc; 759 760 if (!smc_wr_tx_link_hold(link)) 761 return -ENOLINK; 762 rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 763 if (rc) 764 goto put_out; 765 memcpy(wr_buf, llcbuf, sizeof(union smc_llc_msg)); 766 rc = smc_wr_tx_send(link, pend); 767put_out: 768 smc_wr_tx_link_put(link); 769 return rc; 770} 771 772/* schedule an llc send on link, may wait for buffers, 773 * and wait for send completion notification. 774 * @return 0 on success 775 */ 776static int smc_llc_send_message_wait(struct smc_link *link, void *llcbuf) 777{ 778 struct smc_wr_tx_pend_priv *pend; 779 struct smc_wr_buf *wr_buf; 780 int rc; 781 782 if (!smc_wr_tx_link_hold(link)) 783 return -ENOLINK; 784 rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 785 if (rc) 786 goto put_out; 787 memcpy(wr_buf, llcbuf, sizeof(union smc_llc_msg)); 788 rc = smc_wr_tx_send_wait(link, pend, SMC_LLC_WAIT_TIME); 789put_out: 790 smc_wr_tx_link_put(link); 791 return rc; 792} 793 794/********************************* receive ***********************************/ 795 796static int smc_llc_alloc_alt_link(struct smc_link_group *lgr, 797 enum smc_lgr_type lgr_new_t) 798{ 799 int i; 800 801 if (lgr->type == SMC_LGR_SYMMETRIC || 802 (lgr->type != SMC_LGR_SINGLE && 803 (lgr_new_t == SMC_LGR_ASYMMETRIC_LOCAL || 804 lgr_new_t == SMC_LGR_ASYMMETRIC_PEER))) 805 return -EMLINK; 806 807 if (lgr_new_t == SMC_LGR_ASYMMETRIC_LOCAL || 808 lgr_new_t == SMC_LGR_ASYMMETRIC_PEER) { 809 for (i = SMC_LINKS_PER_LGR_MAX - 1; i >= 0; i--) 810 if (lgr->lnk[i].state == SMC_LNK_UNUSED) 811 return i; 812 } else { 813 for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) 814 if (lgr->lnk[i].state == SMC_LNK_UNUSED) 815 return i; 816 } 817 return -EMLINK; 818} 819 820/* send one add_link_continue msg */ 821static int smc_llc_add_link_cont(struct smc_link *link, 822 struct smc_link *link_new, u8 *num_rkeys_todo, 823 int *buf_lst, struct smc_buf_desc **buf_pos) 824{ 825 struct smc_llc_msg_add_link_cont *addc_llc; 826 struct smc_link_group *lgr = link->lgr; 827 int prim_lnk_idx, lnk_idx, i, rc; 828 struct smc_wr_tx_pend_priv *pend; 829 struct smc_wr_buf *wr_buf; 830 struct smc_buf_desc *rmb; 831 u8 n; 832 833 if (!smc_wr_tx_link_hold(link)) 834 return -ENOLINK; 835 rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 836 if (rc) 837 goto put_out; 838 addc_llc = (struct smc_llc_msg_add_link_cont *)wr_buf; 839 memset(addc_llc, 0, sizeof(*addc_llc)); 840 841 prim_lnk_idx = link->link_idx; 842 lnk_idx = link_new->link_idx; 843 addc_llc->link_num = link_new->link_id; 844 addc_llc->num_rkeys = *num_rkeys_todo; 845 n = *num_rkeys_todo; 846 for (i = 0; i < min_t(u8, n, SMC_LLC_RKEYS_PER_CONT_MSG); i++) { 847 if (!*buf_pos) { 848 addc_llc->num_rkeys = addc_llc->num_rkeys - 849 *num_rkeys_todo; 850 *num_rkeys_todo = 0; 851 break; 852 } 853 rmb = *buf_pos; 854 855 addc_llc->rt[i].rmb_key = htonl(rmb->mr_rx[prim_lnk_idx]->rkey); 856 addc_llc->rt[i].rmb_key_new = htonl(rmb->mr_rx[lnk_idx]->rkey); 857 addc_llc->rt[i].rmb_vaddr_new = 858 cpu_to_be64((u64)sg_dma_address(rmb->sgt[lnk_idx].sgl)); 859 860 (*num_rkeys_todo)--; 861 *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos); 862 while (*buf_pos && !(*buf_pos)->used) 863 *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos); 864 } 865 addc_llc->hd.common.llc_type = SMC_LLC_ADD_LINK_CONT; 866 addc_llc->hd.length = sizeof(struct smc_llc_msg_add_link_cont); 867 if (lgr->role == SMC_CLNT) 868 addc_llc->hd.flags |= SMC_LLC_FLAG_RESP; 869 rc = smc_wr_tx_send(link, pend); 870put_out: 871 smc_wr_tx_link_put(link); 872 return rc; 873} 874 875static int smc_llc_cli_rkey_exchange(struct smc_link *link, 876 struct smc_link *link_new) 877{ 878 struct smc_llc_msg_add_link_cont *addc_llc; 879 struct smc_link_group *lgr = link->lgr; 880 u8 max, num_rkeys_send, num_rkeys_recv; 881 struct smc_llc_qentry *qentry; 882 struct smc_buf_desc *buf_pos; 883 int buf_lst; 884 int rc = 0; 885 int i; 886 887 mutex_lock(&lgr->rmbs_lock); 888 num_rkeys_send = lgr->conns_num; 889 buf_pos = smc_llc_get_first_rmb(lgr, &buf_lst); 890 do { 891 qentry = smc_llc_wait(lgr, NULL, SMC_LLC_WAIT_TIME, 892 SMC_LLC_ADD_LINK_CONT); 893 if (!qentry) { 894 rc = -ETIMEDOUT; 895 break; 896 } 897 addc_llc = &qentry->msg.add_link_cont; 898 num_rkeys_recv = addc_llc->num_rkeys; 899 max = min_t(u8, num_rkeys_recv, SMC_LLC_RKEYS_PER_CONT_MSG); 900 for (i = 0; i < max; i++) { 901 smc_rtoken_set(lgr, link->link_idx, link_new->link_idx, 902 addc_llc->rt[i].rmb_key, 903 addc_llc->rt[i].rmb_vaddr_new, 904 addc_llc->rt[i].rmb_key_new); 905 num_rkeys_recv--; 906 } 907 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 908 rc = smc_llc_add_link_cont(link, link_new, &num_rkeys_send, 909 &buf_lst, &buf_pos); 910 if (rc) 911 break; 912 } while (num_rkeys_send || num_rkeys_recv); 913 914 mutex_unlock(&lgr->rmbs_lock); 915 return rc; 916} 917 918/* prepare and send an add link reject response */ 919static int smc_llc_cli_add_link_reject(struct smc_llc_qentry *qentry) 920{ 921 qentry->msg.raw.hdr.flags |= SMC_LLC_FLAG_RESP; 922 qentry->msg.raw.hdr.flags |= SMC_LLC_FLAG_ADD_LNK_REJ; 923 qentry->msg.raw.hdr.add_link_rej_rsn = SMC_LLC_REJ_RSN_NO_ALT_PATH; 924 smc_llc_init_msg_hdr(&qentry->msg.raw.hdr, qentry->link->lgr, 925 sizeof(qentry->msg)); 926 return smc_llc_send_message(qentry->link, &qentry->msg); 927} 928 929static int smc_llc_cli_conf_link(struct smc_link *link, 930 struct smc_init_info *ini, 931 struct smc_link *link_new, 932 enum smc_lgr_type lgr_new_t) 933{ 934 struct smc_link_group *lgr = link->lgr; 935 struct smc_llc_qentry *qentry = NULL; 936 int rc = 0; 937 938 /* receive CONFIRM LINK request over RoCE fabric */ 939 qentry = smc_llc_wait(lgr, NULL, SMC_LLC_WAIT_FIRST_TIME, 0); 940 if (!qentry) { 941 rc = smc_llc_send_delete_link(link, link_new->link_id, 942 SMC_LLC_REQ, false, 943 SMC_LLC_DEL_LOST_PATH); 944 return -ENOLINK; 945 } 946 if (qentry->msg.raw.hdr.common.llc_type != SMC_LLC_CONFIRM_LINK) { 947 /* received DELETE_LINK instead */ 948 qentry->msg.raw.hdr.flags |= SMC_LLC_FLAG_RESP; 949 smc_llc_send_message(link, &qentry->msg); 950 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 951 return -ENOLINK; 952 } 953 smc_llc_save_peer_uid(qentry); 954 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 955 956 rc = smc_ib_modify_qp_rts(link_new); 957 if (rc) { 958 smc_llc_send_delete_link(link, link_new->link_id, SMC_LLC_REQ, 959 false, SMC_LLC_DEL_LOST_PATH); 960 return -ENOLINK; 961 } 962 smc_wr_remember_qp_attr(link_new); 963 964 rc = smcr_buf_reg_lgr(link_new); 965 if (rc) { 966 smc_llc_send_delete_link(link, link_new->link_id, SMC_LLC_REQ, 967 false, SMC_LLC_DEL_LOST_PATH); 968 return -ENOLINK; 969 } 970 971 /* send CONFIRM LINK response over RoCE fabric */ 972 rc = smc_llc_send_confirm_link(link_new, SMC_LLC_RESP); 973 if (rc) { 974 smc_llc_send_delete_link(link, link_new->link_id, SMC_LLC_REQ, 975 false, SMC_LLC_DEL_LOST_PATH); 976 return -ENOLINK; 977 } 978 smc_llc_link_active(link_new); 979 if (lgr_new_t == SMC_LGR_ASYMMETRIC_LOCAL || 980 lgr_new_t == SMC_LGR_ASYMMETRIC_PEER) 981 smcr_lgr_set_type_asym(lgr, lgr_new_t, link_new->link_idx); 982 else 983 smcr_lgr_set_type(lgr, lgr_new_t); 984 return 0; 985} 986 987static void smc_llc_save_add_link_rkeys(struct smc_link *link, 988 struct smc_link *link_new) 989{ 990 struct smc_llc_msg_add_link_v2_ext *ext; 991 struct smc_link_group *lgr = link->lgr; 992 int max, i; 993 994 ext = (struct smc_llc_msg_add_link_v2_ext *)((u8 *)lgr->wr_rx_buf_v2 + 995 SMC_WR_TX_SIZE); 996 max = min_t(u8, ext->num_rkeys, SMC_LLC_RKEYS_PER_MSG_V2); 997 mutex_lock(&lgr->rmbs_lock); 998 for (i = 0; i < max; i++) { 999 smc_rtoken_set(lgr, link->link_idx, link_new->link_idx, 1000 ext->rt[i].rmb_key, 1001 ext->rt[i].rmb_vaddr_new, 1002 ext->rt[i].rmb_key_new); 1003 } 1004 mutex_unlock(&lgr->rmbs_lock); 1005} 1006 1007static void smc_llc_save_add_link_info(struct smc_link *link, 1008 struct smc_llc_msg_add_link *add_llc) 1009{ 1010 link->peer_qpn = ntoh24(add_llc->sender_qp_num); 1011 memcpy(link->peer_gid, add_llc->sender_gid, SMC_GID_SIZE); 1012 memcpy(link->peer_mac, add_llc->sender_mac, ETH_ALEN); 1013 link->peer_psn = ntoh24(add_llc->initial_psn); 1014 link->peer_mtu = add_llc->qp_mtu; 1015} 1016 1017/* as an SMC client, process an add link request */ 1018int smc_llc_cli_add_link(struct smc_link *link, struct smc_llc_qentry *qentry) 1019{ 1020 struct smc_llc_msg_add_link *llc = &qentry->msg.add_link; 1021 enum smc_lgr_type lgr_new_t = SMC_LGR_SYMMETRIC; 1022 struct smc_link_group *lgr = smc_get_lgr(link); 1023 struct smc_init_info *ini = NULL; 1024 struct smc_link *lnk_new = NULL; 1025 int lnk_idx, rc = 0; 1026 1027 if (!llc->qp_mtu) 1028 goto out_reject; 1029 1030 ini = kzalloc(sizeof(*ini), GFP_KERNEL); 1031 if (!ini) { 1032 rc = -ENOMEM; 1033 goto out_reject; 1034 } 1035 1036 ini->vlan_id = lgr->vlan_id; 1037 if (lgr->smc_version == SMC_V2) { 1038 ini->check_smcrv2 = true; 1039 ini->smcrv2.saddr = lgr->saddr; 1040 ini->smcrv2.daddr = smc_ib_gid_to_ipv4(llc->sender_gid); 1041 } 1042 smc_pnet_find_alt_roce(lgr, ini, link->smcibdev); 1043 if (!memcmp(llc->sender_gid, link->peer_gid, SMC_GID_SIZE) && 1044 (lgr->smc_version == SMC_V2 || 1045 !memcmp(llc->sender_mac, link->peer_mac, ETH_ALEN))) { 1046 if (!ini->ib_dev && !ini->smcrv2.ib_dev_v2) 1047 goto out_reject; 1048 lgr_new_t = SMC_LGR_ASYMMETRIC_PEER; 1049 } 1050 if (lgr->smc_version == SMC_V2 && !ini->smcrv2.ib_dev_v2) { 1051 lgr_new_t = SMC_LGR_ASYMMETRIC_LOCAL; 1052 ini->smcrv2.ib_dev_v2 = link->smcibdev; 1053 ini->smcrv2.ib_port_v2 = link->ibport; 1054 } else if (lgr->smc_version < SMC_V2 && !ini->ib_dev) { 1055 lgr_new_t = SMC_LGR_ASYMMETRIC_LOCAL; 1056 ini->ib_dev = link->smcibdev; 1057 ini->ib_port = link->ibport; 1058 } 1059 lnk_idx = smc_llc_alloc_alt_link(lgr, lgr_new_t); 1060 if (lnk_idx < 0) 1061 goto out_reject; 1062 lnk_new = &lgr->lnk[lnk_idx]; 1063 rc = smcr_link_init(lgr, lnk_new, lnk_idx, ini); 1064 if (rc) 1065 goto out_reject; 1066 smc_llc_save_add_link_info(lnk_new, llc); 1067 lnk_new->link_id = llc->link_num; /* SMC server assigns link id */ 1068 smc_llc_link_set_uid(lnk_new); 1069 1070 rc = smc_ib_ready_link(lnk_new); 1071 if (rc) 1072 goto out_clear_lnk; 1073 1074 rc = smcr_buf_map_lgr(lnk_new); 1075 if (rc) 1076 goto out_clear_lnk; 1077 1078 rc = smc_llc_send_add_link(link, 1079 lnk_new->smcibdev->mac[lnk_new->ibport - 1], 1080 lnk_new->gid, lnk_new, SMC_LLC_RESP); 1081 if (rc) 1082 goto out_clear_lnk; 1083 if (lgr->smc_version == SMC_V2) { 1084 smc_llc_save_add_link_rkeys(link, lnk_new); 1085 } else { 1086 rc = smc_llc_cli_rkey_exchange(link, lnk_new); 1087 if (rc) { 1088 rc = 0; 1089 goto out_clear_lnk; 1090 } 1091 } 1092 rc = smc_llc_cli_conf_link(link, ini, lnk_new, lgr_new_t); 1093 if (!rc) 1094 goto out; 1095out_clear_lnk: 1096 lnk_new->state = SMC_LNK_INACTIVE; 1097 smcr_link_clear(lnk_new, false); 1098out_reject: 1099 smc_llc_cli_add_link_reject(qentry); 1100out: 1101 kfree(ini); 1102 kfree(qentry); 1103 return rc; 1104} 1105 1106static void smc_llc_send_request_add_link(struct smc_link *link) 1107{ 1108 struct smc_llc_msg_req_add_link_v2 *llc; 1109 struct smc_wr_tx_pend_priv *pend; 1110 struct smc_wr_v2_buf *wr_buf; 1111 struct smc_gidlist gidlist; 1112 int rc, len, i; 1113 1114 if (!smc_wr_tx_link_hold(link)) 1115 return; 1116 if (link->lgr->type == SMC_LGR_SYMMETRIC || 1117 link->lgr->type == SMC_LGR_ASYMMETRIC_PEER) 1118 goto put_out; 1119 1120 smc_fill_gid_list(link->lgr, &gidlist, link->smcibdev, link->gid); 1121 if (gidlist.len <= 1) 1122 goto put_out; 1123 1124 rc = smc_llc_add_pending_send_v2(link, &wr_buf, &pend); 1125 if (rc) 1126 goto put_out; 1127 llc = (struct smc_llc_msg_req_add_link_v2 *)wr_buf; 1128 memset(llc, 0, SMC_WR_TX_SIZE); 1129 1130 llc->hd.common.llc_type = SMC_LLC_REQ_ADD_LINK; 1131 for (i = 0; i < gidlist.len; i++) 1132 memcpy(llc->gid[i], gidlist.list[i], sizeof(gidlist.list[0])); 1133 llc->gid_cnt = gidlist.len; 1134 len = sizeof(*llc) + (gidlist.len * sizeof(gidlist.list[0])); 1135 smc_llc_init_msg_hdr(&llc->hd, link->lgr, len); 1136 rc = smc_wr_tx_v2_send(link, pend, len); 1137 if (!rc) 1138 /* set REQ_ADD_LINK flow and wait for response from peer */ 1139 link->lgr->llc_flow_lcl.type = SMC_LLC_FLOW_REQ_ADD_LINK; 1140put_out: 1141 smc_wr_tx_link_put(link); 1142} 1143 1144/* as an SMC client, invite server to start the add_link processing */ 1145static void smc_llc_cli_add_link_invite(struct smc_link *link, 1146 struct smc_llc_qentry *qentry) 1147{ 1148 struct smc_link_group *lgr = smc_get_lgr(link); 1149 struct smc_init_info *ini = NULL; 1150 1151 if (lgr->smc_version == SMC_V2) { 1152 smc_llc_send_request_add_link(link); 1153 goto out; 1154 } 1155 1156 if (lgr->type == SMC_LGR_SYMMETRIC || 1157 lgr->type == SMC_LGR_ASYMMETRIC_PEER) 1158 goto out; 1159 1160 ini = kzalloc(sizeof(*ini), GFP_KERNEL); 1161 if (!ini) 1162 goto out; 1163 1164 ini->vlan_id = lgr->vlan_id; 1165 smc_pnet_find_alt_roce(lgr, ini, link->smcibdev); 1166 if (!ini->ib_dev) 1167 goto out; 1168 1169 smc_llc_send_add_link(link, ini->ib_dev->mac[ini->ib_port - 1], 1170 ini->ib_gid, NULL, SMC_LLC_REQ); 1171out: 1172 kfree(ini); 1173 kfree(qentry); 1174} 1175 1176static bool smc_llc_is_empty_llc_message(union smc_llc_msg *llc) 1177{ 1178 int i; 1179 1180 for (i = 0; i < ARRAY_SIZE(llc->raw.data); i++) 1181 if (llc->raw.data[i]) 1182 return false; 1183 return true; 1184} 1185 1186static bool smc_llc_is_local_add_link(union smc_llc_msg *llc) 1187{ 1188 if (llc->raw.hdr.common.llc_type == SMC_LLC_ADD_LINK && 1189 smc_llc_is_empty_llc_message(llc)) 1190 return true; 1191 return false; 1192} 1193 1194static void smc_llc_process_cli_add_link(struct smc_link_group *lgr) 1195{ 1196 struct smc_llc_qentry *qentry; 1197 1198 qentry = smc_llc_flow_qentry_clr(&lgr->llc_flow_lcl); 1199 1200 mutex_lock(&lgr->llc_conf_mutex); 1201 if (smc_llc_is_local_add_link(&qentry->msg)) 1202 smc_llc_cli_add_link_invite(qentry->link, qentry); 1203 else 1204 smc_llc_cli_add_link(qentry->link, qentry); 1205 mutex_unlock(&lgr->llc_conf_mutex); 1206} 1207 1208static int smc_llc_active_link_count(struct smc_link_group *lgr) 1209{ 1210 int i, link_count = 0; 1211 1212 for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 1213 if (!smc_link_active(&lgr->lnk[i])) 1214 continue; 1215 link_count++; 1216 } 1217 return link_count; 1218} 1219 1220/* find the asymmetric link when 3 links are established */ 1221static struct smc_link *smc_llc_find_asym_link(struct smc_link_group *lgr) 1222{ 1223 int asym_idx = -ENOENT; 1224 int i, j, k; 1225 bool found; 1226 1227 /* determine asymmetric link */ 1228 found = false; 1229 for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 1230 for (j = i + 1; j < SMC_LINKS_PER_LGR_MAX; j++) { 1231 if (!smc_link_usable(&lgr->lnk[i]) || 1232 !smc_link_usable(&lgr->lnk[j])) 1233 continue; 1234 if (!memcmp(lgr->lnk[i].gid, lgr->lnk[j].gid, 1235 SMC_GID_SIZE)) { 1236 found = true; /* asym_lnk is i or j */ 1237 break; 1238 } 1239 } 1240 if (found) 1241 break; 1242 } 1243 if (!found) 1244 goto out; /* no asymmetric link */ 1245 for (k = 0; k < SMC_LINKS_PER_LGR_MAX; k++) { 1246 if (!smc_link_usable(&lgr->lnk[k])) 1247 continue; 1248 if (k != i && 1249 !memcmp(lgr->lnk[i].peer_gid, lgr->lnk[k].peer_gid, 1250 SMC_GID_SIZE)) { 1251 asym_idx = i; 1252 break; 1253 } 1254 if (k != j && 1255 !memcmp(lgr->lnk[j].peer_gid, lgr->lnk[k].peer_gid, 1256 SMC_GID_SIZE)) { 1257 asym_idx = j; 1258 break; 1259 } 1260 } 1261out: 1262 return (asym_idx < 0) ? NULL : &lgr->lnk[asym_idx]; 1263} 1264 1265static void smc_llc_delete_asym_link(struct smc_link_group *lgr) 1266{ 1267 struct smc_link *lnk_new = NULL, *lnk_asym; 1268 struct smc_llc_qentry *qentry; 1269 int rc; 1270 1271 lnk_asym = smc_llc_find_asym_link(lgr); 1272 if (!lnk_asym) 1273 return; /* no asymmetric link */ 1274 if (!smc_link_downing(&lnk_asym->state)) 1275 return; 1276 lnk_new = smc_switch_conns(lgr, lnk_asym, false); 1277 smc_wr_tx_wait_no_pending_sends(lnk_asym); 1278 if (!lnk_new) 1279 goto out_free; 1280 /* change flow type from ADD_LINK into DEL_LINK */ 1281 lgr->llc_flow_lcl.type = SMC_LLC_FLOW_DEL_LINK; 1282 rc = smc_llc_send_delete_link(lnk_new, lnk_asym->link_id, SMC_LLC_REQ, 1283 true, SMC_LLC_DEL_NO_ASYM_NEEDED); 1284 if (rc) { 1285 smcr_link_down_cond(lnk_new); 1286 goto out_free; 1287 } 1288 qentry = smc_llc_wait(lgr, lnk_new, SMC_LLC_WAIT_TIME, 1289 SMC_LLC_DELETE_LINK); 1290 if (!qentry) { 1291 smcr_link_down_cond(lnk_new); 1292 goto out_free; 1293 } 1294 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1295out_free: 1296 smcr_link_clear(lnk_asym, true); 1297} 1298 1299static int smc_llc_srv_rkey_exchange(struct smc_link *link, 1300 struct smc_link *link_new) 1301{ 1302 struct smc_llc_msg_add_link_cont *addc_llc; 1303 struct smc_link_group *lgr = link->lgr; 1304 u8 max, num_rkeys_send, num_rkeys_recv; 1305 struct smc_llc_qentry *qentry = NULL; 1306 struct smc_buf_desc *buf_pos; 1307 int buf_lst; 1308 int rc = 0; 1309 int i; 1310 1311 mutex_lock(&lgr->rmbs_lock); 1312 num_rkeys_send = lgr->conns_num; 1313 buf_pos = smc_llc_get_first_rmb(lgr, &buf_lst); 1314 do { 1315 smc_llc_add_link_cont(link, link_new, &num_rkeys_send, 1316 &buf_lst, &buf_pos); 1317 qentry = smc_llc_wait(lgr, link, SMC_LLC_WAIT_TIME, 1318 SMC_LLC_ADD_LINK_CONT); 1319 if (!qentry) { 1320 rc = -ETIMEDOUT; 1321 goto out; 1322 } 1323 addc_llc = &qentry->msg.add_link_cont; 1324 num_rkeys_recv = addc_llc->num_rkeys; 1325 max = min_t(u8, num_rkeys_recv, SMC_LLC_RKEYS_PER_CONT_MSG); 1326 for (i = 0; i < max; i++) { 1327 smc_rtoken_set(lgr, link->link_idx, link_new->link_idx, 1328 addc_llc->rt[i].rmb_key, 1329 addc_llc->rt[i].rmb_vaddr_new, 1330 addc_llc->rt[i].rmb_key_new); 1331 num_rkeys_recv--; 1332 } 1333 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1334 } while (num_rkeys_send || num_rkeys_recv); 1335out: 1336 mutex_unlock(&lgr->rmbs_lock); 1337 return rc; 1338} 1339 1340static int smc_llc_srv_conf_link(struct smc_link *link, 1341 struct smc_link *link_new, 1342 enum smc_lgr_type lgr_new_t) 1343{ 1344 struct smc_link_group *lgr = link->lgr; 1345 struct smc_llc_qentry *qentry = NULL; 1346 int rc; 1347 1348 /* send CONFIRM LINK request over the RoCE fabric */ 1349 rc = smc_llc_send_confirm_link(link_new, SMC_LLC_REQ); 1350 if (rc) 1351 return -ENOLINK; 1352 /* receive CONFIRM LINK response over the RoCE fabric */ 1353 qentry = smc_llc_wait(lgr, link, SMC_LLC_WAIT_FIRST_TIME, 0); 1354 if (!qentry || 1355 qentry->msg.raw.hdr.common.llc_type != SMC_LLC_CONFIRM_LINK) { 1356 /* send DELETE LINK */ 1357 smc_llc_send_delete_link(link, link_new->link_id, SMC_LLC_REQ, 1358 false, SMC_LLC_DEL_LOST_PATH); 1359 if (qentry) 1360 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1361 return -ENOLINK; 1362 } 1363 smc_llc_save_peer_uid(qentry); 1364 smc_llc_link_active(link_new); 1365 if (lgr_new_t == SMC_LGR_ASYMMETRIC_LOCAL || 1366 lgr_new_t == SMC_LGR_ASYMMETRIC_PEER) 1367 smcr_lgr_set_type_asym(lgr, lgr_new_t, link_new->link_idx); 1368 else 1369 smcr_lgr_set_type(lgr, lgr_new_t); 1370 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1371 return 0; 1372} 1373 1374static void smc_llc_send_req_add_link_response(struct smc_llc_qentry *qentry) 1375{ 1376 qentry->msg.raw.hdr.flags |= SMC_LLC_FLAG_RESP; 1377 smc_llc_init_msg_hdr(&qentry->msg.raw.hdr, qentry->link->lgr, 1378 sizeof(qentry->msg)); 1379 memset(&qentry->msg.raw.data, 0, sizeof(qentry->msg.raw.data)); 1380 smc_llc_send_message(qentry->link, &qentry->msg); 1381} 1382 1383int smc_llc_srv_add_link(struct smc_link *link, 1384 struct smc_llc_qentry *req_qentry) 1385{ 1386 enum smc_lgr_type lgr_new_t = SMC_LGR_SYMMETRIC; 1387 struct smc_link_group *lgr = link->lgr; 1388 struct smc_llc_msg_add_link *add_llc; 1389 struct smc_llc_qentry *qentry = NULL; 1390 bool send_req_add_link_resp = false; 1391 struct smc_link *link_new = NULL; 1392 struct smc_init_info *ini = NULL; 1393 int lnk_idx, rc = 0; 1394 1395 if (req_qentry && 1396 req_qentry->msg.raw.hdr.common.llc_type == SMC_LLC_REQ_ADD_LINK) 1397 send_req_add_link_resp = true; 1398 1399 ini = kzalloc(sizeof(*ini), GFP_KERNEL); 1400 if (!ini) { 1401 rc = -ENOMEM; 1402 goto out; 1403 } 1404 1405 /* ignore client add link recommendation, start new flow */ 1406 ini->vlan_id = lgr->vlan_id; 1407 if (lgr->smc_version == SMC_V2) { 1408 ini->check_smcrv2 = true; 1409 ini->smcrv2.saddr = lgr->saddr; 1410 if (send_req_add_link_resp) { 1411 struct smc_llc_msg_req_add_link_v2 *req_add = 1412 &req_qentry->msg.req_add_link; 1413 1414 ini->smcrv2.daddr = smc_ib_gid_to_ipv4(req_add->gid[0]); 1415 } 1416 } 1417 smc_pnet_find_alt_roce(lgr, ini, link->smcibdev); 1418 if (lgr->smc_version == SMC_V2 && !ini->smcrv2.ib_dev_v2) { 1419 lgr_new_t = SMC_LGR_ASYMMETRIC_LOCAL; 1420 ini->smcrv2.ib_dev_v2 = link->smcibdev; 1421 ini->smcrv2.ib_port_v2 = link->ibport; 1422 } else if (lgr->smc_version < SMC_V2 && !ini->ib_dev) { 1423 lgr_new_t = SMC_LGR_ASYMMETRIC_LOCAL; 1424 ini->ib_dev = link->smcibdev; 1425 ini->ib_port = link->ibport; 1426 } 1427 lnk_idx = smc_llc_alloc_alt_link(lgr, lgr_new_t); 1428 if (lnk_idx < 0) { 1429 rc = 0; 1430 goto out; 1431 } 1432 1433 rc = smcr_link_init(lgr, &lgr->lnk[lnk_idx], lnk_idx, ini); 1434 if (rc) 1435 goto out; 1436 link_new = &lgr->lnk[lnk_idx]; 1437 1438 rc = smcr_buf_map_lgr(link_new); 1439 if (rc) 1440 goto out_err; 1441 1442 rc = smc_llc_send_add_link(link, 1443 link_new->smcibdev->mac[link_new->ibport-1], 1444 link_new->gid, link_new, SMC_LLC_REQ); 1445 if (rc) 1446 goto out_err; 1447 send_req_add_link_resp = false; 1448 /* receive ADD LINK response over the RoCE fabric */ 1449 qentry = smc_llc_wait(lgr, link, SMC_LLC_WAIT_TIME, SMC_LLC_ADD_LINK); 1450 if (!qentry) { 1451 rc = -ETIMEDOUT; 1452 goto out_err; 1453 } 1454 add_llc = &qentry->msg.add_link; 1455 if (add_llc->hd.flags & SMC_LLC_FLAG_ADD_LNK_REJ) { 1456 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1457 rc = -ENOLINK; 1458 goto out_err; 1459 } 1460 if (lgr->type == SMC_LGR_SINGLE && 1461 (!memcmp(add_llc->sender_gid, link->peer_gid, SMC_GID_SIZE) && 1462 (lgr->smc_version == SMC_V2 || 1463 !memcmp(add_llc->sender_mac, link->peer_mac, ETH_ALEN)))) { 1464 lgr_new_t = SMC_LGR_ASYMMETRIC_PEER; 1465 } 1466 smc_llc_save_add_link_info(link_new, add_llc); 1467 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1468 1469 rc = smc_ib_ready_link(link_new); 1470 if (rc) 1471 goto out_err; 1472 rc = smcr_buf_reg_lgr(link_new); 1473 if (rc) 1474 goto out_err; 1475 if (lgr->smc_version == SMC_V2) { 1476 smc_llc_save_add_link_rkeys(link, link_new); 1477 } else { 1478 rc = smc_llc_srv_rkey_exchange(link, link_new); 1479 if (rc) 1480 goto out_err; 1481 } 1482 rc = smc_llc_srv_conf_link(link, link_new, lgr_new_t); 1483 if (rc) 1484 goto out_err; 1485 kfree(ini); 1486 return 0; 1487out_err: 1488 if (link_new) { 1489 link_new->state = SMC_LNK_INACTIVE; 1490 smcr_link_clear(link_new, false); 1491 } 1492out: 1493 kfree(ini); 1494 if (send_req_add_link_resp) 1495 smc_llc_send_req_add_link_response(req_qentry); 1496 return rc; 1497} 1498 1499static void smc_llc_process_srv_add_link(struct smc_link_group *lgr) 1500{ 1501 struct smc_link *link = lgr->llc_flow_lcl.qentry->link; 1502 struct smc_llc_qentry *qentry; 1503 int rc; 1504 1505 qentry = smc_llc_flow_qentry_clr(&lgr->llc_flow_lcl); 1506 1507 mutex_lock(&lgr->llc_conf_mutex); 1508 rc = smc_llc_srv_add_link(link, qentry); 1509 if (!rc && lgr->type == SMC_LGR_SYMMETRIC) { 1510 /* delete any asymmetric link */ 1511 smc_llc_delete_asym_link(lgr); 1512 } 1513 mutex_unlock(&lgr->llc_conf_mutex); 1514 kfree(qentry); 1515} 1516 1517/* enqueue a local add_link req to trigger a new add_link flow */ 1518void smc_llc_add_link_local(struct smc_link *link) 1519{ 1520 struct smc_llc_msg_add_link add_llc = {}; 1521 1522 add_llc.hd.common.llc_type = SMC_LLC_ADD_LINK; 1523 smc_llc_init_msg_hdr(&add_llc.hd, link->lgr, sizeof(add_llc)); 1524 /* no dev and port needed */ 1525 smc_llc_enqueue(link, (union smc_llc_msg *)&add_llc); 1526} 1527 1528/* worker to process an add link message */ 1529static void smc_llc_add_link_work(struct work_struct *work) 1530{ 1531 struct smc_link_group *lgr = container_of(work, struct smc_link_group, 1532 llc_add_link_work); 1533 1534 if (list_empty(&lgr->list)) { 1535 /* link group is terminating */ 1536 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1537 goto out; 1538 } 1539 1540 if (lgr->role == SMC_CLNT) 1541 smc_llc_process_cli_add_link(lgr); 1542 else 1543 smc_llc_process_srv_add_link(lgr); 1544out: 1545 if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_REQ_ADD_LINK) 1546 smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); 1547} 1548 1549/* enqueue a local del_link msg to trigger a new del_link flow, 1550 * called only for role SMC_SERV 1551 */ 1552void smc_llc_srv_delete_link_local(struct smc_link *link, u8 del_link_id) 1553{ 1554 struct smc_llc_msg_del_link del_llc = {}; 1555 1556 del_llc.hd.common.llc_type = SMC_LLC_DELETE_LINK; 1557 smc_llc_init_msg_hdr(&del_llc.hd, link->lgr, sizeof(del_llc)); 1558 del_llc.link_num = del_link_id; 1559 del_llc.reason = htonl(SMC_LLC_DEL_LOST_PATH); 1560 del_llc.hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY; 1561 smc_llc_enqueue(link, (union smc_llc_msg *)&del_llc); 1562} 1563 1564static void smc_llc_process_cli_delete_link(struct smc_link_group *lgr) 1565{ 1566 struct smc_link *lnk_del = NULL, *lnk_asym, *lnk; 1567 struct smc_llc_msg_del_link *del_llc; 1568 struct smc_llc_qentry *qentry; 1569 int active_links; 1570 int lnk_idx; 1571 1572 qentry = smc_llc_flow_qentry_clr(&lgr->llc_flow_lcl); 1573 lnk = qentry->link; 1574 del_llc = &qentry->msg.delete_link; 1575 1576 if (del_llc->hd.flags & SMC_LLC_FLAG_DEL_LINK_ALL) { 1577 smc_lgr_terminate_sched(lgr); 1578 goto out; 1579 } 1580 mutex_lock(&lgr->llc_conf_mutex); 1581 /* delete single link */ 1582 for (lnk_idx = 0; lnk_idx < SMC_LINKS_PER_LGR_MAX; lnk_idx++) { 1583 if (lgr->lnk[lnk_idx].link_id != del_llc->link_num) 1584 continue; 1585 lnk_del = &lgr->lnk[lnk_idx]; 1586 break; 1587 } 1588 del_llc->hd.flags |= SMC_LLC_FLAG_RESP; 1589 if (!lnk_del) { 1590 /* link was not found */ 1591 del_llc->reason = htonl(SMC_LLC_DEL_NOLNK); 1592 smc_llc_send_message(lnk, &qentry->msg); 1593 goto out_unlock; 1594 } 1595 lnk_asym = smc_llc_find_asym_link(lgr); 1596 1597 del_llc->reason = 0; 1598 smc_llc_send_message(lnk, &qentry->msg); /* response */ 1599 1600 if (smc_link_downing(&lnk_del->state)) 1601 smc_switch_conns(lgr, lnk_del, false); 1602 smcr_link_clear(lnk_del, true); 1603 1604 active_links = smc_llc_active_link_count(lgr); 1605 if (lnk_del == lnk_asym) { 1606 /* expected deletion of asym link, don't change lgr state */ 1607 } else if (active_links == 1) { 1608 smcr_lgr_set_type(lgr, SMC_LGR_SINGLE); 1609 } else if (!active_links) { 1610 smcr_lgr_set_type(lgr, SMC_LGR_NONE); 1611 smc_lgr_terminate_sched(lgr); 1612 } 1613out_unlock: 1614 mutex_unlock(&lgr->llc_conf_mutex); 1615out: 1616 kfree(qentry); 1617} 1618 1619/* try to send a DELETE LINK ALL request on any active link, 1620 * waiting for send completion 1621 */ 1622void smc_llc_send_link_delete_all(struct smc_link_group *lgr, bool ord, u32 rsn) 1623{ 1624 struct smc_llc_msg_del_link delllc = {}; 1625 int i; 1626 1627 delllc.hd.common.llc_type = SMC_LLC_DELETE_LINK; 1628 smc_llc_init_msg_hdr(&delllc.hd, lgr, sizeof(delllc)); 1629 if (ord) 1630 delllc.hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY; 1631 delllc.hd.flags |= SMC_LLC_FLAG_DEL_LINK_ALL; 1632 delllc.reason = htonl(rsn); 1633 1634 for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 1635 if (!smc_link_sendable(&lgr->lnk[i])) 1636 continue; 1637 if (!smc_llc_send_message_wait(&lgr->lnk[i], &delllc)) 1638 break; 1639 } 1640} 1641 1642static void smc_llc_process_srv_delete_link(struct smc_link_group *lgr) 1643{ 1644 struct smc_llc_msg_del_link *del_llc; 1645 struct smc_link *lnk, *lnk_del; 1646 struct smc_llc_qentry *qentry; 1647 int active_links; 1648 int i; 1649 1650 mutex_lock(&lgr->llc_conf_mutex); 1651 qentry = smc_llc_flow_qentry_clr(&lgr->llc_flow_lcl); 1652 lnk = qentry->link; 1653 del_llc = &qentry->msg.delete_link; 1654 1655 if (qentry->msg.delete_link.hd.flags & SMC_LLC_FLAG_DEL_LINK_ALL) { 1656 /* delete entire lgr */ 1657 smc_llc_send_link_delete_all(lgr, true, ntohl( 1658 qentry->msg.delete_link.reason)); 1659 smc_lgr_terminate_sched(lgr); 1660 goto out; 1661 } 1662 /* delete single link */ 1663 lnk_del = NULL; 1664 for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 1665 if (lgr->lnk[i].link_id == del_llc->link_num) { 1666 lnk_del = &lgr->lnk[i]; 1667 break; 1668 } 1669 } 1670 if (!lnk_del) 1671 goto out; /* asymmetric link already deleted */ 1672 1673 if (smc_link_downing(&lnk_del->state)) { 1674 if (smc_switch_conns(lgr, lnk_del, false)) 1675 smc_wr_tx_wait_no_pending_sends(lnk_del); 1676 } 1677 if (!list_empty(&lgr->list)) { 1678 /* qentry is either a request from peer (send it back to 1679 * initiate the DELETE_LINK processing), or a locally 1680 * enqueued DELETE_LINK request (forward it) 1681 */ 1682 if (!smc_llc_send_message(lnk, &qentry->msg)) { 1683 struct smc_llc_qentry *qentry2; 1684 1685 qentry2 = smc_llc_wait(lgr, lnk, SMC_LLC_WAIT_TIME, 1686 SMC_LLC_DELETE_LINK); 1687 if (qentry2) 1688 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1689 } 1690 } 1691 smcr_link_clear(lnk_del, true); 1692 1693 active_links = smc_llc_active_link_count(lgr); 1694 if (active_links == 1) { 1695 smcr_lgr_set_type(lgr, SMC_LGR_SINGLE); 1696 } else if (!active_links) { 1697 smcr_lgr_set_type(lgr, SMC_LGR_NONE); 1698 smc_lgr_terminate_sched(lgr); 1699 } 1700 1701 if (lgr->type == SMC_LGR_SINGLE && !list_empty(&lgr->list)) { 1702 /* trigger setup of asymm alt link */ 1703 smc_llc_add_link_local(lnk); 1704 } 1705out: 1706 mutex_unlock(&lgr->llc_conf_mutex); 1707 kfree(qentry); 1708} 1709 1710static void smc_llc_delete_link_work(struct work_struct *work) 1711{ 1712 struct smc_link_group *lgr = container_of(work, struct smc_link_group, 1713 llc_del_link_work); 1714 1715 if (list_empty(&lgr->list)) { 1716 /* link group is terminating */ 1717 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1718 goto out; 1719 } 1720 1721 if (lgr->role == SMC_CLNT) 1722 smc_llc_process_cli_delete_link(lgr); 1723 else 1724 smc_llc_process_srv_delete_link(lgr); 1725out: 1726 smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); 1727} 1728 1729/* process a confirm_rkey request from peer, remote flow */ 1730static void smc_llc_rmt_conf_rkey(struct smc_link_group *lgr) 1731{ 1732 struct smc_llc_msg_confirm_rkey *llc; 1733 struct smc_llc_qentry *qentry; 1734 struct smc_link *link; 1735 int num_entries; 1736 int rk_idx; 1737 int i; 1738 1739 qentry = lgr->llc_flow_rmt.qentry; 1740 llc = &qentry->msg.confirm_rkey; 1741 link = qentry->link; 1742 1743 num_entries = llc->rtoken[0].num_rkeys; 1744 if (num_entries > SMC_LLC_RKEYS_PER_MSG) 1745 goto out_err; 1746 /* first rkey entry is for receiving link */ 1747 rk_idx = smc_rtoken_add(link, 1748 llc->rtoken[0].rmb_vaddr, 1749 llc->rtoken[0].rmb_key); 1750 if (rk_idx < 0) 1751 goto out_err; 1752 1753 for (i = 1; i <= min_t(u8, num_entries, SMC_LLC_RKEYS_PER_MSG - 1); i++) 1754 smc_rtoken_set2(lgr, rk_idx, llc->rtoken[i].link_id, 1755 llc->rtoken[i].rmb_vaddr, 1756 llc->rtoken[i].rmb_key); 1757 /* max links is 3 so there is no need to support conf_rkey_cont msgs */ 1758 goto out; 1759out_err: 1760 llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG; 1761 llc->hd.flags |= SMC_LLC_FLAG_RKEY_RETRY; 1762out: 1763 llc->hd.flags |= SMC_LLC_FLAG_RESP; 1764 smc_llc_init_msg_hdr(&llc->hd, link->lgr, sizeof(*llc)); 1765 smc_llc_send_message(link, &qentry->msg); 1766 smc_llc_flow_qentry_del(&lgr->llc_flow_rmt); 1767} 1768 1769/* process a delete_rkey request from peer, remote flow */ 1770static void smc_llc_rmt_delete_rkey(struct smc_link_group *lgr) 1771{ 1772 struct smc_llc_msg_delete_rkey *llc; 1773 struct smc_llc_qentry *qentry; 1774 struct smc_link *link; 1775 u8 err_mask = 0; 1776 int i, max; 1777 1778 qentry = lgr->llc_flow_rmt.qentry; 1779 llc = &qentry->msg.delete_rkey; 1780 link = qentry->link; 1781 1782 if (lgr->smc_version == SMC_V2) { 1783 struct smc_llc_msg_delete_rkey_v2 *llcv2; 1784 1785 memcpy(lgr->wr_rx_buf_v2, llc, sizeof(*llc)); 1786 llcv2 = (struct smc_llc_msg_delete_rkey_v2 *)lgr->wr_rx_buf_v2; 1787 llcv2->num_inval_rkeys = 0; 1788 1789 max = min_t(u8, llcv2->num_rkeys, SMC_LLC_RKEYS_PER_MSG_V2); 1790 for (i = 0; i < max; i++) { 1791 if (smc_rtoken_delete(link, llcv2->rkey[i])) 1792 llcv2->num_inval_rkeys++; 1793 } 1794 memset(&llc->rkey[0], 0, sizeof(llc->rkey)); 1795 memset(&llc->reserved2, 0, sizeof(llc->reserved2)); 1796 smc_llc_init_msg_hdr(&llc->hd, link->lgr, sizeof(*llc)); 1797 if (llcv2->num_inval_rkeys) { 1798 llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG; 1799 llc->err_mask = llcv2->num_inval_rkeys; 1800 } 1801 goto finish; 1802 } 1803 1804 max = min_t(u8, llc->num_rkeys, SMC_LLC_DEL_RKEY_MAX); 1805 for (i = 0; i < max; i++) { 1806 if (smc_rtoken_delete(link, llc->rkey[i])) 1807 err_mask |= 1 << (SMC_LLC_DEL_RKEY_MAX - 1 - i); 1808 } 1809 if (err_mask) { 1810 llc->hd.flags |= SMC_LLC_FLAG_RKEY_NEG; 1811 llc->err_mask = err_mask; 1812 } 1813finish: 1814 llc->hd.flags |= SMC_LLC_FLAG_RESP; 1815 smc_llc_send_message(link, &qentry->msg); 1816 smc_llc_flow_qentry_del(&lgr->llc_flow_rmt); 1817} 1818 1819static void smc_llc_protocol_violation(struct smc_link_group *lgr, u8 type) 1820{ 1821 pr_warn_ratelimited("smc: SMC-R lg %*phN net %llu LLC protocol violation: " 1822 "llc_type %d\n", SMC_LGR_ID_SIZE, &lgr->id, 1823 lgr->net->net_cookie, type); 1824 smc_llc_set_termination_rsn(lgr, SMC_LLC_DEL_PROT_VIOL); 1825 smc_lgr_terminate_sched(lgr); 1826} 1827 1828/* flush the llc event queue */ 1829static void smc_llc_event_flush(struct smc_link_group *lgr) 1830{ 1831 struct smc_llc_qentry *qentry, *q; 1832 1833 spin_lock_bh(&lgr->llc_event_q_lock); 1834 list_for_each_entry_safe(qentry, q, &lgr->llc_event_q, list) { 1835 list_del_init(&qentry->list); 1836 kfree(qentry); 1837 } 1838 spin_unlock_bh(&lgr->llc_event_q_lock); 1839} 1840 1841static void smc_llc_event_handler(struct smc_llc_qentry *qentry) 1842{ 1843 union smc_llc_msg *llc = &qentry->msg; 1844 struct smc_link *link = qentry->link; 1845 struct smc_link_group *lgr = link->lgr; 1846 1847 if (!smc_link_usable(link)) 1848 goto out; 1849 1850 switch (llc->raw.hdr.common.llc_type) { 1851 case SMC_LLC_TEST_LINK: 1852 llc->test_link.hd.flags |= SMC_LLC_FLAG_RESP; 1853 smc_llc_send_message(link, llc); 1854 break; 1855 case SMC_LLC_ADD_LINK: 1856 if (list_empty(&lgr->list)) 1857 goto out; /* lgr is terminating */ 1858 if (lgr->role == SMC_CLNT) { 1859 if (smc_llc_is_local_add_link(llc)) { 1860 if (lgr->llc_flow_lcl.type == 1861 SMC_LLC_FLOW_ADD_LINK) 1862 break; /* add_link in progress */ 1863 if (smc_llc_flow_start(&lgr->llc_flow_lcl, 1864 qentry)) { 1865 schedule_work(&lgr->llc_add_link_work); 1866 } 1867 return; 1868 } 1869 if (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_ADD_LINK && 1870 !lgr->llc_flow_lcl.qentry) { 1871 /* a flow is waiting for this message */ 1872 smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, 1873 qentry); 1874 wake_up(&lgr->llc_msg_waiter); 1875 return; 1876 } 1877 if (lgr->llc_flow_lcl.type == 1878 SMC_LLC_FLOW_REQ_ADD_LINK) { 1879 /* server started add_link processing */ 1880 lgr->llc_flow_lcl.type = SMC_LLC_FLOW_ADD_LINK; 1881 smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, 1882 qentry); 1883 schedule_work(&lgr->llc_add_link_work); 1884 return; 1885 } 1886 if (smc_llc_flow_start(&lgr->llc_flow_lcl, qentry)) { 1887 schedule_work(&lgr->llc_add_link_work); 1888 } 1889 } else if (smc_llc_flow_start(&lgr->llc_flow_lcl, qentry)) { 1890 /* as smc server, handle client suggestion */ 1891 schedule_work(&lgr->llc_add_link_work); 1892 } 1893 return; 1894 case SMC_LLC_CONFIRM_LINK: 1895 case SMC_LLC_ADD_LINK_CONT: 1896 if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) { 1897 /* a flow is waiting for this message */ 1898 smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry); 1899 wake_up(&lgr->llc_msg_waiter); 1900 return; 1901 } 1902 break; 1903 case SMC_LLC_DELETE_LINK: 1904 if (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_ADD_LINK && 1905 !lgr->llc_flow_lcl.qentry) { 1906 /* DEL LINK REQ during ADD LINK SEQ */ 1907 smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry); 1908 wake_up(&lgr->llc_msg_waiter); 1909 } else if (smc_llc_flow_start(&lgr->llc_flow_lcl, qentry)) { 1910 schedule_work(&lgr->llc_del_link_work); 1911 } 1912 return; 1913 case SMC_LLC_CONFIRM_RKEY: 1914 /* new request from remote, assign to remote flow */ 1915 if (smc_llc_flow_start(&lgr->llc_flow_rmt, qentry)) { 1916 /* process here, does not wait for more llc msgs */ 1917 smc_llc_rmt_conf_rkey(lgr); 1918 smc_llc_flow_stop(lgr, &lgr->llc_flow_rmt); 1919 } 1920 return; 1921 case SMC_LLC_CONFIRM_RKEY_CONT: 1922 /* not used because max links is 3, and 3 rkeys fit into 1923 * one CONFIRM_RKEY message 1924 */ 1925 break; 1926 case SMC_LLC_DELETE_RKEY: 1927 /* new request from remote, assign to remote flow */ 1928 if (smc_llc_flow_start(&lgr->llc_flow_rmt, qentry)) { 1929 /* process here, does not wait for more llc msgs */ 1930 smc_llc_rmt_delete_rkey(lgr); 1931 smc_llc_flow_stop(lgr, &lgr->llc_flow_rmt); 1932 } 1933 return; 1934 case SMC_LLC_REQ_ADD_LINK: 1935 /* handle response here, smc_llc_flow_stop() cannot be called 1936 * in tasklet context 1937 */ 1938 if (lgr->role == SMC_CLNT && 1939 lgr->llc_flow_lcl.type == SMC_LLC_FLOW_REQ_ADD_LINK && 1940 (llc->raw.hdr.flags & SMC_LLC_FLAG_RESP)) { 1941 smc_llc_flow_stop(link->lgr, &lgr->llc_flow_lcl); 1942 } else if (lgr->role == SMC_SERV) { 1943 if (smc_llc_flow_start(&lgr->llc_flow_lcl, qentry)) { 1944 /* as smc server, handle client suggestion */ 1945 lgr->llc_flow_lcl.type = SMC_LLC_FLOW_ADD_LINK; 1946 schedule_work(&lgr->llc_add_link_work); 1947 } 1948 return; 1949 } 1950 break; 1951 default: 1952 smc_llc_protocol_violation(lgr, llc->raw.hdr.common.type); 1953 break; 1954 } 1955out: 1956 kfree(qentry); 1957} 1958 1959/* worker to process llc messages on the event queue */ 1960static void smc_llc_event_work(struct work_struct *work) 1961{ 1962 struct smc_link_group *lgr = container_of(work, struct smc_link_group, 1963 llc_event_work); 1964 struct smc_llc_qentry *qentry; 1965 1966 if (!lgr->llc_flow_lcl.type && lgr->delayed_event) { 1967 qentry = lgr->delayed_event; 1968 lgr->delayed_event = NULL; 1969 if (smc_link_usable(qentry->link)) 1970 smc_llc_event_handler(qentry); 1971 else 1972 kfree(qentry); 1973 } 1974 1975again: 1976 spin_lock_bh(&lgr->llc_event_q_lock); 1977 if (!list_empty(&lgr->llc_event_q)) { 1978 qentry = list_first_entry(&lgr->llc_event_q, 1979 struct smc_llc_qentry, list); 1980 list_del_init(&qentry->list); 1981 spin_unlock_bh(&lgr->llc_event_q_lock); 1982 smc_llc_event_handler(qentry); 1983 goto again; 1984 } 1985 spin_unlock_bh(&lgr->llc_event_q_lock); 1986} 1987 1988/* process llc responses in tasklet context */ 1989static void smc_llc_rx_response(struct smc_link *link, 1990 struct smc_llc_qentry *qentry) 1991{ 1992 enum smc_llc_flowtype flowtype = link->lgr->llc_flow_lcl.type; 1993 struct smc_llc_flow *flow = &link->lgr->llc_flow_lcl; 1994 u8 llc_type = qentry->msg.raw.hdr.common.llc_type; 1995 1996 switch (llc_type) { 1997 case SMC_LLC_TEST_LINK: 1998 if (smc_link_active(link)) 1999 complete(&link->llc_testlink_resp); 2000 break; 2001 case SMC_LLC_ADD_LINK: 2002 case SMC_LLC_ADD_LINK_CONT: 2003 case SMC_LLC_CONFIRM_LINK: 2004 if (flowtype != SMC_LLC_FLOW_ADD_LINK || flow->qentry) 2005 break; /* drop out-of-flow response */ 2006 goto assign; 2007 case SMC_LLC_DELETE_LINK: 2008 if (flowtype != SMC_LLC_FLOW_DEL_LINK || flow->qentry) 2009 break; /* drop out-of-flow response */ 2010 goto assign; 2011 case SMC_LLC_CONFIRM_RKEY: 2012 case SMC_LLC_DELETE_RKEY: 2013 if (flowtype != SMC_LLC_FLOW_RKEY || flow->qentry) 2014 break; /* drop out-of-flow response */ 2015 goto assign; 2016 case SMC_LLC_CONFIRM_RKEY_CONT: 2017 /* not used because max links is 3 */ 2018 break; 2019 default: 2020 smc_llc_protocol_violation(link->lgr, 2021 qentry->msg.raw.hdr.common.type); 2022 break; 2023 } 2024 kfree(qentry); 2025 return; 2026assign: 2027 /* assign responses to the local flow, we requested them */ 2028 smc_llc_flow_qentry_set(&link->lgr->llc_flow_lcl, qentry); 2029 wake_up(&link->lgr->llc_msg_waiter); 2030} 2031 2032static void smc_llc_enqueue(struct smc_link *link, union smc_llc_msg *llc) 2033{ 2034 struct smc_link_group *lgr = link->lgr; 2035 struct smc_llc_qentry *qentry; 2036 unsigned long flags; 2037 2038 qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC); 2039 if (!qentry) 2040 return; 2041 qentry->link = link; 2042 INIT_LIST_HEAD(&qentry->list); 2043 memcpy(&qentry->msg, llc, sizeof(union smc_llc_msg)); 2044 2045 /* process responses immediately */ 2046 if ((llc->raw.hdr.flags & SMC_LLC_FLAG_RESP) && 2047 llc->raw.hdr.common.llc_type != SMC_LLC_REQ_ADD_LINK) { 2048 smc_llc_rx_response(link, qentry); 2049 return; 2050 } 2051 2052 /* add requests to event queue */ 2053 spin_lock_irqsave(&lgr->llc_event_q_lock, flags); 2054 list_add_tail(&qentry->list, &lgr->llc_event_q); 2055 spin_unlock_irqrestore(&lgr->llc_event_q_lock, flags); 2056 queue_work(system_highpri_wq, &lgr->llc_event_work); 2057} 2058 2059/* copy received msg and add it to the event queue */ 2060static void smc_llc_rx_handler(struct ib_wc *wc, void *buf) 2061{ 2062 struct smc_link *link = (struct smc_link *)wc->qp->qp_context; 2063 union smc_llc_msg *llc = buf; 2064 2065 if (wc->byte_len < sizeof(*llc)) 2066 return; /* short message */ 2067 if (!llc->raw.hdr.common.llc_version) { 2068 if (llc->raw.hdr.length != sizeof(*llc)) 2069 return; /* invalid message */ 2070 } else { 2071 if (llc->raw.hdr.length_v2 < sizeof(*llc)) 2072 return; /* invalid message */ 2073 } 2074 2075 smc_llc_enqueue(link, llc); 2076} 2077 2078/***************************** worker, utils *********************************/ 2079 2080static void smc_llc_testlink_work(struct work_struct *work) 2081{ 2082 struct smc_link *link = container_of(to_delayed_work(work), 2083 struct smc_link, llc_testlink_wrk); 2084 unsigned long next_interval; 2085 unsigned long expire_time; 2086 u8 user_data[16] = { 0 }; 2087 int rc; 2088 2089 if (!smc_link_active(link)) 2090 return; /* don't reschedule worker */ 2091 expire_time = link->wr_rx_tstamp + link->llc_testlink_time; 2092 if (time_is_after_jiffies(expire_time)) { 2093 next_interval = expire_time - jiffies; 2094 goto out; 2095 } 2096 reinit_completion(&link->llc_testlink_resp); 2097 smc_llc_send_test_link(link, user_data); 2098 /* receive TEST LINK response over RoCE fabric */ 2099 rc = wait_for_completion_interruptible_timeout(&link->llc_testlink_resp, 2100 SMC_LLC_WAIT_TIME); 2101 if (!smc_link_active(link)) 2102 return; /* link state changed */ 2103 if (rc <= 0) { 2104 smcr_link_down_cond_sched(link); 2105 return; 2106 } 2107 next_interval = link->llc_testlink_time; 2108out: 2109 schedule_delayed_work(&link->llc_testlink_wrk, next_interval); 2110} 2111 2112void smc_llc_lgr_init(struct smc_link_group *lgr, struct smc_sock *smc) 2113{ 2114 struct net *net = sock_net(smc->clcsock->sk); 2115 2116 INIT_WORK(&lgr->llc_event_work, smc_llc_event_work); 2117 INIT_WORK(&lgr->llc_add_link_work, smc_llc_add_link_work); 2118 INIT_WORK(&lgr->llc_del_link_work, smc_llc_delete_link_work); 2119 INIT_LIST_HEAD(&lgr->llc_event_q); 2120 spin_lock_init(&lgr->llc_event_q_lock); 2121 spin_lock_init(&lgr->llc_flow_lock); 2122 init_waitqueue_head(&lgr->llc_flow_waiter); 2123 init_waitqueue_head(&lgr->llc_msg_waiter); 2124 mutex_init(&lgr->llc_conf_mutex); 2125 lgr->llc_testlink_time = net->ipv4.sysctl_tcp_keepalive_time; 2126} 2127 2128/* called after lgr was removed from lgr_list */ 2129void smc_llc_lgr_clear(struct smc_link_group *lgr) 2130{ 2131 smc_llc_event_flush(lgr); 2132 wake_up_all(&lgr->llc_flow_waiter); 2133 wake_up_all(&lgr->llc_msg_waiter); 2134 cancel_work_sync(&lgr->llc_event_work); 2135 cancel_work_sync(&lgr->llc_add_link_work); 2136 cancel_work_sync(&lgr->llc_del_link_work); 2137 if (lgr->delayed_event) { 2138 kfree(lgr->delayed_event); 2139 lgr->delayed_event = NULL; 2140 } 2141} 2142 2143int smc_llc_link_init(struct smc_link *link) 2144{ 2145 init_completion(&link->llc_testlink_resp); 2146 INIT_DELAYED_WORK(&link->llc_testlink_wrk, smc_llc_testlink_work); 2147 return 0; 2148} 2149 2150void smc_llc_link_active(struct smc_link *link) 2151{ 2152 pr_warn_ratelimited("smc: SMC-R lg %*phN net %llu link added: id %*phN, " 2153 "peerid %*phN, ibdev %s, ibport %d\n", 2154 SMC_LGR_ID_SIZE, &link->lgr->id, 2155 link->lgr->net->net_cookie, 2156 SMC_LGR_ID_SIZE, &link->link_uid, 2157 SMC_LGR_ID_SIZE, &link->peer_link_uid, 2158 link->smcibdev->ibdev->name, link->ibport); 2159 link->state = SMC_LNK_ACTIVE; 2160 if (link->lgr->llc_testlink_time) { 2161 link->llc_testlink_time = link->lgr->llc_testlink_time; 2162 schedule_delayed_work(&link->llc_testlink_wrk, 2163 link->llc_testlink_time); 2164 } 2165} 2166 2167/* called in worker context */ 2168void smc_llc_link_clear(struct smc_link *link, bool log) 2169{ 2170 if (log) 2171 pr_warn_ratelimited("smc: SMC-R lg %*phN net %llu link removed: id %*phN" 2172 ", peerid %*phN, ibdev %s, ibport %d\n", 2173 SMC_LGR_ID_SIZE, &link->lgr->id, 2174 link->lgr->net->net_cookie, 2175 SMC_LGR_ID_SIZE, &link->link_uid, 2176 SMC_LGR_ID_SIZE, &link->peer_link_uid, 2177 link->smcibdev->ibdev->name, link->ibport); 2178 complete(&link->llc_testlink_resp); 2179 cancel_delayed_work_sync(&link->llc_testlink_wrk); 2180} 2181 2182/* register a new rtoken at the remote peer (for all links) */ 2183int smc_llc_do_confirm_rkey(struct smc_link *send_link, 2184 struct smc_buf_desc *rmb_desc) 2185{ 2186 struct smc_link_group *lgr = send_link->lgr; 2187 struct smc_llc_qentry *qentry = NULL; 2188 int rc = 0; 2189 2190 rc = smc_llc_send_confirm_rkey(send_link, rmb_desc); 2191 if (rc) 2192 goto out; 2193 /* receive CONFIRM RKEY response from server over RoCE fabric */ 2194 qentry = smc_llc_wait(lgr, send_link, SMC_LLC_WAIT_TIME, 2195 SMC_LLC_CONFIRM_RKEY); 2196 if (!qentry || (qentry->msg.raw.hdr.flags & SMC_LLC_FLAG_RKEY_NEG)) 2197 rc = -EFAULT; 2198out: 2199 if (qentry) 2200 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 2201 return rc; 2202} 2203 2204/* unregister an rtoken at the remote peer */ 2205int smc_llc_do_delete_rkey(struct smc_link_group *lgr, 2206 struct smc_buf_desc *rmb_desc) 2207{ 2208 struct smc_llc_qentry *qentry = NULL; 2209 struct smc_link *send_link; 2210 int rc = 0; 2211 2212 send_link = smc_llc_usable_link(lgr); 2213 if (!send_link) 2214 return -ENOLINK; 2215 2216 /* protected by llc_flow control */ 2217 rc = smc_llc_send_delete_rkey(send_link, rmb_desc); 2218 if (rc) 2219 goto out; 2220 /* receive DELETE RKEY response from server over RoCE fabric */ 2221 qentry = smc_llc_wait(lgr, send_link, SMC_LLC_WAIT_TIME, 2222 SMC_LLC_DELETE_RKEY); 2223 if (!qentry || (qentry->msg.raw.hdr.flags & SMC_LLC_FLAG_RKEY_NEG)) 2224 rc = -EFAULT; 2225out: 2226 if (qentry) 2227 smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 2228 return rc; 2229} 2230 2231void smc_llc_link_set_uid(struct smc_link *link) 2232{ 2233 __be32 link_uid; 2234 2235 link_uid = htonl(*((u32 *)link->lgr->id) + link->link_id); 2236 memcpy(link->link_uid, &link_uid, SMC_LGR_ID_SIZE); 2237} 2238 2239/* save peers link user id, used for debug purposes */ 2240void smc_llc_save_peer_uid(struct smc_llc_qentry *qentry) 2241{ 2242 memcpy(qentry->link->peer_link_uid, qentry->msg.confirm_link.link_uid, 2243 SMC_LGR_ID_SIZE); 2244} 2245 2246/* evaluate confirm link request or response */ 2247int smc_llc_eval_conf_link(struct smc_llc_qentry *qentry, 2248 enum smc_llc_reqresp type) 2249{ 2250 if (type == SMC_LLC_REQ) { /* SMC server assigns link_id */ 2251 qentry->link->link_id = qentry->msg.confirm_link.link_num; 2252 smc_llc_link_set_uid(qentry->link); 2253 } 2254 if (!(qentry->msg.raw.hdr.flags & SMC_LLC_FLAG_NO_RMBE_EYEC)) 2255 return -ENOTSUPP; 2256 return 0; 2257} 2258 2259/***************************** init, exit, misc ******************************/ 2260 2261static struct smc_wr_rx_handler smc_llc_rx_handlers[] = { 2262 { 2263 .handler = smc_llc_rx_handler, 2264 .type = SMC_LLC_CONFIRM_LINK 2265 }, 2266 { 2267 .handler = smc_llc_rx_handler, 2268 .type = SMC_LLC_TEST_LINK 2269 }, 2270 { 2271 .handler = smc_llc_rx_handler, 2272 .type = SMC_LLC_ADD_LINK 2273 }, 2274 { 2275 .handler = smc_llc_rx_handler, 2276 .type = SMC_LLC_ADD_LINK_CONT 2277 }, 2278 { 2279 .handler = smc_llc_rx_handler, 2280 .type = SMC_LLC_DELETE_LINK 2281 }, 2282 { 2283 .handler = smc_llc_rx_handler, 2284 .type = SMC_LLC_CONFIRM_RKEY 2285 }, 2286 { 2287 .handler = smc_llc_rx_handler, 2288 .type = SMC_LLC_CONFIRM_RKEY_CONT 2289 }, 2290 { 2291 .handler = smc_llc_rx_handler, 2292 .type = SMC_LLC_DELETE_RKEY 2293 }, 2294 /* V2 types */ 2295 { 2296 .handler = smc_llc_rx_handler, 2297 .type = SMC_LLC_CONFIRM_LINK_V2 2298 }, 2299 { 2300 .handler = smc_llc_rx_handler, 2301 .type = SMC_LLC_TEST_LINK_V2 2302 }, 2303 { 2304 .handler = smc_llc_rx_handler, 2305 .type = SMC_LLC_ADD_LINK_V2 2306 }, 2307 { 2308 .handler = smc_llc_rx_handler, 2309 .type = SMC_LLC_DELETE_LINK_V2 2310 }, 2311 { 2312 .handler = smc_llc_rx_handler, 2313 .type = SMC_LLC_REQ_ADD_LINK_V2 2314 }, 2315 { 2316 .handler = smc_llc_rx_handler, 2317 .type = SMC_LLC_CONFIRM_RKEY_V2 2318 }, 2319 { 2320 .handler = smc_llc_rx_handler, 2321 .type = SMC_LLC_DELETE_RKEY_V2 2322 }, 2323 { 2324 .handler = NULL, 2325 } 2326}; 2327 2328int __init smc_llc_init(void) 2329{ 2330 struct smc_wr_rx_handler *handler; 2331 int rc = 0; 2332 2333 for (handler = smc_llc_rx_handlers; handler->handler; handler++) { 2334 INIT_HLIST_NODE(&handler->list); 2335 rc = smc_wr_rx_register_handler(handler); 2336 if (rc) 2337 break; 2338 } 2339 return rc; 2340}