diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 1afb6e4275f228..c67272007f4112 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c @@ -1067,7 +1067,7 @@ static int smcr_serv_conf_first_link(struct smc_sock *smc) smc_llc_link_active(link); /* initial contact - try to establish second link */ - /* tbd: call smc_llc_srv_add_link(link); */ + smc_llc_srv_add_link(link); return 0; } diff --git a/net/smc/smc_llc.c b/net/smc/smc_llc.c index d56ca60597d42d..e2f254e217594d 100644 --- a/net/smc/smc_llc.c +++ b/net/smc/smc_llc.c @@ -863,6 +863,94 @@ static void smc_llc_process_cli_add_link(struct smc_link_group *lgr) mutex_unlock(&lgr->llc_conf_mutex); } +int smc_llc_srv_add_link(struct smc_link *link) +{ + enum smc_lgr_type lgr_new_t = SMC_LGR_SYMMETRIC; + struct smc_link_group *lgr = link->lgr; + struct smc_llc_msg_add_link *add_llc; + struct smc_llc_qentry *qentry = NULL; + struct smc_link *link_new; + struct smc_init_info ini; + int lnk_idx, rc = 0; + + /* ignore client add link recommendation, start new flow */ + ini.vlan_id = lgr->vlan_id; + smc_pnet_find_alt_roce(lgr, &ini, link->smcibdev); + if (!ini.ib_dev) { + lgr_new_t = SMC_LGR_ASYMMETRIC_LOCAL; + ini.ib_dev = link->smcibdev; + ini.ib_port = link->ibport; + } + lnk_idx = smc_llc_alloc_alt_link(lgr, lgr_new_t); + if (lnk_idx < 0) + return 0; + + rc = smcr_link_init(lgr, &lgr->lnk[lnk_idx], lnk_idx, &ini); + if (rc) + return rc; + link_new = &lgr->lnk[lnk_idx]; + rc = smc_llc_send_add_link(link, + link_new->smcibdev->mac[ini.ib_port - 1], + link_new->gid, link_new, SMC_LLC_REQ); + if (rc) + goto out_err; + /* receive ADD LINK response over the RoCE fabric */ + qentry = smc_llc_wait(lgr, link, SMC_LLC_WAIT_TIME, SMC_LLC_ADD_LINK); + if (!qentry) { + rc = -ETIMEDOUT; + goto out_err; + } + add_llc = &qentry->msg.add_link; + if (add_llc->hd.flags & SMC_LLC_FLAG_ADD_LNK_REJ) { + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); + rc = -ENOLINK; + goto out_err; + } + if (lgr->type == SMC_LGR_SINGLE && + (!memcmp(add_llc->sender_gid, link->peer_gid, SMC_GID_SIZE) && + !memcmp(add_llc->sender_mac, link->peer_mac, ETH_ALEN))) { + lgr_new_t = SMC_LGR_ASYMMETRIC_PEER; + } + smc_llc_save_add_link_info(link_new, add_llc); + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); + + rc = smc_ib_ready_link(link_new); + if (rc) + goto out_err; + rc = smcr_buf_map_lgr(link_new); + if (rc) + goto out_err; + rc = smcr_buf_reg_lgr(link_new); + if (rc) + goto out_err; + /* tbd: rc = smc_llc_srv_rkey_exchange(link, link_new); */ + if (rc) + goto out_err; + /* tbd: rc = smc_llc_srv_conf_link(link, link_new, lgr_new_t); */ + if (rc) + goto out_err; + return 0; +out_err: + smcr_link_clear(link_new); + return rc; +} + +static void smc_llc_process_srv_add_link(struct smc_link_group *lgr) +{ + struct smc_link *link = lgr->llc_flow_lcl.qentry->link; + int rc; + + smc_llc_flow_qentry_del(&lgr->llc_flow_lcl); + + mutex_lock(&lgr->llc_conf_mutex); + rc = smc_llc_srv_add_link(link); + if (!rc && lgr->type == SMC_LGR_SYMMETRIC) { + /* delete any asymmetric link */ + /* tbd: smc_llc_delete_asym_link(lgr); */ + } + mutex_unlock(&lgr->llc_conf_mutex); +} + /* worker to process an add link message */ static void smc_llc_add_link_work(struct work_struct *work) { @@ -877,7 +965,8 @@ static void smc_llc_add_link_work(struct work_struct *work) if (lgr->role == SMC_CLNT) smc_llc_process_cli_add_link(lgr); - /* tbd: call smc_llc_process_srv_add_link(lgr); */ + else + smc_llc_process_srv_add_link(lgr); out: smc_llc_flow_stop(lgr, &lgr->llc_flow_lcl); } diff --git a/net/smc/smc_llc.h b/net/smc/smc_llc.h index 7c314bbef8c801..1a7748d0541f58 100644 --- a/net/smc/smc_llc.h +++ b/net/smc/smc_llc.h @@ -89,6 +89,7 @@ struct smc_llc_qentry *smc_llc_wait(struct smc_link_group *lgr, struct smc_llc_qentry *smc_llc_flow_qentry_clr(struct smc_llc_flow *flow); void smc_llc_flow_qentry_del(struct smc_llc_flow *flow); int smc_llc_cli_add_link(struct smc_link *link, struct smc_llc_qentry *qentry); +int smc_llc_srv_add_link(struct smc_link *link); int smc_llc_init(void) __init; #endif /* SMC_LLC_H */