2005-04-17 02:20:36 +04:00
/*
2005-08-11 10:03:10 +04: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-15 01:21:52 +04:00
* Copyright ( c ) 2004 - 2007 Voltaire Corporation . All rights reserved .
2005-08-11 10:03:10 +04:00
* Copyright ( c ) 2005 Sun Microsystems , Inc . All rights reserved .
2005-04-17 02:20:36 +04: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 11:59:43 +03:00
# include <linux/slab.h>
# include <linux/string.h>
2005-10-25 21:51:39 +04:00
# include "agent.h"
# include "smi.h"
2007-05-15 01:21:52 +04:00
# include "mad_priv.h"
2005-04-17 02:20:36 +04:00
2005-10-25 21:51:39 +04:00
# define SPFX "ib_agent: "
2005-04-17 02:20:36 +04:00
2005-10-25 21:51:39 +04:00
struct ib_agent_port_private {
struct list_head port_list ;
struct ib_mad_agent * agent [ 2 ] ;
} ;
2005-04-17 02:20:36 +04:00
2005-10-25 21:51:39 +04:00
static DEFINE_SPINLOCK ( ib_agent_port_list_lock ) ;
2005-04-17 02:20:36 +04:00
static LIST_HEAD ( ib_agent_port_list ) ;
2005-10-25 21:51:39 +04:00
static struct ib_agent_port_private *
2015-06-01 00:15:31 +03:00
__ib_get_agent_port ( const struct ib_device * device , int port_num )
2005-04-17 02:20:36 +04:00
{
struct ib_agent_port_private * entry ;
2005-10-25 21:51:39 +04:00
list_for_each_entry ( entry , & ib_agent_port_list , port_list ) {
2010-09-28 04:51:11 +04:00
if ( entry - > agent [ 1 ] - > device = = device & &
entry - > agent [ 1 ] - > port_num = = port_num )
2005-10-25 21:51:39 +04:00
return entry ;
2005-04-17 02:20:36 +04:00
}
return NULL ;
}
2005-10-25 21:51:39 +04:00
static struct ib_agent_port_private *
2015-06-01 00:15:31 +03:00
ib_get_agent_port ( const struct ib_device * device , int port_num )
2005-04-17 02:20:36 +04:00
{
struct ib_agent_port_private * entry ;
unsigned long flags ;
spin_lock_irqsave ( & ib_agent_port_list_lock , flags ) ;
2005-10-25 21:51:39 +04:00
entry = __ib_get_agent_port ( device , port_num ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irqrestore ( & ib_agent_port_list_lock , flags ) ;
return entry ;
}
2015-06-06 21:38:30 +03:00
void agent_send_response ( const struct ib_mad_hdr * mad_hdr , const struct ib_grh * grh ,
2015-06-01 00:15:31 +03:00
const struct ib_wc * wc , const struct ib_device * device ,
2015-06-06 21:38:30 +03:00
int port_num , int qpn , size_t resp_mad_len )
2005-04-17 02:20:36 +04:00
{
2005-10-25 21:51:39 +04: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-15 01: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-17 02:20:36 +04:00
2005-10-25 21:51:39 +04:00
if ( ! port_priv ) {
2014-08-09 03:00:53 +04:00
dev_err ( & device - > dev , " Unable to find port agent \n " ) ;
2007-08-03 21:45:17 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
2005-10-25 21:51:39 +04:00
agent = port_priv - > agent [ qpn ] ;
ah = ib_create_ah_from_wc ( agent - > qp - > pd , wc , grh , port_num ) ;
if ( IS_ERR ( ah ) ) {
2014-08-09 03:00:53 +04:00
dev_err ( & device - > dev , " ib_create_ah_from_wc error %ld \n " ,
2011-02-12 00:44:30 +03:00
PTR_ERR ( ah ) ) ;
2007-08-03 21:45:17 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
2005-10-25 21:51:39 +04:00
send_buf = ib_create_send_mad ( agent , wc - > src_qp , wc - > pkey_index , 0 ,
2015-06-06 21:38:30 +03:00
IB_MGMT_MAD_HDR ,
resp_mad_len - IB_MGMT_MAD_HDR ,
2015-06-06 21:38:28 +03:00
GFP_KERNEL ,
IB_MGMT_BASE_VERSION ) ;
2005-10-25 21:51:39 +04:00
if ( IS_ERR ( send_buf ) ) {
2014-08-09 03:00:53 +04:00
dev_err ( & device - > dev , " ib_create_send_mad error \n " ) ;
2005-10-25 21:51:39 +04:00
goto err1 ;
2005-04-17 02:20:36 +04:00
}
2015-06-06 21:38:30 +03:00
memcpy ( send_buf - > mad , mad_hdr , resp_mad_len ) ;
2005-10-25 21:51:39 +04:00
send_buf - > ah = ah ;
2007-05-15 01: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 21:45:17 +04:00
if ( ib_post_send_mad ( send_buf , NULL ) ) {
2014-08-09 03:00:53 +04:00
dev_err ( & device - > dev , " ib_post_send_mad error \n " ) ;
2005-10-25 21:51:39 +04:00
goto err2 ;
2005-04-17 02:20:36 +04:00
}
2007-08-03 21:45:17 +04:00
return ;
2005-10-25 21:51:39 +04:00
err2 :
ib_free_send_mad ( send_buf ) ;
err1 :
ib_destroy_ah ( ah ) ;
2005-04-17 02:20:36 +04:00
}
static void agent_send_handler ( struct ib_mad_agent * mad_agent ,
struct ib_mad_send_wc * mad_send_wc )
{
2005-10-25 21:51:39 +04:00
ib_destroy_ah ( mad_send_wc - > send_buf - > ah ) ;
ib_free_send_mad ( mad_send_wc - > send_buf ) ;
2005-04-17 02:20:36 +04: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 21:51:39 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
/* Create new device info */
2005-11-02 18:23:14 +03:00
port_priv = kzalloc ( sizeof * port_priv , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! port_priv ) {
2014-08-09 03:00:53 +04:00
dev_err ( & device - > dev , " No memory for ib_agent_port_private \n " ) ;
2005-04-17 02:20:36 +04:00
ret = - ENOMEM ;
goto error1 ;
}
2015-05-05 15:50:33 +03:00
if ( rdma_cap_ib_smi ( device , port_num ) ) {
2010-09-28 04:51:11 +04: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 ,
& agent_send_handler ,
2014-08-09 03:00:55 +04:00
NULL , NULL , 0 ) ;
2010-09-28 04:51:11 +04:00
if ( IS_ERR ( port_priv - > agent [ 0 ] ) ) {
ret = PTR_ERR ( port_priv - > agent [ 0 ] ) ;
goto error2 ;
}
2005-04-17 02:20:36 +04:00
}
2005-10-25 21:51:39 +04: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 ,
2014-08-09 03:00:55 +04:00
NULL , NULL , 0 ) ;
2005-10-25 21:51:39 +04:00
if ( IS_ERR ( port_priv - > agent [ 1 ] ) ) {
ret = PTR_ERR ( port_priv - > agent [ 1 ] ) ;
2005-04-17 02:20:36 +04: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 :
2010-09-28 04:51:11 +04:00
if ( port_priv - > agent [ 0 ] )
ib_unregister_mad_agent ( port_priv - > agent [ 0 ] ) ;
2005-04-17 02:20:36 +04: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 21:51:39 +04:00
port_priv = __ib_get_agent_port ( device , port_num ) ;
2005-04-17 02:20:36 +04:00
if ( port_priv = = NULL ) {
spin_unlock_irqrestore ( & ib_agent_port_list_lock , flags ) ;
2014-08-09 03:00:53 +04:00
dev_err ( & device - > dev , " Port %d not found \n " , port_num ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
list_del ( & port_priv - > port_list ) ;
spin_unlock_irqrestore ( & ib_agent_port_list_lock , flags ) ;
2005-10-25 21:51:39 +04:00
ib_unregister_mad_agent ( port_priv - > agent [ 1 ] ) ;
2010-09-28 04:51:11 +04:00
if ( port_priv - > agent [ 0 ] )
ib_unregister_mad_agent ( port_priv - > agent [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
kfree ( port_priv ) ;
return 0 ;
}