xref: /openbmc/linux/drivers/infiniband/core/mad.c (revision 7b7fd0ac7dc1ffcaf24d9bca0f051b0168e43cd4)
11da177e4SLinus Torvalds /*
2de493d47SHal Rosenstock  * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved.
3fa619a77SHal Rosenstock  * Copyright (c) 2005 Intel Corporation.  All rights reserved.
4fa619a77SHal Rosenstock  * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
5b76aabc3SHal Rosenstock  * Copyright (c) 2009 HNR Consulting. All rights reserved.
64d60cad5SIra Weiny  * Copyright (c) 2014,2018 Intel Corporation.  All rights reserved.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * This software is available to you under a choice of one of two
91da177e4SLinus Torvalds  * licenses.  You may choose to be licensed under the terms of the GNU
101da177e4SLinus Torvalds  * General Public License (GPL) Version 2, available from the file
111da177e4SLinus Torvalds  * COPYING in the main directory of this source tree, or the
121da177e4SLinus Torvalds  * OpenIB.org BSD license below:
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  *     Redistribution and use in source and binary forms, with or
151da177e4SLinus Torvalds  *     without modification, are permitted provided that the following
161da177e4SLinus Torvalds  *     conditions are met:
171da177e4SLinus Torvalds  *
181da177e4SLinus Torvalds  *      - Redistributions of source code must retain the above
191da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
201da177e4SLinus Torvalds  *        disclaimer.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  *      - Redistributions in binary form must reproduce the above
231da177e4SLinus Torvalds  *        copyright notice, this list of conditions and the following
241da177e4SLinus Torvalds  *        disclaimer in the documentation and/or other materials
251da177e4SLinus Torvalds  *        provided with the distribution.
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
281da177e4SLinus Torvalds  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
291da177e4SLinus Torvalds  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
301da177e4SLinus Torvalds  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
311da177e4SLinus Torvalds  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
321da177e4SLinus Torvalds  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
331da177e4SLinus Torvalds  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
341da177e4SLinus Torvalds  * SOFTWARE.
351da177e4SLinus Torvalds  *
361da177e4SLinus Torvalds  */
377ef5d4b0SIra Weiny 
387ef5d4b0SIra Weiny #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
397ef5d4b0SIra Weiny 
401da177e4SLinus Torvalds #include <linux/dma-mapping.h>
415a0e3ad6STejun Heo #include <linux/slab.h>
42e4dd23d7SPaul Gortmaker #include <linux/module.h>
4347a2b338SDaniel Jurgens #include <linux/security.h>
44949a2370SMatthew Wilcox #include <linux/xarray.h>
459874e746SJack Morgenstein #include <rdma/ib_cache.h>
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds #include "mad_priv.h"
4847a2b338SDaniel Jurgens #include "core_priv.h"
49fa619a77SHal Rosenstock #include "mad_rmpp.h"
501da177e4SLinus Torvalds #include "smi.h"
518e4349d1SIra Weiny #include "opa_smi.h"
521da177e4SLinus Torvalds #include "agent.h"
531da177e4SLinus Torvalds 
544d60cad5SIra Weiny #define CREATE_TRACE_POINTS
554d60cad5SIra Weiny #include <trace/events/ib_mad.h>
564d60cad5SIra Weiny 
574d60cad5SIra Weiny #ifdef CONFIG_TRACEPOINTS
create_mad_addr_info(struct ib_mad_send_wr_private * mad_send_wr,struct ib_mad_qp_info * qp_info,struct trace_event_raw_ib_mad_send_template * entry)584d60cad5SIra Weiny static void create_mad_addr_info(struct ib_mad_send_wr_private *mad_send_wr,
594d60cad5SIra Weiny 			  struct ib_mad_qp_info *qp_info,
604d60cad5SIra Weiny 			  struct trace_event_raw_ib_mad_send_template *entry)
614d60cad5SIra Weiny {
624d60cad5SIra Weiny 	struct ib_ud_wr *wr = &mad_send_wr->send_wr;
634d60cad5SIra Weiny 	struct rdma_ah_attr attr = {};
644d60cad5SIra Weiny 
654d60cad5SIra Weiny 	rdma_query_ah(wr->ah, &attr);
664d60cad5SIra Weiny 
674d60cad5SIra Weiny 	/* These are common */
684d60cad5SIra Weiny 	entry->sl = attr.sl;
694d60cad5SIra Weiny 	entry->rqpn = wr->remote_qpn;
704d60cad5SIra Weiny 	entry->rqkey = wr->remote_qkey;
714d60cad5SIra Weiny 	entry->dlid = rdma_ah_get_dlid(&attr);
724d60cad5SIra Weiny }
734d60cad5SIra Weiny #endif
744d60cad5SIra Weiny 
7516933955SRoland Dreier static int mad_sendq_size = IB_MAD_QP_SEND_SIZE;
7616933955SRoland Dreier static int mad_recvq_size = IB_MAD_QP_RECV_SIZE;
77b76aabc3SHal Rosenstock 
78b76aabc3SHal Rosenstock module_param_named(send_queue_size, mad_sendq_size, int, 0444);
79b76aabc3SHal Rosenstock MODULE_PARM_DESC(send_queue_size, "Size of send queue in number of work requests");
80b76aabc3SHal Rosenstock module_param_named(recv_queue_size, mad_recvq_size, int, 0444);
81b76aabc3SHal Rosenstock MODULE_PARM_DESC(recv_queue_size, "Size of receive queue in number of work requests");
82b76aabc3SHal Rosenstock 
83949a2370SMatthew Wilcox static DEFINE_XARRAY_ALLOC1(ib_mad_clients);
84949a2370SMatthew Wilcox static u32 ib_mad_client_next;
851da177e4SLinus Torvalds static struct list_head ib_mad_port_list;
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds /* Port list lock */
886276e08aSRoland Dreier static DEFINE_SPINLOCK(ib_mad_port_list_lock);
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds /* Forward declarations */
911da177e4SLinus Torvalds static int method_in_use(struct ib_mad_mgmt_method_table **method,
921da177e4SLinus Torvalds 			 struct ib_mad_reg_req *mad_reg_req);
931da177e4SLinus Torvalds static void remove_mad_reg_req(struct ib_mad_agent_private *priv);
941da177e4SLinus Torvalds static struct ib_mad_agent_private *find_mad_agent(
951da177e4SLinus Torvalds 					struct ib_mad_port_private *port_priv,
96d94bd266SIra Weiny 					const struct ib_mad_hdr *mad);
971da177e4SLinus Torvalds static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info,
981da177e4SLinus Torvalds 				    struct ib_mad_private *mad);
991da177e4SLinus Torvalds static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv);
100c4028958SDavid Howells static void timeout_sends(struct work_struct *work);
101c4028958SDavid Howells static void local_completions(struct work_struct *work);
1021da177e4SLinus Torvalds static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req,
1031da177e4SLinus Torvalds 			      struct ib_mad_agent_private *agent_priv,
1041da177e4SLinus Torvalds 			      u8 mgmt_class);
1051da177e4SLinus Torvalds static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req,
1061da177e4SLinus Torvalds 			   struct ib_mad_agent_private *agent_priv);
107d53e11fdSChristoph Hellwig static bool ib_mad_send_error(struct ib_mad_port_private *port_priv,
108d53e11fdSChristoph Hellwig 			      struct ib_wc *wc);
109d53e11fdSChristoph Hellwig static void ib_mad_send_done(struct ib_cq *cq, struct ib_wc *wc);
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds /*
1121da177e4SLinus Torvalds  * Returns a ib_mad_port_private structure or NULL for a device/port
1131da177e4SLinus Torvalds  * Assumes ib_mad_port_list_lock is being held
1141da177e4SLinus Torvalds  */
1151da177e4SLinus Torvalds static inline struct ib_mad_port_private *
__ib_get_mad_port(struct ib_device * device,u32 port_num)1161fb7f897SMark Bloch __ib_get_mad_port(struct ib_device *device, u32 port_num)
1171da177e4SLinus Torvalds {
1181da177e4SLinus Torvalds 	struct ib_mad_port_private *entry;
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 	list_for_each_entry(entry, &ib_mad_port_list, port_list) {
1211da177e4SLinus Torvalds 		if (entry->device == device && entry->port_num == port_num)
1221da177e4SLinus Torvalds 			return entry;
1231da177e4SLinus Torvalds 	}
1241da177e4SLinus Torvalds 	return NULL;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds /*
1281da177e4SLinus Torvalds  * Wrapper function to return a ib_mad_port_private structure or NULL
1291da177e4SLinus Torvalds  * for a device/port
1301da177e4SLinus Torvalds  */
1311da177e4SLinus Torvalds static inline struct ib_mad_port_private *
ib_get_mad_port(struct ib_device * device,u32 port_num)1321fb7f897SMark Bloch ib_get_mad_port(struct ib_device *device, u32 port_num)
1331da177e4SLinus Torvalds {
1341da177e4SLinus Torvalds 	struct ib_mad_port_private *entry;
1351da177e4SLinus Torvalds 	unsigned long flags;
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 	spin_lock_irqsave(&ib_mad_port_list_lock, flags);
1381da177e4SLinus Torvalds 	entry = __ib_get_mad_port(device, port_num);
1391da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	return entry;
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds 
convert_mgmt_class(u8 mgmt_class)1441da177e4SLinus Torvalds static inline u8 convert_mgmt_class(u8 mgmt_class)
1451da177e4SLinus Torvalds {
1461da177e4SLinus Torvalds 	/* Alias IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE to 0 */
1471da177e4SLinus Torvalds 	return mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE ?
1481da177e4SLinus Torvalds 		0 : mgmt_class;
1491da177e4SLinus Torvalds }
1501da177e4SLinus Torvalds 
get_spl_qp_index(enum ib_qp_type qp_type)1511da177e4SLinus Torvalds static int get_spl_qp_index(enum ib_qp_type qp_type)
1521da177e4SLinus Torvalds {
153b6eb7011SWenpeng Liang 	switch (qp_type) {
1541da177e4SLinus Torvalds 	case IB_QPT_SMI:
1551da177e4SLinus Torvalds 		return 0;
1561da177e4SLinus Torvalds 	case IB_QPT_GSI:
1571da177e4SLinus Torvalds 		return 1;
1581da177e4SLinus Torvalds 	default:
1591da177e4SLinus Torvalds 		return -1;
1601da177e4SLinus Torvalds 	}
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds 
vendor_class_index(u8 mgmt_class)1631da177e4SLinus Torvalds static int vendor_class_index(u8 mgmt_class)
1641da177e4SLinus Torvalds {
1651da177e4SLinus Torvalds 	return mgmt_class - IB_MGMT_CLASS_VENDOR_RANGE2_START;
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds 
is_vendor_class(u8 mgmt_class)1681da177e4SLinus Torvalds static int is_vendor_class(u8 mgmt_class)
1691da177e4SLinus Torvalds {
1701da177e4SLinus Torvalds 	if ((mgmt_class < IB_MGMT_CLASS_VENDOR_RANGE2_START) ||
1711da177e4SLinus Torvalds 	    (mgmt_class > IB_MGMT_CLASS_VENDOR_RANGE2_END))
1721da177e4SLinus Torvalds 		return 0;
1731da177e4SLinus Torvalds 	return 1;
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds 
is_vendor_oui(char * oui)1761da177e4SLinus Torvalds static int is_vendor_oui(char *oui)
1771da177e4SLinus Torvalds {
1781da177e4SLinus Torvalds 	if (oui[0] || oui[1] || oui[2])
1791da177e4SLinus Torvalds 		return 1;
1801da177e4SLinus Torvalds 	return 0;
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
is_vendor_method_in_use(struct ib_mad_mgmt_vendor_class * vendor_class,struct ib_mad_reg_req * mad_reg_req)1831da177e4SLinus Torvalds static int is_vendor_method_in_use(
1841da177e4SLinus Torvalds 		struct ib_mad_mgmt_vendor_class *vendor_class,
1851da177e4SLinus Torvalds 		struct ib_mad_reg_req *mad_reg_req)
1861da177e4SLinus Torvalds {
1871da177e4SLinus Torvalds 	struct ib_mad_mgmt_method_table *method;
1881da177e4SLinus Torvalds 	int i;
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	for (i = 0; i < MAX_MGMT_OUI; i++) {
1911da177e4SLinus Torvalds 		if (!memcmp(vendor_class->oui[i], mad_reg_req->oui, 3)) {
1921da177e4SLinus Torvalds 			method = vendor_class->method_table[i];
1931da177e4SLinus Torvalds 			if (method) {
1941da177e4SLinus Torvalds 				if (method_in_use(&method, mad_reg_req))
1951da177e4SLinus Torvalds 					return 1;
1961da177e4SLinus Torvalds 				else
1971da177e4SLinus Torvalds 					break;
1981da177e4SLinus Torvalds 			}
1991da177e4SLinus Torvalds 		}
2001da177e4SLinus Torvalds 	}
2011da177e4SLinus Torvalds 	return 0;
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds 
ib_response_mad(const struct ib_mad_hdr * hdr)20496909308SIra Weiny int ib_response_mad(const struct ib_mad_hdr *hdr)
2052527e681SSean Hefty {
20696909308SIra Weiny 	return ((hdr->method & IB_MGMT_METHOD_RESP) ||
20796909308SIra Weiny 		(hdr->method == IB_MGMT_METHOD_TRAP_REPRESS) ||
20896909308SIra Weiny 		((hdr->mgmt_class == IB_MGMT_CLASS_BM) &&
20996909308SIra Weiny 		 (hdr->attr_mod & IB_BM_ATTR_MOD_RESP)));
2102527e681SSean Hefty }
2112527e681SSean Hefty EXPORT_SYMBOL(ib_response_mad);
2122527e681SSean Hefty 
2131da177e4SLinus Torvalds /*
2141da177e4SLinus Torvalds  * ib_register_mad_agent - Register to send/receive MADs
2150c271c43SMatthew Wilcox  *
2160c271c43SMatthew Wilcox  * Context: Process context.
2171da177e4SLinus Torvalds  */
ib_register_mad_agent(struct ib_device * device,u32 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,u32 registration_flags)2181da177e4SLinus Torvalds struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
2191fb7f897SMark Bloch 					   u32 port_num,
2201da177e4SLinus Torvalds 					   enum ib_qp_type qp_type,
2211da177e4SLinus Torvalds 					   struct ib_mad_reg_req *mad_reg_req,
2221da177e4SLinus Torvalds 					   u8 rmpp_version,
2231da177e4SLinus Torvalds 					   ib_mad_send_handler send_handler,
2241da177e4SLinus Torvalds 					   ib_mad_recv_handler recv_handler,
2250f29b46dSIra Weiny 					   void *context,
2260f29b46dSIra Weiny 					   u32 registration_flags)
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds 	struct ib_mad_port_private *port_priv;
2291da177e4SLinus Torvalds 	struct ib_mad_agent *ret = ERR_PTR(-EINVAL);
2301da177e4SLinus Torvalds 	struct ib_mad_agent_private *mad_agent_priv;
2311da177e4SLinus Torvalds 	struct ib_mad_reg_req *reg_req = NULL;
2321da177e4SLinus Torvalds 	struct ib_mad_mgmt_class_table *class;
2331da177e4SLinus Torvalds 	struct ib_mad_mgmt_vendor_class_table *vendor;
2341da177e4SLinus Torvalds 	struct ib_mad_mgmt_vendor_class *vendor_class;
2351da177e4SLinus Torvalds 	struct ib_mad_mgmt_method_table *method;
2361da177e4SLinus Torvalds 	int ret2, qpn;
2371da177e4SLinus Torvalds 	u8 mgmt_class, vclass;
2381da177e4SLinus Torvalds 
239798bba01SParav Pandit 	if ((qp_type == IB_QPT_SMI && !rdma_cap_ib_smi(device, port_num)) ||
240798bba01SParav Pandit 	    (qp_type == IB_QPT_GSI && !rdma_cap_ib_cm(device, port_num)))
241798bba01SParav Pandit 		return ERR_PTR(-EPROTONOSUPPORT);
242798bba01SParav Pandit 
2431da177e4SLinus Torvalds 	/* Validate parameters */
2441da177e4SLinus Torvalds 	qpn = get_spl_qp_index(qp_type);
2459ad13a42SIra Weiny 	if (qpn == -1) {
246f9d08f1eSParav Pandit 		dev_dbg_ratelimited(&device->dev, "%s: invalid QP Type %d\n",
247f9d08f1eSParav Pandit 				    __func__, qp_type);
2481da177e4SLinus Torvalds 		goto error1;
2499ad13a42SIra Weiny 	}
2501da177e4SLinus Torvalds 
2519ad13a42SIra Weiny 	if (rmpp_version && rmpp_version != IB_MGMT_RMPP_VERSION) {
252f9d08f1eSParav Pandit 		dev_dbg_ratelimited(&device->dev,
253f9d08f1eSParav Pandit 				    "%s: invalid RMPP Version %u\n",
254f9d08f1eSParav Pandit 				    __func__, rmpp_version);
255fa619a77SHal Rosenstock 		goto error1;
2569ad13a42SIra Weiny 	}
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	/* Validate MAD registration request if supplied */
2591da177e4SLinus Torvalds 	if (mad_reg_req) {
2609ad13a42SIra Weiny 		if (mad_reg_req->mgmt_class_version >= MAX_MGMT_VERSION) {
261f9d08f1eSParav Pandit 			dev_dbg_ratelimited(&device->dev,
262f9d08f1eSParav Pandit 					    "%s: invalid Class Version %u\n",
263f9d08f1eSParav Pandit 					    __func__,
2649ad13a42SIra Weiny 					    mad_reg_req->mgmt_class_version);
2651da177e4SLinus Torvalds 			goto error1;
2669ad13a42SIra Weiny 		}
2679ad13a42SIra Weiny 		if (!recv_handler) {
268f9d08f1eSParav Pandit 			dev_dbg_ratelimited(&device->dev,
269f9d08f1eSParav Pandit 					    "%s: no recv_handler\n", __func__);
2701da177e4SLinus Torvalds 			goto error1;
2719ad13a42SIra Weiny 		}
2721da177e4SLinus Torvalds 		if (mad_reg_req->mgmt_class >= MAX_MGMT_CLASS) {
2731da177e4SLinus Torvalds 			/*
2741da177e4SLinus Torvalds 			 * IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE is the only
2751da177e4SLinus Torvalds 			 * one in this range currently allowed
2761da177e4SLinus Torvalds 			 */
2771da177e4SLinus Torvalds 			if (mad_reg_req->mgmt_class !=
2789ad13a42SIra Weiny 			    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
279f9d08f1eSParav Pandit 				dev_dbg_ratelimited(&device->dev,
280f9d08f1eSParav Pandit 					"%s: Invalid Mgmt Class 0x%x\n",
281f9d08f1eSParav Pandit 					__func__, mad_reg_req->mgmt_class);
2821da177e4SLinus Torvalds 				goto error1;
2839ad13a42SIra Weiny 			}
2841da177e4SLinus Torvalds 		} else if (mad_reg_req->mgmt_class == 0) {
2851da177e4SLinus Torvalds 			/*
2861da177e4SLinus Torvalds 			 * Class 0 is reserved in IBA and is used for
2871da177e4SLinus Torvalds 			 * aliasing of IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE
2881da177e4SLinus Torvalds 			 */
289f9d08f1eSParav Pandit 			dev_dbg_ratelimited(&device->dev,
290f9d08f1eSParav Pandit 					    "%s: Invalid Mgmt Class 0\n",
291f9d08f1eSParav Pandit 					    __func__);
2921da177e4SLinus Torvalds 			goto error1;
2931da177e4SLinus Torvalds 		} else if (is_vendor_class(mad_reg_req->mgmt_class)) {
2941da177e4SLinus Torvalds 			/*
2951da177e4SLinus Torvalds 			 * If class is in "new" vendor range,
2961da177e4SLinus Torvalds 			 * ensure supplied OUI is not zero
2971da177e4SLinus Torvalds 			 */
2989ad13a42SIra Weiny 			if (!is_vendor_oui(mad_reg_req->oui)) {
299f9d08f1eSParav Pandit 				dev_dbg_ratelimited(&device->dev,
300f9d08f1eSParav Pandit 					"%s: No OUI specified for class 0x%x\n",
301f9d08f1eSParav Pandit 					__func__,
3029ad13a42SIra Weiny 					mad_reg_req->mgmt_class);
3031da177e4SLinus Torvalds 				goto error1;
3041da177e4SLinus Torvalds 			}
3059ad13a42SIra Weiny 		}
306618a3c03SHal Rosenstock 		/* Make sure class supplied is consistent with RMPP */
30764cb9c6aSHal Rosenstock 		if (!ib_is_mad_class_rmpp(mad_reg_req->mgmt_class)) {
3089ad13a42SIra Weiny 			if (rmpp_version) {
309f9d08f1eSParav Pandit 				dev_dbg_ratelimited(&device->dev,
310f9d08f1eSParav Pandit 					"%s: RMPP version for non-RMPP class 0x%x\n",
311f9d08f1eSParav Pandit 					__func__, mad_reg_req->mgmt_class);
312618a3c03SHal Rosenstock 				goto error1;
313618a3c03SHal Rosenstock 			}
3149ad13a42SIra Weiny 		}
3151471cb6cSIra Weiny 
3161da177e4SLinus Torvalds 		/* Make sure class supplied is consistent with QP type */
3171da177e4SLinus Torvalds 		if (qp_type == IB_QPT_SMI) {
3181da177e4SLinus Torvalds 			if ((mad_reg_req->mgmt_class !=
3191da177e4SLinus Torvalds 					IB_MGMT_CLASS_SUBN_LID_ROUTED) &&
3201da177e4SLinus Torvalds 			    (mad_reg_req->mgmt_class !=
3219ad13a42SIra Weiny 					IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) {
322f9d08f1eSParav Pandit 				dev_dbg_ratelimited(&device->dev,
323f9d08f1eSParav Pandit 					"%s: Invalid SM QP type: class 0x%x\n",
324f9d08f1eSParav Pandit 					__func__, mad_reg_req->mgmt_class);
3251da177e4SLinus Torvalds 				goto error1;
3269ad13a42SIra Weiny 			}
3271da177e4SLinus Torvalds 		} else {
3281da177e4SLinus Torvalds 			if ((mad_reg_req->mgmt_class ==
3291da177e4SLinus Torvalds 					IB_MGMT_CLASS_SUBN_LID_ROUTED) ||
3301da177e4SLinus Torvalds 			    (mad_reg_req->mgmt_class ==
3319ad13a42SIra Weiny 					IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) {
332f9d08f1eSParav Pandit 				dev_dbg_ratelimited(&device->dev,
333f9d08f1eSParav Pandit 					"%s: Invalid GS QP type: class 0x%x\n",
334f9d08f1eSParav Pandit 					__func__, mad_reg_req->mgmt_class);
3351da177e4SLinus Torvalds 				goto error1;
3361da177e4SLinus Torvalds 			}
3379ad13a42SIra Weiny 		}
3381da177e4SLinus Torvalds 	} else {
3391da177e4SLinus Torvalds 		/* No registration request supplied */
3401da177e4SLinus Torvalds 		if (!send_handler)
3411da177e4SLinus Torvalds 			goto error1;
3421471cb6cSIra Weiny 		if (registration_flags & IB_MAD_USER_RMPP)
3431471cb6cSIra Weiny 			goto error1;
3441da177e4SLinus Torvalds 	}
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 	/* Validate device and port */
3471da177e4SLinus Torvalds 	port_priv = ib_get_mad_port(device, port_num);
3481da177e4SLinus Torvalds 	if (!port_priv) {
3493cea7b4aSWenpeng Liang 		dev_dbg_ratelimited(&device->dev, "%s: Invalid port %u\n",
350f9d08f1eSParav Pandit 				    __func__, port_num);
3511da177e4SLinus Torvalds 		ret = ERR_PTR(-ENODEV);
3521da177e4SLinus Torvalds 		goto error1;
3531da177e4SLinus Torvalds 	}
3541da177e4SLinus Torvalds 
355c8367c4cSIra Weiny 	/* Verify the QP requested is supported. For example, Ethernet devices
356f9d08f1eSParav Pandit 	 * will not have QP0.
357f9d08f1eSParav Pandit 	 */
358c8367c4cSIra Weiny 	if (!port_priv->qp_info[qpn].qp) {
359f9d08f1eSParav Pandit 		dev_dbg_ratelimited(&device->dev, "%s: QP %d not supported\n",
360f9d08f1eSParav Pandit 				    __func__, qpn);
361c8367c4cSIra Weiny 		ret = ERR_PTR(-EPROTONOSUPPORT);
362c8367c4cSIra Weiny 		goto error1;
363c8367c4cSIra Weiny 	}
364c8367c4cSIra Weiny 
3651da177e4SLinus Torvalds 	/* Allocate structures */
366de6eb66bSRoland Dreier 	mad_agent_priv = kzalloc(sizeof *mad_agent_priv, GFP_KERNEL);
3671da177e4SLinus Torvalds 	if (!mad_agent_priv) {
3681da177e4SLinus Torvalds 		ret = ERR_PTR(-ENOMEM);
3691da177e4SLinus Torvalds 		goto error1;
3701da177e4SLinus Torvalds 	}
371b82cab6bSHal Rosenstock 
3721da177e4SLinus Torvalds 	if (mad_reg_req) {
3739893e742SJulia Lawall 		reg_req = kmemdup(mad_reg_req, sizeof *reg_req, GFP_KERNEL);
3741da177e4SLinus Torvalds 		if (!reg_req) {
3751da177e4SLinus Torvalds 			ret = ERR_PTR(-ENOMEM);
376b82cab6bSHal Rosenstock 			goto error3;
3771da177e4SLinus Torvalds 		}
3781da177e4SLinus Torvalds 	}
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 	/* Now, fill in the various structures */
3811da177e4SLinus Torvalds 	mad_agent_priv->qp_info = &port_priv->qp_info[qpn];
3821da177e4SLinus Torvalds 	mad_agent_priv->reg_req = reg_req;
383fa619a77SHal Rosenstock 	mad_agent_priv->agent.rmpp_version = rmpp_version;
3841da177e4SLinus Torvalds 	mad_agent_priv->agent.device = device;
3851da177e4SLinus Torvalds 	mad_agent_priv->agent.recv_handler = recv_handler;
3861da177e4SLinus Torvalds 	mad_agent_priv->agent.send_handler = send_handler;
3871da177e4SLinus Torvalds 	mad_agent_priv->agent.context = context;
3881da177e4SLinus Torvalds 	mad_agent_priv->agent.qp = port_priv->qp_info[qpn].qp;
3891da177e4SLinus Torvalds 	mad_agent_priv->agent.port_num = port_num;
3900f29b46dSIra Weiny 	mad_agent_priv->agent.flags = registration_flags;
391d9620a4cSRalph Campbell 	spin_lock_init(&mad_agent_priv->lock);
392d9620a4cSRalph Campbell 	INIT_LIST_HEAD(&mad_agent_priv->send_list);
393d9620a4cSRalph Campbell 	INIT_LIST_HEAD(&mad_agent_priv->wait_list);
394d9620a4cSRalph Campbell 	INIT_LIST_HEAD(&mad_agent_priv->done_list);
395d9620a4cSRalph Campbell 	INIT_LIST_HEAD(&mad_agent_priv->rmpp_list);
396d9620a4cSRalph Campbell 	INIT_DELAYED_WORK(&mad_agent_priv->timed_work, timeout_sends);
397d9620a4cSRalph Campbell 	INIT_LIST_HEAD(&mad_agent_priv->local_list);
398d9620a4cSRalph Campbell 	INIT_WORK(&mad_agent_priv->local_work, local_completions);
399e41c4253SShay Drory 	refcount_set(&mad_agent_priv->refcount, 1);
400d9620a4cSRalph Campbell 	init_completion(&mad_agent_priv->comp);
4011da177e4SLinus Torvalds 
40247a2b338SDaniel Jurgens 	ret2 = ib_mad_agent_security_setup(&mad_agent_priv->agent, qp_type);
40347a2b338SDaniel Jurgens 	if (ret2) {
40447a2b338SDaniel Jurgens 		ret = ERR_PTR(ret2);
40547a2b338SDaniel Jurgens 		goto error4;
40647a2b338SDaniel Jurgens 	}
40747a2b338SDaniel Jurgens 
408949a2370SMatthew Wilcox 	/*
409949a2370SMatthew Wilcox 	 * The mlx4 driver uses the top byte to distinguish which virtual
410949a2370SMatthew Wilcox 	 * function generated the MAD, so we must avoid using it.
411949a2370SMatthew Wilcox 	 */
412949a2370SMatthew Wilcox 	ret2 = xa_alloc_cyclic(&ib_mad_clients, &mad_agent_priv->agent.hi_tid,
413949a2370SMatthew Wilcox 			mad_agent_priv, XA_LIMIT(0, (1 << 24) - 1),
414949a2370SMatthew Wilcox 			&ib_mad_client_next, GFP_KERNEL);
4159a41e38aSwilly@infradead.org 	if (ret2 < 0) {
4169a41e38aSwilly@infradead.org 		ret = ERR_PTR(ret2);
4179a41e38aSwilly@infradead.org 		goto error5;
4189a41e38aSwilly@infradead.org 	}
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 	/*
4211da177e4SLinus Torvalds 	 * Make sure MAD registration (if supplied)
4221da177e4SLinus Torvalds 	 * is non overlapping with any existing ones
4231da177e4SLinus Torvalds 	 */
4249a41e38aSwilly@infradead.org 	spin_lock_irq(&port_priv->reg_lock);
4251da177e4SLinus Torvalds 	if (mad_reg_req) {
4261da177e4SLinus Torvalds 		mgmt_class = convert_mgmt_class(mad_reg_req->mgmt_class);
4271da177e4SLinus Torvalds 		if (!is_vendor_class(mgmt_class)) {
4281da177e4SLinus Torvalds 			class = port_priv->version[mad_reg_req->
4291da177e4SLinus Torvalds 						   mgmt_class_version].class;
4301da177e4SLinus Torvalds 			if (class) {
4311da177e4SLinus Torvalds 				method = class->method_table[mgmt_class];
4321da177e4SLinus Torvalds 				if (method) {
4331da177e4SLinus Torvalds 					if (method_in_use(&method,
4341da177e4SLinus Torvalds 							   mad_reg_req))
4359a41e38aSwilly@infradead.org 						goto error6;
4361da177e4SLinus Torvalds 				}
4371da177e4SLinus Torvalds 			}
4381da177e4SLinus Torvalds 			ret2 = add_nonoui_reg_req(mad_reg_req, mad_agent_priv,
4391da177e4SLinus Torvalds 						  mgmt_class);
4401da177e4SLinus Torvalds 		} else {
4411da177e4SLinus Torvalds 			/* "New" vendor class range */
4421da177e4SLinus Torvalds 			vendor = port_priv->version[mad_reg_req->
4431da177e4SLinus Torvalds 						    mgmt_class_version].vendor;
4441da177e4SLinus Torvalds 			if (vendor) {
4451da177e4SLinus Torvalds 				vclass = vendor_class_index(mgmt_class);
4461da177e4SLinus Torvalds 				vendor_class = vendor->vendor_class[vclass];
4471da177e4SLinus Torvalds 				if (vendor_class) {
4481da177e4SLinus Torvalds 					if (is_vendor_method_in_use(
4491da177e4SLinus Torvalds 							vendor_class,
4501da177e4SLinus Torvalds 							mad_reg_req))
4519a41e38aSwilly@infradead.org 						goto error6;
4521da177e4SLinus Torvalds 				}
4531da177e4SLinus Torvalds 			}
4541da177e4SLinus Torvalds 			ret2 = add_oui_reg_req(mad_reg_req, mad_agent_priv);
4551da177e4SLinus Torvalds 		}
4561da177e4SLinus Torvalds 		if (ret2) {
4571da177e4SLinus Torvalds 			ret = ERR_PTR(ret2);
4589a41e38aSwilly@infradead.org 			goto error6;
4591da177e4SLinus Torvalds 		}
4601da177e4SLinus Torvalds 	}
4610c271c43SMatthew Wilcox 	spin_unlock_irq(&port_priv->reg_lock);
4621da177e4SLinus Torvalds 
4630e65bae2SIra Weiny 	trace_ib_mad_create_agent(mad_agent_priv);
4641da177e4SLinus Torvalds 	return &mad_agent_priv->agent;
4659a41e38aSwilly@infradead.org error6:
4660c271c43SMatthew Wilcox 	spin_unlock_irq(&port_priv->reg_lock);
467949a2370SMatthew Wilcox 	xa_erase(&ib_mad_clients, mad_agent_priv->agent.hi_tid);
4689a41e38aSwilly@infradead.org error5:
46947a2b338SDaniel Jurgens 	ib_mad_agent_security_cleanup(&mad_agent_priv->agent);
47047a2b338SDaniel Jurgens error4:
4711da177e4SLinus Torvalds 	kfree(reg_req);
472b82cab6bSHal Rosenstock error3:
4732012a116SAdrian Bunk 	kfree(mad_agent_priv);
4741da177e4SLinus Torvalds error1:
4751da177e4SLinus Torvalds 	return ret;
4761da177e4SLinus Torvalds }
4771da177e4SLinus Torvalds EXPORT_SYMBOL(ib_register_mad_agent);
4781da177e4SLinus Torvalds 
deref_mad_agent(struct ib_mad_agent_private * mad_agent_priv)4791b52fa98SSean Hefty static inline void deref_mad_agent(struct ib_mad_agent_private *mad_agent_priv)
4801b52fa98SSean Hefty {
481e41c4253SShay Drory 	if (refcount_dec_and_test(&mad_agent_priv->refcount))
4821b52fa98SSean Hefty 		complete(&mad_agent_priv->comp);
4831b52fa98SSean Hefty }
4841b52fa98SSean Hefty 
unregister_mad_agent(struct ib_mad_agent_private * mad_agent_priv)4851da177e4SLinus Torvalds static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv)
4861da177e4SLinus Torvalds {
4871da177e4SLinus Torvalds 	struct ib_mad_port_private *port_priv;
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 	/* Note that we could still be handling received MADs */
4900e65bae2SIra Weiny 	trace_ib_mad_unregister_agent(mad_agent_priv);
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 	/*
4931da177e4SLinus Torvalds 	 * Canceling all sends results in dropping received response
4941da177e4SLinus Torvalds 	 * MADs, preventing us from queuing additional work
4951da177e4SLinus Torvalds 	 */
4961da177e4SLinus Torvalds 	cancel_mads(mad_agent_priv);
4971da177e4SLinus Torvalds 	port_priv = mad_agent_priv->qp_info->port_priv;
4981da177e4SLinus Torvalds 	cancel_delayed_work(&mad_agent_priv->timed_work);
4991da177e4SLinus Torvalds 
5000c271c43SMatthew Wilcox 	spin_lock_irq(&port_priv->reg_lock);
5011da177e4SLinus Torvalds 	remove_mad_reg_req(mad_agent_priv);
5020c271c43SMatthew Wilcox 	spin_unlock_irq(&port_priv->reg_lock);
503949a2370SMatthew Wilcox 	xa_erase(&ib_mad_clients, mad_agent_priv->agent.hi_tid);
5041da177e4SLinus Torvalds 
505b82cab6bSHal Rosenstock 	flush_workqueue(port_priv->wq);
5061da177e4SLinus Torvalds 
5071b52fa98SSean Hefty 	deref_mad_agent(mad_agent_priv);
5081b52fa98SSean Hefty 	wait_for_completion(&mad_agent_priv->comp);
509116a1b9fSShay Drory 	ib_cancel_rmpp_recvs(mad_agent_priv);
5101da177e4SLinus Torvalds 
51147a2b338SDaniel Jurgens 	ib_mad_agent_security_cleanup(&mad_agent_priv->agent);
51247a2b338SDaniel Jurgens 
5131da177e4SLinus Torvalds 	kfree(mad_agent_priv->reg_req);
5149a41e38aSwilly@infradead.org 	kfree_rcu(mad_agent_priv, rcu);
5151da177e4SLinus Torvalds }
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds /*
5181da177e4SLinus Torvalds  * ib_unregister_mad_agent - Unregisters a client from using MAD services
5190c271c43SMatthew Wilcox  *
5200c271c43SMatthew Wilcox  * Context: Process context.
5211da177e4SLinus Torvalds  */
ib_unregister_mad_agent(struct ib_mad_agent * mad_agent)5228d2216beSZhu Yanjun void ib_unregister_mad_agent(struct ib_mad_agent *mad_agent)
5231da177e4SLinus Torvalds {
5241da177e4SLinus Torvalds 	struct ib_mad_agent_private *mad_agent_priv;
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 	mad_agent_priv = container_of(mad_agent,
5271da177e4SLinus Torvalds 				      struct ib_mad_agent_private,
5281da177e4SLinus Torvalds 				      agent);
5291da177e4SLinus Torvalds 	unregister_mad_agent(mad_agent_priv);
5301da177e4SLinus Torvalds }
5311da177e4SLinus Torvalds EXPORT_SYMBOL(ib_unregister_mad_agent);
5321da177e4SLinus Torvalds 
dequeue_mad(struct ib_mad_list_head * mad_list)5331da177e4SLinus Torvalds static void dequeue_mad(struct ib_mad_list_head *mad_list)
5341da177e4SLinus Torvalds {
5351da177e4SLinus Torvalds 	struct ib_mad_queue *mad_queue;
5361da177e4SLinus Torvalds 	unsigned long flags;
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 	mad_queue = mad_list->mad_queue;
5391da177e4SLinus Torvalds 	spin_lock_irqsave(&mad_queue->lock, flags);
5401da177e4SLinus Torvalds 	list_del(&mad_list->list);
5411da177e4SLinus Torvalds 	mad_queue->count--;
5421da177e4SLinus Torvalds 	spin_unlock_irqrestore(&mad_queue->lock, flags);
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds 
build_smp_wc(struct ib_qp * qp,struct ib_cqe * cqe,u16 slid,u16 pkey_index,u32 port_num,struct ib_wc * wc)545d53e11fdSChristoph Hellwig static void build_smp_wc(struct ib_qp *qp, struct ib_cqe *cqe, u16 slid,
5461fb7f897SMark Bloch 		u16 pkey_index, u32 port_num, struct ib_wc *wc)
5471da177e4SLinus Torvalds {
5481da177e4SLinus Torvalds 	memset(wc, 0, sizeof *wc);
549d53e11fdSChristoph Hellwig 	wc->wr_cqe = cqe;
5501da177e4SLinus Torvalds 	wc->status = IB_WC_SUCCESS;
5511da177e4SLinus Torvalds 	wc->opcode = IB_WC_RECV;
5521da177e4SLinus Torvalds 	wc->pkey_index = pkey_index;
5531da177e4SLinus Torvalds 	wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh);
5541da177e4SLinus Torvalds 	wc->src_qp = IB_QP0;
555062dbb69SMichael S. Tsirkin 	wc->qp = qp;
5561da177e4SLinus Torvalds 	wc->slid = slid;
5571da177e4SLinus Torvalds 	wc->sl = 0;
5581da177e4SLinus Torvalds 	wc->dlid_path_bits = 0;
5591da177e4SLinus Torvalds 	wc->port_num = port_num;
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds 
mad_priv_size(const struct ib_mad_private * mp)562c9082e51SIra Weiny static size_t mad_priv_size(const struct ib_mad_private *mp)
563c9082e51SIra Weiny {
564c9082e51SIra Weiny 	return sizeof(struct ib_mad_private) + mp->mad_size;
565c9082e51SIra Weiny }
566c9082e51SIra Weiny 
alloc_mad_private(size_t mad_size,gfp_t flags)567c9082e51SIra Weiny static struct ib_mad_private *alloc_mad_private(size_t mad_size, gfp_t flags)
568c9082e51SIra Weiny {
569c9082e51SIra Weiny 	size_t size = sizeof(struct ib_mad_private) + mad_size;
570c9082e51SIra Weiny 	struct ib_mad_private *ret = kzalloc(size, flags);
571c9082e51SIra Weiny 
572c9082e51SIra Weiny 	if (ret)
573c9082e51SIra Weiny 		ret->mad_size = mad_size;
574c9082e51SIra Weiny 
575c9082e51SIra Weiny 	return ret;
576c9082e51SIra Weiny }
577c9082e51SIra Weiny 
port_mad_size(const struct ib_mad_port_private * port_priv)578c9082e51SIra Weiny static size_t port_mad_size(const struct ib_mad_port_private *port_priv)
579c9082e51SIra Weiny {
580c9082e51SIra Weiny 	return rdma_max_mad_size(port_priv->device, port_priv->port_num);
581c9082e51SIra Weiny }
582c9082e51SIra Weiny 
mad_priv_dma_size(const struct ib_mad_private * mp)583c9082e51SIra Weiny static size_t mad_priv_dma_size(const struct ib_mad_private *mp)
584c9082e51SIra Weiny {
585c9082e51SIra Weiny 	return sizeof(struct ib_grh) + mp->mad_size;
586c9082e51SIra Weiny }
587c9082e51SIra Weiny 
5881da177e4SLinus Torvalds /*
5891da177e4SLinus Torvalds  * Return 0 if SMP is to be sent
5901da177e4SLinus Torvalds  * Return 1 if SMP was consumed locally (whether or not solicited)
5911da177e4SLinus Torvalds  * Return < 0 if error
5921da177e4SLinus Torvalds  */
handle_outgoing_dr_smp(struct ib_mad_agent_private * mad_agent_priv,struct ib_mad_send_wr_private * mad_send_wr)5931da177e4SLinus Torvalds static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
59434816ad9SSean Hefty 				  struct ib_mad_send_wr_private *mad_send_wr)
5951da177e4SLinus Torvalds {
596de493d47SHal Rosenstock 	int ret = 0;
59734816ad9SSean Hefty 	struct ib_smp *smp = mad_send_wr->send_buf.mad;
5988e4349d1SIra Weiny 	struct opa_smp *opa_smp = (struct opa_smp *)smp;
5991da177e4SLinus Torvalds 	unsigned long flags;
6001da177e4SLinus Torvalds 	struct ib_mad_local_private *local;
6011da177e4SLinus Torvalds 	struct ib_mad_private *mad_priv;
6021da177e4SLinus Torvalds 	struct ib_mad_port_private *port_priv;
6031da177e4SLinus Torvalds 	struct ib_mad_agent_private *recv_mad_agent = NULL;
6041da177e4SLinus Torvalds 	struct ib_device *device = mad_agent_priv->agent.device;
6051fb7f897SMark Bloch 	u32 port_num;
6061da177e4SLinus Torvalds 	struct ib_wc mad_wc;
607e622f2f4SChristoph Hellwig 	struct ib_ud_wr *send_wr = &mad_send_wr->send_wr;
608c9082e51SIra Weiny 	size_t mad_size = port_mad_size(mad_agent_priv->qp_info->port_priv);
6094cd7c947SIra Weiny 	u16 out_mad_pkey_index = 0;
6108e4349d1SIra Weiny 	u16 drslid;
6118e4349d1SIra Weiny 	bool opa = rdma_cap_opa_mad(mad_agent_priv->qp_info->port_priv->device,
6128e4349d1SIra Weiny 				    mad_agent_priv->qp_info->port_priv->port_num);
6131da177e4SLinus Torvalds 
6144139032bSHal Rosenstock 	if (rdma_cap_ib_switch(device) &&
6151bae4dbfSHal Rosenstock 	    smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
616e622f2f4SChristoph Hellwig 		port_num = send_wr->port_num;
6171bae4dbfSHal Rosenstock 	else
6181bae4dbfSHal Rosenstock 		port_num = mad_agent_priv->agent.port_num;
6191bae4dbfSHal Rosenstock 
6208cf3f04fSRalph Campbell 	/*
6218cf3f04fSRalph Campbell 	 * Directed route handling starts if the initial LID routed part of
6228cf3f04fSRalph Campbell 	 * a request or the ending LID routed part of a response is empty.
6238cf3f04fSRalph Campbell 	 * If we are at the start of the LID routed part, don't update the
6248cf3f04fSRalph Campbell 	 * hop_ptr or hop_cnt.  See section 14.2.2, Vol 1 IB spec.
6258cf3f04fSRalph Campbell 	 */
6269fa240bbSHal Rosenstock 	if (opa && smp->class_version == OPA_SM_CLASS_VERSION) {
6278e4349d1SIra Weiny 		u32 opa_drslid;
6288e4349d1SIra Weiny 
6292ccfbb70SIra Weiny 		trace_ib_mad_handle_out_opa_smi(opa_smp);
6302ccfbb70SIra Weiny 
6318e4349d1SIra Weiny 		if ((opa_get_smp_direction(opa_smp)
6328e4349d1SIra Weiny 		     ? opa_smp->route.dr.dr_dlid : opa_smp->route.dr.dr_slid) ==
6338e4349d1SIra Weiny 		     OPA_LID_PERMISSIVE &&
6344139032bSHal Rosenstock 		     opa_smi_handle_dr_smp_send(opa_smp,
6354139032bSHal Rosenstock 						rdma_cap_ib_switch(device),
6368e4349d1SIra Weiny 						port_num) == IB_SMI_DISCARD) {
6378e4349d1SIra Weiny 			ret = -EINVAL;
6388e4349d1SIra Weiny 			dev_err(&device->dev, "OPA Invalid directed route\n");
6398e4349d1SIra Weiny 			goto out;
6408e4349d1SIra Weiny 		}
6418e4349d1SIra Weiny 		opa_drslid = be32_to_cpu(opa_smp->route.dr.dr_slid);
642cd4cd565SIra Weiny 		if (opa_drslid != be32_to_cpu(OPA_LID_PERMISSIVE) &&
6438e4349d1SIra Weiny 		    opa_drslid & 0xffff0000) {
6448e4349d1SIra Weiny 			ret = -EINVAL;
6458e4349d1SIra Weiny 			dev_err(&device->dev, "OPA Invalid dr_slid 0x%x\n",
6468e4349d1SIra Weiny 			       opa_drslid);
6478e4349d1SIra Weiny 			goto out;
6488e4349d1SIra Weiny 		}
6498e4349d1SIra Weiny 		drslid = (u16)(opa_drslid & 0x0000ffff);
6508e4349d1SIra Weiny 
6518e4349d1SIra Weiny 		/* Check to post send on QP or process locally */
6528e4349d1SIra Weiny 		if (opa_smi_check_local_smp(opa_smp, device) == IB_SMI_DISCARD &&
6538e4349d1SIra Weiny 		    opa_smi_check_local_returning_smp(opa_smp, device) == IB_SMI_DISCARD)
6548e4349d1SIra Weiny 			goto out;
6558e4349d1SIra Weiny 	} else {
6562ccfbb70SIra Weiny 		trace_ib_mad_handle_out_ib_smi(smp);
6572ccfbb70SIra Weiny 
6588cf3f04fSRalph Campbell 		if ((ib_get_smp_direction(smp) ? smp->dr_dlid : smp->dr_slid) ==
6598cf3f04fSRalph Campbell 		     IB_LID_PERMISSIVE &&
6604139032bSHal Rosenstock 		     smi_handle_dr_smp_send(smp, rdma_cap_ib_switch(device), port_num) ==
661de493d47SHal Rosenstock 		     IB_SMI_DISCARD) {
6621da177e4SLinus Torvalds 			ret = -EINVAL;
6637ef5d4b0SIra Weiny 			dev_err(&device->dev, "Invalid directed route\n");
6641da177e4SLinus Torvalds 			goto out;
6651da177e4SLinus Torvalds 		}
6668e4349d1SIra Weiny 		drslid = be16_to_cpu(smp->dr_slid);
667de493d47SHal Rosenstock 
6681da177e4SLinus Torvalds 		/* Check to post send on QP or process locally */
669727792daSSteve Welch 		if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD &&
670727792daSSteve Welch 		    smi_check_local_returning_smp(smp, device) == IB_SMI_DISCARD)
6711da177e4SLinus Torvalds 			goto out;
6728e4349d1SIra Weiny 	}
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	local = kmalloc(sizeof *local, GFP_ATOMIC);
6751da177e4SLinus Torvalds 	if (!local) {
6761da177e4SLinus Torvalds 		ret = -ENOMEM;
6771da177e4SLinus Torvalds 		goto out;
6781da177e4SLinus Torvalds 	}
6791da177e4SLinus Torvalds 	local->mad_priv = NULL;
6801da177e4SLinus Torvalds 	local->recv_mad_agent = NULL;
681c9082e51SIra Weiny 	mad_priv = alloc_mad_private(mad_size, GFP_ATOMIC);
6821da177e4SLinus Torvalds 	if (!mad_priv) {
6831da177e4SLinus Torvalds 		ret = -ENOMEM;
6841da177e4SLinus Torvalds 		kfree(local);
6851da177e4SLinus Torvalds 		goto out;
6861da177e4SLinus Torvalds 	}
6871da177e4SLinus Torvalds 
688062dbb69SMichael S. Tsirkin 	build_smp_wc(mad_agent_priv->agent.qp,
689d53e11fdSChristoph Hellwig 		     send_wr->wr.wr_cqe, drslid,
690e622f2f4SChristoph Hellwig 		     send_wr->pkey_index,
691e622f2f4SChristoph Hellwig 		     send_wr->port_num, &mad_wc);
6921da177e4SLinus Torvalds 
6938e4349d1SIra Weiny 	if (opa && smp->base_version == OPA_MGMT_BASE_VERSION) {
6948e4349d1SIra Weiny 		mad_wc.byte_len = mad_send_wr->send_buf.hdr_len
6958e4349d1SIra Weiny 					+ mad_send_wr->send_buf.data_len
6968e4349d1SIra Weiny 					+ sizeof(struct ib_grh);
6978e4349d1SIra Weiny 	}
6988e4349d1SIra Weiny 
6991da177e4SLinus Torvalds 	/* No GRH for DR SMP */
7003023a1e9SKamal Heib 	ret = device->ops.process_mad(device, 0, port_num, &mad_wc, NULL,
701e26e7b88SLeon Romanovsky 				      (const struct ib_mad *)smp,
702e26e7b88SLeon Romanovsky 				      (struct ib_mad *)mad_priv->mad, &mad_size,
703e26e7b88SLeon Romanovsky 				      &out_mad_pkey_index);
704b6eb7011SWenpeng Liang 	switch (ret) {
7051da177e4SLinus Torvalds 	case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY:
706c9082e51SIra Weiny 		if (ib_response_mad((const struct ib_mad_hdr *)mad_priv->mad) &&
7071da177e4SLinus Torvalds 		    mad_agent_priv->agent.recv_handler) {
7081da177e4SLinus Torvalds 			local->mad_priv = mad_priv;
7091da177e4SLinus Torvalds 			local->recv_mad_agent = mad_agent_priv;
7101da177e4SLinus Torvalds 			/*
7111da177e4SLinus Torvalds 			 * Reference MAD agent until receive
7121da177e4SLinus Torvalds 			 * side of local completion handled
7131da177e4SLinus Torvalds 			 */
714e41c4253SShay Drory 			refcount_inc(&mad_agent_priv->refcount);
7151da177e4SLinus Torvalds 		} else
716c9082e51SIra Weiny 			kfree(mad_priv);
7171da177e4SLinus Torvalds 		break;
7181da177e4SLinus Torvalds 	case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED:
719c9082e51SIra Weiny 		kfree(mad_priv);
7204780c195SRalph Campbell 		break;
7211da177e4SLinus Torvalds 	case IB_MAD_RESULT_SUCCESS:
7221da177e4SLinus Torvalds 		/* Treat like an incoming receive MAD */
7231da177e4SLinus Torvalds 		port_priv = ib_get_mad_port(mad_agent_priv->agent.device,
7241da177e4SLinus Torvalds 					    mad_agent_priv->agent.port_num);
7251da177e4SLinus Torvalds 		if (port_priv) {
726c9082e51SIra Weiny 			memcpy(mad_priv->mad, smp, mad_priv->mad_size);
7271da177e4SLinus Torvalds 			recv_mad_agent = find_mad_agent(port_priv,
728c9082e51SIra Weiny 						        (const struct ib_mad_hdr *)mad_priv->mad);
7291da177e4SLinus Torvalds 		}
7301da177e4SLinus Torvalds 		if (!port_priv || !recv_mad_agent) {
7314780c195SRalph Campbell 			/*
7324780c195SRalph Campbell 			 * No receiving agent so drop packet and
7334780c195SRalph Campbell 			 * generate send completion.
7344780c195SRalph Campbell 			 */
735c9082e51SIra Weiny 			kfree(mad_priv);
7364780c195SRalph Campbell 			break;
7371da177e4SLinus Torvalds 		}
7381da177e4SLinus Torvalds 		local->mad_priv = mad_priv;
7391da177e4SLinus Torvalds 		local->recv_mad_agent = recv_mad_agent;
7401da177e4SLinus Torvalds 		break;
7411da177e4SLinus Torvalds 	default:
742c9082e51SIra Weiny 		kfree(mad_priv);
7431da177e4SLinus Torvalds 		kfree(local);
7441da177e4SLinus Torvalds 		ret = -EINVAL;
7451da177e4SLinus Torvalds 		goto out;
7461da177e4SLinus Torvalds 	}
7471da177e4SLinus Torvalds 
74834816ad9SSean Hefty 	local->mad_send_wr = mad_send_wr;
7498e4349d1SIra Weiny 	if (opa) {
750e622f2f4SChristoph Hellwig 		local->mad_send_wr->send_wr.pkey_index = out_mad_pkey_index;
7518e4349d1SIra Weiny 		local->return_wc_byte_len = mad_size;
7528e4349d1SIra Weiny 	}
7531da177e4SLinus Torvalds 	/* Reference MAD agent until send side of local completion handled */
754e41c4253SShay Drory 	refcount_inc(&mad_agent_priv->refcount);
7551da177e4SLinus Torvalds 	/* Queue local completion to local list */
7561da177e4SLinus Torvalds 	spin_lock_irqsave(&mad_agent_priv->lock, flags);
7571da177e4SLinus Torvalds 	list_add_tail(&local->completion_list, &mad_agent_priv->local_list);
7581da177e4SLinus Torvalds 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
7591da177e4SLinus Torvalds 	queue_work(mad_agent_priv->qp_info->port_priv->wq,
7601da177e4SLinus Torvalds 		   &mad_agent_priv->local_work);
7611da177e4SLinus Torvalds 	ret = 1;
7621da177e4SLinus Torvalds out:
7631da177e4SLinus Torvalds 	return ret;
7641da177e4SLinus Torvalds }
7651da177e4SLinus Torvalds 
get_pad_size(int hdr_len,int data_len,size_t mad_size)766548ead17SIra Weiny static int get_pad_size(int hdr_len, int data_len, size_t mad_size)
767824c8ae7SHal Rosenstock {
768824c8ae7SHal Rosenstock 	int seg_size, pad;
769824c8ae7SHal Rosenstock 
770548ead17SIra Weiny 	seg_size = mad_size - hdr_len;
771824c8ae7SHal Rosenstock 	if (data_len && seg_size) {
772824c8ae7SHal Rosenstock 		pad = seg_size - data_len % seg_size;
773f36e1793SJack Morgenstein 		return pad == seg_size ? 0 : pad;
774824c8ae7SHal Rosenstock 	} else
775f36e1793SJack Morgenstein 		return seg_size;
776f36e1793SJack Morgenstein }
777f36e1793SJack Morgenstein 
free_send_rmpp_list(struct ib_mad_send_wr_private * mad_send_wr)778f36e1793SJack Morgenstein static void free_send_rmpp_list(struct ib_mad_send_wr_private *mad_send_wr)
779f36e1793SJack Morgenstein {
780f36e1793SJack Morgenstein 	struct ib_rmpp_segment *s, *t;
781f36e1793SJack Morgenstein 
782f36e1793SJack Morgenstein 	list_for_each_entry_safe(s, t, &mad_send_wr->rmpp_list, list) {
783f36e1793SJack Morgenstein 		list_del(&s->list);
784f36e1793SJack Morgenstein 		kfree(s);
785f36e1793SJack Morgenstein 	}
786f36e1793SJack Morgenstein }
787f36e1793SJack Morgenstein 
alloc_send_rmpp_list(struct ib_mad_send_wr_private * send_wr,size_t mad_size,gfp_t gfp_mask)788f36e1793SJack Morgenstein static int alloc_send_rmpp_list(struct ib_mad_send_wr_private *send_wr,
789548ead17SIra Weiny 				size_t mad_size, gfp_t gfp_mask)
790f36e1793SJack Morgenstein {
791f36e1793SJack Morgenstein 	struct ib_mad_send_buf *send_buf = &send_wr->send_buf;
792f36e1793SJack Morgenstein 	struct ib_rmpp_mad *rmpp_mad = send_buf->mad;
793f36e1793SJack Morgenstein 	struct ib_rmpp_segment *seg = NULL;
794f36e1793SJack Morgenstein 	int left, seg_size, pad;
795f36e1793SJack Morgenstein 
796548ead17SIra Weiny 	send_buf->seg_size = mad_size - send_buf->hdr_len;
797548ead17SIra Weiny 	send_buf->seg_rmpp_size = mad_size - IB_MGMT_RMPP_HDR;
798f36e1793SJack Morgenstein 	seg_size = send_buf->seg_size;
799f36e1793SJack Morgenstein 	pad = send_wr->pad;
800f36e1793SJack Morgenstein 
801f36e1793SJack Morgenstein 	/* Allocate data segments. */
802f36e1793SJack Morgenstein 	for (left = send_buf->data_len + pad; left > 0; left -= seg_size) {
803f36e1793SJack Morgenstein 		seg = kmalloc(sizeof(*seg) + seg_size, gfp_mask);
804f36e1793SJack Morgenstein 		if (!seg) {
805f36e1793SJack Morgenstein 			free_send_rmpp_list(send_wr);
806f36e1793SJack Morgenstein 			return -ENOMEM;
807f36e1793SJack Morgenstein 		}
808f36e1793SJack Morgenstein 		seg->num = ++send_buf->seg_count;
809f36e1793SJack Morgenstein 		list_add_tail(&seg->list, &send_wr->rmpp_list);
810f36e1793SJack Morgenstein 	}
811f36e1793SJack Morgenstein 
812f36e1793SJack Morgenstein 	/* Zero any padding */
813f36e1793SJack Morgenstein 	if (pad)
814f36e1793SJack Morgenstein 		memset(seg->data + seg_size - pad, 0, pad);
815f36e1793SJack Morgenstein 
816f36e1793SJack Morgenstein 	rmpp_mad->rmpp_hdr.rmpp_version = send_wr->mad_agent_priv->
817f36e1793SJack Morgenstein 					  agent.rmpp_version;
818f36e1793SJack Morgenstein 	rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA;
819f36e1793SJack Morgenstein 	ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
820f36e1793SJack Morgenstein 
821f36e1793SJack Morgenstein 	send_wr->cur_seg = container_of(send_wr->rmpp_list.next,
822f36e1793SJack Morgenstein 					struct ib_rmpp_segment, list);
823f36e1793SJack Morgenstein 	send_wr->last_ack_seg = send_wr->cur_seg;
824f36e1793SJack Morgenstein 	return 0;
825824c8ae7SHal Rosenstock }
826824c8ae7SHal Rosenstock 
ib_mad_kernel_rmpp_agent(const struct ib_mad_agent * agent)827f766c58fSIra Weiny int ib_mad_kernel_rmpp_agent(const struct ib_mad_agent *agent)
8281471cb6cSIra Weiny {
8291471cb6cSIra Weiny 	return agent->rmpp_version && !(agent->flags & IB_MAD_USER_RMPP);
8301471cb6cSIra Weiny }
8311471cb6cSIra Weiny EXPORT_SYMBOL(ib_mad_kernel_rmpp_agent);
8321471cb6cSIra Weiny 
ib_create_send_mad(struct ib_mad_agent * mad_agent,u32 remote_qpn,u16 pkey_index,int rmpp_active,int hdr_len,int data_len,gfp_t gfp_mask,u8 base_version)833824c8ae7SHal Rosenstock struct ib_mad_send_buf *ib_create_send_mad(struct ib_mad_agent *mad_agent,
834824c8ae7SHal Rosenstock 					   u32 remote_qpn, u16 pkey_index,
835f681967aSWenpeng Liang 					   int rmpp_active, int hdr_len,
836f681967aSWenpeng Liang 					   int data_len, gfp_t gfp_mask,
837da2dfaa3SIra Weiny 					   u8 base_version)
838824c8ae7SHal Rosenstock {
839824c8ae7SHal Rosenstock 	struct ib_mad_agent_private *mad_agent_priv;
84034816ad9SSean Hefty 	struct ib_mad_send_wr_private *mad_send_wr;
841f36e1793SJack Morgenstein 	int pad, message_size, ret, size;
842824c8ae7SHal Rosenstock 	void *buf;
843548ead17SIra Weiny 	size_t mad_size;
844548ead17SIra Weiny 	bool opa;
845824c8ae7SHal Rosenstock 
84634816ad9SSean Hefty 	mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private,
84734816ad9SSean Hefty 				      agent);
848548ead17SIra Weiny 
849548ead17SIra Weiny 	opa = rdma_cap_opa_mad(mad_agent->device, mad_agent->port_num);
850548ead17SIra Weiny 
851548ead17SIra Weiny 	if (opa && base_version == OPA_MGMT_BASE_VERSION)
852548ead17SIra Weiny 		mad_size = sizeof(struct opa_mad);
853548ead17SIra Weiny 	else
854548ead17SIra Weiny 		mad_size = sizeof(struct ib_mad);
855548ead17SIra Weiny 
856548ead17SIra Weiny 	pad = get_pad_size(hdr_len, data_len, mad_size);
857f36e1793SJack Morgenstein 	message_size = hdr_len + data_len + pad;
858824c8ae7SHal Rosenstock 
8591471cb6cSIra Weiny 	if (ib_mad_kernel_rmpp_agent(mad_agent)) {
860548ead17SIra Weiny 		if (!rmpp_active && message_size > mad_size)
8611471cb6cSIra Weiny 			return ERR_PTR(-EINVAL);
8621471cb6cSIra Weiny 	} else
863548ead17SIra Weiny 		if (rmpp_active || message_size > mad_size)
864fa619a77SHal Rosenstock 			return ERR_PTR(-EINVAL);
865fa619a77SHal Rosenstock 
866548ead17SIra Weiny 	size = rmpp_active ? hdr_len : mad_size;
867f36e1793SJack Morgenstein 	buf = kzalloc(sizeof *mad_send_wr + size, gfp_mask);
868824c8ae7SHal Rosenstock 	if (!buf)
869824c8ae7SHal Rosenstock 		return ERR_PTR(-ENOMEM);
870824c8ae7SHal Rosenstock 
871f36e1793SJack Morgenstein 	mad_send_wr = buf + size;
872f36e1793SJack Morgenstein 	INIT_LIST_HEAD(&mad_send_wr->rmpp_list);
87334816ad9SSean Hefty 	mad_send_wr->send_buf.mad = buf;
874f36e1793SJack Morgenstein 	mad_send_wr->send_buf.hdr_len = hdr_len;
875f36e1793SJack Morgenstein 	mad_send_wr->send_buf.data_len = data_len;
876f36e1793SJack Morgenstein 	mad_send_wr->pad = pad;
877824c8ae7SHal Rosenstock 
87834816ad9SSean Hefty 	mad_send_wr->mad_agent_priv = mad_agent_priv;
879f36e1793SJack Morgenstein 	mad_send_wr->sg_list[0].length = hdr_len;
8804be90bc6SJason Gunthorpe 	mad_send_wr->sg_list[0].lkey = mad_agent->qp->pd->local_dma_lkey;
881548ead17SIra Weiny 
882548ead17SIra Weiny 	/* OPA MADs don't have to be the full 2048 bytes */
883548ead17SIra Weiny 	if (opa && base_version == OPA_MGMT_BASE_VERSION &&
884548ead17SIra Weiny 	    data_len < mad_size - hdr_len)
885548ead17SIra Weiny 		mad_send_wr->sg_list[1].length = data_len;
886548ead17SIra Weiny 	else
887548ead17SIra Weiny 		mad_send_wr->sg_list[1].length = mad_size - hdr_len;
888548ead17SIra Weiny 
8894be90bc6SJason Gunthorpe 	mad_send_wr->sg_list[1].lkey = mad_agent->qp->pd->local_dma_lkey;
890824c8ae7SHal Rosenstock 
891d53e11fdSChristoph Hellwig 	mad_send_wr->mad_list.cqe.done = ib_mad_send_done;
892d53e11fdSChristoph Hellwig 
893d53e11fdSChristoph Hellwig 	mad_send_wr->send_wr.wr.wr_cqe = &mad_send_wr->mad_list.cqe;
894e622f2f4SChristoph Hellwig 	mad_send_wr->send_wr.wr.sg_list = mad_send_wr->sg_list;
895e622f2f4SChristoph Hellwig 	mad_send_wr->send_wr.wr.num_sge = 2;
896e622f2f4SChristoph Hellwig 	mad_send_wr->send_wr.wr.opcode = IB_WR_SEND;
897e622f2f4SChristoph Hellwig 	mad_send_wr->send_wr.wr.send_flags = IB_SEND_SIGNALED;
898e622f2f4SChristoph Hellwig 	mad_send_wr->send_wr.remote_qpn = remote_qpn;
899e622f2f4SChristoph Hellwig 	mad_send_wr->send_wr.remote_qkey = IB_QP_SET_QKEY;
900e622f2f4SChristoph Hellwig 	mad_send_wr->send_wr.pkey_index = pkey_index;
901fa619a77SHal Rosenstock 
902fa619a77SHal Rosenstock 	if (rmpp_active) {
903548ead17SIra Weiny 		ret = alloc_send_rmpp_list(mad_send_wr, mad_size, gfp_mask);
904f36e1793SJack Morgenstein 		if (ret) {
905f36e1793SJack Morgenstein 			kfree(buf);
906f36e1793SJack Morgenstein 			return ERR_PTR(ret);
907f36e1793SJack Morgenstein 		}
908fa619a77SHal Rosenstock 	}
909fa619a77SHal Rosenstock 
91034816ad9SSean Hefty 	mad_send_wr->send_buf.mad_agent = mad_agent;
911e41c4253SShay Drory 	refcount_inc(&mad_agent_priv->refcount);
91234816ad9SSean Hefty 	return &mad_send_wr->send_buf;
913824c8ae7SHal Rosenstock }
914824c8ae7SHal Rosenstock EXPORT_SYMBOL(ib_create_send_mad);
915824c8ae7SHal Rosenstock 
ib_get_mad_data_offset(u8 mgmt_class)916618a3c03SHal Rosenstock int ib_get_mad_data_offset(u8 mgmt_class)
917618a3c03SHal Rosenstock {
918618a3c03SHal Rosenstock 	if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM)
919618a3c03SHal Rosenstock 		return IB_MGMT_SA_HDR;
920618a3c03SHal Rosenstock 	else if ((mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) ||
921618a3c03SHal Rosenstock 		 (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) ||
922618a3c03SHal Rosenstock 		 (mgmt_class == IB_MGMT_CLASS_BIS))
923618a3c03SHal Rosenstock 		return IB_MGMT_DEVICE_HDR;
924618a3c03SHal Rosenstock 	else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
925618a3c03SHal Rosenstock 		 (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))
926618a3c03SHal Rosenstock 		return IB_MGMT_VENDOR_HDR;
927618a3c03SHal Rosenstock 	else
928618a3c03SHal Rosenstock 		return IB_MGMT_MAD_HDR;
929618a3c03SHal Rosenstock }
930618a3c03SHal Rosenstock EXPORT_SYMBOL(ib_get_mad_data_offset);
931618a3c03SHal Rosenstock 
ib_is_mad_class_rmpp(u8 mgmt_class)932618a3c03SHal Rosenstock int ib_is_mad_class_rmpp(u8 mgmt_class)
933618a3c03SHal Rosenstock {
934618a3c03SHal Rosenstock 	if ((mgmt_class == IB_MGMT_CLASS_SUBN_ADM) ||
935618a3c03SHal Rosenstock 	    (mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) ||
936618a3c03SHal Rosenstock 	    (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) ||
937618a3c03SHal Rosenstock 	    (mgmt_class == IB_MGMT_CLASS_BIS) ||
938618a3c03SHal Rosenstock 	    ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
939618a3c03SHal Rosenstock 	     (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)))
940618a3c03SHal Rosenstock 		return 1;
941618a3c03SHal Rosenstock 	return 0;
942618a3c03SHal Rosenstock }
943618a3c03SHal Rosenstock EXPORT_SYMBOL(ib_is_mad_class_rmpp);
944618a3c03SHal Rosenstock 
ib_get_rmpp_segment(struct ib_mad_send_buf * send_buf,int seg_num)945f36e1793SJack Morgenstein void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num)
946f36e1793SJack Morgenstein {
947f36e1793SJack Morgenstein 	struct ib_mad_send_wr_private *mad_send_wr;
948f36e1793SJack Morgenstein 	struct list_head *list;
949f36e1793SJack Morgenstein 
950f36e1793SJack Morgenstein 	mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private,
951f36e1793SJack Morgenstein 				   send_buf);
952f36e1793SJack Morgenstein 	list = &mad_send_wr->cur_seg->list;
953f36e1793SJack Morgenstein 
954f36e1793SJack Morgenstein 	if (mad_send_wr->cur_seg->num < seg_num) {
955f36e1793SJack Morgenstein 		list_for_each_entry(mad_send_wr->cur_seg, list, list)
956f36e1793SJack Morgenstein 			if (mad_send_wr->cur_seg->num == seg_num)
957f36e1793SJack Morgenstein 				break;
958f36e1793SJack Morgenstein 	} else if (mad_send_wr->cur_seg->num > seg_num) {
959f36e1793SJack Morgenstein 		list_for_each_entry_reverse(mad_send_wr->cur_seg, list, list)
960f36e1793SJack Morgenstein 			if (mad_send_wr->cur_seg->num == seg_num)
961f36e1793SJack Morgenstein 				break;
962f36e1793SJack Morgenstein 	}
963f36e1793SJack Morgenstein 	return mad_send_wr->cur_seg->data;
964f36e1793SJack Morgenstein }
965f36e1793SJack Morgenstein EXPORT_SYMBOL(ib_get_rmpp_segment);
966f36e1793SJack Morgenstein 
ib_get_payload(struct ib_mad_send_wr_private * mad_send_wr)967f36e1793SJack Morgenstein static inline void *ib_get_payload(struct ib_mad_send_wr_private *mad_send_wr)
968f36e1793SJack Morgenstein {
969f36e1793SJack Morgenstein 	if (mad_send_wr->send_buf.seg_count)
970f36e1793SJack Morgenstein 		return ib_get_rmpp_segment(&mad_send_wr->send_buf,
971f36e1793SJack Morgenstein 					   mad_send_wr->seg_num);
972f36e1793SJack Morgenstein 	else
973f36e1793SJack Morgenstein 		return mad_send_wr->send_buf.mad +
974f36e1793SJack Morgenstein 		       mad_send_wr->send_buf.hdr_len;
975f36e1793SJack Morgenstein }
976f36e1793SJack Morgenstein 
ib_free_send_mad(struct ib_mad_send_buf * send_buf)977824c8ae7SHal Rosenstock void ib_free_send_mad(struct ib_mad_send_buf *send_buf)
978824c8ae7SHal Rosenstock {
979824c8ae7SHal Rosenstock 	struct ib_mad_agent_private *mad_agent_priv;
980f36e1793SJack Morgenstein 	struct ib_mad_send_wr_private *mad_send_wr;
981824c8ae7SHal Rosenstock 
982824c8ae7SHal Rosenstock 	mad_agent_priv = container_of(send_buf->mad_agent,
983824c8ae7SHal Rosenstock 				      struct ib_mad_agent_private, agent);
984f36e1793SJack Morgenstein 	mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private,
985f36e1793SJack Morgenstein 				   send_buf);
986824c8ae7SHal Rosenstock 
987f36e1793SJack Morgenstein 	free_send_rmpp_list(mad_send_wr);
988f36e1793SJack Morgenstein 	kfree(send_buf->mad);
9891b52fa98SSean Hefty 	deref_mad_agent(mad_agent_priv);
990824c8ae7SHal Rosenstock }
991824c8ae7SHal Rosenstock EXPORT_SYMBOL(ib_free_send_mad);
992824c8ae7SHal Rosenstock 
ib_send_mad(struct ib_mad_send_wr_private * mad_send_wr)993fa619a77SHal Rosenstock int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr)
9941da177e4SLinus Torvalds {
9951da177e4SLinus Torvalds 	struct ib_mad_qp_info *qp_info;
996cabe3cbcSHal Rosenstock 	struct list_head *list;
99734816ad9SSean Hefty 	struct ib_mad_agent *mad_agent;
99834816ad9SSean Hefty 	struct ib_sge *sge;
9991da177e4SLinus Torvalds 	unsigned long flags;
10001da177e4SLinus Torvalds 	int ret;
10011da177e4SLinus Torvalds 
1002f8197a4eSHal Rosenstock 	/* Set WR ID to find mad_send_wr upon completion */
1003d760ce8fSHal Rosenstock 	qp_info = mad_send_wr->mad_agent_priv->qp_info;
10041da177e4SLinus Torvalds 	mad_send_wr->mad_list.mad_queue = &qp_info->send_queue;
1005d53e11fdSChristoph Hellwig 	mad_send_wr->mad_list.cqe.done = ib_mad_send_done;
1006d53e11fdSChristoph Hellwig 	mad_send_wr->send_wr.wr.wr_cqe = &mad_send_wr->mad_list.cqe;
10071da177e4SLinus Torvalds 
100834816ad9SSean Hefty 	mad_agent = mad_send_wr->send_buf.mad_agent;
100934816ad9SSean Hefty 	sge = mad_send_wr->sg_list;
10101527106fSRalph Campbell 	sge[0].addr = ib_dma_map_single(mad_agent->device,
1011f36e1793SJack Morgenstein 					mad_send_wr->send_buf.mad,
1012f36e1793SJack Morgenstein 					sge[0].length,
101334816ad9SSean Hefty 					DMA_TO_DEVICE);
10142c34e68fSYan Burman 	if (unlikely(ib_dma_mapping_error(mad_agent->device, sge[0].addr)))
10152c34e68fSYan Burman 		return -ENOMEM;
10162c34e68fSYan Burman 
10171527106fSRalph Campbell 	mad_send_wr->header_mapping = sge[0].addr;
1018f36e1793SJack Morgenstein 
10191527106fSRalph Campbell 	sge[1].addr = ib_dma_map_single(mad_agent->device,
1020f36e1793SJack Morgenstein 					ib_get_payload(mad_send_wr),
1021f36e1793SJack Morgenstein 					sge[1].length,
1022f36e1793SJack Morgenstein 					DMA_TO_DEVICE);
10232c34e68fSYan Burman 	if (unlikely(ib_dma_mapping_error(mad_agent->device, sge[1].addr))) {
10242c34e68fSYan Burman 		ib_dma_unmap_single(mad_agent->device,
10252c34e68fSYan Burman 				    mad_send_wr->header_mapping,
10262c34e68fSYan Burman 				    sge[0].length, DMA_TO_DEVICE);
10272c34e68fSYan Burman 		return -ENOMEM;
10282c34e68fSYan Burman 	}
10291527106fSRalph Campbell 	mad_send_wr->payload_mapping = sge[1].addr;
103034816ad9SSean Hefty 
10311da177e4SLinus Torvalds 	spin_lock_irqsave(&qp_info->send_queue.lock, flags);
1032cabe3cbcSHal Rosenstock 	if (qp_info->send_queue.count < qp_info->send_queue.max_active) {
10334d60cad5SIra Weiny 		trace_ib_mad_ib_send_mad(mad_send_wr, qp_info);
1034e622f2f4SChristoph Hellwig 		ret = ib_post_send(mad_agent->qp, &mad_send_wr->send_wr.wr,
10351fec77bfSBart Van Assche 				   NULL);
1036cabe3cbcSHal Rosenstock 		list = &qp_info->send_queue.list;
10371da177e4SLinus Torvalds 	} else {
10381da177e4SLinus Torvalds 		ret = 0;
1039cabe3cbcSHal Rosenstock 		list = &qp_info->overflow_list;
10401da177e4SLinus Torvalds 	}
1041cabe3cbcSHal Rosenstock 
1042cabe3cbcSHal Rosenstock 	if (!ret) {
1043cabe3cbcSHal Rosenstock 		qp_info->send_queue.count++;
1044cabe3cbcSHal Rosenstock 		list_add_tail(&mad_send_wr->mad_list.list, list);
1045cabe3cbcSHal Rosenstock 	}
1046cabe3cbcSHal Rosenstock 	spin_unlock_irqrestore(&qp_info->send_queue.lock, flags);
1047f36e1793SJack Morgenstein 	if (ret) {
10481527106fSRalph Campbell 		ib_dma_unmap_single(mad_agent->device,
10491527106fSRalph Campbell 				    mad_send_wr->header_mapping,
1050f36e1793SJack Morgenstein 				    sge[0].length, DMA_TO_DEVICE);
10511527106fSRalph Campbell 		ib_dma_unmap_single(mad_agent->device,
10521527106fSRalph Campbell 				    mad_send_wr->payload_mapping,
1053f36e1793SJack Morgenstein 				    sge[1].length, DMA_TO_DEVICE);
1054f36e1793SJack Morgenstein 	}
10551da177e4SLinus Torvalds 	return ret;
10561da177e4SLinus Torvalds }
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds /*
10591da177e4SLinus Torvalds  * ib_post_send_mad - Posts MAD(s) to the send queue of the QP associated
10601da177e4SLinus Torvalds  *  with the registered client
10611da177e4SLinus Torvalds  */
ib_post_send_mad(struct ib_mad_send_buf * send_buf,struct ib_mad_send_buf ** bad_send_buf)106234816ad9SSean Hefty int ib_post_send_mad(struct ib_mad_send_buf *send_buf,
106334816ad9SSean Hefty 		     struct ib_mad_send_buf **bad_send_buf)
10641da177e4SLinus Torvalds {
10651da177e4SLinus Torvalds 	struct ib_mad_agent_private *mad_agent_priv;
106634816ad9SSean Hefty 	struct ib_mad_send_buf *next_send_buf;
106734816ad9SSean Hefty 	struct ib_mad_send_wr_private *mad_send_wr;
106834816ad9SSean Hefty 	unsigned long flags;
106934816ad9SSean Hefty 	int ret = -EINVAL;
10701da177e4SLinus Torvalds 
10711da177e4SLinus Torvalds 	/* Walk list of send WRs and post each on send list */
107234816ad9SSean Hefty 	for (; send_buf; send_buf = next_send_buf) {
107334816ad9SSean Hefty 		mad_send_wr = container_of(send_buf,
107434816ad9SSean Hefty 					   struct ib_mad_send_wr_private,
107534816ad9SSean Hefty 					   send_buf);
107634816ad9SSean Hefty 		mad_agent_priv = mad_send_wr->mad_agent_priv;
10771da177e4SLinus Torvalds 
107847a2b338SDaniel Jurgens 		ret = ib_mad_enforce_security(mad_agent_priv,
107947a2b338SDaniel Jurgens 					      mad_send_wr->send_wr.pkey_index);
108047a2b338SDaniel Jurgens 		if (ret)
108147a2b338SDaniel Jurgens 			goto error;
108247a2b338SDaniel Jurgens 
108334816ad9SSean Hefty 		if (!send_buf->mad_agent->send_handler ||
108434816ad9SSean Hefty 		    (send_buf->timeout_ms &&
108534816ad9SSean Hefty 		     !send_buf->mad_agent->recv_handler)) {
108634816ad9SSean Hefty 			ret = -EINVAL;
108734816ad9SSean Hefty 			goto error;
10881da177e4SLinus Torvalds 		}
10891da177e4SLinus Torvalds 
1090618a3c03SHal Rosenstock 		if (!ib_is_mad_class_rmpp(((struct ib_mad_hdr *) send_buf->mad)->mgmt_class)) {
1091618a3c03SHal Rosenstock 			if (mad_agent_priv->agent.rmpp_version) {
1092618a3c03SHal Rosenstock 				ret = -EINVAL;
1093618a3c03SHal Rosenstock 				goto error;
1094618a3c03SHal Rosenstock 			}
1095618a3c03SHal Rosenstock 		}
1096618a3c03SHal Rosenstock 
10971da177e4SLinus Torvalds 		/*
10981da177e4SLinus Torvalds 		 * Save pointer to next work request to post in case the
10991da177e4SLinus Torvalds 		 * current one completes, and the user modifies the work
11001da177e4SLinus Torvalds 		 * request associated with the completion
11011da177e4SLinus Torvalds 		 */
110234816ad9SSean Hefty 		next_send_buf = send_buf->next;
1103e622f2f4SChristoph Hellwig 		mad_send_wr->send_wr.ah = send_buf->ah;
11041da177e4SLinus Torvalds 
110534816ad9SSean Hefty 		if (((struct ib_mad_hdr *) send_buf->mad)->mgmt_class ==
110634816ad9SSean Hefty 		    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
110734816ad9SSean Hefty 			ret = handle_outgoing_dr_smp(mad_agent_priv,
110834816ad9SSean Hefty 						     mad_send_wr);
11091da177e4SLinus Torvalds 			if (ret < 0)		/* error */
111034816ad9SSean Hefty 				goto error;
11111da177e4SLinus Torvalds 			else if (ret == 1)	/* locally consumed */
111234816ad9SSean Hefty 				continue;
11131da177e4SLinus Torvalds 		}
11141da177e4SLinus Torvalds 
111534816ad9SSean Hefty 		mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid;
11161da177e4SLinus Torvalds 		/* Timeout will be updated after send completes */
111734816ad9SSean Hefty 		mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms);
11184fc8cd49SSean Hefty 		mad_send_wr->max_retries = send_buf->retries;
11194fc8cd49SSean Hefty 		mad_send_wr->retries_left = send_buf->retries;
11204fc8cd49SSean Hefty 		send_buf->retries = 0;
112134816ad9SSean Hefty 		/* Reference for work request to QP + response */
11221da177e4SLinus Torvalds 		mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0);
11231da177e4SLinus Torvalds 		mad_send_wr->status = IB_WC_SUCCESS;
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds 		/* Reference MAD agent until send completes */
1126e41c4253SShay Drory 		refcount_inc(&mad_agent_priv->refcount);
11271da177e4SLinus Torvalds 		spin_lock_irqsave(&mad_agent_priv->lock, flags);
11281da177e4SLinus Torvalds 		list_add_tail(&mad_send_wr->agent_list,
11291da177e4SLinus Torvalds 			      &mad_agent_priv->send_list);
11301da177e4SLinus Torvalds 		spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
11311da177e4SLinus Torvalds 
11321471cb6cSIra Weiny 		if (ib_mad_kernel_rmpp_agent(&mad_agent_priv->agent)) {
1133fa619a77SHal Rosenstock 			ret = ib_send_rmpp_mad(mad_send_wr);
1134fa619a77SHal Rosenstock 			if (ret >= 0 && ret != IB_RMPP_RESULT_CONSUMED)
1135d760ce8fSHal Rosenstock 				ret = ib_send_mad(mad_send_wr);
1136fa619a77SHal Rosenstock 		} else
1137fa619a77SHal Rosenstock 			ret = ib_send_mad(mad_send_wr);
1138fa619a77SHal Rosenstock 		if (ret < 0) {
11391da177e4SLinus Torvalds 			/* Fail send request */
11401da177e4SLinus Torvalds 			spin_lock_irqsave(&mad_agent_priv->lock, flags);
11411da177e4SLinus Torvalds 			list_del(&mad_send_wr->agent_list);
11421da177e4SLinus Torvalds 			spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
1143b9af0e2dSShay Drory 			deref_mad_agent(mad_agent_priv);
114434816ad9SSean Hefty 			goto error;
11451da177e4SLinus Torvalds 		}
11461da177e4SLinus Torvalds 	}
11471da177e4SLinus Torvalds 	return 0;
114834816ad9SSean Hefty error:
114934816ad9SSean Hefty 	if (bad_send_buf)
115034816ad9SSean Hefty 		*bad_send_buf = send_buf;
11511da177e4SLinus Torvalds 	return ret;
11521da177e4SLinus Torvalds }
11531da177e4SLinus Torvalds EXPORT_SYMBOL(ib_post_send_mad);
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds /*
11561da177e4SLinus Torvalds  * ib_free_recv_mad - Returns data buffers used to receive
11571da177e4SLinus Torvalds  *  a MAD to the access layer
11581da177e4SLinus Torvalds  */
ib_free_recv_mad(struct ib_mad_recv_wc * mad_recv_wc)11591da177e4SLinus Torvalds void ib_free_recv_mad(struct ib_mad_recv_wc *mad_recv_wc)
11601da177e4SLinus Torvalds {
1161fa619a77SHal Rosenstock 	struct ib_mad_recv_buf *mad_recv_buf, *temp_recv_buf;
11621da177e4SLinus Torvalds 	struct ib_mad_private_header *mad_priv_hdr;
11631da177e4SLinus Torvalds 	struct ib_mad_private *priv;
1164fa619a77SHal Rosenstock 	struct list_head free_list;
11651da177e4SLinus Torvalds 
1166fa619a77SHal Rosenstock 	INIT_LIST_HEAD(&free_list);
1167fa619a77SHal Rosenstock 	list_splice_init(&mad_recv_wc->rmpp_list, &free_list);
11681da177e4SLinus Torvalds 
1169fa619a77SHal Rosenstock 	list_for_each_entry_safe(mad_recv_buf, temp_recv_buf,
1170fa619a77SHal Rosenstock 					&free_list, list) {
1171fa619a77SHal Rosenstock 		mad_recv_wc = container_of(mad_recv_buf, struct ib_mad_recv_wc,
1172fa619a77SHal Rosenstock 					   recv_buf);
11731da177e4SLinus Torvalds 		mad_priv_hdr = container_of(mad_recv_wc,
11741da177e4SLinus Torvalds 					    struct ib_mad_private_header,
11751da177e4SLinus Torvalds 					    recv_wc);
11761da177e4SLinus Torvalds 		priv = container_of(mad_priv_hdr, struct ib_mad_private,
11771da177e4SLinus Torvalds 				    header);
1178c9082e51SIra Weiny 		kfree(priv);
11791da177e4SLinus Torvalds 	}
1180fa619a77SHal Rosenstock }
11811da177e4SLinus Torvalds EXPORT_SYMBOL(ib_free_recv_mad);
11821da177e4SLinus Torvalds 
method_in_use(struct ib_mad_mgmt_method_table ** method,struct ib_mad_reg_req * mad_reg_req)11831da177e4SLinus Torvalds static int method_in_use(struct ib_mad_mgmt_method_table **method,
11841da177e4SLinus Torvalds 			 struct ib_mad_reg_req *mad_reg_req)
11851da177e4SLinus Torvalds {
11861da177e4SLinus Torvalds 	int i;
11871da177e4SLinus Torvalds 
118819b629f5SAkinobu Mita 	for_each_set_bit(i, mad_reg_req->method_mask, IB_MGMT_MAX_METHODS) {
11891da177e4SLinus Torvalds 		if ((*method)->agent[i]) {
11907ef5d4b0SIra Weiny 			pr_err("Method %d already in use\n", i);
11911da177e4SLinus Torvalds 			return -EINVAL;
11921da177e4SLinus Torvalds 		}
11931da177e4SLinus Torvalds 	}
11941da177e4SLinus Torvalds 	return 0;
11951da177e4SLinus Torvalds }
11961da177e4SLinus Torvalds 
allocate_method_table(struct ib_mad_mgmt_method_table ** method)11971da177e4SLinus Torvalds static int allocate_method_table(struct ib_mad_mgmt_method_table **method)
11981da177e4SLinus Torvalds {
11991da177e4SLinus Torvalds 	/* Allocate management method table */
1200de6eb66bSRoland Dreier 	*method = kzalloc(sizeof **method, GFP_ATOMIC);
120127162432SLeon Romanovsky 	return (*method) ? 0 : (-ENOMEM);
12021da177e4SLinus Torvalds }
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds /*
12051da177e4SLinus Torvalds  * Check to see if there are any methods still in use
12061da177e4SLinus Torvalds  */
check_method_table(struct ib_mad_mgmt_method_table * method)12071da177e4SLinus Torvalds static int check_method_table(struct ib_mad_mgmt_method_table *method)
12081da177e4SLinus Torvalds {
12091da177e4SLinus Torvalds 	int i;
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds 	for (i = 0; i < IB_MGMT_MAX_METHODS; i++)
12121da177e4SLinus Torvalds 		if (method->agent[i])
12131da177e4SLinus Torvalds 			return 1;
12141da177e4SLinus Torvalds 	return 0;
12151da177e4SLinus Torvalds }
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds /*
12181da177e4SLinus Torvalds  * Check to see if there are any method tables for this class still in use
12191da177e4SLinus Torvalds  */
check_class_table(struct ib_mad_mgmt_class_table * class)12201da177e4SLinus Torvalds static int check_class_table(struct ib_mad_mgmt_class_table *class)
12211da177e4SLinus Torvalds {
12221da177e4SLinus Torvalds 	int i;
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds 	for (i = 0; i < MAX_MGMT_CLASS; i++)
12251da177e4SLinus Torvalds 		if (class->method_table[i])
12261da177e4SLinus Torvalds 			return 1;
12271da177e4SLinus Torvalds 	return 0;
12281da177e4SLinus Torvalds }
12291da177e4SLinus Torvalds 
check_vendor_class(struct ib_mad_mgmt_vendor_class * vendor_class)12301da177e4SLinus Torvalds static int check_vendor_class(struct ib_mad_mgmt_vendor_class *vendor_class)
12311da177e4SLinus Torvalds {
12321da177e4SLinus Torvalds 	int i;
12331da177e4SLinus Torvalds 
12341da177e4SLinus Torvalds 	for (i = 0; i < MAX_MGMT_OUI; i++)
12351da177e4SLinus Torvalds 		if (vendor_class->method_table[i])
12361da177e4SLinus Torvalds 			return 1;
12371da177e4SLinus Torvalds 	return 0;
12381da177e4SLinus Torvalds }
12391da177e4SLinus Torvalds 
find_vendor_oui(struct ib_mad_mgmt_vendor_class * vendor_class,const char * oui)12401da177e4SLinus Torvalds static int find_vendor_oui(struct ib_mad_mgmt_vendor_class *vendor_class,
1241d94bd266SIra Weiny 			   const char *oui)
12421da177e4SLinus Torvalds {
12431da177e4SLinus Torvalds 	int i;
12441da177e4SLinus Torvalds 
12451da177e4SLinus Torvalds 	for (i = 0; i < MAX_MGMT_OUI; i++)
12461da177e4SLinus Torvalds 		/* Is there matching OUI for this vendor class ? */
12471da177e4SLinus Torvalds 		if (!memcmp(vendor_class->oui[i], oui, 3))
12481da177e4SLinus Torvalds 			return i;
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 	return -1;
12511da177e4SLinus Torvalds }
12521da177e4SLinus Torvalds 
check_vendor_table(struct ib_mad_mgmt_vendor_class_table * vendor)12531da177e4SLinus Torvalds static int check_vendor_table(struct ib_mad_mgmt_vendor_class_table *vendor)
12541da177e4SLinus Torvalds {
12551da177e4SLinus Torvalds 	int i;
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	for (i = 0; i < MAX_MGMT_VENDOR_RANGE2; i++)
12581da177e4SLinus Torvalds 		if (vendor->vendor_class[i])
12591da177e4SLinus Torvalds 			return 1;
12601da177e4SLinus Torvalds 
12611da177e4SLinus Torvalds 	return 0;
12621da177e4SLinus Torvalds }
12631da177e4SLinus Torvalds 
remove_methods_mad_agent(struct ib_mad_mgmt_method_table * method,struct ib_mad_agent_private * agent)12641da177e4SLinus Torvalds static void remove_methods_mad_agent(struct ib_mad_mgmt_method_table *method,
12651da177e4SLinus Torvalds 				     struct ib_mad_agent_private *agent)
12661da177e4SLinus Torvalds {
12671da177e4SLinus Torvalds 	int i;
12681da177e4SLinus Torvalds 
12691da177e4SLinus Torvalds 	/* Remove any methods for this mad agent */
1270b6eb7011SWenpeng Liang 	for (i = 0; i < IB_MGMT_MAX_METHODS; i++)
1271b6eb7011SWenpeng Liang 		if (method->agent[i] == agent)
12721da177e4SLinus Torvalds 			method->agent[i] = NULL;
12731da177e4SLinus Torvalds }
12741da177e4SLinus Torvalds 
add_nonoui_reg_req(struct ib_mad_reg_req * mad_reg_req,struct ib_mad_agent_private * agent_priv,u8 mgmt_class)12751da177e4SLinus Torvalds static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req,
12761da177e4SLinus Torvalds 			      struct ib_mad_agent_private *agent_priv,
12771da177e4SLinus Torvalds 			      u8 mgmt_class)
12781da177e4SLinus Torvalds {
12791da177e4SLinus Torvalds 	struct ib_mad_port_private *port_priv;
12801da177e4SLinus Torvalds 	struct ib_mad_mgmt_class_table **class;
12811da177e4SLinus Torvalds 	struct ib_mad_mgmt_method_table **method;
12821da177e4SLinus Torvalds 	int i, ret;
12831da177e4SLinus Torvalds 
12841da177e4SLinus Torvalds 	port_priv = agent_priv->qp_info->port_priv;
12851da177e4SLinus Torvalds 	class = &port_priv->version[mad_reg_req->mgmt_class_version].class;
12861da177e4SLinus Torvalds 	if (!*class) {
12871da177e4SLinus Torvalds 		/* Allocate management class table for "new" class version */
1288de6eb66bSRoland Dreier 		*class = kzalloc(sizeof **class, GFP_ATOMIC);
12891da177e4SLinus Torvalds 		if (!*class) {
12901da177e4SLinus Torvalds 			ret = -ENOMEM;
12911da177e4SLinus Torvalds 			goto error1;
12921da177e4SLinus Torvalds 		}
1293de6eb66bSRoland Dreier 
12941da177e4SLinus Torvalds 		/* Allocate method table for this management class */
12951da177e4SLinus Torvalds 		method = &(*class)->method_table[mgmt_class];
12961da177e4SLinus Torvalds 		if ((ret = allocate_method_table(method)))
12971da177e4SLinus Torvalds 			goto error2;
12981da177e4SLinus Torvalds 	} else {
12991da177e4SLinus Torvalds 		method = &(*class)->method_table[mgmt_class];
13001da177e4SLinus Torvalds 		if (!*method) {
13011da177e4SLinus Torvalds 			/* Allocate method table for this management class */
13021da177e4SLinus Torvalds 			if ((ret = allocate_method_table(method)))
13031da177e4SLinus Torvalds 				goto error1;
13041da177e4SLinus Torvalds 		}
13051da177e4SLinus Torvalds 	}
13061da177e4SLinus Torvalds 
13071da177e4SLinus Torvalds 	/* Now, make sure methods are not already in use */
13081da177e4SLinus Torvalds 	if (method_in_use(method, mad_reg_req))
13091da177e4SLinus Torvalds 		goto error3;
13101da177e4SLinus Torvalds 
13111da177e4SLinus Torvalds 	/* Finally, add in methods being registered */
131219b629f5SAkinobu Mita 	for_each_set_bit(i, mad_reg_req->method_mask, IB_MGMT_MAX_METHODS)
13131da177e4SLinus Torvalds 		(*method)->agent[i] = agent_priv;
131419b629f5SAkinobu Mita 
13151da177e4SLinus Torvalds 	return 0;
13161da177e4SLinus Torvalds 
13171da177e4SLinus Torvalds error3:
13181da177e4SLinus Torvalds 	/* Remove any methods for this mad agent */
13191da177e4SLinus Torvalds 	remove_methods_mad_agent(*method, agent_priv);
13201da177e4SLinus Torvalds 	/* Now, check to see if there are any methods in use */
13211da177e4SLinus Torvalds 	if (!check_method_table(*method)) {
13221da177e4SLinus Torvalds 		/* If not, release management method table */
13231da177e4SLinus Torvalds 		kfree(*method);
13241da177e4SLinus Torvalds 		*method = NULL;
13251da177e4SLinus Torvalds 	}
13261da177e4SLinus Torvalds 	ret = -EINVAL;
13271da177e4SLinus Torvalds 	goto error1;
13281da177e4SLinus Torvalds error2:
13291da177e4SLinus Torvalds 	kfree(*class);
13301da177e4SLinus Torvalds 	*class = NULL;
13311da177e4SLinus Torvalds error1:
13321da177e4SLinus Torvalds 	return ret;
13331da177e4SLinus Torvalds }
13341da177e4SLinus Torvalds 
add_oui_reg_req(struct ib_mad_reg_req * mad_reg_req,struct ib_mad_agent_private * agent_priv)13351da177e4SLinus Torvalds static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req,
13361da177e4SLinus Torvalds 			   struct ib_mad_agent_private *agent_priv)
13371da177e4SLinus Torvalds {
13381da177e4SLinus Torvalds 	struct ib_mad_port_private *port_priv;
13391da177e4SLinus Torvalds 	struct ib_mad_mgmt_vendor_class_table **vendor_table;
13401da177e4SLinus Torvalds 	struct ib_mad_mgmt_vendor_class_table *vendor = NULL;
13411da177e4SLinus Torvalds 	struct ib_mad_mgmt_vendor_class *vendor_class = NULL;
13421da177e4SLinus Torvalds 	struct ib_mad_mgmt_method_table **method;
13431da177e4SLinus Torvalds 	int i, ret = -ENOMEM;
13441da177e4SLinus Torvalds 	u8 vclass;
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	/* "New" vendor (with OUI) class */
13471da177e4SLinus Torvalds 	vclass = vendor_class_index(mad_reg_req->mgmt_class);
13481da177e4SLinus Torvalds 	port_priv = agent_priv->qp_info->port_priv;
13491da177e4SLinus Torvalds 	vendor_table = &port_priv->version[
13501da177e4SLinus Torvalds 				mad_reg_req->mgmt_class_version].vendor;
13511da177e4SLinus Torvalds 	if (!*vendor_table) {
13521da177e4SLinus Torvalds 		/* Allocate mgmt vendor class table for "new" class version */
1353de6eb66bSRoland Dreier 		vendor = kzalloc(sizeof *vendor, GFP_ATOMIC);
135427162432SLeon Romanovsky 		if (!vendor)
13551da177e4SLinus Torvalds 			goto error1;
1356de6eb66bSRoland Dreier 
13571da177e4SLinus Torvalds 		*vendor_table = vendor;
13581da177e4SLinus Torvalds 	}
13591da177e4SLinus Torvalds 	if (!(*vendor_table)->vendor_class[vclass]) {
13601da177e4SLinus Torvalds 		/* Allocate table for this management vendor class */
1361de6eb66bSRoland Dreier 		vendor_class = kzalloc(sizeof *vendor_class, GFP_ATOMIC);
136227162432SLeon Romanovsky 		if (!vendor_class)
13631da177e4SLinus Torvalds 			goto error2;
1364de6eb66bSRoland Dreier 
13651da177e4SLinus Torvalds 		(*vendor_table)->vendor_class[vclass] = vendor_class;
13661da177e4SLinus Torvalds 	}
13671da177e4SLinus Torvalds 	for (i = 0; i < MAX_MGMT_OUI; i++) {
13681da177e4SLinus Torvalds 		/* Is there matching OUI for this vendor class ? */
13691da177e4SLinus Torvalds 		if (!memcmp((*vendor_table)->vendor_class[vclass]->oui[i],
13701da177e4SLinus Torvalds 			    mad_reg_req->oui, 3)) {
13711da177e4SLinus Torvalds 			method = &(*vendor_table)->vendor_class[
13721da177e4SLinus Torvalds 						vclass]->method_table[i];
13732468b82dSLeon Romanovsky 			if (!*method)
13742468b82dSLeon Romanovsky 				goto error3;
13751da177e4SLinus Torvalds 			goto check_in_use;
13761da177e4SLinus Torvalds 		}
13771da177e4SLinus Torvalds 	}
13781da177e4SLinus Torvalds 	for (i = 0; i < MAX_MGMT_OUI; i++) {
13791da177e4SLinus Torvalds 		/* OUI slot available ? */
13801da177e4SLinus Torvalds 		if (!is_vendor_oui((*vendor_table)->vendor_class[
13811da177e4SLinus Torvalds 				vclass]->oui[i])) {
13821da177e4SLinus Torvalds 			method = &(*vendor_table)->vendor_class[
13831da177e4SLinus Torvalds 				vclass]->method_table[i];
13841da177e4SLinus Torvalds 			/* Allocate method table for this OUI */
13852468b82dSLeon Romanovsky 			if (!*method) {
13862468b82dSLeon Romanovsky 				ret = allocate_method_table(method);
13872468b82dSLeon Romanovsky 				if (ret)
13881da177e4SLinus Torvalds 					goto error3;
13892468b82dSLeon Romanovsky 			}
13901da177e4SLinus Torvalds 			memcpy((*vendor_table)->vendor_class[vclass]->oui[i],
13911da177e4SLinus Torvalds 			       mad_reg_req->oui, 3);
13921da177e4SLinus Torvalds 			goto check_in_use;
13931da177e4SLinus Torvalds 		}
13941da177e4SLinus Torvalds 	}
13957ef5d4b0SIra Weiny 	dev_err(&agent_priv->agent.device->dev, "All OUI slots in use\n");
13961da177e4SLinus Torvalds 	goto error3;
13971da177e4SLinus Torvalds 
13981da177e4SLinus Torvalds check_in_use:
13991da177e4SLinus Torvalds 	/* Now, make sure methods are not already in use */
14001da177e4SLinus Torvalds 	if (method_in_use(method, mad_reg_req))
14011da177e4SLinus Torvalds 		goto error4;
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds 	/* Finally, add in methods being registered */
140419b629f5SAkinobu Mita 	for_each_set_bit(i, mad_reg_req->method_mask, IB_MGMT_MAX_METHODS)
14051da177e4SLinus Torvalds 		(*method)->agent[i] = agent_priv;
140619b629f5SAkinobu Mita 
14071da177e4SLinus Torvalds 	return 0;
14081da177e4SLinus Torvalds 
14091da177e4SLinus Torvalds error4:
14101da177e4SLinus Torvalds 	/* Remove any methods for this mad agent */
14111da177e4SLinus Torvalds 	remove_methods_mad_agent(*method, agent_priv);
14121da177e4SLinus Torvalds 	/* Now, check to see if there are any methods in use */
14131da177e4SLinus Torvalds 	if (!check_method_table(*method)) {
14141da177e4SLinus Torvalds 		/* If not, release management method table */
14151da177e4SLinus Torvalds 		kfree(*method);
14161da177e4SLinus Torvalds 		*method = NULL;
14171da177e4SLinus Torvalds 	}
14181da177e4SLinus Torvalds 	ret = -EINVAL;
14191da177e4SLinus Torvalds error3:
14201da177e4SLinus Torvalds 	if (vendor_class) {
14211da177e4SLinus Torvalds 		(*vendor_table)->vendor_class[vclass] = NULL;
14221da177e4SLinus Torvalds 		kfree(vendor_class);
14231da177e4SLinus Torvalds 	}
14241da177e4SLinus Torvalds error2:
14251da177e4SLinus Torvalds 	if (vendor) {
14261da177e4SLinus Torvalds 		*vendor_table = NULL;
14271da177e4SLinus Torvalds 		kfree(vendor);
14281da177e4SLinus Torvalds 	}
14291da177e4SLinus Torvalds error1:
14301da177e4SLinus Torvalds 	return ret;
14311da177e4SLinus Torvalds }
14321da177e4SLinus Torvalds 
remove_mad_reg_req(struct ib_mad_agent_private * agent_priv)14331da177e4SLinus Torvalds static void remove_mad_reg_req(struct ib_mad_agent_private *agent_priv)
14341da177e4SLinus Torvalds {
14351da177e4SLinus Torvalds 	struct ib_mad_port_private *port_priv;
14361da177e4SLinus Torvalds 	struct ib_mad_mgmt_class_table *class;
14371da177e4SLinus Torvalds 	struct ib_mad_mgmt_method_table *method;
14381da177e4SLinus Torvalds 	struct ib_mad_mgmt_vendor_class_table *vendor;
14391da177e4SLinus Torvalds 	struct ib_mad_mgmt_vendor_class *vendor_class;
14401da177e4SLinus Torvalds 	int index;
14411da177e4SLinus Torvalds 	u8 mgmt_class;
14421da177e4SLinus Torvalds 
14431da177e4SLinus Torvalds 	/*
14441da177e4SLinus Torvalds 	 * Was MAD registration request supplied
14451da177e4SLinus Torvalds 	 * with original registration ?
14461da177e4SLinus Torvalds 	 */
1447b6eb7011SWenpeng Liang 	if (!agent_priv->reg_req)
14481da177e4SLinus Torvalds 		goto out;
14491da177e4SLinus Torvalds 
14501da177e4SLinus Torvalds 	port_priv = agent_priv->qp_info->port_priv;
14511da177e4SLinus Torvalds 	mgmt_class = convert_mgmt_class(agent_priv->reg_req->mgmt_class);
14521da177e4SLinus Torvalds 	class = port_priv->version[
14531da177e4SLinus Torvalds 			agent_priv->reg_req->mgmt_class_version].class;
14541da177e4SLinus Torvalds 	if (!class)
14551da177e4SLinus Torvalds 		goto vendor_check;
14561da177e4SLinus Torvalds 
14571da177e4SLinus Torvalds 	method = class->method_table[mgmt_class];
14581da177e4SLinus Torvalds 	if (method) {
14591da177e4SLinus Torvalds 		/* Remove any methods for this mad agent */
14601da177e4SLinus Torvalds 		remove_methods_mad_agent(method, agent_priv);
14611da177e4SLinus Torvalds 		/* Now, check to see if there are any methods still in use */
14621da177e4SLinus Torvalds 		if (!check_method_table(method)) {
14631da177e4SLinus Torvalds 			/* If not, release management method table */
14641da177e4SLinus Torvalds 			kfree(method);
14651da177e4SLinus Torvalds 			class->method_table[mgmt_class] = NULL;
14661da177e4SLinus Torvalds 			/* Any management classes left ? */
14671da177e4SLinus Torvalds 			if (!check_class_table(class)) {
14681da177e4SLinus Torvalds 				/* If not, release management class table */
14691da177e4SLinus Torvalds 				kfree(class);
14701da177e4SLinus Torvalds 				port_priv->version[
14711da177e4SLinus Torvalds 					agent_priv->reg_req->
14721da177e4SLinus Torvalds 					mgmt_class_version].class = NULL;
14731da177e4SLinus Torvalds 			}
14741da177e4SLinus Torvalds 		}
14751da177e4SLinus Torvalds 	}
14761da177e4SLinus Torvalds 
14771da177e4SLinus Torvalds vendor_check:
14781da177e4SLinus Torvalds 	if (!is_vendor_class(mgmt_class))
14791da177e4SLinus Torvalds 		goto out;
14801da177e4SLinus Torvalds 
14811da177e4SLinus Torvalds 	/* normalize mgmt_class to vendor range 2 */
14821da177e4SLinus Torvalds 	mgmt_class = vendor_class_index(agent_priv->reg_req->mgmt_class);
14831da177e4SLinus Torvalds 	vendor = port_priv->version[
14841da177e4SLinus Torvalds 			agent_priv->reg_req->mgmt_class_version].vendor;
14851da177e4SLinus Torvalds 
14861da177e4SLinus Torvalds 	if (!vendor)
14871da177e4SLinus Torvalds 		goto out;
14881da177e4SLinus Torvalds 
14891da177e4SLinus Torvalds 	vendor_class = vendor->vendor_class[mgmt_class];
14901da177e4SLinus Torvalds 	if (vendor_class) {
14911da177e4SLinus Torvalds 		index = find_vendor_oui(vendor_class, agent_priv->reg_req->oui);
14921da177e4SLinus Torvalds 		if (index < 0)
14931da177e4SLinus Torvalds 			goto out;
14941da177e4SLinus Torvalds 		method = vendor_class->method_table[index];
14951da177e4SLinus Torvalds 		if (method) {
14961da177e4SLinus Torvalds 			/* Remove any methods for this mad agent */
14971da177e4SLinus Torvalds 			remove_methods_mad_agent(method, agent_priv);
14981da177e4SLinus Torvalds 			/*
14991da177e4SLinus Torvalds 			 * Now, check to see if there are
15001da177e4SLinus Torvalds 			 * any methods still in use
15011da177e4SLinus Torvalds 			 */
15021da177e4SLinus Torvalds 			if (!check_method_table(method)) {
15031da177e4SLinus Torvalds 				/* If not, release management method table */
15041da177e4SLinus Torvalds 				kfree(method);
15051da177e4SLinus Torvalds 				vendor_class->method_table[index] = NULL;
15061da177e4SLinus Torvalds 				memset(vendor_class->oui[index], 0, 3);
15071da177e4SLinus Torvalds 				/* Any OUIs left ? */
15081da177e4SLinus Torvalds 				if (!check_vendor_class(vendor_class)) {
15091da177e4SLinus Torvalds 					/* If not, release vendor class table */
15101da177e4SLinus Torvalds 					kfree(vendor_class);
15111da177e4SLinus Torvalds 					vendor->vendor_class[mgmt_class] = NULL;
15121da177e4SLinus Torvalds 					/* Any other vendor classes left ? */
15131da177e4SLinus Torvalds 					if (!check_vendor_table(vendor)) {
15141da177e4SLinus Torvalds 						kfree(vendor);
15151da177e4SLinus Torvalds 						port_priv->version[
15161da177e4SLinus Torvalds 							agent_priv->reg_req->
15171da177e4SLinus Torvalds 							mgmt_class_version].
15181da177e4SLinus Torvalds 							vendor = NULL;
15191da177e4SLinus Torvalds 					}
15201da177e4SLinus Torvalds 				}
15211da177e4SLinus Torvalds 			}
15221da177e4SLinus Torvalds 		}
15231da177e4SLinus Torvalds 	}
15241da177e4SLinus Torvalds 
15251da177e4SLinus Torvalds out:
15261da177e4SLinus Torvalds 	return;
15271da177e4SLinus Torvalds }
15281da177e4SLinus Torvalds 
15291da177e4SLinus Torvalds static struct ib_mad_agent_private *
find_mad_agent(struct ib_mad_port_private * port_priv,const struct ib_mad_hdr * mad_hdr)15301da177e4SLinus Torvalds find_mad_agent(struct ib_mad_port_private *port_priv,
1531d94bd266SIra Weiny 	       const struct ib_mad_hdr *mad_hdr)
15321da177e4SLinus Torvalds {
15331da177e4SLinus Torvalds 	struct ib_mad_agent_private *mad_agent = NULL;
15341da177e4SLinus Torvalds 	unsigned long flags;
15351da177e4SLinus Torvalds 
1536d94bd266SIra Weiny 	if (ib_response_mad(mad_hdr)) {
15371da177e4SLinus Torvalds 		u32 hi_tid;
15381da177e4SLinus Torvalds 
15391da177e4SLinus Torvalds 		/*
15401da177e4SLinus Torvalds 		 * Routing is based on high 32 bits of transaction ID
15411da177e4SLinus Torvalds 		 * of MAD.
15421da177e4SLinus Torvalds 		 */
1543d94bd266SIra Weiny 		hi_tid = be64_to_cpu(mad_hdr->tid) >> 32;
15449a41e38aSwilly@infradead.org 		rcu_read_lock();
1545949a2370SMatthew Wilcox 		mad_agent = xa_load(&ib_mad_clients, hi_tid);
1546e41c4253SShay Drory 		if (mad_agent && !refcount_inc_not_zero(&mad_agent->refcount))
15479a41e38aSwilly@infradead.org 			mad_agent = NULL;
15489a41e38aSwilly@infradead.org 		rcu_read_unlock();
15491da177e4SLinus Torvalds 	} else {
15501da177e4SLinus Torvalds 		struct ib_mad_mgmt_class_table *class;
15511da177e4SLinus Torvalds 		struct ib_mad_mgmt_method_table *method;
15521da177e4SLinus Torvalds 		struct ib_mad_mgmt_vendor_class_table *vendor;
15531da177e4SLinus Torvalds 		struct ib_mad_mgmt_vendor_class *vendor_class;
1554d94bd266SIra Weiny 		const struct ib_vendor_mad *vendor_mad;
15551da177e4SLinus Torvalds 		int index;
15561da177e4SLinus Torvalds 
15579a41e38aSwilly@infradead.org 		spin_lock_irqsave(&port_priv->reg_lock, flags);
15581da177e4SLinus Torvalds 		/*
15591da177e4SLinus Torvalds 		 * Routing is based on version, class, and method
15601da177e4SLinus Torvalds 		 * For "newer" vendor MADs, also based on OUI
15611da177e4SLinus Torvalds 		 */
1562d94bd266SIra Weiny 		if (mad_hdr->class_version >= MAX_MGMT_VERSION)
15631da177e4SLinus Torvalds 			goto out;
1564d94bd266SIra Weiny 		if (!is_vendor_class(mad_hdr->mgmt_class)) {
15651da177e4SLinus Torvalds 			class = port_priv->version[
1566d94bd266SIra Weiny 					mad_hdr->class_version].class;
15671da177e4SLinus Torvalds 			if (!class)
15681da177e4SLinus Torvalds 				goto out;
1569d94bd266SIra Weiny 			if (convert_mgmt_class(mad_hdr->mgmt_class) >=
15702fe2f378SBart Van Assche 			    ARRAY_SIZE(class->method_table))
1571b7ab0b19SHefty, Sean 				goto out;
15721da177e4SLinus Torvalds 			method = class->method_table[convert_mgmt_class(
1573d94bd266SIra Weiny 							mad_hdr->mgmt_class)];
15741da177e4SLinus Torvalds 			if (method)
1575d94bd266SIra Weiny 				mad_agent = method->agent[mad_hdr->method &
15761da177e4SLinus Torvalds 							  ~IB_MGMT_METHOD_RESP];
15771da177e4SLinus Torvalds 		} else {
15781da177e4SLinus Torvalds 			vendor = port_priv->version[
1579d94bd266SIra Weiny 					mad_hdr->class_version].vendor;
15801da177e4SLinus Torvalds 			if (!vendor)
15811da177e4SLinus Torvalds 				goto out;
15821da177e4SLinus Torvalds 			vendor_class = vendor->vendor_class[vendor_class_index(
1583d94bd266SIra Weiny 						mad_hdr->mgmt_class)];
15841da177e4SLinus Torvalds 			if (!vendor_class)
15851da177e4SLinus Torvalds 				goto out;
15861da177e4SLinus Torvalds 			/* Find matching OUI */
1587d94bd266SIra Weiny 			vendor_mad = (const struct ib_vendor_mad *)mad_hdr;
15881da177e4SLinus Torvalds 			index = find_vendor_oui(vendor_class, vendor_mad->oui);
15891da177e4SLinus Torvalds 			if (index == -1)
15901da177e4SLinus Torvalds 				goto out;
15911da177e4SLinus Torvalds 			method = vendor_class->method_table[index];
15921da177e4SLinus Torvalds 			if (method) {
1593d94bd266SIra Weiny 				mad_agent = method->agent[mad_hdr->method &
15941da177e4SLinus Torvalds 							  ~IB_MGMT_METHOD_RESP];
15951da177e4SLinus Torvalds 			}
15961da177e4SLinus Torvalds 		}
15979a41e38aSwilly@infradead.org 		if (mad_agent)
1598e41c4253SShay Drory 			refcount_inc(&mad_agent->refcount);
15999a41e38aSwilly@infradead.org out:
16009a41e38aSwilly@infradead.org 		spin_unlock_irqrestore(&port_priv->reg_lock, flags);
16011da177e4SLinus Torvalds 	}
16021da177e4SLinus Torvalds 
16039a41e38aSwilly@infradead.org 	if (mad_agent && !mad_agent->agent.recv_handler) {
16047ef5d4b0SIra Weiny 		dev_notice(&port_priv->device->dev,
16051fb7f897SMark Bloch 			   "No receive handler for client %p on port %u\n",
16061da177e4SLinus Torvalds 			   &mad_agent->agent, port_priv->port_num);
16079a41e38aSwilly@infradead.org 		deref_mad_agent(mad_agent);
16081da177e4SLinus Torvalds 		mad_agent = NULL;
16091da177e4SLinus Torvalds 	}
16101da177e4SLinus Torvalds 
16111da177e4SLinus Torvalds 	return mad_agent;
16121da177e4SLinus Torvalds }
16131da177e4SLinus Torvalds 
validate_mad(const struct ib_mad_hdr * mad_hdr,const struct ib_mad_qp_info * qp_info,bool opa)16148e4349d1SIra Weiny static int validate_mad(const struct ib_mad_hdr *mad_hdr,
16158e4349d1SIra Weiny 			const struct ib_mad_qp_info *qp_info,
16168e4349d1SIra Weiny 			bool opa)
16171da177e4SLinus Torvalds {
16181da177e4SLinus Torvalds 	int valid = 0;
16198e4349d1SIra Weiny 	u32 qp_num = qp_info->qp->qp_num;
16201da177e4SLinus Torvalds 
16211da177e4SLinus Torvalds 	/* Make sure MAD base version is understood */
16228e4349d1SIra Weiny 	if (mad_hdr->base_version != IB_MGMT_BASE_VERSION &&
16238e4349d1SIra Weiny 	    (!opa || mad_hdr->base_version != OPA_MGMT_BASE_VERSION)) {
16243cea7b4aSWenpeng Liang 		pr_err("MAD received with unsupported base version %u %s\n",
16258e4349d1SIra Weiny 		       mad_hdr->base_version, opa ? "(opa)" : "");
16261da177e4SLinus Torvalds 		goto out;
16271da177e4SLinus Torvalds 	}
16281da177e4SLinus Torvalds 
16291da177e4SLinus Torvalds 	/* Filter SMI packets sent to other than QP0 */
163077f60833SIra Weiny 	if ((mad_hdr->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED) ||
163177f60833SIra Weiny 	    (mad_hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)) {
16321da177e4SLinus Torvalds 		if (qp_num == 0)
16331da177e4SLinus Torvalds 			valid = 1;
16341da177e4SLinus Torvalds 	} else {
163553370886SHal Rosenstock 		/* CM attributes other than ClassPortInfo only use Send method */
163653370886SHal Rosenstock 		if ((mad_hdr->mgmt_class == IB_MGMT_CLASS_CM) &&
163753370886SHal Rosenstock 		    (mad_hdr->attr_id != IB_MGMT_CLASSPORTINFO_ATTR_ID) &&
163853370886SHal Rosenstock 		    (mad_hdr->method != IB_MGMT_METHOD_SEND))
163953370886SHal Rosenstock 			goto out;
16401da177e4SLinus Torvalds 		/* Filter GSI packets sent to QP0 */
16411da177e4SLinus Torvalds 		if (qp_num != 0)
16421da177e4SLinus Torvalds 			valid = 1;
16431da177e4SLinus Torvalds 	}
16441da177e4SLinus Torvalds 
16451da177e4SLinus Torvalds out:
16461da177e4SLinus Torvalds 	return valid;
16471da177e4SLinus Torvalds }
16481da177e4SLinus Torvalds 
is_rmpp_data_mad(const struct ib_mad_agent_private * mad_agent_priv,const struct ib_mad_hdr * mad_hdr)1649f766c58fSIra Weiny static int is_rmpp_data_mad(const struct ib_mad_agent_private *mad_agent_priv,
1650f766c58fSIra Weiny 			    const struct ib_mad_hdr *mad_hdr)
1651fa619a77SHal Rosenstock {
1652fa619a77SHal Rosenstock 	struct ib_rmpp_mad *rmpp_mad;
1653fa619a77SHal Rosenstock 
1654fa619a77SHal Rosenstock 	rmpp_mad = (struct ib_rmpp_mad *)mad_hdr;
1655fa619a77SHal Rosenstock 	return !mad_agent_priv->agent.rmpp_version ||
16561471cb6cSIra Weiny 		!ib_mad_kernel_rmpp_agent(&mad_agent_priv->agent) ||
1657fa619a77SHal Rosenstock 		!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
1658fa619a77SHal Rosenstock 				    IB_MGMT_RMPP_FLAG_ACTIVE) ||
1659fa619a77SHal Rosenstock 		(rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA);
1660fa619a77SHal Rosenstock }
1661fa619a77SHal Rosenstock 
rcv_has_same_class(const struct ib_mad_send_wr_private * wr,const struct ib_mad_recv_wc * rwc)16628bf4b30cSIra Weiny static inline int rcv_has_same_class(const struct ib_mad_send_wr_private *wr,
16638bf4b30cSIra Weiny 				     const struct ib_mad_recv_wc *rwc)
1664fa9656bbSJack Morgenstein {
16658bf4b30cSIra Weiny 	return ((struct ib_mad_hdr *)(wr->send_buf.mad))->mgmt_class ==
1666fa9656bbSJack Morgenstein 		rwc->recv_buf.mad->mad_hdr.mgmt_class;
1667fa9656bbSJack Morgenstein }
1668fa9656bbSJack Morgenstein 
1669f681967aSWenpeng Liang static inline int
rcv_has_same_gid(const struct ib_mad_agent_private * mad_agent_priv,const struct ib_mad_send_wr_private * wr,const struct ib_mad_recv_wc * rwc)1670f681967aSWenpeng Liang rcv_has_same_gid(const struct ib_mad_agent_private *mad_agent_priv,
1671f766c58fSIra Weiny 		 const struct ib_mad_send_wr_private *wr,
1672f766c58fSIra Weiny 		 const struct ib_mad_recv_wc *rwc)
1673fa9656bbSJack Morgenstein {
167490898850SDasaratharaman Chandramouli 	struct rdma_ah_attr attr;
1675fa9656bbSJack Morgenstein 	u8 send_resp, rcv_resp;
16769874e746SJack Morgenstein 	union ib_gid sgid;
16779874e746SJack Morgenstein 	struct ib_device *device = mad_agent_priv->agent.device;
16781fb7f897SMark Bloch 	u32 port_num = mad_agent_priv->agent.port_num;
16799874e746SJack Morgenstein 	u8 lmc;
1680d8966fcdSDasaratharaman Chandramouli 	bool has_grh;
1681fa9656bbSJack Morgenstein 
168296909308SIra Weiny 	send_resp = ib_response_mad((struct ib_mad_hdr *)wr->send_buf.mad);
168396909308SIra Weiny 	rcv_resp = ib_response_mad(&rwc->recv_buf.mad->mad_hdr);
1684fa9656bbSJack Morgenstein 
1685fa9656bbSJack Morgenstein 	if (send_resp == rcv_resp)
1686fa9656bbSJack Morgenstein 		/* both requests, or both responses. GIDs different */
1687fa9656bbSJack Morgenstein 		return 0;
1688fa9656bbSJack Morgenstein 
1689bfbfd661SDasaratharaman Chandramouli 	if (rdma_query_ah(wr->send_buf.ah, &attr))
1690fa9656bbSJack Morgenstein 		/* Assume not equal, to avoid false positives. */
1691fa9656bbSJack Morgenstein 		return 0;
1692fa9656bbSJack Morgenstein 
1693d8966fcdSDasaratharaman Chandramouli 	has_grh = !!(rdma_ah_get_ah_flags(&attr) & IB_AH_GRH);
1694d8966fcdSDasaratharaman Chandramouli 	if (has_grh != !!(rwc->wc->wc_flags & IB_WC_GRH))
1695fa9656bbSJack Morgenstein 		/* one has GID, other does not.  Assume different */
1696fa9656bbSJack Morgenstein 		return 0;
16979874e746SJack Morgenstein 
16989874e746SJack Morgenstein 	if (!send_resp && rcv_resp) {
16999874e746SJack Morgenstein 		/* is request/response. */
1700d8966fcdSDasaratharaman Chandramouli 		if (!has_grh) {
17019874e746SJack Morgenstein 			if (ib_get_cached_lmc(device, port_num, &lmc))
17029874e746SJack Morgenstein 				return 0;
1703d8966fcdSDasaratharaman Chandramouli 			return (!lmc || !((rdma_ah_get_path_bits(&attr) ^
17049874e746SJack Morgenstein 					   rwc->wc->dlid_path_bits) &
17059874e746SJack Morgenstein 					  ((1 << lmc) - 1)));
17069874e746SJack Morgenstein 		} else {
1707d8966fcdSDasaratharaman Chandramouli 			const struct ib_global_route *grh =
1708d8966fcdSDasaratharaman Chandramouli 					rdma_ah_read_grh(&attr);
1709d8966fcdSDasaratharaman Chandramouli 
17101dfce294SParav Pandit 			if (rdma_query_gid(device, port_num,
17111dfce294SParav Pandit 					   grh->sgid_index, &sgid))
17129874e746SJack Morgenstein 				return 0;
17139874e746SJack Morgenstein 			return !memcmp(sgid.raw, rwc->recv_buf.grh->dgid.raw,
17149874e746SJack Morgenstein 				       16);
1715fa9656bbSJack Morgenstein 		}
17169874e746SJack Morgenstein 	}
17179874e746SJack Morgenstein 
1718d8966fcdSDasaratharaman Chandramouli 	if (!has_grh)
1719d8966fcdSDasaratharaman Chandramouli 		return rdma_ah_get_dlid(&attr) == rwc->wc->slid;
17209874e746SJack Morgenstein 	else
1721d8966fcdSDasaratharaman Chandramouli 		return !memcmp(rdma_ah_read_grh(&attr)->dgid.raw,
1722d8966fcdSDasaratharaman Chandramouli 			       rwc->recv_buf.grh->sgid.raw,
17239874e746SJack Morgenstein 			       16);
17249874e746SJack Morgenstein }
17259874e746SJack Morgenstein 
is_direct(u8 class)17269874e746SJack Morgenstein static inline int is_direct(u8 class)
17279874e746SJack Morgenstein {
17289874e746SJack Morgenstein 	return (class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE);
17299874e746SJack Morgenstein }
17309874e746SJack Morgenstein 
1731fa619a77SHal Rosenstock struct ib_mad_send_wr_private*
ib_find_send_mad(const struct ib_mad_agent_private * mad_agent_priv,const struct ib_mad_recv_wc * wc)1732f766c58fSIra Weiny ib_find_send_mad(const struct ib_mad_agent_private *mad_agent_priv,
1733f766c58fSIra Weiny 		 const struct ib_mad_recv_wc *wc)
17341da177e4SLinus Torvalds {
17359874e746SJack Morgenstein 	struct ib_mad_send_wr_private *wr;
173683a1d228SIra Weiny 	const struct ib_mad_hdr *mad_hdr;
1737fa9656bbSJack Morgenstein 
173883a1d228SIra Weiny 	mad_hdr = &wc->recv_buf.mad->mad_hdr;
17391da177e4SLinus Torvalds 
17409874e746SJack Morgenstein 	list_for_each_entry(wr, &mad_agent_priv->wait_list, agent_list) {
174183a1d228SIra Weiny 		if ((wr->tid == mad_hdr->tid) &&
17429874e746SJack Morgenstein 		    rcv_has_same_class(wr, wc) &&
17439874e746SJack Morgenstein 		    /*
17449874e746SJack Morgenstein 		     * Don't check GID for direct routed MADs.
17459874e746SJack Morgenstein 		     * These might have permissive LIDs.
17469874e746SJack Morgenstein 		     */
174783a1d228SIra Weiny 		    (is_direct(mad_hdr->mgmt_class) ||
17489874e746SJack Morgenstein 		     rcv_has_same_gid(mad_agent_priv, wr, wc)))
174939798695SRoland Dreier 			return (wr->status == IB_WC_SUCCESS) ? wr : NULL;
17501da177e4SLinus Torvalds 	}
17511da177e4SLinus Torvalds 
17521da177e4SLinus Torvalds 	/*
17531da177e4SLinus Torvalds 	 * It's possible to receive the response before we've
17541da177e4SLinus Torvalds 	 * been notified that the send has completed
17551da177e4SLinus Torvalds 	 */
17569874e746SJack Morgenstein 	list_for_each_entry(wr, &mad_agent_priv->send_list, agent_list) {
1757c597eee5SIra Weiny 		if (is_rmpp_data_mad(mad_agent_priv, wr->send_buf.mad) &&
175883a1d228SIra Weiny 		    wr->tid == mad_hdr->tid &&
17599874e746SJack Morgenstein 		    wr->timeout &&
17609874e746SJack Morgenstein 		    rcv_has_same_class(wr, wc) &&
17619874e746SJack Morgenstein 		    /*
17629874e746SJack Morgenstein 		     * Don't check GID for direct routed MADs.
17639874e746SJack Morgenstein 		     * These might have permissive LIDs.
17649874e746SJack Morgenstein 		     */
176583a1d228SIra Weiny 		    (is_direct(mad_hdr->mgmt_class) ||
17669874e746SJack Morgenstein 		     rcv_has_same_gid(mad_agent_priv, wr, wc)))
17671da177e4SLinus Torvalds 			/* Verify request has not been canceled */
17689874e746SJack Morgenstein 			return (wr->status == IB_WC_SUCCESS) ? wr : NULL;
17691da177e4SLinus Torvalds 	}
17701da177e4SLinus Torvalds 	return NULL;
17711da177e4SLinus Torvalds }
17721da177e4SLinus Torvalds 
ib_mark_mad_done(struct ib_mad_send_wr_private * mad_send_wr)1773fa619a77SHal Rosenstock void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr)
17746a0c435eSHal Rosenstock {
17756a0c435eSHal Rosenstock 	mad_send_wr->timeout = 0;
1776179e0917SAkinobu Mita 	if (mad_send_wr->refcount == 1)
1777179e0917SAkinobu Mita 		list_move_tail(&mad_send_wr->agent_list,
17786a0c435eSHal Rosenstock 			      &mad_send_wr->mad_agent_priv->done_list);
17796a0c435eSHal Rosenstock }
17806a0c435eSHal Rosenstock 
ib_mad_complete_recv(struct ib_mad_agent_private * mad_agent_priv,struct ib_mad_recv_wc * mad_recv_wc)17811da177e4SLinus Torvalds static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
17824a0754faSHal Rosenstock 				 struct ib_mad_recv_wc *mad_recv_wc)
17831da177e4SLinus Torvalds {
17841da177e4SLinus Torvalds 	struct ib_mad_send_wr_private *mad_send_wr;
17851da177e4SLinus Torvalds 	struct ib_mad_send_wc mad_send_wc;
17861da177e4SLinus Torvalds 	unsigned long flags;
178747a2b338SDaniel Jurgens 	int ret;
178847a2b338SDaniel Jurgens 
178989548bcaSParav Pandit 	INIT_LIST_HEAD(&mad_recv_wc->rmpp_list);
179047a2b338SDaniel Jurgens 	ret = ib_mad_enforce_security(mad_agent_priv,
179147a2b338SDaniel Jurgens 				      mad_recv_wc->wc->pkey_index);
179247a2b338SDaniel Jurgens 	if (ret) {
179347a2b338SDaniel Jurgens 		ib_free_recv_mad(mad_recv_wc);
179447a2b338SDaniel Jurgens 		deref_mad_agent(mad_agent_priv);
179589548bcaSParav Pandit 		return;
179647a2b338SDaniel Jurgens 	}
17971da177e4SLinus Torvalds 
1798fa619a77SHal Rosenstock 	list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
17991471cb6cSIra Weiny 	if (ib_mad_kernel_rmpp_agent(&mad_agent_priv->agent)) {
1800fa619a77SHal Rosenstock 		mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv,
1801fa619a77SHal Rosenstock 						      mad_recv_wc);
1802fa619a77SHal Rosenstock 		if (!mad_recv_wc) {
18031b52fa98SSean Hefty 			deref_mad_agent(mad_agent_priv);
1804fa619a77SHal Rosenstock 			return;
1805fa619a77SHal Rosenstock 		}
1806fa619a77SHal Rosenstock 	}
1807fa619a77SHal Rosenstock 
18081da177e4SLinus Torvalds 	/* Complete corresponding request */
180996909308SIra Weiny 	if (ib_response_mad(&mad_recv_wc->recv_buf.mad->mad_hdr)) {
18101da177e4SLinus Torvalds 		spin_lock_irqsave(&mad_agent_priv->lock, flags);
1811fa9656bbSJack Morgenstein 		mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc);
18121da177e4SLinus Torvalds 		if (!mad_send_wr) {
18131da177e4SLinus Torvalds 			spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
18141471cb6cSIra Weiny 			if (!ib_mad_kernel_rmpp_agent(&mad_agent_priv->agent)
18151471cb6cSIra Weiny 			   && ib_is_mad_class_rmpp(mad_recv_wc->recv_buf.mad->mad_hdr.mgmt_class)
18161471cb6cSIra Weiny 			   && (ib_get_rmpp_flags(&((struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad)->rmpp_hdr)
18171471cb6cSIra Weiny 					& IB_MGMT_RMPP_FLAG_ACTIVE)) {
18181471cb6cSIra Weiny 				/* user rmpp is in effect
18191471cb6cSIra Weiny 				 * and this is an active RMPP MAD
18201471cb6cSIra Weiny 				 */
1821ca281265SChristoph Hellwig 				mad_agent_priv->agent.recv_handler(
1822ca281265SChristoph Hellwig 						&mad_agent_priv->agent, NULL,
18231471cb6cSIra Weiny 						mad_recv_wc);
1824b9af0e2dSShay Drory 				deref_mad_agent(mad_agent_priv);
18251471cb6cSIra Weiny 			} else {
18261471cb6cSIra Weiny 				/* not user rmpp, revert to normal behavior and
182726caea5fSWenpeng Liang 				 * drop the mad
182826caea5fSWenpeng Liang 				 */
18294a0754faSHal Rosenstock 				ib_free_recv_mad(mad_recv_wc);
18301b52fa98SSean Hefty 				deref_mad_agent(mad_agent_priv);
18311da177e4SLinus Torvalds 				return;
18321da177e4SLinus Torvalds 			}
18331471cb6cSIra Weiny 		} else {
1834fa619a77SHal Rosenstock 			ib_mark_mad_done(mad_send_wr);
18351da177e4SLinus Torvalds 			spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
18361da177e4SLinus Torvalds 
18371da177e4SLinus Torvalds 			/* Defined behavior is to complete response before request */
1838ca281265SChristoph Hellwig 			mad_agent_priv->agent.recv_handler(
1839ca281265SChristoph Hellwig 					&mad_agent_priv->agent,
1840ca281265SChristoph Hellwig 					&mad_send_wr->send_buf,
18414a0754faSHal Rosenstock 					mad_recv_wc);
1842b9af0e2dSShay Drory 			deref_mad_agent(mad_agent_priv);
18431da177e4SLinus Torvalds 
18441da177e4SLinus Torvalds 			mad_send_wc.status = IB_WC_SUCCESS;
18451da177e4SLinus Torvalds 			mad_send_wc.vendor_err = 0;
184634816ad9SSean Hefty 			mad_send_wc.send_buf = &mad_send_wr->send_buf;
18471da177e4SLinus Torvalds 			ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc);
18481471cb6cSIra Weiny 		}
18491da177e4SLinus Torvalds 	} else {
1850ca281265SChristoph Hellwig 		mad_agent_priv->agent.recv_handler(&mad_agent_priv->agent, NULL,
18514a0754faSHal Rosenstock 						   mad_recv_wc);
18521b52fa98SSean Hefty 		deref_mad_agent(mad_agent_priv);
18531da177e4SLinus Torvalds 	}
18541da177e4SLinus Torvalds }
18551da177e4SLinus Torvalds 
handle_ib_smi(const struct ib_mad_port_private * port_priv,const struct ib_mad_qp_info * qp_info,const struct ib_wc * wc,u32 port_num,struct ib_mad_private * recv,struct ib_mad_private * response)1856e11ae8aaSIra Weiny static enum smi_action handle_ib_smi(const struct ib_mad_port_private *port_priv,
1857e11ae8aaSIra Weiny 				     const struct ib_mad_qp_info *qp_info,
1858e11ae8aaSIra Weiny 				     const struct ib_wc *wc,
18591fb7f897SMark Bloch 				     u32 port_num,
1860e11ae8aaSIra Weiny 				     struct ib_mad_private *recv,
1861e11ae8aaSIra Weiny 				     struct ib_mad_private *response)
1862e11ae8aaSIra Weiny {
1863e11ae8aaSIra Weiny 	enum smi_forward_action retsmi;
1864c9082e51SIra Weiny 	struct ib_smp *smp = (struct ib_smp *)recv->mad;
1865e11ae8aaSIra Weiny 
18662ccfbb70SIra Weiny 	trace_ib_mad_handle_ib_smi(smp);
18672ccfbb70SIra Weiny 
1868c9082e51SIra Weiny 	if (smi_handle_dr_smp_recv(smp,
18694139032bSHal Rosenstock 				   rdma_cap_ib_switch(port_priv->device),
1870e11ae8aaSIra Weiny 				   port_num,
1871e11ae8aaSIra Weiny 				   port_priv->device->phys_port_cnt) ==
1872e11ae8aaSIra Weiny 				   IB_SMI_DISCARD)
1873e11ae8aaSIra Weiny 		return IB_SMI_DISCARD;
1874e11ae8aaSIra Weiny 
1875c9082e51SIra Weiny 	retsmi = smi_check_forward_dr_smp(smp);
1876e11ae8aaSIra Weiny 	if (retsmi == IB_SMI_LOCAL)
1877e11ae8aaSIra Weiny 		return IB_SMI_HANDLE;
1878e11ae8aaSIra Weiny 
1879e11ae8aaSIra Weiny 	if (retsmi == IB_SMI_SEND) { /* don't forward */
1880c9082e51SIra Weiny 		if (smi_handle_dr_smp_send(smp,
18814139032bSHal Rosenstock 					   rdma_cap_ib_switch(port_priv->device),
1882e11ae8aaSIra Weiny 					   port_num) == IB_SMI_DISCARD)
1883e11ae8aaSIra Weiny 			return IB_SMI_DISCARD;
1884e11ae8aaSIra Weiny 
1885c9082e51SIra Weiny 		if (smi_check_local_smp(smp, port_priv->device) == IB_SMI_DISCARD)
1886e11ae8aaSIra Weiny 			return IB_SMI_DISCARD;
18874139032bSHal Rosenstock 	} else if (rdma_cap_ib_switch(port_priv->device)) {
1888e11ae8aaSIra Weiny 		/* forward case for switches */
1889c9082e51SIra Weiny 		memcpy(response, recv, mad_priv_size(response));
1890e11ae8aaSIra Weiny 		response->header.recv_wc.wc = &response->header.wc;
1891c9082e51SIra Weiny 		response->header.recv_wc.recv_buf.mad = (struct ib_mad *)response->mad;
1892e11ae8aaSIra Weiny 		response->header.recv_wc.recv_buf.grh = &response->grh;
1893e11ae8aaSIra Weiny 
1894c9082e51SIra Weiny 		agent_send_response((const struct ib_mad_hdr *)response->mad,
1895e11ae8aaSIra Weiny 				    &response->grh, wc,
1896e11ae8aaSIra Weiny 				    port_priv->device,
1897c9082e51SIra Weiny 				    smi_get_fwd_port(smp),
1898c9082e51SIra Weiny 				    qp_info->qp->qp_num,
18998e4349d1SIra Weiny 				    response->mad_size,
19008e4349d1SIra Weiny 				    false);
1901e11ae8aaSIra Weiny 
1902e11ae8aaSIra Weiny 		return IB_SMI_DISCARD;
1903e11ae8aaSIra Weiny 	}
1904e11ae8aaSIra Weiny 	return IB_SMI_HANDLE;
1905e11ae8aaSIra Weiny }
1906e11ae8aaSIra Weiny 
generate_unmatched_resp(const struct ib_mad_private * recv,struct ib_mad_private * response,size_t * resp_len,bool opa)1907c9082e51SIra Weiny static bool generate_unmatched_resp(const struct ib_mad_private *recv,
19088e4349d1SIra Weiny 				    struct ib_mad_private *response,
19098e4349d1SIra Weiny 				    size_t *resp_len, bool opa)
19100b307043SSwapna Thete {
1911c9082e51SIra Weiny 	const struct ib_mad_hdr *recv_hdr = (const struct ib_mad_hdr *)recv->mad;
1912c9082e51SIra Weiny 	struct ib_mad_hdr *resp_hdr = (struct ib_mad_hdr *)response->mad;
1913c9082e51SIra Weiny 
1914c9082e51SIra Weiny 	if (recv_hdr->method == IB_MGMT_METHOD_GET ||
1915c9082e51SIra Weiny 	    recv_hdr->method == IB_MGMT_METHOD_SET) {
1916c9082e51SIra Weiny 		memcpy(response, recv, mad_priv_size(response));
19170b307043SSwapna Thete 		response->header.recv_wc.wc = &response->header.wc;
1918c9082e51SIra Weiny 		response->header.recv_wc.recv_buf.mad = (struct ib_mad *)response->mad;
19190b307043SSwapna Thete 		response->header.recv_wc.recv_buf.grh = &response->grh;
1920c9082e51SIra Weiny 		resp_hdr->method = IB_MGMT_METHOD_GET_RESP;
1921c9082e51SIra Weiny 		resp_hdr->status = cpu_to_be16(IB_MGMT_MAD_STATUS_UNSUPPORTED_METHOD_ATTRIB);
1922c9082e51SIra Weiny 		if (recv_hdr->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
1923c9082e51SIra Weiny 			resp_hdr->status |= IB_SMP_DIRECTION;
19240b307043SSwapna Thete 
19258e4349d1SIra Weiny 		if (opa && recv_hdr->base_version == OPA_MGMT_BASE_VERSION) {
19268e4349d1SIra Weiny 			if (recv_hdr->mgmt_class ==
19278e4349d1SIra Weiny 			    IB_MGMT_CLASS_SUBN_LID_ROUTED ||
19288e4349d1SIra Weiny 			    recv_hdr->mgmt_class ==
19298e4349d1SIra Weiny 			    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
19308e4349d1SIra Weiny 				*resp_len = opa_get_smp_header_size(
19318e4349d1SIra Weiny 							(struct opa_smp *)recv->mad);
19328e4349d1SIra Weiny 			else
19338e4349d1SIra Weiny 				*resp_len = sizeof(struct ib_mad_hdr);
19348e4349d1SIra Weiny 		}
19358e4349d1SIra Weiny 
19360b307043SSwapna Thete 		return true;
19370b307043SSwapna Thete 	} else {
19380b307043SSwapna Thete 		return false;
19390b307043SSwapna Thete 	}
19400b307043SSwapna Thete }
19418e4349d1SIra Weiny 
19428e4349d1SIra Weiny static enum smi_action
handle_opa_smi(struct ib_mad_port_private * port_priv,struct ib_mad_qp_info * qp_info,struct ib_wc * wc,u32 port_num,struct ib_mad_private * recv,struct ib_mad_private * response)19438e4349d1SIra Weiny handle_opa_smi(struct ib_mad_port_private *port_priv,
19448e4349d1SIra Weiny 	       struct ib_mad_qp_info *qp_info,
19458e4349d1SIra Weiny 	       struct ib_wc *wc,
19461fb7f897SMark Bloch 	       u32 port_num,
19478e4349d1SIra Weiny 	       struct ib_mad_private *recv,
19488e4349d1SIra Weiny 	       struct ib_mad_private *response)
19498e4349d1SIra Weiny {
19508e4349d1SIra Weiny 	enum smi_forward_action retsmi;
19518e4349d1SIra Weiny 	struct opa_smp *smp = (struct opa_smp *)recv->mad;
19528e4349d1SIra Weiny 
19532ccfbb70SIra Weiny 	trace_ib_mad_handle_opa_smi(smp);
19542ccfbb70SIra Weiny 
19558e4349d1SIra Weiny 	if (opa_smi_handle_dr_smp_recv(smp,
19564139032bSHal Rosenstock 				   rdma_cap_ib_switch(port_priv->device),
19578e4349d1SIra Weiny 				   port_num,
19588e4349d1SIra Weiny 				   port_priv->device->phys_port_cnt) ==
19598e4349d1SIra Weiny 				   IB_SMI_DISCARD)
19608e4349d1SIra Weiny 		return IB_SMI_DISCARD;
19618e4349d1SIra Weiny 
19628e4349d1SIra Weiny 	retsmi = opa_smi_check_forward_dr_smp(smp);
19638e4349d1SIra Weiny 	if (retsmi == IB_SMI_LOCAL)
19648e4349d1SIra Weiny 		return IB_SMI_HANDLE;
19658e4349d1SIra Weiny 
19668e4349d1SIra Weiny 	if (retsmi == IB_SMI_SEND) { /* don't forward */
19678e4349d1SIra Weiny 		if (opa_smi_handle_dr_smp_send(smp,
19684139032bSHal Rosenstock 					   rdma_cap_ib_switch(port_priv->device),
19698e4349d1SIra Weiny 					   port_num) == IB_SMI_DISCARD)
19708e4349d1SIra Weiny 			return IB_SMI_DISCARD;
19718e4349d1SIra Weiny 
19728e4349d1SIra Weiny 		if (opa_smi_check_local_smp(smp, port_priv->device) ==
19738e4349d1SIra Weiny 		    IB_SMI_DISCARD)
19748e4349d1SIra Weiny 			return IB_SMI_DISCARD;
19758e4349d1SIra Weiny 
19764139032bSHal Rosenstock 	} else if (rdma_cap_ib_switch(port_priv->device)) {
19778e4349d1SIra Weiny 		/* forward case for switches */
19788e4349d1SIra Weiny 		memcpy(response, recv, mad_priv_size(response));
19798e4349d1SIra Weiny 		response->header.recv_wc.wc = &response->header.wc;
19808e4349d1SIra Weiny 		response->header.recv_wc.recv_buf.opa_mad =
19818e4349d1SIra Weiny 				(struct opa_mad *)response->mad;
19828e4349d1SIra Weiny 		response->header.recv_wc.recv_buf.grh = &response->grh;
19838e4349d1SIra Weiny 
19848e4349d1SIra Weiny 		agent_send_response((const struct ib_mad_hdr *)response->mad,
19858e4349d1SIra Weiny 				    &response->grh, wc,
19868e4349d1SIra Weiny 				    port_priv->device,
19878e4349d1SIra Weiny 				    opa_smi_get_fwd_port(smp),
19888e4349d1SIra Weiny 				    qp_info->qp->qp_num,
19898e4349d1SIra Weiny 				    recv->header.wc.byte_len,
19908e4349d1SIra Weiny 				    true);
19918e4349d1SIra Weiny 
19928e4349d1SIra Weiny 		return IB_SMI_DISCARD;
19938e4349d1SIra Weiny 	}
19948e4349d1SIra Weiny 
19958e4349d1SIra Weiny 	return IB_SMI_HANDLE;
19968e4349d1SIra Weiny }
19978e4349d1SIra Weiny 
19988e4349d1SIra Weiny static enum smi_action
handle_smi(struct ib_mad_port_private * port_priv,struct ib_mad_qp_info * qp_info,struct ib_wc * wc,u32 port_num,struct ib_mad_private * recv,struct ib_mad_private * response,bool opa)19998e4349d1SIra Weiny handle_smi(struct ib_mad_port_private *port_priv,
20008e4349d1SIra Weiny 	   struct ib_mad_qp_info *qp_info,
20018e4349d1SIra Weiny 	   struct ib_wc *wc,
20021fb7f897SMark Bloch 	   u32 port_num,
20038e4349d1SIra Weiny 	   struct ib_mad_private *recv,
20048e4349d1SIra Weiny 	   struct ib_mad_private *response,
20058e4349d1SIra Weiny 	   bool opa)
20068e4349d1SIra Weiny {
20078e4349d1SIra Weiny 	struct ib_mad_hdr *mad_hdr = (struct ib_mad_hdr *)recv->mad;
20088e4349d1SIra Weiny 
20098e4349d1SIra Weiny 	if (opa && mad_hdr->base_version == OPA_MGMT_BASE_VERSION &&
20109fa240bbSHal Rosenstock 	    mad_hdr->class_version == OPA_SM_CLASS_VERSION)
20118e4349d1SIra Weiny 		return handle_opa_smi(port_priv, qp_info, wc, port_num, recv,
20128e4349d1SIra Weiny 				      response);
20138e4349d1SIra Weiny 
20148e4349d1SIra Weiny 	return handle_ib_smi(port_priv, qp_info, wc, port_num, recv, response);
20158e4349d1SIra Weiny }
20168e4349d1SIra Weiny 
ib_mad_recv_done(struct ib_cq * cq,struct ib_wc * wc)2017d53e11fdSChristoph Hellwig static void ib_mad_recv_done(struct ib_cq *cq, struct ib_wc *wc)
20181da177e4SLinus Torvalds {
2019d53e11fdSChristoph Hellwig 	struct ib_mad_port_private *port_priv = cq->cq_context;
2020d53e11fdSChristoph Hellwig 	struct ib_mad_list_head *mad_list =
2021d53e11fdSChristoph Hellwig 		container_of(wc->wr_cqe, struct ib_mad_list_head, cqe);
20221da177e4SLinus Torvalds 	struct ib_mad_qp_info *qp_info;
20231da177e4SLinus Torvalds 	struct ib_mad_private_header *mad_priv_hdr;
2024445d6807SHal Rosenstock 	struct ib_mad_private *recv, *response = NULL;
20251da177e4SLinus Torvalds 	struct ib_mad_agent_private *mad_agent;
20261fb7f897SMark Bloch 	u32 port_num;
2027a9e74323SJack Morgenstein 	int ret = IB_MAD_RESULT_SUCCESS;
20284cd7c947SIra Weiny 	size_t mad_size;
20294cd7c947SIra Weiny 	u16 resp_mad_pkey_index = 0;
20308e4349d1SIra Weiny 	bool opa;
20311da177e4SLinus Torvalds 
2032d53e11fdSChristoph Hellwig 	if (list_empty_careful(&port_priv->port_list))
2033d53e11fdSChristoph Hellwig 		return;
2034d53e11fdSChristoph Hellwig 
2035d53e11fdSChristoph Hellwig 	if (wc->status != IB_WC_SUCCESS) {
2036d53e11fdSChristoph Hellwig 		/*
2037d53e11fdSChristoph Hellwig 		 * Receive errors indicate that the QP has entered the error
2038d53e11fdSChristoph Hellwig 		 * state - error handling/shutdown code will cleanup
2039d53e11fdSChristoph Hellwig 		 */
2040d53e11fdSChristoph Hellwig 		return;
2041d53e11fdSChristoph Hellwig 	}
2042d53e11fdSChristoph Hellwig 
20431da177e4SLinus Torvalds 	qp_info = mad_list->mad_queue->qp_info;
20441da177e4SLinus Torvalds 	dequeue_mad(mad_list);
20451da177e4SLinus Torvalds 
20468e4349d1SIra Weiny 	opa = rdma_cap_opa_mad(qp_info->port_priv->device,
20478e4349d1SIra Weiny 			       qp_info->port_priv->port_num);
20488e4349d1SIra Weiny 
20491da177e4SLinus Torvalds 	mad_priv_hdr = container_of(mad_list, struct ib_mad_private_header,
20501da177e4SLinus Torvalds 				    mad_list);
20511da177e4SLinus Torvalds 	recv = container_of(mad_priv_hdr, struct ib_mad_private, header);
20521527106fSRalph Campbell 	ib_dma_unmap_single(port_priv->device,
20531527106fSRalph Campbell 			    recv->header.mapping,
2054c9082e51SIra Weiny 			    mad_priv_dma_size(recv),
20551da177e4SLinus Torvalds 			    DMA_FROM_DEVICE);
20561da177e4SLinus Torvalds 
20571da177e4SLinus Torvalds 	/* Setup MAD receive work completion from "normal" work completion */
205824239affSSean Hefty 	recv->header.wc = *wc;
205924239affSSean Hefty 	recv->header.recv_wc.wc = &recv->header.wc;
20608e4349d1SIra Weiny 
20618e4349d1SIra Weiny 	if (opa && ((struct ib_mad_hdr *)(recv->mad))->base_version == OPA_MGMT_BASE_VERSION) {
20628e4349d1SIra Weiny 		recv->header.recv_wc.mad_len = wc->byte_len - sizeof(struct ib_grh);
20638e4349d1SIra Weiny 		recv->header.recv_wc.mad_seg_size = sizeof(struct opa_mad);
20648e4349d1SIra Weiny 	} else {
20651da177e4SLinus Torvalds 		recv->header.recv_wc.mad_len = sizeof(struct ib_mad);
20668e4349d1SIra Weiny 		recv->header.recv_wc.mad_seg_size = sizeof(struct ib_mad);
20678e4349d1SIra Weiny 	}
20688e4349d1SIra Weiny 
2069c9082e51SIra Weiny 	recv->header.recv_wc.recv_buf.mad = (struct ib_mad *)recv->mad;
20701da177e4SLinus Torvalds 	recv->header.recv_wc.recv_buf.grh = &recv->grh;
20711da177e4SLinus Torvalds 
20721da177e4SLinus Torvalds 	/* Validate MAD */
20738e4349d1SIra Weiny 	if (!validate_mad((const struct ib_mad_hdr *)recv->mad, qp_info, opa))
20741da177e4SLinus Torvalds 		goto out;
20751da177e4SLinus Torvalds 
2076821bf1deSIra Weiny 	trace_ib_mad_recv_done_handler(qp_info, wc,
2077821bf1deSIra Weiny 				       (struct ib_mad_hdr *)recv->mad);
2078821bf1deSIra Weiny 
20794cd7c947SIra Weiny 	mad_size = recv->mad_size;
20804cd7c947SIra Weiny 	response = alloc_mad_private(mad_size, GFP_KERNEL);
208127162432SLeon Romanovsky 	if (!response)
2082445d6807SHal Rosenstock 		goto out;
2083445d6807SHal Rosenstock 
20844139032bSHal Rosenstock 	if (rdma_cap_ib_switch(port_priv->device))
20851bae4dbfSHal Rosenstock 		port_num = wc->port_num;
20861bae4dbfSHal Rosenstock 	else
20871bae4dbfSHal Rosenstock 		port_num = port_priv->port_num;
20881bae4dbfSHal Rosenstock 
2089c9082e51SIra Weiny 	if (((struct ib_mad_hdr *)recv->mad)->mgmt_class ==
20901da177e4SLinus Torvalds 	    IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
20918e4349d1SIra Weiny 		if (handle_smi(port_priv, qp_info, wc, port_num, recv,
20928e4349d1SIra Weiny 			       response, opa)
2093e11ae8aaSIra Weiny 		    == IB_SMI_DISCARD)
20941bae4dbfSHal Rosenstock 			goto out;
20951bae4dbfSHal Rosenstock 	}
20961da177e4SLinus Torvalds 
20971da177e4SLinus Torvalds 	/* Give driver "right of first refusal" on incoming MAD */
20983023a1e9SKamal Heib 	if (port_priv->device->ops.process_mad) {
20993023a1e9SKamal Heib 		ret = port_priv->device->ops.process_mad(
21003023a1e9SKamal Heib 			port_priv->device, 0, port_priv->port_num, wc,
2101e26e7b88SLeon Romanovsky 			&recv->grh, (const struct ib_mad *)recv->mad,
2102e26e7b88SLeon Romanovsky 			(struct ib_mad *)response->mad, &mad_size,
2103e26e7b88SLeon Romanovsky 			&resp_mad_pkey_index);
21048e4349d1SIra Weiny 
21058e4349d1SIra Weiny 		if (opa)
21068e4349d1SIra Weiny 			wc->pkey_index = resp_mad_pkey_index;
21078e4349d1SIra Weiny 
21081da177e4SLinus Torvalds 		if (ret & IB_MAD_RESULT_SUCCESS) {
21091da177e4SLinus Torvalds 			if (ret & IB_MAD_RESULT_CONSUMED)
21101da177e4SLinus Torvalds 				goto out;
21111da177e4SLinus Torvalds 			if (ret & IB_MAD_RESULT_REPLY) {
2112c9082e51SIra Weiny 				agent_send_response((const struct ib_mad_hdr *)response->mad,
211334816ad9SSean Hefty 						    &recv->grh, wc,
21141da177e4SLinus Torvalds 						    port_priv->device,
21151bae4dbfSHal Rosenstock 						    port_num,
2116c9082e51SIra Weiny 						    qp_info->qp->qp_num,
21178e4349d1SIra Weiny 						    mad_size, opa);
21181da177e4SLinus Torvalds 				goto out;
21191da177e4SLinus Torvalds 			}
21201da177e4SLinus Torvalds 		}
21211da177e4SLinus Torvalds 	}
21221da177e4SLinus Torvalds 
2123c9082e51SIra Weiny 	mad_agent = find_mad_agent(port_priv, (const struct ib_mad_hdr *)recv->mad);
21241da177e4SLinus Torvalds 	if (mad_agent) {
21250e65bae2SIra Weiny 		trace_ib_mad_recv_done_agent(mad_agent);
21264a0754faSHal Rosenstock 		ib_mad_complete_recv(mad_agent, &recv->header.recv_wc);
21271da177e4SLinus Torvalds 		/*
21281da177e4SLinus Torvalds 		 * recv is freed up in error cases in ib_mad_complete_recv
21291da177e4SLinus Torvalds 		 * or via recv_handler in ib_mad_complete_recv()
21301da177e4SLinus Torvalds 		 */
21311da177e4SLinus Torvalds 		recv = NULL;
2132a9e74323SJack Morgenstein 	} else if ((ret & IB_MAD_RESULT_SUCCESS) &&
21338e4349d1SIra Weiny 		   generate_unmatched_resp(recv, response, &mad_size, opa)) {
2134c9082e51SIra Weiny 		agent_send_response((const struct ib_mad_hdr *)response->mad, &recv->grh, wc,
2135c9082e51SIra Weiny 				    port_priv->device, port_num,
21368e4349d1SIra Weiny 				    qp_info->qp->qp_num, mad_size, opa);
21371da177e4SLinus Torvalds 	}
21381da177e4SLinus Torvalds 
21391da177e4SLinus Torvalds out:
21401da177e4SLinus Torvalds 	/* Post another receive request for this QP */
21411da177e4SLinus Torvalds 	if (response) {
21421da177e4SLinus Torvalds 		ib_mad_post_receive_mads(qp_info, response);
2143c9082e51SIra Weiny 		kfree(recv);
21441da177e4SLinus Torvalds 	} else
21451da177e4SLinus Torvalds 		ib_mad_post_receive_mads(qp_info, recv);
21461da177e4SLinus Torvalds }
21471da177e4SLinus Torvalds 
adjust_timeout(struct ib_mad_agent_private * mad_agent_priv)21481da177e4SLinus Torvalds static void adjust_timeout(struct ib_mad_agent_private *mad_agent_priv)
21491da177e4SLinus Torvalds {
21501da177e4SLinus Torvalds 	struct ib_mad_send_wr_private *mad_send_wr;
21511da177e4SLinus Torvalds 	unsigned long delay;
21521da177e4SLinus Torvalds 
21531da177e4SLinus Torvalds 	if (list_empty(&mad_agent_priv->wait_list)) {
2154136b5721STejun Heo 		cancel_delayed_work(&mad_agent_priv->timed_work);
21551da177e4SLinus Torvalds 	} else {
21561da177e4SLinus Torvalds 		mad_send_wr = list_entry(mad_agent_priv->wait_list.next,
21571da177e4SLinus Torvalds 					 struct ib_mad_send_wr_private,
21581da177e4SLinus Torvalds 					 agent_list);
21591da177e4SLinus Torvalds 
21601da177e4SLinus Torvalds 		if (time_after(mad_agent_priv->timeout,
21611da177e4SLinus Torvalds 			       mad_send_wr->timeout)) {
21621da177e4SLinus Torvalds 			mad_agent_priv->timeout = mad_send_wr->timeout;
21631da177e4SLinus Torvalds 			delay = mad_send_wr->timeout - jiffies;
21641da177e4SLinus Torvalds 			if ((long)delay <= 0)
21651da177e4SLinus Torvalds 				delay = 1;
2166e7c2f967STejun Heo 			mod_delayed_work(mad_agent_priv->qp_info->port_priv->wq,
21671da177e4SLinus Torvalds 					 &mad_agent_priv->timed_work, delay);
21681da177e4SLinus Torvalds 		}
21691da177e4SLinus Torvalds 	}
21701da177e4SLinus Torvalds }
21711da177e4SLinus Torvalds 
wait_for_response(struct ib_mad_send_wr_private * mad_send_wr)2172d760ce8fSHal Rosenstock static void wait_for_response(struct ib_mad_send_wr_private *mad_send_wr)
21731da177e4SLinus Torvalds {
2174d760ce8fSHal Rosenstock 	struct ib_mad_agent_private *mad_agent_priv;
21751da177e4SLinus Torvalds 	struct ib_mad_send_wr_private *temp_mad_send_wr;
21761da177e4SLinus Torvalds 	struct list_head *list_item;
21771da177e4SLinus Torvalds 	unsigned long delay;
21781da177e4SLinus Torvalds 
2179d760ce8fSHal Rosenstock 	mad_agent_priv = mad_send_wr->mad_agent_priv;
21801da177e4SLinus Torvalds 	list_del(&mad_send_wr->agent_list);
21811da177e4SLinus Torvalds 
21821da177e4SLinus Torvalds 	delay = mad_send_wr->timeout;
21831da177e4SLinus Torvalds 	mad_send_wr->timeout += jiffies;
21841da177e4SLinus Torvalds 
218529bb33ddSHal Rosenstock 	if (delay) {
21861da177e4SLinus Torvalds 		list_for_each_prev(list_item, &mad_agent_priv->wait_list) {
21871da177e4SLinus Torvalds 			temp_mad_send_wr = list_entry(list_item,
21881da177e4SLinus Torvalds 						struct ib_mad_send_wr_private,
21891da177e4SLinus Torvalds 						agent_list);
21901da177e4SLinus Torvalds 			if (time_after(mad_send_wr->timeout,
21911da177e4SLinus Torvalds 				       temp_mad_send_wr->timeout))
21921da177e4SLinus Torvalds 				break;
21931da177e4SLinus Torvalds 		}
2194b6eb7011SWenpeng Liang 	} else {
219529bb33ddSHal Rosenstock 		list_item = &mad_agent_priv->wait_list;
2196b6eb7011SWenpeng Liang 	}
2197b6eb7011SWenpeng Liang 
21981da177e4SLinus Torvalds 	list_add(&mad_send_wr->agent_list, list_item);
21991da177e4SLinus Torvalds 
22001da177e4SLinus Torvalds 	/* Reschedule a work item if we have a shorter timeout */
2201e7c2f967STejun Heo 	if (mad_agent_priv->wait_list.next == &mad_send_wr->agent_list)
2202e7c2f967STejun Heo 		mod_delayed_work(mad_agent_priv->qp_info->port_priv->wq,
22031da177e4SLinus Torvalds 				 &mad_agent_priv->timed_work, delay);
22041da177e4SLinus Torvalds }
22051da177e4SLinus Torvalds 
ib_reset_mad_timeout(struct ib_mad_send_wr_private * mad_send_wr,unsigned long timeout_ms)220603b61ad2SHal Rosenstock void ib_reset_mad_timeout(struct ib_mad_send_wr_private *mad_send_wr,
2207dbace111SLeon Romanovsky 			  unsigned long timeout_ms)
220803b61ad2SHal Rosenstock {
220903b61ad2SHal Rosenstock 	mad_send_wr->timeout = msecs_to_jiffies(timeout_ms);
221003b61ad2SHal Rosenstock 	wait_for_response(mad_send_wr);
221103b61ad2SHal Rosenstock }
221203b61ad2SHal Rosenstock 
22131da177e4SLinus Torvalds /*
22141da177e4SLinus Torvalds  * Process a send work completion
22151da177e4SLinus Torvalds  */
ib_mad_complete_send_wr(struct ib_mad_send_wr_private * mad_send_wr,struct ib_mad_send_wc * mad_send_wc)2216fa619a77SHal Rosenstock void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr,
22171da177e4SLinus Torvalds 			     struct ib_mad_send_wc *mad_send_wc)
22181da177e4SLinus Torvalds {
22191da177e4SLinus Torvalds 	struct ib_mad_agent_private	*mad_agent_priv;
22201da177e4SLinus Torvalds 	unsigned long			flags;
2221fa619a77SHal Rosenstock 	int				ret;
22221da177e4SLinus Torvalds 
2223d760ce8fSHal Rosenstock 	mad_agent_priv = mad_send_wr->mad_agent_priv;
22241da177e4SLinus Torvalds 	spin_lock_irqsave(&mad_agent_priv->lock, flags);
22251471cb6cSIra Weiny 	if (ib_mad_kernel_rmpp_agent(&mad_agent_priv->agent)) {
2226fa619a77SHal Rosenstock 		ret = ib_process_rmpp_send_wc(mad_send_wr, mad_send_wc);
2227fa619a77SHal Rosenstock 		if (ret == IB_RMPP_RESULT_CONSUMED)
2228fa619a77SHal Rosenstock 			goto done;
2229fa619a77SHal Rosenstock 	} else
2230fa619a77SHal Rosenstock 		ret = IB_RMPP_RESULT_UNHANDLED;
2231fa619a77SHal Rosenstock 
22321da177e4SLinus Torvalds 	if (mad_send_wc->status != IB_WC_SUCCESS &&
22331da177e4SLinus Torvalds 	    mad_send_wr->status == IB_WC_SUCCESS) {
22341da177e4SLinus Torvalds 		mad_send_wr->status = mad_send_wc->status;
22351da177e4SLinus Torvalds 		mad_send_wr->refcount -= (mad_send_wr->timeout > 0);
22361da177e4SLinus Torvalds 	}
22371da177e4SLinus Torvalds 
22381da177e4SLinus Torvalds 	if (--mad_send_wr->refcount > 0) {
22391da177e4SLinus Torvalds 		if (mad_send_wr->refcount == 1 && mad_send_wr->timeout &&
22401da177e4SLinus Torvalds 		    mad_send_wr->status == IB_WC_SUCCESS) {
2241d760ce8fSHal Rosenstock 			wait_for_response(mad_send_wr);
22421da177e4SLinus Torvalds 		}
2243fa619a77SHal Rosenstock 		goto done;
22441da177e4SLinus Torvalds 	}
22451da177e4SLinus Torvalds 
22461da177e4SLinus Torvalds 	/* Remove send from MAD agent and notify client of completion */
22471da177e4SLinus Torvalds 	list_del(&mad_send_wr->agent_list);
22481da177e4SLinus Torvalds 	adjust_timeout(mad_agent_priv);
22491da177e4SLinus Torvalds 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
22501da177e4SLinus Torvalds 
22511da177e4SLinus Torvalds 	if (mad_send_wr->status != IB_WC_SUCCESS)
22521da177e4SLinus Torvalds 		mad_send_wc->status = mad_send_wr->status;
225334816ad9SSean Hefty 	if (ret == IB_RMPP_RESULT_INTERNAL)
225434816ad9SSean Hefty 		ib_rmpp_send_handler(mad_send_wc);
225534816ad9SSean Hefty 	else
22561da177e4SLinus Torvalds 		mad_agent_priv->agent.send_handler(&mad_agent_priv->agent,
22571da177e4SLinus Torvalds 						   mad_send_wc);
22581da177e4SLinus Torvalds 
22591da177e4SLinus Torvalds 	/* Release reference on agent taken when sending */
22601b52fa98SSean Hefty 	deref_mad_agent(mad_agent_priv);
2261fa619a77SHal Rosenstock 	return;
2262fa619a77SHal Rosenstock done:
2263fa619a77SHal Rosenstock 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
22641da177e4SLinus Torvalds }
22651da177e4SLinus Torvalds 
ib_mad_send_done(struct ib_cq * cq,struct ib_wc * wc)2266d53e11fdSChristoph Hellwig static void ib_mad_send_done(struct ib_cq *cq, struct ib_wc *wc)
22671da177e4SLinus Torvalds {
2268d53e11fdSChristoph Hellwig 	struct ib_mad_port_private *port_priv = cq->cq_context;
2269d53e11fdSChristoph Hellwig 	struct ib_mad_list_head *mad_list =
2270d53e11fdSChristoph Hellwig 		container_of(wc->wr_cqe, struct ib_mad_list_head, cqe);
22711da177e4SLinus Torvalds 	struct ib_mad_send_wr_private	*mad_send_wr, *queued_send_wr;
22721da177e4SLinus Torvalds 	struct ib_mad_qp_info		*qp_info;
22731da177e4SLinus Torvalds 	struct ib_mad_queue		*send_queue;
227434816ad9SSean Hefty 	struct ib_mad_send_wc		mad_send_wc;
22751da177e4SLinus Torvalds 	unsigned long flags;
22761da177e4SLinus Torvalds 	int ret;
22771da177e4SLinus Torvalds 
2278d53e11fdSChristoph Hellwig 	if (list_empty_careful(&port_priv->port_list))
2279d53e11fdSChristoph Hellwig 		return;
2280d53e11fdSChristoph Hellwig 
2281d53e11fdSChristoph Hellwig 	if (wc->status != IB_WC_SUCCESS) {
2282d53e11fdSChristoph Hellwig 		if (!ib_mad_send_error(port_priv, wc))
2283d53e11fdSChristoph Hellwig 			return;
2284d53e11fdSChristoph Hellwig 	}
2285d53e11fdSChristoph Hellwig 
22861da177e4SLinus Torvalds 	mad_send_wr = container_of(mad_list, struct ib_mad_send_wr_private,
22871da177e4SLinus Torvalds 				   mad_list);
22881da177e4SLinus Torvalds 	send_queue = mad_list->mad_queue;
22891da177e4SLinus Torvalds 	qp_info = send_queue->qp_info;
22901da177e4SLinus Torvalds 
22910e65bae2SIra Weiny 	trace_ib_mad_send_done_agent(mad_send_wr->mad_agent_priv);
22924d60cad5SIra Weiny 	trace_ib_mad_send_done_handler(mad_send_wr, wc);
22934d60cad5SIra Weiny 
22941da177e4SLinus Torvalds retry:
22951527106fSRalph Campbell 	ib_dma_unmap_single(mad_send_wr->send_buf.mad_agent->device,
22961527106fSRalph Campbell 			    mad_send_wr->header_mapping,
229734816ad9SSean Hefty 			    mad_send_wr->sg_list[0].length, DMA_TO_DEVICE);
22981527106fSRalph Campbell 	ib_dma_unmap_single(mad_send_wr->send_buf.mad_agent->device,
22991527106fSRalph Campbell 			    mad_send_wr->payload_mapping,
2300f36e1793SJack Morgenstein 			    mad_send_wr->sg_list[1].length, DMA_TO_DEVICE);
23011da177e4SLinus Torvalds 	queued_send_wr = NULL;
23021da177e4SLinus Torvalds 	spin_lock_irqsave(&send_queue->lock, flags);
23031da177e4SLinus Torvalds 	list_del(&mad_list->list);
23041da177e4SLinus Torvalds 
23051da177e4SLinus Torvalds 	/* Move queued send to the send queue */
23061da177e4SLinus Torvalds 	if (send_queue->count-- > send_queue->max_active) {
23071da177e4SLinus Torvalds 		mad_list = container_of(qp_info->overflow_list.next,
23081da177e4SLinus Torvalds 					struct ib_mad_list_head, list);
23091da177e4SLinus Torvalds 		queued_send_wr = container_of(mad_list,
23101da177e4SLinus Torvalds 					struct ib_mad_send_wr_private,
23111da177e4SLinus Torvalds 					mad_list);
2312179e0917SAkinobu Mita 		list_move_tail(&mad_list->list, &send_queue->list);
23131da177e4SLinus Torvalds 	}
23141da177e4SLinus Torvalds 	spin_unlock_irqrestore(&send_queue->lock, flags);
23151da177e4SLinus Torvalds 
231634816ad9SSean Hefty 	mad_send_wc.send_buf = &mad_send_wr->send_buf;
231734816ad9SSean Hefty 	mad_send_wc.status = wc->status;
231834816ad9SSean Hefty 	mad_send_wc.vendor_err = wc->vendor_err;
231934816ad9SSean Hefty 	ib_mad_complete_send_wr(mad_send_wr, &mad_send_wc);
23201da177e4SLinus Torvalds 
23211da177e4SLinus Torvalds 	if (queued_send_wr) {
23224d60cad5SIra Weiny 		trace_ib_mad_send_done_resend(queued_send_wr, qp_info);
2323e622f2f4SChristoph Hellwig 		ret = ib_post_send(qp_info->qp, &queued_send_wr->send_wr.wr,
23241fec77bfSBart Van Assche 				   NULL);
23251da177e4SLinus Torvalds 		if (ret) {
23267ef5d4b0SIra Weiny 			dev_err(&port_priv->device->dev,
23277ef5d4b0SIra Weiny 				"ib_post_send failed: %d\n", ret);
23281da177e4SLinus Torvalds 			mad_send_wr = queued_send_wr;
23291da177e4SLinus Torvalds 			wc->status = IB_WC_LOC_QP_OP_ERR;
23301da177e4SLinus Torvalds 			goto retry;
23311da177e4SLinus Torvalds 		}
23321da177e4SLinus Torvalds 	}
23331da177e4SLinus Torvalds }
23341da177e4SLinus Torvalds 
mark_sends_for_retry(struct ib_mad_qp_info * qp_info)23351da177e4SLinus Torvalds static void mark_sends_for_retry(struct ib_mad_qp_info *qp_info)
23361da177e4SLinus Torvalds {
23371da177e4SLinus Torvalds 	struct ib_mad_send_wr_private *mad_send_wr;
23381da177e4SLinus Torvalds 	struct ib_mad_list_head *mad_list;
23391da177e4SLinus Torvalds 	unsigned long flags;
23401da177e4SLinus Torvalds 
23411da177e4SLinus Torvalds 	spin_lock_irqsave(&qp_info->send_queue.lock, flags);
23421da177e4SLinus Torvalds 	list_for_each_entry(mad_list, &qp_info->send_queue.list, list) {
23431da177e4SLinus Torvalds 		mad_send_wr = container_of(mad_list,
23441da177e4SLinus Torvalds 					   struct ib_mad_send_wr_private,
23451da177e4SLinus Torvalds 					   mad_list);
23461da177e4SLinus Torvalds 		mad_send_wr->retry = 1;
23471da177e4SLinus Torvalds 	}
23481da177e4SLinus Torvalds 	spin_unlock_irqrestore(&qp_info->send_queue.lock, flags);
23491da177e4SLinus Torvalds }
23501da177e4SLinus Torvalds 
ib_mad_send_error(struct ib_mad_port_private * port_priv,struct ib_wc * wc)2351d53e11fdSChristoph Hellwig static bool ib_mad_send_error(struct ib_mad_port_private *port_priv,
23521da177e4SLinus Torvalds 		struct ib_wc *wc)
23531da177e4SLinus Torvalds {
2354d53e11fdSChristoph Hellwig 	struct ib_mad_list_head *mad_list =
2355d53e11fdSChristoph Hellwig 		container_of(wc->wr_cqe, struct ib_mad_list_head, cqe);
2356d53e11fdSChristoph Hellwig 	struct ib_mad_qp_info *qp_info = mad_list->mad_queue->qp_info;
23571da177e4SLinus Torvalds 	struct ib_mad_send_wr_private *mad_send_wr;
23581da177e4SLinus Torvalds 	int ret;
23591da177e4SLinus Torvalds 
23601da177e4SLinus Torvalds 	/*
23611da177e4SLinus Torvalds 	 * Send errors will transition the QP to SQE - move
23621da177e4SLinus Torvalds 	 * QP to RTS and repost flushed work requests
23631da177e4SLinus Torvalds 	 */
23641da177e4SLinus Torvalds 	mad_send_wr = container_of(mad_list, struct ib_mad_send_wr_private,
23651da177e4SLinus Torvalds 				   mad_list);
23661da177e4SLinus Torvalds 	if (wc->status == IB_WC_WR_FLUSH_ERR) {
23671da177e4SLinus Torvalds 		if (mad_send_wr->retry) {
23681da177e4SLinus Torvalds 			/* Repost send */
23691da177e4SLinus Torvalds 			mad_send_wr->retry = 0;
23704d60cad5SIra Weiny 			trace_ib_mad_error_handler(mad_send_wr, qp_info);
2371e622f2f4SChristoph Hellwig 			ret = ib_post_send(qp_info->qp, &mad_send_wr->send_wr.wr,
23721fec77bfSBart Van Assche 					   NULL);
2373d53e11fdSChristoph Hellwig 			if (!ret)
2374d53e11fdSChristoph Hellwig 				return false;
2375d53e11fdSChristoph Hellwig 		}
23761da177e4SLinus Torvalds 	} else {
23771da177e4SLinus Torvalds 		struct ib_qp_attr *attr;
23781da177e4SLinus Torvalds 
23791da177e4SLinus Torvalds 		/* Transition QP to RTS and fail offending send */
23801da177e4SLinus Torvalds 		attr = kmalloc(sizeof *attr, GFP_KERNEL);
23811da177e4SLinus Torvalds 		if (attr) {
23821da177e4SLinus Torvalds 			attr->qp_state = IB_QPS_RTS;
23831da177e4SLinus Torvalds 			attr->cur_qp_state = IB_QPS_SQE;
23841da177e4SLinus Torvalds 			ret = ib_modify_qp(qp_info->qp, attr,
23851da177e4SLinus Torvalds 					   IB_QP_STATE | IB_QP_CUR_STATE);
23861da177e4SLinus Torvalds 			kfree(attr);
23871da177e4SLinus Torvalds 			if (ret)
23887ef5d4b0SIra Weiny 				dev_err(&port_priv->device->dev,
2389d53e11fdSChristoph Hellwig 					"%s - ib_modify_qp to RTS: %d\n",
2390d53e11fdSChristoph Hellwig 					__func__, ret);
23911da177e4SLinus Torvalds 			else
23921da177e4SLinus Torvalds 				mark_sends_for_retry(qp_info);
23931da177e4SLinus Torvalds 		}
23941da177e4SLinus Torvalds 	}
23951da177e4SLinus Torvalds 
2396d53e11fdSChristoph Hellwig 	return true;
23971da177e4SLinus Torvalds }
23981da177e4SLinus Torvalds 
cancel_mads(struct ib_mad_agent_private * mad_agent_priv)23991da177e4SLinus Torvalds static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv)
24001da177e4SLinus Torvalds {
24011da177e4SLinus Torvalds 	unsigned long flags;
24021da177e4SLinus Torvalds 	struct ib_mad_send_wr_private *mad_send_wr, *temp_mad_send_wr;
24031da177e4SLinus Torvalds 	struct ib_mad_send_wc mad_send_wc;
24041da177e4SLinus Torvalds 	struct list_head cancel_list;
24051da177e4SLinus Torvalds 
24061da177e4SLinus Torvalds 	INIT_LIST_HEAD(&cancel_list);
24071da177e4SLinus Torvalds 
24081da177e4SLinus Torvalds 	spin_lock_irqsave(&mad_agent_priv->lock, flags);
24091da177e4SLinus Torvalds 	list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr,
24101da177e4SLinus Torvalds 				 &mad_agent_priv->send_list, agent_list) {
24111da177e4SLinus Torvalds 		if (mad_send_wr->status == IB_WC_SUCCESS) {
24121da177e4SLinus Torvalds 			mad_send_wr->status = IB_WC_WR_FLUSH_ERR;
24131da177e4SLinus Torvalds 			mad_send_wr->refcount -= (mad_send_wr->timeout > 0);
24141da177e4SLinus Torvalds 		}
24151da177e4SLinus Torvalds 	}
24161da177e4SLinus Torvalds 
24171da177e4SLinus Torvalds 	/* Empty wait list to prevent receives from finding a request */
24181da177e4SLinus Torvalds 	list_splice_init(&mad_agent_priv->wait_list, &cancel_list);
24191da177e4SLinus Torvalds 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
24201da177e4SLinus Torvalds 
24211da177e4SLinus Torvalds 	/* Report all cancelled requests */
24221da177e4SLinus Torvalds 	mad_send_wc.status = IB_WC_WR_FLUSH_ERR;
24231da177e4SLinus Torvalds 	mad_send_wc.vendor_err = 0;
24241da177e4SLinus Torvalds 
24251da177e4SLinus Torvalds 	list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr,
24261da177e4SLinus Torvalds 				 &cancel_list, agent_list) {
242734816ad9SSean Hefty 		mad_send_wc.send_buf = &mad_send_wr->send_buf;
242834816ad9SSean Hefty 		list_del(&mad_send_wr->agent_list);
24291da177e4SLinus Torvalds 		mad_agent_priv->agent.send_handler(&mad_agent_priv->agent,
24301da177e4SLinus Torvalds 						   &mad_send_wc);
2431b9af0e2dSShay Drory 		deref_mad_agent(mad_agent_priv);
24321da177e4SLinus Torvalds 	}
24331da177e4SLinus Torvalds }
24341da177e4SLinus Torvalds 
24351da177e4SLinus Torvalds static struct ib_mad_send_wr_private*
find_send_wr(struct ib_mad_agent_private * mad_agent_priv,struct ib_mad_send_buf * send_buf)243634816ad9SSean Hefty find_send_wr(struct ib_mad_agent_private *mad_agent_priv,
243734816ad9SSean Hefty 	     struct ib_mad_send_buf *send_buf)
24381da177e4SLinus Torvalds {
24391da177e4SLinus Torvalds 	struct ib_mad_send_wr_private *mad_send_wr;
24401da177e4SLinus Torvalds 
24411da177e4SLinus Torvalds 	list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list,
24421da177e4SLinus Torvalds 			    agent_list) {
244334816ad9SSean Hefty 		if (&mad_send_wr->send_buf == send_buf)
24441da177e4SLinus Torvalds 			return mad_send_wr;
24451da177e4SLinus Torvalds 	}
24461da177e4SLinus Torvalds 
24471da177e4SLinus Torvalds 	list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list,
24481da177e4SLinus Torvalds 			    agent_list) {
2449c597eee5SIra Weiny 		if (is_rmpp_data_mad(mad_agent_priv,
2450c597eee5SIra Weiny 				     mad_send_wr->send_buf.mad) &&
245134816ad9SSean Hefty 		    &mad_send_wr->send_buf == send_buf)
24521da177e4SLinus Torvalds 			return mad_send_wr;
24531da177e4SLinus Torvalds 	}
24541da177e4SLinus Torvalds 	return NULL;
24551da177e4SLinus Torvalds }
24561da177e4SLinus Torvalds 
ib_modify_mad(struct ib_mad_send_buf * send_buf,u32 timeout_ms)245770076a41SMark Zhang int ib_modify_mad(struct ib_mad_send_buf *send_buf, u32 timeout_ms)
24581da177e4SLinus Torvalds {
24591da177e4SLinus Torvalds 	struct ib_mad_agent_private *mad_agent_priv;
24601da177e4SLinus Torvalds 	struct ib_mad_send_wr_private *mad_send_wr;
24611da177e4SLinus Torvalds 	unsigned long flags;
2462cabe3cbcSHal Rosenstock 	int active;
24631da177e4SLinus Torvalds 
246470076a41SMark Zhang 	if (!send_buf)
246570076a41SMark Zhang 		return -EINVAL;
246670076a41SMark Zhang 
246770076a41SMark Zhang 	mad_agent_priv = container_of(send_buf->mad_agent,
246870076a41SMark Zhang 				      struct ib_mad_agent_private, agent);
24691da177e4SLinus Torvalds 	spin_lock_irqsave(&mad_agent_priv->lock, flags);
247034816ad9SSean Hefty 	mad_send_wr = find_send_wr(mad_agent_priv, send_buf);
247103b61ad2SHal Rosenstock 	if (!mad_send_wr || mad_send_wr->status != IB_WC_SUCCESS) {
24721da177e4SLinus Torvalds 		spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
247303b61ad2SHal Rosenstock 		return -EINVAL;
24741da177e4SLinus Torvalds 	}
24751da177e4SLinus Torvalds 
2476cabe3cbcSHal Rosenstock 	active = (!mad_send_wr->timeout || mad_send_wr->refcount > 1);
247703b61ad2SHal Rosenstock 	if (!timeout_ms) {
24781da177e4SLinus Torvalds 		mad_send_wr->status = IB_WC_WR_FLUSH_ERR;
247903b61ad2SHal Rosenstock 		mad_send_wr->refcount -= (mad_send_wr->timeout > 0);
24801da177e4SLinus Torvalds 	}
24811da177e4SLinus Torvalds 
248234816ad9SSean Hefty 	mad_send_wr->send_buf.timeout_ms = timeout_ms;
2483cabe3cbcSHal Rosenstock 	if (active)
248403b61ad2SHal Rosenstock 		mad_send_wr->timeout = msecs_to_jiffies(timeout_ms);
248503b61ad2SHal Rosenstock 	else
248603b61ad2SHal Rosenstock 		ib_reset_mad_timeout(mad_send_wr, timeout_ms);
24871da177e4SLinus Torvalds 
248803b61ad2SHal Rosenstock 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
248903b61ad2SHal Rosenstock 	return 0;
249003b61ad2SHal Rosenstock }
249103b61ad2SHal Rosenstock EXPORT_SYMBOL(ib_modify_mad);
249203b61ad2SHal Rosenstock 
local_completions(struct work_struct * work)2493c4028958SDavid Howells static void local_completions(struct work_struct *work)
24941da177e4SLinus Torvalds {
24951da177e4SLinus Torvalds 	struct ib_mad_agent_private *mad_agent_priv;
24961da177e4SLinus Torvalds 	struct ib_mad_local_private *local;
24971da177e4SLinus Torvalds 	struct ib_mad_agent_private *recv_mad_agent;
24981da177e4SLinus Torvalds 	unsigned long flags;
24991d9bc6d6SRalph Campbell 	int free_mad;
25001da177e4SLinus Torvalds 	struct ib_wc wc;
25011da177e4SLinus Torvalds 	struct ib_mad_send_wc mad_send_wc;
25028e4349d1SIra Weiny 	bool opa;
25031da177e4SLinus Torvalds 
2504c4028958SDavid Howells 	mad_agent_priv =
2505c4028958SDavid Howells 		container_of(work, struct ib_mad_agent_private, local_work);
25061da177e4SLinus Torvalds 
25078e4349d1SIra Weiny 	opa = rdma_cap_opa_mad(mad_agent_priv->qp_info->port_priv->device,
25088e4349d1SIra Weiny 			       mad_agent_priv->qp_info->port_priv->port_num);
25098e4349d1SIra Weiny 
25101da177e4SLinus Torvalds 	spin_lock_irqsave(&mad_agent_priv->lock, flags);
25111da177e4SLinus Torvalds 	while (!list_empty(&mad_agent_priv->local_list)) {
25121da177e4SLinus Torvalds 		local = list_entry(mad_agent_priv->local_list.next,
25131da177e4SLinus Torvalds 				   struct ib_mad_local_private,
25141da177e4SLinus Torvalds 				   completion_list);
251537289efeSMichael S. Tsirkin 		list_del(&local->completion_list);
25161da177e4SLinus Torvalds 		spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
25171d9bc6d6SRalph Campbell 		free_mad = 0;
25181da177e4SLinus Torvalds 		if (local->mad_priv) {
25198e4349d1SIra Weiny 			u8 base_version;
25201da177e4SLinus Torvalds 			recv_mad_agent = local->recv_mad_agent;
25211da177e4SLinus Torvalds 			if (!recv_mad_agent) {
25227ef5d4b0SIra Weiny 				dev_err(&mad_agent_priv->agent.device->dev,
25237ef5d4b0SIra Weiny 					"No receive MAD agent for local completion\n");
25241d9bc6d6SRalph Campbell 				free_mad = 1;
25251da177e4SLinus Torvalds 				goto local_send_completion;
25261da177e4SLinus Torvalds 			}
25271da177e4SLinus Torvalds 
25281da177e4SLinus Torvalds 			/*
25291da177e4SLinus Torvalds 			 * Defined behavior is to complete response
25301da177e4SLinus Torvalds 			 * before request
25311da177e4SLinus Torvalds 			 */
2532062dbb69SMichael S. Tsirkin 			build_smp_wc(recv_mad_agent->agent.qp,
2533d53e11fdSChristoph Hellwig 				     local->mad_send_wr->send_wr.wr.wr_cqe,
253497f52eb4SSean Hefty 				     be16_to_cpu(IB_LID_PERMISSIVE),
2535e622f2f4SChristoph Hellwig 				     local->mad_send_wr->send_wr.pkey_index,
25368e4349d1SIra Weiny 				     recv_mad_agent->agent.port_num, &wc);
25371da177e4SLinus Torvalds 
25381da177e4SLinus Torvalds 			local->mad_priv->header.recv_wc.wc = &wc;
25398e4349d1SIra Weiny 
25408e4349d1SIra Weiny 			base_version = ((struct ib_mad_hdr *)(local->mad_priv->mad))->base_version;
25418e4349d1SIra Weiny 			if (opa && base_version == OPA_MGMT_BASE_VERSION) {
25428e4349d1SIra Weiny 				local->mad_priv->header.recv_wc.mad_len = local->return_wc_byte_len;
25438e4349d1SIra Weiny 				local->mad_priv->header.recv_wc.mad_seg_size = sizeof(struct opa_mad);
25448e4349d1SIra Weiny 			} else {
25458e4349d1SIra Weiny 				local->mad_priv->header.recv_wc.mad_len = sizeof(struct ib_mad);
25468e4349d1SIra Weiny 				local->mad_priv->header.recv_wc.mad_seg_size = sizeof(struct ib_mad);
25478e4349d1SIra Weiny 			}
25488e4349d1SIra Weiny 
2549fa619a77SHal Rosenstock 			INIT_LIST_HEAD(&local->mad_priv->header.recv_wc.rmpp_list);
2550fa619a77SHal Rosenstock 			list_add(&local->mad_priv->header.recv_wc.recv_buf.list,
2551fa619a77SHal Rosenstock 				 &local->mad_priv->header.recv_wc.rmpp_list);
25521da177e4SLinus Torvalds 			local->mad_priv->header.recv_wc.recv_buf.grh = NULL;
25531da177e4SLinus Torvalds 			local->mad_priv->header.recv_wc.recv_buf.mad =
2554c9082e51SIra Weiny 						(struct ib_mad *)local->mad_priv->mad;
25551da177e4SLinus Torvalds 			recv_mad_agent->agent.recv_handler(
25561da177e4SLinus Torvalds 						&recv_mad_agent->agent,
2557ca281265SChristoph Hellwig 						&local->mad_send_wr->send_buf,
25581da177e4SLinus Torvalds 						&local->mad_priv->header.recv_wc);
25591da177e4SLinus Torvalds 			spin_lock_irqsave(&recv_mad_agent->lock, flags);
2560b9af0e2dSShay Drory 			deref_mad_agent(recv_mad_agent);
25611da177e4SLinus Torvalds 			spin_unlock_irqrestore(&recv_mad_agent->lock, flags);
25621da177e4SLinus Torvalds 		}
25631da177e4SLinus Torvalds 
25641da177e4SLinus Torvalds local_send_completion:
25651da177e4SLinus Torvalds 		/* Complete send */
25661da177e4SLinus Torvalds 		mad_send_wc.status = IB_WC_SUCCESS;
25671da177e4SLinus Torvalds 		mad_send_wc.vendor_err = 0;
256834816ad9SSean Hefty 		mad_send_wc.send_buf = &local->mad_send_wr->send_buf;
25691da177e4SLinus Torvalds 		mad_agent_priv->agent.send_handler(&mad_agent_priv->agent,
25701da177e4SLinus Torvalds 						   &mad_send_wc);
25711da177e4SLinus Torvalds 
25721da177e4SLinus Torvalds 		spin_lock_irqsave(&mad_agent_priv->lock, flags);
2573b9af0e2dSShay Drory 		deref_mad_agent(mad_agent_priv);
25741d9bc6d6SRalph Campbell 		if (free_mad)
2575c9082e51SIra Weiny 			kfree(local->mad_priv);
25761da177e4SLinus Torvalds 		kfree(local);
25771da177e4SLinus Torvalds 	}
25781da177e4SLinus Torvalds 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
25791da177e4SLinus Torvalds }
25801da177e4SLinus Torvalds 
retry_send(struct ib_mad_send_wr_private * mad_send_wr)2581f75b7a52SHal Rosenstock static int retry_send(struct ib_mad_send_wr_private *mad_send_wr)
2582f75b7a52SHal Rosenstock {
2583f75b7a52SHal Rosenstock 	int ret;
2584f75b7a52SHal Rosenstock 
25854fc8cd49SSean Hefty 	if (!mad_send_wr->retries_left)
2586f75b7a52SHal Rosenstock 		return -ETIMEDOUT;
2587f75b7a52SHal Rosenstock 
25884fc8cd49SSean Hefty 	mad_send_wr->retries_left--;
25894fc8cd49SSean Hefty 	mad_send_wr->send_buf.retries++;
25904fc8cd49SSean Hefty 
259134816ad9SSean Hefty 	mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms);
2592f75b7a52SHal Rosenstock 
25931471cb6cSIra Weiny 	if (ib_mad_kernel_rmpp_agent(&mad_send_wr->mad_agent_priv->agent)) {
2594fa619a77SHal Rosenstock 		ret = ib_retry_rmpp(mad_send_wr);
2595fa619a77SHal Rosenstock 		switch (ret) {
2596fa619a77SHal Rosenstock 		case IB_RMPP_RESULT_UNHANDLED:
2597fa619a77SHal Rosenstock 			ret = ib_send_mad(mad_send_wr);
2598fa619a77SHal Rosenstock 			break;
2599fa619a77SHal Rosenstock 		case IB_RMPP_RESULT_CONSUMED:
2600fa619a77SHal Rosenstock 			ret = 0;
2601fa619a77SHal Rosenstock 			break;
2602fa619a77SHal Rosenstock 		default:
2603fa619a77SHal Rosenstock 			ret = -ECOMM;
2604fa619a77SHal Rosenstock 			break;
2605fa619a77SHal Rosenstock 		}
2606fa619a77SHal Rosenstock 	} else
2607f75b7a52SHal Rosenstock 		ret = ib_send_mad(mad_send_wr);
2608f75b7a52SHal Rosenstock 
2609f75b7a52SHal Rosenstock 	if (!ret) {
2610f75b7a52SHal Rosenstock 		mad_send_wr->refcount++;
2611f75b7a52SHal Rosenstock 		list_add_tail(&mad_send_wr->agent_list,
2612f75b7a52SHal Rosenstock 			      &mad_send_wr->mad_agent_priv->send_list);
2613f75b7a52SHal Rosenstock 	}
2614f75b7a52SHal Rosenstock 	return ret;
2615f75b7a52SHal Rosenstock }
2616f75b7a52SHal Rosenstock 
timeout_sends(struct work_struct * work)2617c4028958SDavid Howells static void timeout_sends(struct work_struct *work)
26181da177e4SLinus Torvalds {
2619*a195a42dSSaravanan Vajravel 	struct ib_mad_send_wr_private *mad_send_wr, *n;
26201da177e4SLinus Torvalds 	struct ib_mad_agent_private *mad_agent_priv;
26211da177e4SLinus Torvalds 	struct ib_mad_send_wc mad_send_wc;
2622*a195a42dSSaravanan Vajravel 	struct list_head local_list;
26231da177e4SLinus Torvalds 	unsigned long flags, delay;
26241da177e4SLinus Torvalds 
2625c4028958SDavid Howells 	mad_agent_priv = container_of(work, struct ib_mad_agent_private,
2626c4028958SDavid Howells 				      timed_work.work);
26271da177e4SLinus Torvalds 	mad_send_wc.vendor_err = 0;
2628*a195a42dSSaravanan Vajravel 	INIT_LIST_HEAD(&local_list);
26291da177e4SLinus Torvalds 
26301da177e4SLinus Torvalds 	spin_lock_irqsave(&mad_agent_priv->lock, flags);
26311da177e4SLinus Torvalds 	while (!list_empty(&mad_agent_priv->wait_list)) {
26321da177e4SLinus Torvalds 		mad_send_wr = list_entry(mad_agent_priv->wait_list.next,
26331da177e4SLinus Torvalds 					 struct ib_mad_send_wr_private,
26341da177e4SLinus Torvalds 					 agent_list);
26351da177e4SLinus Torvalds 
26361da177e4SLinus Torvalds 		if (time_after(mad_send_wr->timeout, jiffies)) {
26371da177e4SLinus Torvalds 			delay = mad_send_wr->timeout - jiffies;
26381da177e4SLinus Torvalds 			if ((long)delay <= 0)
26391da177e4SLinus Torvalds 				delay = 1;
26401da177e4SLinus Torvalds 			queue_delayed_work(mad_agent_priv->qp_info->
26411da177e4SLinus Torvalds 					   port_priv->wq,
26421da177e4SLinus Torvalds 					   &mad_agent_priv->timed_work, delay);
26431da177e4SLinus Torvalds 			break;
26441da177e4SLinus Torvalds 		}
26451da177e4SLinus Torvalds 
2646*a195a42dSSaravanan Vajravel 		list_del_init(&mad_send_wr->agent_list);
264729bb33ddSHal Rosenstock 		if (mad_send_wr->status == IB_WC_SUCCESS &&
264829bb33ddSHal Rosenstock 		    !retry_send(mad_send_wr))
2649f75b7a52SHal Rosenstock 			continue;
2650f75b7a52SHal Rosenstock 
2651*a195a42dSSaravanan Vajravel 		list_add_tail(&mad_send_wr->agent_list, &local_list);
2652*a195a42dSSaravanan Vajravel 	}
26531da177e4SLinus Torvalds 	spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
26541da177e4SLinus Torvalds 
2655*a195a42dSSaravanan Vajravel 	list_for_each_entry_safe(mad_send_wr, n, &local_list, agent_list) {
265603b61ad2SHal Rosenstock 		if (mad_send_wr->status == IB_WC_SUCCESS)
265703b61ad2SHal Rosenstock 			mad_send_wc.status = IB_WC_RESP_TIMEOUT_ERR;
265803b61ad2SHal Rosenstock 		else
265903b61ad2SHal Rosenstock 			mad_send_wc.status = mad_send_wr->status;
266034816ad9SSean Hefty 		mad_send_wc.send_buf = &mad_send_wr->send_buf;
26611da177e4SLinus Torvalds 		mad_agent_priv->agent.send_handler(&mad_agent_priv->agent,
26621da177e4SLinus Torvalds 						   &mad_send_wc);
2663b9af0e2dSShay Drory 		deref_mad_agent(mad_agent_priv);
26641da177e4SLinus Torvalds 	}
26651da177e4SLinus Torvalds }
26661da177e4SLinus Torvalds 
26671da177e4SLinus Torvalds /*
26681da177e4SLinus Torvalds  * Allocate receive MADs and post receive WRs for them
26691da177e4SLinus Torvalds  */
ib_mad_post_receive_mads(struct ib_mad_qp_info * qp_info,struct ib_mad_private * mad)26701da177e4SLinus Torvalds static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info,
26711da177e4SLinus Torvalds 				    struct ib_mad_private *mad)
26721da177e4SLinus Torvalds {
26731da177e4SLinus Torvalds 	unsigned long flags;
26741da177e4SLinus Torvalds 	int post, ret;
26751da177e4SLinus Torvalds 	struct ib_mad_private *mad_priv;
26761da177e4SLinus Torvalds 	struct ib_sge sg_list;
26771fec77bfSBart Van Assche 	struct ib_recv_wr recv_wr;
26781da177e4SLinus Torvalds 	struct ib_mad_queue *recv_queue = &qp_info->recv_queue;
26791da177e4SLinus Torvalds 
26801da177e4SLinus Torvalds 	/* Initialize common scatter list fields */
26814be90bc6SJason Gunthorpe 	sg_list.lkey = qp_info->port_priv->pd->local_dma_lkey;
26821da177e4SLinus Torvalds 
26831da177e4SLinus Torvalds 	/* Initialize common receive WR fields */
26841da177e4SLinus Torvalds 	recv_wr.next = NULL;
26851da177e4SLinus Torvalds 	recv_wr.sg_list = &sg_list;
26861da177e4SLinus Torvalds 	recv_wr.num_sge = 1;
26871da177e4SLinus Torvalds 
26881da177e4SLinus Torvalds 	do {
26891da177e4SLinus Torvalds 		/* Allocate and map receive buffer */
26901da177e4SLinus Torvalds 		if (mad) {
26911da177e4SLinus Torvalds 			mad_priv = mad;
26921da177e4SLinus Torvalds 			mad = NULL;
26931da177e4SLinus Torvalds 		} else {
2694c9082e51SIra Weiny 			mad_priv = alloc_mad_private(port_mad_size(qp_info->port_priv),
2695c9082e51SIra Weiny 						     GFP_ATOMIC);
26961da177e4SLinus Torvalds 			if (!mad_priv) {
26971da177e4SLinus Torvalds 				ret = -ENOMEM;
26981da177e4SLinus Torvalds 				break;
26991da177e4SLinus Torvalds 			}
27001da177e4SLinus Torvalds 		}
2701c9082e51SIra Weiny 		sg_list.length = mad_priv_dma_size(mad_priv);
27021527106fSRalph Campbell 		sg_list.addr = ib_dma_map_single(qp_info->port_priv->device,
27031da177e4SLinus Torvalds 						 &mad_priv->grh,
2704c9082e51SIra Weiny 						 mad_priv_dma_size(mad_priv),
27051da177e4SLinus Torvalds 						 DMA_FROM_DEVICE);
27062c34e68fSYan Burman 		if (unlikely(ib_dma_mapping_error(qp_info->port_priv->device,
27072c34e68fSYan Burman 						  sg_list.addr))) {
2708a17f4bedSFan Guo 			kfree(mad_priv);
27092c34e68fSYan Burman 			ret = -ENOMEM;
27102c34e68fSYan Burman 			break;
27112c34e68fSYan Burman 		}
27121527106fSRalph Campbell 		mad_priv->header.mapping = sg_list.addr;
27131da177e4SLinus Torvalds 		mad_priv->header.mad_list.mad_queue = recv_queue;
2714d53e11fdSChristoph Hellwig 		mad_priv->header.mad_list.cqe.done = ib_mad_recv_done;
2715d53e11fdSChristoph Hellwig 		recv_wr.wr_cqe = &mad_priv->header.mad_list.cqe;
27161da177e4SLinus Torvalds 
27171da177e4SLinus Torvalds 		/* Post receive WR */
27181da177e4SLinus Torvalds 		spin_lock_irqsave(&recv_queue->lock, flags);
27191da177e4SLinus Torvalds 		post = (++recv_queue->count < recv_queue->max_active);
27201da177e4SLinus Torvalds 		list_add_tail(&mad_priv->header.mad_list.list, &recv_queue->list);
27211da177e4SLinus Torvalds 		spin_unlock_irqrestore(&recv_queue->lock, flags);
27221fec77bfSBart Van Assche 		ret = ib_post_recv(qp_info->qp, &recv_wr, NULL);
27231da177e4SLinus Torvalds 		if (ret) {
27241da177e4SLinus Torvalds 			spin_lock_irqsave(&recv_queue->lock, flags);
27251da177e4SLinus Torvalds 			list_del(&mad_priv->header.mad_list.list);
27261da177e4SLinus Torvalds 			recv_queue->count--;
27271da177e4SLinus Torvalds 			spin_unlock_irqrestore(&recv_queue->lock, flags);
27281527106fSRalph Campbell 			ib_dma_unmap_single(qp_info->port_priv->device,
27291527106fSRalph Campbell 					    mad_priv->header.mapping,
2730c9082e51SIra Weiny 					    mad_priv_dma_size(mad_priv),
27311da177e4SLinus Torvalds 					    DMA_FROM_DEVICE);
2732c9082e51SIra Weiny 			kfree(mad_priv);
27337ef5d4b0SIra Weiny 			dev_err(&qp_info->port_priv->device->dev,
27347ef5d4b0SIra Weiny 				"ib_post_recv failed: %d\n", ret);
27351da177e4SLinus Torvalds 			break;
27361da177e4SLinus Torvalds 		}
27371da177e4SLinus Torvalds 	} while (post);
27381da177e4SLinus Torvalds 
27391da177e4SLinus Torvalds 	return ret;
27401da177e4SLinus Torvalds }
27411da177e4SLinus Torvalds 
27421da177e4SLinus Torvalds /*
27431da177e4SLinus Torvalds  * Return all the posted receive MADs
27441da177e4SLinus Torvalds  */
cleanup_recv_queue(struct ib_mad_qp_info * qp_info)27451da177e4SLinus Torvalds static void cleanup_recv_queue(struct ib_mad_qp_info *qp_info)
27461da177e4SLinus Torvalds {
27471da177e4SLinus Torvalds 	struct ib_mad_private_header *mad_priv_hdr;
27481da177e4SLinus Torvalds 	struct ib_mad_private *recv;
27491da177e4SLinus Torvalds 	struct ib_mad_list_head *mad_list;
27501da177e4SLinus Torvalds 
2751fac70d51SEli Cohen 	if (!qp_info->qp)
2752fac70d51SEli Cohen 		return;
2753fac70d51SEli Cohen 
27541da177e4SLinus Torvalds 	while (!list_empty(&qp_info->recv_queue.list)) {
27551da177e4SLinus Torvalds 
27561da177e4SLinus Torvalds 		mad_list = list_entry(qp_info->recv_queue.list.next,
27571da177e4SLinus Torvalds 				      struct ib_mad_list_head, list);
27581da177e4SLinus Torvalds 		mad_priv_hdr = container_of(mad_list,
27591da177e4SLinus Torvalds 					    struct ib_mad_private_header,
27601da177e4SLinus Torvalds 					    mad_list);
27611da177e4SLinus Torvalds 		recv = container_of(mad_priv_hdr, struct ib_mad_private,
27621da177e4SLinus Torvalds 				    header);
27631da177e4SLinus Torvalds 
27641da177e4SLinus Torvalds 		/* Remove from posted receive MAD list */
27651da177e4SLinus Torvalds 		list_del(&mad_list->list);
27661da177e4SLinus Torvalds 
27671527106fSRalph Campbell 		ib_dma_unmap_single(qp_info->port_priv->device,
27681527106fSRalph Campbell 				    recv->header.mapping,
2769c9082e51SIra Weiny 				    mad_priv_dma_size(recv),
27701da177e4SLinus Torvalds 				    DMA_FROM_DEVICE);
2771c9082e51SIra Weiny 		kfree(recv);
27721da177e4SLinus Torvalds 	}
27731da177e4SLinus Torvalds 
27741da177e4SLinus Torvalds 	qp_info->recv_queue.count = 0;
27751da177e4SLinus Torvalds }
27761da177e4SLinus Torvalds 
27771da177e4SLinus Torvalds /*
27781da177e4SLinus Torvalds  * Start the port
27791da177e4SLinus Torvalds  */
ib_mad_port_start(struct ib_mad_port_private * port_priv)27801da177e4SLinus Torvalds static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
27811da177e4SLinus Torvalds {
27821da177e4SLinus Torvalds 	int ret, i;
27831da177e4SLinus Torvalds 	struct ib_qp_attr *attr;
27841da177e4SLinus Torvalds 	struct ib_qp *qp;
2785ef5ed416SJack Morgenstein 	u16 pkey_index;
27861da177e4SLinus Torvalds 
27871da177e4SLinus Torvalds 	attr = kmalloc(sizeof *attr, GFP_KERNEL);
278827162432SLeon Romanovsky 	if (!attr)
27891da177e4SLinus Torvalds 		return -ENOMEM;
27901da177e4SLinus Torvalds 
2791ef5ed416SJack Morgenstein 	ret = ib_find_pkey(port_priv->device, port_priv->port_num,
2792ef5ed416SJack Morgenstein 			   IB_DEFAULT_PKEY_FULL, &pkey_index);
2793ef5ed416SJack Morgenstein 	if (ret)
2794ef5ed416SJack Morgenstein 		pkey_index = 0;
2795ef5ed416SJack Morgenstein 
27961da177e4SLinus Torvalds 	for (i = 0; i < IB_MAD_QPS_CORE; i++) {
27971da177e4SLinus Torvalds 		qp = port_priv->qp_info[i].qp;
2798fac70d51SEli Cohen 		if (!qp)
2799fac70d51SEli Cohen 			continue;
2800fac70d51SEli Cohen 
28011da177e4SLinus Torvalds 		/*
28021da177e4SLinus Torvalds 		 * PKey index for QP1 is irrelevant but
28031da177e4SLinus Torvalds 		 * one is needed for the Reset to Init transition
28041da177e4SLinus Torvalds 		 */
28051da177e4SLinus Torvalds 		attr->qp_state = IB_QPS_INIT;
2806ef5ed416SJack Morgenstein 		attr->pkey_index = pkey_index;
28071da177e4SLinus Torvalds 		attr->qkey = (qp->qp_num == 0) ? 0 : IB_QP1_QKEY;
28081da177e4SLinus Torvalds 		ret = ib_modify_qp(qp, attr, IB_QP_STATE |
28091da177e4SLinus Torvalds 					     IB_QP_PKEY_INDEX | IB_QP_QKEY);
28101da177e4SLinus Torvalds 		if (ret) {
28117ef5d4b0SIra Weiny 			dev_err(&port_priv->device->dev,
28127ef5d4b0SIra Weiny 				"Couldn't change QP%d state to INIT: %d\n",
28137ef5d4b0SIra Weiny 				i, ret);
28141da177e4SLinus Torvalds 			goto out;
28151da177e4SLinus Torvalds 		}
28161da177e4SLinus Torvalds 
28171da177e4SLinus Torvalds 		attr->qp_state = IB_QPS_RTR;
28181da177e4SLinus Torvalds 		ret = ib_modify_qp(qp, attr, IB_QP_STATE);
28191da177e4SLinus Torvalds 		if (ret) {
28207ef5d4b0SIra Weiny 			dev_err(&port_priv->device->dev,
28217ef5d4b0SIra Weiny 				"Couldn't change QP%d state to RTR: %d\n",
28227ef5d4b0SIra Weiny 				i, ret);
28231da177e4SLinus Torvalds 			goto out;
28241da177e4SLinus Torvalds 		}
28251da177e4SLinus Torvalds 
28261da177e4SLinus Torvalds 		attr->qp_state = IB_QPS_RTS;
28271da177e4SLinus Torvalds 		attr->sq_psn = IB_MAD_SEND_Q_PSN;
28281da177e4SLinus Torvalds 		ret = ib_modify_qp(qp, attr, IB_QP_STATE | IB_QP_SQ_PSN);
28291da177e4SLinus Torvalds 		if (ret) {
28307ef5d4b0SIra Weiny 			dev_err(&port_priv->device->dev,
28317ef5d4b0SIra Weiny 				"Couldn't change QP%d state to RTS: %d\n",
28327ef5d4b0SIra Weiny 				i, ret);
28331da177e4SLinus Torvalds 			goto out;
28341da177e4SLinus Torvalds 		}
28351da177e4SLinus Torvalds 	}
28361da177e4SLinus Torvalds 
28371da177e4SLinus Torvalds 	ret = ib_req_notify_cq(port_priv->cq, IB_CQ_NEXT_COMP);
28381da177e4SLinus Torvalds 	if (ret) {
28397ef5d4b0SIra Weiny 		dev_err(&port_priv->device->dev,
28407ef5d4b0SIra Weiny 			"Failed to request completion notification: %d\n",
28417ef5d4b0SIra Weiny 			ret);
28421da177e4SLinus Torvalds 		goto out;
28431da177e4SLinus Torvalds 	}
28441da177e4SLinus Torvalds 
28451da177e4SLinus Torvalds 	for (i = 0; i < IB_MAD_QPS_CORE; i++) {
2846fac70d51SEli Cohen 		if (!port_priv->qp_info[i].qp)
2847fac70d51SEli Cohen 			continue;
2848fac70d51SEli Cohen 
28491da177e4SLinus Torvalds 		ret = ib_mad_post_receive_mads(&port_priv->qp_info[i], NULL);
28501da177e4SLinus Torvalds 		if (ret) {
28517ef5d4b0SIra Weiny 			dev_err(&port_priv->device->dev,
28527ef5d4b0SIra Weiny 				"Couldn't post receive WRs\n");
28531da177e4SLinus Torvalds 			goto out;
28541da177e4SLinus Torvalds 		}
28551da177e4SLinus Torvalds 	}
28561da177e4SLinus Torvalds out:
28571da177e4SLinus Torvalds 	kfree(attr);
28581da177e4SLinus Torvalds 	return ret;
28591da177e4SLinus Torvalds }
28601da177e4SLinus Torvalds 
qp_event_handler(struct ib_event * event,void * qp_context)28611da177e4SLinus Torvalds static void qp_event_handler(struct ib_event *event, void *qp_context)
28621da177e4SLinus Torvalds {
28631da177e4SLinus Torvalds 	struct ib_mad_qp_info	*qp_info = qp_context;
28641da177e4SLinus Torvalds 
28651da177e4SLinus Torvalds 	/* It's worse than that! He's dead, Jim! */
28667ef5d4b0SIra Weiny 	dev_err(&qp_info->port_priv->device->dev,
28673cea7b4aSWenpeng Liang 		"Fatal error (%d) on MAD QP (%u)\n",
28681da177e4SLinus Torvalds 		event->event, qp_info->qp->qp_num);
28691da177e4SLinus Torvalds }
28701da177e4SLinus Torvalds 
init_mad_queue(struct ib_mad_qp_info * qp_info,struct ib_mad_queue * mad_queue)28711da177e4SLinus Torvalds static void init_mad_queue(struct ib_mad_qp_info *qp_info,
28721da177e4SLinus Torvalds 			   struct ib_mad_queue *mad_queue)
28731da177e4SLinus Torvalds {
28741da177e4SLinus Torvalds 	mad_queue->qp_info = qp_info;
28751da177e4SLinus Torvalds 	mad_queue->count = 0;
28761da177e4SLinus Torvalds 	spin_lock_init(&mad_queue->lock);
28771da177e4SLinus Torvalds 	INIT_LIST_HEAD(&mad_queue->list);
28781da177e4SLinus Torvalds }
28791da177e4SLinus Torvalds 
init_mad_qp(struct ib_mad_port_private * port_priv,struct ib_mad_qp_info * qp_info)28801da177e4SLinus Torvalds static void init_mad_qp(struct ib_mad_port_private *port_priv,
28811da177e4SLinus Torvalds 			struct ib_mad_qp_info *qp_info)
28821da177e4SLinus Torvalds {
28831da177e4SLinus Torvalds 	qp_info->port_priv = port_priv;
28841da177e4SLinus Torvalds 	init_mad_queue(qp_info, &qp_info->send_queue);
28851da177e4SLinus Torvalds 	init_mad_queue(qp_info, &qp_info->recv_queue);
28861da177e4SLinus Torvalds 	INIT_LIST_HEAD(&qp_info->overflow_list);
28871da177e4SLinus Torvalds }
28881da177e4SLinus Torvalds 
create_mad_qp(struct ib_mad_qp_info * qp_info,enum ib_qp_type qp_type)28891da177e4SLinus Torvalds static int create_mad_qp(struct ib_mad_qp_info *qp_info,
28901da177e4SLinus Torvalds 			 enum ib_qp_type qp_type)
28911da177e4SLinus Torvalds {
28921da177e4SLinus Torvalds 	struct ib_qp_init_attr	qp_init_attr;
28931da177e4SLinus Torvalds 	int ret;
28941da177e4SLinus Torvalds 
28951da177e4SLinus Torvalds 	memset(&qp_init_attr, 0, sizeof qp_init_attr);
28961da177e4SLinus Torvalds 	qp_init_attr.send_cq = qp_info->port_priv->cq;
28971da177e4SLinus Torvalds 	qp_init_attr.recv_cq = qp_info->port_priv->cq;
28981da177e4SLinus Torvalds 	qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
2899b76aabc3SHal Rosenstock 	qp_init_attr.cap.max_send_wr = mad_sendq_size;
2900b76aabc3SHal Rosenstock 	qp_init_attr.cap.max_recv_wr = mad_recvq_size;
29011da177e4SLinus Torvalds 	qp_init_attr.cap.max_send_sge = IB_MAD_SEND_REQ_MAX_SG;
29021da177e4SLinus Torvalds 	qp_init_attr.cap.max_recv_sge = IB_MAD_RECV_REQ_MAX_SG;
29031da177e4SLinus Torvalds 	qp_init_attr.qp_type = qp_type;
29041da177e4SLinus Torvalds 	qp_init_attr.port_num = qp_info->port_priv->port_num;
29051da177e4SLinus Torvalds 	qp_init_attr.qp_context = qp_info;
29061da177e4SLinus Torvalds 	qp_init_attr.event_handler = qp_event_handler;
29071da177e4SLinus Torvalds 	qp_info->qp = ib_create_qp(qp_info->port_priv->pd, &qp_init_attr);
29081da177e4SLinus Torvalds 	if (IS_ERR(qp_info->qp)) {
29097ef5d4b0SIra Weiny 		dev_err(&qp_info->port_priv->device->dev,
29107ef5d4b0SIra Weiny 			"Couldn't create ib_mad QP%d\n",
29111da177e4SLinus Torvalds 			get_spl_qp_index(qp_type));
29121da177e4SLinus Torvalds 		ret = PTR_ERR(qp_info->qp);
29131da177e4SLinus Torvalds 		goto error;
29141da177e4SLinus Torvalds 	}
29151da177e4SLinus Torvalds 	/* Use minimum queue sizes unless the CQ is resized */
2916b76aabc3SHal Rosenstock 	qp_info->send_queue.max_active = mad_sendq_size;
2917b76aabc3SHal Rosenstock 	qp_info->recv_queue.max_active = mad_recvq_size;
29181da177e4SLinus Torvalds 	return 0;
29191da177e4SLinus Torvalds 
29201da177e4SLinus Torvalds error:
29211da177e4SLinus Torvalds 	return ret;
29221da177e4SLinus Torvalds }
29231da177e4SLinus Torvalds 
destroy_mad_qp(struct ib_mad_qp_info * qp_info)29241da177e4SLinus Torvalds static void destroy_mad_qp(struct ib_mad_qp_info *qp_info)
29251da177e4SLinus Torvalds {
2926fac70d51SEli Cohen 	if (!qp_info->qp)
2927fac70d51SEli Cohen 		return;
2928fac70d51SEli Cohen 
29291da177e4SLinus Torvalds 	ib_destroy_qp(qp_info->qp);
29301da177e4SLinus Torvalds }
29311da177e4SLinus Torvalds 
29321da177e4SLinus Torvalds /*
29331da177e4SLinus Torvalds  * Open the port
29341da177e4SLinus Torvalds  * Create the QP, PD, MR, and CQ if needed
29351da177e4SLinus Torvalds  */
ib_mad_port_open(struct ib_device * device,u32 port_num)29361da177e4SLinus Torvalds static int ib_mad_port_open(struct ib_device *device,
29371fb7f897SMark Bloch 			    u32 port_num)
29381da177e4SLinus Torvalds {
29391da177e4SLinus Torvalds 	int ret, cq_size;
29401da177e4SLinus Torvalds 	struct ib_mad_port_private *port_priv;
29411da177e4SLinus Torvalds 	unsigned long flags;
29421da177e4SLinus Torvalds 	char name[sizeof "ib_mad123"];
2943fac70d51SEli Cohen 	int has_smi;
29441da177e4SLinus Torvalds 
2945337877a4SIra Weiny 	if (WARN_ON(rdma_max_mad_size(device, port_num) < IB_MGMT_MAD_SIZE))
2946337877a4SIra Weiny 		return -EFAULT;
2947337877a4SIra Weiny 
2948548ead17SIra Weiny 	if (WARN_ON(rdma_cap_opa_mad(device, port_num) &&
2949548ead17SIra Weiny 		    rdma_max_mad_size(device, port_num) < OPA_MGMT_MAD_SIZE))
2950548ead17SIra Weiny 		return -EFAULT;
2951548ead17SIra Weiny 
29521da177e4SLinus Torvalds 	/* Create new device info */
2953de6eb66bSRoland Dreier 	port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL);
295427162432SLeon Romanovsky 	if (!port_priv)
29551da177e4SLinus Torvalds 		return -ENOMEM;
2956de6eb66bSRoland Dreier 
29571da177e4SLinus Torvalds 	port_priv->device = device;
29581da177e4SLinus Torvalds 	port_priv->port_num = port_num;
29591da177e4SLinus Torvalds 	spin_lock_init(&port_priv->reg_lock);
29601da177e4SLinus Torvalds 	init_mad_qp(port_priv, &port_priv->qp_info[0]);
29611da177e4SLinus Torvalds 	init_mad_qp(port_priv, &port_priv->qp_info[1]);
29621da177e4SLinus Torvalds 
2963fac70d51SEli Cohen 	cq_size = mad_sendq_size + mad_recvq_size;
296429541e3aSMichael Wang 	has_smi = rdma_cap_ib_smi(device, port_num);
2965fac70d51SEli Cohen 	if (has_smi)
2966fac70d51SEli Cohen 		cq_size *= 2;
2967fac70d51SEli Cohen 
2968770b7d96SJack Morgenstein 	port_priv->pd = ib_alloc_pd(device, 0);
2969770b7d96SJack Morgenstein 	if (IS_ERR(port_priv->pd)) {
2970770b7d96SJack Morgenstein 		dev_err(&device->dev, "Couldn't create ib_mad PD\n");
2971770b7d96SJack Morgenstein 		ret = PTR_ERR(port_priv->pd);
2972770b7d96SJack Morgenstein 		goto error3;
2973770b7d96SJack Morgenstein 	}
2974770b7d96SJack Morgenstein 
2975d53e11fdSChristoph Hellwig 	port_priv->cq = ib_alloc_cq(port_priv->device, port_priv, cq_size, 0,
2976f794809aSJack Morgenstein 			IB_POLL_UNBOUND_WORKQUEUE);
29771da177e4SLinus Torvalds 	if (IS_ERR(port_priv->cq)) {
29787ef5d4b0SIra Weiny 		dev_err(&device->dev, "Couldn't create ib_mad CQ\n");
29791da177e4SLinus Torvalds 		ret = PTR_ERR(port_priv->cq);
29801da177e4SLinus Torvalds 		goto error4;
29811da177e4SLinus Torvalds 	}
29821da177e4SLinus Torvalds 
2983fac70d51SEli Cohen 	if (has_smi) {
29841da177e4SLinus Torvalds 		ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI);
29851da177e4SLinus Torvalds 		if (ret)
29861da177e4SLinus Torvalds 			goto error6;
2987fac70d51SEli Cohen 	}
29881da177e4SLinus Torvalds 	ret = create_mad_qp(&port_priv->qp_info[1], IB_QPT_GSI);
29891da177e4SLinus Torvalds 	if (ret)
29901da177e4SLinus Torvalds 		goto error7;
29911da177e4SLinus Torvalds 
29921fb7f897SMark Bloch 	snprintf(name, sizeof(name), "ib_mad%u", port_num);
29931c99e299SBhaktipriya Shridhar 	port_priv->wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM);
29941da177e4SLinus Torvalds 	if (!port_priv->wq) {
29951da177e4SLinus Torvalds 		ret = -ENOMEM;
29961da177e4SLinus Torvalds 		goto error8;
29971da177e4SLinus Torvalds 	}
29981da177e4SLinus Torvalds 
2999dc05980dSMichael S. Tsirkin 	spin_lock_irqsave(&ib_mad_port_list_lock, flags);
3000dc05980dSMichael S. Tsirkin 	list_add_tail(&port_priv->port_list, &ib_mad_port_list);
3001dc05980dSMichael S. Tsirkin 	spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
3002dc05980dSMichael S. Tsirkin 
30031da177e4SLinus Torvalds 	ret = ib_mad_port_start(port_priv);
30041da177e4SLinus Torvalds 	if (ret) {
30057ef5d4b0SIra Weiny 		dev_err(&device->dev, "Couldn't start port\n");
30061da177e4SLinus Torvalds 		goto error9;
30071da177e4SLinus Torvalds 	}
30081da177e4SLinus Torvalds 
30091da177e4SLinus Torvalds 	return 0;
30101da177e4SLinus Torvalds 
30111da177e4SLinus Torvalds error9:
3012dc05980dSMichael S. Tsirkin 	spin_lock_irqsave(&ib_mad_port_list_lock, flags);
3013dc05980dSMichael S. Tsirkin 	list_del_init(&port_priv->port_list);
3014dc05980dSMichael S. Tsirkin 	spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
3015dc05980dSMichael S. Tsirkin 
30161da177e4SLinus Torvalds 	destroy_workqueue(port_priv->wq);
30171da177e4SLinus Torvalds error8:
30181da177e4SLinus Torvalds 	destroy_mad_qp(&port_priv->qp_info[1]);
30191da177e4SLinus Torvalds error7:
30201da177e4SLinus Torvalds 	destroy_mad_qp(&port_priv->qp_info[0]);
30211da177e4SLinus Torvalds error6:
3022d53e11fdSChristoph Hellwig 	ib_free_cq(port_priv->cq);
30231da177e4SLinus Torvalds 	cleanup_recv_queue(&port_priv->qp_info[1]);
30241da177e4SLinus Torvalds 	cleanup_recv_queue(&port_priv->qp_info[0]);
3025770b7d96SJack Morgenstein error4:
3026770b7d96SJack Morgenstein 	ib_dealloc_pd(port_priv->pd);
30271da177e4SLinus Torvalds error3:
30281da177e4SLinus Torvalds 	kfree(port_priv);
30291da177e4SLinus Torvalds 
30301da177e4SLinus Torvalds 	return ret;
30311da177e4SLinus Torvalds }
30321da177e4SLinus Torvalds 
30331da177e4SLinus Torvalds /*
30341da177e4SLinus Torvalds  * Close the port
30351da177e4SLinus Torvalds  * If there are no classes using the port, free the port
30361da177e4SLinus Torvalds  * resources (CQ, MR, PD, QP) and remove the port's info structure
30371da177e4SLinus Torvalds  */
ib_mad_port_close(struct ib_device * device,u32 port_num)30381fb7f897SMark Bloch static int ib_mad_port_close(struct ib_device *device, u32 port_num)
30391da177e4SLinus Torvalds {
30401da177e4SLinus Torvalds 	struct ib_mad_port_private *port_priv;
30411da177e4SLinus Torvalds 	unsigned long flags;
30421da177e4SLinus Torvalds 
30431da177e4SLinus Torvalds 	spin_lock_irqsave(&ib_mad_port_list_lock, flags);
30441da177e4SLinus Torvalds 	port_priv = __ib_get_mad_port(device, port_num);
30451da177e4SLinus Torvalds 	if (port_priv == NULL) {
30461da177e4SLinus Torvalds 		spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
30471fb7f897SMark Bloch 		dev_err(&device->dev, "Port %u not found\n", port_num);
30481da177e4SLinus Torvalds 		return -ENODEV;
30491da177e4SLinus Torvalds 	}
3050dc05980dSMichael S. Tsirkin 	list_del_init(&port_priv->port_list);
30511da177e4SLinus Torvalds 	spin_unlock_irqrestore(&ib_mad_port_list_lock, flags);
30521da177e4SLinus Torvalds 
30531da177e4SLinus Torvalds 	destroy_workqueue(port_priv->wq);
30541da177e4SLinus Torvalds 	destroy_mad_qp(&port_priv->qp_info[1]);
30551da177e4SLinus Torvalds 	destroy_mad_qp(&port_priv->qp_info[0]);
3056d53e11fdSChristoph Hellwig 	ib_free_cq(port_priv->cq);
3057770b7d96SJack Morgenstein 	ib_dealloc_pd(port_priv->pd);
30581da177e4SLinus Torvalds 	cleanup_recv_queue(&port_priv->qp_info[1]);
30591da177e4SLinus Torvalds 	cleanup_recv_queue(&port_priv->qp_info[0]);
30601da177e4SLinus Torvalds 	/* XXX: Handle deallocation of MAD registration tables */
30611da177e4SLinus Torvalds 
30621da177e4SLinus Torvalds 	kfree(port_priv);
30631da177e4SLinus Torvalds 
30641da177e4SLinus Torvalds 	return 0;
30651da177e4SLinus Torvalds }
30661da177e4SLinus Torvalds 
ib_mad_init_device(struct ib_device * device)306711a0ae4cSJason Gunthorpe static int ib_mad_init_device(struct ib_device *device)
30681da177e4SLinus Torvalds {
30694139032bSHal Rosenstock 	int start, i;
307011a0ae4cSJason Gunthorpe 	unsigned int count = 0;
307111a0ae4cSJason Gunthorpe 	int ret;
30721da177e4SLinus Torvalds 
30734139032bSHal Rosenstock 	start = rdma_start_port(device);
30744ab6fb7eSRoland Dreier 
30754139032bSHal Rosenstock 	for (i = start; i <= rdma_end_port(device); i++) {
3076c757dea8SMichael Wang 		if (!rdma_cap_ib_mad(device, i))
3077827f2a8bSMichael Wang 			continue;
3078827f2a8bSMichael Wang 
307911a0ae4cSJason Gunthorpe 		ret = ib_mad_port_open(device, i);
308011a0ae4cSJason Gunthorpe 		if (ret) {
30817ef5d4b0SIra Weiny 			dev_err(&device->dev, "Couldn't open port %d\n", i);
30824ab6fb7eSRoland Dreier 			goto error;
30831da177e4SLinus Torvalds 		}
308411a0ae4cSJason Gunthorpe 		ret = ib_agent_port_open(device, i);
308511a0ae4cSJason Gunthorpe 		if (ret) {
30867ef5d4b0SIra Weiny 			dev_err(&device->dev,
30877ef5d4b0SIra Weiny 				"Couldn't open port %d for agents\n", i);
30884ab6fb7eSRoland Dreier 			goto error_agent;
30891da177e4SLinus Torvalds 		}
309011a0ae4cSJason Gunthorpe 		count++;
30911da177e4SLinus Torvalds 	}
309211a0ae4cSJason Gunthorpe 	if (!count)
309311a0ae4cSJason Gunthorpe 		return -EOPNOTSUPP;
309411a0ae4cSJason Gunthorpe 
309511a0ae4cSJason Gunthorpe 	return 0;
30961da177e4SLinus Torvalds 
30974ab6fb7eSRoland Dreier error_agent:
30984ab6fb7eSRoland Dreier 	if (ib_mad_port_close(device, i))
30997ef5d4b0SIra Weiny 		dev_err(&device->dev, "Couldn't close port %d\n", i);
31004ab6fb7eSRoland Dreier 
31014ab6fb7eSRoland Dreier error:
3102827f2a8bSMichael Wang 	while (--i >= start) {
3103c757dea8SMichael Wang 		if (!rdma_cap_ib_mad(device, i))
3104827f2a8bSMichael Wang 			continue;
31054ab6fb7eSRoland Dreier 
31064ab6fb7eSRoland Dreier 		if (ib_agent_port_close(device, i))
31077ef5d4b0SIra Weiny 			dev_err(&device->dev,
31087ef5d4b0SIra Weiny 				"Couldn't close port %d for agents\n", i);
31094ab6fb7eSRoland Dreier 		if (ib_mad_port_close(device, i))
31107ef5d4b0SIra Weiny 			dev_err(&device->dev, "Couldn't close port %d\n", i);
31111da177e4SLinus Torvalds 	}
311211a0ae4cSJason Gunthorpe 	return ret;
31131da177e4SLinus Torvalds }
31141da177e4SLinus Torvalds 
ib_mad_remove_device(struct ib_device * device,void * client_data)31157c1eb45aSHaggai Eran static void ib_mad_remove_device(struct ib_device *device, void *client_data)
31161da177e4SLinus Torvalds {
3117ea1075edSJason Gunthorpe 	unsigned int i;
3118070e140cSSteve Wise 
3119ea1075edSJason Gunthorpe 	rdma_for_each_port (device, i) {
3120c757dea8SMichael Wang 		if (!rdma_cap_ib_mad(device, i))
3121827f2a8bSMichael Wang 			continue;
3122827f2a8bSMichael Wang 
3123827f2a8bSMichael Wang 		if (ib_agent_port_close(device, i))
31247ef5d4b0SIra Weiny 			dev_err(&device->dev,
31253cea7b4aSWenpeng Liang 				"Couldn't close port %u for agents\n", i);
3126827f2a8bSMichael Wang 		if (ib_mad_port_close(device, i))
31273cea7b4aSWenpeng Liang 			dev_err(&device->dev, "Couldn't close port %u\n", i);
31281da177e4SLinus Torvalds 	}
31291da177e4SLinus Torvalds }
31301da177e4SLinus Torvalds 
31311da177e4SLinus Torvalds static struct ib_client mad_client = {
31321da177e4SLinus Torvalds 	.name   = "mad",
31331da177e4SLinus Torvalds 	.add = ib_mad_init_device,
31341da177e4SLinus Torvalds 	.remove = ib_mad_remove_device
31351da177e4SLinus Torvalds };
31361da177e4SLinus Torvalds 
ib_mad_init(void)31374c2cb422SMark Bloch int ib_mad_init(void)
31381da177e4SLinus Torvalds {
3139b76aabc3SHal Rosenstock 	mad_recvq_size = min(mad_recvq_size, IB_MAD_QP_MAX_SIZE);
3140b76aabc3SHal Rosenstock 	mad_recvq_size = max(mad_recvq_size, IB_MAD_QP_MIN_SIZE);
3141b76aabc3SHal Rosenstock 
3142b76aabc3SHal Rosenstock 	mad_sendq_size = min(mad_sendq_size, IB_MAD_QP_MAX_SIZE);
3143b76aabc3SHal Rosenstock 	mad_sendq_size = max(mad_sendq_size, IB_MAD_QP_MIN_SIZE);
3144b76aabc3SHal Rosenstock 
31451da177e4SLinus Torvalds 	INIT_LIST_HEAD(&ib_mad_port_list);
31461da177e4SLinus Torvalds 
31471da177e4SLinus Torvalds 	if (ib_register_client(&mad_client)) {
31487ef5d4b0SIra Weiny 		pr_err("Couldn't register ib_mad client\n");
3149c9082e51SIra Weiny 		return -EINVAL;
31501da177e4SLinus Torvalds 	}
31511da177e4SLinus Torvalds 
31521da177e4SLinus Torvalds 	return 0;
31531da177e4SLinus Torvalds }
31541da177e4SLinus Torvalds 
ib_mad_cleanup(void)31554c2cb422SMark Bloch void ib_mad_cleanup(void)
31561da177e4SLinus Torvalds {
31571da177e4SLinus Torvalds 	ib_unregister_client(&mad_client);
31581da177e4SLinus Torvalds }
3159