/drivers/infiniband/core/mad.c
C | 3026 lines | 2389 code | 356 blank | 281 comment | 392 complexity | e99f6b5a2fd60ee78e8c3c34540713aa MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
Large files files are truncated, but you can click here to view the full file
- /*
- * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved.
- * Copyright (c) 2005 Intel Corporation. All rights reserved.
- * Copyright (c) 2005 Mellanox Technologies Ltd. All rights reserved.
- * Copyright (c) 2009 HNR Consulting. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- */
- #include <linux/dma-mapping.h>
- #include <linux/slab.h>
- #include <rdma/ib_cache.h>
- #include "mad_priv.h"
- #include "mad_rmpp.h"
- #include "smi.h"
- #include "agent.h"
- MODULE_LICENSE("Dual BSD/GPL");
- MODULE_DESCRIPTION("kernel IB MAD API");
- MODULE_AUTHOR("Hal Rosenstock");
- MODULE_AUTHOR("Sean Hefty");
- static int mad_sendq_size = IB_MAD_QP_SEND_SIZE;
- static int mad_recvq_size = IB_MAD_QP_RECV_SIZE;
- module_param_named(send_queue_size, mad_sendq_size, int, 0444);
- MODULE_PARM_DESC(send_queue_size, "Size of send queue in number of work requests");
- module_param_named(recv_queue_size, mad_recvq_size, int, 0444);
- MODULE_PARM_DESC(recv_queue_size, "Size of receive queue in number of work requests");
- static struct kmem_cache *ib_mad_cache;
- static struct list_head ib_mad_port_list;
- static u32 ib_mad_client_id = 0;
- /* Port list lock */
- static DEFINE_SPINLOCK(ib_mad_port_list_lock);
- /* Forward declarations */
- static int method_in_use(struct ib_mad_mgmt_method_table **method,
- struct ib_mad_reg_req *mad_reg_req);
- static void remove_mad_reg_req(struct ib_mad_agent_private *priv);
- static struct ib_mad_agent_private *find_mad_agent(
- struct ib_mad_port_private *port_priv,
- struct ib_mad *mad);
- static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info,
- struct ib_mad_private *mad);
- static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv);
- static void timeout_sends(struct work_struct *work);
- static void local_completions(struct work_struct *work);
- static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req,
- struct ib_mad_agent_private *agent_priv,
- u8 mgmt_class);
- static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req,
- struct ib_mad_agent_private *agent_priv);
- /*
- * Returns a ib_mad_port_private structure or NULL for a device/port
- * Assumes ib_mad_port_list_lock is being held
- */
- static inline struct ib_mad_port_private *
- __ib_get_mad_port(struct ib_device *device, int port_num)
- {
- struct ib_mad_port_private *entry;
- list_for_each_entry(entry, &ib_mad_port_list, port_list) {
- if (entry->device == device && entry->port_num == port_num)
- return entry;
- }
- return NULL;
- }
- /*
- * Wrapper function to return a ib_mad_port_private structure or NULL
- * for a device/port
- */
- static inline struct ib_mad_port_private *
- ib_get_mad_port(struct ib_device *device, int port_num)
- {
- struct ib_mad_port_private *entry;
- unsigned long flags;
- spin_lock_irqsave(&ib_mad_port_list_lock, flags);
- entry = __ib_get_mad_port(device, port_num);
- spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
- return entry;
- }
- static inline u8 convert_mgmt_class(u8 mgmt_class)
- {
- /* Alias IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE to 0 */
- return mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ?
- 0 : mgmt_class;
- }
- static int get_spl_qp_index(enum ib_qp_type qp_type)
- {
- switch (qp_type)
- {
- case IB_QPT_SMI:
- return 0;
- case IB_QPT_GSI:
- return 1;
- default:
- return -1;
- }
- }
- static int vendor_class_index(u8 mgmt_class)
- {
- return mgmt_class - IB_MGMT_CLASS_VENDOR_RANGE2_START;
- }
- static int is_vendor_class(u8 mgmt_class)
- {
- if ((mgmt_class < IB_MGMT_CLASS_VENDOR_RANGE2_START) ||
- (mgmt_class > IB_MGMT_CLASS_VENDOR_RANGE2_END))
- return 0;
- return 1;
- }
- static int is_vendor_oui(char *oui)
- {
- if (oui[0] || oui[1] || oui[2])
- return 1;
- return 0;
- }
- static int is_vendor_method_in_use(
- struct ib_mad_mgmt_vendor_class *vendor_class,
- struct ib_mad_reg_req *mad_reg_req)
- {
- struct ib_mad_mgmt_method_table *method;
- int i;
- for (i = 0; i < MAX_MGMT_OUI; i++) {
- if (!memcmp(vendor_class->oui[i], mad_reg_req->oui, 3)) {
- method = vendor_class->method_table[i];
- if (method) {
- if (method_in_use(&method, mad_reg_req))
- return 1;
- else
- break;
- }
- }
- }
- return 0;
- }
- int ib_response_mad(struct ib_mad *mad)
- {
- return ((mad->mad_hdr.method & IB_MGMT_METHOD_RESP) ||
- (mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) ||
- ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_BM) &&
- (mad->mad_hdr.attr_mod & IB_BM_ATTR_MOD_RESP)));
- }
- EXPORT_SYMBOL(ib_response_mad);
- /*
- * ib_register_mad_agent - Register to send/receive MADs
- */
- struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
- u8 port_num,
- enum ib_qp_type qp_type,
- struct ib_mad_reg_req *mad_reg_req,
- u8 rmpp_version,
- ib_mad_send_handler send_handler,
- ib_mad_recv_handler recv_handler,
- void *context)
- {
- struct ib_mad_port_private *port_priv;
- struct ib_mad_agent *ret = ERR_PTR(-EINVAL);
- struct ib_mad_agent_private *mad_agent_priv;
- struct ib_mad_reg_req *reg_req = NULL;
- struct ib_mad_mgmt_class_table *class;
- struct ib_mad_mgmt_vendor_class_table *vendor;
- struct ib_mad_mgmt_vendor_class *vendor_class;
- struct ib_mad_mgmt_method_table *method;
- int ret2, qpn;
- unsigned long flags;
- u8 mgmt_class, vclass;
- /* Validate parameters */
- qpn = get_spl_qp_index(qp_type);
- if (qpn == -1)
- goto error1;
- if (rmpp_version && rmpp_version != IB_MGMT_RMPP_VERSION)
- goto error1;
- /* Validate MAD registration request if supplied */
- if (mad_reg_req) {
- if (mad_reg_req->mgmt_class_version >= MAX_MGMT_VERSION)
- goto error1;
- if (!recv_handler)
- goto error1;
- if (mad_reg_req->mgmt_class >= MAX_MGMT_CLASS) {
- /*
- * IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE is the only
- * one in this range currently allowed
- */
- if (mad_reg_req->mgmt_class !=
- IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
- goto error1;
- } else if (mad_reg_req->mgmt_class == 0) {
- /*
- * Class 0 is reserved in IBA and is used for
- * aliasing of IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE
- */
- goto error1;
- } else if (is_vendor_class(mad_reg_req->mgmt_class)) {
- /*
- * If class is in "new" vendor range,
- * ensure supplied OUI is not zero
- */
- if (!is_vendor_oui(mad_reg_req->oui))
- goto error1;
- }
- /* Make sure class supplied is consistent with RMPP */
-