linux/net/smc/smc_llc.c
<<
>>
Prefs
   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 *  For now, we only support the necessary "confirm link" functionality
   8 *  which happens for the first RoCE link after successful CLC handshake.
   9 *
  10 *  Copyright IBM Corp. 2016
  11 *
  12 *  Author(s):  Klaus Wacker <Klaus.Wacker@de.ibm.com>
  13 *              Ursula Braun <ubraun@linux.vnet.ibm.com>
  14 */
  15
  16#include <net/tcp.h>
  17#include <rdma/ib_verbs.h>
  18
  19#include "smc.h"
  20#include "smc_core.h"
  21#include "smc_clc.h"
  22#include "smc_llc.h"
  23
  24/********************************** send *************************************/
  25
  26struct smc_llc_tx_pend {
  27};
  28
  29/* handler for send/transmission completion of an LLC msg */
  30static void smc_llc_tx_handler(struct smc_wr_tx_pend_priv *pend,
  31                               struct smc_link *link,
  32                               enum ib_wc_status wc_status)
  33{
  34        /* future work: handle wc_status error for recovery and failover */
  35}
  36
  37/**
  38 * smc_llc_add_pending_send() - add LLC control message to pending WQE transmits
  39 * @link: Pointer to SMC link used for sending LLC control message.
  40 * @wr_buf: Out variable returning pointer to work request payload buffer.
  41 * @pend: Out variable returning pointer to private pending WR tracking.
  42 *        It's the context the transmit complete handler will get.
  43 *
  44 * Reserves and pre-fills an entry for a pending work request send/tx.
  45 * Used by mid-level smc_llc_send_msg() to prepare for later actual send/tx.
  46 * Can sleep due to smc_get_ctrl_buf (if not in softirq context).
  47 *
  48 * Return: 0 on success, otherwise an error value.
  49 */
  50static int smc_llc_add_pending_send(struct smc_link *link,
  51                                    struct smc_wr_buf **wr_buf,
  52                                    struct smc_wr_tx_pend_priv **pend)
  53{
  54        int rc;
  55
  56        rc = smc_wr_tx_get_free_slot(link, smc_llc_tx_handler, wr_buf, pend);
  57        if (rc < 0)
  58                return rc;
  59        BUILD_BUG_ON_MSG(
  60                sizeof(union smc_llc_msg) > SMC_WR_BUF_SIZE,
  61                "must increase SMC_WR_BUF_SIZE to at least sizeof(struct smc_llc_msg)");
  62        BUILD_BUG_ON_MSG(
  63                sizeof(union smc_llc_msg) != SMC_WR_TX_SIZE,
  64                "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()");
  65        BUILD_BUG_ON_MSG(
  66                sizeof(struct smc_llc_tx_pend) > SMC_WR_TX_PEND_PRIV_SIZE,
  67                "must increase SMC_WR_TX_PEND_PRIV_SIZE to at least sizeof(struct smc_llc_tx_pend)");
  68        return 0;
  69}
  70
  71/* high-level API to send LLC confirm link */
  72int smc_llc_send_confirm_link(struct smc_link *link, u8 mac[],
  73                              union ib_gid *gid,
  74                              enum smc_llc_reqresp reqresp)
  75{
  76        struct smc_link_group *lgr = container_of(link, struct smc_link_group,
  77                                                  lnk[SMC_SINGLE_LINK]);
  78        struct smc_llc_msg_confirm_link *confllc;
  79        struct smc_wr_tx_pend_priv *pend;
  80        struct smc_wr_buf *wr_buf;
  81        int rc;
  82
  83        rc = smc_llc_add_pending_send(link, &wr_buf, &pend);
  84        if (rc)
  85                return rc;
  86        confllc = (struct smc_llc_msg_confirm_link *)wr_buf;
  87        memset(confllc, 0, sizeof(*confllc));
  88        confllc->hd.common.type = SMC_LLC_CONFIRM_LINK;
  89        confllc->hd.length = sizeof(struct smc_llc_msg_confirm_link);
  90        if (reqresp == SMC_LLC_RESP)
  91                confllc->hd.flags |= SMC_LLC_FLAG_RESP;
  92        memcpy(confllc->sender_mac, mac, ETH_ALEN);
  93        memcpy(confllc->sender_gid, gid, SMC_GID_SIZE);
  94        hton24(confllc->sender_qp_num, link->roce_qp->qp_num);
  95        /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */
  96        memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE);
  97        confllc->max_links = SMC_LINKS_PER_LGR_MAX;
  98        /* send llc message */
  99        rc = smc_wr_tx_send(link, pend);
 100        return rc;
 101}
 102
 103/********************************* receive ***********************************/
 104
 105static void smc_llc_rx_confirm_link(struct smc_link *link,
 106                                    struct smc_llc_msg_confirm_link *llc)
 107{
 108        struct smc_link_group *lgr;
 109
 110        lgr = container_of(link, struct smc_link_group, lnk[SMC_SINGLE_LINK]);
 111        if (llc->hd.flags & SMC_LLC_FLAG_RESP) {
 112                if (lgr->role == SMC_SERV)
 113                        complete(&link->llc_confirm_resp);
 114        } else {
 115                if (lgr->role == SMC_CLNT) {
 116                        link->link_id = llc->link_num;
 117                        complete(&link->llc_confirm);
 118                }
 119        }
 120}
 121
 122static void smc_llc_rx_handler(struct ib_wc *wc, void *buf)
 123{
 124        struct smc_link *link = (struct smc_link *)wc->qp->qp_context;
 125        union smc_llc_msg *llc = buf;
 126
 127        if (wc->byte_len < sizeof(*llc))
 128                return; /* short message */
 129        if (llc->raw.hdr.length != sizeof(*llc))
 130                return; /* invalid message */
 131        if (llc->raw.hdr.common.type == SMC_LLC_CONFIRM_LINK)
 132                smc_llc_rx_confirm_link(link, &llc->confirm_link);
 133}
 134
 135/***************************** init, exit, misc ******************************/
 136
 137static struct smc_wr_rx_handler smc_llc_rx_handlers[] = {
 138        {
 139                .handler        = smc_llc_rx_handler,
 140                .type           = SMC_LLC_CONFIRM_LINK
 141        },
 142        {
 143                .handler        = NULL,
 144        }
 145};
 146
 147int __init smc_llc_init(void)
 148{
 149        struct smc_wr_rx_handler *handler;
 150        int rc = 0;
 151
 152        for (handler = smc_llc_rx_handlers; handler->handler; handler++) {
 153                INIT_HLIST_NODE(&handler->list);
 154                rc = smc_wr_rx_register_handler(handler);
 155                if (rc)
 156                        break;
 157        }
 158        return rc;
 159}
 160