11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
22a1d9b7f09aaaacf235656cb32a40ba2c79590b3Roland Dreier * Copyright (c) 2004, 2005 Mellanox Technologies Ltd.  All rights reserved.
32a1d9b7f09aaaacf235656cb32a40ba2c79590b3Roland Dreier * Copyright (c) 2004, 2005 Infinicon Corporation.  All rights reserved.
42a1d9b7f09aaaacf235656cb32a40ba2c79590b3Roland Dreier * Copyright (c) 2004, 2005 Intel Corporation.  All rights reserved.
52a1d9b7f09aaaacf235656cb32a40ba2c79590b3Roland Dreier * Copyright (c) 2004, 2005 Topspin Corporation.  All rights reserved.
61bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock * Copyright (c) 2004-2007 Voltaire Corporation.  All rights reserved.
72a1d9b7f09aaaacf235656cb32a40ba2c79590b3Roland Dreier * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software is available to you under a choice of one of two
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * licenses.  You may choose to be licensed under the terms of the GNU
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * General Public License (GPL) Version 2, available from the file
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * COPYING in the main directory of this source tree, or the
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OpenIB.org BSD license below:
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     Redistribution and use in source and binary forms, with or
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     without modification, are permitted provided that the following
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     conditions are met:
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      - Redistributions of source code must retain the above
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        copyright notice, this list of conditions and the following
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        disclaimer.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      - Redistributions in binary form must reproduce the above
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        copyright notice, this list of conditions and the following
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        disclaimer in the documentation and/or other materials
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        provided with the distribution.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SOFTWARE.
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
398c65b4a60450590e79a28e9717ceffa9e4debb3fTim Schmielau#include <linux/slab.h>
408c65b4a60450590e79a28e9717ceffa9e4debb3fTim Schmielau#include <linux/string.h>
418c65b4a60450590e79a28e9717ceffa9e4debb3fTim Schmielau
4234816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty#include "agent.h"
4334816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty#include "smi.h"
441bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock#include "mad_priv.h"
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4634816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty#define SPFX "ib_agent: "
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4834816ad98efe4d47ffd858a0345321f9d85d9420Sean Heftystruct ib_agent_port_private {
4934816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	struct list_head port_list;
5034816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	struct ib_mad_agent *agent[2];
5134816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty};
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5334816ad98efe4d47ffd858a0345321f9d85d9420Sean Heftystatic DEFINE_SPINLOCK(ib_agent_port_list_lock);
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic LIST_HEAD(ib_agent_port_list);
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5634816ad98efe4d47ffd858a0345321f9d85d9420Sean Heftystatic struct ib_agent_port_private *
5734816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty__ib_get_agent_port(struct ib_device *device, int port_num)
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_agent_port_private *entry;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6134816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	list_for_each_entry(entry, &ib_agent_port_list, port_list) {
62fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen		if (entry->agent[1]->device == device &&
63fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen		    entry->agent[1]->port_num == port_num)
6434816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty			return entry;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6934816ad98efe4d47ffd858a0345321f9d85d9420Sean Heftystatic struct ib_agent_port_private *
7034816ad98efe4d47ffd858a0345321f9d85d9420Sean Heftyib_get_agent_port(struct ib_device *device, int port_num)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_agent_port_private *entry;
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&ib_agent_port_list_lock, flags);
7634816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	entry = __ib_get_agent_port(device, port_num);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return entry;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
818fc394b1971241999ef9b022feabf6a164791e3fHal Rosenstockvoid agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
828fc394b1971241999ef9b022feabf6a164791e3fHal Rosenstock			 struct ib_wc *wc, struct ib_device *device,
838fc394b1971241999ef9b022feabf6a164791e3fHal Rosenstock			 int port_num, int qpn)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8534816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	struct ib_agent_port_private *port_priv;
8634816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	struct ib_mad_agent *agent;
8734816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	struct ib_mad_send_buf *send_buf;
8834816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	struct ib_ah *ah;
891bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock	struct ib_mad_send_wr_private *mad_send_wr;
901bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock
911bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock	if (device->node_type == RDMA_NODE_IB_SWITCH)
921bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock		port_priv = ib_get_agent_port(device, 0);
931bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock	else
941bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock		port_priv = ib_get_agent_port(device, port_num);
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9634816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	if (!port_priv) {
9734816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty		printk(KERN_ERR SPFX "Unable to find port agent\n");
988fc394b1971241999ef9b022feabf6a164791e3fHal Rosenstock		return;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10134816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	agent = port_priv->agent[qpn];
10234816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num);
10334816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	if (IS_ERR(ah)) {
1041eba843dd7678b9033a0d1ccff21c21b857de77bMichael Heinz		printk(KERN_ERR SPFX "ib_create_ah_from_wc error %ld\n",
1051eba843dd7678b9033a0d1ccff21c21b857de77bMichael Heinz			PTR_ERR(ah));
1068fc394b1971241999ef9b022feabf6a164791e3fHal Rosenstock		return;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10934816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0,
11034816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty				      IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
11134816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty				      GFP_KERNEL);
11234816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	if (IS_ERR(send_buf)) {
1138fc394b1971241999ef9b022feabf6a164791e3fHal Rosenstock		printk(KERN_ERR SPFX "ib_create_send_mad error\n");
11434816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty		goto err1;
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11734816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	memcpy(send_buf->mad, mad, sizeof *mad);
11834816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	send_buf->ah = ah;
1191bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock
1201bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock	if (device->node_type == RDMA_NODE_IB_SWITCH) {
1211bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock		mad_send_wr = container_of(send_buf,
1221bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock					   struct ib_mad_send_wr_private,
1231bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock					   send_buf);
1241bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock		mad_send_wr->send_wr.wr.ud.port_num = port_num;
1251bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock	}
1261bae4dbf9576e563da23927e4078fffbbce67a75Hal Rosenstock
1278fc394b1971241999ef9b022feabf6a164791e3fHal Rosenstock	if (ib_post_send_mad(send_buf, NULL)) {
1288fc394b1971241999ef9b022feabf6a164791e3fHal Rosenstock		printk(KERN_ERR SPFX "ib_post_send_mad error\n");
12934816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty		goto err2;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1318fc394b1971241999ef9b022feabf6a164791e3fHal Rosenstock	return;
13234816ad98efe4d47ffd858a0345321f9d85d9420Sean Heftyerr2:
13334816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	ib_free_send_mad(send_buf);
13434816ad98efe4d47ffd858a0345321f9d85d9420Sean Heftyerr1:
13534816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	ib_destroy_ah(ah);
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void agent_send_handler(struct ib_mad_agent *mad_agent,
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       struct ib_mad_send_wc *mad_send_wc)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14134816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	ib_destroy_ah(mad_send_wc->send_buf->ah);
14234816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	ib_free_send_mad(mad_send_wc->send_buf);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ib_agent_port_open(struct ib_device *device, int port_num)
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_agent_port_private *port_priv;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
14934816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	int ret;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Create new device info */
152de6eb66b56d9df5ce6bd254994f05e065214e8cdRoland Dreier	port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!port_priv) {
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR SPFX "No memory for ib_agent_port_private\n");
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = -ENOMEM;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error1;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen	if (rdma_port_get_link_layer(device, port_num) == IB_LINK_LAYER_INFINIBAND) {
160fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen		/* Obtain send only MAD agent for SMI QP */
161fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen		port_priv->agent[0] = ib_register_mad_agent(device, port_num,
162fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen							    IB_QPT_SMI, NULL, 0,
163fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen							    &agent_send_handler,
164fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen							    NULL, NULL);
165fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen		if (IS_ERR(port_priv->agent[0])) {
166fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen			ret = PTR_ERR(port_priv->agent[0]);
167fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen			goto error2;
168fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen		}
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17134816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	/* Obtain send only MAD agent for GSI QP */
17234816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	port_priv->agent[1] = ib_register_mad_agent(device, port_num,
17334816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty						    IB_QPT_GSI, NULL, 0,
17434816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty						    &agent_send_handler,
17534816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty						    NULL, NULL);
17634816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	if (IS_ERR(port_priv->agent[1])) {
17734816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty		ret = PTR_ERR(port_priv->agent[1]);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto error3;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&ib_agent_port_list_lock, flags);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&port_priv->port_list, &ib_agent_port_list);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror3:
188fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen	if (port_priv->agent[0])
189fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen		ib_unregister_mad_agent(port_priv->agent[0]);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror2:
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(port_priv);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror1:
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint ib_agent_port_close(struct ib_device *device, int port_num)
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct ib_agent_port_private *port_priv;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&ib_agent_port_list_lock, flags);
20234816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	port_priv = __ib_get_agent_port(device, port_num);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (port_priv == NULL) {
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR SPFX "Port %d not found\n", port_num);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_del(&port_priv->port_list);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&ib_agent_port_list_lock, flags);
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
21134816ad98efe4d47ffd858a0345321f9d85d9420Sean Hefty	ib_unregister_mad_agent(port_priv->agent[1]);
212fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen	if (port_priv->agent[0])
213fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen		ib_unregister_mad_agent(port_priv->agent[0]);
214fac70d51914674ce8ae742ed73441ddb4770ad20Eli Cohen
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(port_priv);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
218