2005-04-16 15:20:36 -07:00
/*
* Copyright ( c ) 2004 Topspin Communications . All rights reserved .
2006-09-22 15:22:46 -07:00
* Copyright ( c ) 2005 Voltaire , Inc . All rights reserved .
2005-07-27 11:45:42 -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 .
*
2006-03-03 21:54:13 -08:00
* $ Id : user_mad . c 5596 2006 - 03 - 03 01 : 00 : 07 Z sean . hefty $
2005-04-16 15:20:36 -07:00
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/fs.h>
# include <linux/cdev.h>
# include <linux/pci.h>
# include <linux/dma-mapping.h>
# include <linux/poll.h>
# include <linux/rwsem.h>
# include <linux/kref.h>
# include <asm/uaccess.h>
# include <asm/semaphore.h>
2005-08-25 13:40:04 -07:00
# include <rdma/ib_mad.h>
# include <rdma/ib_user_mad.h>
2005-04-16 15:20:36 -07:00
MODULE_AUTHOR ( " Roland Dreier " ) ;
MODULE_DESCRIPTION ( " InfiniBand userspace MAD packet access " ) ;
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
enum {
IB_UMAD_MAX_PORTS = 64 ,
IB_UMAD_MAX_AGENTS = 32 ,
IB_UMAD_MAJOR = 231 ,
IB_UMAD_MINOR_BASE = 0
} ;
2005-10-28 15:37:23 -07:00
/*
* Our lifetime rules for these structs are the following : each time a
* device special file is opened , we look up the corresponding struct
* ib_umad_port by minor in the umad_port [ ] table while holding the
* port_lock . If this lookup succeeds , we take a reference on the
* ib_umad_port ' s struct ib_umad_device while still holding the
* port_lock ; if the lookup fails , we fail the open ( ) . We drop these
* references in the corresponding close ( ) .
*
* In addition to references coming from open character devices , there
* is one more reference to each ib_umad_device representing the
* module ' s reference taken when allocating the ib_umad_device in
* ib_umad_add_one ( ) .
*
* When destroying an ib_umad_device , we clear all of its
* ib_umad_ports from umad_port [ ] while holding port_lock before
* dropping the module ' s reference to the ib_umad_device . This is
* always safe because any open ( ) calls will either succeed and obtain
* a reference before we clear the umad_port [ ] entries , or fail after
* we clear the umad_port [ ] entries .
*/
2005-04-16 15:20:36 -07:00
struct ib_umad_port {
2005-10-28 15:37:23 -07:00
struct cdev * dev ;
struct class_device * class_dev ;
2005-04-16 15:20:36 -07:00
2005-10-28 15:37:23 -07:00
struct cdev * sm_dev ;
struct class_device * sm_class_dev ;
2005-04-16 15:20:36 -07:00
struct semaphore sm_sem ;
2005-11-03 12:01:18 -08:00
struct rw_semaphore mutex ;
struct list_head file_list ;
2005-04-16 15:20:36 -07:00
struct ib_device * ib_dev ;
struct ib_umad_device * umad_dev ;
2005-10-28 15:37:23 -07:00
int dev_num ;
2005-04-16 15:20:36 -07:00
u8 port_num ;
} ;
struct ib_umad_device {
int start_port , end_port ;
struct kref ref ;
struct ib_umad_port port [ 0 ] ;
} ;
struct ib_umad_file {
2005-11-10 10:18:23 -08:00
struct ib_umad_port * port ;
struct list_head recv_list ;
2006-07-20 11:25:50 +03:00
struct list_head send_list ;
2005-11-10 10:18:23 -08:00
struct list_head port_list ;
spinlock_t recv_lock ;
2006-07-20 11:25:50 +03:00
spinlock_t send_lock ;
2005-11-10 10:18:23 -08:00
wait_queue_head_t recv_wait ;
struct ib_mad_agent * agent [ IB_UMAD_MAX_AGENTS ] ;
int agents_dead ;
2005-04-16 15:20:36 -07:00
} ;
struct ib_umad_packet {
2005-07-27 11:45:42 -07:00
struct ib_mad_send_buf * msg ;
2006-03-03 21:54:13 -08:00
struct ib_mad_recv_wc * recv_wc ;
2005-04-16 15:20:36 -07:00
struct list_head list ;
2005-07-27 11:45:42 -07:00
int length ;
struct ib_user_mad mad ;
2005-04-16 15:20:36 -07:00
} ;
2005-10-28 15:37:23 -07:00
static struct class * umad_class ;
2005-04-16 15:20:36 -07:00
static const dev_t base_dev = MKDEV ( IB_UMAD_MAJOR , IB_UMAD_MINOR_BASE ) ;
2005-10-28 15:37:23 -07:00
static DEFINE_SPINLOCK ( port_lock ) ;
static struct ib_umad_port * umad_port [ IB_UMAD_MAX_PORTS ] ;
2007-04-02 12:45:16 -04:00
static DECLARE_BITMAP ( dev_map , IB_UMAD_MAX_PORTS ) ;
2005-04-16 15:20:36 -07:00
static void ib_umad_add_one ( struct ib_device * device ) ;
static void ib_umad_remove_one ( struct ib_device * device ) ;
2005-10-28 15:37:23 -07:00
static void ib_umad_release_dev ( struct kref * ref )
{
struct ib_umad_device * dev =
container_of ( ref , struct ib_umad_device , ref ) ;
kfree ( dev ) ;
}
2005-11-10 10:18:23 -08:00
/* caller must hold port->mutex at least for reading */
static struct ib_mad_agent * __get_agent ( struct ib_umad_file * file , int id )
{
return file - > agents_dead ? NULL : file - > agent [ id ] ;
}
2005-04-16 15:20:36 -07:00
static int queue_packet ( struct ib_umad_file * file ,
struct ib_mad_agent * agent ,
struct ib_umad_packet * packet )
{
int ret = 1 ;
2005-11-03 12:01:18 -08:00
down_read ( & file - > port - > mutex ) ;
2005-11-10 10:18:23 -08:00
2005-07-27 11:45:42 -07:00
for ( packet - > mad . hdr . id = 0 ;
packet - > mad . hdr . id < IB_UMAD_MAX_AGENTS ;
packet - > mad . hdr . id + + )
2005-11-10 10:18:23 -08:00
if ( agent = = __get_agent ( file , packet - > mad . hdr . id ) ) {
2005-04-16 15:20:36 -07:00
spin_lock_irq ( & file - > recv_lock ) ;
list_add_tail ( & packet - > list , & file - > recv_list ) ;
spin_unlock_irq ( & file - > recv_lock ) ;
wake_up_interruptible ( & file - > recv_wait ) ;
ret = 0 ;
break ;
}
2005-11-03 12:01:18 -08:00
up_read ( & file - > port - > mutex ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
2006-07-20 11:25:50 +03:00
static void dequeue_send ( struct ib_umad_file * file ,
struct ib_umad_packet * packet )
{
spin_lock_irq ( & file - > send_lock ) ;
list_del ( & packet - > list ) ;
spin_unlock_irq ( & file - > send_lock ) ;
}
2005-04-16 15:20:36 -07:00
static void send_handler ( struct ib_mad_agent * agent ,
struct ib_mad_send_wc * send_wc )
{
struct ib_umad_file * file = agent - > context ;
2005-10-25 10:51:39 -07:00
struct ib_umad_packet * packet = send_wc - > send_buf - > context [ 0 ] ;
2005-04-16 15:20:36 -07:00
2006-07-20 11:25:50 +03:00
dequeue_send ( file , packet ) ;
2005-10-25 10:51:39 -07:00
ib_destroy_ah ( packet - > msg - > ah ) ;
2005-07-27 11:45:42 -07:00
ib_free_send_mad ( packet - > msg ) ;
2005-04-16 15:20:36 -07:00
if ( send_wc - > status = = IB_WC_RESP_TIMEOUT_ERR ) {
2006-03-03 21:54:13 -08:00
packet - > length = IB_MGMT_MAD_HDR ;
packet - > mad . hdr . status = ETIMEDOUT ;
if ( ! queue_packet ( file , agent , packet ) )
return ;
2005-07-27 11:45:42 -07:00
}
2005-04-16 15:20:36 -07:00
kfree ( packet ) ;
}
static void recv_handler ( struct ib_mad_agent * agent ,
struct ib_mad_recv_wc * mad_recv_wc )
{
struct ib_umad_file * file = agent - > context ;
struct ib_umad_packet * packet ;
if ( mad_recv_wc - > wc - > status ! = IB_WC_SUCCESS )
2006-03-03 21:54:13 -08:00
goto err1 ;
2005-04-16 15:20:36 -07:00
2006-03-03 21:54:13 -08:00
packet = kzalloc ( sizeof * packet , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! packet )
2006-03-03 21:54:13 -08:00
goto err1 ;
2005-04-16 15:20:36 -07:00
2006-03-03 21:54:13 -08:00
packet - > length = mad_recv_wc - > mad_len ;
packet - > recv_wc = mad_recv_wc ;
2005-04-16 15:20:36 -07:00
2005-07-27 11:45:42 -07:00
packet - > mad . hdr . status = 0 ;
2006-03-03 21:54:13 -08:00
packet - > mad . hdr . length = sizeof ( struct ib_user_mad ) +
mad_recv_wc - > mad_len ;
2005-07-27 11:45:42 -07:00
packet - > mad . hdr . qpn = cpu_to_be32 ( mad_recv_wc - > wc - > src_qp ) ;
packet - > mad . hdr . lid = cpu_to_be16 ( mad_recv_wc - > wc - > slid ) ;
packet - > mad . hdr . sl = mad_recv_wc - > wc - > sl ;
packet - > mad . hdr . path_bits = mad_recv_wc - > wc - > dlid_path_bits ;
packet - > mad . hdr . grh_present = ! ! ( mad_recv_wc - > wc - > wc_flags & IB_WC_GRH ) ;
if ( packet - > mad . hdr . grh_present ) {
2005-04-16 15:20:36 -07:00
/* XXX parse GRH */
2005-07-27 11:45:42 -07:00
packet - > mad . hdr . gid_index = 0 ;
packet - > mad . hdr . hop_limit = 0 ;
packet - > mad . hdr . traffic_class = 0 ;
memset ( packet - > mad . hdr . gid , 0 , 16 ) ;
packet - > mad . hdr . flow_label = 0 ;
2005-04-16 15:20:36 -07:00
}
if ( queue_packet ( file , agent , packet ) )
2006-03-03 21:54:13 -08:00
goto err2 ;
return ;
2005-04-16 15:20:36 -07:00
2006-03-03 21:54:13 -08:00
err2 :
kfree ( packet ) ;
err1 :
2005-04-16 15:20:36 -07:00
ib_free_recv_mad ( mad_recv_wc ) ;
}
2006-03-03 21:54:13 -08:00
static ssize_t copy_recv_mad ( char __user * buf , struct ib_umad_packet * packet ,
size_t count )
{
struct ib_mad_recv_buf * recv_buf ;
int left , seg_payload , offset , max_seg_payload ;
/* We need enough room to copy the first (or only) MAD segment. */
recv_buf = & packet - > recv_wc - > recv_buf ;
if ( ( packet - > length < = sizeof ( * recv_buf - > mad ) & &
count < sizeof ( packet - > mad ) + packet - > length ) | |
( packet - > length > sizeof ( * recv_buf - > mad ) & &
count < sizeof ( packet - > mad ) + sizeof ( * recv_buf - > mad ) ) )
return - EINVAL ;
if ( copy_to_user ( buf , & packet - > mad , sizeof ( packet - > mad ) ) )
return - EFAULT ;
buf + = sizeof ( packet - > mad ) ;
seg_payload = min_t ( int , packet - > length , sizeof ( * recv_buf - > mad ) ) ;
if ( copy_to_user ( buf , recv_buf - > mad , seg_payload ) )
return - EFAULT ;
if ( seg_payload < packet - > length ) {
/*
* Multipacket RMPP MAD message . Copy remainder of message .
* Note that last segment may have a shorter payload .
*/
if ( count < sizeof ( packet - > mad ) + packet - > length ) {
/*
* The buffer is too small , return the first RMPP segment ,
* which includes the RMPP message length .
*/
return - ENOSPC ;
}
2006-03-28 16:40:04 -08:00
offset = ib_get_mad_data_offset ( recv_buf - > mad - > mad_hdr . mgmt_class ) ;
2006-03-03 21:54:13 -08:00
max_seg_payload = sizeof ( struct ib_mad ) - offset ;
for ( left = packet - > length - seg_payload , buf + = seg_payload ;
left ; left - = seg_payload , buf + = seg_payload ) {
recv_buf = container_of ( recv_buf - > list . next ,
struct ib_mad_recv_buf , list ) ;
seg_payload = min ( left , max_seg_payload ) ;
if ( copy_to_user ( buf , ( ( void * ) recv_buf - > mad ) + offset ,
seg_payload ) )
return - EFAULT ;
}
}
return sizeof ( packet - > mad ) + packet - > length ;
}
static ssize_t copy_send_mad ( char __user * buf , struct ib_umad_packet * packet ,
size_t count )
{
ssize_t size = sizeof ( packet - > mad ) + packet - > length ;
if ( count < size )
return - EINVAL ;
if ( copy_to_user ( buf , & packet - > mad , size ) )
return - EFAULT ;
return size ;
}
2005-04-16 15:20:36 -07:00
static ssize_t ib_umad_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * pos )
{
struct ib_umad_file * file = filp - > private_data ;
struct ib_umad_packet * packet ;
ssize_t ret ;
2006-03-03 21:54:13 -08:00
if ( count < sizeof ( struct ib_user_mad ) )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
spin_lock_irq ( & file - > recv_lock ) ;
while ( list_empty ( & file - > recv_list ) ) {
spin_unlock_irq ( & file - > recv_lock ) ;
if ( filp - > f_flags & O_NONBLOCK )
return - EAGAIN ;
if ( wait_event_interruptible ( file - > recv_wait ,
! list_empty ( & file - > recv_list ) ) )
return - ERESTARTSYS ;
spin_lock_irq ( & file - > recv_lock ) ;
}
packet = list_entry ( file - > recv_list . next , struct ib_umad_packet , list ) ;
list_del ( & packet - > list ) ;
spin_unlock_irq ( & file - > recv_lock ) ;
2006-03-03 21:54:13 -08:00
if ( packet - > recv_wc )
ret = copy_recv_mad ( buf , packet , count ) ;
2005-04-16 15:20:36 -07:00
else
2006-03-03 21:54:13 -08:00
ret = copy_send_mad ( buf , packet , count ) ;
2005-07-27 11:45:42 -07:00
if ( ret < 0 ) {
/* Requeue packet */
spin_lock_irq ( & file - > recv_lock ) ;
list_add ( & packet - > list , & file - > recv_list ) ;
spin_unlock_irq ( & file - > recv_lock ) ;
2006-03-03 21:54:13 -08:00
} else {
if ( packet - > recv_wc )
ib_free_recv_mad ( packet - > recv_wc ) ;
2005-07-27 11:45:42 -07:00
kfree ( packet ) ;
2006-03-03 21:54:13 -08:00
}
2005-04-16 15:20:36 -07:00
return ret ;
}
2006-03-03 21:54:13 -08:00
static int copy_rmpp_mad ( struct ib_mad_send_buf * msg , const char __user * buf )
{
int left , seg ;
/* Copy class specific header */
if ( ( msg - > hdr_len > IB_MGMT_RMPP_HDR ) & &
copy_from_user ( msg - > mad + IB_MGMT_RMPP_HDR , buf + IB_MGMT_RMPP_HDR ,
msg - > hdr_len - IB_MGMT_RMPP_HDR ) )
return - EFAULT ;
/* All headers are in place. Copy data segments. */
for ( seg = 1 , left = msg - > data_len , buf + = msg - > hdr_len ; left > 0 ;
seg + + , left - = msg - > seg_size , buf + = msg - > seg_size ) {
if ( copy_from_user ( ib_get_rmpp_segment ( msg , seg ) , buf ,
min ( left , msg - > seg_size ) ) )
return - EFAULT ;
}
return 0 ;
}
2006-07-20 11:25:50 +03:00
static int same_destination ( struct ib_user_mad_hdr * hdr1 ,
struct ib_user_mad_hdr * hdr2 )
{
if ( ! hdr1 - > grh_present & & ! hdr2 - > grh_present )
return ( hdr1 - > lid = = hdr2 - > lid ) ;
if ( hdr1 - > grh_present & & hdr2 - > grh_present )
return ! memcmp ( hdr1 - > gid , hdr2 - > gid , 16 ) ;
return 0 ;
}
static int is_duplicate ( struct ib_umad_file * file ,
struct ib_umad_packet * packet )
{
struct ib_umad_packet * sent_packet ;
struct ib_mad_hdr * sent_hdr , * hdr ;
hdr = ( struct ib_mad_hdr * ) packet - > mad . data ;
list_for_each_entry ( sent_packet , & file - > send_list , list ) {
sent_hdr = ( struct ib_mad_hdr * ) sent_packet - > mad . data ;
if ( ( hdr - > tid ! = sent_hdr - > tid ) | |
( hdr - > mgmt_class ! = sent_hdr - > mgmt_class ) )
continue ;
/*
* No need to be overly clever here . If two new operations have
* the same TID , reject the second as a duplicate . This is more
* restrictive than required by the spec .
*/
if ( ! ib_response_mad ( ( struct ib_mad * ) hdr ) ) {
if ( ! ib_response_mad ( ( struct ib_mad * ) sent_hdr ) )
return 1 ;
continue ;
} else if ( ! ib_response_mad ( ( struct ib_mad * ) sent_hdr ) )
continue ;
if ( same_destination ( & packet - > mad . hdr , & sent_packet - > mad . hdr ) )
return 1 ;
}
return 0 ;
}
2005-04-16 15:20:36 -07:00
static ssize_t ib_umad_write ( struct file * filp , const char __user * buf ,
size_t count , loff_t * pos )
{
struct ib_umad_file * file = filp - > private_data ;
struct ib_umad_packet * packet ;
struct ib_mad_agent * agent ;
struct ib_ah_attr ah_attr ;
2005-10-25 10:51:39 -07:00
struct ib_ah * ah ;
2005-07-27 11:45:42 -07:00
struct ib_rmpp_mad * rmpp_mad ;
2005-08-13 21:05:57 -07:00
__be64 * tid ;
2006-03-03 21:54:13 -08:00
int ret , data_len , hdr_len , copy_offset , rmpp_active ;
2005-04-16 15:20:36 -07:00
2005-11-18 14:18:26 -08:00
if ( count < sizeof ( struct ib_user_mad ) + IB_MGMT_RMPP_HDR )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
2006-03-03 21:54:13 -08:00
packet = kzalloc ( sizeof * packet + IB_MGMT_RMPP_HDR , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! packet )
return - ENOMEM ;
2005-07-27 11:45:42 -07:00
if ( copy_from_user ( & packet - > mad , buf ,
2005-10-27 20:48:11 -07:00
sizeof ( struct ib_user_mad ) + IB_MGMT_RMPP_HDR ) ) {
2005-07-27 11:45:42 -07:00
ret = - EFAULT ;
goto err ;
2005-04-16 15:20:36 -07:00
}
2005-07-27 11:45:42 -07:00
if ( packet - > mad . hdr . id < 0 | |
packet - > mad . hdr . id > = IB_UMAD_MAX_AGENTS ) {
2005-04-16 15:20:36 -07:00
ret = - EINVAL ;
goto err ;
}
2005-11-03 12:01:18 -08:00
down_read ( & file - > port - > mutex ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 10:18:23 -08:00
agent = __get_agent ( file , packet - > mad . hdr . id ) ;
2005-04-16 15:20:36 -07:00
if ( ! agent ) {
ret = - EINVAL ;
goto err_up ;
}
memset ( & ah_attr , 0 , sizeof ah_attr ) ;
2005-07-27 11:45:42 -07:00
ah_attr . dlid = be16_to_cpu ( packet - > mad . hdr . lid ) ;
ah_attr . sl = packet - > mad . hdr . sl ;
ah_attr . src_path_bits = packet - > mad . hdr . path_bits ;
2005-04-16 15:20:36 -07:00
ah_attr . port_num = file - > port - > port_num ;
2005-07-27 11:45:42 -07:00
if ( packet - > mad . hdr . grh_present ) {
2005-04-16 15:20:36 -07:00
ah_attr . ah_flags = IB_AH_GRH ;
2005-07-27 11:45:42 -07:00
memcpy ( ah_attr . grh . dgid . raw , packet - > mad . hdr . gid , 16 ) ;
2005-08-13 21:05:57 -07:00
ah_attr . grh . flow_label = be32_to_cpu ( packet - > mad . hdr . flow_label ) ;
2005-07-27 11:45:42 -07:00
ah_attr . grh . hop_limit = packet - > mad . hdr . hop_limit ;
ah_attr . grh . traffic_class = packet - > mad . hdr . traffic_class ;
2005-04-16 15:20:36 -07:00
}
2005-10-25 10:51:39 -07:00
ah = ib_create_ah ( agent - > qp - > pd , & ah_attr ) ;
if ( IS_ERR ( ah ) ) {
ret = PTR_ERR ( ah ) ;
2005-04-16 15:20:36 -07:00
goto err_up ;
}
2005-07-27 11:45:42 -07:00
rmpp_mad = ( struct ib_rmpp_mad * ) packet - > mad . data ;
2006-03-28 16:40:04 -08:00
hdr_len = ib_get_mad_data_offset ( rmpp_mad - > mad_hdr . mgmt_class ) ;
if ( ! ib_is_mad_class_rmpp ( rmpp_mad - > mad_hdr . mgmt_class ) ) {
copy_offset = IB_MGMT_MAD_HDR ;
rmpp_active = 0 ;
} else {
2006-03-03 21:54:13 -08:00
copy_offset = IB_MGMT_RMPP_HDR ;
rmpp_active = ib_get_rmpp_flags ( & rmpp_mad - > rmpp_hdr ) &
IB_MGMT_RMPP_FLAG_ACTIVE ;
2005-07-27 11:45:42 -07:00
}
2006-03-03 21:54:13 -08:00
data_len = count - sizeof ( struct ib_user_mad ) - hdr_len ;
2005-07-27 11:45:42 -07:00
packet - > msg = ib_create_send_mad ( agent ,
be32_to_cpu ( packet - > mad . hdr . qpn ) ,
2006-03-03 21:54:13 -08:00
0 , rmpp_active , hdr_len ,
data_len , GFP_KERNEL ) ;
2005-07-27 11:45:42 -07:00
if ( IS_ERR ( packet - > msg ) ) {
ret = PTR_ERR ( packet - > msg ) ;
goto err_ah ;
}
2005-04-16 15:20:36 -07:00
2005-10-25 10:51:39 -07:00
packet - > msg - > ah = ah ;
packet - > msg - > timeout_ms = packet - > mad . hdr . timeout_ms ;
packet - > msg - > retries = packet - > mad . hdr . retries ;
packet - > msg - > context [ 0 ] = packet ;
2005-04-16 15:20:36 -07:00
2006-03-03 21:54:13 -08:00
/* Copy MAD header. Any RMPP header is already in place. */
2005-10-27 20:48:11 -07:00
memcpy ( packet - > msg - > mad , packet - > mad . data , IB_MGMT_MAD_HDR ) ;
2006-03-03 21:54:13 -08:00
buf + = sizeof ( struct ib_user_mad ) ;
if ( ! rmpp_active ) {
if ( copy_from_user ( packet - > msg - > mad + copy_offset ,
buf + copy_offset ,
hdr_len + data_len - copy_offset ) ) {
ret = - EFAULT ;
goto err_msg ;
}
} else {
ret = copy_rmpp_mad ( packet - > msg , buf ) ;
if ( ret )
goto err_msg ;
2005-07-27 11:45:42 -07:00
}
/*
2006-07-20 11:25:50 +03:00
* Set the high - order part of the transaction ID to make MADs from
* different agents unique , and allow routing responses back to the
* original requestor .
2005-07-27 11:45:42 -07:00
*/
2006-07-20 11:25:50 +03:00
if ( ! ib_response_mad ( packet - > msg - > mad ) ) {
2005-10-27 20:33:43 -07:00
tid = & ( ( struct ib_mad_hdr * ) packet - > msg - > mad ) - > tid ;
2005-07-27 11:45:42 -07:00
* tid = cpu_to_be64 ( ( ( u64 ) agent - > hi_tid ) < < 32 |
( be64_to_cpup ( tid ) & 0xffffffff ) ) ;
2006-07-20 11:25:50 +03:00
rmpp_mad - > mad_hdr . tid = * tid ;
}
spin_lock_irq ( & file - > send_lock ) ;
ret = is_duplicate ( file , packet ) ;
if ( ! ret )
list_add_tail ( & packet - > list , & file - > send_list ) ;
spin_unlock_irq ( & file - > send_lock ) ;
if ( ret ) {
ret = - EINVAL ;
goto err_msg ;
2005-04-16 15:20:36 -07:00
}
2005-10-25 10:51:39 -07:00
ret = ib_post_send_mad ( packet - > msg , NULL ) ;
2005-07-27 11:45:42 -07:00
if ( ret )
2006-07-20 11:25:50 +03:00
goto err_send ;
2005-07-27 11:45:42 -07:00
2005-11-03 12:01:18 -08:00
up_read ( & file - > port - > mutex ) ;
2005-10-27 20:48:11 -07:00
return count ;
2005-07-27 11:45:42 -07:00
2006-07-20 11:25:50 +03:00
err_send :
dequeue_send ( file , packet ) ;
2005-07-27 11:45:42 -07:00
err_msg :
ib_free_send_mad ( packet - > msg ) ;
err_ah :
2005-10-25 10:51:39 -07:00
ib_destroy_ah ( ah ) ;
2005-04-16 15:20:36 -07:00
err_up :
2005-11-03 12:01:18 -08:00
up_read ( & file - > port - > mutex ) ;
2005-04-16 15:20:36 -07:00
err :
kfree ( packet ) ;
return ret ;
}
static unsigned int ib_umad_poll ( struct file * filp , struct poll_table_struct * wait )
{
struct ib_umad_file * file = filp - > private_data ;
/* we will always be able to post a MAD send */
unsigned int mask = POLLOUT | POLLWRNORM ;
poll_wait ( filp , & file - > recv_wait , wait ) ;
if ( ! list_empty ( & file - > recv_list ) )
mask | = POLLIN | POLLRDNORM ;
return mask ;
}
static int ib_umad_reg_agent ( struct ib_umad_file * file , unsigned long arg )
{
struct ib_user_mad_reg_req ureq ;
struct ib_mad_reg_req req ;
struct ib_mad_agent * agent ;
int agent_id ;
int ret ;
2005-11-03 12:01:18 -08:00
down_write ( & file - > port - > mutex ) ;
if ( ! file - > port - > ib_dev ) {
ret = - EPIPE ;
goto out ;
}
2005-04-16 15:20:36 -07:00
if ( copy_from_user ( & ureq , ( void __user * ) arg , sizeof ureq ) ) {
ret = - EFAULT ;
goto out ;
}
if ( ureq . qpn ! = 0 & & ureq . qpn ! = 1 ) {
ret = - EINVAL ;
goto out ;
}
for ( agent_id = 0 ; agent_id < IB_UMAD_MAX_AGENTS ; + + agent_id )
2005-11-10 10:18:23 -08:00
if ( ! __get_agent ( file , agent_id ) )
2005-04-16 15:20:36 -07:00
goto found ;
ret = - ENOMEM ;
goto out ;
found :
2005-04-16 15:26:11 -07:00
if ( ureq . mgmt_class ) {
req . mgmt_class = ureq . mgmt_class ;
req . mgmt_class_version = ureq . mgmt_class_version ;
memcpy ( req . method_mask , ureq . method_mask , sizeof req . method_mask ) ;
memcpy ( req . oui , ureq . oui , sizeof req . oui ) ;
}
2005-04-16 15:20:36 -07:00
agent = ib_register_mad_agent ( file - > port - > ib_dev , file - > port - > port_num ,
ureq . qpn ? IB_QPT_GSI : IB_QPT_SMI ,
2005-04-16 15:26:11 -07:00
ureq . mgmt_class ? & req : NULL ,
2005-07-27 11:45:42 -07:00
ureq . rmpp_version ,
send_handler , recv_handler , file ) ;
2005-04-16 15:20:36 -07:00
if ( IS_ERR ( agent ) ) {
ret = PTR_ERR ( agent ) ;
goto out ;
}
if ( put_user ( agent_id ,
( u32 __user * ) ( arg + offsetof ( struct ib_user_mad_reg_req , id ) ) ) ) {
ret = - EFAULT ;
2005-11-09 09:58:10 -08:00
ib_unregister_mad_agent ( agent ) ;
goto out ;
2005-04-16 15:20:36 -07:00
}
2005-11-07 10:41:29 -08:00
file - > agent [ agent_id ] = agent ;
2005-04-16 15:20:36 -07:00
ret = 0 ;
2005-11-07 10:41:29 -08:00
2005-04-16 15:20:36 -07:00
out :
2005-11-03 12:01:18 -08:00
up_write ( & file - > port - > mutex ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
static int ib_umad_unreg_agent ( struct ib_umad_file * file , unsigned long arg )
{
2005-11-07 10:41:29 -08:00
struct ib_mad_agent * agent = NULL ;
2005-04-16 15:20:36 -07:00
u32 id ;
int ret = 0 ;
2005-11-07 10:41:29 -08:00
if ( get_user ( id , ( u32 __user * ) arg ) )
return - EFAULT ;
2005-04-16 15:20:36 -07:00
2005-11-07 10:41:29 -08:00
down_write ( & file - > port - > mutex ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 10:18:23 -08:00
if ( id < 0 | | id > = IB_UMAD_MAX_AGENTS | | ! __get_agent ( file , id ) ) {
2005-04-16 15:20:36 -07:00
ret = - EINVAL ;
goto out ;
}
2005-11-07 10:41:29 -08:00
agent = file - > agent [ id ] ;
2005-04-16 15:20:36 -07:00
file - > agent [ id ] = NULL ;
out :
2005-11-03 12:01:18 -08:00
up_write ( & file - > port - > mutex ) ;
2005-11-07 10:41:29 -08:00
2005-11-09 09:58:10 -08:00
if ( agent )
2005-11-07 10:41:29 -08:00
ib_unregister_mad_agent ( agent ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
2005-07-27 11:45:42 -07:00
static long ib_umad_ioctl ( struct file * filp , unsigned int cmd ,
unsigned long arg )
2005-04-16 15:20:36 -07:00
{
switch ( cmd ) {
case IB_USER_MAD_REGISTER_AGENT :
return ib_umad_reg_agent ( filp - > private_data , arg ) ;
case IB_USER_MAD_UNREGISTER_AGENT :
return ib_umad_unreg_agent ( filp - > private_data , arg ) ;
default :
return - ENOIOCTLCMD ;
}
}
static int ib_umad_open ( struct inode * inode , struct file * filp )
{
2005-10-28 15:37:23 -07:00
struct ib_umad_port * port ;
2005-04-16 15:20:36 -07:00
struct ib_umad_file * file ;
2005-11-03 12:01:18 -08:00
int ret = 0 ;
2005-04-16 15:20:36 -07:00
2005-10-28 15:37:23 -07:00
spin_lock ( & port_lock ) ;
port = umad_port [ iminor ( inode ) - IB_UMAD_MINOR_BASE ] ;
if ( port )
kref_get ( & port - > umad_dev - > ref ) ;
spin_unlock ( & port_lock ) ;
if ( ! port )
return - ENXIO ;
2005-11-03 12:01:18 -08:00
down_write ( & port - > mutex ) ;
if ( ! port - > ib_dev ) {
ret = - ENXIO ;
goto out ;
}
2005-10-27 20:48:11 -07:00
file = kzalloc ( sizeof * file , GFP_KERNEL ) ;
2005-10-28 15:37:23 -07:00
if ( ! file ) {
kref_put ( & port - > umad_dev - > ref , ib_umad_release_dev ) ;
2005-11-03 12:01:18 -08:00
ret = - ENOMEM ;
goto out ;
2005-10-28 15:37:23 -07:00
}
2005-04-16 15:20:36 -07:00
spin_lock_init ( & file - > recv_lock ) ;
2006-07-20 11:25:50 +03:00
spin_lock_init ( & file - > send_lock ) ;
2005-04-16 15:20:36 -07:00
INIT_LIST_HEAD ( & file - > recv_list ) ;
2006-07-20 11:25:50 +03:00
INIT_LIST_HEAD ( & file - > send_list ) ;
2005-04-16 15:20:36 -07:00
init_waitqueue_head ( & file - > recv_wait ) ;
file - > port = port ;
filp - > private_data = file ;
2005-11-03 12:01:18 -08:00
list_add_tail ( & file - > port_list , & port - > file_list ) ;
out :
up_write ( & port - > mutex ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
static int ib_umad_close ( struct inode * inode , struct file * filp )
{
struct ib_umad_file * file = filp - > private_data ;
2005-10-28 15:37:23 -07:00
struct ib_umad_device * dev = file - > port - > umad_dev ;
2005-05-25 12:31:30 -07:00
struct ib_umad_packet * packet , * tmp ;
2005-11-10 10:18:23 -08:00
int already_dead ;
2005-04-16 15:20:36 -07:00
int i ;
2005-11-10 10:18:23 -08:00
down_write ( & file - > port - > mutex ) ;
already_dead = file - > agents_dead ;
file - > agents_dead = 1 ;
2005-04-16 15:20:36 -07:00
2006-03-03 21:54:13 -08:00
list_for_each_entry_safe ( packet , tmp , & file - > recv_list , list ) {
if ( packet - > recv_wc )
ib_free_recv_mad ( packet - > recv_wc ) ;
2005-05-25 12:31:30 -07:00
kfree ( packet ) ;
2006-03-03 21:54:13 -08:00
}
2005-05-25 12:31:30 -07:00
2005-11-03 12:01:18 -08:00
list_del ( & file - > port_list ) ;
2005-11-10 10:18:23 -08:00
downgrade_write ( & file - > port - > mutex ) ;
if ( ! already_dead )
for ( i = 0 ; i < IB_UMAD_MAX_AGENTS ; + + i )
if ( file - > agent [ i ] )
ib_unregister_mad_agent ( file - > agent [ i ] ) ;
2005-04-16 15:20:36 -07:00
2005-11-10 10:18:23 -08:00
up_read ( & file - > port - > mutex ) ;
kfree ( file ) ;
2005-10-28 15:37:23 -07:00
kref_put ( & dev - > ref , ib_umad_release_dev ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-02-12 00:55:32 -08:00
static const struct file_operations umad_fops = {
2005-07-27 11:45:42 -07:00
. owner = THIS_MODULE ,
. read = ib_umad_read ,
. write = ib_umad_write ,
. poll = ib_umad_poll ,
2005-04-16 15:20:36 -07:00
. unlocked_ioctl = ib_umad_ioctl ,
2005-07-27 11:45:42 -07:00
. compat_ioctl = ib_umad_ioctl ,
. open = ib_umad_open ,
. release = ib_umad_close
2005-04-16 15:20:36 -07:00
} ;
static int ib_umad_sm_open ( struct inode * inode , struct file * filp )
{
2005-10-28 15:37:23 -07:00
struct ib_umad_port * port ;
2005-04-16 15:20:36 -07:00
struct ib_port_modify props = {
. set_port_cap_mask = IB_PORT_SM
} ;
int ret ;
2005-10-28 15:37:23 -07:00
spin_lock ( & port_lock ) ;
port = umad_port [ iminor ( inode ) - IB_UMAD_MINOR_BASE - IB_UMAD_MAX_PORTS ] ;
if ( port )
kref_get ( & port - > umad_dev - > ref ) ;
spin_unlock ( & port_lock ) ;
if ( ! port )
return - ENXIO ;
2005-04-16 15:20:36 -07:00
if ( filp - > f_flags & O_NONBLOCK ) {
2005-10-28 15:37:23 -07:00
if ( down_trylock ( & port - > sm_sem ) ) {
ret = - EAGAIN ;
goto fail ;
}
2005-04-16 15:20:36 -07:00
} else {
2005-10-28 15:37:23 -07:00
if ( down_interruptible ( & port - > sm_sem ) ) {
ret = - ERESTARTSYS ;
goto fail ;
}
2005-04-16 15:20:36 -07:00
}
ret = ib_modify_port ( port - > ib_dev , port - > port_num , 0 , & props ) ;
if ( ret ) {
up ( & port - > sm_sem ) ;
2005-10-28 15:37:23 -07:00
goto fail ;
2005-04-16 15:20:36 -07:00
}
filp - > private_data = port ;
return 0 ;
2005-10-28 15:37:23 -07:00
fail :
kref_put ( & port - > umad_dev - > ref , ib_umad_release_dev ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
static int ib_umad_sm_close ( struct inode * inode , struct file * filp )
{
struct ib_umad_port * port = filp - > private_data ;
struct ib_port_modify props = {
. clr_port_cap_mask = IB_PORT_SM
} ;
2005-11-03 12:01:18 -08:00
int ret = 0 ;
down_write ( & port - > mutex ) ;
if ( port - > ib_dev )
ret = ib_modify_port ( port - > ib_dev , port - > port_num , 0 , & props ) ;
up_write ( & port - > mutex ) ;
2005-04-16 15:20:36 -07:00
up ( & port - > sm_sem ) ;
2005-10-28 15:37:23 -07:00
kref_put ( & port - > umad_dev - > ref , ib_umad_release_dev ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
2007-02-12 00:55:32 -08:00
static const struct file_operations umad_sm_fops = {
2005-04-16 15:20:36 -07:00
. owner = THIS_MODULE ,
. open = ib_umad_sm_open ,
. release = ib_umad_sm_close
} ;
static struct ib_client umad_client = {
. name = " umad " ,
. add = ib_umad_add_one ,
. remove = ib_umad_remove_one
} ;
static ssize_t show_ibdev ( struct class_device * class_dev , char * buf )
{
struct ib_umad_port * port = class_get_devdata ( class_dev ) ;
2005-10-28 15:37:23 -07:00
if ( ! port )
return - ENODEV ;
2005-04-16 15:20:36 -07:00
return sprintf ( buf , " %s \n " , port - > ib_dev - > name ) ;
}
static CLASS_DEVICE_ATTR ( ibdev , S_IRUGO , show_ibdev , NULL ) ;
static ssize_t show_port ( struct class_device * class_dev , char * buf )
{
struct ib_umad_port * port = class_get_devdata ( class_dev ) ;
2005-10-28 15:37:23 -07:00
if ( ! port )
return - ENODEV ;
2005-04-16 15:20:36 -07:00
return sprintf ( buf , " %d \n " , port - > port_num ) ;
}
static CLASS_DEVICE_ATTR ( port , S_IRUGO , show_port , NULL ) ;
static ssize_t show_abi_version ( struct class * class , char * buf )
{
return sprintf ( buf , " %d \n " , IB_USER_MAD_ABI_VERSION ) ;
}
static CLASS_ATTR ( abi_version , S_IRUGO , show_abi_version , NULL ) ;
static int ib_umad_init_port ( struct ib_device * device , int port_num ,
struct ib_umad_port * port )
{
2005-10-28 15:37:23 -07:00
spin_lock ( & port_lock ) ;
port - > dev_num = find_first_zero_bit ( dev_map , IB_UMAD_MAX_PORTS ) ;
if ( port - > dev_num > = IB_UMAD_MAX_PORTS ) {
spin_unlock ( & port_lock ) ;
2005-04-16 15:20:36 -07:00
return - 1 ;
}
2005-10-28 15:37:23 -07:00
set_bit ( port - > dev_num , dev_map ) ;
spin_unlock ( & port_lock ) ;
2005-04-16 15:20:36 -07:00
port - > ib_dev = device ;
port - > port_num = port_num ;
init_MUTEX ( & port - > sm_sem ) ;
2005-11-03 12:01:18 -08:00
init_rwsem ( & port - > mutex ) ;
INIT_LIST_HEAD ( & port - > file_list ) ;
2005-04-16 15:20:36 -07:00
2005-10-28 15:37:23 -07:00
port - > dev = cdev_alloc ( ) ;
if ( ! port - > dev )
2005-04-16 15:20:36 -07:00
return - 1 ;
2005-10-28 15:37:23 -07:00
port - > dev - > owner = THIS_MODULE ;
port - > dev - > ops = & umad_fops ;
kobject_set_name ( & port - > dev - > kobj , " umad%d " , port - > dev_num ) ;
if ( cdev_add ( port - > dev , base_dev + port - > dev_num , 1 ) )
2005-04-16 15:20:36 -07:00
goto err_cdev ;
2005-10-28 16:38:15 -07:00
port - > class_dev = class_device_create ( umad_class , NULL , port - > dev - > dev ,
2005-10-28 15:37:23 -07:00
device - > dma_device ,
" umad%d " , port - > dev_num ) ;
if ( IS_ERR ( port - > class_dev ) )
goto err_cdev ;
2005-04-16 15:20:36 -07:00
2005-10-28 15:37:23 -07:00
if ( class_device_create_file ( port - > class_dev , & class_device_attr_ibdev ) )
2005-04-16 15:20:36 -07:00
goto err_class ;
2005-10-28 15:37:23 -07:00
if ( class_device_create_file ( port - > class_dev , & class_device_attr_port ) )
2005-04-16 15:20:36 -07:00
goto err_class ;
2005-10-28 15:37:23 -07:00
port - > sm_dev = cdev_alloc ( ) ;
if ( ! port - > sm_dev )
goto err_class ;
port - > sm_dev - > owner = THIS_MODULE ;
port - > sm_dev - > ops = & umad_sm_fops ;
2005-11-06 15:47:02 -08:00
kobject_set_name ( & port - > sm_dev - > kobj , " issm%d " , port - > dev_num ) ;
2005-10-28 15:37:23 -07:00
if ( cdev_add ( port - > sm_dev , base_dev + port - > dev_num + IB_UMAD_MAX_PORTS , 1 ) )
goto err_sm_cdev ;
2005-04-16 15:20:36 -07:00
2005-10-28 16:38:15 -07:00
port - > sm_class_dev = class_device_create ( umad_class , NULL , port - > sm_dev - > dev ,
2005-10-28 15:37:23 -07:00
device - > dma_device ,
" issm%d " , port - > dev_num ) ;
if ( IS_ERR ( port - > sm_class_dev ) )
2005-04-16 15:20:36 -07:00
goto err_sm_cdev ;
2005-10-28 15:37:23 -07:00
class_set_devdata ( port - > class_dev , port ) ;
class_set_devdata ( port - > sm_class_dev , port ) ;
2005-04-16 15:20:36 -07:00
2005-10-28 15:37:23 -07:00
if ( class_device_create_file ( port - > sm_class_dev , & class_device_attr_ibdev ) )
2005-04-16 15:20:36 -07:00
goto err_sm_class ;
2005-10-28 15:37:23 -07:00
if ( class_device_create_file ( port - > sm_class_dev , & class_device_attr_port ) )
2005-04-16 15:20:36 -07:00
goto err_sm_class ;
2005-10-28 15:37:23 -07:00
spin_lock ( & port_lock ) ;
umad_port [ port - > dev_num ] = port ;
spin_unlock ( & port_lock ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
err_sm_class :
2005-10-28 15:37:23 -07:00
class_device_destroy ( umad_class , port - > sm_dev - > dev ) ;
2005-04-16 15:20:36 -07:00
err_sm_cdev :
2005-10-28 15:37:23 -07:00
cdev_del ( port - > sm_dev ) ;
2005-04-16 15:20:36 -07:00
err_class :
2005-10-28 15:37:23 -07:00
class_device_destroy ( umad_class , port - > dev - > dev ) ;
2005-04-16 15:20:36 -07:00
err_cdev :
2005-10-28 15:37:23 -07:00
cdev_del ( port - > dev ) ;
clear_bit ( port - > dev_num , dev_map ) ;
2005-04-16 15:20:36 -07:00
return - 1 ;
}
2005-10-28 15:37:23 -07:00
static void ib_umad_kill_port ( struct ib_umad_port * port )
{
2005-11-03 12:01:18 -08:00
struct ib_umad_file * file ;
int id ;
2005-10-28 15:37:23 -07:00
class_set_devdata ( port - > class_dev , NULL ) ;
class_set_devdata ( port - > sm_class_dev , NULL ) ;
class_device_destroy ( umad_class , port - > dev - > dev ) ;
class_device_destroy ( umad_class , port - > sm_dev - > dev ) ;
cdev_del ( port - > dev ) ;
cdev_del ( port - > sm_dev ) ;
spin_lock ( & port_lock ) ;
umad_port [ port - > dev_num ] = NULL ;
spin_unlock ( & port_lock ) ;
2005-11-03 12:01:18 -08:00
down_write ( & port - > mutex ) ;
port - > ib_dev = NULL ;
2005-11-10 10:18:23 -08:00
/*
* Now go through the list of files attached to this port and
* unregister all of their MAD agents . We need to hold
* port - > mutex while doing this to avoid racing with
* ib_umad_close ( ) , but we can ' t hold the mutex for writing
* while calling ib_unregister_mad_agent ( ) , since that might
* deadlock by calling back into queue_packet ( ) . So we
* downgrade our lock to a read lock , and then drop and
* reacquire the write lock for the next iteration .
*
* We do list_del_init ( ) on the file ' s list_head so that the
* list_del in ib_umad_close ( ) is still OK , even after the
* file is removed from the list .
*/
while ( ! list_empty ( & port - > file_list ) ) {
file = list_entry ( port - > file_list . next , struct ib_umad_file ,
port_list ) ;
file - > agents_dead = 1 ;
list_del_init ( & file - > port_list ) ;
downgrade_write ( & port - > mutex ) ;
for ( id = 0 ; id < IB_UMAD_MAX_AGENTS ; + + id )
if ( file - > agent [ id ] )
ib_unregister_mad_agent ( file - > agent [ id ] ) ;
up_read ( & port - > mutex ) ;
down_write ( & port - > mutex ) ;
}
2005-11-03 12:01:18 -08:00
up_write ( & port - > mutex ) ;
2005-10-28 15:37:23 -07:00
clear_bit ( port - > dev_num , dev_map ) ;
}
2005-04-16 15:20:36 -07:00
static void ib_umad_add_one ( struct ib_device * device )
{
struct ib_umad_device * umad_dev ;
int s , e , i ;
2006-08-03 16:02:42 -05:00
if ( rdma_node_get_transport ( device - > node_type ) ! = RDMA_TRANSPORT_IB )
return ;
if ( device - > node_type = = RDMA_NODE_IB_SWITCH )
2005-04-16 15:20:36 -07:00
s = e = 0 ;
else {
s = 1 ;
e = device - > phys_port_cnt ;
}
2005-10-27 20:48:11 -07:00
umad_dev = kzalloc ( sizeof * umad_dev +
2005-04-16 15:20:36 -07:00
( e - s + 1 ) * sizeof ( struct ib_umad_port ) ,
GFP_KERNEL ) ;
if ( ! umad_dev )
return ;
kref_init ( & umad_dev - > ref ) ;
umad_dev - > start_port = s ;
umad_dev - > end_port = e ;
for ( i = s ; i < = e ; + + i ) {
umad_dev - > port [ i - s ] . umad_dev = umad_dev ;
if ( ib_umad_init_port ( device , i , & umad_dev - > port [ i - s ] ) )
goto err ;
}
ib_set_client_data ( device , & umad_client , umad_dev ) ;
return ;
err :
2005-10-28 15:37:23 -07:00
while ( - - i > = s )
2005-11-06 15:47:02 -08:00
ib_umad_kill_port ( & umad_dev - > port [ i - s ] ) ;
2005-04-16 15:20:36 -07:00
kref_put ( & umad_dev - > ref , ib_umad_release_dev ) ;
}
static void ib_umad_remove_one ( struct ib_device * device )
{
struct ib_umad_device * umad_dev = ib_get_client_data ( device , & umad_client ) ;
int i ;
if ( ! umad_dev )
return ;
2005-10-28 15:37:23 -07:00
for ( i = 0 ; i < = umad_dev - > end_port - umad_dev - > start_port ; + + i )
ib_umad_kill_port ( & umad_dev - > port [ i ] ) ;
2005-04-16 15:20:36 -07:00
kref_put ( & umad_dev - > ref , ib_umad_release_dev ) ;
}
static int __init ib_umad_init ( void )
{
int ret ;
ret = register_chrdev_region ( base_dev , IB_UMAD_MAX_PORTS * 2 ,
" infiniband_mad " ) ;
if ( ret ) {
printk ( KERN_ERR " user_mad: couldn't register device number \n " ) ;
goto out ;
}
2005-10-28 15:37:23 -07:00
umad_class = class_create ( THIS_MODULE , " infiniband_mad " ) ;
if ( IS_ERR ( umad_class ) ) {
ret = PTR_ERR ( umad_class ) ;
2005-04-16 15:20:36 -07:00
printk ( KERN_ERR " user_mad: couldn't create class infiniband_mad \n " ) ;
goto out_chrdev ;
}
2005-10-28 15:37:23 -07:00
ret = class_create_file ( umad_class , & class_attr_abi_version ) ;
2005-04-16 15:20:36 -07:00
if ( ret ) {
printk ( KERN_ERR " user_mad: couldn't create abi_version attribute \n " ) ;
goto out_class ;
}
ret = ib_register_client ( & umad_client ) ;
if ( ret ) {
printk ( KERN_ERR " user_mad: couldn't register ib_umad client \n " ) ;
goto out_class ;
}
return 0 ;
out_class :
2005-10-28 15:37:23 -07:00
class_destroy ( umad_class ) ;
2005-04-16 15:20:36 -07:00
out_chrdev :
unregister_chrdev_region ( base_dev , IB_UMAD_MAX_PORTS * 2 ) ;
out :
return ret ;
}
static void __exit ib_umad_cleanup ( void )
{
ib_unregister_client ( & umad_client ) ;
2005-10-28 15:37:23 -07:00
class_destroy ( umad_class ) ;
2005-04-16 15:20:36 -07:00
unregister_chrdev_region ( base_dev , IB_UMAD_MAX_PORTS * 2 ) ;
}
module_init ( ib_umad_init ) ;
module_exit ( ib_umad_cleanup ) ;