diff options
Diffstat (limited to 'drivers/infiniband/ulp')
30 files changed, 298 insertions, 3549 deletions
diff --git a/drivers/infiniband/ulp/Makefile b/drivers/infiniband/ulp/Makefile index 4d0004b58377..51b0d41699b8 100644 --- a/drivers/infiniband/ulp/Makefile +++ b/drivers/infiniband/ulp/Makefile @@ -4,5 +4,4 @@ obj-$(CONFIG_INFINIBAND_SRP) += srp/ obj-$(CONFIG_INFINIBAND_SRPT) += srpt/ obj-$(CONFIG_INFINIBAND_ISER) += iser/ obj-$(CONFIG_INFINIBAND_ISERT) += isert/ -obj-$(CONFIG_INFINIBAND_OPA_VNIC) += opa_vnic/ obj-$(CONFIG_INFINIBAND_RTRS) += rtrs/ diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig index 254e31a90a66..b5253a231bdd 100644 --- a/drivers/infiniband/ulp/ipoib/Kconfig +++ b/drivers/infiniband/ulp/ipoib/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config INFINIBAND_IPOIB tristate "IP-over-InfiniBand" - depends on NETDEVICES && INET && (IPV6 || IPV6=n) + depends on NETDEVICES && INET help Support for the IP-over-InfiniBand protocol (IPoIB). This transports IP packets over InfiniBand so you can use your IB diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 91f866e3fb8b..143e03b64902 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -87,6 +87,7 @@ enum { IPOIB_FLAG_INITIALIZED = 1, IPOIB_FLAG_ADMIN_UP = 2, IPOIB_PKEY_ASSIGNED = 3, + IPOIB_FLAG_MCAST_FLUSH = 4, IPOIB_FLAG_SUBINTERFACE = 5, IPOIB_STOP_REAPER = 7, IPOIB_FLAG_ADMIN_CM = 9, @@ -414,6 +415,12 @@ struct ipoib_dev_priv { const struct net_device_ops *rn_ops; }; +static inline bool ipoib_mcast_allowed(struct ipoib_dev_priv *priv) +{ + return test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) && + !test_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags); +} + struct ipoib_ah { struct net_device *dev; struct ib_ah *ah; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 57fec88a1629..ed0592898384 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1071,8 +1071,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_ struct ib_qp *tx_qp; if (dev->features & NETIF_F_SG) - attr.cap.max_send_sge = min_t(u32, priv->ca->attrs.max_send_sge, - MAX_SKB_FRAGS + 1); + attr.cap.max_send_sge = min(priv->ca->attrs.max_send_sge, MAX_SKB_FRAGS + 1); tx_qp = ib_create_qp(priv->pd, &attr); tx->max_send_sge = attr.cap.max_send_sge; @@ -1582,7 +1581,8 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) int ipoib_cm_dev_init(struct net_device *dev) { struct ipoib_dev_priv *priv = ipoib_priv(dev); - int max_srq_sge, i; + u32 max_srq_sge; + int i; u8 addr; INIT_LIST_HEAD(&priv->cm.passive_ids); @@ -1600,9 +1600,9 @@ int ipoib_cm_dev_init(struct net_device *dev) skb_queue_head_init(&priv->cm.skb_queue); - ipoib_dbg(priv, "max_srq_sge=%d\n", priv->ca->attrs.max_srq_sge); + ipoib_dbg(priv, "max_srq_sge=%u\n", priv->ca->attrs.max_srq_sge); - max_srq_sge = min_t(int, IPOIB_CM_RX_SG, priv->ca->attrs.max_srq_sge); + max_srq_sge = min(priv->ca->attrs.max_srq_sge, IPOIB_CM_RX_SG); ipoib_cm_create_srq(dev, max_srq_sge); if (ipoib_cm_has_srq(dev)) { priv->cm.max_cm_mtu = max_srq_sge * PAGE_SIZE - 0x10; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 5061d52a7b12..81bbb3f7c113 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -1227,17 +1227,19 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, } if (level == IPOIB_FLUSH_LIGHT) { - int oper_up; ipoib_mark_paths_invalid(dev); - /* Set IPoIB operation as down to prevent races between: + /* Set MCAST_FLUSH to prevent races between: * the flush flow which leaves MCG and on the fly joins * which can happen during that time. mcast restart task * should deal with join requests we missed. + * + * Do not clear OPER_UP for this; restoring it races with + * ipoib_ib_dev_down() and can leave OPER_UP set after the + * device is down. */ - oper_up = test_and_clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags); + set_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags); ipoib_mcast_dev_flush(dev); - if (oper_up) - set_bit(IPOIB_FLAG_OPER_UP, &priv->flags); + clear_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags); ipoib_reap_dead_ahs(priv); } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 402671567736..6c14246befb1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1297,16 +1297,19 @@ static int ipoib_hard_header(struct sk_buff *skb, return IPOIB_HARD_LEN; } -static void ipoib_set_mcast_list(struct net_device *dev) +static int ipoib_set_rx_mode_async(struct net_device *dev, + struct netdev_hw_addr_list *uc, + struct netdev_hw_addr_list *mc) { struct ipoib_dev_priv *priv = ipoib_priv(dev); if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { ipoib_dbg(priv, "IPOIB_FLAG_OPER_UP not set"); - return; + return 0; } queue_work(priv->wq, &priv->restart_task); + return 0; } static int ipoib_get_iflink(const struct net_device *dev) @@ -2160,7 +2163,7 @@ static const struct net_device_ops ipoib_netdev_ops_pf = { .ndo_fix_features = ipoib_fix_features, .ndo_start_xmit = ipoib_start_xmit, .ndo_tx_timeout = ipoib_timeout, - .ndo_set_rx_mode = ipoib_set_mcast_list, + .ndo_set_rx_mode_async = ipoib_set_rx_mode_async, .ndo_get_iflink = ipoib_get_iflink, .ndo_set_vf_link_state = ipoib_set_vf_link_state, .ndo_get_vf_config = ipoib_get_vf_config, @@ -2183,7 +2186,7 @@ static const struct net_device_ops ipoib_netdev_ops_vf = { .ndo_fix_features = ipoib_fix_features, .ndo_start_xmit = ipoib_start_xmit, .ndo_tx_timeout = ipoib_timeout, - .ndo_set_rx_mode = ipoib_set_mcast_list, + .ndo_set_rx_mode_async = ipoib_set_rx_mode_async, .ndo_get_iflink = ipoib_get_iflink, .ndo_get_stats64 = ipoib_get_stats, .ndo_eth_ioctl = ipoib_ioctl, @@ -2780,6 +2783,7 @@ err_client: err_sa: ib_sa_unregister_client(&ipoib_sa_client); destroy_workqueue(ipoib_workqueue); + rcu_barrier(); err_fs: ipoib_unregister_debugfs(); @@ -2797,6 +2801,7 @@ static void __exit ipoib_cleanup_module(void) ib_sa_unregister_client(&ipoib_sa_client); ipoib_unregister_debugfs(); destroy_workqueue(ipoib_workqueue); + rcu_barrier(); } module_init(ipoib_init_module); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 6401af2fd548..379b78374e21 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -74,7 +74,7 @@ static void __ipoib_mcast_schedule_join_thread(struct ipoib_dev_priv *priv, struct ipoib_mcast *mcast, bool delay) { - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) return; /* @@ -469,7 +469,7 @@ static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast) int ret = 0; if (!priv->broadcast || - !test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + !ipoib_mcast_allowed(priv)) return -EINVAL; init_completion(&mcast->done); @@ -555,7 +555,7 @@ void ipoib_mcast_join_task(struct work_struct *work) unsigned long delay_until = 0; struct ipoib_mcast *mcast = NULL; - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) return; if (ib_query_port(priv->ca, priv->port, &port_attr)) { @@ -577,7 +577,7 @@ void ipoib_mcast_join_task(struct work_struct *work) netif_addr_unlock_bh(dev); spin_lock_irq(&priv->lock); - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) goto out; if (!priv->broadcast) { @@ -749,7 +749,7 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) spin_lock_irqsave(&priv->lock, flags); - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) || + if (!ipoib_mcast_allowed(priv) || !priv->broadcast || !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { ++dev->stats.tx_dropped; @@ -871,7 +871,7 @@ void ipoib_mcast_restart_task(struct work_struct *work) LIST_HEAD(remove_list); struct ib_sa_mcmember_rec rec; - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) /* * shortcut...on shutdown flush is called next, just * let it do all the work @@ -965,9 +965,9 @@ void ipoib_mcast_restart_task(struct work_struct *work) ipoib_mcast_remove_list(&remove_list); /* - * Double check that we are still up + * Double check that we are still up and not flushing */ - if (test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { + if (ipoib_mcast_allowed(priv)) { spin_lock_irq(&priv->lock); __ipoib_mcast_schedule_join_thread(priv, NULL, 0); spin_unlock_irq(&priv->lock); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 3ed1ea566690..2490696a1aab 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -147,8 +147,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) .cap = { .max_send_wr = ipoib_sendq_size, .max_recv_wr = ipoib_recvq_size, - .max_send_sge = min_t(u32, priv->ca->attrs.max_send_sge, - MAX_SKB_FRAGS + 1), + .max_send_sge = min(priv->ca->attrs.max_send_sge, MAX_SKB_FRAGS + 1), .max_recv_sge = IPOIB_UD_RX_SG }, .sq_sig_type = IB_SIGNAL_ALL_WR, diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 12a2d12fef07..7ea6888b479c 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -598,11 +598,8 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, iser_dbg("conn %p: remote invalidation for rkey %#x\n", iser_conn, rkey); - if (unlikely(!iser_conn->snd_w_inv)) { - iser_err("conn %p: unexpected remote invalidation, terminating connection\n", - iser_conn); - return -EPROTO; - } + if (unlikely(!iser_conn->snd_w_inv)) + goto bad_inv; task = iscsi_itt_to_ctask(iser_conn->iscsi_conn, hdr->itt); if (likely(task)) { @@ -611,12 +608,16 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, if (iser_task->dir[ISER_DIR_IN]) { desc = iser_task->rdma_reg[ISER_DIR_IN].desc; + if (unlikely(!desc)) + goto bad_inv; if (unlikely(iser_inv_desc(desc, rkey))) return -EINVAL; } if (iser_task->dir[ISER_DIR_OUT]) { desc = iser_task->rdma_reg[ISER_DIR_OUT].desc; + if (unlikely(!desc)) + goto bad_inv; if (unlikely(iser_inv_desc(desc, rkey))) return -EINVAL; } @@ -627,6 +628,11 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, } return 0; + +bad_inv: + iser_err("conn %p: unexpected remote invalidation, terminating connection\n", + iser_conn); + return -EPROTO; } diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index f03b3bb3c0c4..55fe68e5b837 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -244,8 +244,7 @@ static int iser_create_ib_conn_res(struct ib_conn *ib_conn) max_send_wr = ISER_QP_SIG_MAX_REQ_DTOS + 1; else max_send_wr = ISER_QP_MAX_REQ_DTOS + 1; - max_send_wr = min_t(unsigned int, max_send_wr, - (unsigned int)ib_dev->attrs.max_qp_wr); + max_send_wr = min(max_send_wr, ib_dev->attrs.max_qp_wr); cq_size = max_send_wr + ISER_QP_MAX_RECV_DTOS; ib_conn->cq = ib_cq_pool_get(ib_dev, cq_size, -1, IB_POLL_SOFTIRQ); @@ -589,7 +588,7 @@ static void iser_route_handler(struct rdma_cm_id *cma_id) goto failure; memset(&conn_param, 0, sizeof conn_param); - conn_param.responder_resources = ib_dev->attrs.max_qp_rd_atom; + conn_param.responder_resources = min(ib_dev->attrs.max_qp_rd_atom, U8_MAX); conn_param.initiator_depth = 1; conn_param.retry_count = 7; conn_param.rnr_retry_count = 6; diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 348005e71891..e69db43370ff 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -21,6 +21,7 @@ #include <target/target_core_fabric.h> #include <target/iscsi/iscsi_transport.h> #include <linux/semaphore.h> +#include <linux/wait_bit.h> #include "ib_isert.h" @@ -59,6 +60,8 @@ static void isert_recv_done(struct ib_cq *cq, struct ib_wc *wc); static void isert_send_done(struct ib_cq *cq, struct ib_wc *wc); static void isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc); static void isert_login_send_done(struct ib_cq *cq, struct ib_wc *wc); +static void isert_unmap_tx_desc(struct iser_tx_desc *tx_desc, + struct ib_device *ib_dev); static int isert_sg_tablesize_set(const char *val, const struct kernel_param *kp) { @@ -214,9 +217,9 @@ isert_create_device_ib_res(struct isert_device *device) struct ib_device *ib_dev = device->ib_device; int ret; - isert_dbg("devattr->max_send_sge: %d devattr->max_recv_sge %d\n", + isert_dbg("devattr->max_send_sge: %u devattr->max_recv_sge %u\n", ib_dev->attrs.max_send_sge, ib_dev->attrs.max_recv_sge); - isert_dbg("devattr->max_sge_rd: %d\n", ib_dev->attrs.max_sge_rd); + isert_dbg("devattr->max_sge_rd: %u\n", ib_dev->attrs.max_sge_rd); device->pd = ib_alloc_pd(ib_dev, 0); if (IS_ERR(device->pd)) { @@ -308,6 +311,7 @@ isert_init_conn(struct isert_conn *isert_conn) init_completion(&isert_conn->login_req_comp); init_waitqueue_head(&isert_conn->rem_wait); kref_init(&isert_conn->kref); + atomic_set(&isert_conn->ctrl_comp_cnt, 0); mutex_init(&isert_conn->mutex); INIT_WORK(&isert_conn->release_work, isert_release_work); } @@ -381,8 +385,7 @@ isert_set_nego_params(struct isert_conn *isert_conn, struct ib_device_attr *attr = &isert_conn->device->ib_device->attrs; /* Set max inflight RDMA READ requests */ - isert_conn->initiator_depth = min_t(u8, param->initiator_depth, - attr->max_qp_init_rd_atom); + isert_conn->initiator_depth = min(param->initiator_depth, attr->max_qp_init_rd_atom); isert_dbg("Using initiator_depth: %u\n", isert_conn->initiator_depth); if (param->private_data) { @@ -496,6 +499,8 @@ isert_connect_release(struct isert_conn *isert_conn) if (isert_conn->qp) isert_destroy_qp(isert_conn); + isert_unmap_tx_desc(&isert_conn->login_tx_desc, device->ib_device); + if (isert_conn->login_desc) isert_free_login_buf(isert_conn); @@ -943,27 +948,16 @@ isert_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login, } if (!login->login_failed) { if (login->login_complete) { - ret = isert_alloc_rx_descriptors(isert_conn); - if (ret) - return ret; - - ret = isert_post_recvm(isert_conn, - ISERT_QP_MAX_RECV_DTOS); - if (ret) - return ret; - - /* Now we are in FULL_FEATURE phase */ - mutex_lock(&isert_conn->mutex); - isert_conn->state = ISER_CONN_FULL_FEATURE; - mutex_unlock(&isert_conn->mutex); - goto post_send; + /* Posted and sent from isert_get_rx_pdu(). */ + isert_conn->login_rsp_pending = true; + return 0; } ret = isert_login_post_recv(isert_conn); if (ret) return ret; } -post_send: + ret = isert_login_post_send(isert_conn, tx_desc); if (ret) return ret; @@ -971,6 +965,21 @@ post_send: return 0; } +static int +isert_check_login_req(struct isert_conn *isert_conn) +{ + struct iscsi_hdr *hdr = isert_get_iscsi_hdr(isert_conn->login_desc); + u32 dlength = ntoh24(hdr->dlength); + + if (unlikely(dlength > (u32)isert_conn->login_req_len)) { + isert_dbg("login PDU declares %u data bytes but only %d were received\n", + dlength, isert_conn->login_req_len); + return -EINVAL; + } + + return 0; +} + static void isert_rx_login_req(struct isert_conn *isert_conn) { @@ -1333,6 +1342,21 @@ isert_recv_done(struct ib_cq *cq, struct ib_wc *wc) ib_dma_sync_single_for_cpu(ib_dev, rx_desc->dma_addr, ISER_RX_SIZE, DMA_FROM_DEVICE); + /* + * The data segment length declared in the BHS is attacker controlled + * and is used further down to read that many bytes out of the fixed + * size receive descriptor, so it has to be checked against the number + * of bytes that were actually received. Comparing without subtracting + * also rejects PDUs shorter than the iSER and iSCSI headers, which + * would otherwise be parsed out of stale descriptor contents. + */ + if (unlikely(wc->byte_len < ISER_HEADERS_LEN + ntoh24(hdr->dlength))) { + isert_err("PDU declares %u data bytes but only %u bytes were received\n", + ntoh24(hdr->dlength), wc->byte_len); + iscsit_cause_connection_reinstatement(isert_conn->conn, 0); + return; + } + isert_dbg("DMA: 0x%llx, iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %d\n", rx_desc->dma_addr, hdr->opcode, hdr->itt, hdr->flags, (int)(wc->byte_len - ISER_HEADERS_LEN)); @@ -1383,13 +1407,23 @@ isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc) ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_desc->dma_addr, ISER_RX_SIZE, DMA_FROM_DEVICE); + if (unlikely(wc->byte_len < ISER_HEADERS_LEN)) { + isert_dbg("login request length %u is too short\n", + wc->byte_len); + return; + } + isert_conn->login_req_len = wc->byte_len - ISER_HEADERS_LEN; if (isert_conn->conn) { struct iscsi_login *login = isert_conn->conn->conn_login; - if (login && !login->first_request) + if (login && !login->first_request) { + if (isert_check_login_req(isert_conn)) + return; + isert_rx_login_req(isert_conn); + } } mutex_lock(&isert_conn->mutex); @@ -1662,6 +1696,8 @@ isert_do_control_comp(struct work_struct *work) struct isert_conn *isert_conn = isert_cmd->conn; struct ib_device *ib_dev = isert_conn->cm_id->device; struct iscsit_cmd *cmd = isert_cmd->iscsit_cmd; + /* The switch below may free isert_cmd. */ + bool counted = isert_cmd->ctrl_counted; isert_dbg("Cmd %p i_state %d\n", isert_cmd, cmd->i_state); @@ -1683,6 +1719,14 @@ isert_do_control_comp(struct work_struct *work) dump_stack(); break; } + + /* + * The count is what keeps isert_conn alive, so drop it last. The wait + * queue lives in the global hash table, not in isert_conn, so this is + * safe even if the waiter has already freed the connection. + */ + if (counted && atomic_dec_and_test(&isert_conn->ctrl_comp_cnt)) + wake_up_var(&isert_conn->ctrl_comp_cnt); } static void @@ -1726,6 +1770,12 @@ isert_send_done(struct ib_cq *cq, struct ib_wc *wc) case ISTATE_SEND_TEXTRSP: isert_unmap_tx_desc(tx_desc, ib_dev); + /* Paired with the wait in isert_wait_conn(). */ + isert_cmd->ctrl_counted = + isert_cmd->iscsit_cmd->i_state != ISTATE_SEND_LOGOUTRSP; + if (isert_cmd->ctrl_counted) + atomic_inc(&isert_conn->ctrl_comp_cnt); + INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp); queue_work(isert_comp_wq, &isert_cmd->comp_work); return; @@ -2354,6 +2404,10 @@ isert_get_login_rx(struct iscsit_conn *conn, struct iscsi_login *login) if (!login->first_request) return 0; + ret = isert_check_login_req(isert_conn); + if (ret) + return ret; + isert_rx_login_req(isert_conn); isert_info("before login_comp conn: %p\n", conn); @@ -2566,6 +2620,10 @@ static void isert_wait_conn(struct iscsit_conn *conn) isert_wait4cmds(conn); isert_wait4logout(isert_conn); + /* Paired with the count taken in isert_send_done(). */ + wait_var_event(&isert_conn->ctrl_comp_cnt, + !atomic_read(&isert_conn->ctrl_comp_cnt)); + queue_work(isert_release_wq, &isert_conn->release_work); } @@ -2579,8 +2637,30 @@ static void isert_free_conn(struct iscsit_conn *conn) static void isert_get_rx_pdu(struct iscsit_conn *conn) { + struct isert_conn *isert_conn = conn->context; struct completion comp; + /* The login timeout timer can fail the login after isert_put_login_tx(). */ + if (!isert_conn->login_rsp_pending) + return; + + isert_conn->login_rsp_pending = false; + + /* The session is registered by now; see isert_put_login_tx(). */ + if (isert_alloc_rx_descriptors(isert_conn)) + return; + + if (isert_post_recvm(isert_conn, ISERT_QP_MAX_RECV_DTOS)) + return; + + /* Now we are in FULL_FEATURE phase */ + mutex_lock(&isert_conn->mutex); + isert_conn->state = ISER_CONN_FULL_FEATURE; + mutex_unlock(&isert_conn->mutex); + + if (isert_login_post_send(isert_conn, &isert_conn->login_tx_desc)) + return; + init_completion(&comp); wait_for_completion_interruptible(&comp); diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h index 0b2dfd6e7e27..519b17e54bd3 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.h +++ b/drivers/infiniband/ulp/isert/ib_isert.h @@ -153,6 +153,7 @@ struct isert_cmd { struct work_struct comp_work; struct scatterlist sg; bool ctx_init_done; + bool ctrl_counted; }; static inline struct isert_cmd *tx_desc_to_cmd(struct iser_tx_desc *desc) @@ -178,6 +179,7 @@ struct isert_conn { struct completion login_comp; struct completion login_req_comp; struct iser_tx_desc login_tx_desc; + bool login_rsp_pending; struct rdma_cm_id *cm_id; struct ib_qp *qp; struct ib_cq *cq; @@ -186,6 +188,7 @@ struct isert_conn { struct mutex mutex; struct kref kref; struct work_struct release_work; + atomic_t ctrl_comp_cnt; bool logout_posted; bool snd_w_inv; wait_queue_head_t rem_wait; diff --git a/drivers/infiniband/ulp/opa_vnic/Kconfig b/drivers/infiniband/ulp/opa_vnic/Kconfig deleted file mode 100644 index 4d43d055fa8e..000000000000 --- a/drivers/infiniband/ulp/opa_vnic/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config INFINIBAND_OPA_VNIC - tristate "Cornelis OPX VNIC support" - depends on X86_64 && INFINIBAND - help - This is Omni-Path Express (OPX) Virtual Network Interface Controller (VNIC) - driver for Ethernet over Omni-Path feature. It implements the HW - independent VNIC functionality. It interfaces with Linux stack for - data path and IB MAD for the control path. diff --git a/drivers/infiniband/ulp/opa_vnic/Makefile b/drivers/infiniband/ulp/opa_vnic/Makefile deleted file mode 100644 index 196183817cdc..000000000000 --- a/drivers/infiniband/ulp/opa_vnic/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Makefile - Cornelis Omni-Path Express Virtual Network Controller driver -# Copyright(c) 2017, Intel Corporation. -# Copyright(c) 2021, Cornelis Networks. -# -obj-$(CONFIG_INFINIBAND_OPA_VNIC) += opa_vnic.o - -opa_vnic-y := opa_vnic_netdev.o opa_vnic_encap.o opa_vnic_ethtool.o \ - opa_vnic_vema.o opa_vnic_vema_iface.o diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c deleted file mode 100644 index 53dcf06fbee0..000000000000 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Copyright(c) 2017 Intel Corporation. - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * BSD LICENSE - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * This file contains OPA VNIC encapsulation/decapsulation function. - */ - -#include <linux/if_ether.h> -#include <linux/if_vlan.h> - -#include "opa_vnic_internal.h" - -/* OPA 16B Header fields */ -#define OPA_16B_LID_MASK 0xFFFFFull -#define OPA_16B_SLID_HIGH_SHFT 8 -#define OPA_16B_SLID_MASK 0xF00ull -#define OPA_16B_DLID_MASK 0xF000ull -#define OPA_16B_DLID_HIGH_SHFT 12 -#define OPA_16B_LEN_SHFT 20 -#define OPA_16B_SC_SHFT 20 -#define OPA_16B_RC_SHFT 25 -#define OPA_16B_PKEY_SHFT 16 - -#define OPA_VNIC_L4_HDR_SHFT 16 - -/* L2+L4 hdr len is 20 bytes (5 quad words) */ -#define OPA_VNIC_HDR_QW_LEN 5 - -static inline void opa_vnic_make_header(u8 *hdr, u32 slid, u32 dlid, u16 len, - u16 pkey, u16 entropy, u8 sc, u8 rc, - u8 l4_type, u16 l4_hdr) -{ - /* h[1]: LT=1, 16B L2=10 */ - u32 h[OPA_VNIC_HDR_QW_LEN] = {0, 0xc0000000, 0, 0, 0}; - - h[2] = l4_type; - h[3] = entropy; - h[4] = l4_hdr << OPA_VNIC_L4_HDR_SHFT; - - /* Extract and set 4 upper bits and 20 lower bits of the lids */ - h[0] |= (slid & OPA_16B_LID_MASK); - h[2] |= ((slid >> (20 - OPA_16B_SLID_HIGH_SHFT)) & OPA_16B_SLID_MASK); - - h[1] |= (dlid & OPA_16B_LID_MASK); - h[2] |= ((dlid >> (20 - OPA_16B_DLID_HIGH_SHFT)) & OPA_16B_DLID_MASK); - - h[0] |= (len << OPA_16B_LEN_SHFT); - h[1] |= (rc << OPA_16B_RC_SHFT); - h[1] |= (sc << OPA_16B_SC_SHFT); - h[2] |= ((u32)pkey << OPA_16B_PKEY_SHFT); - - memcpy(hdr, h, OPA_VNIC_HDR_LEN); -} - -/* - * Using a simple hash table for mac table implementation with the last octet - * of mac address as a key. - */ -static void opa_vnic_free_mac_tbl(struct hlist_head *mactbl) -{ - struct opa_vnic_mac_tbl_node *node; - struct hlist_node *tmp; - int bkt; - - if (!mactbl) - return; - - vnic_hash_for_each_safe(mactbl, bkt, tmp, node, hlist) { - hash_del(&node->hlist); - kfree(node); - } - kfree(mactbl); -} - -static struct hlist_head *opa_vnic_alloc_mac_tbl(void) -{ - u32 size = sizeof(struct hlist_head) * OPA_VNIC_MAC_TBL_SIZE; - struct hlist_head *mactbl; - - mactbl = kzalloc(size, GFP_KERNEL); - if (!mactbl) - return ERR_PTR(-ENOMEM); - - vnic_hash_init(mactbl); - return mactbl; -} - -/* opa_vnic_release_mac_tbl - empty and free the mac table */ -void opa_vnic_release_mac_tbl(struct opa_vnic_adapter *adapter) -{ - struct hlist_head *mactbl; - - mutex_lock(&adapter->mactbl_lock); - mactbl = rcu_access_pointer(adapter->mactbl); - rcu_assign_pointer(adapter->mactbl, NULL); - synchronize_rcu(); - opa_vnic_free_mac_tbl(mactbl); - adapter->info.vport.mac_tbl_digest = 0; - mutex_unlock(&adapter->mactbl_lock); -} - -/* - * opa_vnic_query_mac_tbl - query the mac table for a section - * - * This function implements query of specific function of the mac table. - * The function also expects the requested range to be valid. - */ -void opa_vnic_query_mac_tbl(struct opa_vnic_adapter *adapter, - struct opa_veswport_mactable *tbl) -{ - struct opa_vnic_mac_tbl_node *node; - struct hlist_head *mactbl; - int bkt; - u16 loffset, lnum_entries; - - rcu_read_lock(); - mactbl = rcu_dereference(adapter->mactbl); - if (!mactbl) - goto get_mac_done; - - loffset = be16_to_cpu(tbl->offset); - lnum_entries = be16_to_cpu(tbl->num_entries); - - vnic_hash_for_each(mactbl, bkt, node, hlist) { - struct __opa_vnic_mactable_entry *nentry = &node->entry; - struct opa_veswport_mactable_entry *entry; - - if ((node->index < loffset) || - (node->index >= (loffset + lnum_entries))) - continue; - - /* populate entry in the tbl corresponding to the index */ - entry = &tbl->tbl_entries[node->index - loffset]; - memcpy(entry->mac_addr, nentry->mac_addr, - ARRAY_SIZE(entry->mac_addr)); - memcpy(entry->mac_addr_mask, nentry->mac_addr_mask, - ARRAY_SIZE(entry->mac_addr_mask)); - entry->dlid_sd = cpu_to_be32(nentry->dlid_sd); - } - tbl->mac_tbl_digest = cpu_to_be32(adapter->info.vport.mac_tbl_digest); -get_mac_done: - rcu_read_unlock(); -} - -/* - * opa_vnic_update_mac_tbl - update mac table section - * - * This function updates the specified section of the mac table. - * The procedure includes following steps. - * - Allocate a new mac (hash) table. - * - Add the specified entries to the new table. - * (except the ones that are requested to be deleted). - * - Add all the other entries from the old mac table. - * - If there is a failure, free the new table and return. - * - Switch to the new table. - * - Free the old table and return. - * - * The function also expects the requested range to be valid. - */ -int opa_vnic_update_mac_tbl(struct opa_vnic_adapter *adapter, - struct opa_veswport_mactable *tbl) -{ - struct opa_vnic_mac_tbl_node *node, *new_node; - struct hlist_head *new_mactbl, *old_mactbl; - int i, bkt, rc = 0; - u8 key; - u16 loffset, lnum_entries; - - mutex_lock(&adapter->mactbl_lock); - /* allocate new mac table */ - new_mactbl = opa_vnic_alloc_mac_tbl(); - if (IS_ERR(new_mactbl)) { - mutex_unlock(&adapter->mactbl_lock); - return PTR_ERR(new_mactbl); - } - - loffset = be16_to_cpu(tbl->offset); - lnum_entries = be16_to_cpu(tbl->num_entries); - - /* add updated entries to the new mac table */ - for (i = 0; i < lnum_entries; i++) { - struct __opa_vnic_mactable_entry *nentry; - struct opa_veswport_mactable_entry *entry = - &tbl->tbl_entries[i]; - u8 *mac_addr = entry->mac_addr; - u8 empty_mac[ETH_ALEN] = { 0 }; - - v_dbg("new mac entry %4d: %02x:%02x:%02x:%02x:%02x:%02x %x\n", - loffset + i, mac_addr[0], mac_addr[1], mac_addr[2], - mac_addr[3], mac_addr[4], mac_addr[5], - entry->dlid_sd); - - /* if the entry is being removed, do not add it */ - if (!memcmp(mac_addr, empty_mac, ARRAY_SIZE(empty_mac))) - continue; - - node = kzalloc_obj(*node); - if (!node) { - rc = -ENOMEM; - goto updt_done; - } - - node->index = loffset + i; - nentry = &node->entry; - memcpy(nentry->mac_addr, entry->mac_addr, - ARRAY_SIZE(nentry->mac_addr)); - memcpy(nentry->mac_addr_mask, entry->mac_addr_mask, - ARRAY_SIZE(nentry->mac_addr_mask)); - nentry->dlid_sd = be32_to_cpu(entry->dlid_sd); - key = node->entry.mac_addr[OPA_VNIC_MAC_HASH_IDX]; - vnic_hash_add(new_mactbl, &node->hlist, key); - } - - /* add other entries from current mac table to new mac table */ - old_mactbl = rcu_access_pointer(adapter->mactbl); - if (!old_mactbl) - goto switch_tbl; - - vnic_hash_for_each(old_mactbl, bkt, node, hlist) { - if ((node->index >= loffset) && - (node->index < (loffset + lnum_entries))) - continue; - - new_node = kzalloc_obj(*new_node); - if (!new_node) { - rc = -ENOMEM; - goto updt_done; - } - - new_node->index = node->index; - memcpy(&new_node->entry, &node->entry, sizeof(node->entry)); - key = new_node->entry.mac_addr[OPA_VNIC_MAC_HASH_IDX]; - vnic_hash_add(new_mactbl, &new_node->hlist, key); - } - -switch_tbl: - /* switch to new table */ - rcu_assign_pointer(adapter->mactbl, new_mactbl); - synchronize_rcu(); - - adapter->info.vport.mac_tbl_digest = be32_to_cpu(tbl->mac_tbl_digest); -updt_done: - /* upon failure, free the new table; otherwise, free the old table */ - if (rc) - opa_vnic_free_mac_tbl(new_mactbl); - else - opa_vnic_free_mac_tbl(old_mactbl); - - mutex_unlock(&adapter->mactbl_lock); - return rc; -} - -/* opa_vnic_chk_mac_tbl - check mac table for dlid */ -static uint32_t opa_vnic_chk_mac_tbl(struct opa_vnic_adapter *adapter, - struct ethhdr *mac_hdr) -{ - struct opa_vnic_mac_tbl_node *node; - struct hlist_head *mactbl; - u32 dlid = 0; - u8 key; - - rcu_read_lock(); - mactbl = rcu_dereference(adapter->mactbl); - if (unlikely(!mactbl)) - goto chk_done; - - key = mac_hdr->h_dest[OPA_VNIC_MAC_HASH_IDX]; - vnic_hash_for_each_possible(mactbl, node, hlist, key) { - struct __opa_vnic_mactable_entry *entry = &node->entry; - - /* if related to source mac, skip */ - if (unlikely(OPA_VNIC_DLID_SD_IS_SRC_MAC(entry->dlid_sd))) - continue; - - if (!memcmp(node->entry.mac_addr, mac_hdr->h_dest, - ARRAY_SIZE(node->entry.mac_addr))) { - /* mac address found */ - dlid = OPA_VNIC_DLID_SD_GET_DLID(node->entry.dlid_sd); - break; - } - } - -chk_done: - rcu_read_unlock(); - return dlid; -} - -/* opa_vnic_get_dlid - find and return the DLID */ -static uint32_t opa_vnic_get_dlid(struct opa_vnic_adapter *adapter, - struct sk_buff *skb, u8 def_port) -{ - struct __opa_veswport_info *info = &adapter->info; - struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb); - u32 dlid; - - dlid = opa_vnic_chk_mac_tbl(adapter, mac_hdr); - if (dlid) - return dlid; - - if (is_multicast_ether_addr(mac_hdr->h_dest)) { - dlid = info->vesw.u_mcast_dlid; - } else { - if (is_local_ether_addr(mac_hdr->h_dest)) { - dlid = ((uint32_t)mac_hdr->h_dest[5] << 16) | - ((uint32_t)mac_hdr->h_dest[4] << 8) | - mac_hdr->h_dest[3]; - if (unlikely(!dlid)) - v_warn("Null dlid in MAC address\n"); - } else if (def_port != OPA_VNIC_INVALID_PORT) { - if (def_port < OPA_VESW_MAX_NUM_DEF_PORT) - dlid = info->vesw.u_ucast_dlid[def_port]; - } - } - - return dlid; -} - -/* opa_vnic_get_sc - return the service class */ -static u8 opa_vnic_get_sc(struct __opa_veswport_info *info, - struct sk_buff *skb) -{ - struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb); - u16 vlan_tci; - u8 sc; - - if (!__vlan_get_tag(skb, &vlan_tci)) { - u8 pcp = OPA_VNIC_VLAN_PCP(vlan_tci); - - if (is_multicast_ether_addr(mac_hdr->h_dest)) - sc = info->vport.pcp_to_sc_mc[pcp]; - else - sc = info->vport.pcp_to_sc_uc[pcp]; - } else { - if (is_multicast_ether_addr(mac_hdr->h_dest)) - sc = info->vport.non_vlan_sc_mc; - else - sc = info->vport.non_vlan_sc_uc; - } - - return sc; -} - -u8 opa_vnic_get_vl(struct opa_vnic_adapter *adapter, struct sk_buff *skb) -{ - struct ethhdr *mac_hdr = (struct ethhdr *)skb_mac_header(skb); - struct __opa_veswport_info *info = &adapter->info; - u8 vl; - - if (skb_vlan_tag_present(skb)) { - u8 pcp = skb_vlan_tag_get(skb) >> VLAN_PRIO_SHIFT; - - if (is_multicast_ether_addr(mac_hdr->h_dest)) - vl = info->vport.pcp_to_vl_mc[pcp]; - else - vl = info->vport.pcp_to_vl_uc[pcp]; - } else { - if (is_multicast_ether_addr(mac_hdr->h_dest)) - vl = info->vport.non_vlan_vl_mc; - else - vl = info->vport.non_vlan_vl_uc; - } - - return vl; -} - -/* opa_vnic_get_rc - return the routing control */ -static u8 opa_vnic_get_rc(struct __opa_veswport_info *info, - struct sk_buff *skb) -{ - u8 proto, rout_ctrl; - - switch (vlan_get_protocol(skb)) { - case htons(ETH_P_IPV6): - proto = ipv6_hdr(skb)->nexthdr; - if (proto == IPPROTO_TCP) - rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, - IPV6_TCP); - else if (proto == IPPROTO_UDP) - rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, - IPV6_UDP); - else - rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, IPV6); - break; - case htons(ETH_P_IP): - proto = ip_hdr(skb)->protocol; - if (proto == IPPROTO_TCP) - rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, - IPV4_TCP); - else if (proto == IPPROTO_UDP) - rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, - IPV4_UDP); - else - rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, IPV4); - break; - default: - rout_ctrl = OPA_VNIC_ENCAP_RC_EXT(info->vesw.rc, DEFAULT); - } - - return rout_ctrl; -} - -/* opa_vnic_calc_entropy - calculate the packet entropy */ -u8 opa_vnic_calc_entropy(struct sk_buff *skb) -{ - u32 hash = skb_get_hash(skb); - - /* store XOR of all bytes in lower 8 bits */ - hash ^= hash >> 8; - hash ^= hash >> 16; - - /* return lower 8 bits as entropy */ - return (u8)(hash & 0xFF); -} - -/* opa_vnic_get_def_port - get default port based on entropy */ -static inline u8 opa_vnic_get_def_port(struct opa_vnic_adapter *adapter, - u8 entropy) -{ - u8 flow_id; - - /* Add the upper and lower 4-bits of entropy to get the flow id */ - flow_id = ((entropy & 0xf) + (entropy >> 4)); - return adapter->flow_tbl[flow_id & (OPA_VNIC_FLOW_TBL_SIZE - 1)]; -} - -/* Calculate packet length including OPA header, crc and padding */ -static inline int opa_vnic_wire_length(struct sk_buff *skb) -{ - u32 pad_len; - - /* padding for 8 bytes size alignment */ - pad_len = -(skb->len + OPA_VNIC_ICRC_TAIL_LEN) & 0x7; - pad_len += OPA_VNIC_ICRC_TAIL_LEN; - - return (skb->len + pad_len) >> 3; -} - -/* opa_vnic_encap_skb - encapsulate skb packet with OPA header and meta data */ -void opa_vnic_encap_skb(struct opa_vnic_adapter *adapter, struct sk_buff *skb) -{ - struct __opa_veswport_info *info = &adapter->info; - struct opa_vnic_skb_mdata *mdata; - u8 def_port, sc, rc, entropy, *hdr; - u16 len, l4_hdr; - u32 dlid; - - hdr = skb_push(skb, OPA_VNIC_HDR_LEN); - - entropy = opa_vnic_calc_entropy(skb); - def_port = opa_vnic_get_def_port(adapter, entropy); - len = opa_vnic_wire_length(skb); - dlid = opa_vnic_get_dlid(adapter, skb, def_port); - sc = opa_vnic_get_sc(info, skb); - rc = opa_vnic_get_rc(info, skb); - l4_hdr = info->vesw.vesw_id; - - mdata = skb_push(skb, sizeof(*mdata)); - mdata->vl = opa_vnic_get_vl(adapter, skb); - mdata->entropy = entropy; - mdata->flags = 0; - if (unlikely(!dlid)) { - mdata->flags = OPA_VNIC_SKB_MDATA_ENCAP_ERR; - return; - } - - opa_vnic_make_header(hdr, info->vport.encap_slid, dlid, len, - info->vesw.pkey, entropy, sc, rc, - OPA_VNIC_L4_ETHR, l4_hdr); -} diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.h b/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.h deleted file mode 100644 index 012fc27c5c93..000000000000 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_encap.h +++ /dev/null @@ -1,524 +0,0 @@ -#ifndef _OPA_VNIC_ENCAP_H -#define _OPA_VNIC_ENCAP_H -/* - * Copyright(c) 2017 Intel Corporation. - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * BSD LICENSE - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * This file contains all OPA VNIC declaration required for encapsulation - * and decapsulation of Ethernet packets - */ - -#include <linux/types.h> -#include <rdma/ib_mad.h> - -/* EMA class version */ -#define OPA_EMA_CLASS_VERSION 0x80 - -/* - * Define the Intel vendor management class for OPA - * ETHERNET MANAGEMENT - */ -#define OPA_MGMT_CLASS_INTEL_EMA 0x34 - -/* EM attribute IDs */ -#define OPA_EM_ATTR_CLASS_PORT_INFO 0x0001 -#define OPA_EM_ATTR_VESWPORT_INFO 0x0011 -#define OPA_EM_ATTR_VESWPORT_MAC_ENTRIES 0x0012 -#define OPA_EM_ATTR_IFACE_UCAST_MACS 0x0013 -#define OPA_EM_ATTR_IFACE_MCAST_MACS 0x0014 -#define OPA_EM_ATTR_DELETE_VESW 0x0015 -#define OPA_EM_ATTR_VESWPORT_SUMMARY_COUNTERS 0x0020 -#define OPA_EM_ATTR_VESWPORT_ERROR_COUNTERS 0x0022 - -/* VNIC configured and operational state values */ -#define OPA_VNIC_STATE_DROP_ALL 0x1 -#define OPA_VNIC_STATE_FORWARDING 0x3 - -#define OPA_VESW_MAX_NUM_DEF_PORT 16 -#define OPA_VNIC_MAX_NUM_PCP 8 - -#define OPA_VNIC_EMA_DATA (OPA_MGMT_MAD_SIZE - IB_MGMT_VENDOR_HDR) - -/* Defines for vendor specific notice(trap) attributes */ -#define OPA_INTEL_EMA_NOTICE_TYPE_INFO 0x04 - -/* INTEL OUI */ -#define INTEL_OUI_1 0x00 -#define INTEL_OUI_2 0x06 -#define INTEL_OUI_3 0x6a - -/* Trap opcodes sent from VNIC */ -#define OPA_VESWPORT_TRAP_IFACE_UCAST_MAC_CHANGE 0x1 -#define OPA_VESWPORT_TRAP_IFACE_MCAST_MAC_CHANGE 0x2 -#define OPA_VESWPORT_TRAP_ETH_LINK_STATUS_CHANGE 0x3 - -#define OPA_VNIC_DLID_SD_IS_SRC_MAC(dlid_sd) (!!((dlid_sd) & 0x20)) -#define OPA_VNIC_DLID_SD_GET_DLID(dlid_sd) ((dlid_sd) >> 8) - -/* VNIC Ethernet link status */ -#define OPA_VNIC_ETH_LINK_UP 1 -#define OPA_VNIC_ETH_LINK_DOWN 2 - -/* routing control */ -#define OPA_VNIC_ENCAP_RC_DEFAULT 0 -#define OPA_VNIC_ENCAP_RC_IPV4 4 -#define OPA_VNIC_ENCAP_RC_IPV4_UDP 8 -#define OPA_VNIC_ENCAP_RC_IPV4_TCP 12 -#define OPA_VNIC_ENCAP_RC_IPV6 16 -#define OPA_VNIC_ENCAP_RC_IPV6_TCP 20 -#define OPA_VNIC_ENCAP_RC_IPV6_UDP 24 - -#define OPA_VNIC_ENCAP_RC_EXT(w, b) (((w) >> OPA_VNIC_ENCAP_RC_ ## b) & 0x7) - -/** - * struct opa_vesw_info - OPA vnic switch information - * @fabric_id: 10-bit fabric id - * @vesw_id: 12-bit virtual ethernet switch id - * @rsvd0: reserved bytes - * @def_port_mask: bitmask of default ports - * @rsvd1: reserved bytes - * @pkey: partition key - * @rsvd2: reserved bytes - * @u_mcast_dlid: unknown multicast dlid - * @u_ucast_dlid: array of unknown unicast dlids - * @rsvd3: reserved bytes - * @rc: routing control - * @eth_mtu: Ethernet MTU - * @rsvd4: reserved bytes - */ -struct opa_vesw_info { - __be16 fabric_id; - __be16 vesw_id; - - u8 rsvd0[6]; - __be16 def_port_mask; - - u8 rsvd1[2]; - __be16 pkey; - - u8 rsvd2[4]; - __be32 u_mcast_dlid; - __be32 u_ucast_dlid[OPA_VESW_MAX_NUM_DEF_PORT]; - - __be32 rc; - - u8 rsvd3[56]; - __be16 eth_mtu; - u8 rsvd4[2]; -} __packed; - -/** - * struct opa_per_veswport_info - OPA vnic per port information - * @port_num: port number - * @eth_link_status: current ethernet link state - * @rsvd0: reserved bytes - * @base_mac_addr: base mac address - * @config_state: configured port state - * @oper_state: operational port state - * @max_mac_tbl_ent: max number of mac table entries - * @max_smac_ent: max smac entries in mac table - * @mac_tbl_digest: mac table digest - * @rsvd1: reserved bytes - * @encap_slid: base slid for the port - * @pcp_to_sc_uc: sc by pcp index for unicast ethernet packets - * @pcp_to_vl_uc: vl by pcp index for unicast ethernet packets - * @pcp_to_sc_mc: sc by pcp index for multicast ethernet packets - * @pcp_to_vl_mc: vl by pcp index for multicast ethernet packets - * @non_vlan_sc_uc: sc for non-vlan unicast ethernet packets - * @non_vlan_vl_uc: vl for non-vlan unicast ethernet packets - * @non_vlan_sc_mc: sc for non-vlan multicast ethernet packets - * @non_vlan_vl_mc: vl for non-vlan multicast ethernet packets - * @rsvd2: reserved bytes - * @uc_macs_gen_count: generation count for unicast macs list - * @mc_macs_gen_count: generation count for multicast macs list - * @rsvd3: reserved bytes - */ -struct opa_per_veswport_info { - __be32 port_num; - - u8 eth_link_status; - u8 rsvd0[3]; - - u8 base_mac_addr[ETH_ALEN]; - u8 config_state; - u8 oper_state; - - __be16 max_mac_tbl_ent; - __be16 max_smac_ent; - __be32 mac_tbl_digest; - u8 rsvd1[4]; - - __be32 encap_slid; - - u8 pcp_to_sc_uc[OPA_VNIC_MAX_NUM_PCP]; - u8 pcp_to_vl_uc[OPA_VNIC_MAX_NUM_PCP]; - u8 pcp_to_sc_mc[OPA_VNIC_MAX_NUM_PCP]; - u8 pcp_to_vl_mc[OPA_VNIC_MAX_NUM_PCP]; - - u8 non_vlan_sc_uc; - u8 non_vlan_vl_uc; - u8 non_vlan_sc_mc; - u8 non_vlan_vl_mc; - - u8 rsvd2[48]; - - __be16 uc_macs_gen_count; - __be16 mc_macs_gen_count; - - u8 rsvd3[8]; -} __packed; - -/** - * struct opa_veswport_info - OPA vnic port information - * @vesw: OPA vnic switch information - * @vport: OPA vnic per port information - * - * On host, each of the virtual ethernet ports belongs - * to a different virtual ethernet switches. - */ -struct opa_veswport_info { - struct opa_vesw_info vesw; - struct opa_per_veswport_info vport; -}; - -/** - * struct opa_veswport_mactable_entry - single entry in the forwarding table - * @mac_addr: MAC address - * @mac_addr_mask: MAC address bit mask - * @dlid_sd: Matching DLID and side data - * - * On the host each virtual ethernet port will have - * a forwarding table. These tables are used to - * map a MAC to a LID and other data. For more - * details see struct opa_veswport_mactable_entries. - * This is the structure of a single mactable entry - */ -struct opa_veswport_mactable_entry { - u8 mac_addr[ETH_ALEN]; - u8 mac_addr_mask[ETH_ALEN]; - __be32 dlid_sd; -} __packed; - -/** - * struct opa_veswport_mactable - Forwarding table array - * @offset: mac table starting offset - * @num_entries: Number of entries to get or set - * @mac_tbl_digest: mac table digest - * @tbl_entries: Array of table entries - * - * The EM sends down this structure in a MAD indicating - * the starting offset in the forwarding table that this - * entry is to be loaded into and the number of entries - * that that this MAD instance contains - * The mac_tbl_digest has been added to this MAD structure. It will be set by - * the EM and it will be used by the EM to check if there are any - * discrepancies with this value and the value - * maintained by the EM in the case of VNIC port being deleted or unloaded - * A new instantiation of a VNIC will always have a value of zero. - * This value is stored as part of the vnic adapter structure and will be - * accessed by the GET and SET routines for both the mactable entries and the - * veswport info. - */ -struct opa_veswport_mactable { - __be16 offset; - __be16 num_entries; - __be32 mac_tbl_digest; - struct opa_veswport_mactable_entry tbl_entries[]; -} __packed; - -/** - * struct opa_veswport_summary_counters - summary counters - * @vp_instance: vport instance on the OPA port - * @vesw_id: virtual ethernet switch id - * @veswport_num: virtual ethernet switch port number - * @tx_errors: transmit errors - * @rx_errors: receive errors - * @tx_packets: transmit packets - * @rx_packets: receive packets - * @tx_bytes: transmit bytes - * @rx_bytes: receive bytes - * @tx_unicast: unicast packets transmitted - * @tx_mcastbcast: multicast/broadcast packets transmitted - * @tx_untagged: non-vlan packets transmitted - * @tx_vlan: vlan packets transmitted - * @tx_64_size: transmit packet length is 64 bytes - * @tx_65_127: transmit packet length is >=65 and < 127 bytes - * @tx_128_255: transmit packet length is >=128 and < 255 bytes - * @tx_256_511: transmit packet length is >=256 and < 511 bytes - * @tx_512_1023: transmit packet length is >=512 and < 1023 bytes - * @tx_1024_1518: transmit packet length is >=1024 and < 1518 bytes - * @tx_1519_max: transmit packet length >= 1519 bytes - * @rx_unicast: unicast packets received - * @rx_mcastbcast: multicast/broadcast packets received - * @rx_untagged: non-vlan packets received - * @rx_vlan: vlan packets received - * @rx_64_size: received packet length is 64 bytes - * @rx_65_127: received packet length is >=65 and < 127 bytes - * @rx_128_255: received packet length is >=128 and < 255 bytes - * @rx_256_511: received packet length is >=256 and < 511 bytes - * @rx_512_1023: received packet length is >=512 and < 1023 bytes - * @rx_1024_1518: received packet length is >=1024 and < 1518 bytes - * @rx_1519_max: received packet length >= 1519 bytes - * @reserved: reserved bytes - * - * All the above are counters of corresponding conditions. - */ -struct opa_veswport_summary_counters { - __be16 vp_instance; - __be16 vesw_id; - __be32 veswport_num; - - __be64 tx_errors; - __be64 rx_errors; - __be64 tx_packets; - __be64 rx_packets; - __be64 tx_bytes; - __be64 rx_bytes; - - __be64 tx_unicast; - __be64 tx_mcastbcast; - - __be64 tx_untagged; - __be64 tx_vlan; - - __be64 tx_64_size; - __be64 tx_65_127; - __be64 tx_128_255; - __be64 tx_256_511; - __be64 tx_512_1023; - __be64 tx_1024_1518; - __be64 tx_1519_max; - - __be64 rx_unicast; - __be64 rx_mcastbcast; - - __be64 rx_untagged; - __be64 rx_vlan; - - __be64 rx_64_size; - __be64 rx_65_127; - __be64 rx_128_255; - __be64 rx_256_511; - __be64 rx_512_1023; - __be64 rx_1024_1518; - __be64 rx_1519_max; - - __be64 reserved[16]; -} __packed; - -/** - * struct opa_veswport_error_counters - error counters - * @vp_instance: vport instance on the OPA port - * @vesw_id: virtual ethernet switch id - * @veswport_num: virtual ethernet switch port number - * @tx_errors: transmit errors - * @rx_errors: receive errors - * @rsvd0: reserved bytes - * @tx_smac_filt: smac filter errors - * @rsvd1: reserved bytes - * @rsvd2: reserved bytes - * @rsvd3: reserved bytes - * @tx_dlid_zero: transmit packets with invalid dlid - * @rsvd4: reserved bytes - * @tx_logic: other transmit errors - * @rsvd5: reserved bytes - * @tx_drop_state: packet tansmission in non-forward port state - * @rx_bad_veswid: received packet with invalid vesw id - * @rsvd6: reserved bytes - * @rx_runt: received ethernet packet with length < 64 bytes - * @rx_oversize: received ethernet packet with length > MTU size - * @rsvd7: reserved bytes - * @rx_eth_down: received packets when interface is down - * @rx_drop_state: received packets in non-forwarding port state - * @rx_logic: other receive errors - * @rsvd8: reserved bytes - * @rsvd9: reserved bytes - * - * All the above are counters of corresponding error conditions. - */ -struct opa_veswport_error_counters { - __be16 vp_instance; - __be16 vesw_id; - __be32 veswport_num; - - __be64 tx_errors; - __be64 rx_errors; - - __be64 rsvd0; - __be64 tx_smac_filt; - __be64 rsvd1; - __be64 rsvd2; - __be64 rsvd3; - __be64 tx_dlid_zero; - __be64 rsvd4; - __be64 tx_logic; - __be64 rsvd5; - __be64 tx_drop_state; - - __be64 rx_bad_veswid; - __be64 rsvd6; - __be64 rx_runt; - __be64 rx_oversize; - __be64 rsvd7; - __be64 rx_eth_down; - __be64 rx_drop_state; - __be64 rx_logic; - __be64 rsvd8; - - __be64 rsvd9[16]; -} __packed; - -/** - * struct opa_veswport_trap - Trap message sent to EM by VNIC - * @fabric_id: 10 bit fabric id - * @veswid: 12 bit virtual ethernet switch id - * @veswportnum: logical port number on the Virtual switch - * @opaportnum: physical port num (redundant on host) - * @veswportindex: switch port index on opa port 0 based - * @opcode: operation - * @reserved: 32 bit for alignment - * - * The VNIC will send trap messages to the Ethernet manager to - * inform it about changes to the VNIC config, behaviour etc. - * This is the format of the trap payload. - */ -struct opa_veswport_trap { - __be16 fabric_id; - __be16 veswid; - __be32 veswportnum; - __be16 opaportnum; - u8 veswportindex; - u8 opcode; - __be32 reserved; -} __packed; - -/** - * struct opa_vnic_iface_mac_entry - single entry in the mac list - * @mac_addr: MAC address - */ -struct opa_vnic_iface_mac_entry { - u8 mac_addr[ETH_ALEN]; -}; - -/** - * struct opa_veswport_iface_macs - Msg to set globally administered MAC - * @start_idx: position of first entry (0 based) - * @num_macs_in_msg: number of MACs in this message - * @tot_macs_in_lst: The total number of MACs the agent has - * @gen_count: gen_count to indicate change - * @entry: The mac list entry - * - * Same attribute IDS and attribute modifiers as in locally administered - * addresses used to set globally administered addresses - */ -struct opa_veswport_iface_macs { - __be16 start_idx; - __be16 num_macs_in_msg; - __be16 tot_macs_in_lst; - __be16 gen_count; - struct opa_vnic_iface_mac_entry entry[]; -} __packed; - -/** - * struct opa_vnic_vema_mad - Generic VEMA MAD - * @mad_hdr: Generic MAD header - * @rmpp_hdr: RMPP header for vendor specific MADs - * @reserved: reserved bytes - * @oui: Unique org identifier - * @data: MAD data - */ -struct opa_vnic_vema_mad { - struct ib_mad_hdr mad_hdr; - struct ib_rmpp_hdr rmpp_hdr; - u8 reserved; - u8 oui[3]; - u8 data[OPA_VNIC_EMA_DATA]; -}; - -/** - * struct opa_vnic_notice_attr - Generic Notice MAD - * @gen_type: Generic/Specific bit and type of notice - * @oui_1: Vendor ID byte 1 - * @oui_2: Vendor ID byte 2 - * @oui_3: Vendor ID byte 3 - * @trap_num: Trap number - * @toggle_count: Notice toggle bit and count value - * @issuer_lid: Trap issuer's lid - * @reserved: reserved bytes - * @issuer_gid: Issuer GID (only if Report method) - * @raw_data: Trap message body - */ -struct opa_vnic_notice_attr { - u8 gen_type; - u8 oui_1; - u8 oui_2; - u8 oui_3; - __be16 trap_num; - __be16 toggle_count; - __be32 issuer_lid; - __be32 reserved; - u8 issuer_gid[16]; - u8 raw_data[64]; -} __packed; - -/** - * struct opa_vnic_vema_mad_trap - Generic VEMA MAD Trap - * @mad_hdr: Generic MAD header - * @rmpp_hdr: RMPP header for vendor specific MADs - * @reserved: reserved bytes - * @oui: Unique org identifier - * @notice: Notice structure - */ -struct opa_vnic_vema_mad_trap { - struct ib_mad_hdr mad_hdr; - struct ib_rmpp_hdr rmpp_hdr; - u8 reserved; - u8 oui[3]; - struct opa_vnic_notice_attr notice; -}; - -#endif /* _OPA_VNIC_ENCAP_H */ diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c deleted file mode 100644 index 316959940d2f..000000000000 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_ethtool.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright(c) 2017 Intel Corporation. - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * BSD LICENSE - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * This file contains OPA VNIC ethtool functions - */ - -#include <linux/ethtool.h> - -#include "opa_vnic_internal.h" - -enum {NETDEV_STATS, VNIC_STATS}; - -struct vnic_stats { - char stat_string[ETH_GSTRING_LEN]; - struct { - int sizeof_stat; - int stat_offset; - }; -}; - -#define VNIC_STAT(m) { sizeof_field(struct opa_vnic_stats, m), \ - offsetof(struct opa_vnic_stats, m) } - -static struct vnic_stats vnic_gstrings_stats[] = { - /* NETDEV stats */ - {"rx_packets", VNIC_STAT(netstats.rx_packets)}, - {"tx_packets", VNIC_STAT(netstats.tx_packets)}, - {"rx_bytes", VNIC_STAT(netstats.rx_bytes)}, - {"tx_bytes", VNIC_STAT(netstats.tx_bytes)}, - {"rx_errors", VNIC_STAT(netstats.rx_errors)}, - {"tx_errors", VNIC_STAT(netstats.tx_errors)}, - {"rx_dropped", VNIC_STAT(netstats.rx_dropped)}, - {"tx_dropped", VNIC_STAT(netstats.tx_dropped)}, - - /* SUMMARY counters */ - {"tx_unicast", VNIC_STAT(tx_grp.unicast)}, - {"tx_mcastbcast", VNIC_STAT(tx_grp.mcastbcast)}, - {"tx_untagged", VNIC_STAT(tx_grp.untagged)}, - {"tx_vlan", VNIC_STAT(tx_grp.vlan)}, - - {"tx_64_size", VNIC_STAT(tx_grp.s_64)}, - {"tx_65_127", VNIC_STAT(tx_grp.s_65_127)}, - {"tx_128_255", VNIC_STAT(tx_grp.s_128_255)}, - {"tx_256_511", VNIC_STAT(tx_grp.s_256_511)}, - {"tx_512_1023", VNIC_STAT(tx_grp.s_512_1023)}, - {"tx_1024_1518", VNIC_STAT(tx_grp.s_1024_1518)}, - {"tx_1519_max", VNIC_STAT(tx_grp.s_1519_max)}, - - {"rx_unicast", VNIC_STAT(rx_grp.unicast)}, - {"rx_mcastbcast", VNIC_STAT(rx_grp.mcastbcast)}, - {"rx_untagged", VNIC_STAT(rx_grp.untagged)}, - {"rx_vlan", VNIC_STAT(rx_grp.vlan)}, - - {"rx_64_size", VNIC_STAT(rx_grp.s_64)}, - {"rx_65_127", VNIC_STAT(rx_grp.s_65_127)}, - {"rx_128_255", VNIC_STAT(rx_grp.s_128_255)}, - {"rx_256_511", VNIC_STAT(rx_grp.s_256_511)}, - {"rx_512_1023", VNIC_STAT(rx_grp.s_512_1023)}, - {"rx_1024_1518", VNIC_STAT(rx_grp.s_1024_1518)}, - {"rx_1519_max", VNIC_STAT(rx_grp.s_1519_max)}, - - /* ERROR counters */ - {"rx_fifo_errors", VNIC_STAT(netstats.rx_fifo_errors)}, - {"rx_length_errors", VNIC_STAT(netstats.rx_length_errors)}, - - {"tx_fifo_errors", VNIC_STAT(netstats.tx_fifo_errors)}, - {"tx_carrier_errors", VNIC_STAT(netstats.tx_carrier_errors)}, - - {"tx_dlid_zero", VNIC_STAT(tx_dlid_zero)}, - {"tx_drop_state", VNIC_STAT(tx_drop_state)}, - {"rx_drop_state", VNIC_STAT(rx_drop_state)}, - {"rx_oversize", VNIC_STAT(rx_oversize)}, - {"rx_runt", VNIC_STAT(rx_runt)}, -}; - -#define VNIC_STATS_LEN ARRAY_SIZE(vnic_gstrings_stats) - -/* vnic_get_drvinfo - get driver info */ -static void vnic_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *drvinfo) -{ - strscpy(drvinfo->driver, opa_vnic_driver_name, sizeof(drvinfo->driver)); - strscpy(drvinfo->bus_info, dev_name(netdev->dev.parent), - sizeof(drvinfo->bus_info)); -} - -/* vnic_get_sset_count - get string set count */ -static int vnic_get_sset_count(struct net_device *netdev, int sset) -{ - return (sset == ETH_SS_STATS) ? VNIC_STATS_LEN : -EOPNOTSUPP; -} - -/* vnic_get_ethtool_stats - get statistics */ -static void vnic_get_ethtool_stats(struct net_device *netdev, - struct ethtool_stats *stats, u64 *data) -{ - struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev); - struct opa_vnic_stats vstats; - int i; - - memset(&vstats, 0, sizeof(vstats)); - spin_lock(&adapter->stats_lock); - adapter->rn_ops->ndo_get_stats64(netdev, &vstats.netstats); - spin_unlock(&adapter->stats_lock); - for (i = 0; i < VNIC_STATS_LEN; i++) { - char *p = (char *)&vstats + vnic_gstrings_stats[i].stat_offset; - - data[i] = (vnic_gstrings_stats[i].sizeof_stat == - sizeof(u64)) ? *(u64 *)p : *(u32 *)p; - } -} - -/* vnic_get_strings - get strings */ -static void vnic_get_strings(struct net_device *netdev, u32 stringset, u8 *data) -{ - int i; - - if (stringset != ETH_SS_STATS) - return; - - for (i = 0; i < VNIC_STATS_LEN; i++) - ethtool_puts(&data, vnic_gstrings_stats[i].stat_string); -} - -/* ethtool ops */ -static const struct ethtool_ops opa_vnic_ethtool_ops = { - .get_drvinfo = vnic_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_strings = vnic_get_strings, - .get_sset_count = vnic_get_sset_count, - .get_ethtool_stats = vnic_get_ethtool_stats, -}; - -/* opa_vnic_set_ethtool_ops - set ethtool ops */ -void opa_vnic_set_ethtool_ops(struct net_device *netdev) -{ - netdev->ethtool_ops = &opa_vnic_ethtool_ops; -} diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h b/drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h deleted file mode 100644 index dd942dd642bd..000000000000 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_internal.h +++ /dev/null @@ -1,329 +0,0 @@ -#ifndef _OPA_VNIC_INTERNAL_H -#define _OPA_VNIC_INTERNAL_H -/* - * Copyright(c) 2017 Intel Corporation. - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * BSD LICENSE - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * This file contains OPA VNIC driver internal declarations - */ - -#include <linux/bitops.h> -#include <linux/etherdevice.h> -#include <linux/hashtable.h> -#include <linux/sizes.h> -#include <rdma/opa_vnic.h> - -#include "opa_vnic_encap.h" - -#define OPA_VNIC_VLAN_PCP(vlan_tci) \ - (((vlan_tci) & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT) - -/* Flow to default port redirection table size */ -#define OPA_VNIC_FLOW_TBL_SIZE 32 - -/* Invalid port number */ -#define OPA_VNIC_INVALID_PORT 0xff - -struct opa_vnic_adapter; - -/* - * struct __opa_vesw_info - OPA vnic virtual switch info - * - * Same as opa_vesw_info without bitwise attribute. - */ -struct __opa_vesw_info { - u16 fabric_id; - u16 vesw_id; - - u8 rsvd0[6]; - u16 def_port_mask; - - u8 rsvd1[2]; - u16 pkey; - - u8 rsvd2[4]; - u32 u_mcast_dlid; - u32 u_ucast_dlid[OPA_VESW_MAX_NUM_DEF_PORT]; - - u32 rc; - - u8 rsvd3[56]; - u16 eth_mtu; - u8 rsvd4[2]; -} __packed; - -/* - * struct __opa_per_veswport_info - OPA vnic per port info - * - * Same as opa_per_veswport_info without bitwise attribute. - */ -struct __opa_per_veswport_info { - u32 port_num; - - u8 eth_link_status; - u8 rsvd0[3]; - - u8 base_mac_addr[ETH_ALEN]; - u8 config_state; - u8 oper_state; - - u16 max_mac_tbl_ent; - u16 max_smac_ent; - u32 mac_tbl_digest; - u8 rsvd1[4]; - - u32 encap_slid; - - u8 pcp_to_sc_uc[OPA_VNIC_MAX_NUM_PCP]; - u8 pcp_to_vl_uc[OPA_VNIC_MAX_NUM_PCP]; - u8 pcp_to_sc_mc[OPA_VNIC_MAX_NUM_PCP]; - u8 pcp_to_vl_mc[OPA_VNIC_MAX_NUM_PCP]; - - u8 non_vlan_sc_uc; - u8 non_vlan_vl_uc; - u8 non_vlan_sc_mc; - u8 non_vlan_vl_mc; - - u8 rsvd2[48]; - - u16 uc_macs_gen_count; - u16 mc_macs_gen_count; - - u8 rsvd3[8]; -} __packed; - -/* - * struct __opa_veswport_info - OPA vnic port info - * - * Same as opa_veswport_info without bitwise attribute. - */ -struct __opa_veswport_info { - struct __opa_vesw_info vesw; - struct __opa_per_veswport_info vport; -}; - -/* - * struct __opa_veswport_trap - OPA vnic trap info - * - * Same as opa_veswport_trap without bitwise attribute. - */ -struct __opa_veswport_trap { - u16 fabric_id; - u16 veswid; - u32 veswportnum; - u16 opaportnum; - u8 veswportindex; - u8 opcode; - u32 reserved; -} __packed; - -/** - * struct opa_vnic_ctrl_port - OPA virtual NIC control port - * @ibdev: pointer to ib device - * @ops: opa vnic control operations - * @num_ports: number of opa ports - */ -struct opa_vnic_ctrl_port { - struct ib_device *ibdev; - struct opa_vnic_ctrl_ops *ops; - u8 num_ports; -}; - -/** - * struct opa_vnic_adapter - OPA VNIC netdev private data structure - * @netdev: pointer to associated netdev - * @ibdev: ib device - * @cport: pointer to opa vnic control port - * @rn_ops: rdma netdev's net_device_ops - * @port_num: OPA port number - * @vport_num: vesw port number - * @lock: adapter lock - * @info: virtual ethernet switch port information - * @vema_mac_addr: mac address configured by vema - * @umac_hash: unicast maclist hash - * @mmac_hash: multicast maclist hash - * @mactbl: hash table of MAC entries - * @mactbl_lock: mac table lock - * @stats_lock: statistics lock - * @flow_tbl: flow to default port redirection table - * @trap_timeout: trap timeout - * @trap_count: no. of traps allowed within timeout period - */ -struct opa_vnic_adapter { - struct net_device *netdev; - struct ib_device *ibdev; - struct opa_vnic_ctrl_port *cport; - const struct net_device_ops *rn_ops; - - u8 port_num; - u8 vport_num; - - /* Lock used around concurrent updates to netdev */ - struct mutex lock; - - struct __opa_veswport_info info; - u8 vema_mac_addr[ETH_ALEN]; - u32 umac_hash; - u32 mmac_hash; - struct hlist_head __rcu *mactbl; - - /* Lock used to protect updates to mac table */ - struct mutex mactbl_lock; - - /* Lock used to protect access to vnic counters */ - spinlock_t stats_lock; - - u8 flow_tbl[OPA_VNIC_FLOW_TBL_SIZE]; - - unsigned long trap_timeout; - u8 trap_count; -}; - -/* Same as opa_veswport_mactable_entry, but without bitwise attribute */ -struct __opa_vnic_mactable_entry { - u8 mac_addr[ETH_ALEN]; - u8 mac_addr_mask[ETH_ALEN]; - u32 dlid_sd; -} __packed; - -/** - * struct opa_vnic_mac_tbl_node - OPA VNIC mac table node - * @hlist: hash list handle - * @index: index of entry in the mac table - * @entry: entry in the table - */ -struct opa_vnic_mac_tbl_node { - struct hlist_node hlist; - u16 index; - struct __opa_vnic_mactable_entry entry; -}; - -#define v_dbg(format, arg...) \ - netdev_dbg(adapter->netdev, format, ## arg) -#define v_err(format, arg...) \ - netdev_err(adapter->netdev, format, ## arg) -#define v_info(format, arg...) \ - netdev_info(adapter->netdev, format, ## arg) -#define v_warn(format, arg...) \ - netdev_warn(adapter->netdev, format, ## arg) - -#define c_err(format, arg...) \ - dev_err(&cport->ibdev->dev, format, ## arg) -#define c_info(format, arg...) \ - dev_info(&cport->ibdev->dev, format, ## arg) -#define c_dbg(format, arg...) \ - dev_dbg(&cport->ibdev->dev, format, ## arg) - -/* The maximum allowed entries in the mac table */ -#define OPA_VNIC_MAC_TBL_MAX_ENTRIES 2048 -/* Limit of smac entries in mac table */ -#define OPA_VNIC_MAX_SMAC_LIMIT 256 - -/* The last octet of the MAC address is used as the key to the hash table */ -#define OPA_VNIC_MAC_HASH_IDX 5 - -/* The VNIC MAC hash table is of size 2^8 */ -#define OPA_VNIC_MAC_TBL_HASH_BITS 8 -#define OPA_VNIC_MAC_TBL_SIZE BIT(OPA_VNIC_MAC_TBL_HASH_BITS) - -/* VNIC HASH MACROS */ -#define vnic_hash_init(hashtable) __hash_init(hashtable, OPA_VNIC_MAC_TBL_SIZE) - -#define vnic_hash_add(hashtable, node, key) \ - hlist_add_head(node, \ - &hashtable[hash_min(key, ilog2(OPA_VNIC_MAC_TBL_SIZE))]) - -#define vnic_hash_for_each_safe(name, bkt, tmp, obj, member) \ - for ((bkt) = 0, obj = NULL; \ - !obj && (bkt) < OPA_VNIC_MAC_TBL_SIZE; (bkt)++) \ - hlist_for_each_entry_safe(obj, tmp, &name[bkt], member) - -#define vnic_hash_for_each_possible(name, obj, member, key) \ - hlist_for_each_entry(obj, \ - &name[hash_min(key, ilog2(OPA_VNIC_MAC_TBL_SIZE))], member) - -#define vnic_hash_for_each(name, bkt, obj, member) \ - for ((bkt) = 0, obj = NULL; \ - !obj && (bkt) < OPA_VNIC_MAC_TBL_SIZE; (bkt)++) \ - hlist_for_each_entry(obj, &name[bkt], member) - -extern char opa_vnic_driver_name[]; - -struct opa_vnic_adapter *opa_vnic_add_netdev(struct ib_device *ibdev, - u8 port_num, u8 vport_num); -void opa_vnic_rem_netdev(struct opa_vnic_adapter *adapter); -void opa_vnic_encap_skb(struct opa_vnic_adapter *adapter, struct sk_buff *skb); -u8 opa_vnic_get_vl(struct opa_vnic_adapter *adapter, struct sk_buff *skb); -u8 opa_vnic_calc_entropy(struct sk_buff *skb); -void opa_vnic_process_vema_config(struct opa_vnic_adapter *adapter); -void opa_vnic_release_mac_tbl(struct opa_vnic_adapter *adapter); -void opa_vnic_query_mac_tbl(struct opa_vnic_adapter *adapter, - struct opa_veswport_mactable *tbl); -int opa_vnic_update_mac_tbl(struct opa_vnic_adapter *adapter, - struct opa_veswport_mactable *tbl); -void opa_vnic_query_ucast_macs(struct opa_vnic_adapter *adapter, - struct opa_veswport_iface_macs *macs); -void opa_vnic_query_mcast_macs(struct opa_vnic_adapter *adapter, - struct opa_veswport_iface_macs *macs); -void opa_vnic_get_summary_counters(struct opa_vnic_adapter *adapter, - struct opa_veswport_summary_counters *cntrs); -void opa_vnic_get_error_counters(struct opa_vnic_adapter *adapter, - struct opa_veswport_error_counters *cntrs); -void opa_vnic_get_vesw_info(struct opa_vnic_adapter *adapter, - struct opa_vesw_info *info); -void opa_vnic_set_vesw_info(struct opa_vnic_adapter *adapter, - struct opa_vesw_info *info); -void opa_vnic_get_per_veswport_info(struct opa_vnic_adapter *adapter, - struct opa_per_veswport_info *info); -void opa_vnic_set_per_veswport_info(struct opa_vnic_adapter *adapter, - struct opa_per_veswport_info *info); -void opa_vnic_vema_report_event(struct opa_vnic_adapter *adapter, u8 event); -void opa_vnic_set_ethtool_ops(struct net_device *netdev); -void opa_vnic_vema_send_trap(struct opa_vnic_adapter *adapter, - struct __opa_veswport_trap *data, u32 lid); - -#endif /* _OPA_VNIC_INTERNAL_H */ diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c deleted file mode 100644 index 1c3e7251f0f4..000000000000 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_netdev.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright(c) 2017 Intel Corporation. - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * BSD LICENSE - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * This file contains OPA Virtual Network Interface Controller (VNIC) driver - * netdev functionality. - */ - -#include <linux/if_vlan.h> -#include <linux/crc32.h> - -#include "opa_vnic_internal.h" - -#define OPA_TX_TIMEOUT_MS 1000 - -#define OPA_VNIC_SKB_HEADROOM \ - ALIGN((OPA_VNIC_HDR_LEN + OPA_VNIC_SKB_MDATA_LEN), 8) - -/* This function is overloaded for opa_vnic specific implementation */ -static void opa_vnic_get_stats64(struct net_device *netdev, - struct rtnl_link_stats64 *stats) -{ - struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev); - struct opa_vnic_stats vstats; - - memset(&vstats, 0, sizeof(vstats)); - spin_lock(&adapter->stats_lock); - adapter->rn_ops->ndo_get_stats64(netdev, &vstats.netstats); - spin_unlock(&adapter->stats_lock); - memcpy(stats, &vstats.netstats, sizeof(*stats)); -} - -/* opa_netdev_start_xmit - transmit function */ -static netdev_tx_t opa_netdev_start_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev); - - v_dbg("xmit: queue %d skb len %d\n", skb->queue_mapping, skb->len); - /* pad to ensure mininum ethernet packet length */ - if (unlikely(skb->len < ETH_ZLEN)) { - if (skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - - skb_put(skb, ETH_ZLEN - skb->len); - } - - opa_vnic_encap_skb(adapter, skb); - return adapter->rn_ops->ndo_start_xmit(skb, netdev); -} - -static u16 opa_vnic_select_queue(struct net_device *netdev, struct sk_buff *skb, - struct net_device *sb_dev) -{ - struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev); - struct opa_vnic_skb_mdata *mdata; - int rc; - - /* pass entropy and vl as metadata in skb */ - mdata = skb_push(skb, sizeof(*mdata)); - mdata->entropy = opa_vnic_calc_entropy(skb); - mdata->vl = opa_vnic_get_vl(adapter, skb); - rc = adapter->rn_ops->ndo_select_queue(netdev, skb, sb_dev); - skb_pull(skb, sizeof(*mdata)); - return rc; -} - -static void opa_vnic_update_state(struct opa_vnic_adapter *adapter, bool up) -{ - struct __opa_veswport_info *info = &adapter->info; - - mutex_lock(&adapter->lock); - /* Operational state can only be DROP_ALL or FORWARDING */ - if ((info->vport.config_state == OPA_VNIC_STATE_FORWARDING) && up) { - info->vport.oper_state = OPA_VNIC_STATE_FORWARDING; - info->vport.eth_link_status = OPA_VNIC_ETH_LINK_UP; - } else { - info->vport.oper_state = OPA_VNIC_STATE_DROP_ALL; - info->vport.eth_link_status = OPA_VNIC_ETH_LINK_DOWN; - } - - if (info->vport.config_state == OPA_VNIC_STATE_FORWARDING) - netif_dormant_off(adapter->netdev); - else - netif_dormant_on(adapter->netdev); - mutex_unlock(&adapter->lock); -} - -/* opa_vnic_process_vema_config - process vema configuration updates */ -void opa_vnic_process_vema_config(struct opa_vnic_adapter *adapter) -{ - struct __opa_veswport_info *info = &adapter->info; - struct rdma_netdev *rn = netdev_priv(adapter->netdev); - u8 port_num[OPA_VESW_MAX_NUM_DEF_PORT] = { 0 }; - struct net_device *netdev = adapter->netdev; - u8 i, port_count = 0; - u16 port_mask; - - /* If the base_mac_addr is changed, update the interface mac address */ - if (memcmp(info->vport.base_mac_addr, adapter->vema_mac_addr, - ARRAY_SIZE(info->vport.base_mac_addr))) { - struct sockaddr saddr; - - memcpy(saddr.sa_data, info->vport.base_mac_addr, - ARRAY_SIZE(info->vport.base_mac_addr)); - mutex_lock(&adapter->lock); - eth_commit_mac_addr_change(netdev, &saddr); - memcpy(adapter->vema_mac_addr, - info->vport.base_mac_addr, ETH_ALEN); - mutex_unlock(&adapter->lock); - } - - rn->set_id(netdev, info->vesw.vesw_id); - - /* Handle MTU limit change */ - rtnl_lock(); - netdev->max_mtu = max_t(unsigned int, info->vesw.eth_mtu, - netdev->min_mtu); - if (netdev->mtu > netdev->max_mtu) - dev_set_mtu(netdev, netdev->max_mtu); - rtnl_unlock(); - - /* Update flow to default port redirection table */ - port_mask = info->vesw.def_port_mask; - for (i = 0; i < OPA_VESW_MAX_NUM_DEF_PORT; i++) { - if (port_mask & 1) - port_num[port_count++] = i; - port_mask >>= 1; - } - - /* - * Build the flow table. Flow table is required when destination LID - * is not available. Up to OPA_VNIC_FLOW_TBL_SIZE flows supported. - * Each flow need a default port number to get its dlid from the - * u_ucast_dlid array. - */ - for (i = 0; i < OPA_VNIC_FLOW_TBL_SIZE; i++) - adapter->flow_tbl[i] = port_count ? port_num[i % port_count] : - OPA_VNIC_INVALID_PORT; - - /* update state */ - opa_vnic_update_state(adapter, !!(netdev->flags & IFF_UP)); -} - -/* - * Set the power on default values in adapter's vema interface structure. - */ -static inline void opa_vnic_set_pod_values(struct opa_vnic_adapter *adapter) -{ - adapter->info.vport.max_mac_tbl_ent = OPA_VNIC_MAC_TBL_MAX_ENTRIES; - adapter->info.vport.max_smac_ent = OPA_VNIC_MAX_SMAC_LIMIT; - adapter->info.vport.config_state = OPA_VNIC_STATE_DROP_ALL; - adapter->info.vport.eth_link_status = OPA_VNIC_ETH_LINK_DOWN; - adapter->info.vesw.eth_mtu = ETH_DATA_LEN; -} - -/* opa_vnic_set_mac_addr - change mac address */ -static int opa_vnic_set_mac_addr(struct net_device *netdev, void *addr) -{ - struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev); - struct sockaddr *sa = addr; - int rc; - - if (!memcmp(netdev->dev_addr, sa->sa_data, ETH_ALEN)) - return 0; - - mutex_lock(&adapter->lock); - rc = eth_mac_addr(netdev, addr); - mutex_unlock(&adapter->lock); - if (rc) - return rc; - - adapter->info.vport.uc_macs_gen_count++; - opa_vnic_vema_report_event(adapter, - OPA_VESWPORT_TRAP_IFACE_UCAST_MAC_CHANGE); - return 0; -} - -/* - * opa_vnic_mac_send_event - post event on possible mac list exchange - * Send trap when digest from uc/mc mac list differs from previous run. - * Digest is evaluated similar to how cksum does. - */ -static void opa_vnic_mac_send_event(struct net_device *netdev, u8 event) -{ - struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev); - struct netdev_hw_addr *ha; - struct netdev_hw_addr_list *hw_list; - u32 *ref_crc; - u32 l, crc = 0; - - switch (event) { - case OPA_VESWPORT_TRAP_IFACE_UCAST_MAC_CHANGE: - hw_list = &netdev->uc; - adapter->info.vport.uc_macs_gen_count++; - ref_crc = &adapter->umac_hash; - break; - case OPA_VESWPORT_TRAP_IFACE_MCAST_MAC_CHANGE: - hw_list = &netdev->mc; - adapter->info.vport.mc_macs_gen_count++; - ref_crc = &adapter->mmac_hash; - break; - default: - return; - } - netdev_hw_addr_list_for_each(ha, hw_list) { - crc = crc32_le(crc, ha->addr, ETH_ALEN); - } - l = netdev_hw_addr_list_count(hw_list) * ETH_ALEN; - crc = ~crc32_le(crc, (void *)&l, sizeof(l)); - - if (crc != *ref_crc) { - *ref_crc = crc; - opa_vnic_vema_report_event(adapter, event); - } -} - -/* opa_vnic_set_rx_mode - handle uc/mc mac list change */ -static void opa_vnic_set_rx_mode(struct net_device *netdev) -{ - opa_vnic_mac_send_event(netdev, - OPA_VESWPORT_TRAP_IFACE_UCAST_MAC_CHANGE); - - opa_vnic_mac_send_event(netdev, - OPA_VESWPORT_TRAP_IFACE_MCAST_MAC_CHANGE); -} - -/* opa_netdev_open - activate network interface */ -static int opa_netdev_open(struct net_device *netdev) -{ - struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev); - int rc; - - rc = adapter->rn_ops->ndo_open(adapter->netdev); - if (rc) { - v_dbg("open failed %d\n", rc); - return rc; - } - - /* Update status and send trap */ - opa_vnic_update_state(adapter, true); - opa_vnic_vema_report_event(adapter, - OPA_VESWPORT_TRAP_ETH_LINK_STATUS_CHANGE); - return 0; -} - -/* opa_netdev_close - disable network interface */ -static int opa_netdev_close(struct net_device *netdev) -{ - struct opa_vnic_adapter *adapter = opa_vnic_priv(netdev); - int rc; - - rc = adapter->rn_ops->ndo_stop(adapter->netdev); - if (rc) { - v_dbg("close failed %d\n", rc); - return rc; - } - - /* Update status and send trap */ - opa_vnic_update_state(adapter, false); - opa_vnic_vema_report_event(adapter, - OPA_VESWPORT_TRAP_ETH_LINK_STATUS_CHANGE); - return 0; -} - -/* netdev ops */ -static const struct net_device_ops opa_netdev_ops = { - .ndo_open = opa_netdev_open, - .ndo_stop = opa_netdev_close, - .ndo_start_xmit = opa_netdev_start_xmit, - .ndo_get_stats64 = opa_vnic_get_stats64, - .ndo_set_rx_mode = opa_vnic_set_rx_mode, - .ndo_select_queue = opa_vnic_select_queue, - .ndo_set_mac_address = opa_vnic_set_mac_addr, -}; - -/* opa_vnic_add_netdev - create vnic netdev interface */ -struct opa_vnic_adapter *opa_vnic_add_netdev(struct ib_device *ibdev, - u8 port_num, u8 vport_num) -{ - struct opa_vnic_adapter *adapter; - struct net_device *netdev; - struct rdma_netdev *rn; - int rc; - - netdev = ibdev->ops.alloc_rdma_netdev(ibdev, port_num, - RDMA_NETDEV_OPA_VNIC, - "veth%d", NET_NAME_UNKNOWN, - ether_setup); - if (!netdev) - return ERR_PTR(-ENOMEM); - else if (IS_ERR(netdev)) - return ERR_CAST(netdev); - - rn = netdev_priv(netdev); - adapter = kzalloc_obj(*adapter); - if (!adapter) { - rc = -ENOMEM; - goto adapter_err; - } - - rn->clnt_priv = adapter; - rn->hca = ibdev; - rn->port_num = port_num; - adapter->netdev = netdev; - adapter->ibdev = ibdev; - adapter->port_num = port_num; - adapter->vport_num = vport_num; - adapter->rn_ops = netdev->netdev_ops; - - netdev->netdev_ops = &opa_netdev_ops; - netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; - netdev->hard_header_len += OPA_VNIC_SKB_HEADROOM; - mutex_init(&adapter->lock); - mutex_init(&adapter->mactbl_lock); - spin_lock_init(&adapter->stats_lock); - - SET_NETDEV_DEV(netdev, ibdev->dev.parent); - - opa_vnic_set_ethtool_ops(netdev); - - opa_vnic_set_pod_values(adapter); - - rc = register_netdev(netdev); - if (rc) - goto netdev_err; - - netif_carrier_off(netdev); - netif_dormant_on(netdev); - v_info("initialized\n"); - - return adapter; -netdev_err: - mutex_destroy(&adapter->lock); - mutex_destroy(&adapter->mactbl_lock); - kfree(adapter); -adapter_err: - rn->free_rdma_netdev(netdev); - - return ERR_PTR(rc); -} - -/* opa_vnic_rem_netdev - remove vnic netdev interface */ -void opa_vnic_rem_netdev(struct opa_vnic_adapter *adapter) -{ - struct net_device *netdev = adapter->netdev; - struct rdma_netdev *rn = netdev_priv(netdev); - - v_info("removing\n"); - unregister_netdev(netdev); - opa_vnic_release_mac_tbl(adapter); - mutex_destroy(&adapter->lock); - mutex_destroy(&adapter->mactbl_lock); - kfree(adapter); - rn->free_rdma_netdev(netdev); -} diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c deleted file mode 100644 index 21c6cea8b1db..000000000000 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema.c +++ /dev/null @@ -1,1056 +0,0 @@ -/* - * Copyright(c) 2017 Intel Corporation. - * Copyright(c) 2021 Cornelis Networks. - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * BSD LICENSE - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * This file contains OPX Virtual Network Interface Controller (VNIC) - * Ethernet Management Agent (EMA) driver - */ - -#include <linux/module.h> -#include <linux/xarray.h> -#include <rdma/ib_addr.h> -#include <rdma/ib_verbs.h> -#include <rdma/opa_smi.h> -#include <rdma/opa_port_info.h> - -#include "opa_vnic_internal.h" - -char opa_vnic_driver_name[] = "opa_vnic"; - -/* - * The trap service level is kept in bits 3 to 7 in the trap_sl_rsvd - * field in the class port info MAD. - */ -#define GET_TRAP_SL_FROM_CLASS_PORT_INFO(x) (((x) >> 3) & 0x1f) - -/* Cap trap bursts to a reasonable limit good for normal cases */ -#define OPA_VNIC_TRAP_BURST_LIMIT 4 - -/* - * VNIC trap limit timeout. - * Inverse of cap2_mask response time out (1.0737 secs) = 0.9 - * secs approx IB spec 13.4.6.2.1 PortInfoSubnetTimeout and - * 13.4.9 Traps. - */ -#define OPA_VNIC_TRAP_TIMEOUT ((4096 * (1UL << 18)) / 1000) - -#define OPA_VNIC_UNSUP_ATTR \ - cpu_to_be16(IB_MGMT_MAD_STATUS_UNSUPPORTED_METHOD_ATTRIB) - -#define OPA_VNIC_INVAL_ATTR \ - cpu_to_be16(IB_MGMT_MAD_STATUS_INVALID_ATTRIB_VALUE) - -#define OPA_VNIC_CLASS_CAP_TRAP 0x1 - -/* Maximum number of VNIC ports supported */ -#define OPA_VNIC_MAX_NUM_VPORT 255 - -/** - * struct opa_vnic_vema_port -- VNIC VEMA port details - * @cport: pointer to port - * @mad_agent: pointer to mad agent for port - * @class_port_info: Class port info information. - * @tid: Transaction id - * @port_num: OPA port number - * @vports: vnic ports - * @event_handler: ib event handler - * @lock: adapter interface lock - */ -struct opa_vnic_vema_port { - struct opa_vnic_ctrl_port *cport; - struct ib_mad_agent *mad_agent; - struct opa_class_port_info class_port_info; - u64 tid; - u8 port_num; - struct xarray vports; - struct ib_event_handler event_handler; - - /* Lock to query/update network adapter */ - struct mutex lock; -}; - -static int opa_vnic_vema_add_one(struct ib_device *device); -static void opa_vnic_vema_rem_one(struct ib_device *device, - void *client_data); - -static struct ib_client opa_vnic_client = { - .name = opa_vnic_driver_name, - .add = opa_vnic_vema_add_one, - .remove = opa_vnic_vema_rem_one, -}; - -/** - * vema_get_vport_num -- Get the vnic from the mad - * @recvd_mad: Received mad - * - * Return: returns value of the vnic port number - */ -static inline u8 vema_get_vport_num(struct opa_vnic_vema_mad *recvd_mad) -{ - return be32_to_cpu(recvd_mad->mad_hdr.attr_mod) & 0xff; -} - -/** - * vema_get_vport_adapter -- Get vnic port adapter from recvd mad - * @recvd_mad: received mad - * @port: ptr to port struct on which MAD was recvd - * - * Return: vnic adapter - */ -static inline struct opa_vnic_adapter * -vema_get_vport_adapter(struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_port *port) -{ - u8 vport_num = vema_get_vport_num(recvd_mad); - - return xa_load(&port->vports, vport_num); -} - -/** - * vema_mac_tbl_req_ok -- Check if mac request has correct values - * @mac_tbl: mac table - * - * This function checks for the validity of the offset and number of - * entries required. - * - * Return: true if offset and num_entries are valid - */ -static inline bool vema_mac_tbl_req_ok(struct opa_veswport_mactable *mac_tbl) -{ - u16 offset, num_entries; - u16 req_entries = ((OPA_VNIC_EMA_DATA - sizeof(*mac_tbl)) / - sizeof(mac_tbl->tbl_entries[0])); - - offset = be16_to_cpu(mac_tbl->offset); - num_entries = be16_to_cpu(mac_tbl->num_entries); - - return ((num_entries <= req_entries) && - (offset + num_entries <= OPA_VNIC_MAC_TBL_MAX_ENTRIES)); -} - -/* - * Return the power on default values in the port info structure - * in big endian format as required by MAD. - */ -static inline void vema_get_pod_values(struct opa_veswport_info *port_info) -{ - memset(port_info, 0, sizeof(*port_info)); - port_info->vport.max_mac_tbl_ent = - cpu_to_be16(OPA_VNIC_MAC_TBL_MAX_ENTRIES); - port_info->vport.max_smac_ent = - cpu_to_be16(OPA_VNIC_MAX_SMAC_LIMIT); - port_info->vport.oper_state = OPA_VNIC_STATE_DROP_ALL; - port_info->vport.config_state = OPA_VNIC_STATE_DROP_ALL; - port_info->vesw.eth_mtu = cpu_to_be16(ETH_DATA_LEN); -} - -/** - * vema_add_vport -- Add a new vnic port - * @port: ptr to opa_vnic_vema_port struct - * @vport_num: vnic port number (to be added) - * - * Return a pointer to the vnic adapter structure - */ -static struct opa_vnic_adapter *vema_add_vport(struct opa_vnic_vema_port *port, - u8 vport_num) -{ - struct opa_vnic_ctrl_port *cport = port->cport; - struct opa_vnic_adapter *adapter; - - adapter = opa_vnic_add_netdev(cport->ibdev, port->port_num, vport_num); - if (!IS_ERR(adapter)) { - int rc; - - adapter->cport = cport; - rc = xa_insert(&port->vports, vport_num, adapter, GFP_KERNEL); - if (rc < 0) { - opa_vnic_rem_netdev(adapter); - adapter = ERR_PTR(rc); - } - } - - return adapter; -} - -/** - * vema_get_class_port_info -- Get class info for port - * @port: Port on whic MAD was received - * @recvd_mad: pointer to the received mad - * @rsp_mad: pointer to respose mad - * - * This function copies the latest class port info value set for the - * port and stores it for generating traps - */ -static void vema_get_class_port_info(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - struct opa_class_port_info *port_info; - - port_info = (struct opa_class_port_info *)rsp_mad->data; - memcpy(port_info, &port->class_port_info, sizeof(*port_info)); - port_info->base_version = OPA_MGMT_BASE_VERSION; - port_info->class_version = OPA_EMA_CLASS_VERSION; - - /* - * Set capability mask bit indicating agent generates traps, - * and set the maximum number of VNIC ports supported. - */ - port_info->cap_mask = cpu_to_be16((OPA_VNIC_CLASS_CAP_TRAP | - (OPA_VNIC_MAX_NUM_VPORT << 8))); - - /* - * Since a get routine is always sent by the EM first we - * set the expected response time to - * 4.096 usec * 2^18 == 1.0737 sec here. - */ - port_info->cap_mask2_resp_time = cpu_to_be32(18); -} - -/** - * vema_set_class_port_info -- Get class info for port - * @port: Port on whic MAD was received - * @recvd_mad: pointer to the received mad - * @rsp_mad: pointer to respose mad - * - * This function updates the port class info for the specific vnic - * and sets up the response mad data - */ -static void vema_set_class_port_info(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - memcpy(&port->class_port_info, recvd_mad->data, - sizeof(port->class_port_info)); - - vema_get_class_port_info(port, recvd_mad, rsp_mad); -} - -/** - * vema_get_veswport_info -- Get veswport info - * @port: source port on which MAD was received - * @recvd_mad: pointer to the received mad - * @rsp_mad: pointer to respose mad - */ -static void vema_get_veswport_info(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - struct opa_veswport_info *port_info = - (struct opa_veswport_info *)rsp_mad->data; - struct opa_vnic_adapter *adapter; - - adapter = vema_get_vport_adapter(recvd_mad, port); - if (adapter) { - memset(port_info, 0, sizeof(*port_info)); - opa_vnic_get_vesw_info(adapter, &port_info->vesw); - opa_vnic_get_per_veswport_info(adapter, - &port_info->vport); - } else { - vema_get_pod_values(port_info); - } -} - -/** - * vema_set_veswport_info -- Set veswport info - * @port: source port on which MAD was received - * @recvd_mad: pointer to the received mad - * @rsp_mad: pointer to respose mad - * - * This function gets the port class infor for vnic - */ -static void vema_set_veswport_info(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - struct opa_vnic_ctrl_port *cport = port->cport; - struct opa_veswport_info *port_info; - struct opa_vnic_adapter *adapter; - u8 vport_num; - - vport_num = vema_get_vport_num(recvd_mad); - - adapter = vema_get_vport_adapter(recvd_mad, port); - if (!adapter) { - adapter = vema_add_vport(port, vport_num); - if (IS_ERR(adapter)) { - c_err("failed to add vport %d: %ld\n", - vport_num, PTR_ERR(adapter)); - goto err_exit; - } - } - - port_info = (struct opa_veswport_info *)recvd_mad->data; - opa_vnic_set_vesw_info(adapter, &port_info->vesw); - opa_vnic_set_per_veswport_info(adapter, &port_info->vport); - - /* Process the new config settings */ - opa_vnic_process_vema_config(adapter); - - vema_get_veswport_info(port, recvd_mad, rsp_mad); - return; - -err_exit: - rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR; -} - -/** - * vema_get_mac_entries -- Get MAC entries in VNIC MAC table - * @port: source port on which MAD was received - * @recvd_mad: pointer to the received mad - * @rsp_mad: pointer to respose mad - * - * This function gets the MAC entries that are programmed into - * the VNIC MAC forwarding table. It checks for the validity of - * the index into the MAC table and the number of entries that - * are to be retrieved. - */ -static void vema_get_mac_entries(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - struct opa_veswport_mactable *mac_tbl_in, *mac_tbl_out; - struct opa_vnic_adapter *adapter; - - adapter = vema_get_vport_adapter(recvd_mad, port); - if (!adapter) { - rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR; - return; - } - - mac_tbl_in = (struct opa_veswport_mactable *)recvd_mad->data; - mac_tbl_out = (struct opa_veswport_mactable *)rsp_mad->data; - - if (vema_mac_tbl_req_ok(mac_tbl_in)) { - mac_tbl_out->offset = mac_tbl_in->offset; - mac_tbl_out->num_entries = mac_tbl_in->num_entries; - opa_vnic_query_mac_tbl(adapter, mac_tbl_out); - } else { - rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR; - } -} - -/** - * vema_set_mac_entries -- Set MAC entries in VNIC MAC table - * @port: source port on which MAD was received - * @recvd_mad: pointer to the received mad - * @rsp_mad: pointer to respose mad - * - * This function sets the MAC entries in the VNIC forwarding table - * It checks for the validity of the index and the number of forwarding - * table entries to be programmed. - */ -static void vema_set_mac_entries(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - struct opa_veswport_mactable *mac_tbl; - struct opa_vnic_adapter *adapter; - - adapter = vema_get_vport_adapter(recvd_mad, port); - if (!adapter) { - rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR; - return; - } - - mac_tbl = (struct opa_veswport_mactable *)recvd_mad->data; - if (vema_mac_tbl_req_ok(mac_tbl)) { - if (opa_vnic_update_mac_tbl(adapter, mac_tbl)) - rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR; - } else { - rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR; - } - vema_get_mac_entries(port, recvd_mad, rsp_mad); -} - -/** - * vema_set_delete_vesw -- Reset VESW info to POD values - * @port: source port on which MAD was received - * @recvd_mad: pointer to the received mad - * @rsp_mad: pointer to respose mad - * - * This function clears all the fields of veswport info for the requested vesw - * and sets them back to the power-on default values. It does not delete the - * vesw. - */ -static void vema_set_delete_vesw(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - struct opa_veswport_info *port_info = - (struct opa_veswport_info *)rsp_mad->data; - struct opa_vnic_adapter *adapter; - - adapter = vema_get_vport_adapter(recvd_mad, port); - if (!adapter) { - rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR; - return; - } - - vema_get_pod_values(port_info); - opa_vnic_set_vesw_info(adapter, &port_info->vesw); - opa_vnic_set_per_veswport_info(adapter, &port_info->vport); - - /* Process the new config settings */ - opa_vnic_process_vema_config(adapter); - - opa_vnic_release_mac_tbl(adapter); - - vema_get_veswport_info(port, recvd_mad, rsp_mad); -} - -/** - * vema_get_mac_list -- Get the unicast/multicast macs. - * @port: source port on which MAD was received - * @recvd_mad: Received mad contains fields to set vnic parameters - * @rsp_mad: Response mad to be built - * @attr_id: Attribute ID indicating multicast or unicast mac list - */ -static void vema_get_mac_list(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad, - u16 attr_id) -{ - struct opa_veswport_iface_macs *macs_in, *macs_out; - int max_entries = (OPA_VNIC_EMA_DATA - sizeof(*macs_out)) / ETH_ALEN; - struct opa_vnic_adapter *adapter; - - adapter = vema_get_vport_adapter(recvd_mad, port); - if (!adapter) { - rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR; - return; - } - - macs_in = (struct opa_veswport_iface_macs *)recvd_mad->data; - macs_out = (struct opa_veswport_iface_macs *)rsp_mad->data; - - macs_out->start_idx = macs_in->start_idx; - if (macs_in->num_macs_in_msg) - macs_out->num_macs_in_msg = macs_in->num_macs_in_msg; - else - macs_out->num_macs_in_msg = cpu_to_be16(max_entries); - - if (attr_id == OPA_EM_ATTR_IFACE_MCAST_MACS) - opa_vnic_query_mcast_macs(adapter, macs_out); - else - opa_vnic_query_ucast_macs(adapter, macs_out); -} - -/** - * vema_get_summary_counters -- Gets summary counters. - * @port: source port on which MAD was received - * @recvd_mad: Received mad contains fields to set vnic parameters - * @rsp_mad: Response mad to be built - */ -static void vema_get_summary_counters(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - struct opa_veswport_summary_counters *cntrs; - struct opa_vnic_adapter *adapter; - - adapter = vema_get_vport_adapter(recvd_mad, port); - if (adapter) { - cntrs = (struct opa_veswport_summary_counters *)rsp_mad->data; - opa_vnic_get_summary_counters(adapter, cntrs); - } else { - rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR; - } -} - -/** - * vema_get_error_counters -- Gets summary counters. - * @port: source port on which MAD was received - * @recvd_mad: Received mad contains fields to set vnic parameters - * @rsp_mad: Response mad to be built - */ -static void vema_get_error_counters(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - struct opa_veswport_error_counters *cntrs; - struct opa_vnic_adapter *adapter; - - adapter = vema_get_vport_adapter(recvd_mad, port); - if (adapter) { - cntrs = (struct opa_veswport_error_counters *)rsp_mad->data; - opa_vnic_get_error_counters(adapter, cntrs); - } else { - rsp_mad->mad_hdr.status = OPA_VNIC_INVAL_ATTR; - } -} - -/** - * vema_get -- Process received get MAD - * @port: source port on which MAD was received - * @recvd_mad: Received mad - * @rsp_mad: Response mad to be built - */ -static void vema_get(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - u16 attr_id = be16_to_cpu(recvd_mad->mad_hdr.attr_id); - - switch (attr_id) { - case OPA_EM_ATTR_CLASS_PORT_INFO: - vema_get_class_port_info(port, recvd_mad, rsp_mad); - break; - case OPA_EM_ATTR_VESWPORT_INFO: - vema_get_veswport_info(port, recvd_mad, rsp_mad); - break; - case OPA_EM_ATTR_VESWPORT_MAC_ENTRIES: - vema_get_mac_entries(port, recvd_mad, rsp_mad); - break; - case OPA_EM_ATTR_IFACE_UCAST_MACS: - case OPA_EM_ATTR_IFACE_MCAST_MACS: - vema_get_mac_list(port, recvd_mad, rsp_mad, attr_id); - break; - case OPA_EM_ATTR_VESWPORT_SUMMARY_COUNTERS: - vema_get_summary_counters(port, recvd_mad, rsp_mad); - break; - case OPA_EM_ATTR_VESWPORT_ERROR_COUNTERS: - vema_get_error_counters(port, recvd_mad, rsp_mad); - break; - default: - rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR; - break; - } -} - -/** - * vema_set -- Process received set MAD - * @port: source port on which MAD was received - * @recvd_mad: Received mad contains fields to set vnic parameters - * @rsp_mad: Response mad to be built - */ -static void vema_set(struct opa_vnic_vema_port *port, - struct opa_vnic_vema_mad *recvd_mad, - struct opa_vnic_vema_mad *rsp_mad) -{ - u16 attr_id = be16_to_cpu(recvd_mad->mad_hdr.attr_id); - - switch (attr_id) { - case OPA_EM_ATTR_CLASS_PORT_INFO: - vema_set_class_port_info(port, recvd_mad, rsp_mad); - break; - case OPA_EM_ATTR_VESWPORT_INFO: - vema_set_veswport_info(port, recvd_mad, rsp_mad); - break; - case OPA_EM_ATTR_VESWPORT_MAC_ENTRIES: - vema_set_mac_entries(port, recvd_mad, rsp_mad); - break; - case OPA_EM_ATTR_DELETE_VESW: - vema_set_delete_vesw(port, recvd_mad, rsp_mad); - break; - default: - rsp_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR; - break; - } -} - -/** - * vema_send -- Send handler for VEMA MAD agent - * @mad_agent: pointer to the mad agent - * @mad_wc: pointer to mad send work completion information - * - * Free all the data structures associated with the sent MAD - */ -static void vema_send(struct ib_mad_agent *mad_agent, - struct ib_mad_send_wc *mad_wc) -{ - rdma_destroy_ah(mad_wc->send_buf->ah, RDMA_DESTROY_AH_SLEEPABLE); - ib_free_send_mad(mad_wc->send_buf); -} - -/** - * vema_recv -- Recv handler for VEMA MAD agent - * @mad_agent: pointer to the mad agent - * @send_buf: Send buffer if found, else NULL - * @mad_wc: pointer to mad send work completion information - * - * Handle only set and get methods and respond to other methods - * as unsupported. Allocate response buffer and address handle - * for the response MAD. - */ -static void vema_recv(struct ib_mad_agent *mad_agent, - struct ib_mad_send_buf *send_buf, - struct ib_mad_recv_wc *mad_wc) -{ - struct opa_vnic_vema_port *port; - struct ib_ah *ah; - struct ib_mad_send_buf *rsp; - struct opa_vnic_vema_mad *vema_mad; - - if (!mad_wc || !mad_wc->recv_buf.mad) - return; - - port = mad_agent->context; - ah = ib_create_ah_from_wc(mad_agent->qp->pd, mad_wc->wc, - mad_wc->recv_buf.grh, mad_agent->port_num); - if (IS_ERR(ah)) - goto free_recv_mad; - - rsp = ib_create_send_mad(mad_agent, mad_wc->wc->src_qp, - mad_wc->wc->pkey_index, 0, - IB_MGMT_VENDOR_HDR, OPA_VNIC_EMA_DATA, - GFP_KERNEL, OPA_MGMT_BASE_VERSION); - if (IS_ERR(rsp)) - goto err_rsp; - - rsp->ah = ah; - vema_mad = rsp->mad; - memcpy(vema_mad, mad_wc->recv_buf.mad, IB_MGMT_VENDOR_HDR); - vema_mad->mad_hdr.method = IB_MGMT_METHOD_GET_RESP; - vema_mad->mad_hdr.status = 0; - - /* Lock ensures network adapter is not removed */ - mutex_lock(&port->lock); - - switch (mad_wc->recv_buf.mad->mad_hdr.method) { - case IB_MGMT_METHOD_GET: - vema_get(port, (struct opa_vnic_vema_mad *)mad_wc->recv_buf.mad, - vema_mad); - break; - case IB_MGMT_METHOD_SET: - vema_set(port, (struct opa_vnic_vema_mad *)mad_wc->recv_buf.mad, - vema_mad); - break; - default: - vema_mad->mad_hdr.status = OPA_VNIC_UNSUP_ATTR; - break; - } - mutex_unlock(&port->lock); - - if (!ib_post_send_mad(rsp, NULL)) { - /* - * with post send successful ah and send mad - * will be destroyed in send handler - */ - goto free_recv_mad; - } - - ib_free_send_mad(rsp); - -err_rsp: - rdma_destroy_ah(ah, RDMA_DESTROY_AH_SLEEPABLE); -free_recv_mad: - ib_free_recv_mad(mad_wc); -} - -/** - * vema_get_port -- Gets the opa_vnic_vema_port - * @cport: pointer to control dev - * @port_num: Port number - * - * This function loops through the ports and returns - * the opa_vnic_vema port structure that is associated - * with the OPA port number - * - * Return: ptr to requested opa_vnic_vema_port strucure - * if success, NULL if not - */ -static struct opa_vnic_vema_port * -vema_get_port(struct opa_vnic_ctrl_port *cport, u8 port_num) -{ - struct opa_vnic_vema_port *port = (void *)cport + sizeof(*cport); - - if (port_num > cport->num_ports) - return NULL; - - return port + (port_num - 1); -} - -/** - * opa_vnic_vema_send_trap -- This function sends a trap to the EM - * @adapter: pointer to vnic adapter - * @data: pointer to trap data filled by calling function - * @lid: issuers lid (encap_slid from vesw_port_info) - * - * This function is called from the VNIC driver to send a trap if there - * is somethng the EM should be notified about. These events currently - * are - * 1) UNICAST INTERFACE MACADDRESS changes - * 2) MULTICAST INTERFACE MACADDRESS changes - * 3) ETHERNET LINK STATUS changes - * While allocating the send mad the remote site qpn used is 1 - * as this is the well known QP. - * - */ -void opa_vnic_vema_send_trap(struct opa_vnic_adapter *adapter, - struct __opa_veswport_trap *data, u32 lid) -{ - struct opa_vnic_ctrl_port *cport = adapter->cport; - struct ib_mad_send_buf *send_buf; - struct opa_vnic_vema_port *port; - struct ib_device *ibp; - struct opa_vnic_vema_mad_trap *trap_mad; - struct opa_class_port_info *class; - struct rdma_ah_attr ah_attr; - struct ib_ah *ah; - struct opa_veswport_trap *trap; - u32 trap_lid; - u16 pkey_idx; - - if (!cport) - goto err_exit; - ibp = cport->ibdev; - port = vema_get_port(cport, data->opaportnum); - if (!port || !port->mad_agent) - goto err_exit; - - if (time_before(jiffies, adapter->trap_timeout)) { - if (adapter->trap_count == OPA_VNIC_TRAP_BURST_LIMIT) { - v_warn("Trap rate exceeded\n"); - goto err_exit; - } else { - adapter->trap_count++; - } - } else { - adapter->trap_count = 0; - } - - class = &port->class_port_info; - /* Set up address handle */ - memset(&ah_attr, 0, sizeof(ah_attr)); - ah_attr.type = rdma_ah_find_type(ibp, port->port_num); - rdma_ah_set_sl(&ah_attr, - GET_TRAP_SL_FROM_CLASS_PORT_INFO(class->trap_sl_rsvd)); - rdma_ah_set_port_num(&ah_attr, port->port_num); - trap_lid = be32_to_cpu(class->trap_lid); - /* - * check for trap lid validity, must not be zero - * The trap sink could change after we fashion the MAD but since traps - * are not guaranteed we won't use a lock as anyway the change will take - * place even with locking. - */ - if (!trap_lid) { - c_err("%s: Invalid dlid\n", __func__); - goto err_exit; - } - - rdma_ah_set_dlid(&ah_attr, trap_lid); - ah = rdma_create_ah(port->mad_agent->qp->pd, &ah_attr, 0); - if (IS_ERR(ah)) { - c_err("%s:Couldn't create new AH = %p\n", __func__, ah); - c_err("%s:dlid = %d, sl = %d, port = %d\n", __func__, - rdma_ah_get_dlid(&ah_attr), rdma_ah_get_sl(&ah_attr), - rdma_ah_get_port_num(&ah_attr)); - goto err_exit; - } - - if (ib_find_pkey(ibp, data->opaportnum, IB_DEFAULT_PKEY_FULL, - &pkey_idx) < 0) { - c_err("%s:full key not found, defaulting to partial\n", - __func__); - if (ib_find_pkey(ibp, data->opaportnum, IB_DEFAULT_PKEY_PARTIAL, - &pkey_idx) < 0) - pkey_idx = 1; - } - - send_buf = ib_create_send_mad(port->mad_agent, 1, pkey_idx, 0, - IB_MGMT_VENDOR_HDR, IB_MGMT_MAD_DATA, - GFP_ATOMIC, OPA_MGMT_BASE_VERSION); - if (IS_ERR(send_buf)) { - c_err("%s:Couldn't allocate send buf\n", __func__); - goto err_sndbuf; - } - - send_buf->ah = ah; - - /* Set up common MAD hdr */ - trap_mad = send_buf->mad; - trap_mad->mad_hdr.base_version = OPA_MGMT_BASE_VERSION; - trap_mad->mad_hdr.mgmt_class = OPA_MGMT_CLASS_INTEL_EMA; - trap_mad->mad_hdr.class_version = OPA_EMA_CLASS_VERSION; - trap_mad->mad_hdr.method = IB_MGMT_METHOD_TRAP; - port->tid++; - trap_mad->mad_hdr.tid = cpu_to_be64(port->tid); - trap_mad->mad_hdr.attr_id = IB_SMP_ATTR_NOTICE; - - /* Set up vendor OUI */ - trap_mad->oui[0] = INTEL_OUI_1; - trap_mad->oui[1] = INTEL_OUI_2; - trap_mad->oui[2] = INTEL_OUI_3; - - /* Setup notice attribute portion */ - trap_mad->notice.gen_type = OPA_INTEL_EMA_NOTICE_TYPE_INFO << 1; - trap_mad->notice.oui_1 = INTEL_OUI_1; - trap_mad->notice.oui_2 = INTEL_OUI_2; - trap_mad->notice.oui_3 = INTEL_OUI_3; - trap_mad->notice.issuer_lid = cpu_to_be32(lid); - - /* copy the actual trap data */ - trap = (struct opa_veswport_trap *)trap_mad->notice.raw_data; - trap->fabric_id = cpu_to_be16(data->fabric_id); - trap->veswid = cpu_to_be16(data->veswid); - trap->veswportnum = cpu_to_be32(data->veswportnum); - trap->opaportnum = cpu_to_be16(data->opaportnum); - trap->veswportindex = data->veswportindex; - trap->opcode = data->opcode; - - /* If successful send set up rate limit timeout else bail */ - if (ib_post_send_mad(send_buf, NULL)) { - ib_free_send_mad(send_buf); - } else { - if (adapter->trap_count) - return; - adapter->trap_timeout = jiffies + - usecs_to_jiffies(OPA_VNIC_TRAP_TIMEOUT); - return; - } - -err_sndbuf: - rdma_destroy_ah(ah, 0); -err_exit: - v_err("Aborting trap\n"); -} - -static void opa_vnic_event(struct ib_event_handler *handler, - struct ib_event *record) -{ - struct opa_vnic_vema_port *port = - container_of(handler, struct opa_vnic_vema_port, event_handler); - struct opa_vnic_ctrl_port *cport = port->cport; - struct opa_vnic_adapter *adapter; - unsigned long index; - - if (record->element.port_num != port->port_num) - return; - - c_dbg("OPA_VNIC received event %d on device %s port %d\n", - record->event, dev_name(&record->device->dev), - record->element.port_num); - - if (record->event != IB_EVENT_PORT_ERR && - record->event != IB_EVENT_PORT_ACTIVE) - return; - - xa_for_each(&port->vports, index, adapter) { - if (record->event == IB_EVENT_PORT_ACTIVE) - netif_carrier_on(adapter->netdev); - else - netif_carrier_off(adapter->netdev); - } -} - -/** - * vema_unregister -- Unregisters agent - * @cport: pointer to control port - * - * This deletes the registration by VEMA for MADs - */ -static void vema_unregister(struct opa_vnic_ctrl_port *cport) -{ - struct opa_vnic_adapter *adapter; - unsigned long index; - int i; - - for (i = 1; i <= cport->num_ports; i++) { - struct opa_vnic_vema_port *port = vema_get_port(cport, i); - - if (!port->mad_agent) - continue; - - /* Lock ensures no MAD is being processed */ - mutex_lock(&port->lock); - xa_for_each(&port->vports, index, adapter) - opa_vnic_rem_netdev(adapter); - mutex_unlock(&port->lock); - - ib_unregister_mad_agent(port->mad_agent); - port->mad_agent = NULL; - mutex_destroy(&port->lock); - xa_destroy(&port->vports); - ib_unregister_event_handler(&port->event_handler); - } -} - -/** - * vema_register -- Registers agent - * @cport: pointer to control port - * - * This function registers the handlers for the VEMA MADs - * - * Return: returns 0 on success. non zero otherwise - */ -static int vema_register(struct opa_vnic_ctrl_port *cport) -{ - struct ib_mad_reg_req reg_req = { - .mgmt_class = OPA_MGMT_CLASS_INTEL_EMA, - .mgmt_class_version = OPA_MGMT_BASE_VERSION, - .oui = { INTEL_OUI_1, INTEL_OUI_2, INTEL_OUI_3 } - }; - int i; - - set_bit(IB_MGMT_METHOD_GET, reg_req.method_mask); - set_bit(IB_MGMT_METHOD_SET, reg_req.method_mask); - - /* register ib event handler and mad agent for each port on dev */ - for (i = 1; i <= cport->num_ports; i++) { - struct opa_vnic_vema_port *port = vema_get_port(cport, i); - int ret; - - port->cport = cport; - port->port_num = i; - - INIT_IB_EVENT_HANDLER(&port->event_handler, - cport->ibdev, opa_vnic_event); - ib_register_event_handler(&port->event_handler); - - xa_init(&port->vports); - mutex_init(&port->lock); - port->mad_agent = ib_register_mad_agent(cport->ibdev, i, - IB_QPT_GSI, ®_req, - IB_MGMT_RMPP_VERSION, - vema_send, vema_recv, - port, 0); - if (IS_ERR(port->mad_agent)) { - ret = PTR_ERR(port->mad_agent); - port->mad_agent = NULL; - mutex_destroy(&port->lock); - vema_unregister(cport); - return ret; - } - } - - return 0; -} - -/** - * opa_vnic_ctrl_config_dev -- This function sends a trap to the EM - * by way of ib_modify_port to indicate support for ethernet on the - * fabric. - * @cport: pointer to control port - * @en: enable or disable ethernet on fabric support - */ -static void opa_vnic_ctrl_config_dev(struct opa_vnic_ctrl_port *cport, bool en) -{ - struct ib_port_modify pm = { 0 }; - int i; - - if (en) - pm.set_port_cap_mask = OPA_CAP_MASK3_IsEthOnFabricSupported; - else - pm.clr_port_cap_mask = OPA_CAP_MASK3_IsEthOnFabricSupported; - - for (i = 1; i <= cport->num_ports; i++) - ib_modify_port(cport->ibdev, i, IB_PORT_OPA_MASK_CHG, &pm); -} - -/** - * opa_vnic_vema_add_one -- Handle new ib device - * @device: ib device pointer - * - * Allocate the vnic control port and initialize it. - */ -static int opa_vnic_vema_add_one(struct ib_device *device) -{ - struct opa_vnic_ctrl_port *cport; - int rc, size = sizeof(*cport); - - if (!rdma_cap_opa_vnic(device)) - return -EOPNOTSUPP; - - size += device->phys_port_cnt * sizeof(struct opa_vnic_vema_port); - cport = kzalloc(size, GFP_KERNEL); - if (!cport) - return -ENOMEM; - - cport->num_ports = device->phys_port_cnt; - cport->ibdev = device; - - /* Initialize opa vnic management agent (vema) */ - rc = vema_register(cport); - if (!rc) - c_info("VNIC client initialized\n"); - - ib_set_client_data(device, &opa_vnic_client, cport); - opa_vnic_ctrl_config_dev(cport, true); - return 0; -} - -/** - * opa_vnic_vema_rem_one -- Handle ib device removal - * @device: ib device pointer - * @client_data: ib client data - * - * Uninitialize and free the vnic control port. - */ -static void opa_vnic_vema_rem_one(struct ib_device *device, - void *client_data) -{ - struct opa_vnic_ctrl_port *cport = client_data; - - c_info("removing VNIC client\n"); - opa_vnic_ctrl_config_dev(cport, false); - vema_unregister(cport); - kfree(cport); -} - -static int __init opa_vnic_init(void) -{ - int rc; - - rc = ib_register_client(&opa_vnic_client); - if (rc) - pr_err("VNIC driver register failed %d\n", rc); - - return rc; -} -module_init(opa_vnic_init); - -static void opa_vnic_deinit(void) -{ - ib_unregister_client(&opa_vnic_client); -} -module_exit(opa_vnic_deinit); - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("Cornelis Networks"); -MODULE_DESCRIPTION("Cornelis OPX Virtual Network driver"); diff --git a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c b/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c deleted file mode 100644 index 292c037aa239..000000000000 --- a/drivers/infiniband/ulp/opa_vnic/opa_vnic_vema_iface.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Copyright(c) 2017 Intel Corporation. - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * BSD LICENSE - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * This file contains OPA VNIC EMA Interface functions. - */ - -#include "opa_vnic_internal.h" - -/** - * opa_vnic_vema_report_event - sent trap to report the specified event - * @adapter: vnic port adapter - * @event: event to be reported - * - * This function calls vema api to sent a trap for the given event. - */ -void opa_vnic_vema_report_event(struct opa_vnic_adapter *adapter, u8 event) -{ - struct __opa_veswport_info *info = &adapter->info; - struct __opa_veswport_trap trap_data; - - trap_data.fabric_id = info->vesw.fabric_id; - trap_data.veswid = info->vesw.vesw_id; - trap_data.veswportnum = info->vport.port_num; - trap_data.opaportnum = adapter->port_num; - trap_data.veswportindex = adapter->vport_num; - trap_data.opcode = event; - - opa_vnic_vema_send_trap(adapter, &trap_data, info->vport.encap_slid); -} - -/** - * opa_vnic_get_summary_counters - get summary counters - * @adapter: vnic port adapter - * @cntrs: pointer to destination summary counters structure - * - * This function populates the summary counters that is maintained by the - * given adapter to destination address provided. - */ -void opa_vnic_get_summary_counters(struct opa_vnic_adapter *adapter, - struct opa_veswport_summary_counters *cntrs) -{ - struct opa_vnic_stats vstats; - __be64 *dst; - u64 *src; - - memset(&vstats, 0, sizeof(vstats)); - spin_lock(&adapter->stats_lock); - adapter->rn_ops->ndo_get_stats64(adapter->netdev, &vstats.netstats); - spin_unlock(&adapter->stats_lock); - - cntrs->vp_instance = cpu_to_be16(adapter->vport_num); - cntrs->vesw_id = cpu_to_be16(adapter->info.vesw.vesw_id); - cntrs->veswport_num = cpu_to_be32(adapter->port_num); - - cntrs->tx_errors = cpu_to_be64(vstats.netstats.tx_errors); - cntrs->rx_errors = cpu_to_be64(vstats.netstats.rx_errors); - cntrs->tx_packets = cpu_to_be64(vstats.netstats.tx_packets); - cntrs->rx_packets = cpu_to_be64(vstats.netstats.rx_packets); - cntrs->tx_bytes = cpu_to_be64(vstats.netstats.tx_bytes); - cntrs->rx_bytes = cpu_to_be64(vstats.netstats.rx_bytes); - - /* - * This loop depends on layout of - * opa_veswport_summary_counters opa_vnic_stats structures. - */ - for (dst = &cntrs->tx_unicast, src = &vstats.tx_grp.unicast; - dst < &cntrs->reserved[0]; dst++, src++) { - *dst = cpu_to_be64(*src); - } -} - -/** - * opa_vnic_get_error_counters - get error counters - * @adapter: vnic port adapter - * @cntrs: pointer to destination error counters structure - * - * This function populates the error counters that is maintained by the - * given adapter to destination address provided. - */ -void opa_vnic_get_error_counters(struct opa_vnic_adapter *adapter, - struct opa_veswport_error_counters *cntrs) -{ - struct opa_vnic_stats vstats; - - memset(&vstats, 0, sizeof(vstats)); - spin_lock(&adapter->stats_lock); - adapter->rn_ops->ndo_get_stats64(adapter->netdev, &vstats.netstats); - spin_unlock(&adapter->stats_lock); - - cntrs->vp_instance = cpu_to_be16(adapter->vport_num); - cntrs->vesw_id = cpu_to_be16(adapter->info.vesw.vesw_id); - cntrs->veswport_num = cpu_to_be32(adapter->port_num); - - cntrs->tx_errors = cpu_to_be64(vstats.netstats.tx_errors); - cntrs->rx_errors = cpu_to_be64(vstats.netstats.rx_errors); - cntrs->tx_dlid_zero = cpu_to_be64(vstats.tx_dlid_zero); - cntrs->tx_drop_state = cpu_to_be64(vstats.tx_drop_state); - cntrs->tx_logic = cpu_to_be64(vstats.netstats.tx_fifo_errors + - vstats.netstats.tx_carrier_errors); - - cntrs->rx_bad_veswid = cpu_to_be64(vstats.netstats.rx_nohandler); - cntrs->rx_runt = cpu_to_be64(vstats.rx_runt); - cntrs->rx_oversize = cpu_to_be64(vstats.rx_oversize); - cntrs->rx_drop_state = cpu_to_be64(vstats.rx_drop_state); - cntrs->rx_logic = cpu_to_be64(vstats.netstats.rx_fifo_errors); -} - -/** - * opa_vnic_get_vesw_info -- Get the vesw information - * @adapter: vnic port adapter - * @info: pointer to destination vesw info structure - * - * This function copies the vesw info that is maintained by the - * given adapter to destination address provided. - */ -void opa_vnic_get_vesw_info(struct opa_vnic_adapter *adapter, - struct opa_vesw_info *info) -{ - struct __opa_vesw_info *src = &adapter->info.vesw; - int i; - - info->fabric_id = cpu_to_be16(src->fabric_id); - info->vesw_id = cpu_to_be16(src->vesw_id); - memcpy(info->rsvd0, src->rsvd0, ARRAY_SIZE(src->rsvd0)); - info->def_port_mask = cpu_to_be16(src->def_port_mask); - memcpy(info->rsvd1, src->rsvd1, ARRAY_SIZE(src->rsvd1)); - info->pkey = cpu_to_be16(src->pkey); - - memcpy(info->rsvd2, src->rsvd2, ARRAY_SIZE(src->rsvd2)); - info->u_mcast_dlid = cpu_to_be32(src->u_mcast_dlid); - for (i = 0; i < OPA_VESW_MAX_NUM_DEF_PORT; i++) - info->u_ucast_dlid[i] = cpu_to_be32(src->u_ucast_dlid[i]); - - info->rc = cpu_to_be32(src->rc); - - memcpy(info->rsvd3, src->rsvd3, ARRAY_SIZE(src->rsvd3)); - info->eth_mtu = cpu_to_be16(src->eth_mtu); - memcpy(info->rsvd4, src->rsvd4, ARRAY_SIZE(src->rsvd4)); -} - -/** - * opa_vnic_set_vesw_info -- Set the vesw information - * @adapter: vnic port adapter - * @info: pointer to vesw info structure - * - * This function updates the vesw info that is maintained by the - * given adapter with vesw info provided. Reserved fields are stored - * and returned back to EM as is. - */ -void opa_vnic_set_vesw_info(struct opa_vnic_adapter *adapter, - struct opa_vesw_info *info) -{ - struct __opa_vesw_info *dst = &adapter->info.vesw; - int i; - - dst->fabric_id = be16_to_cpu(info->fabric_id); - dst->vesw_id = be16_to_cpu(info->vesw_id); - memcpy(dst->rsvd0, info->rsvd0, ARRAY_SIZE(info->rsvd0)); - dst->def_port_mask = be16_to_cpu(info->def_port_mask); - memcpy(dst->rsvd1, info->rsvd1, ARRAY_SIZE(info->rsvd1)); - dst->pkey = be16_to_cpu(info->pkey); - - memcpy(dst->rsvd2, info->rsvd2, ARRAY_SIZE(info->rsvd2)); - dst->u_mcast_dlid = be32_to_cpu(info->u_mcast_dlid); - for (i = 0; i < OPA_VESW_MAX_NUM_DEF_PORT; i++) - dst->u_ucast_dlid[i] = be32_to_cpu(info->u_ucast_dlid[i]); - - dst->rc = be32_to_cpu(info->rc); - - memcpy(dst->rsvd3, info->rsvd3, ARRAY_SIZE(info->rsvd3)); - dst->eth_mtu = be16_to_cpu(info->eth_mtu); - memcpy(dst->rsvd4, info->rsvd4, ARRAY_SIZE(info->rsvd4)); -} - -/** - * opa_vnic_get_per_veswport_info -- Get the vesw per port information - * @adapter: vnic port adapter - * @info: pointer to destination vport info structure - * - * This function copies the vesw per port info that is maintained by the - * given adapter to destination address provided. - * Note that the read only fields are not copied. - */ -void opa_vnic_get_per_veswport_info(struct opa_vnic_adapter *adapter, - struct opa_per_veswport_info *info) -{ - struct __opa_per_veswport_info *src = &adapter->info.vport; - - info->port_num = cpu_to_be32(src->port_num); - info->eth_link_status = src->eth_link_status; - memcpy(info->rsvd0, src->rsvd0, ARRAY_SIZE(src->rsvd0)); - - memcpy(info->base_mac_addr, src->base_mac_addr, - ARRAY_SIZE(info->base_mac_addr)); - info->config_state = src->config_state; - info->oper_state = src->oper_state; - info->max_mac_tbl_ent = cpu_to_be16(src->max_mac_tbl_ent); - info->max_smac_ent = cpu_to_be16(src->max_smac_ent); - info->mac_tbl_digest = cpu_to_be32(src->mac_tbl_digest); - memcpy(info->rsvd1, src->rsvd1, ARRAY_SIZE(src->rsvd1)); - - info->encap_slid = cpu_to_be32(src->encap_slid); - memcpy(info->pcp_to_sc_uc, src->pcp_to_sc_uc, - ARRAY_SIZE(info->pcp_to_sc_uc)); - memcpy(info->pcp_to_vl_uc, src->pcp_to_vl_uc, - ARRAY_SIZE(info->pcp_to_vl_uc)); - memcpy(info->pcp_to_sc_mc, src->pcp_to_sc_mc, - ARRAY_SIZE(info->pcp_to_sc_mc)); - memcpy(info->pcp_to_vl_mc, src->pcp_to_vl_mc, - ARRAY_SIZE(info->pcp_to_vl_mc)); - info->non_vlan_sc_uc = src->non_vlan_sc_uc; - info->non_vlan_vl_uc = src->non_vlan_vl_uc; - info->non_vlan_sc_mc = src->non_vlan_sc_mc; - info->non_vlan_vl_mc = src->non_vlan_vl_mc; - memcpy(info->rsvd2, src->rsvd2, ARRAY_SIZE(src->rsvd2)); - - info->uc_macs_gen_count = cpu_to_be16(src->uc_macs_gen_count); - info->mc_macs_gen_count = cpu_to_be16(src->mc_macs_gen_count); - memcpy(info->rsvd3, src->rsvd3, ARRAY_SIZE(src->rsvd3)); -} - -/** - * opa_vnic_set_per_veswport_info -- Set vesw per port information - * @adapter: vnic port adapter - * @info: pointer to vport info structure - * - * This function updates the vesw per port info that is maintained by the - * given adapter with vesw per port info provided. Reserved fields are - * stored and returned back to EM as is. - */ -void opa_vnic_set_per_veswport_info(struct opa_vnic_adapter *adapter, - struct opa_per_veswport_info *info) -{ - struct __opa_per_veswport_info *dst = &adapter->info.vport; - - dst->port_num = be32_to_cpu(info->port_num); - memcpy(dst->rsvd0, info->rsvd0, ARRAY_SIZE(info->rsvd0)); - - memcpy(dst->base_mac_addr, info->base_mac_addr, - ARRAY_SIZE(dst->base_mac_addr)); - dst->config_state = info->config_state; - memcpy(dst->rsvd1, info->rsvd1, ARRAY_SIZE(info->rsvd1)); - - dst->encap_slid = be32_to_cpu(info->encap_slid); - memcpy(dst->pcp_to_sc_uc, info->pcp_to_sc_uc, - ARRAY_SIZE(dst->pcp_to_sc_uc)); - memcpy(dst->pcp_to_vl_uc, info->pcp_to_vl_uc, - ARRAY_SIZE(dst->pcp_to_vl_uc)); - memcpy(dst->pcp_to_sc_mc, info->pcp_to_sc_mc, - ARRAY_SIZE(dst->pcp_to_sc_mc)); - memcpy(dst->pcp_to_vl_mc, info->pcp_to_vl_mc, - ARRAY_SIZE(dst->pcp_to_vl_mc)); - dst->non_vlan_sc_uc = info->non_vlan_sc_uc; - dst->non_vlan_vl_uc = info->non_vlan_vl_uc; - dst->non_vlan_sc_mc = info->non_vlan_sc_mc; - dst->non_vlan_vl_mc = info->non_vlan_vl_mc; - memcpy(dst->rsvd2, info->rsvd2, ARRAY_SIZE(info->rsvd2)); - memcpy(dst->rsvd3, info->rsvd3, ARRAY_SIZE(info->rsvd3)); -} - -/** - * opa_vnic_query_mcast_macs - query multicast mac list - * @adapter: vnic port adapter - * @macs: pointer mac list - * - * This function populates the provided mac list with the configured - * multicast addresses in the adapter. - */ -void opa_vnic_query_mcast_macs(struct opa_vnic_adapter *adapter, - struct opa_veswport_iface_macs *macs) -{ - u16 start_idx, num_macs, idx = 0, count = 0; - struct netdev_hw_addr *ha; - - start_idx = be16_to_cpu(macs->start_idx); - num_macs = be16_to_cpu(macs->num_macs_in_msg); - netdev_for_each_mc_addr(ha, adapter->netdev) { - struct opa_vnic_iface_mac_entry *entry = &macs->entry[count]; - - if (start_idx > idx++) - continue; - else if (num_macs == count) - break; - memcpy(entry, ha->addr, sizeof(*entry)); - count++; - } - - macs->tot_macs_in_lst = cpu_to_be16(netdev_mc_count(adapter->netdev)); - macs->num_macs_in_msg = cpu_to_be16(count); - macs->gen_count = cpu_to_be16(adapter->info.vport.mc_macs_gen_count); -} - -/** - * opa_vnic_query_ucast_macs - query unicast mac list - * @adapter: vnic port adapter - * @macs: pointer mac list - * - * This function populates the provided mac list with the configured - * unicast addresses in the adapter. - */ -void opa_vnic_query_ucast_macs(struct opa_vnic_adapter *adapter, - struct opa_veswport_iface_macs *macs) -{ - u16 start_idx, tot_macs, num_macs, idx = 0, count = 0, em_macs = 0; - struct netdev_hw_addr *ha; - - start_idx = be16_to_cpu(macs->start_idx); - num_macs = be16_to_cpu(macs->num_macs_in_msg); - /* loop through dev_addrs list first */ - for_each_dev_addr(adapter->netdev, ha) { - struct opa_vnic_iface_mac_entry *entry = &macs->entry[count]; - - /* Do not include EM specified MAC address */ - if (!memcmp(adapter->info.vport.base_mac_addr, ha->addr, - ARRAY_SIZE(adapter->info.vport.base_mac_addr))) { - em_macs++; - continue; - } - - if (start_idx > idx++) - continue; - else if (num_macs == count) - break; - memcpy(entry, ha->addr, sizeof(*entry)); - count++; - } - - /* loop through uc list */ - netdev_for_each_uc_addr(ha, adapter->netdev) { - struct opa_vnic_iface_mac_entry *entry = &macs->entry[count]; - - if (start_idx > idx++) - continue; - else if (num_macs == count) - break; - memcpy(entry, ha->addr, sizeof(*entry)); - count++; - } - - tot_macs = netdev_hw_addr_list_count(&adapter->netdev->dev_addrs) + - netdev_uc_count(adapter->netdev) - em_macs; - macs->tot_macs_in_lst = cpu_to_be16(tot_macs); - macs->num_macs_in_msg = cpu_to_be16(count); - macs->gen_count = cpu_to_be16(adapter->info.vport.uc_macs_gen_count); -} diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c b/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c index 287e0ea43287..f8b833bd81ad 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt-sysfs.c @@ -37,8 +37,6 @@ static void rtrs_clt_path_stats_release(struct kobject *kobj) stats = container_of(kobj, struct rtrs_clt_stats, kobj_stats); free_percpu(stats->pcpu_stats); - - kfree(stats); } static struct kobj_type ktype_stats = { diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h b/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h index 7738e2676855..29e23404bb7b 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h @@ -55,7 +55,7 @@ DECLARE_EVENT_CLASS(rtrs_clt_conn_class, __entry->max_reconnect_attempts = clt->max_reconnect_attempts; __entry->fail_cnt = clt_path->stats->reconnects.fail_cnt; __entry->success_cnt = clt_path->stats->reconnects.successful_cnt; - memcpy(__entry->sessname, kobject_name(&clt_path->kobj), NAME_MAX); + strscpy(__entry->sessname, kobject_name(&clt_path->kobj) ?: "", NAME_MAX); ), TP_printk("RTRS-CLT: sess='%s' state=%s attempts='%d' max-attempts='%d' fail='%d' success='%d'", diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 3362362f9e2e..eac38b57b00d 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -1536,7 +1536,7 @@ static struct rtrs_clt_path *alloc_path(struct rtrs_clt_sess *clt, int cpu; size_t total_con; - clt_path = kzalloc_obj(*clt_path); + clt_path = kzalloc_flex(*clt_path, stats, 1); if (!clt_path) goto err; @@ -1552,10 +1552,6 @@ static struct rtrs_clt_path *alloc_path(struct rtrs_clt_sess *clt, clt_path->s.con_num = total_con; clt_path->s.irq_con_num = con_num + 1; - clt_path->stats = kzalloc_obj(*clt_path->stats); - if (!clt_path->stats) - goto err_free_con; - mutex_init(&clt_path->init_mutex); uuid_gen(&clt_path->s.uuid); memcpy(&clt_path->s.dst_addr, path->dst, @@ -1583,7 +1579,7 @@ static struct rtrs_clt_path *alloc_path(struct rtrs_clt_sess *clt, clt_path->mp_skip_entry = alloc_percpu(typeof(*clt_path->mp_skip_entry)); if (!clt_path->mp_skip_entry) - goto err_free_stats; + goto err_free_con; for_each_possible_cpu(cpu) INIT_LIST_HEAD(per_cpu_ptr(clt_path->mp_skip_entry, cpu)); @@ -1596,8 +1592,6 @@ static struct rtrs_clt_path *alloc_path(struct rtrs_clt_sess *clt, err_free_percpu: free_percpu(clt_path->mp_skip_entry); -err_free_stats: - kfree(clt_path->stats); err_free_con: kfree(clt_path->s.con); err_free_path: @@ -1681,8 +1675,7 @@ static int create_con_cq_qp(struct rtrs_clt_con *con) * + 2 for drain and heartbeat * in case qp gets into error state. */ - max_send_wr = - min_t(int, wr_limit, SERVICE_CON_QUEUE_DEPTH * 2 + 2); + max_send_wr = min(wr_limit, SERVICE_CON_QUEUE_DEPTH * 2 + 2); max_recv_wr = max_send_wr; } else { /* @@ -1698,11 +1691,9 @@ static int create_con_cq_qp(struct rtrs_clt_con *con) wr_limit = clt_path->s.dev->ib_dev->attrs.max_qp_wr; /* Shared between connections */ clt_path->s.dev_ref++; - max_send_wr = min_t(int, wr_limit, - /* QD * (REQ + RSP + FR REGS or INVS) + drain */ - clt_path->queue_depth * 4 + 1); - max_recv_wr = min_t(int, wr_limit, - clt_path->queue_depth * 3 + 1); + /* QD * (REQ + RSP + FR REGS or INVS) + drain */ + max_send_wr = min(wr_limit, clt_path->queue_depth * 4 + 1); + max_recv_wr = min(wr_limit, clt_path->queue_depth * 3 + 1); max_send_sge = 2; } atomic_set(&con->c.sq_wr_avail, max_send_wr); @@ -1741,6 +1732,8 @@ static void destroy_con_cq_qp(struct rtrs_clt_con *con) /* * Be careful here: destroy_con_cq_qp() can be called even * create_con_cq_qp() failed, see comments there. + * Caller must set con->destroyed under this lock first so a + * racing ADDR_RESOLVED cannot ib_cq_pool_get() after we PUT/SKIP. */ lockdep_assert_held(&con->con_mutex); rtrs_cq_qp_destroy(&con->c); @@ -1775,6 +1768,10 @@ static int rtrs_rdma_addr_resolved(struct rtrs_clt_con *con) int err; mutex_lock(&con->con_mutex); + if (con->destroyed) { + mutex_unlock(&con->con_mutex); + return -ECONNABORTED; + } err = create_con_cq_qp(con); mutex_unlock(&con->con_mutex); if (err) { @@ -2230,6 +2227,7 @@ static void rtrs_clt_stop_and_destroy_conns(struct rtrs_clt_path *clt_path) break; con = to_clt_con(clt_path->s.con[cid]); mutex_lock(&con->con_mutex); + con->destroyed = true; destroy_con_cq_qp(con); mutex_unlock(&con->con_mutex); destroy_cm(con); @@ -2396,6 +2394,7 @@ destroy: if (con->c.cm_id) { stop_cm(con); mutex_lock(&con->con_mutex); + con->destroyed = true; destroy_con_cq_qp(con); mutex_unlock(&con->con_mutex); destroy_cm(con); @@ -2863,7 +2862,6 @@ struct rtrs_clt_sess *rtrs_clt_open(struct rtrs_clt_ops *ops, list_del_rcu(&clt_path->s.entry); rtrs_clt_close_conns(clt_path, true); free_percpu(clt_path->stats->pcpu_stats); - kfree(clt_path->stats); free_path(clt_path); goto close_all_path; } @@ -2873,7 +2871,6 @@ struct rtrs_clt_sess *rtrs_clt_open(struct rtrs_clt_ops *ops, list_del_rcu(&clt_path->s.entry); rtrs_clt_close_conns(clt_path, true); free_percpu(clt_path->stats->pcpu_stats); - kfree(clt_path->stats); free_path(clt_path); goto close_all_path; } @@ -3166,7 +3163,6 @@ close_path: rtrs_clt_remove_path_from_arr(clt_path); rtrs_clt_close_conns(clt_path, true); free_percpu(clt_path->stats->pcpu_stats); - kfree(clt_path->stats); free_path(clt_path); return err; @@ -3219,7 +3215,7 @@ static int __init rtrs_client_init(void) pr_err("Failed to create rtrs-client dev class\n"); return ret; } - rtrs_wq = alloc_workqueue("rtrs_client_wq", 0, 0); + rtrs_wq = alloc_workqueue("rtrs_client_wq", WQ_PERCPU, 0); if (!rtrs_wq) { class_unregister(&rtrs_clt_dev_class); return -ENOMEM; diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.h b/drivers/infiniband/ulp/rtrs/rtrs-clt.h index 986239ed2d3b..ad64f4517c4b 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.h @@ -75,6 +75,8 @@ struct rtrs_clt_con { unsigned int cpu; struct mutex con_mutex; int cm_err; + /* Set under con_mutex before CQ/QP teardown. */ + bool destroyed; }; /** @@ -142,12 +144,12 @@ struct rtrs_clt_path { u32 flags; struct kobject kobj; u8 for_new_clt; - struct rtrs_clt_stats *stats; /* cache hca_port and hca_name to display in sysfs */ u8 hca_port; char hca_name[IB_DEVICE_NAME_MAX]; struct list_head __percpu *mp_skip_entry; + struct rtrs_clt_stats stats[]; }; struct rtrs_clt_sess { diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c b/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c index 51727c7d710c..9dd9141c86a5 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv-sysfs.c @@ -295,8 +295,8 @@ remove_group: put_kobj: kobject_del(&srv_path->kobj); destroy_root: - kobject_put(&srv_path->kobj); rtrs_srv_destroy_once_sysfs_root_folders(srv_path); + kobject_put(&srv_path->kobj); return err; } diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h b/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h index 587d3e033081..a7d7b971e6c8 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h @@ -61,7 +61,7 @@ TRACE_EVENT(send_io_resp_imm, __entry->msg_id = id->msg_id; __entry->wr_cnt = atomic_read(&con->c.wr_cnt); __entry->signal_interval = s->signal_interval; - memcpy(__entry->sessname, kobject_name(&srv_path->kobj), NAME_MAX); + strscpy(__entry->sessname, kobject_name(&srv_path->kobj) ?: "", NAME_MAX); ), TP_printk("sess='%s' state='%s' dir=%s err='%d' inval='%d' glob-inval='%d' msgid='%u' wrcnt='%d' sig-interval='%u'", diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv.c b/drivers/infiniband/ulp/rtrs/rtrs-srv.c index 0140bfaed721..5314599d29fe 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv.c @@ -225,8 +225,9 @@ static int rdma_write_sg(struct rtrs_srv_op *id) /* WR will fail with length error * if this is 0 */ - if (plist->length == 0) { - rtrs_err(s, "Invalid RDMA-Write sg list length 0\n"); + if (plist->length == 0 || plist->length > max_chunk_size) { + rtrs_err(s, "Invalid RDMA-Write sg list length %u\n", + plist->length); return -EINVAL; } @@ -1059,6 +1060,11 @@ static void process_read(struct rtrs_srv_con *con, "Processing read request failed, invalid message\n"); return; } + usr_len = le16_to_cpu(msg->usr_len); + if (usr_len > off) { + pr_debug("rtrs-srv: Invalid usr_len %zu > off %u\n", usr_len, off); + return; + } rtrs_srv_get_ops_ids(srv_path); rtrs_srv_update_rdma_stats(srv_path->stats, off, READ); id = srv_path->ops_ids[buf_id]; @@ -1066,7 +1072,6 @@ static void process_read(struct rtrs_srv_con *con, id->dir = READ; id->msg_id = buf_id; id->rd_msg = msg; - usr_len = le16_to_cpu(msg->usr_len); data_len = off - usr_len; data = page_address(srv->chunks[buf_id]); ret = ctx->ops.rdma_ev(srv->priv, id, data, data_len, @@ -1112,6 +1117,11 @@ static void process_write(struct rtrs_srv_con *con, rtrs_srv_state_str(srv_path->state)); return; } + usr_len = le16_to_cpu(req->usr_len); + if (usr_len > off) { + pr_debug("rtrs-srv: Invalid usr_len %zu > off %u\n", usr_len, off); + return; + } rtrs_srv_get_ops_ids(srv_path); rtrs_srv_update_rdma_stats(srv_path->stats, off, WRITE); id = srv_path->ops_ids[buf_id]; @@ -1119,7 +1129,6 @@ static void process_write(struct rtrs_srv_con *con, id->dir = WRITE; id->msg_id = buf_id; - usr_len = le16_to_cpu(req->usr_len); data_len = off - usr_len; data = page_address(srv->chunks[buf_id]); ret = ctx->ops.rdma_ev(srv->priv, id, data, data_len, @@ -1731,21 +1740,16 @@ static int create_con(struct rtrs_srv_path *srv_path, * All receive and all send (each requiring invalidate) * + 2 for drain and heartbeat */ - max_send_wr = min_t(int, wr_limit, - SERVICE_CON_QUEUE_DEPTH * 2 + 2); + max_send_wr = min(wr_limit, SERVICE_CON_QUEUE_DEPTH * 2 + 2); max_recv_wr = max_send_wr; s->signal_interval = min_not_zero(srv->queue_depth, (size_t)SERVICE_CON_QUEUE_DEPTH); } else { /* when always_invlaidate enalbed, we need linv+rinv+mr+imm */ if (always_invalidate) - max_send_wr = - min_t(int, wr_limit, - srv->queue_depth * (1 + 4) + 1); + max_send_wr = min(wr_limit, srv->queue_depth * (1 + 4) + 1); else - max_send_wr = - min_t(int, wr_limit, - srv->queue_depth * (1 + 2) + 1); + max_send_wr = min(wr_limit, srv->queue_depth * (1 + 2) + 1); max_recv_wr = srv->queue_depth + 1; } @@ -2385,7 +2389,7 @@ static int __init rtrs_server_init(void) if (err) goto out_err; - rtrs_wq = alloc_workqueue("rtrs_server_wq", 0, 0); + rtrs_wq = alloc_workqueue("rtrs_server_wq", WQ_PERCPU, 0); if (!rtrs_wq) { err = -ENOMEM; goto out_dev_class; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 30339dcabb4d..955f36efeebd 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -43,6 +43,7 @@ #include <linux/jiffies.h> #include <linux/lockdep.h> #include <linux/inet.h> +#include <net/net_namespace.h> #include <rdma/ib_cache.h> #include <linux/atomic.h> @@ -556,7 +557,7 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) init_attr->cap.max_send_wr = m * target->queue_size; init_attr->cap.max_recv_wr = target->queue_size + 1; init_attr->cap.max_recv_sge = 1; - init_attr->cap.max_send_sge = min(SRP_MAX_SGE, attr->max_send_sge); + init_attr->cap.max_send_sge = min(attr->max_send_sge, SRP_MAX_SGE); init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; init_attr->qp_type = IB_QPT_RC; init_attr->send_cq = send_cq; @@ -1037,24 +1038,30 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost) static void srp_remove_target(struct srp_target_port *target) { + struct scsi_device *sdev; struct srp_rdma_ch *ch; int i; WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); srp_del_scsi_host_attr(target->scsi_host); - srp_rport_get(target->rport); - srp_remove_host(target->scsi_host); - scsi_remove_host(target->scsi_host); + /* + * Remove all logical units. This must happen before the + * srp_disconnect_target() call because scsi_remove_device() may trigger + * submission of SCSI commands. See also sd_shutdown(). + */ + shost_for_each_device(sdev, target->scsi_host) + scsi_remove_device(sdev); srp_stop_rport_timers(target->rport); srp_disconnect_target(target); - kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net); + kobj_ns_drop(KOBJ_NS_TYPE_NET, to_ns_common(target->net)); for (i = 0; i < target->ch_count; i++) { ch = &target->ch[i]; srp_free_ch_ib(target, ch); } cancel_work_sync(&target->tl_err_work); - srp_rport_put(target->rport); + srp_remove_host(target->scsi_host); + scsi_remove_host(target->scsi_host); kfree(target->ch); target->ch = NULL; @@ -1931,7 +1938,8 @@ static int srp_post_recv(struct srp_rdma_ch *ch, struct srp_iu *iu) return ib_post_recv(ch->qp, &wr, NULL); } -static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) +static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp, + u32 byte_len) { struct srp_target_port *target = ch->target; struct srp_request *req; @@ -1943,7 +1951,8 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) ch->req_lim += be32_to_cpu(rsp->req_lim_delta); if (rsp->tag == ch->tsk_mgmt_tag) { ch->tsk_mgmt_status = -1; - if (be32_to_cpu(rsp->resp_data_len) >= 4) + if (be32_to_cpu(rsp->resp_data_len) >= 4 && + byte_len >= sizeof(*rsp) + 4) ch->tsk_mgmt_status = rsp->data[3]; complete(&ch->tsk_mgmt_done); } else { @@ -1972,10 +1981,27 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp) scmnd->result = rsp->status; if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { - memcpy(scmnd->sense_buffer, rsp->data + - be32_to_cpu(rsp->resp_data_len), - min_t(int, be32_to_cpu(rsp->sense_data_len), - SCSI_SENSE_BUFFERSIZE)); + u32 resp_len = be32_to_cpu(rsp->resp_data_len); + u32 sense_len = be32_to_cpu(rsp->sense_data_len); + + /* + * The sense data starts resp_data_len bytes past the + * response data area; both lengths come from the + * target-controlled response. Copy the sense data + * only if it has not been truncated, that is, only if + * the full sense region fits within the bytes actually + * received. Otherwise the copy source would run past + * the receive buffer (sized to the target-chosen + * max_ti_iu_len), reading out of bounds. + */ + if (sizeof(*rsp) + (u64)resp_len + sense_len <= byte_len) + memcpy(scmnd->sense_buffer, + rsp->data + resp_len, + min(sense_len, SCSI_SENSE_BUFFERSIZE)); + else + shost_printk(KERN_ERR, target->scsi_host, + "dropping truncated sense data (resp_data_len %u sense_data_len %u, %u bytes received)\n", + resp_len, sense_len, byte_len); } if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER)) @@ -2026,13 +2052,20 @@ static int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta, } static void srp_process_cred_req(struct srp_rdma_ch *ch, - struct srp_cred_req *req) + struct srp_cred_req *req, u32 byte_len) { - struct srp_cred_rsp rsp = { - .opcode = SRP_CRED_RSP, - .tag = req->tag, - }; - s32 delta = be32_to_cpu(req->req_lim_delta); + struct srp_cred_rsp rsp = { .opcode = SRP_CRED_RSP }; + s32 delta; + + if (byte_len < sizeof(*req)) { + shost_printk(KERN_ERR, ch->target->scsi_host, PFX + "dropping truncated SRP_CRED_REQ (%u bytes received, %zu expected)\n", + byte_len, sizeof(*req)); + return; + } + + rsp.tag = req->tag; + delta = be32_to_cpu(req->req_lim_delta); if (srp_response_common(ch, delta, &rsp, sizeof(rsp))) shost_printk(KERN_ERR, ch->target->scsi_host, PFX @@ -2040,14 +2073,21 @@ static void srp_process_cred_req(struct srp_rdma_ch *ch, } static void srp_process_aer_req(struct srp_rdma_ch *ch, - struct srp_aer_req *req) + struct srp_aer_req *req, u32 byte_len) { struct srp_target_port *target = ch->target; - struct srp_aer_rsp rsp = { - .opcode = SRP_AER_RSP, - .tag = req->tag, - }; - s32 delta = be32_to_cpu(req->req_lim_delta); + struct srp_aer_rsp rsp = { .opcode = SRP_AER_RSP }; + s32 delta; + + if (byte_len < sizeof(*req)) { + shost_printk(KERN_ERR, target->scsi_host, PFX + "dropping truncated SRP_AER_REQ (%u bytes received, %zu expected)\n", + byte_len, sizeof(*req)); + return; + } + + rsp.tag = req->tag; + delta = be32_to_cpu(req->req_lim_delta); shost_printk(KERN_ERR, target->scsi_host, PFX "ignoring AER for LUN %llu\n", scsilun_to_int(&req->lun)); @@ -2085,15 +2125,15 @@ static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc) switch (opcode) { case SRP_RSP: - srp_process_rsp(ch, iu->buf); + srp_process_rsp(ch, iu->buf, wc->byte_len); break; case SRP_CRED_REQ: - srp_process_cred_req(ch, iu->buf); + srp_process_cred_req(ch, iu->buf, wc->byte_len); break; case SRP_AER_REQ: - srp_process_aer_req(ch, iu->buf); + srp_process_aer_req(ch, iu->buf, wc->byte_len); break; case SRP_T_LOGOUT: @@ -3170,10 +3210,24 @@ static struct attribute *srp_class_attrs[]; ATTRIBUTE_GROUPS(srp_class); +/* + * SRP hosts are named after their ib device, so tag the class by the ib + * device's net namespace. + */ +static const struct ns_common *srp_net_namespace(const struct device *dev) +{ + struct srp_host *host = container_of(dev, struct srp_host, dev); + struct net *net = rdma_dev_net(host->srp_dev->dev); + + return net ? to_ns_common(net) : NULL; +} + static struct class srp_class = { .name = "infiniband_srp", .dev_groups = srp_class_groups, - .dev_release = srp_release_dev + .dev_release = srp_release_dev, + .ns_type = &net_ns_type_operations, + .namespace = srp_net_namespace, }; /** @@ -3713,7 +3767,7 @@ static ssize_t add_target_store(struct device *dev, target = host_to_target(target_host); - target->net = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); + target->net = to_net_ns(kobj_ns_grab_current(KOBJ_NS_TYPE_NET)); target->io_class = SRP_REV16A_IB_IO_CLASS; target->scsi_host = target_host; target->srp_host = host; @@ -3905,7 +3959,7 @@ put: * earlier in this function. */ if (target->state != SRP_TARGET_REMOVED) - kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net); + kobj_ns_drop(KOBJ_NS_TYPE_NET, to_ns_common(target->net)); scsi_host_put(target->scsi_host); } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index e00b87acf481..7197d95f2216 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -77,8 +77,8 @@ module_param(srp_max_req_size, int, 0444); MODULE_PARM_DESC(srp_max_req_size, "Maximum size of SRP request messages in bytes."); -static int srpt_srq_size = DEFAULT_SRPT_SRQ_SIZE; -module_param(srpt_srq_size, int, 0444); +static unsigned int srpt_srq_size = DEFAULT_SRPT_SRQ_SIZE; +module_param(srpt_srq_size, uint, 0444); MODULE_PARM_DESC(srpt_srq_size, "Shared receive queue (SRQ) size."); @@ -405,8 +405,7 @@ static void srpt_get_ioc(struct srpt_port *sport, u32 slot, if (sdev->use_srq) send_queue_depth = sdev->srq_size; else - send_queue_depth = min(MAX_SRPT_RQ_SIZE, - sdev->device->attrs.max_qp_wr); + send_queue_depth = min(sdev->device->attrs.max_qp_wr, MAX_SRPT_RQ_SIZE); memset(iocp, 0, sizeof(*iocp)); strcpy(iocp->id_string, SRPT_ID_STRING); @@ -960,6 +959,7 @@ static int srpt_alloc_rw_ctxs(struct srpt_send_ioctx *ioctx, struct srpt_rdma_ch *ch = ioctx->ch; struct scatterlist *prev = NULL; unsigned prev_nents; + u8 n_rdma, n_rw_ctx; int ret, i; if (nbufs == 1) { @@ -970,6 +970,9 @@ static int srpt_alloc_rw_ctxs(struct srpt_send_ioctx *ioctx, return -ENOMEM; } + n_rw_ctx = ioctx->n_rw_ctx; + n_rdma = ioctx->n_rdma; + for (i = ioctx->n_rw_ctx; i < nbufs; i++, db++) { struct srpt_rw_ctx *ctx = &ioctx->rw_ctxs[i]; u64 remote_addr = be64_to_cpu(db->va); @@ -1016,6 +1019,9 @@ unwind: } if (ioctx->rw_ctxs != &ioctx->s_rw_ctx) kfree(ioctx->rw_ctxs); + ioctx->rw_ctxs = NULL; + ioctx->n_rw_ctx = n_rw_ctx; + ioctx->n_rdma = n_rdma; return ret; } @@ -1129,9 +1135,10 @@ static int srpt_get_desc_tbl(struct srpt_recv_ioctx *recv_ioctx, struct srp_imm_buf *imm_buf = srpt_get_desc_buf(srp_cmd); void *data = (void *)srp_cmd + imm_data_offset; uint32_t len = be32_to_cpu(imm_buf->len); - uint32_t req_size = imm_data_offset + len; + uint32_t req_size; - if (req_size > srp_max_req_size) { + if (check_add_overflow((uint32_t)imm_data_offset, len, &req_size) || + req_size > srp_max_req_size) { pr_err("Immediate data (length %d + %d) exceeds request size %d\n", imm_data_offset, len, srp_max_req_size); return -EINVAL; @@ -1595,7 +1602,7 @@ static void srpt_handle_cmd(struct srpt_rdma_ch *ch, rc = target_init_cmd(cmd, ch->sess, &send_ioctx->sense_data[0], scsilun_to_int(&srp_cmd->lun), data_len, - TCM_SIMPLE_TAG, dir, TARGET_SCF_ACK_KREF); + cmd->sam_task_attr, dir, TARGET_SCF_ACK_KREF); if (rc != 0) { pr_debug("target_submit_cmd() returned %d for tag %#llx\n", rc, srp_cmd->tag); @@ -1850,7 +1857,7 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch) struct srpt_port *sport = ch->sport; struct srpt_device *sdev = sport->sdev; const struct ib_device_attr *attrs = &sdev->device->attrs; - int sq_size = sport->port_attrib.srp_sq_size; + u32 sq_size = sport->port_attrib.srp_sq_size; int i, ret; WARN_ON(ch->rq_size < 1); @@ -1911,13 +1918,13 @@ retry: bool retry = sq_size > MIN_SRPT_SQ_SIZE; if (retry) { - pr_debug("failed to create queue pair with sq_size = %d (%d) - retrying\n", + pr_debug("failed to create queue pair with sq_size = %u (%d) - retrying\n", sq_size, ret); ib_cq_pool_put(ch->cq, ch->cq_size); sq_size = max(sq_size / 2, MIN_SRPT_SQ_SIZE); goto retry; } else { - pr_err("failed to create queue pair with sq_size = %d (%d)\n", + pr_err("failed to create queue pair with sq_size = %u (%d)\n", sq_size, ret); goto err_destroy_cq; } @@ -1925,7 +1932,7 @@ retry: atomic_set(&ch->sq_wr_avail, qp_init->cap.max_send_wr); - pr_debug("%s: max_cqe= %d max_sge= %d sq_size = %d ch= %p\n", + pr_debug("%s: max_cqe= %d max_sge= %d sq_size = %u ch= %p\n", __func__, ch->cq->cqe, qp_init->cap.max_send_sge, qp_init->cap.max_send_wr, ch); @@ -2298,7 +2305,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev, * depth to avoid that the initiator driver has to report QUEUE_FULL * to the SCSI mid-layer. */ - ch->rq_size = min(MAX_SRPT_RQ_SIZE, sdev->device->attrs.max_qp_wr); + ch->rq_size = min(sdev->device->attrs.max_qp_wr, MAX_SRPT_RQ_SIZE); spin_lock_init(&ch->spinlock); ch->state = CH_CONNECTING; INIT_LIST_HEAD(&ch->cmd_wait_list); @@ -3136,7 +3143,7 @@ static int srpt_alloc_srq(struct srpt_device *sdev) return PTR_ERR(srq); } - pr_debug("create SRQ #wr= %d max_allow=%d dev= %s\n", sdev->srq_size, + pr_debug("create SRQ #wr= %d max_allow=%u dev= %s\n", sdev->srq_size, sdev->device->attrs.max_srq_wr, dev_name(&device->dev)); sdev->req_buf_cache = srpt_cache_get(srp_max_req_size); @@ -3925,6 +3932,7 @@ static const struct target_core_fabric_ops srpt_template = { .tfc_wwn_attrs = srpt_wwn_attrs, .tfc_tpg_attrib_attrs = srpt_tpg_attrib_attrs, + .default_compl_type = TARGET_QUEUE_COMPL, .default_submit_type = TARGET_DIRECT_SUBMIT, .direct_submit_supp = 1, }; @@ -3950,7 +3958,7 @@ static int __init srpt_init_module(void) if (srpt_srq_size < MIN_SRPT_SRQ_SIZE || srpt_srq_size > MAX_SRPT_SRQ_SIZE) { - pr_err("invalid value %d for kernel module parameter srpt_srq_size -- must be in the range [%d..%d].\n", + pr_err("invalid value %u for kernel module parameter srpt_srq_size -- must be in the range [%d..%d].\n", srpt_srq_size, MIN_SRPT_SRQ_SIZE, MAX_SRPT_SRQ_SIZE); goto out; } |
