| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-08-10 23:03:10 -07:00
										 |  |  |  * Copyright (c) 2004, 2005 Mellanox Technologies Ltd.  All rights reserved. | 
					
						
							|  |  |  |  * Copyright (c) 2004, 2005 Infinicon Corporation.  All rights reserved. | 
					
						
							|  |  |  |  * Copyright (c) 2004, 2005 Intel Corporation.  All rights reserved. | 
					
						
							|  |  |  |  * Copyright (c) 2004, 2005 Topspin Corporation.  All rights reserved. | 
					
						
							| 
									
										
										
										
											2007-05-14 17:21:52 -04:00
										 |  |  |  * Copyright (c) 2004-2007 Voltaire Corporation.  All rights reserved. | 
					
						
							| 
									
										
										
										
											2005-08-10 23:03:10 -07:00
										 |  |  |  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This software is available to you under a choice of one of two | 
					
						
							|  |  |  |  * licenses.  You may choose to be licensed under the terms of the GNU | 
					
						
							|  |  |  |  * General Public License (GPL) Version 2, available from the file | 
					
						
							|  |  |  |  * COPYING in the main directory of this source tree, or the | 
					
						
							|  |  |  |  * OpenIB.org BSD license below: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     Redistribution and use in source and binary forms, with or | 
					
						
							|  |  |  |  *     without modification, are permitted provided that the following | 
					
						
							|  |  |  |  *     conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *      - Redistributions of source code must retain the above | 
					
						
							|  |  |  |  *        copyright notice, this list of conditions and the following | 
					
						
							|  |  |  |  *        disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *      - Redistributions in binary form must reproduce the above | 
					
						
							|  |  |  |  *        copyright notice, this list of conditions and the following | 
					
						
							|  |  |  |  *        disclaimer in the documentation and/or other materials | 
					
						
							|  |  |  |  *        provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | 
					
						
							|  |  |  |  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | 
					
						
							|  |  |  |  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 
					
						
							|  |  |  |  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | 
					
						
							|  |  |  |  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | 
					
						
							|  |  |  |  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | 
					
						
							|  |  |  |  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 
					
						
							|  |  |  |  * SOFTWARE. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-11-07 00:59:43 -08:00
										 |  |  | #include <linux/slab.h>
 | 
					
						
							|  |  |  | #include <linux/string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | #include "agent.h"
 | 
					
						
							|  |  |  | #include "smi.h"
 | 
					
						
							| 
									
										
										
										
											2007-05-14 17:21:52 -04:00
										 |  |  | #include "mad_priv.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | #define SPFX "ib_agent: "
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | struct ib_agent_port_private { | 
					
						
							|  |  |  | 	struct list_head port_list; | 
					
						
							|  |  |  | 	struct ib_mad_agent *agent[2]; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | static DEFINE_SPINLOCK(ib_agent_port_list_lock); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | static LIST_HEAD(ib_agent_port_list); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | static struct ib_agent_port_private * | 
					
						
							|  |  |  | __ib_get_agent_port(struct ib_device *device, int port_num) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ib_agent_port_private *entry; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	list_for_each_entry(entry, &ib_agent_port_list, port_list) { | 
					
						
							|  |  |  | 		if (entry->agent[0]->device == device && | 
					
						
							|  |  |  | 		    entry->agent[0]->port_num == port_num) | 
					
						
							|  |  |  | 			return entry; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | static struct ib_agent_port_private * | 
					
						
							|  |  |  | ib_get_agent_port(struct ib_device *device, int port_num) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ib_agent_port_private *entry; | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&ib_agent_port_list_lock, flags); | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	entry = __ib_get_agent_port(device, port_num); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | 
					
						
							|  |  |  | 	return entry; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-03 10:45:17 -07:00
										 |  |  | void agent_send_response(struct ib_mad *mad, struct ib_grh *grh, | 
					
						
							|  |  |  | 			 struct ib_wc *wc, struct ib_device *device, | 
					
						
							|  |  |  | 			 int port_num, int qpn) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	struct ib_agent_port_private *port_priv; | 
					
						
							|  |  |  | 	struct ib_mad_agent *agent; | 
					
						
							|  |  |  | 	struct ib_mad_send_buf *send_buf; | 
					
						
							|  |  |  | 	struct ib_ah *ah; | 
					
						
							| 
									
										
										
										
											2007-05-14 17:21:52 -04:00
										 |  |  | 	struct ib_mad_send_wr_private *mad_send_wr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (device->node_type == RDMA_NODE_IB_SWITCH) | 
					
						
							|  |  |  | 		port_priv = ib_get_agent_port(device, 0); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		port_priv = ib_get_agent_port(device, port_num); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	if (!port_priv) { | 
					
						
							|  |  |  | 		printk(KERN_ERR SPFX "Unable to find port agent\n"); | 
					
						
							| 
									
										
										
										
											2007-08-03 10:45:17 -07:00
										 |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	agent = port_priv->agent[qpn]; | 
					
						
							|  |  |  | 	ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num); | 
					
						
							|  |  |  | 	if (IS_ERR(ah)) { | 
					
						
							| 
									
										
										
										
											2007-08-03 10:45:17 -07:00
										 |  |  | 		printk(KERN_ERR SPFX "ib_create_ah_from_wc error\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0, | 
					
						
							|  |  |  | 				      IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, | 
					
						
							|  |  |  | 				      GFP_KERNEL); | 
					
						
							|  |  |  | 	if (IS_ERR(send_buf)) { | 
					
						
							| 
									
										
										
										
											2007-08-03 10:45:17 -07:00
										 |  |  | 		printk(KERN_ERR SPFX "ib_create_send_mad error\n"); | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 		goto err1; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	memcpy(send_buf->mad, mad, sizeof *mad); | 
					
						
							|  |  |  | 	send_buf->ah = ah; | 
					
						
							| 
									
										
										
										
											2007-05-14 17:21:52 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (device->node_type == RDMA_NODE_IB_SWITCH) { | 
					
						
							|  |  |  | 		mad_send_wr = container_of(send_buf, | 
					
						
							|  |  |  | 					   struct ib_mad_send_wr_private, | 
					
						
							|  |  |  | 					   send_buf); | 
					
						
							|  |  |  | 		mad_send_wr->send_wr.wr.ud.port_num = port_num; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-03 10:45:17 -07:00
										 |  |  | 	if (ib_post_send_mad(send_buf, NULL)) { | 
					
						
							|  |  |  | 		printk(KERN_ERR SPFX "ib_post_send_mad error\n"); | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 		goto err2; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-08-03 10:45:17 -07:00
										 |  |  | 	return; | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | err2: | 
					
						
							|  |  |  | 	ib_free_send_mad(send_buf); | 
					
						
							|  |  |  | err1: | 
					
						
							|  |  |  | 	ib_destroy_ah(ah); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void agent_send_handler(struct ib_mad_agent *mad_agent, | 
					
						
							|  |  |  | 			       struct ib_mad_send_wc *mad_send_wc) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	ib_destroy_ah(mad_send_wc->send_buf->ah); | 
					
						
							|  |  |  | 	ib_free_send_mad(mad_send_wc->send_buf); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ib_agent_port_open(struct ib_device *device, int port_num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ib_agent_port_private *port_priv; | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Create new device info */ | 
					
						
							| 
									
										
										
										
											2005-11-02 07:23:14 -08:00
										 |  |  | 	port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (!port_priv) { | 
					
						
							|  |  |  | 		printk(KERN_ERR SPFX "No memory for ib_agent_port_private\n"); | 
					
						
							|  |  |  | 		ret = -ENOMEM; | 
					
						
							|  |  |  | 		goto error1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	/* Obtain send only MAD agent for SMI QP */ | 
					
						
							|  |  |  | 	port_priv->agent[0] = ib_register_mad_agent(device, port_num, | 
					
						
							|  |  |  | 						    IB_QPT_SMI, NULL, 0, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 						    &agent_send_handler, | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 						    NULL, NULL); | 
					
						
							|  |  |  | 	if (IS_ERR(port_priv->agent[0])) { | 
					
						
							|  |  |  | 		ret = PTR_ERR(port_priv->agent[0]); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		goto error2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	/* Obtain send only MAD agent for GSI QP */ | 
					
						
							|  |  |  | 	port_priv->agent[1] = ib_register_mad_agent(device, port_num, | 
					
						
							|  |  |  | 						    IB_QPT_GSI, NULL, 0, | 
					
						
							|  |  |  | 						    &agent_send_handler, | 
					
						
							|  |  |  | 						    NULL, NULL); | 
					
						
							|  |  |  | 	if (IS_ERR(port_priv->agent[1])) { | 
					
						
							|  |  |  | 		ret = PTR_ERR(port_priv->agent[1]); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		goto error3; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&ib_agent_port_list_lock, flags); | 
					
						
							|  |  |  | 	list_add_tail(&port_priv->port_list, &ib_agent_port_list); | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error3: | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	ib_unregister_mad_agent(port_priv->agent[0]); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | error2: | 
					
						
							|  |  |  | 	kfree(port_priv); | 
					
						
							|  |  |  | error1: | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ib_agent_port_close(struct ib_device *device, int port_num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ib_agent_port_private *port_priv; | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&ib_agent_port_list_lock, flags); | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	port_priv = __ib_get_agent_port(device, port_num); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	if (port_priv == NULL) { | 
					
						
							|  |  |  | 		spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | 
					
						
							|  |  |  | 		printk(KERN_ERR SPFX "Port %d not found\n", port_num); | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	list_del(&port_priv->port_list); | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&ib_agent_port_list_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-25 10:51:39 -07:00
										 |  |  | 	ib_unregister_mad_agent(port_priv->agent[1]); | 
					
						
							|  |  |  | 	ib_unregister_mad_agent(port_priv->agent[0]); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	kfree(port_priv); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } |