Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-smc-add-and-delete-link-processing'

Karsten Graul says:

====================
net/smc: add and delete link processing

These patches add the 'add link' and 'delete link' processing as
SMC server and client. This processing allows to establish and
remove links of a link group dynamically.

v2: Fix mess up with unused static functions. Merge patch 8 into patch 4.
Postpone patch 13 to next series.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+800 -43
+2 -2
net/smc/af_smc.c
··· 427 427 return rc; 428 428 } 429 429 smc_llc_flow_qentry_clr(&link->lgr->llc_flow_lcl); 430 - /* tbd: call smc_llc_cli_add_link(link, qentry); */ 430 + smc_llc_cli_add_link(link, qentry); 431 431 return 0; 432 432 } 433 433 ··· 1067 1067 smc_llc_link_active(link); 1068 1068 1069 1069 /* initial contact - try to establish second link */ 1070 - /* tbd: call smc_llc_srv_add_link(link); */ 1070 + smc_llc_srv_add_link(link); 1071 1071 return 0; 1072 1072 } 1073 1073
+12 -17
net/smc/smc_core.c
··· 193 193 void smc_lgr_cleanup_early(struct smc_connection *conn) 194 194 { 195 195 struct smc_link_group *lgr = conn->lgr; 196 + struct list_head *lgr_list; 197 + spinlock_t *lgr_lock; 196 198 197 199 if (!lgr) 198 200 return; 199 201 200 202 smc_conn_free(conn); 201 - smc_lgr_forget(lgr); 203 + lgr_list = smc_lgr_list_head(lgr, &lgr_lock); 204 + spin_lock_bh(lgr_lock); 205 + /* do not use this link group for new connections */ 206 + if (!list_empty(lgr_list)) 207 + list_del_init(lgr_list); 208 + spin_unlock_bh(lgr_lock); 202 209 smc_lgr_schedule_free_work_fast(lgr); 203 210 } 204 211 ··· 280 273 return link_id; 281 274 } 282 275 283 - static int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk, 284 - u8 link_idx, struct smc_init_info *ini) 276 + int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk, 277 + u8 link_idx, struct smc_init_info *ini) 285 278 { 286 279 u8 rndvec[3]; 287 280 int rc; ··· 660 653 kfree(lgr); 661 654 } 662 655 663 - void smc_lgr_forget(struct smc_link_group *lgr) 664 - { 665 - struct list_head *lgr_list; 666 - spinlock_t *lgr_lock; 667 - 668 - lgr_list = smc_lgr_list_head(lgr, &lgr_lock); 669 - spin_lock_bh(lgr_lock); 670 - /* do not use this link group for new connections */ 671 - if (!list_empty(lgr_list)) 672 - list_del_init(lgr_list); 673 - spin_unlock_bh(lgr_lock); 674 - } 675 - 676 656 static void smcd_unregister_all_dmbs(struct smc_link_group *lgr) 677 657 { 678 658 int i; ··· 883 889 link = smc_llc_usable_link(lgr); 884 890 if (!link) 885 891 return; 886 - /* tbd: call smc_llc_srv_add_link_local(link); */ 892 + smc_llc_srv_add_link_local(link); 887 893 } else { 888 894 /* invite server to start add link processing */ 889 895 u8 gid[SMC_GID_SIZE]; ··· 954 960 955 961 if (lgr->role == SMC_SERV) { 956 962 /* trigger local delete link processing */ 963 + smc_llc_srv_delete_link_local(to_lnk, del_link_id); 957 964 } else { 958 965 if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) { 959 966 /* another llc task is ongoing */
+3 -1
net/smc/smc_core.h
··· 254 254 struct mutex llc_conf_mutex; 255 255 /* protects lgr reconfig. */ 256 256 struct work_struct llc_add_link_work; 257 + struct work_struct llc_del_link_work; 257 258 struct work_struct llc_event_work; 258 259 /* llc event worker */ 259 260 wait_queue_head_t llc_waiter; ··· 344 343 struct smc_clc_msg_accept_confirm; 345 344 struct smc_clc_msg_local; 346 345 347 - void smc_lgr_forget(struct smc_link_group *lgr); 348 346 void smc_lgr_cleanup_early(struct smc_connection *conn); 349 347 void smc_lgr_terminate_sched(struct smc_link_group *lgr); 350 348 void smcr_port_add(struct smc_ib_device *smcibdev, u8 ibport); ··· 374 374 int smc_core_init(void); 375 375 void smc_core_exit(void); 376 376 377 + int smcr_link_init(struct smc_link_group *lgr, struct smc_link *lnk, 378 + u8 link_idx, struct smc_init_info *ini); 377 379 void smcr_link_clear(struct smc_link *lnk); 378 380 int smcr_buf_map_lgr(struct smc_link *lnk); 379 381 int smcr_buf_reg_lgr(struct smc_link *lnk);
+776 -22
net/smc/smc_llc.c
··· 17 17 #include "smc_core.h" 18 18 #include "smc_clc.h" 19 19 #include "smc_llc.h" 20 + #include "smc_pnet.h" 20 21 21 22 #define SMC_LLC_DATA_LEN 40 22 23 ··· 70 69 u8 reserved[8]; 71 70 }; 72 71 72 + struct smc_llc_msg_add_link_cont_rt { 73 + __be32 rmb_key; 74 + __be32 rmb_key_new; 75 + __be64 rmb_vaddr_new; 76 + }; 77 + 78 + #define SMC_LLC_RKEYS_PER_CONT_MSG 2 79 + 80 + struct smc_llc_msg_add_link_cont { /* type 0x03 */ 81 + struct smc_llc_hdr hd; 82 + u8 link_num; 83 + u8 num_rkeys; 84 + u8 reserved2[2]; 85 + struct smc_llc_msg_add_link_cont_rt rt[SMC_LLC_RKEYS_PER_CONT_MSG]; 86 + u8 reserved[4]; 87 + } __packed; /* format defined in RFC7609 */ 88 + 73 89 #define SMC_LLC_FLAG_DEL_LINK_ALL 0x40 74 90 #define SMC_LLC_FLAG_DEL_LINK_ORDERLY 0x20 75 91 ··· 138 120 union smc_llc_msg { 139 121 struct smc_llc_msg_confirm_link confirm_link; 140 122 struct smc_llc_msg_add_link add_link; 123 + struct smc_llc_msg_add_link_cont add_link_cont; 141 124 struct smc_llc_msg_del_link delete_link; 142 125 143 126 struct smc_llc_msg_confirm_rkey confirm_rkey; ··· 158 139 struct smc_link *link; 159 140 union smc_llc_msg msg; 160 141 }; 142 + 143 + static void smc_llc_enqueue(struct smc_link *link, union smc_llc_msg *llc); 161 144 162 145 struct smc_llc_qentry *smc_llc_flow_qentry_clr(struct smc_llc_flow *flow) 163 146 { ··· 383 362 hton24(confllc->sender_qp_num, link->roce_qp->qp_num); 384 363 confllc->link_num = link->link_id; 385 364 memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE); 386 - confllc->max_links = SMC_LLC_ADD_LNK_MAX_LINKS; /* enforce peer resp. */ 365 + confllc->max_links = SMC_LLC_ADD_LNK_MAX_LINKS; 387 366 /* send llc message */ 388 367 rc = smc_wr_tx_send(link, pend); 389 368 return rc; ··· 562 541 563 542 /********************************* receive ***********************************/ 564 543 544 + static int smc_llc_alloc_alt_link(struct smc_link_group *lgr, 545 + enum smc_lgr_type lgr_new_t) 546 + { 547 + int i; 548 + 549 + if (lgr->type == SMC_LGR_SYMMETRIC || 550 + (lgr->type != SMC_LGR_SINGLE && 551 + (lgr_new_t == SMC_LGR_ASYMMETRIC_LOCAL || 552 + lgr_new_t == SMC_LGR_ASYMMETRIC_PEER))) 553 + return -EMLINK; 554 + 555 + if (lgr_new_t == SMC_LGR_ASYMMETRIC_LOCAL || 556 + lgr_new_t == SMC_LGR_ASYMMETRIC_PEER) { 557 + for (i = SMC_LINKS_PER_LGR_MAX - 1; i >= 0; i--) 558 + if (lgr->lnk[i].state == SMC_LNK_UNUSED) 559 + return i; 560 + } else { 561 + for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) 562 + if (lgr->lnk[i].state == SMC_LNK_UNUSED) 563 + return i; 564 + } 565 + return -EMLINK; 566 + } 567 + 568 + /* return first buffer from any of the next buf lists */ 569 + static struct smc_buf_desc *_smc_llc_get_next_rmb(struct smc_link_group *lgr, 570 + int *buf_lst) 571 + { 572 + struct smc_buf_desc *buf_pos; 573 + 574 + while (*buf_lst < SMC_RMBE_SIZES) { 575 + buf_pos = list_first_entry_or_null(&lgr->rmbs[*buf_lst], 576 + struct smc_buf_desc, list); 577 + if (buf_pos) 578 + return buf_pos; 579 + (*buf_lst)++; 580 + } 581 + return NULL; 582 + } 583 + 584 + /* return next rmb from buffer lists */ 585 + static struct smc_buf_desc *smc_llc_get_next_rmb(struct smc_link_group *lgr, 586 + int *buf_lst, 587 + struct smc_buf_desc *buf_pos) 588 + { 589 + struct smc_buf_desc *buf_next; 590 + 591 + if (!buf_pos || list_is_last(&buf_pos->list, &lgr->rmbs[*buf_lst])) { 592 + (*buf_lst)++; 593 + return _smc_llc_get_next_rmb(lgr, buf_lst); 594 + } 595 + buf_next = list_next_entry(buf_pos, list); 596 + return buf_next; 597 + } 598 + 599 + static struct smc_buf_desc *smc_llc_get_first_rmb(struct smc_link_group *lgr, 600 + int *buf_lst) 601 + { 602 + *buf_lst = 0; 603 + return smc_llc_get_next_rmb(lgr, buf_lst, NULL); 604 + } 605 + 606 + /* send one add_link_continue msg */ 607 + static int smc_llc_add_link_cont(struct smc_link *link, 608 + struct smc_link *link_new, u8 *num_rkeys_todo, 609 + int *buf_lst, struct smc_buf_desc **buf_pos) 610 + { 611 + struct smc_llc_msg_add_link_cont *addc_llc; 612 + struct smc_link_group *lgr = link->lgr; 613 + int prim_lnk_idx, lnk_idx, i, rc; 614 + struct smc_wr_tx_pend_priv *pend; 615 + struct smc_wr_buf *wr_buf; 616 + struct smc_buf_desc *rmb; 617 + u8 n; 618 + 619 + rc = smc_llc_add_pending_send(link, &wr_buf, &pend); 620 + if (rc) 621 + return rc; 622 + addc_llc = (struct smc_llc_msg_add_link_cont *)wr_buf; 623 + memset(addc_llc, 0, sizeof(*addc_llc)); 624 + 625 + prim_lnk_idx = link->link_idx; 626 + lnk_idx = link_new->link_idx; 627 + addc_llc->link_num = link_new->link_id; 628 + addc_llc->num_rkeys = *num_rkeys_todo; 629 + n = *num_rkeys_todo; 630 + for (i = 0; i < min_t(u8, n, SMC_LLC_RKEYS_PER_CONT_MSG); i++) { 631 + if (!*buf_pos) { 632 + addc_llc->num_rkeys = addc_llc->num_rkeys - 633 + *num_rkeys_todo; 634 + *num_rkeys_todo = 0; 635 + break; 636 + } 637 + rmb = *buf_pos; 638 + 639 + addc_llc->rt[i].rmb_key = htonl(rmb->mr_rx[prim_lnk_idx]->rkey); 640 + addc_llc->rt[i].rmb_key_new = htonl(rmb->mr_rx[lnk_idx]->rkey); 641 + addc_llc->rt[i].rmb_vaddr_new = 642 + cpu_to_be64((u64)sg_dma_address(rmb->sgt[lnk_idx].sgl)); 643 + 644 + (*num_rkeys_todo)--; 645 + *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos); 646 + while (*buf_pos && !(*buf_pos)->used) 647 + *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos); 648 + } 649 + addc_llc->hd.common.type = SMC_LLC_ADD_LINK_CONT; 650 + addc_llc->hd.length = sizeof(struct smc_llc_msg_add_link_cont); 651 + if (lgr->role == SMC_CLNT) 652 + addc_llc->hd.flags |= SMC_LLC_FLAG_RESP; 653 + return smc_wr_tx_send(link, pend); 654 + } 655 + 656 + static int smc_llc_cli_rkey_exchange(struct smc_link *link, 657 + struct smc_link *link_new) 658 + { 659 + struct smc_llc_msg_add_link_cont *addc_llc; 660 + struct smc_link_group *lgr = link->lgr; 661 + u8 max, num_rkeys_send, num_rkeys_recv; 662 + struct smc_llc_qentry *qentry; 663 + struct smc_buf_desc *buf_pos; 664 + int buf_lst; 665 + int rc = 0; 666 + int i; 667 + 668 + mutex_lock(&lgr->rmbs_lock); 669 + num_rkeys_send = lgr->conns_num; 670 + buf_pos = smc_llc_get_first_rmb(lgr, &buf_lst); 671 + do { 672 + qentry = smc_llc_wait(lgr, NULL, SMC_LLC_WAIT_TIME, 673 + SMC_LLC_ADD_LINK_CONT); 674 + if (!qentry) { 675 + rc = -ETIMEDOUT; 676 + break; 677 + } 678 + addc_llc = &qentry->msg.add_link_cont; 679 + num_rkeys_recv = addc_llc->num_rkeys; 680 + max = min_t(u8, num_rkeys_recv, SMC_LLC_RKEYS_PER_CONT_MSG); 681 + for (i = 0; i < max; i++) { 682 + smc_rtoken_set(lgr, link->link_idx, link_new->link_idx, 683 + addc_llc->rt[i].rmb_key, 684 + addc_llc->rt[i].rmb_vaddr_new, 685 + addc_llc->rt[i].rmb_key_new); 686 + num_rkeys_recv--; 687 + } 688 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 689 + rc = smc_llc_add_link_cont(link, link_new, &num_rkeys_send, 690 + &buf_lst, &buf_pos); 691 + if (rc) 692 + break; 693 + } while (num_rkeys_send || num_rkeys_recv); 694 + 695 + mutex_unlock(&lgr->rmbs_lock); 696 + return rc; 697 + } 698 + 699 + /* prepare and send an add link reject response */ 700 + static int smc_llc_cli_add_link_reject(struct smc_llc_qentry *qentry) 701 + { 702 + qentry->msg.raw.hdr.flags |= SMC_LLC_FLAG_RESP; 703 + qentry->msg.raw.hdr.flags |= SMC_LLC_FLAG_ADD_LNK_REJ; 704 + qentry->msg.raw.hdr.add_link_rej_rsn = SMC_LLC_REJ_RSN_NO_ALT_PATH; 705 + return smc_llc_send_message(qentry->link, &qentry->msg); 706 + } 707 + 708 + static int smc_llc_cli_conf_link(struct smc_link *link, 709 + struct smc_init_info *ini, 710 + struct smc_link *link_new, 711 + enum smc_lgr_type lgr_new_t) 712 + { 713 + struct smc_link_group *lgr = link->lgr; 714 + struct smc_llc_msg_del_link *del_llc; 715 + struct smc_llc_qentry *qentry = NULL; 716 + int rc = 0; 717 + 718 + /* receive CONFIRM LINK request over RoCE fabric */ 719 + qentry = smc_llc_wait(lgr, NULL, SMC_LLC_WAIT_FIRST_TIME, 0); 720 + if (!qentry) { 721 + rc = smc_llc_send_delete_link(link, link_new->link_id, 722 + SMC_LLC_REQ, false, 723 + SMC_LLC_DEL_LOST_PATH); 724 + return -ENOLINK; 725 + } 726 + if (qentry->msg.raw.hdr.common.type != SMC_LLC_CONFIRM_LINK) { 727 + /* received DELETE_LINK instead */ 728 + del_llc = &qentry->msg.delete_link; 729 + qentry->msg.raw.hdr.flags |= SMC_LLC_FLAG_RESP; 730 + smc_llc_send_message(link, &qentry->msg); 731 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 732 + return -ENOLINK; 733 + } 734 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 735 + 736 + rc = smc_ib_modify_qp_rts(link_new); 737 + if (rc) { 738 + smc_llc_send_delete_link(link, link_new->link_id, SMC_LLC_REQ, 739 + false, SMC_LLC_DEL_LOST_PATH); 740 + return -ENOLINK; 741 + } 742 + smc_wr_remember_qp_attr(link_new); 743 + 744 + rc = smcr_buf_reg_lgr(link_new); 745 + if (rc) { 746 + smc_llc_send_delete_link(link, link_new->link_id, SMC_LLC_REQ, 747 + false, SMC_LLC_DEL_LOST_PATH); 748 + return -ENOLINK; 749 + } 750 + 751 + /* send CONFIRM LINK response over RoCE fabric */ 752 + rc = smc_llc_send_confirm_link(link_new, SMC_LLC_RESP); 753 + if (rc) { 754 + smc_llc_send_delete_link(link, link_new->link_id, SMC_LLC_REQ, 755 + false, SMC_LLC_DEL_LOST_PATH); 756 + return -ENOLINK; 757 + } 758 + smc_llc_link_active(link_new); 759 + lgr->type = lgr_new_t; 760 + return 0; 761 + } 762 + 763 + static void smc_llc_save_add_link_info(struct smc_link *link, 764 + struct smc_llc_msg_add_link *add_llc) 765 + { 766 + link->peer_qpn = ntoh24(add_llc->sender_qp_num); 767 + memcpy(link->peer_gid, add_llc->sender_gid, SMC_GID_SIZE); 768 + memcpy(link->peer_mac, add_llc->sender_mac, ETH_ALEN); 769 + link->peer_psn = ntoh24(add_llc->initial_psn); 770 + link->peer_mtu = add_llc->qp_mtu; 771 + } 772 + 773 + /* as an SMC client, process an add link request */ 774 + int smc_llc_cli_add_link(struct smc_link *link, struct smc_llc_qentry *qentry) 775 + { 776 + struct smc_llc_msg_add_link *llc = &qentry->msg.add_link; 777 + enum smc_lgr_type lgr_new_t = SMC_LGR_SYMMETRIC; 778 + struct smc_link_group *lgr = smc_get_lgr(link); 779 + struct smc_link *lnk_new = NULL; 780 + struct smc_init_info ini; 781 + int lnk_idx, rc = 0; 782 + 783 + ini.vlan_id = lgr->vlan_id; 784 + smc_pnet_find_alt_roce(lgr, &ini, link->smcibdev); 785 + if (!memcmp(llc->sender_gid, link->peer_gid, SMC_GID_SIZE) && 786 + !memcmp(llc->sender_mac, link->peer_mac, ETH_ALEN)) { 787 + if (!ini.ib_dev) 788 + goto out_reject; 789 + lgr_new_t = SMC_LGR_ASYMMETRIC_PEER; 790 + } 791 + if (!ini.ib_dev) { 792 + lgr_new_t = SMC_LGR_ASYMMETRIC_LOCAL; 793 + ini.ib_dev = link->smcibdev; 794 + ini.ib_port = link->ibport; 795 + } 796 + lnk_idx = smc_llc_alloc_alt_link(lgr, lgr_new_t); 797 + if (lnk_idx < 0) 798 + goto out_reject; 799 + lnk_new = &lgr->lnk[lnk_idx]; 800 + rc = smcr_link_init(lgr, lnk_new, lnk_idx, &ini); 801 + if (rc) 802 + goto out_reject; 803 + smc_llc_save_add_link_info(lnk_new, llc); 804 + lnk_new->link_id = llc->link_num; 805 + 806 + rc = smc_ib_ready_link(lnk_new); 807 + if (rc) 808 + goto out_clear_lnk; 809 + 810 + rc = smcr_buf_map_lgr(lnk_new); 811 + if (rc) 812 + goto out_clear_lnk; 813 + 814 + rc = smc_llc_send_add_link(link, 815 + lnk_new->smcibdev->mac[ini.ib_port - 1], 816 + lnk_new->gid, lnk_new, SMC_LLC_RESP); 817 + if (rc) 818 + goto out_clear_lnk; 819 + rc = smc_llc_cli_rkey_exchange(link, lnk_new); 820 + if (rc) { 821 + rc = 0; 822 + goto out_clear_lnk; 823 + } 824 + rc = smc_llc_cli_conf_link(link, &ini, lnk_new, lgr_new_t); 825 + if (!rc) 826 + goto out; 827 + out_clear_lnk: 828 + smcr_link_clear(lnk_new); 829 + out_reject: 830 + smc_llc_cli_add_link_reject(qentry); 831 + out: 832 + kfree(qentry); 833 + return rc; 834 + } 835 + 836 + static void smc_llc_process_cli_add_link(struct smc_link_group *lgr) 837 + { 838 + struct smc_llc_qentry *qentry; 839 + 840 + qentry = smc_llc_flow_qentry_clr(&lgr->llc_flow_lcl); 841 + 842 + mutex_lock(&lgr->llc_conf_mutex); 843 + smc_llc_cli_add_link(qentry->link, qentry); 844 + mutex_unlock(&lgr->llc_conf_mutex); 845 + } 846 + 847 + static int smc_llc_active_link_count(struct smc_link_group *lgr) 848 + { 849 + int i, link_count = 0; 850 + 851 + for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 852 + if (!smc_link_usable(&lgr->lnk[i])) 853 + continue; 854 + link_count++; 855 + } 856 + return link_count; 857 + } 858 + 859 + /* find the asymmetric link when 3 links are established */ 860 + static struct smc_link *smc_llc_find_asym_link(struct smc_link_group *lgr) 861 + { 862 + int asym_idx = -ENOENT; 863 + int i, j, k; 864 + bool found; 865 + 866 + /* determine asymmetric link */ 867 + found = false; 868 + for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 869 + for (j = i + 1; j < SMC_LINKS_PER_LGR_MAX; j++) { 870 + if (!smc_link_usable(&lgr->lnk[i]) || 871 + !smc_link_usable(&lgr->lnk[j])) 872 + continue; 873 + if (!memcmp(lgr->lnk[i].gid, lgr->lnk[j].gid, 874 + SMC_GID_SIZE)) { 875 + found = true; /* asym_lnk is i or j */ 876 + break; 877 + } 878 + } 879 + if (found) 880 + break; 881 + } 882 + if (!found) 883 + goto out; /* no asymmetric link */ 884 + for (k = 0; k < SMC_LINKS_PER_LGR_MAX; k++) { 885 + if (!smc_link_usable(&lgr->lnk[k])) 886 + continue; 887 + if (k != i && 888 + !memcmp(lgr->lnk[i].peer_gid, lgr->lnk[k].peer_gid, 889 + SMC_GID_SIZE)) { 890 + asym_idx = i; 891 + break; 892 + } 893 + if (k != j && 894 + !memcmp(lgr->lnk[j].peer_gid, lgr->lnk[k].peer_gid, 895 + SMC_GID_SIZE)) { 896 + asym_idx = j; 897 + break; 898 + } 899 + } 900 + out: 901 + return (asym_idx < 0) ? NULL : &lgr->lnk[asym_idx]; 902 + } 903 + 904 + static void smc_llc_delete_asym_link(struct smc_link_group *lgr) 905 + { 906 + struct smc_link *lnk_new = NULL, *lnk_asym; 907 + struct smc_llc_qentry *qentry; 908 + int rc; 909 + 910 + lnk_asym = smc_llc_find_asym_link(lgr); 911 + if (!lnk_asym) 912 + return; /* no asymmetric link */ 913 + if (!smc_link_downing(&lnk_asym->state)) 914 + return; 915 + /* tbd: lnk_new = smc_switch_conns(lgr, lnk_asym, false); */ 916 + smc_wr_tx_wait_no_pending_sends(lnk_asym); 917 + if (!lnk_new) 918 + goto out_free; 919 + /* change flow type from ADD_LINK into DEL_LINK */ 920 + lgr->llc_flow_lcl.type = SMC_LLC_FLOW_DEL_LINK; 921 + rc = smc_llc_send_delete_link(lnk_new, lnk_asym->link_id, SMC_LLC_REQ, 922 + true, SMC_LLC_DEL_NO_ASYM_NEEDED); 923 + if (rc) { 924 + smcr_link_down_cond(lnk_new); 925 + goto out_free; 926 + } 927 + qentry = smc_llc_wait(lgr, lnk_new, SMC_LLC_WAIT_TIME, 928 + SMC_LLC_DELETE_LINK); 929 + if (!qentry) { 930 + smcr_link_down_cond(lnk_new); 931 + goto out_free; 932 + } 933 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 934 + out_free: 935 + smcr_link_clear(lnk_asym); 936 + } 937 + 938 + static int smc_llc_srv_rkey_exchange(struct smc_link *link, 939 + struct smc_link *link_new) 940 + { 941 + struct smc_llc_msg_add_link_cont *addc_llc; 942 + struct smc_link_group *lgr = link->lgr; 943 + u8 max, num_rkeys_send, num_rkeys_recv; 944 + struct smc_llc_qentry *qentry = NULL; 945 + struct smc_buf_desc *buf_pos; 946 + int buf_lst; 947 + int rc = 0; 948 + int i; 949 + 950 + mutex_lock(&lgr->rmbs_lock); 951 + num_rkeys_send = lgr->conns_num; 952 + buf_pos = smc_llc_get_first_rmb(lgr, &buf_lst); 953 + do { 954 + smc_llc_add_link_cont(link, link_new, &num_rkeys_send, 955 + &buf_lst, &buf_pos); 956 + qentry = smc_llc_wait(lgr, link, SMC_LLC_WAIT_TIME, 957 + SMC_LLC_ADD_LINK_CONT); 958 + if (!qentry) { 959 + rc = -ETIMEDOUT; 960 + goto out; 961 + } 962 + addc_llc = &qentry->msg.add_link_cont; 963 + num_rkeys_recv = addc_llc->num_rkeys; 964 + max = min_t(u8, num_rkeys_recv, SMC_LLC_RKEYS_PER_CONT_MSG); 965 + for (i = 0; i < max; i++) { 966 + smc_rtoken_set(lgr, link->link_idx, link_new->link_idx, 967 + addc_llc->rt[i].rmb_key, 968 + addc_llc->rt[i].rmb_vaddr_new, 969 + addc_llc->rt[i].rmb_key_new); 970 + num_rkeys_recv--; 971 + } 972 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 973 + } while (num_rkeys_send || num_rkeys_recv); 974 + out: 975 + mutex_unlock(&lgr->rmbs_lock); 976 + return rc; 977 + } 978 + 979 + static int smc_llc_srv_conf_link(struct smc_link *link, 980 + struct smc_link *link_new, 981 + enum smc_lgr_type lgr_new_t) 982 + { 983 + struct smc_link_group *lgr = link->lgr; 984 + struct smc_llc_qentry *qentry = NULL; 985 + int rc; 986 + 987 + /* send CONFIRM LINK request over the RoCE fabric */ 988 + rc = smc_llc_send_confirm_link(link_new, SMC_LLC_REQ); 989 + if (rc) 990 + return -ENOLINK; 991 + /* receive CONFIRM LINK response over the RoCE fabric */ 992 + qentry = smc_llc_wait(lgr, link, SMC_LLC_WAIT_FIRST_TIME, 993 + SMC_LLC_CONFIRM_LINK); 994 + if (!qentry) { 995 + /* send DELETE LINK */ 996 + smc_llc_send_delete_link(link, link_new->link_id, SMC_LLC_REQ, 997 + false, SMC_LLC_DEL_LOST_PATH); 998 + return -ENOLINK; 999 + } 1000 + smc_llc_link_active(link_new); 1001 + lgr->type = lgr_new_t; 1002 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1003 + return 0; 1004 + } 1005 + 1006 + int smc_llc_srv_add_link(struct smc_link *link) 1007 + { 1008 + enum smc_lgr_type lgr_new_t = SMC_LGR_SYMMETRIC; 1009 + struct smc_link_group *lgr = link->lgr; 1010 + struct smc_llc_msg_add_link *add_llc; 1011 + struct smc_llc_qentry *qentry = NULL; 1012 + struct smc_link *link_new; 1013 + struct smc_init_info ini; 1014 + int lnk_idx, rc = 0; 1015 + 1016 + /* ignore client add link recommendation, start new flow */ 1017 + ini.vlan_id = lgr->vlan_id; 1018 + smc_pnet_find_alt_roce(lgr, &ini, link->smcibdev); 1019 + if (!ini.ib_dev) { 1020 + lgr_new_t = SMC_LGR_ASYMMETRIC_LOCAL; 1021 + ini.ib_dev = link->smcibdev; 1022 + ini.ib_port = link->ibport; 1023 + } 1024 + lnk_idx = smc_llc_alloc_alt_link(lgr, lgr_new_t); 1025 + if (lnk_idx < 0) 1026 + return 0; 1027 + 1028 + rc = smcr_link_init(lgr, &lgr->lnk[lnk_idx], lnk_idx, &ini); 1029 + if (rc) 1030 + return rc; 1031 + link_new = &lgr->lnk[lnk_idx]; 1032 + rc = smc_llc_send_add_link(link, 1033 + link_new->smcibdev->mac[ini.ib_port - 1], 1034 + link_new->gid, link_new, SMC_LLC_REQ); 1035 + if (rc) 1036 + goto out_err; 1037 + /* receive ADD LINK response over the RoCE fabric */ 1038 + qentry = smc_llc_wait(lgr, link, SMC_LLC_WAIT_TIME, SMC_LLC_ADD_LINK); 1039 + if (!qentry) { 1040 + rc = -ETIMEDOUT; 1041 + goto out_err; 1042 + } 1043 + add_llc = &qentry->msg.add_link; 1044 + if (add_llc->hd.flags & SMC_LLC_FLAG_ADD_LNK_REJ) { 1045 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1046 + rc = -ENOLINK; 1047 + goto out_err; 1048 + } 1049 + if (lgr->type == SMC_LGR_SINGLE && 1050 + (!memcmp(add_llc->sender_gid, link->peer_gid, SMC_GID_SIZE) && 1051 + !memcmp(add_llc->sender_mac, link->peer_mac, ETH_ALEN))) { 1052 + lgr_new_t = SMC_LGR_ASYMMETRIC_PEER; 1053 + } 1054 + smc_llc_save_add_link_info(link_new, add_llc); 1055 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1056 + 1057 + rc = smc_ib_ready_link(link_new); 1058 + if (rc) 1059 + goto out_err; 1060 + rc = smcr_buf_map_lgr(link_new); 1061 + if (rc) 1062 + goto out_err; 1063 + rc = smcr_buf_reg_lgr(link_new); 1064 + if (rc) 1065 + goto out_err; 1066 + rc = smc_llc_srv_rkey_exchange(link, link_new); 1067 + if (rc) 1068 + goto out_err; 1069 + rc = smc_llc_srv_conf_link(link, link_new, lgr_new_t); 1070 + if (rc) 1071 + goto out_err; 1072 + return 0; 1073 + out_err: 1074 + smcr_link_clear(link_new); 1075 + return rc; 1076 + } 1077 + 1078 + static void smc_llc_process_srv_add_link(struct smc_link_group *lgr) 1079 + { 1080 + struct smc_link *link = lgr->llc_flow_lcl.qentry->link; 1081 + int rc; 1082 + 1083 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 1084 + 1085 + mutex_lock(&lgr->llc_conf_mutex); 1086 + rc = smc_llc_srv_add_link(link); 1087 + if (!rc && lgr->type == SMC_LGR_SYMMETRIC) { 1088 + /* delete any asymmetric link */ 1089 + smc_llc_delete_asym_link(lgr); 1090 + } 1091 + mutex_unlock(&lgr->llc_conf_mutex); 1092 + } 1093 + 1094 + /* enqueue a local add_link req to trigger a new add_link flow, only as SERV */ 1095 + void smc_llc_srv_add_link_local(struct smc_link *link) 1096 + { 1097 + struct smc_llc_msg_add_link add_llc = {0}; 1098 + 1099 + add_llc.hd.length = sizeof(add_llc); 1100 + add_llc.hd.common.type = SMC_LLC_ADD_LINK; 1101 + /* no dev and port needed, we as server ignore client data anyway */ 1102 + smc_llc_enqueue(link, (union smc_llc_msg *)&add_llc); 1103 + } 1104 + 565 1105 /* worker to process an add link message */ 566 1106 static void smc_llc_add_link_work(struct work_struct *work) 567 1107 { ··· 1135 553 goto out; 1136 554 } 1137 555 1138 - /* tbd: call smc_llc_process_cli_add_link(lgr); */ 1139 - /* tbd: call smc_llc_process_srv_add_link(lgr); */ 556 + if (lgr->role == SMC_CLNT) 557 + smc_llc_process_cli_add_link(lgr); 558 + else 559 + smc_llc_process_srv_add_link(lgr); 1140 560 out: 1141 561 smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); 1142 562 } 1143 563 1144 - static void smc_llc_rx_delete_link(struct smc_link *link, 1145 - struct smc_llc_msg_del_link *llc) 564 + /* enqueue a local del_link msg to trigger a new del_link flow, 565 + * called only for role SMC_SERV 566 + */ 567 + void smc_llc_srv_delete_link_local(struct smc_link *link, u8 del_link_id) 1146 568 { 1147 - struct smc_link_group *lgr = smc_get_lgr(link); 569 + struct smc_llc_msg_del_link del_llc = {0}; 1148 570 1149 - smc_lgr_forget(lgr); 1150 - if (lgr->role == SMC_SERV) { 1151 - /* client asks to delete this link, send request */ 1152 - smc_llc_send_delete_link(link, 0, SMC_LLC_REQ, true, 1153 - SMC_LLC_DEL_PROG_INIT_TERM); 1154 - } else { 1155 - /* server requests to delete this link, send response */ 1156 - smc_llc_send_delete_link(link, 0, SMC_LLC_RESP, true, 1157 - SMC_LLC_DEL_PROG_INIT_TERM); 571 + del_llc.hd.length = sizeof(del_llc); 572 + del_llc.hd.common.type = SMC_LLC_DELETE_LINK; 573 + del_llc.link_num = del_link_id; 574 + del_llc.reason = htonl(SMC_LLC_DEL_LOST_PATH); 575 + del_llc.hd.flags |= SMC_LLC_FLAG_DEL_LINK_ORDERLY; 576 + smc_llc_enqueue(link, (union smc_llc_msg *)&del_llc); 577 + } 578 + 579 + static void smc_llc_process_cli_delete_link(struct smc_link_group *lgr) 580 + { 581 + struct smc_link *lnk_del = NULL, *lnk_asym, *lnk; 582 + struct smc_llc_msg_del_link *del_llc; 583 + struct smc_llc_qentry *qentry; 584 + int active_links; 585 + int lnk_idx; 586 + 587 + qentry = smc_llc_flow_qentry_clr(&lgr->llc_flow_lcl); 588 + lnk = qentry->link; 589 + del_llc = &qentry->msg.delete_link; 590 + 591 + if (del_llc->hd.flags & SMC_LLC_FLAG_DEL_LINK_ALL) { 592 + smc_lgr_terminate_sched(lgr); 593 + goto out; 1158 594 } 1159 - smcr_link_down_cond(link); 595 + mutex_lock(&lgr->llc_conf_mutex); 596 + /* delete single link */ 597 + for (lnk_idx = 0; lnk_idx < SMC_LINKS_PER_LGR_MAX; lnk_idx++) { 598 + if (lgr->lnk[lnk_idx].link_id != del_llc->link_num) 599 + continue; 600 + lnk_del = &lgr->lnk[lnk_idx]; 601 + break; 602 + } 603 + del_llc->hd.flags |= SMC_LLC_FLAG_RESP; 604 + if (!lnk_del) { 605 + /* link was not found */ 606 + del_llc->reason = htonl(SMC_LLC_DEL_NOLNK); 607 + smc_llc_send_message(lnk, &qentry->msg); 608 + goto out_unlock; 609 + } 610 + lnk_asym = smc_llc_find_asym_link(lgr); 611 + 612 + del_llc->reason = 0; 613 + smc_llc_send_message(lnk, &qentry->msg); /* response */ 614 + 615 + if (smc_link_downing(&lnk_del->state)) { 616 + /* tbd: call smc_switch_conns(lgr, lnk_del, false); */ 617 + smc_wr_tx_wait_no_pending_sends(lnk_del); 618 + } 619 + smcr_link_clear(lnk_del); 620 + 621 + active_links = smc_llc_active_link_count(lgr); 622 + if (lnk_del == lnk_asym) { 623 + /* expected deletion of asym link, don't change lgr state */ 624 + } else if (active_links == 1) { 625 + lgr->type = SMC_LGR_SINGLE; 626 + } else if (!active_links) { 627 + lgr->type = SMC_LGR_NONE; 628 + smc_lgr_terminate_sched(lgr); 629 + } 630 + out_unlock: 631 + mutex_unlock(&lgr->llc_conf_mutex); 632 + out: 633 + kfree(qentry); 634 + } 635 + 636 + static void smc_llc_process_srv_delete_link(struct smc_link_group *lgr) 637 + { 638 + struct smc_llc_msg_del_link *del_llc; 639 + struct smc_link *lnk, *lnk_del; 640 + struct smc_llc_qentry *qentry; 641 + int active_links; 642 + int i; 643 + 644 + mutex_lock(&lgr->llc_conf_mutex); 645 + qentry = smc_llc_flow_qentry_clr(&lgr->llc_flow_lcl); 646 + lnk = qentry->link; 647 + del_llc = &qentry->msg.delete_link; 648 + 649 + if (qentry->msg.delete_link.hd.flags & SMC_LLC_FLAG_DEL_LINK_ALL) { 650 + /* delete entire lgr */ 651 + smc_lgr_terminate_sched(lgr); 652 + goto out; 653 + } 654 + /* delete single link */ 655 + lnk_del = NULL; 656 + for (i = 0; i < SMC_LINKS_PER_LGR_MAX; i++) { 657 + if (lgr->lnk[i].link_id == del_llc->link_num) { 658 + lnk_del = &lgr->lnk[i]; 659 + break; 660 + } 661 + } 662 + if (!lnk_del) 663 + goto out; /* asymmetric link already deleted */ 664 + 665 + if (smc_link_downing(&lnk_del->state)) { 666 + /* tbd: call smc_switch_conns(lgr, lnk_del, false); */ 667 + smc_wr_tx_wait_no_pending_sends(lnk_del); 668 + } 669 + if (!list_empty(&lgr->list)) { 670 + /* qentry is either a request from peer (send it back to 671 + * initiate the DELETE_LINK processing), or a locally 672 + * enqueued DELETE_LINK request (forward it) 673 + */ 674 + if (!smc_llc_send_message(lnk, &qentry->msg)) { 675 + struct smc_llc_msg_del_link *del_llc_resp; 676 + struct smc_llc_qentry *qentry2; 677 + 678 + qentry2 = smc_llc_wait(lgr, lnk, SMC_LLC_WAIT_TIME, 679 + SMC_LLC_DELETE_LINK); 680 + if (!qentry2) { 681 + } else { 682 + del_llc_resp = &qentry2->msg.delete_link; 683 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 684 + } 685 + } 686 + } 687 + smcr_link_clear(lnk_del); 688 + 689 + active_links = smc_llc_active_link_count(lgr); 690 + if (active_links == 1) { 691 + lgr->type = SMC_LGR_SINGLE; 692 + } else if (!active_links) { 693 + lgr->type = SMC_LGR_NONE; 694 + smc_lgr_terminate_sched(lgr); 695 + } 696 + 697 + if (lgr->type == SMC_LGR_SINGLE && !list_empty(&lgr->list)) { 698 + /* trigger setup of asymm alt link */ 699 + smc_llc_srv_add_link_local(lnk); 700 + } 701 + out: 702 + mutex_unlock(&lgr->llc_conf_mutex); 703 + kfree(qentry); 704 + } 705 + 706 + static void smc_llc_delete_link_work(struct work_struct *work) 707 + { 708 + struct smc_link_group *lgr = container_of(work, struct smc_link_group, 709 + llc_del_link_work); 710 + 711 + if (list_empty(&lgr->list)) { 712 + /* link group is terminating */ 713 + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); 714 + goto out; 715 + } 716 + 717 + if (lgr->role == SMC_CLNT) 718 + smc_llc_process_cli_delete_link(lgr); 719 + else 720 + smc_llc_process_srv_delete_link(lgr); 721 + out: 722 + smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); 1160 723 } 1161 724 1162 725 /* process a confirm_rkey request from peer, remote flow */ ··· 1414 687 } 1415 688 return; 1416 689 case SMC_LLC_CONFIRM_LINK: 690 + case SMC_LLC_ADD_LINK_CONT: 1417 691 if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) { 1418 692 /* a flow is waiting for this message */ 1419 693 smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, qentry); ··· 1423 695 } 1424 696 break; 1425 697 case SMC_LLC_DELETE_LINK: 1426 - smc_llc_rx_delete_link(link, &llc->delete_link); 1427 - break; 698 + if (lgr->role == SMC_CLNT) { 699 + /* server requests to delete this link, send response */ 700 + if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) { 701 + /* DEL LINK REQ during ADD LINK SEQ */ 702 + smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, 703 + qentry); 704 + wake_up_interruptible(&lgr->llc_waiter); 705 + } else if (smc_llc_flow_start(&lgr->llc_flow_lcl, 706 + qentry)) { 707 + schedule_work(&lgr->llc_del_link_work); 708 + } 709 + } else { 710 + if (lgr->llc_flow_lcl.type == SMC_LLC_FLOW_ADD_LINK && 711 + !lgr->llc_flow_lcl.qentry) { 712 + /* DEL LINK REQ during ADD LINK SEQ */ 713 + smc_llc_flow_qentry_set(&lgr->llc_flow_lcl, 714 + qentry); 715 + wake_up_interruptible(&lgr->llc_waiter); 716 + } else if (smc_llc_flow_start(&lgr->llc_flow_lcl, 717 + qentry)) { 718 + schedule_work(&lgr->llc_del_link_work); 719 + } 720 + } 721 + return; 1428 722 case SMC_LLC_CONFIRM_RKEY: 1429 723 /* new request from remote, assign to remote flow */ 1430 724 if (smc_llc_flow_start(&lgr->llc_flow_rmt, qentry)) { ··· 1515 765 complete(&link->llc_testlink_resp); 1516 766 break; 1517 767 case SMC_LLC_ADD_LINK: 768 + case SMC_LLC_DELETE_LINK: 1518 769 case SMC_LLC_CONFIRM_LINK: 770 + case SMC_LLC_ADD_LINK_CONT: 1519 771 case SMC_LLC_CONFIRM_RKEY: 1520 772 case SMC_LLC_DELETE_RKEY: 1521 773 /* assign responses to the local flow, we requested them */ 1522 774 smc_llc_flow_qentry_set(&link->lgr->llc_flow_lcl, qentry); 1523 775 wake_up_interruptible(&link->lgr->llc_waiter); 1524 776 return; 1525 - case SMC_LLC_DELETE_LINK: 1526 - if (link->lgr->role == SMC_SERV) 1527 - smc_lgr_schedule_free_work_fast(link->lgr); 1528 - break; 1529 777 case SMC_LLC_CONFIRM_RKEY_CONT: 1530 778 /* not used because max links is 3 */ 1531 779 break; ··· 1611 863 1612 864 INIT_WORK(&lgr->llc_event_work, smc_llc_event_work); 1613 865 INIT_WORK(&lgr->llc_add_link_work, smc_llc_add_link_work); 866 + INIT_WORK(&lgr->llc_del_link_work, smc_llc_delete_link_work); 1614 867 INIT_LIST_HEAD(&lgr->llc_event_q); 1615 868 spin_lock_init(&lgr->llc_event_q_lock); 1616 869 spin_lock_init(&lgr->llc_flow_lock); ··· 1627 878 wake_up_interruptible_all(&lgr->llc_waiter); 1628 879 cancel_work_sync(&lgr->llc_event_work); 1629 880 cancel_work_sync(&lgr->llc_add_link_work); 881 + cancel_work_sync(&lgr->llc_del_link_work); 1630 882 if (lgr->delayed_event) { 1631 883 kfree(lgr->delayed_event); 1632 884 lgr->delayed_event = NULL; ··· 1734 984 { 1735 985 .handler = smc_llc_rx_handler, 1736 986 .type = SMC_LLC_ADD_LINK 987 + }, 988 + { 989 + .handler = smc_llc_rx_handler, 990 + .type = SMC_LLC_ADD_LINK_CONT 1737 991 }, 1738 992 { 1739 993 .handler = smc_llc_rx_handler,
+5
net/smc/smc_llc.h
··· 28 28 enum smc_llc_msg_type { 29 29 SMC_LLC_CONFIRM_LINK = 0x01, 30 30 SMC_LLC_ADD_LINK = 0x02, 31 + SMC_LLC_ADD_LINK_CONT = 0x03, 31 32 SMC_LLC_DELETE_LINK = 0x04, 32 33 SMC_LLC_CONFIRM_RKEY = 0x06, 33 34 SMC_LLC_TEST_LINK = 0x07, ··· 69 68 int smc_llc_send_delete_link(struct smc_link *link, u8 link_del_id, 70 69 enum smc_llc_reqresp reqresp, bool orderly, 71 70 u32 reason); 71 + void smc_llc_srv_delete_link_local(struct smc_link *link, u8 del_link_id); 72 72 void smc_llc_lgr_init(struct smc_link_group *lgr, struct smc_sock *smc); 73 73 void smc_llc_lgr_clear(struct smc_link_group *lgr); 74 74 int smc_llc_link_init(struct smc_link *link); ··· 89 87 int time_out, u8 exp_msg); 90 88 struct smc_llc_qentry *smc_llc_flow_qentry_clr(struct smc_llc_flow *flow); 91 89 void smc_llc_flow_qentry_del(struct smc_llc_flow *flow); 90 + int smc_llc_cli_add_link(struct smc_link *link, struct smc_llc_qentry *qentry); 91 + int smc_llc_srv_add_link(struct smc_link *link); 92 + void smc_llc_srv_add_link_local(struct smc_link *link); 92 93 int smc_llc_init(void) __init; 93 94 94 95 #endif /* SMC_LLC_H */
+1 -1
net/smc/smc_wr.c
··· 61 61 } 62 62 63 63 /* wait till all pending tx work requests on the given link are completed */ 64 - static inline int smc_wr_tx_wait_no_pending_sends(struct smc_link *link) 64 + int smc_wr_tx_wait_no_pending_sends(struct smc_link *link) 65 65 { 66 66 if (wait_event_timeout(link->wr_tx_wait, !smc_wr_is_tx_pend(link), 67 67 SMC_WR_TX_WAIT_PENDING_TIME))
+1
net/smc/smc_wr.h
··· 106 106 smc_wr_tx_filter filter, 107 107 smc_wr_tx_dismisser dismisser, 108 108 unsigned long data); 109 + int smc_wr_tx_wait_no_pending_sends(struct smc_link *link); 109 110 110 111 int smc_wr_rx_register_handler(struct smc_wr_rx_handler *handler); 111 112 int smc_wr_rx_post_init(struct smc_link *link);