2005-04-17 02:20:36 +04:00
/*
* drivers / s390 / net / claw . c
* ESCON CLAW network driver
*
2005-09-06 17:03:09 +04:00
* Linux for zSeries version
2009-06-16 12:30:33 +04:00
* Copyright IBM Corp . 2002 , 2009
2005-04-17 02:20:36 +04:00
* Author ( s ) Original code written by :
2009-06-16 12:30:33 +04:00
* Kazuo Iimura < iimura @ jp . ibm . com >
2005-04-17 02:20:36 +04:00
* Rewritten by
2009-06-16 12:30:33 +04:00
* Andy Richter < richtera @ us . ibm . com >
* Marc Price < mwprice @ us . ibm . com >
2005-04-17 02:20:36 +04:00
*
* sysfs parms :
* group x . x . rrrr , x . x . wwww
* read_buffer nnnnnnn
* write_buffer nnnnnn
* host_name aaaaaaaa
* adapter_name aaaaaaaa
* api_type aaaaaaaa
*
* eg .
* group 0.0 .0200 0.0 .0201
* read_buffer 25
* write_buffer 20
* host_name LINUX390
* adapter_name RS6K
* api_type TCPIP
*
* where
*
* The device id is decided by the order entries
* are added to the group the first is claw0 the second claw1
* up to CLAW_MAX_DEV
*
* rrrr - the first of 2 consecutive device addresses used for the
* CLAW protocol .
* The specified address is always used as the input ( Read )
* channel and the next address is used as the output channel .
*
* wwww - the second of 2 consecutive device addresses used for
* the CLAW protocol .
* The specified address is always used as the output
* channel and the previous address is used as the input channel .
*
* read_buffer - specifies number of input buffers to allocate .
* write_buffer - specifies number of output buffers to allocate .
* host_name - host name
* adaptor_name - adaptor name
* api_type - API type TCPIP or API will be sent and expected
* as ws_name
*
* Note the following requirements :
* 1 ) host_name must match the configured adapter_name on the remote side
* 2 ) adaptor_name must match the configured host name on the remote side
*
* Change History
* 1.00 Initial release shipped
* 1.10 Changes for Buffer allocation
* 1.15 Changed for 2.6 Kernel No longer compiles on 2.4 or lower
* 1.25 Added Packing support
2008-07-18 17:24:56 +04:00
* 1.5
2005-04-17 02:20:36 +04:00
*/
2009-01-20 09:14:33 +03:00
# define KMSG_COMPONENT "claw"
2005-04-17 02:20:36 +04:00
# include <asm/ccwdev.h>
# include <asm/ccwgroup.h>
# include <asm/debug.h>
# include <asm/idals.h>
# include <asm/io.h>
2007-10-19 10:40:25 +04:00
# include <linux/bitops.h>
2005-04-17 02:20:36 +04:00
# include <linux/ctype.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/if_arp.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/ip.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
# include <linux/proc_fs.h>
# include <linux/sched.h>
# include <linux/signal.h>
# include <linux/skbuff.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/tcp.h>
# include <linux/timer.h>
# include <linux/types.h>
# include "cu3088.h"
# include "claw.h"
2008-07-18 17:24:56 +04:00
/*
CLAW uses the s390dbf file system see claw_trace and claw_setup
2005-04-17 02:20:36 +04:00
*/
2009-01-20 09:14:33 +03:00
static char version [ ] __initdata = " CLAW driver " ;
2007-02-05 23:16:47 +03:00
static char debug_buffer [ 255 ] ;
2005-04-17 02:20:36 +04:00
/**
* Debug Facility Stuff
*/
static debug_info_t * claw_dbf_setup ;
static debug_info_t * claw_dbf_trace ;
/**
* CLAW Debug Facility functions
*/
static void
claw_unregister_debug_facility ( void )
{
if ( claw_dbf_setup )
debug_unregister ( claw_dbf_setup ) ;
if ( claw_dbf_trace )
debug_unregister ( claw_dbf_trace ) ;
}
static int
claw_register_debug_facility ( void )
{
2005-06-26 01:55:33 +04:00
claw_dbf_setup = debug_register ( " claw_setup " , 2 , 1 , 8 ) ;
claw_dbf_trace = debug_register ( " claw_trace " , 2 , 2 , 8 ) ;
2005-04-17 02:20:36 +04:00
if ( claw_dbf_setup = = NULL | | claw_dbf_trace = = NULL ) {
claw_unregister_debug_facility ( ) ;
return - ENOMEM ;
}
debug_register_view ( claw_dbf_setup , & debug_hex_ascii_view ) ;
debug_set_level ( claw_dbf_setup , 2 ) ;
debug_register_view ( claw_dbf_trace , & debug_hex_ascii_view ) ;
debug_set_level ( claw_dbf_trace , 2 ) ;
return 0 ;
}
static inline void
claw_set_busy ( struct net_device * dev )
{
2008-08-21 19:10:23 +04:00
( ( struct claw_privbk * ) dev - > ml_priv ) - > tbusy = 1 ;
2005-04-17 02:20:36 +04:00
eieio ( ) ;
}
static inline void
claw_clear_busy ( struct net_device * dev )
{
2008-08-21 19:10:23 +04:00
clear_bit ( 0 , & ( ( ( struct claw_privbk * ) dev - > ml_priv ) - > tbusy ) ) ;
2005-04-17 02:20:36 +04:00
netif_wake_queue ( dev ) ;
eieio ( ) ;
}
static inline int
claw_check_busy ( struct net_device * dev )
{
eieio ( ) ;
2008-08-21 19:10:23 +04:00
return ( ( struct claw_privbk * ) dev - > ml_priv ) - > tbusy ;
2005-04-17 02:20:36 +04:00
}
static inline void
claw_setbit_busy ( int nr , struct net_device * dev )
{
netif_stop_queue ( dev ) ;
2008-08-21 19:10:23 +04:00
set_bit ( nr , ( void * ) & ( ( ( struct claw_privbk * ) dev - > ml_priv ) - > tbusy ) ) ;
2005-04-17 02:20:36 +04:00
}
static inline void
claw_clearbit_busy ( int nr , struct net_device * dev )
{
2008-08-21 19:10:23 +04:00
clear_bit ( nr , ( void * ) & ( ( ( struct claw_privbk * ) dev - > ml_priv ) - > tbusy ) ) ;
2005-04-17 02:20:36 +04:00
netif_wake_queue ( dev ) ;
}
static inline int
claw_test_and_setbit_busy ( int nr , struct net_device * dev )
{
netif_stop_queue ( dev ) ;
return test_and_set_bit ( nr ,
2008-08-21 19:10:23 +04:00
( void * ) & ( ( ( struct claw_privbk * ) dev - > ml_priv ) - > tbusy ) ) ;
2005-04-17 02:20:36 +04:00
}
/* Functions for the DEV methods */
static int claw_probe ( struct ccwgroup_device * cgdev ) ;
static void claw_remove_device ( struct ccwgroup_device * cgdev ) ;
static void claw_purge_skb_queue ( struct sk_buff_head * q ) ;
static int claw_new_device ( struct ccwgroup_device * cgdev ) ;
static int claw_shutdown_device ( struct ccwgroup_device * cgdev ) ;
static int claw_tx ( struct sk_buff * skb , struct net_device * dev ) ;
static int claw_change_mtu ( struct net_device * dev , int new_mtu ) ;
static int claw_open ( struct net_device * dev ) ;
static void claw_irq_handler ( struct ccw_device * cdev ,
unsigned long intparm , struct irb * irb ) ;
static void claw_irq_tasklet ( unsigned long data ) ;
static int claw_release ( struct net_device * dev ) ;
static void claw_write_retry ( struct chbk * p_ch ) ;
static void claw_write_next ( struct chbk * p_ch ) ;
static void claw_timer ( struct chbk * p_ch ) ;
/* Functions */
static int add_claw_reads ( struct net_device * dev ,
struct ccwbk * p_first , struct ccwbk * p_last ) ;
2007-02-05 23:18:53 +03:00
static void ccw_check_return_code ( struct ccw_device * cdev , int return_code ) ;
static void ccw_check_unit_check ( struct chbk * p_ch , unsigned char sense ) ;
2005-04-17 02:20:36 +04:00
static int find_link ( struct net_device * dev , char * host_name , char * ws_name ) ;
static int claw_hw_tx ( struct sk_buff * skb , struct net_device * dev , long linkid ) ;
static int init_ccw_bk ( struct net_device * dev ) ;
static void probe_error ( struct ccwgroup_device * cgdev ) ;
static struct net_device_stats * claw_stats ( struct net_device * dev ) ;
2007-02-05 23:18:53 +03:00
static int pages_to_order_of_mag ( int num_of_pages ) ;
2005-04-17 02:20:36 +04:00
static struct sk_buff * claw_pack_skb ( struct claw_privbk * privptr ) ;
/* sysfs Functions */
2009-01-20 09:14:33 +03:00
static ssize_t claw_hname_show ( struct device * dev ,
struct device_attribute * attr , char * buf ) ;
static ssize_t claw_hname_write ( struct device * dev ,
struct device_attribute * attr ,
2005-04-17 02:20:36 +04:00
const char * buf , size_t count ) ;
2009-01-20 09:14:33 +03:00
static ssize_t claw_adname_show ( struct device * dev ,
struct device_attribute * attr , char * buf ) ;
static ssize_t claw_adname_write ( struct device * dev ,
struct device_attribute * attr ,
2005-04-17 02:20:36 +04:00
const char * buf , size_t count ) ;
2009-01-20 09:14:33 +03:00
static ssize_t claw_apname_show ( struct device * dev ,
struct device_attribute * attr , char * buf ) ;
static ssize_t claw_apname_write ( struct device * dev ,
struct device_attribute * attr ,
2005-04-17 02:20:36 +04:00
const char * buf , size_t count ) ;
2009-01-20 09:14:33 +03:00
static ssize_t claw_wbuff_show ( struct device * dev ,
struct device_attribute * attr , char * buf ) ;
static ssize_t claw_wbuff_write ( struct device * dev ,
struct device_attribute * attr ,
2005-04-17 02:20:36 +04:00
const char * buf , size_t count ) ;
2009-01-20 09:14:33 +03:00
static ssize_t claw_rbuff_show ( struct device * dev ,
struct device_attribute * attr , char * buf ) ;
static ssize_t claw_rbuff_write ( struct device * dev ,
struct device_attribute * attr ,
2005-04-17 02:20:36 +04:00
const char * buf , size_t count ) ;
static int claw_add_files ( struct device * dev ) ;
static void claw_remove_files ( struct device * dev ) ;
/* Functions for System Validate */
static int claw_process_control ( struct net_device * dev , struct ccwbk * p_ccw ) ;
static int claw_send_control ( struct net_device * dev , __u8 type , __u8 link ,
__u8 correlator , __u8 rc , char * local_name , char * remote_name ) ;
static int claw_snd_conn_req ( struct net_device * dev , __u8 link ) ;
static int claw_snd_disc ( struct net_device * dev , struct clawctl * p_ctl ) ;
static int claw_snd_sys_validate_rsp ( struct net_device * dev ,
struct clawctl * p_ctl , __u32 return_code ) ;
static int claw_strt_conn_req ( struct net_device * dev ) ;
2008-07-18 17:24:56 +04:00
static void claw_strt_read ( struct net_device * dev , int lock ) ;
static void claw_strt_out_IO ( struct net_device * dev ) ;
static void claw_free_wrt_buf ( struct net_device * dev ) ;
2005-04-17 02:20:36 +04:00
/* Functions for unpack reads */
2008-07-18 17:24:56 +04:00
static void unpack_read ( struct net_device * dev ) ;
2005-04-17 02:20:36 +04:00
2009-06-16 12:30:33 +04:00
static int claw_pm_prepare ( struct ccwgroup_device * gdev )
{
return - EPERM ;
}
2005-04-17 02:20:36 +04:00
/* ccwgroup table */
static struct ccwgroup_driver claw_group_driver = {
. owner = THIS_MODULE ,
. name = " claw " ,
. max_slaves = 2 ,
. driver_id = 0xC3D3C1E6 ,
. probe = claw_probe ,
. remove = claw_remove_device ,
. set_online = claw_new_device ,
. set_offline = claw_shutdown_device ,
2009-06-16 12:30:33 +04:00
. prepare = claw_pm_prepare ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Key functions
*/
/*----------------------------------------------------------------*
* claw_probe *
* this function is called for each CLAW device . *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_probe ( struct ccwgroup_device * cgdev )
{
int rc ;
struct claw_privbk * privptr = NULL ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " probe " ) ;
2005-04-17 02:20:36 +04:00
if ( ! get_device ( & cgdev - > dev ) )
return - ENODEV ;
2006-03-24 14:15:31 +03:00
privptr = kzalloc ( sizeof ( struct claw_privbk ) , GFP_KERNEL ) ;
2009-05-04 23:40:54 +04:00
dev_set_drvdata ( & cgdev - > dev , privptr ) ;
2005-04-17 02:20:36 +04:00
if ( privptr = = NULL ) {
probe_error ( cgdev ) ;
put_device ( & cgdev - > dev ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 2 , setup , " probex%d " , - ENOMEM ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
privptr - > p_mtc_envelope = kzalloc ( MAX_ENVELOPE_SIZE , GFP_KERNEL ) ;
privptr - > p_env = kzalloc ( sizeof ( struct claw_env ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ( privptr - > p_mtc_envelope = = NULL ) | | ( privptr - > p_env = = NULL ) ) {
probe_error ( cgdev ) ;
put_device ( & cgdev - > dev ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 2 , setup , " probex%d " , - ENOMEM ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
memcpy ( privptr - > p_env - > adapter_name , WS_NAME_NOT_DEF , 8 ) ;
memcpy ( privptr - > p_env - > host_name , WS_NAME_NOT_DEF , 8 ) ;
memcpy ( privptr - > p_env - > api_type , WS_NAME_NOT_DEF , 8 ) ;
privptr - > p_env - > packing = 0 ;
privptr - > p_env - > write_buffers = 5 ;
privptr - > p_env - > read_buffers = 5 ;
privptr - > p_env - > read_size = CLAW_FRAME_SIZE ;
privptr - > p_env - > write_size = CLAW_FRAME_SIZE ;
rc = claw_add_files ( & cgdev - > dev ) ;
if ( rc ) {
probe_error ( cgdev ) ;
put_device ( & cgdev - > dev ) ;
2009-01-20 09:14:33 +03:00
dev_err ( & cgdev - > dev , " Creating the /proc files for a new "
" CLAW device failed \n " ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 2 , setup , " probex%d " , rc ) ;
2005-04-17 02:20:36 +04:00
return rc ;
}
privptr - > p_env - > p_priv = privptr ;
cgdev - > cdev [ 0 ] - > handler = claw_irq_handler ;
cgdev - > cdev [ 1 ] - > handler = claw_irq_handler ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " prbext 0 " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
} /* end of claw_probe */
/*-------------------------------------------------------------------*
* claw_tx *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_tx ( struct sk_buff * skb , struct net_device * dev )
{
int rc ;
2008-08-21 19:10:23 +04:00
struct claw_privbk * privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
unsigned long saveflags ;
struct chbk * p_ch ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " claw_tx " ) ;
2005-04-17 02:20:36 +04:00
p_ch = & privptr - > channel [ WRITE ] ;
spin_lock_irqsave ( get_ccwdev_lock ( p_ch - > cdev ) , saveflags ) ;
rc = claw_hw_tx ( skb , dev , 1 ) ;
spin_unlock_irqrestore ( get_ccwdev_lock ( p_ch - > cdev ) , saveflags ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 4 , trace , " clawtx%d " , rc ) ;
2009-03-24 06:27:46 +03:00
if ( rc )
rc = NETDEV_TX_BUSY ;
2009-07-06 06:23:38 +04:00
else
rc = NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
return rc ;
} /* end of claw_tx */
/*------------------------------------------------------------------*
* pack the collect queue into an skb and return it *
* If not packing just return the top skb from the queue *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static struct sk_buff *
claw_pack_skb ( struct claw_privbk * privptr )
{
struct sk_buff * new_skb , * held_skb ;
struct chbk * p_ch = & privptr - > channel [ WRITE ] ;
struct claw_env * p_env = privptr - > p_env ;
int pkt_cnt , pk_ind , so_far ;
new_skb = NULL ; /* assume no dice */
pkt_cnt = 0 ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " PackSKBe " ) ;
2005-07-09 01:57:23 +04:00
if ( ! skb_queue_empty ( & p_ch - > collect_queue ) ) {
2005-04-17 02:20:36 +04:00
/* some data */
held_skb = skb_dequeue ( & p_ch - > collect_queue ) ;
if ( held_skb )
2005-09-06 17:03:09 +04:00
dev_kfree_skb_any ( held_skb ) ;
2005-04-17 02:20:36 +04:00
else
return NULL ;
2005-09-06 17:03:09 +04:00
if ( p_env - > packing ! = DO_PACKED )
return held_skb ;
2005-04-17 02:20:36 +04:00
/* get a new SKB we will pack at least one */
new_skb = dev_alloc_skb ( p_env - > write_size ) ;
if ( new_skb = = NULL ) {
atomic_inc ( & held_skb - > users ) ;
skb_queue_head ( & p_ch - > collect_queue , held_skb ) ;
return NULL ;
}
/* we have packed packet and a place to put it */
pk_ind = 1 ;
so_far = 0 ;
new_skb - > cb [ 1 ] = ' P ' ; /* every skb on queue has pack header */
while ( ( pk_ind ) & & ( held_skb ! = NULL ) ) {
if ( held_skb - > len + so_far < = p_env - > write_size - 8 ) {
memcpy ( skb_put ( new_skb , held_skb - > len ) ,
held_skb - > data , held_skb - > len ) ;
privptr - > stats . tx_packets + + ;
so_far + = held_skb - > len ;
pkt_cnt + + ;
2005-09-06 17:03:09 +04:00
dev_kfree_skb_any ( held_skb ) ;
2005-04-17 02:20:36 +04:00
held_skb = skb_dequeue ( & p_ch - > collect_queue ) ;
if ( held_skb )
atomic_dec ( & held_skb - > users ) ;
} else {
pk_ind = 0 ;
atomic_inc ( & held_skb - > users ) ;
skb_queue_head ( & p_ch - > collect_queue , held_skb ) ;
}
}
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " PackSKBx " ) ;
2005-04-17 02:20:36 +04:00
return new_skb ;
}
/*-------------------------------------------------------------------*
* claw_change_mtu *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_change_mtu ( struct net_device * dev , int new_mtu )
{
2008-08-21 19:10:23 +04:00
struct claw_privbk * privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
int buff_size ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " setmtu " ) ;
2005-04-17 02:20:36 +04:00
buff_size = privptr - > p_env - > write_size ;
if ( ( new_mtu < 60 ) | | ( new_mtu > buff_size ) ) {
return - EINVAL ;
}
dev - > mtu = new_mtu ;
return 0 ;
} /* end of claw_change_mtu */
/*-------------------------------------------------------------------*
* claw_open *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_open ( struct net_device * dev )
{
int rc ;
int i ;
unsigned long saveflags = 0 ;
unsigned long parm ;
struct claw_privbk * privptr ;
DECLARE_WAITQUEUE ( wait , current ) ;
struct timer_list timer ;
struct ccwbk * p_buf ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " open " ) ;
2008-08-21 19:10:23 +04:00
privptr = ( struct claw_privbk * ) dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
/* allocate and initialize CCW blocks */
if ( privptr - > buffs_alloc = = 0 ) {
rc = init_ccw_bk ( dev ) ;
if ( rc ) {
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " openmem " ) ;
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
}
privptr - > system_validate_comp = 0 ;
privptr - > release_pend = 0 ;
if ( strncmp ( privptr - > p_env - > api_type , WS_APPL_NAME_PACKED , 6 ) = = 0 ) {
privptr - > p_env - > read_size = DEF_PACK_BUFSIZE ;
privptr - > p_env - > write_size = DEF_PACK_BUFSIZE ;
privptr - > p_env - > packing = PACKING_ASK ;
} else {
privptr - > p_env - > packing = 0 ;
privptr - > p_env - > read_size = CLAW_FRAME_SIZE ;
privptr - > p_env - > write_size = CLAW_FRAME_SIZE ;
}
claw_set_busy ( dev ) ;
tasklet_init ( & privptr - > channel [ READ ] . tasklet , claw_irq_tasklet ,
( unsigned long ) & privptr - > channel [ READ ] ) ;
for ( i = 0 ; i < 2 ; i + + ) {
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 2 , trace , " opn_ch%d " , i ) ;
2005-04-17 02:20:36 +04:00
init_waitqueue_head ( & privptr - > channel [ i ] . wait ) ;
/* skb_queue_head_init(&p_ch->io_queue); */
if ( i = = WRITE )
skb_queue_head_init (
& privptr - > channel [ WRITE ] . collect_queue ) ;
privptr - > channel [ i ] . flag_a = 0 ;
privptr - > channel [ i ] . IO_active = 0 ;
privptr - > channel [ i ] . flag & = ~ CLAW_TIMER ;
init_timer ( & timer ) ;
timer . function = ( void * ) claw_timer ;
timer . data = ( unsigned long ) ( & privptr - > channel [ i ] ) ;
timer . expires = jiffies + 15 * HZ ;
add_timer ( & timer ) ;
spin_lock_irqsave ( get_ccwdev_lock (
privptr - > channel [ i ] . cdev ) , saveflags ) ;
parm = ( unsigned long ) & privptr - > channel [ i ] ;
privptr - > channel [ i ] . claw_state = CLAW_START_HALT_IO ;
rc = 0 ;
add_wait_queue ( & privptr - > channel [ i ] . wait , & wait ) ;
rc = ccw_device_halt (
( struct ccw_device * ) privptr - > channel [ i ] . cdev , parm ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
spin_unlock_irqrestore (
get_ccwdev_lock ( privptr - > channel [ i ] . cdev ) , saveflags ) ;
schedule ( ) ;
set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( & privptr - > channel [ i ] . wait , & wait ) ;
if ( rc ! = 0 )
ccw_check_return_code ( privptr - > channel [ i ] . cdev , rc ) ;
if ( ( privptr - > channel [ i ] . flag & CLAW_TIMER ) = = 0x00 )
del_timer ( & timer ) ;
}
if ( ( ( ( privptr - > channel [ READ ] . last_dstat |
privptr - > channel [ WRITE ] . last_dstat ) &
~ ( DEV_STAT_CHN_END | DEV_STAT_DEV_END ) ) ! = 0x00 ) | |
( ( ( privptr - > channel [ READ ] . flag |
privptr - > channel [ WRITE ] . flag ) & CLAW_TIMER ) ! = 0x00 ) ) {
2009-01-20 09:14:33 +03:00
dev_info ( & privptr - > channel [ READ ] . cdev - > dev ,
" %s: remote side is not ready \n " , dev - > name ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " notrdy " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < 2 ; i + + ) {
spin_lock_irqsave (
get_ccwdev_lock ( privptr - > channel [ i ] . cdev ) ,
saveflags ) ;
parm = ( unsigned long ) & privptr - > channel [ i ] ;
privptr - > channel [ i ] . claw_state = CLAW_STOP ;
rc = ccw_device_halt (
( struct ccw_device * ) & privptr - > channel [ i ] . cdev ,
parm ) ;
spin_unlock_irqrestore (
get_ccwdev_lock ( privptr - > channel [ i ] . cdev ) ,
saveflags ) ;
if ( rc ! = 0 ) {
ccw_check_return_code (
privptr - > channel [ i ] . cdev , rc ) ;
}
}
free_pages ( ( unsigned long ) privptr - > p_buff_ccw ,
( int ) pages_to_order_of_mag ( privptr - > p_buff_ccw_num ) ) ;
if ( privptr - > p_env - > read_size < PAGE_SIZE ) {
free_pages ( ( unsigned long ) privptr - > p_buff_read ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_read_num ) ) ;
}
else {
p_buf = privptr - > p_read_active_first ;
while ( p_buf ! = NULL ) {
free_pages ( ( unsigned long ) p_buf - > p_buffer ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_pages_perread ) ) ;
p_buf = p_buf - > next ;
}
}
if ( privptr - > p_env - > write_size < PAGE_SIZE ) {
free_pages ( ( unsigned long ) privptr - > p_buff_write ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_write_num ) ) ;
}
else {
p_buf = privptr - > p_write_active_first ;
while ( p_buf ! = NULL ) {
free_pages ( ( unsigned long ) p_buf - > p_buffer ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_pages_perwrite ) ) ;
p_buf = p_buf - > next ;
}
}
privptr - > buffs_alloc = 0 ;
privptr - > channel [ READ ] . flag = 0x00 ;
privptr - > channel [ WRITE ] . flag = 0x00 ;
privptr - > p_buff_ccw = NULL ;
privptr - > p_buff_read = NULL ;
privptr - > p_buff_write = NULL ;
claw_clear_busy ( dev ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " open EIO " ) ;
2005-04-17 02:20:36 +04:00
return - EIO ;
}
/* Send SystemValidate command */
claw_clear_busy ( dev ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " openok " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
} /* end of claw_open */
/*-------------------------------------------------------------------*
* *
* claw_irq_handler *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
claw_irq_handler ( struct ccw_device * cdev ,
unsigned long intparm , struct irb * irb )
{
struct chbk * p_ch = NULL ;
struct claw_privbk * privptr = NULL ;
struct net_device * dev = NULL ;
struct claw_env * p_env ;
struct chbk * p_ch_r = NULL ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " clawirq " ) ;
2005-04-17 02:20:36 +04:00
/* Bypass all 'unsolicited interrupts' */
2009-05-04 23:40:54 +04:00
privptr = dev_get_drvdata ( & cdev - > dev ) ;
if ( ! privptr ) {
2009-01-20 09:14:33 +03:00
dev_warn ( & cdev - > dev , " An uninitialized CLAW device received an "
" IRQ, c-%02x d-%02x \n " ,
irb - > scsw . cmd . cstat , irb - > scsw . cmd . dstat ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " badirq " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/* Try to extract channel from driver data. */
if ( privptr - > channel [ READ ] . cdev = = cdev )
p_ch = & privptr - > channel [ READ ] ;
else if ( privptr - > channel [ WRITE ] . cdev = = cdev )
p_ch = & privptr - > channel [ WRITE ] ;
else {
2009-01-20 09:14:33 +03:00
dev_warn ( & cdev - > dev , " The device is not a CLAW device \n " ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " badchan " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 4 , trace , " IRQCH=%d " , p_ch - > flag ) ;
2005-04-17 02:20:36 +04:00
dev = ( struct net_device * ) ( p_ch - > ndev ) ;
p_env = privptr - > p_env ;
/* Copy interruption response block. */
memcpy ( p_ch - > irb , irb , sizeof ( struct irb ) ) ;
2008-07-18 17:24:56 +04:00
/* Check for good subchannel return code, otherwise info message */
2008-07-14 11:58:50 +04:00
if ( irb - > scsw . cmd . cstat & & ! ( irb - > scsw . cmd . cstat & SCHN_STAT_PCI ) ) {
2009-01-20 09:14:33 +03:00
dev_info ( & cdev - > dev ,
" %s: subchannel check for device: %04x - "
2005-04-17 02:20:36 +04:00
" Sch Stat %02x Dev Stat %02x CPA - %04x \n " ,
dev - > name , p_ch - > devno ,
2008-07-14 11:58:50 +04:00
irb - > scsw . cmd . cstat , irb - > scsw . cmd . dstat ,
irb - > scsw . cmd . cpa ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " chanchk " ) ;
2005-04-17 02:20:36 +04:00
/* return; */
}
/* Check the reason-code of a unit check */
2008-07-14 11:58:50 +04:00
if ( irb - > scsw . cmd . dstat & DEV_STAT_UNIT_CHECK )
2005-04-17 02:20:36 +04:00
ccw_check_unit_check ( p_ch , irb - > ecw [ 0 ] ) ;
/* State machine to bring the connection up, down and to restart */
2008-07-14 11:58:50 +04:00
p_ch - > last_dstat = irb - > scsw . cmd . dstat ;
2005-04-17 02:20:36 +04:00
switch ( p_ch - > claw_state ) {
2008-07-18 17:24:56 +04:00
case CLAW_STOP : /* HALT_IO by claw_release (halt sequence) */
if ( ! ( ( p_ch - > irb - > scsw . cmd . stctl & SCSW_STCTL_SEC_STATUS ) | |
( p_ch - > irb - > scsw . cmd . stctl = = SCSW_STCTL_STATUS_PEND ) | |
( p_ch - > irb - > scsw . cmd . stctl = =
( SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND ) ) ) )
return ;
wake_up ( & p_ch - > wait ) ; /* wake up claw_release */
CLAW_DBF_TEXT ( 4 , trace , " stop " ) ;
return ;
case CLAW_START_HALT_IO : /* HALT_IO issued by claw_open */
if ( ! ( ( p_ch - > irb - > scsw . cmd . stctl & SCSW_STCTL_SEC_STATUS ) | |
( p_ch - > irb - > scsw . cmd . stctl = = SCSW_STCTL_STATUS_PEND ) | |
( p_ch - > irb - > scsw . cmd . stctl = =
( SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND ) ) ) ) {
CLAW_DBF_TEXT ( 4 , trace , " haltio " ) ;
return ;
}
if ( p_ch - > flag = = CLAW_READ ) {
p_ch - > claw_state = CLAW_START_READ ;
wake_up ( & p_ch - > wait ) ; /* wake claw_open (READ)*/
} else if ( p_ch - > flag = = CLAW_WRITE ) {
p_ch - > claw_state = CLAW_START_WRITE ;
2009-01-20 09:14:33 +03:00
/* send SYSTEM_VALIDATE */
2008-07-18 17:24:56 +04:00
claw_strt_read ( dev , LOCK_NO ) ;
claw_send_control ( dev ,
SYSTEM_VALIDATE_REQUEST ,
0 , 0 , 0 ,
p_env - > host_name ,
p_env - > adapter_name ) ;
} else {
2009-01-20 09:14:33 +03:00
dev_warn ( & cdev - > dev , " The CLAW device received "
" an unexpected IRQ, "
" c-%02x d-%02x \n " ,
2008-07-18 17:24:56 +04:00
irb - > scsw . cmd . cstat ,
irb - > scsw . cmd . dstat ) ;
return ;
}
CLAW_DBF_TEXT ( 4 , trace , " haltio " ) ;
return ;
case CLAW_START_READ :
CLAW_DBF_TEXT ( 4 , trace , " ReadIRQ " ) ;
if ( p_ch - > irb - > scsw . cmd . dstat & DEV_STAT_UNIT_CHECK ) {
clear_bit ( 0 , ( void * ) & p_ch - > IO_active ) ;
if ( ( p_ch - > irb - > ecw [ 0 ] & 0x41 ) = = 0x41 | |
( p_ch - > irb - > ecw [ 0 ] & 0x40 ) = = 0x40 | |
( p_ch - > irb - > ecw [ 0 ] ) = = 0 ) {
privptr - > stats . rx_errors + + ;
2009-01-20 09:14:33 +03:00
dev_info ( & cdev - > dev ,
" %s: Restart is required after remote "
2008-07-18 17:24:56 +04:00
" side recovers \n " ,
dev - > name ) ;
}
CLAW_DBF_TEXT ( 4 , trace , " notrdy " ) ;
return ;
}
if ( ( p_ch - > irb - > scsw . cmd . cstat & SCHN_STAT_PCI ) & &
( p_ch - > irb - > scsw . cmd . dstat = = 0 ) ) {
if ( test_and_set_bit ( CLAW_BH_ACTIVE ,
( void * ) & p_ch - > flag_a ) = = 0 )
tasklet_schedule ( & p_ch - > tasklet ) ;
2005-04-17 02:20:36 +04:00
else
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " PCINoBH " ) ;
CLAW_DBF_TEXT ( 4 , trace , " PCI_read " ) ;
return ;
}
if ( ! ( ( p_ch - > irb - > scsw . cmd . stctl & SCSW_STCTL_SEC_STATUS ) | |
( p_ch - > irb - > scsw . cmd . stctl = = SCSW_STCTL_STATUS_PEND ) | |
( p_ch - > irb - > scsw . cmd . stctl = =
( SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND ) ) ) ) {
CLAW_DBF_TEXT ( 4 , trace , " SPend_rd " ) ;
return ;
}
clear_bit ( 0 , ( void * ) & p_ch - > IO_active ) ;
claw_clearbit_busy ( TB_RETRY , dev ) ;
if ( test_and_set_bit ( CLAW_BH_ACTIVE ,
( void * ) & p_ch - > flag_a ) = = 0 )
tasklet_schedule ( & p_ch - > tasklet ) ;
else
CLAW_DBF_TEXT ( 4 , trace , " RdBHAct " ) ;
CLAW_DBF_TEXT ( 4 , trace , " RdIRQXit " ) ;
return ;
case CLAW_START_WRITE :
if ( p_ch - > irb - > scsw . cmd . dstat & DEV_STAT_UNIT_CHECK ) {
2009-01-20 09:14:33 +03:00
dev_info ( & cdev - > dev ,
" %s: Unit Check Occured in "
2008-07-18 17:24:56 +04:00
" write channel \n " , dev - > name ) ;
clear_bit ( 0 , ( void * ) & p_ch - > IO_active ) ;
if ( p_ch - > irb - > ecw [ 0 ] & 0x80 ) {
2009-01-20 09:14:33 +03:00
dev_info ( & cdev - > dev ,
" %s: Resetting Event "
2008-07-18 17:24:56 +04:00
" occurred: \n " , dev - > name ) ;
init_timer ( & p_ch - > timer ) ;
p_ch - > timer . function =
( void * ) claw_write_retry ;
p_ch - > timer . data = ( unsigned long ) p_ch ;
p_ch - > timer . expires = jiffies + 10 * HZ ;
add_timer ( & p_ch - > timer ) ;
2009-01-20 09:14:33 +03:00
dev_info ( & cdev - > dev ,
" %s: write connection "
2008-07-18 17:24:56 +04:00
" restarting \n " , dev - > name ) ;
}
CLAW_DBF_TEXT ( 4 , trace , " rstrtwrt " ) ;
return ;
}
if ( p_ch - > irb - > scsw . cmd . dstat & DEV_STAT_UNIT_EXCEP ) {
clear_bit ( 0 , ( void * ) & p_ch - > IO_active ) ;
2009-01-20 09:14:33 +03:00
dev_info ( & cdev - > dev ,
" %s: Unit Exception "
" occurred in write channel \n " ,
dev - > name ) ;
2008-07-18 17:24:56 +04:00
}
if ( ! ( ( p_ch - > irb - > scsw . cmd . stctl & SCSW_STCTL_SEC_STATUS ) | |
( p_ch - > irb - > scsw . cmd . stctl = = SCSW_STCTL_STATUS_PEND ) | |
( p_ch - > irb - > scsw . cmd . stctl = =
( SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND ) ) ) ) {
CLAW_DBF_TEXT ( 4 , trace , " writeUE " ) ;
return ;
}
clear_bit ( 0 , ( void * ) & p_ch - > IO_active ) ;
if ( claw_test_and_setbit_busy ( TB_TX , dev ) = = 0 ) {
claw_write_next ( p_ch ) ;
claw_clearbit_busy ( TB_TX , dev ) ;
claw_clear_busy ( dev ) ;
}
p_ch_r = ( struct chbk * ) & privptr - > channel [ READ ] ;
if ( test_and_set_bit ( CLAW_BH_ACTIVE ,
( void * ) & p_ch_r - > flag_a ) = = 0 )
tasklet_schedule ( & p_ch_r - > tasklet ) ;
CLAW_DBF_TEXT ( 4 , trace , " StWtExit " ) ;
return ;
default :
2009-01-20 09:14:33 +03:00
dev_warn ( & cdev - > dev ,
" The CLAW device for %s received an unexpected IRQ \n " ,
dev - > name ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " badIRQ " ) ;
return ;
2005-04-17 02:20:36 +04:00
}
} /* end of claw_irq_handler */
/*-------------------------------------------------------------------*
* claw_irq_tasklet *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
claw_irq_tasklet ( unsigned long data )
{
struct chbk * p_ch ;
struct net_device * dev ;
struct claw_privbk * privptr ;
p_ch = ( struct chbk * ) data ;
dev = ( struct net_device * ) p_ch - > ndev ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " IRQtask " ) ;
2008-08-21 19:10:23 +04:00
privptr = ( struct claw_privbk * ) dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
unpack_read ( dev ) ;
clear_bit ( CLAW_BH_ACTIVE , ( void * ) & p_ch - > flag_a ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " TskletXt " ) ;
2005-04-17 02:20:36 +04:00
return ;
} /* end of claw_irq_bh */
/*-------------------------------------------------------------------*
* claw_release *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_release ( struct net_device * dev )
{
int rc ;
int i ;
unsigned long saveflags ;
unsigned long parm ;
struct claw_privbk * privptr ;
DECLARE_WAITQUEUE ( wait , current ) ;
struct ccwbk * p_this_ccw ;
struct ccwbk * p_buf ;
if ( ! dev )
return 0 ;
2008-08-21 19:10:23 +04:00
privptr = ( struct claw_privbk * ) dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
if ( ! privptr )
return 0 ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " release " ) ;
2005-04-17 02:20:36 +04:00
privptr - > release_pend = 1 ;
claw_setbit_busy ( TB_STOP , dev ) ;
for ( i = 1 ; i > = 0 ; i - - ) {
spin_lock_irqsave (
get_ccwdev_lock ( privptr - > channel [ i ] . cdev ) , saveflags ) ;
/* del_timer(&privptr->channel[READ].timer); */
privptr - > channel [ i ] . claw_state = CLAW_STOP ;
privptr - > channel [ i ] . IO_active = 0 ;
parm = ( unsigned long ) & privptr - > channel [ i ] ;
if ( i = = WRITE )
claw_purge_skb_queue (
& privptr - > channel [ WRITE ] . collect_queue ) ;
rc = ccw_device_halt ( privptr - > channel [ i ] . cdev , parm ) ;
if ( privptr - > system_validate_comp = = 0x00 ) /* never opened? */
init_waitqueue_head ( & privptr - > channel [ i ] . wait ) ;
add_wait_queue ( & privptr - > channel [ i ] . wait , & wait ) ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
spin_unlock_irqrestore (
get_ccwdev_lock ( privptr - > channel [ i ] . cdev ) , saveflags ) ;
schedule ( ) ;
set_current_state ( TASK_RUNNING ) ;
remove_wait_queue ( & privptr - > channel [ i ] . wait , & wait ) ;
if ( rc ! = 0 ) {
ccw_check_return_code ( privptr - > channel [ i ] . cdev , rc ) ;
}
}
if ( privptr - > pk_skb ! = NULL ) {
2005-09-06 17:03:09 +04:00
dev_kfree_skb_any ( privptr - > pk_skb ) ;
2005-04-17 02:20:36 +04:00
privptr - > pk_skb = NULL ;
}
if ( privptr - > buffs_alloc ! = 1 ) {
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " none2fre " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " freebufs " ) ;
2005-04-17 02:20:36 +04:00
if ( privptr - > p_buff_ccw ! = NULL ) {
free_pages ( ( unsigned long ) privptr - > p_buff_ccw ,
( int ) pages_to_order_of_mag ( privptr - > p_buff_ccw_num ) ) ;
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " freeread " ) ;
2005-04-17 02:20:36 +04:00
if ( privptr - > p_env - > read_size < PAGE_SIZE ) {
if ( privptr - > p_buff_read ! = NULL ) {
free_pages ( ( unsigned long ) privptr - > p_buff_read ,
( int ) pages_to_order_of_mag ( privptr - > p_buff_read_num ) ) ;
}
}
else {
p_buf = privptr - > p_read_active_first ;
while ( p_buf ! = NULL ) {
free_pages ( ( unsigned long ) p_buf - > p_buffer ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_pages_perread ) ) ;
p_buf = p_buf - > next ;
}
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " freewrit " ) ;
2005-04-17 02:20:36 +04:00
if ( privptr - > p_env - > write_size < PAGE_SIZE ) {
free_pages ( ( unsigned long ) privptr - > p_buff_write ,
( int ) pages_to_order_of_mag ( privptr - > p_buff_write_num ) ) ;
}
else {
p_buf = privptr - > p_write_active_first ;
while ( p_buf ! = NULL ) {
free_pages ( ( unsigned long ) p_buf - > p_buffer ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_pages_perwrite ) ) ;
p_buf = p_buf - > next ;
}
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " clearptr " ) ;
2005-04-17 02:20:36 +04:00
privptr - > buffs_alloc = 0 ;
privptr - > p_buff_ccw = NULL ;
privptr - > p_buff_read = NULL ;
privptr - > p_buff_write = NULL ;
privptr - > system_validate_comp = 0 ;
privptr - > release_pend = 0 ;
/* Remove any writes that were pending and reset all reads */
p_this_ccw = privptr - > p_read_active_first ;
while ( p_this_ccw ! = NULL ) {
p_this_ccw - > header . length = 0xffff ;
p_this_ccw - > header . opcode = 0xff ;
p_this_ccw - > header . flag = 0x00 ;
p_this_ccw = p_this_ccw - > next ;
}
while ( privptr - > p_write_active_first ! = NULL ) {
p_this_ccw = privptr - > p_write_active_first ;
p_this_ccw - > header . flag = CLAW_PENDING ;
privptr - > p_write_active_first = p_this_ccw - > next ;
p_this_ccw - > next = privptr - > p_write_free_chain ;
privptr - > p_write_free_chain = p_this_ccw ;
+ + privptr - > write_free_count ;
}
privptr - > p_write_active_last = NULL ;
privptr - > mtc_logical_link = - 1 ;
privptr - > mtc_skipping = 1 ;
privptr - > mtc_offset = 0 ;
if ( ( ( privptr - > channel [ READ ] . last_dstat |
privptr - > channel [ WRITE ] . last_dstat ) &
~ ( DEV_STAT_CHN_END | DEV_STAT_DEV_END ) ) ! = 0x00 ) {
2009-01-20 09:14:33 +03:00
dev_warn ( & privptr - > channel [ READ ] . cdev - > dev ,
" Deactivating %s completed with incorrect "
" subchannel status "
" (read %02x, write %02x) \n " ,
2005-04-17 02:20:36 +04:00
dev - > name ,
privptr - > channel [ READ ] . last_dstat ,
privptr - > channel [ WRITE ] . last_dstat ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " badclose " ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " rlsexit " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
} /* end of claw_release */
/*-------------------------------------------------------------------*
* claw_write_retry *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
claw_write_retry ( struct chbk * p_ch )
{
struct net_device * dev = p_ch - > ndev ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " w_retry " ) ;
2005-04-17 02:20:36 +04:00
if ( p_ch - > claw_state = = CLAW_STOP ) {
return ;
}
claw_strt_out_IO ( dev ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " rtry_xit " ) ;
2005-04-17 02:20:36 +04:00
return ;
} /* end of claw_write_retry */
/*-------------------------------------------------------------------*
* claw_write_next *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
claw_write_next ( struct chbk * p_ch )
{
struct net_device * dev ;
struct claw_privbk * privptr = NULL ;
struct sk_buff * pk_skb ;
int rc ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " claw_wrt " ) ;
2005-04-17 02:20:36 +04:00
if ( p_ch - > claw_state = = CLAW_STOP )
return ;
dev = ( struct net_device * ) p_ch - > ndev ;
2008-08-21 19:10:23 +04:00
privptr = ( struct claw_privbk * ) dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
claw_free_wrt_buf ( dev ) ;
if ( ( privptr - > write_free_count > 0 ) & &
2005-07-09 01:57:23 +04:00
! skb_queue_empty ( & p_ch - > collect_queue ) ) {
2005-04-17 02:20:36 +04:00
pk_skb = claw_pack_skb ( privptr ) ;
while ( pk_skb ! = NULL ) {
rc = claw_hw_tx ( pk_skb , dev , 1 ) ;
if ( privptr - > write_free_count > 0 ) {
pk_skb = claw_pack_skb ( privptr ) ;
} else
pk_skb = NULL ;
}
}
if ( privptr - > p_write_active_first ! = NULL ) {
claw_strt_out_IO ( dev ) ;
}
return ;
} /* end of claw_write_next */
/*-------------------------------------------------------------------*
* *
* claw_timer *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
claw_timer ( struct chbk * p_ch )
{
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " timer " ) ;
2005-04-17 02:20:36 +04:00
p_ch - > flag | = CLAW_TIMER ;
wake_up ( & p_ch - > wait ) ;
return ;
} /* end of claw_timer */
/*
*
* functions
*/
/*-------------------------------------------------------------------*
* *
* pages_to_order_of_mag *
* *
* takes a number of pages from 1 to 512 and returns the *
* log ( num_pages ) / log ( 2 ) get_free_pages ( ) needs a base 2 order *
* of magnitude get_free_pages ( ) has an upper order of 9 *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-02-05 23:18:53 +03:00
static int
2005-04-17 02:20:36 +04:00
pages_to_order_of_mag ( int num_of_pages )
{
int order_of_mag = 1 ; /* assume 2 pages */
2009-03-24 06:27:51 +03:00
int nump ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 5 , trace , " pages%d " , num_of_pages ) ;
2005-04-17 02:20:36 +04:00
if ( num_of_pages = = 1 ) { return 0 ; } /* magnitude of 0 = 1 page */
/* 512 pages = 2Meg on 4k page systems */
if ( num_of_pages > = 512 ) { return 9 ; }
/* we have two or more pages order is at least 1 */
for ( nump = 2 ; nump < = 512 ; nump * = 2 ) {
if ( num_of_pages < = nump )
break ;
order_of_mag + = 1 ;
}
if ( order_of_mag > 9 ) { order_of_mag = 9 ; } /* I know it's paranoid */
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 5 , trace , " mag%d " , order_of_mag ) ;
2005-04-17 02:20:36 +04:00
return order_of_mag ;
}
/*-------------------------------------------------------------------*
* *
* add_claw_reads *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
add_claw_reads ( struct net_device * dev , struct ccwbk * p_first ,
struct ccwbk * p_last )
{
struct claw_privbk * privptr ;
struct ccw1 temp_ccw ;
struct endccw * p_end ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " addreads " ) ;
2008-08-21 19:10:23 +04:00
privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
p_end = privptr - > p_end_ccw ;
/* first CCW and last CCW contains a new set of read channel programs
* to apend the running channel programs
*/
if ( p_first = = NULL ) {
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " addexit " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* set up ending CCW sequence for this segment */
if ( p_end - > read1 ) {
p_end - > read1 = 0x00 ; /* second ending CCW is now active */
/* reset ending CCWs and setup TIC CCWs */
p_end - > read2_nop2 . cmd_code = CCW_CLAW_CMD_READFF ;
p_end - > read2_nop2 . flags = CCW_FLAG_SLI | CCW_FLAG_SKIP ;
p_last - > r_TIC_1 . cda = ( __u32 ) __pa ( & p_end - > read2_nop1 ) ;
p_last - > r_TIC_2 . cda = ( __u32 ) __pa ( & p_end - > read2_nop1 ) ;
p_end - > read2_nop2 . cda = 0 ;
p_end - > read2_nop2 . count = 1 ;
}
else {
p_end - > read1 = 0x01 ; /* first ending CCW is now active */
/* reset ending CCWs and setup TIC CCWs */
p_end - > read1_nop2 . cmd_code = CCW_CLAW_CMD_READFF ;
p_end - > read1_nop2 . flags = CCW_FLAG_SLI | CCW_FLAG_SKIP ;
p_last - > r_TIC_1 . cda = ( __u32 ) __pa ( & p_end - > read1_nop1 ) ;
p_last - > r_TIC_2 . cda = ( __u32 ) __pa ( & p_end - > read1_nop1 ) ;
p_end - > read1_nop2 . cda = 0 ;
p_end - > read1_nop2 . count = 1 ;
}
if ( privptr - > p_read_active_first = = NULL ) {
2009-01-20 09:14:33 +03:00
privptr - > p_read_active_first = p_first ; /* set new first */
privptr - > p_read_active_last = p_last ; /* set new last */
2005-04-17 02:20:36 +04:00
}
else {
/* set up TIC ccw */
temp_ccw . cda = ( __u32 ) __pa ( & p_first - > read ) ;
temp_ccw . count = 0 ;
temp_ccw . flags = 0 ;
temp_ccw . cmd_code = CCW_CLAW_CMD_TIC ;
if ( p_end - > read1 ) {
/* first set of CCW's is chained to the new read */
/* chain, so the second set is chained to the active chain. */
/* Therefore modify the second set to point to the new */
/* read chain set up TIC CCWs */
/* make sure we update the CCW so channel doesn't fetch it */
/* when it's only half done */
memcpy ( & p_end - > read2_nop2 , & temp_ccw ,
sizeof ( struct ccw1 ) ) ;
privptr - > p_read_active_last - > r_TIC_1 . cda =
( __u32 ) __pa ( & p_first - > read ) ;
privptr - > p_read_active_last - > r_TIC_2 . cda =
( __u32 ) __pa ( & p_first - > read ) ;
}
else {
/* make sure we update the CCW so channel doesn't */
/* fetch it when it is only half done */
memcpy ( & p_end - > read1_nop2 , & temp_ccw ,
sizeof ( struct ccw1 ) ) ;
privptr - > p_read_active_last - > r_TIC_1 . cda =
( __u32 ) __pa ( & p_first - > read ) ;
privptr - > p_read_active_last - > r_TIC_2 . cda =
( __u32 ) __pa ( & p_first - > read ) ;
}
2009-01-20 09:14:33 +03:00
/* chain in new set of blocks */
2005-04-17 02:20:36 +04:00
privptr - > p_read_active_last - > next = p_first ;
privptr - > p_read_active_last = p_last ;
} /* end of if ( privptr-> p_read_active_first ==NULL) */
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " addexit " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
} /* end of add_claw_reads */
/*-------------------------------------------------------------------*
* ccw_check_return_code *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-02-05 23:18:53 +03:00
static void
2005-04-17 02:20:36 +04:00
ccw_check_return_code ( struct ccw_device * cdev , int return_code )
{
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " ccwret " ) ;
2005-04-17 02:20:36 +04:00
if ( return_code ! = 0 ) {
switch ( return_code ) {
2008-07-18 17:24:56 +04:00
case - EBUSY : /* BUSY is a transient state no action needed */
break ;
case - ENODEV :
2009-01-20 09:14:33 +03:00
dev_err ( & cdev - > dev , " The remote channel adapter is not "
" available \n " ) ;
2008-07-18 17:24:56 +04:00
break ;
case - EINVAL :
2009-01-20 09:14:33 +03:00
dev_err ( & cdev - > dev ,
" The status of the remote channel adapter "
" is not valid \n " ) ;
2008-07-18 17:24:56 +04:00
break ;
default :
2009-01-20 09:14:33 +03:00
dev_err ( & cdev - > dev , " The common device layer "
" returned error code %d \n " ,
return_code ) ;
2008-07-18 17:24:56 +04:00
}
}
CLAW_DBF_TEXT ( 4 , trace , " ccwret " ) ;
2005-04-17 02:20:36 +04:00
} /* end of ccw_check_return_code */
/*-------------------------------------------------------------------*
* ccw_check_unit_check *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2007-02-05 23:18:53 +03:00
static void
2005-04-17 02:20:36 +04:00
ccw_check_unit_check ( struct chbk * p_ch , unsigned char sense )
{
2008-07-18 17:24:56 +04:00
struct net_device * ndev = p_ch - > ndev ;
2009-01-20 09:14:33 +03:00
struct device * dev = & p_ch - > cdev - > dev ;
2005-04-17 02:20:36 +04:00
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " unitchek " ) ;
2009-01-20 09:14:33 +03:00
dev_warn ( dev , " The communication peer of %s disconnected \n " ,
ndev - > name ) ;
2005-04-17 02:20:36 +04:00
2009-03-24 06:27:51 +03:00
if ( sense & 0x40 ) {
if ( sense & 0x01 ) {
2009-01-20 09:14:33 +03:00
dev_warn ( dev , " The remote channel adapter for "
" %s has been reset \n " ,
ndev - > name ) ;
2009-03-24 06:27:51 +03:00
}
} else if ( sense & 0x20 ) {
if ( sense & 0x04 ) {
2009-01-20 09:14:33 +03:00
dev_warn ( dev , " A data streaming timeout occurred "
" for %s \n " ,
ndev - > name ) ;
2009-03-24 06:27:51 +03:00
} else if ( sense & 0x10 ) {
2009-01-20 09:14:33 +03:00
dev_warn ( dev , " The remote channel adapter for %s "
" is faulty \n " ,
ndev - > name ) ;
2009-03-24 06:27:51 +03:00
} else {
dev_warn ( dev , " A data transfer parity error occurred "
2009-01-20 09:14:33 +03:00
" for %s \n " ,
ndev - > name ) ;
2009-03-24 06:27:51 +03:00
}
} else if ( sense & 0x10 ) {
dev_warn ( dev , " A read data parity error occurred "
" for %s \n " ,
ndev - > name ) ;
}
2005-04-17 02:20:36 +04:00
} /* end of ccw_check_unit_check */
/*-------------------------------------------------------------------*
* find_link *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
find_link ( struct net_device * dev , char * host_name , char * ws_name )
{
struct claw_privbk * privptr ;
struct claw_env * p_env ;
int rc = 0 ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " findlink " ) ;
2008-08-21 19:10:23 +04:00
privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
p_env = privptr - > p_env ;
switch ( p_env - > packing )
{
case PACKING_ASK :
if ( ( memcmp ( WS_APPL_NAME_PACKED , host_name , 8 ) ! = 0 ) | |
( memcmp ( WS_APPL_NAME_PACKED , ws_name , 8 ) ! = 0 ) )
rc = EINVAL ;
break ;
case DO_PACKED :
case PACK_SEND :
if ( ( memcmp ( WS_APPL_NAME_IP_NAME , host_name , 8 ) ! = 0 ) | |
( memcmp ( WS_APPL_NAME_IP_NAME , ws_name , 8 ) ! = 0 ) )
rc = EINVAL ;
break ;
default :
if ( ( memcmp ( HOST_APPL_NAME , host_name , 8 ) ! = 0 ) | |
( memcmp ( p_env - > api_type , ws_name , 8 ) ! = 0 ) )
rc = EINVAL ;
break ;
}
2009-03-24 06:27:51 +03:00
return rc ;
2005-04-17 02:20:36 +04:00
} /* end of find_link */
/*-------------------------------------------------------------------*
* claw_hw_tx *
* *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_hw_tx ( struct sk_buff * skb , struct net_device * dev , long linkid )
{
int rc = 0 ;
struct claw_privbk * privptr ;
struct ccwbk * p_this_ccw ;
struct ccwbk * p_first_ccw ;
struct ccwbk * p_last_ccw ;
__u32 numBuffers ;
signed long len_of_data ;
unsigned long bytesInThisBuffer ;
unsigned char * pDataAddress ;
struct endccw * pEnd ;
struct ccw1 tempCCW ;
struct chbk * p_ch ;
struct claw_env * p_env ;
int lock ;
struct clawph * pk_head ;
struct chbk * ch ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " hw_tx " ) ;
2008-08-21 19:10:23 +04:00
privptr = ( struct claw_privbk * ) ( dev - > ml_priv ) ;
2005-04-17 02:20:36 +04:00
p_ch = ( struct chbk * ) & privptr - > channel [ WRITE ] ;
p_env = privptr - > p_env ;
claw_free_wrt_buf ( dev ) ; /* Clean up free chain if posible */
/* scan the write queue to free any completed write packets */
p_first_ccw = NULL ;
p_last_ccw = NULL ;
if ( ( p_env - > packing > = PACK_SEND ) & &
( skb - > cb [ 1 ] ! = ' P ' ) ) {
skb_push ( skb , sizeof ( struct clawph ) ) ;
pk_head = ( struct clawph * ) skb - > data ;
pk_head - > len = skb - > len - sizeof ( struct clawph ) ;
if ( pk_head - > len % 4 ) {
pk_head - > len + = 4 - ( pk_head - > len % 4 ) ;
skb_pad ( skb , 4 - ( pk_head - > len % 4 ) ) ;
skb_put ( skb , 4 - ( pk_head - > len % 4 ) ) ;
}
if ( p_env - > packing = = DO_PACKED )
pk_head - > link_num = linkid ;
else
pk_head - > link_num = 0 ;
pk_head - > flag = 0x00 ;
skb_pad ( skb , 4 ) ;
skb - > cb [ 1 ] = ' P ' ;
}
if ( linkid = = 0 ) {
if ( claw_check_busy ( dev ) ) {
if ( privptr - > write_free_count ! = 0 ) {
claw_clear_busy ( dev ) ;
}
else {
claw_strt_out_IO ( dev ) ;
claw_free_wrt_buf ( dev ) ;
if ( privptr - > write_free_count = = 0 ) {
ch = & privptr - > channel [ WRITE ] ;
atomic_inc ( & skb - > users ) ;
skb_queue_tail ( & ch - > collect_queue , skb ) ;
goto Done ;
}
else {
claw_clear_busy ( dev ) ;
}
}
}
/* tx lock */
if ( claw_test_and_setbit_busy ( TB_TX , dev ) ) { /* set to busy */
ch = & privptr - > channel [ WRITE ] ;
atomic_inc ( & skb - > users ) ;
skb_queue_tail ( & ch - > collect_queue , skb ) ;
claw_strt_out_IO ( dev ) ;
rc = - EBUSY ;
goto Done2 ;
}
}
/* See how many write buffers are required to hold this data */
2008-02-18 16:41:55 +03:00
numBuffers = DIV_ROUND_UP ( skb - > len , privptr - > p_env - > write_size ) ;
2005-04-17 02:20:36 +04:00
/* If that number of buffers isn't available, give up for now */
if ( privptr - > write_free_count < numBuffers | |
privptr - > p_write_free_chain = = NULL ) {
claw_setbit_busy ( TB_NOBUFFER , dev ) ;
ch = & privptr - > channel [ WRITE ] ;
atomic_inc ( & skb - > users ) ;
skb_queue_tail ( & ch - > collect_queue , skb ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " clawbusy " ) ;
2005-04-17 02:20:36 +04:00
goto Done2 ;
}
pDataAddress = skb - > data ;
len_of_data = skb - > len ;
while ( len_of_data > 0 ) {
p_this_ccw = privptr - > p_write_free_chain ; /* get a block */
if ( p_this_ccw = = NULL ) { /* lost the race */
ch = & privptr - > channel [ WRITE ] ;
atomic_inc ( & skb - > users ) ;
skb_queue_tail ( & ch - > collect_queue , skb ) ;
goto Done2 ;
}
privptr - > p_write_free_chain = p_this_ccw - > next ;
p_this_ccw - > next = NULL ;
- - privptr - > write_free_count ; /* -1 */
2009-03-24 06:27:51 +03:00
if ( len_of_data > = privptr - > p_env - > write_size )
bytesInThisBuffer = privptr - > p_env - > write_size ;
else
bytesInThisBuffer = len_of_data ;
2005-04-17 02:20:36 +04:00
memcpy ( p_this_ccw - > p_buffer , pDataAddress , bytesInThisBuffer ) ;
len_of_data - = bytesInThisBuffer ;
pDataAddress + = ( unsigned long ) bytesInThisBuffer ;
/* setup write CCW */
p_this_ccw - > write . cmd_code = ( linkid * 8 ) + 1 ;
if ( len_of_data > 0 ) {
p_this_ccw - > write . cmd_code + = MORE_to_COME_FLAG ;
}
p_this_ccw - > write . count = bytesInThisBuffer ;
/* now add to end of this chain */
if ( p_first_ccw = = NULL ) {
p_first_ccw = p_this_ccw ;
}
if ( p_last_ccw ! = NULL ) {
p_last_ccw - > next = p_this_ccw ;
/* set up TIC ccws */
p_last_ccw - > w_TIC_1 . cda =
( __u32 ) __pa ( & p_this_ccw - > write ) ;
}
p_last_ccw = p_this_ccw ; /* save new last block */
}
/* FirstCCW and LastCCW now contain a new set of write channel
* programs to append to the running channel program
*/
if ( p_first_ccw ! = NULL ) {
2009-01-20 09:14:33 +03:00
/* setup ending ccw sequence for this segment */
2005-04-17 02:20:36 +04:00
pEnd = privptr - > p_end_ccw ;
if ( pEnd - > write1 ) {
pEnd - > write1 = 0x00 ; /* second end ccw is now active */
/* set up Tic CCWs */
p_last_ccw - > w_TIC_1 . cda =
( __u32 ) __pa ( & pEnd - > write2_nop1 ) ;
pEnd - > write2_nop2 . cmd_code = CCW_CLAW_CMD_READFF ;
pEnd - > write2_nop2 . flags =
CCW_FLAG_SLI | CCW_FLAG_SKIP ;
pEnd - > write2_nop2 . cda = 0 ;
pEnd - > write2_nop2 . count = 1 ;
}
else { /* end of if (pEnd->write1)*/
pEnd - > write1 = 0x01 ; /* first end ccw is now active */
/* set up Tic CCWs */
p_last_ccw - > w_TIC_1 . cda =
( __u32 ) __pa ( & pEnd - > write1_nop1 ) ;
pEnd - > write1_nop2 . cmd_code = CCW_CLAW_CMD_READFF ;
pEnd - > write1_nop2 . flags =
CCW_FLAG_SLI | CCW_FLAG_SKIP ;
pEnd - > write1_nop2 . cda = 0 ;
pEnd - > write1_nop2 . count = 1 ;
} /* end if if (pEnd->write1) */
if ( privptr - > p_write_active_first = = NULL ) {
privptr - > p_write_active_first = p_first_ccw ;
privptr - > p_write_active_last = p_last_ccw ;
}
else {
/* set up Tic CCWs */
tempCCW . cda = ( __u32 ) __pa ( & p_first_ccw - > write ) ;
tempCCW . count = 0 ;
tempCCW . flags = 0 ;
tempCCW . cmd_code = CCW_CLAW_CMD_TIC ;
if ( pEnd - > write1 ) {
/*
* first set of ending CCW ' s is chained to the new write
* chain , so the second set is chained to the active chain
* Therefore modify the second set to point the new write chain .
* make sure we update the CCW atomically
* so channel does not fetch it when it ' s only half done
*/
memcpy ( & pEnd - > write2_nop2 , & tempCCW ,
sizeof ( struct ccw1 ) ) ;
privptr - > p_write_active_last - > w_TIC_1 . cda =
( __u32 ) __pa ( & p_first_ccw - > write ) ;
}
else {
/*make sure we update the CCW atomically
* so channel does not fetch it when it ' s only half done
*/
memcpy ( & pEnd - > write1_nop2 , & tempCCW ,
sizeof ( struct ccw1 ) ) ;
privptr - > p_write_active_last - > w_TIC_1 . cda =
( __u32 ) __pa ( & p_first_ccw - > write ) ;
} /* end if if (pEnd->write1) */
privptr - > p_write_active_last - > next = p_first_ccw ;
privptr - > p_write_active_last = p_last_ccw ;
}
} /* endif (p_first_ccw!=NULL) */
2005-09-06 17:03:09 +04:00
dev_kfree_skb_any ( skb ) ;
2005-04-17 02:20:36 +04:00
if ( linkid = = 0 ) {
lock = LOCK_NO ;
}
else {
lock = LOCK_YES ;
}
claw_strt_out_IO ( dev ) ;
/* if write free count is zero , set NOBUFFER */
if ( privptr - > write_free_count = = 0 ) {
claw_setbit_busy ( TB_NOBUFFER , dev ) ;
}
Done2 :
claw_clearbit_busy ( TB_TX , dev ) ;
Done :
return ( rc ) ;
} /* end of claw_hw_tx */
/*-------------------------------------------------------------------*
* *
* init_ccw_bk *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
init_ccw_bk ( struct net_device * dev )
{
__u32 ccw_blocks_required ;
__u32 ccw_blocks_perpage ;
__u32 ccw_pages_required ;
__u32 claw_reads_perpage = 1 ;
__u32 claw_read_pages ;
__u32 claw_writes_perpage = 1 ;
__u32 claw_write_pages ;
void * p_buff = NULL ;
struct ccwbk * p_free_chain ;
struct ccwbk * p_buf ;
struct ccwbk * p_last_CCWB ;
struct ccwbk * p_first_CCWB ;
struct endccw * p_endccw = NULL ;
2008-08-21 19:10:23 +04:00
addr_t real_address ;
struct claw_privbk * privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
struct clawh * pClawH = NULL ;
addr_t real_TIC_address ;
int i , j ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " init_ccw " ) ;
2005-04-17 02:20:36 +04:00
/* initialize statistics field */
privptr - > active_link_ID = 0 ;
/* initialize ccwbk pointers */
privptr - > p_write_free_chain = NULL ; /* pointer to free ccw chain*/
privptr - > p_write_active_first = NULL ; /* pointer to the first write ccw*/
privptr - > p_write_active_last = NULL ; /* pointer to the last write ccw*/
privptr - > p_read_active_first = NULL ; /* pointer to the first read ccw*/
privptr - > p_read_active_last = NULL ; /* pointer to the last read ccw */
privptr - > p_end_ccw = NULL ; /* pointer to ending ccw */
privptr - > p_claw_signal_blk = NULL ; /* pointer to signal block */
privptr - > buffs_alloc = 0 ;
memset ( & privptr - > end_ccw , 0x00 , sizeof ( struct endccw ) ) ;
memset ( & privptr - > ctl_bk , 0x00 , sizeof ( struct clawctl ) ) ;
/* initialize free write ccwbk counter */
privptr - > write_free_count = 0 ; /* number of free bufs on write chain */
p_last_CCWB = NULL ;
p_first_CCWB = NULL ;
/*
* We need 1 CCW block for each read buffer , 1 for each
* write buffer , plus 1 for ClawSignalBlock
*/
ccw_blocks_required =
privptr - > p_env - > read_buffers + privptr - > p_env - > write_buffers + 1 ;
/*
* compute number of CCW blocks that will fit in a page
*/
ccw_blocks_perpage = PAGE_SIZE / CCWBK_SIZE ;
ccw_pages_required =
2008-02-18 16:41:55 +03:00
DIV_ROUND_UP ( ccw_blocks_required , ccw_blocks_perpage ) ;
2005-04-17 02:20:36 +04:00
/*
* read and write sizes are set by 2 constants in claw . h
* 4 k and 32 k . Unpacked values other than 4 k are not going to
* provide good performance . With packing buffers support 32 k
* buffers are used .
*/
2008-02-18 16:41:55 +03:00
if ( privptr - > p_env - > read_size < PAGE_SIZE ) {
claw_reads_perpage = PAGE_SIZE / privptr - > p_env - > read_size ;
claw_read_pages = DIV_ROUND_UP ( privptr - > p_env - > read_buffers ,
claw_reads_perpage ) ;
2005-04-17 02:20:36 +04:00
}
else { /* > or equal */
2008-02-18 16:41:55 +03:00
privptr - > p_buff_pages_perread =
DIV_ROUND_UP ( privptr - > p_env - > read_size , PAGE_SIZE ) ;
claw_read_pages = privptr - > p_env - > read_buffers *
privptr - > p_buff_pages_perread ;
2005-04-17 02:20:36 +04:00
}
if ( privptr - > p_env - > write_size < PAGE_SIZE ) {
2008-02-18 16:41:55 +03:00
claw_writes_perpage =
PAGE_SIZE / privptr - > p_env - > write_size ;
claw_write_pages = DIV_ROUND_UP ( privptr - > p_env - > write_buffers ,
claw_writes_perpage ) ;
2005-04-17 02:20:36 +04:00
}
else { /* > or equal */
2008-02-18 16:41:55 +03:00
privptr - > p_buff_pages_perwrite =
DIV_ROUND_UP ( privptr - > p_env - > read_size , PAGE_SIZE ) ;
claw_write_pages = privptr - > p_env - > write_buffers *
privptr - > p_buff_pages_perwrite ;
2005-04-17 02:20:36 +04:00
}
/*
* allocate ccw_pages_required
*/
if ( privptr - > p_buff_ccw = = NULL ) {
privptr - > p_buff_ccw =
( void * ) __get_free_pages ( __GFP_DMA ,
( int ) pages_to_order_of_mag ( ccw_pages_required ) ) ;
if ( privptr - > p_buff_ccw = = NULL ) {
return - ENOMEM ;
}
privptr - > p_buff_ccw_num = ccw_pages_required ;
}
memset ( privptr - > p_buff_ccw , 0x00 ,
privptr - > p_buff_ccw_num * PAGE_SIZE ) ;
/*
* obtain ending ccw block address
*
*/
privptr - > p_end_ccw = ( struct endccw * ) & privptr - > end_ccw ;
real_address = ( __u32 ) __pa ( privptr - > p_end_ccw ) ;
/* Initialize ending CCW block */
p_endccw = privptr - > p_end_ccw ;
p_endccw - > real = real_address ;
p_endccw - > write1 = 0x00 ;
p_endccw - > read1 = 0x00 ;
/* write1_nop1 */
p_endccw - > write1_nop1 . cmd_code = CCW_CLAW_CMD_NOP ;
p_endccw - > write1_nop1 . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_endccw - > write1_nop1 . count = 1 ;
p_endccw - > write1_nop1 . cda = 0 ;
/* write1_nop2 */
p_endccw - > write1_nop2 . cmd_code = CCW_CLAW_CMD_READFF ;
p_endccw - > write1_nop2 . flags = CCW_FLAG_SLI | CCW_FLAG_SKIP ;
p_endccw - > write1_nop2 . count = 1 ;
p_endccw - > write1_nop2 . cda = 0 ;
/* write2_nop1 */
p_endccw - > write2_nop1 . cmd_code = CCW_CLAW_CMD_NOP ;
p_endccw - > write2_nop1 . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_endccw - > write2_nop1 . count = 1 ;
p_endccw - > write2_nop1 . cda = 0 ;
/* write2_nop2 */
p_endccw - > write2_nop2 . cmd_code = CCW_CLAW_CMD_READFF ;
p_endccw - > write2_nop2 . flags = CCW_FLAG_SLI | CCW_FLAG_SKIP ;
p_endccw - > write2_nop2 . count = 1 ;
p_endccw - > write2_nop2 . cda = 0 ;
/* read1_nop1 */
p_endccw - > read1_nop1 . cmd_code = CCW_CLAW_CMD_NOP ;
p_endccw - > read1_nop1 . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_endccw - > read1_nop1 . count = 1 ;
p_endccw - > read1_nop1 . cda = 0 ;
/* read1_nop2 */
p_endccw - > read1_nop2 . cmd_code = CCW_CLAW_CMD_READFF ;
p_endccw - > read1_nop2 . flags = CCW_FLAG_SLI | CCW_FLAG_SKIP ;
p_endccw - > read1_nop2 . count = 1 ;
p_endccw - > read1_nop2 . cda = 0 ;
/* read2_nop1 */
p_endccw - > read2_nop1 . cmd_code = CCW_CLAW_CMD_NOP ;
p_endccw - > read2_nop1 . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_endccw - > read2_nop1 . count = 1 ;
p_endccw - > read2_nop1 . cda = 0 ;
/* read2_nop2 */
p_endccw - > read2_nop2 . cmd_code = CCW_CLAW_CMD_READFF ;
p_endccw - > read2_nop2 . flags = CCW_FLAG_SLI | CCW_FLAG_SKIP ;
p_endccw - > read2_nop2 . count = 1 ;
p_endccw - > read2_nop2 . cda = 0 ;
/*
* Build a chain of CCWs
*
*/
p_buff = privptr - > p_buff_ccw ;
p_free_chain = NULL ;
for ( i = 0 ; i < ccw_pages_required ; i + + ) {
real_address = ( __u32 ) __pa ( p_buff ) ;
p_buf = p_buff ;
for ( j = 0 ; j < ccw_blocks_perpage ; j + + ) {
p_buf - > next = p_free_chain ;
p_free_chain = p_buf ;
p_buf - > real = ( __u32 ) __pa ( p_buf ) ;
+ + p_buf ;
}
p_buff + = PAGE_SIZE ;
}
/*
* Initialize ClawSignalBlock
*
*/
if ( privptr - > p_claw_signal_blk = = NULL ) {
privptr - > p_claw_signal_blk = p_free_chain ;
p_free_chain = p_free_chain - > next ;
pClawH = ( struct clawh * ) privptr - > p_claw_signal_blk ;
pClawH - > length = 0xffff ;
pClawH - > opcode = 0xff ;
pClawH - > flag = CLAW_BUSY ;
}
/*
* allocate write_pages_required and add to free chain
*/
if ( privptr - > p_buff_write = = NULL ) {
if ( privptr - > p_env - > write_size < PAGE_SIZE ) {
privptr - > p_buff_write =
( void * ) __get_free_pages ( __GFP_DMA ,
( int ) pages_to_order_of_mag ( claw_write_pages ) ) ;
if ( privptr - > p_buff_write = = NULL ) {
privptr - > p_buff_ccw = NULL ;
return - ENOMEM ;
}
/*
* Build CLAW write free chain
*
*/
memset ( privptr - > p_buff_write , 0x00 ,
ccw_pages_required * PAGE_SIZE ) ;
privptr - > p_write_free_chain = NULL ;
p_buff = privptr - > p_buff_write ;
for ( i = 0 ; i < privptr - > p_env - > write_buffers ; i + + ) {
p_buf = p_free_chain ; /* get a CCW */
p_free_chain = p_buf - > next ;
p_buf - > next = privptr - > p_write_free_chain ;
privptr - > p_write_free_chain = p_buf ;
p_buf - > p_buffer = ( struct clawbuf * ) p_buff ;
p_buf - > write . cda = ( __u32 ) __pa ( p_buff ) ;
p_buf - > write . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > w_read_FF . cmd_code = CCW_CLAW_CMD_READFF ;
p_buf - > w_read_FF . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > w_read_FF . count = 1 ;
p_buf - > w_read_FF . cda =
( __u32 ) __pa ( & p_buf - > header . flag ) ;
p_buf - > w_TIC_1 . cmd_code = CCW_CLAW_CMD_TIC ;
p_buf - > w_TIC_1 . flags = 0 ;
p_buf - > w_TIC_1 . count = 0 ;
2009-01-20 09:14:33 +03:00
if ( ( ( unsigned long ) p_buff +
privptr - > p_env - > write_size ) > =
2005-04-17 02:20:36 +04:00
( ( unsigned long ) ( p_buff + 2 *
2009-01-20 09:14:33 +03:00
( privptr - > p_env - > write_size ) - 1 ) & PAGE_MASK ) ) {
p_buff = p_buff + privptr - > p_env - > write_size ;
2005-04-17 02:20:36 +04:00
}
}
}
else /* Buffers are => PAGE_SIZE. 1 buff per get_free_pages */
{
privptr - > p_write_free_chain = NULL ;
for ( i = 0 ; i < privptr - > p_env - > write_buffers ; i + + ) {
p_buff = ( void * ) __get_free_pages ( __GFP_DMA ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_pages_perwrite ) ) ;
if ( p_buff = = NULL ) {
free_pages ( ( unsigned long ) privptr - > p_buff_ccw ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_ccw_num ) ) ;
privptr - > p_buff_ccw = NULL ;
p_buf = privptr - > p_buff_write ;
while ( p_buf ! = NULL ) {
free_pages ( ( unsigned long )
p_buf - > p_buffer ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_pages_perwrite ) ) ;
p_buf = p_buf - > next ;
}
return - ENOMEM ;
} /* Error on get_pages */
memset ( p_buff , 0x00 , privptr - > p_env - > write_size ) ;
p_buf = p_free_chain ;
p_free_chain = p_buf - > next ;
p_buf - > next = privptr - > p_write_free_chain ;
privptr - > p_write_free_chain = p_buf ;
privptr - > p_buff_write = p_buf ;
p_buf - > p_buffer = ( struct clawbuf * ) p_buff ;
p_buf - > write . cda = ( __u32 ) __pa ( p_buff ) ;
p_buf - > write . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > w_read_FF . cmd_code = CCW_CLAW_CMD_READFF ;
p_buf - > w_read_FF . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > w_read_FF . count = 1 ;
p_buf - > w_read_FF . cda =
( __u32 ) __pa ( & p_buf - > header . flag ) ;
p_buf - > w_TIC_1 . cmd_code = CCW_CLAW_CMD_TIC ;
p_buf - > w_TIC_1 . flags = 0 ;
p_buf - > w_TIC_1 . count = 0 ;
} /* for all write_buffers */
} /* else buffers are PAGE_SIZE or bigger */
}
privptr - > p_buff_write_num = claw_write_pages ;
privptr - > write_free_count = privptr - > p_env - > write_buffers ;
/*
* allocate read_pages_required and chain to free chain
*/
if ( privptr - > p_buff_read = = NULL ) {
if ( privptr - > p_env - > read_size < PAGE_SIZE ) {
privptr - > p_buff_read =
( void * ) __get_free_pages ( __GFP_DMA ,
( int ) pages_to_order_of_mag ( claw_read_pages ) ) ;
if ( privptr - > p_buff_read = = NULL ) {
free_pages ( ( unsigned long ) privptr - > p_buff_ccw ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_ccw_num ) ) ;
/* free the write pages size is < page size */
free_pages ( ( unsigned long ) privptr - > p_buff_write ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_write_num ) ) ;
privptr - > p_buff_ccw = NULL ;
privptr - > p_buff_write = NULL ;
return - ENOMEM ;
}
memset ( privptr - > p_buff_read , 0x00 , claw_read_pages * PAGE_SIZE ) ;
privptr - > p_buff_read_num = claw_read_pages ;
/*
* Build CLAW read free chain
*
*/
p_buff = privptr - > p_buff_read ;
for ( i = 0 ; i < privptr - > p_env - > read_buffers ; i + + ) {
p_buf = p_free_chain ;
p_free_chain = p_buf - > next ;
if ( p_last_CCWB = = NULL ) {
p_buf - > next = NULL ;
real_TIC_address = 0 ;
p_last_CCWB = p_buf ;
}
else {
p_buf - > next = p_first_CCWB ;
real_TIC_address =
( __u32 ) __pa ( & p_first_CCWB - > read ) ;
}
p_first_CCWB = p_buf ;
p_buf - > p_buffer = ( struct clawbuf * ) p_buff ;
/* initialize read command */
p_buf - > read . cmd_code = CCW_CLAW_CMD_READ ;
p_buf - > read . cda = ( __u32 ) __pa ( p_buff ) ;
p_buf - > read . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > read . count = privptr - > p_env - > read_size ;
/* initialize read_h command */
p_buf - > read_h . cmd_code = CCW_CLAW_CMD_READHEADER ;
p_buf - > read_h . cda =
( __u32 ) __pa ( & ( p_buf - > header ) ) ;
p_buf - > read_h . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > read_h . count = sizeof ( struct clawh ) ;
/* initialize Signal command */
p_buf - > signal . cmd_code = CCW_CLAW_CMD_SIGNAL_SMOD ;
p_buf - > signal . cda =
( __u32 ) __pa ( & ( pClawH - > flag ) ) ;
p_buf - > signal . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > signal . count = 1 ;
/* initialize r_TIC_1 command */
p_buf - > r_TIC_1 . cmd_code = CCW_CLAW_CMD_TIC ;
p_buf - > r_TIC_1 . cda = ( __u32 ) real_TIC_address ;
p_buf - > r_TIC_1 . flags = 0 ;
p_buf - > r_TIC_1 . count = 0 ;
/* initialize r_read_FF command */
p_buf - > r_read_FF . cmd_code = CCW_CLAW_CMD_READFF ;
p_buf - > r_read_FF . cda =
( __u32 ) __pa ( & ( pClawH - > flag ) ) ;
p_buf - > r_read_FF . flags =
CCW_FLAG_SLI | CCW_FLAG_CC | CCW_FLAG_PCI ;
p_buf - > r_read_FF . count = 1 ;
/* initialize r_TIC_2 */
memcpy ( & p_buf - > r_TIC_2 ,
& p_buf - > r_TIC_1 , sizeof ( struct ccw1 ) ) ;
/* initialize Header */
p_buf - > header . length = 0xffff ;
p_buf - > header . opcode = 0xff ;
p_buf - > header . flag = CLAW_PENDING ;
2009-01-20 09:14:33 +03:00
if ( ( ( unsigned long ) p_buff + privptr - > p_env - > read_size ) > =
( ( unsigned long ) ( p_buff + 2 * ( privptr - > p_env - > read_size )
- 1 )
& PAGE_MASK ) ) {
2005-04-17 02:20:36 +04:00
p_buff = p_buff + privptr - > p_env - > read_size ;
}
else {
p_buff =
( void * ) ( ( unsigned long )
2009-01-20 09:14:33 +03:00
( p_buff + 2 * ( privptr - > p_env - > read_size ) - 1 )
2005-04-17 02:20:36 +04:00
& PAGE_MASK ) ;
}
} /* for read_buffers */
} /* read_size < PAGE_SIZE */
else { /* read Size >= PAGE_SIZE */
for ( i = 0 ; i < privptr - > p_env - > read_buffers ; i + + ) {
p_buff = ( void * ) __get_free_pages ( __GFP_DMA ,
2009-01-20 09:14:33 +03:00
( int ) pages_to_order_of_mag (
privptr - > p_buff_pages_perread ) ) ;
2005-04-17 02:20:36 +04:00
if ( p_buff = = NULL ) {
free_pages ( ( unsigned long ) privptr - > p_buff_ccw ,
2009-01-20 09:14:33 +03:00
( int ) pages_to_order_of_mag ( privptr - >
p_buff_ccw_num ) ) ;
2005-04-17 02:20:36 +04:00
/* free the write pages */
p_buf = privptr - > p_buff_write ;
while ( p_buf ! = NULL ) {
2009-01-20 09:14:33 +03:00
free_pages (
( unsigned long ) p_buf - > p_buffer ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_pages_perwrite ) ) ;
2005-04-17 02:20:36 +04:00
p_buf = p_buf - > next ;
}
/* free any read pages already alloc */
p_buf = privptr - > p_buff_read ;
while ( p_buf ! = NULL ) {
2009-01-20 09:14:33 +03:00
free_pages (
( unsigned long ) p_buf - > p_buffer ,
( int ) pages_to_order_of_mag (
privptr - > p_buff_pages_perread ) ) ;
2005-04-17 02:20:36 +04:00
p_buf = p_buf - > next ;
}
privptr - > p_buff_ccw = NULL ;
privptr - > p_buff_write = NULL ;
return - ENOMEM ;
}
memset ( p_buff , 0x00 , privptr - > p_env - > read_size ) ;
p_buf = p_free_chain ;
privptr - > p_buff_read = p_buf ;
p_free_chain = p_buf - > next ;
if ( p_last_CCWB = = NULL ) {
p_buf - > next = NULL ;
real_TIC_address = 0 ;
p_last_CCWB = p_buf ;
}
else {
p_buf - > next = p_first_CCWB ;
real_TIC_address =
( addr_t ) __pa (
& p_first_CCWB - > read ) ;
}
p_first_CCWB = p_buf ;
/* save buff address */
p_buf - > p_buffer = ( struct clawbuf * ) p_buff ;
/* initialize read command */
p_buf - > read . cmd_code = CCW_CLAW_CMD_READ ;
p_buf - > read . cda = ( __u32 ) __pa ( p_buff ) ;
p_buf - > read . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > read . count = privptr - > p_env - > read_size ;
/* initialize read_h command */
p_buf - > read_h . cmd_code = CCW_CLAW_CMD_READHEADER ;
p_buf - > read_h . cda =
( __u32 ) __pa ( & ( p_buf - > header ) ) ;
p_buf - > read_h . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > read_h . count = sizeof ( struct clawh ) ;
/* initialize Signal command */
p_buf - > signal . cmd_code = CCW_CLAW_CMD_SIGNAL_SMOD ;
p_buf - > signal . cda =
( __u32 ) __pa ( & ( pClawH - > flag ) ) ;
p_buf - > signal . flags = CCW_FLAG_SLI | CCW_FLAG_CC ;
p_buf - > signal . count = 1 ;
/* initialize r_TIC_1 command */
p_buf - > r_TIC_1 . cmd_code = CCW_CLAW_CMD_TIC ;
p_buf - > r_TIC_1 . cda = ( __u32 ) real_TIC_address ;
p_buf - > r_TIC_1 . flags = 0 ;
p_buf - > r_TIC_1 . count = 0 ;
/* initialize r_read_FF command */
p_buf - > r_read_FF . cmd_code = CCW_CLAW_CMD_READFF ;
p_buf - > r_read_FF . cda =
( __u32 ) __pa ( & ( pClawH - > flag ) ) ;
p_buf - > r_read_FF . flags =
CCW_FLAG_SLI | CCW_FLAG_CC | CCW_FLAG_PCI ;
p_buf - > r_read_FF . count = 1 ;
/* initialize r_TIC_2 */
memcpy ( & p_buf - > r_TIC_2 , & p_buf - > r_TIC_1 ,
sizeof ( struct ccw1 ) ) ;
/* initialize Header */
p_buf - > header . length = 0xffff ;
p_buf - > header . opcode = 0xff ;
p_buf - > header . flag = CLAW_PENDING ;
} /* For read_buffers */
} /* read_size >= PAGE_SIZE */
} /* pBuffread = NULL */
add_claw_reads ( dev , p_first_CCWB , p_last_CCWB ) ;
privptr - > buffs_alloc = 1 ;
2008-07-18 17:24:56 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
} /* end of init_ccw_bk */
/*-------------------------------------------------------------------*
* *
* probe_error *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
probe_error ( struct ccwgroup_device * cgdev )
{
2008-08-21 19:10:22 +04:00
struct claw_privbk * privptr ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " proberr " ) ;
2009-05-04 23:40:54 +04:00
privptr = dev_get_drvdata ( & cgdev - > dev ) ;
2008-08-21 19:10:22 +04:00
if ( privptr ! = NULL ) {
2009-05-04 23:40:54 +04:00
dev_set_drvdata ( & cgdev - > dev , NULL ) ;
2005-11-07 12:01:30 +03:00
kfree ( privptr - > p_env ) ;
2008-08-21 19:10:22 +04:00
kfree ( privptr - > p_mtc_envelope ) ;
kfree ( privptr ) ;
}
2005-04-17 02:20:36 +04:00
} /* probe_error */
/*-------------------------------------------------------------------*
* claw_process_control *
* *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_process_control ( struct net_device * dev , struct ccwbk * p_ccw )
{
struct clawbuf * p_buf ;
struct clawctl ctlbk ;
struct clawctl * p_ctlbk ;
char temp_host_name [ 8 ] ;
char temp_ws_name [ 8 ] ;
struct claw_privbk * privptr ;
struct claw_env * p_env ;
struct sysval * p_sysval ;
struct conncmd * p_connect = NULL ;
int rc ;
struct chbk * p_ch = NULL ;
2008-07-18 17:24:56 +04:00
struct device * tdev ;
CLAW_DBF_TEXT ( 2 , setup , " clw_cntl " ) ;
2005-04-17 02:20:36 +04:00
udelay ( 1000 ) ; /* Wait a ms for the control packets to
* catch up to each other */
2008-08-21 19:10:23 +04:00
privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
p_env = privptr - > p_env ;
2008-07-18 17:24:56 +04:00
tdev = & privptr - > channel [ READ ] . cdev - > dev ;
2005-04-17 02:20:36 +04:00
memcpy ( & temp_host_name , p_env - > host_name , 8 ) ;
memcpy ( & temp_ws_name , p_env - > adapter_name , 8 ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s: CLAW device %.8s: "
2005-04-17 02:20:36 +04:00
" Received Control Packet \n " ,
dev - > name , temp_ws_name ) ;
if ( privptr - > release_pend = = 1 ) {
return 0 ;
}
p_buf = p_ccw - > p_buffer ;
p_ctlbk = & ctlbk ;
if ( p_env - > packing = = DO_PACKED ) { /* packing in progress?*/
memcpy ( p_ctlbk , & p_buf - > buffer [ 4 ] , sizeof ( struct clawctl ) ) ;
} else {
memcpy ( p_ctlbk , p_buf , sizeof ( struct clawctl ) ) ;
}
switch ( p_ctlbk - > command )
{
2008-07-18 17:24:56 +04:00
case SYSTEM_VALIDATE_REQUEST :
if ( p_ctlbk - > version ! = CLAW_VERSION_ID ) {
claw_snd_sys_validate_rsp ( dev , p_ctlbk ,
CLAW_RC_WRONG_VERSION ) ;
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " The communication peer of %s "
" uses an incorrect API version %d \n " ,
dev - > name , p_ctlbk - > version ) ;
2008-07-18 17:24:56 +04:00
}
p_sysval = ( struct sysval * ) & ( p_ctlbk - > data ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s: Recv Sys Validate Request: "
" Vers=%d,link_id=%d,Corr=%d,WS name=%.8s, "
" Host name=%.8s \n " ,
dev - > name , p_ctlbk - > version ,
p_ctlbk - > linkid ,
p_ctlbk - > correlator ,
p_sysval - > WS_name ,
p_sysval - > host_name ) ;
2008-07-18 17:24:56 +04:00
if ( memcmp ( temp_host_name , p_sysval - > host_name , 8 ) ) {
claw_snd_sys_validate_rsp ( dev , p_ctlbk ,
CLAW_RC_NAME_MISMATCH ) ;
CLAW_DBF_TEXT ( 2 , setup , " HSTBAD " ) ;
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , p_sysval - > host_name ) ;
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , temp_host_name ) ;
2009-01-20 09:14:33 +03:00
dev_warn ( tdev ,
" Host name %s for %s does not match the "
" remote adapter name %s \n " ,
2008-07-18 17:24:56 +04:00
p_sysval - > host_name ,
2009-01-20 09:14:33 +03:00
dev - > name ,
2008-07-18 17:24:56 +04:00
temp_host_name ) ;
}
if ( memcmp ( temp_ws_name , p_sysval - > WS_name , 8 ) ) {
claw_snd_sys_validate_rsp ( dev , p_ctlbk ,
CLAW_RC_NAME_MISMATCH ) ;
CLAW_DBF_TEXT ( 2 , setup , " WSNBAD " ) ;
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , p_sysval - > WS_name ) ;
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , temp_ws_name ) ;
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " Adapter name %s for %s does not match "
" the remote host name %s \n " ,
p_sysval - > WS_name ,
dev - > name ,
temp_ws_name ) ;
2008-07-18 17:24:56 +04:00
}
if ( ( p_sysval - > write_frame_size < p_env - > write_size ) & &
( p_env - > packing = = 0 ) ) {
claw_snd_sys_validate_rsp ( dev , p_ctlbk ,
CLAW_RC_HOST_RCV_TOO_SMALL ) ;
2009-01-20 09:14:33 +03:00
dev_warn ( tdev ,
" The local write buffer is smaller than the "
" remote read buffer \n " ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " wrtszbad " ) ;
}
if ( ( p_sysval - > read_frame_size < p_env - > read_size ) & &
( p_env - > packing = = 0 ) ) {
claw_snd_sys_validate_rsp ( dev , p_ctlbk ,
CLAW_RC_HOST_RCV_TOO_SMALL ) ;
2009-01-20 09:14:33 +03:00
dev_warn ( tdev ,
" The local read buffer is smaller than the "
" remote write buffer \n " ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " rdsizbad " ) ;
}
claw_snd_sys_validate_rsp ( dev , p_ctlbk , 0 ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev ,
" CLAW device %.8s: System validate "
" completed. \n " , temp_ws_name ) ;
dev_info ( tdev ,
" %s: sys Validate Rsize:%d Wsize:%d \n " ,
dev - > name , p_sysval - > read_frame_size ,
p_sysval - > write_frame_size ) ;
2008-07-18 17:24:56 +04:00
privptr - > system_validate_comp = 1 ;
if ( strncmp ( p_env - > api_type , WS_APPL_NAME_PACKED , 6 ) = = 0 )
p_env - > packing = PACKING_ASK ;
claw_strt_conn_req ( dev ) ;
break ;
case SYSTEM_VALIDATE_RESPONSE :
p_sysval = ( struct sysval * ) & ( p_ctlbk - > data ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev ,
" Settings for %s validated (version=%d, "
" remote device=%d, rc=%d, adapter name=%.8s, "
" host name=%.8s) \n " ,
2008-07-18 17:24:56 +04:00
dev - > name ,
p_ctlbk - > version ,
p_ctlbk - > correlator ,
p_ctlbk - > rc ,
p_sysval - > WS_name ,
p_sysval - > host_name ) ;
switch ( p_ctlbk - > rc ) {
case 0 :
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s: CLAW device "
" %.8s: System validate completed. \n " ,
dev - > name , temp_ws_name ) ;
2008-07-18 17:24:56 +04:00
if ( privptr - > system_validate_comp = = 0 )
claw_strt_conn_req ( dev ) ;
privptr - > system_validate_comp = 1 ;
break ;
case CLAW_RC_NAME_MISMATCH :
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " Validating %s failed because of "
" a host or adapter name mismatch \n " ,
dev - > name ) ;
2008-07-18 17:24:56 +04:00
break ;
case CLAW_RC_WRONG_VERSION :
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " Validating %s failed because of a "
" version conflict \n " ,
2008-07-18 17:24:56 +04:00
dev - > name ) ;
break ;
case CLAW_RC_HOST_RCV_TOO_SMALL :
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " Validating %s failed because of a "
" frame size conflict \n " ,
2008-07-18 17:24:56 +04:00
dev - > name ) ;
break ;
default :
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " The communication peer of %s rejected "
" the connection \n " ,
dev - > name ) ;
2008-07-18 17:24:56 +04:00
break ;
}
break ;
2005-04-17 02:20:36 +04:00
2008-07-18 17:24:56 +04:00
case CONNECTION_REQUEST :
p_connect = ( struct conncmd * ) & ( p_ctlbk - > data ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s: Recv Conn Req: Vers=%d,link_id=%d, "
2008-07-18 17:24:56 +04:00
" Corr=%d,HOST appl=%.8s,WS appl=%.8s \n " ,
dev - > name ,
p_ctlbk - > version ,
p_ctlbk - > linkid ,
p_ctlbk - > correlator ,
p_connect - > host_name ,
p_connect - > WS_name ) ;
if ( privptr - > active_link_ID ! = 0 ) {
claw_snd_disc ( dev , p_ctlbk ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s rejected a connection request "
" because it is already active \n " ,
2008-07-18 17:24:56 +04:00
dev - > name ) ;
}
if ( p_ctlbk - > linkid ! = 1 ) {
claw_snd_disc ( dev , p_ctlbk ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s rejected a request to open multiple "
" connections \n " ,
2008-07-18 17:24:56 +04:00
dev - > name ) ;
}
rc = find_link ( dev , p_connect - > host_name , p_connect - > WS_name ) ;
if ( rc ! = 0 ) {
claw_snd_disc ( dev , p_ctlbk ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s rejected a connection request "
" because of a type mismatch \n " ,
2008-07-18 17:24:56 +04:00
dev - > name ) ;
}
claw_send_control ( dev ,
CONNECTION_CONFIRM , p_ctlbk - > linkid ,
p_ctlbk - > correlator ,
0 , p_connect - > host_name ,
p_connect - > WS_name ) ;
if ( p_env - > packing = = PACKING_ASK ) {
p_env - > packing = PACK_SEND ;
claw_snd_conn_req ( dev , 0 ) ;
}
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s: CLAW device %.8s: Connection "
2008-07-18 17:24:56 +04:00
" completed link_id=%d. \n " ,
dev - > name , temp_ws_name ,
p_ctlbk - > linkid ) ;
privptr - > active_link_ID = p_ctlbk - > linkid ;
p_ch = & privptr - > channel [ WRITE ] ;
wake_up ( & p_ch - > wait ) ; /* wake up claw_open ( WRITE) */
break ;
case CONNECTION_RESPONSE :
p_connect = ( struct conncmd * ) & ( p_ctlbk - > data ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s: Recv Conn Resp: Vers=%d,link_id=%d, "
2008-07-18 17:24:56 +04:00
" Corr=%d,RC=%d,Host appl=%.8s, WS appl=%.8s \n " ,
dev - > name ,
p_ctlbk - > version ,
p_ctlbk - > linkid ,
p_ctlbk - > correlator ,
p_ctlbk - > rc ,
p_connect - > host_name ,
p_connect - > WS_name ) ;
if ( p_ctlbk - > rc ! = 0 ) {
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " The communication peer of %s rejected "
" a connection request \n " ,
dev - > name ) ;
2008-07-18 17:24:56 +04:00
return 1 ;
}
rc = find_link ( dev ,
p_connect - > host_name , p_connect - > WS_name ) ;
if ( rc ! = 0 ) {
claw_snd_disc ( dev , p_ctlbk ) ;
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " The communication peer of %s "
" rejected a connection "
" request because of a type mismatch \n " ,
2008-07-18 17:24:56 +04:00
dev - > name ) ;
}
/* should be until CONNECTION_CONFIRM */
privptr - > active_link_ID = - ( p_ctlbk - > linkid ) ;
break ;
case CONNECTION_CONFIRM :
p_connect = ( struct conncmd * ) & ( p_ctlbk - > data ) ;
2009-01-20 09:14:33 +03:00
dev_info ( tdev ,
" %s: Recv Conn Confirm:Vers=%d,link_id=%d, "
2008-07-18 17:24:56 +04:00
" Corr=%d,Host appl=%.8s,WS appl=%.8s \n " ,
dev - > name ,
p_ctlbk - > version ,
p_ctlbk - > linkid ,
p_ctlbk - > correlator ,
p_connect - > host_name ,
p_connect - > WS_name ) ;
if ( p_ctlbk - > linkid = = - ( privptr - > active_link_ID ) ) {
privptr - > active_link_ID = p_ctlbk - > linkid ;
if ( p_env - > packing > PACKING_ASK ) {
2009-01-20 09:14:33 +03:00
dev_info ( tdev ,
" %s: Confirmed Now packing \n " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
p_env - > packing = DO_PACKED ;
}
2008-07-18 17:24:56 +04:00
p_ch = & privptr - > channel [ WRITE ] ;
wake_up ( & p_ch - > wait ) ;
} else {
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " Activating %s failed because of "
" an incorrect link ID=%d \n " ,
2008-07-18 17:24:56 +04:00
dev - > name , p_ctlbk - > linkid ) ;
claw_snd_disc ( dev , p_ctlbk ) ;
}
break ;
case DISCONNECT :
2009-01-20 09:14:33 +03:00
dev_info ( tdev , " %s: Disconnect: "
2008-07-18 17:24:56 +04:00
" Vers=%d,link_id=%d,Corr=%d \n " ,
dev - > name , p_ctlbk - > version ,
p_ctlbk - > linkid , p_ctlbk - > correlator ) ;
if ( ( p_ctlbk - > linkid = = 2 ) & &
( p_env - > packing = = PACK_SEND ) ) {
privptr - > active_link_ID = 1 ;
p_env - > packing = DO_PACKED ;
} else
privptr - > active_link_ID = 0 ;
break ;
case CLAW_ERROR :
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " The communication peer of %s failed \n " ,
2008-07-18 17:24:56 +04:00
dev - > name ) ;
break ;
default :
2009-01-20 09:14:33 +03:00
dev_warn ( tdev , " The communication peer of %s sent "
" an unknown command code \n " ,
dev - > name ) ;
2008-07-18 17:24:56 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
} /* end of claw_process_control */
/*-------------------------------------------------------------------*
* claw_send_control *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_send_control ( struct net_device * dev , __u8 type , __u8 link ,
__u8 correlator , __u8 rc , char * local_name , char * remote_name )
{
struct claw_privbk * privptr ;
struct clawctl * p_ctl ;
struct sysval * p_sysval ;
struct conncmd * p_connect ;
struct sk_buff * skb ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " sndcntl " ) ;
2008-08-21 19:10:23 +04:00
privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
p_ctl = ( struct clawctl * ) & privptr - > ctl_bk ;
p_ctl - > command = type ;
p_ctl - > version = CLAW_VERSION_ID ;
p_ctl - > linkid = link ;
p_ctl - > correlator = correlator ;
p_ctl - > rc = rc ;
p_sysval = ( struct sysval * ) & p_ctl - > data ;
p_connect = ( struct conncmd * ) & p_ctl - > data ;
switch ( p_ctl - > command ) {
case SYSTEM_VALIDATE_REQUEST :
case SYSTEM_VALIDATE_RESPONSE :
memcpy ( & p_sysval - > host_name , local_name , 8 ) ;
memcpy ( & p_sysval - > WS_name , remote_name , 8 ) ;
if ( privptr - > p_env - > packing > 0 ) {
2009-01-20 09:14:33 +03:00
p_sysval - > read_frame_size = DEF_PACK_BUFSIZE ;
p_sysval - > write_frame_size = DEF_PACK_BUFSIZE ;
2005-04-17 02:20:36 +04:00
} else {
2008-07-18 17:24:56 +04:00
/* how big is the biggest group of packets */
2009-01-20 09:14:33 +03:00
p_sysval - > read_frame_size =
privptr - > p_env - > read_size ;
p_sysval - > write_frame_size =
privptr - > p_env - > write_size ;
2005-04-17 02:20:36 +04:00
}
memset ( & p_sysval - > reserved , 0x00 , 4 ) ;
break ;
case CONNECTION_REQUEST :
case CONNECTION_RESPONSE :
case CONNECTION_CONFIRM :
case DISCONNECT :
memcpy ( & p_sysval - > host_name , local_name , 8 ) ;
memcpy ( & p_sysval - > WS_name , remote_name , 8 ) ;
if ( privptr - > p_env - > packing > 0 ) {
/* How big is the biggest packet */
p_connect - > reserved1 [ 0 ] = CLAW_FRAME_SIZE ;
p_connect - > reserved1 [ 1 ] = CLAW_FRAME_SIZE ;
} else {
memset ( & p_connect - > reserved1 , 0x00 , 4 ) ;
memset ( & p_connect - > reserved2 , 0x00 , 4 ) ;
}
break ;
default :
break ;
}
/* write Control Record to the device */
skb = dev_alloc_skb ( sizeof ( struct clawctl ) ) ;
if ( ! skb ) {
return - ENOMEM ;
}
memcpy ( skb_put ( skb , sizeof ( struct clawctl ) ) ,
p_ctl , sizeof ( struct clawctl ) ) ;
if ( privptr - > p_env - > packing > = PACK_SEND )
claw_hw_tx ( skb , dev , 1 ) ;
else
claw_hw_tx ( skb , dev , 0 ) ;
return 0 ;
} /* end of claw_send_control */
/*-------------------------------------------------------------------*
* claw_snd_conn_req *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_snd_conn_req ( struct net_device * dev , __u8 link )
{
int rc ;
2008-08-21 19:10:23 +04:00
struct claw_privbk * privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
struct clawctl * p_ctl ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " snd_conn " ) ;
2005-04-17 02:20:36 +04:00
rc = 1 ;
p_ctl = ( struct clawctl * ) & privptr - > ctl_bk ;
p_ctl - > linkid = link ;
if ( privptr - > system_validate_comp = = 0x00 ) {
return rc ;
}
if ( privptr - > p_env - > packing = = PACKING_ASK )
rc = claw_send_control ( dev , CONNECTION_REQUEST , 0 , 0 , 0 ,
WS_APPL_NAME_PACKED , WS_APPL_NAME_PACKED ) ;
if ( privptr - > p_env - > packing = = PACK_SEND ) {
rc = claw_send_control ( dev , CONNECTION_REQUEST , 0 , 0 , 0 ,
WS_APPL_NAME_IP_NAME , WS_APPL_NAME_IP_NAME ) ;
}
if ( privptr - > p_env - > packing = = 0 )
rc = claw_send_control ( dev , CONNECTION_REQUEST , 0 , 0 , 0 ,
HOST_APPL_NAME , privptr - > p_env - > api_type ) ;
return rc ;
} /* end of claw_snd_conn_req */
/*-------------------------------------------------------------------*
* claw_snd_disc *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_snd_disc ( struct net_device * dev , struct clawctl * p_ctl )
{
int rc ;
struct conncmd * p_connect ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " snd_dsc " ) ;
2005-04-17 02:20:36 +04:00
p_connect = ( struct conncmd * ) & p_ctl - > data ;
rc = claw_send_control ( dev , DISCONNECT , p_ctl - > linkid ,
p_ctl - > correlator , 0 ,
p_connect - > host_name , p_connect - > WS_name ) ;
return rc ;
} /* end of claw_snd_disc */
/*-------------------------------------------------------------------*
* claw_snd_sys_validate_rsp *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_snd_sys_validate_rsp ( struct net_device * dev ,
struct clawctl * p_ctl , __u32 return_code )
{
struct claw_env * p_env ;
struct claw_privbk * privptr ;
int rc ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " chkresp " ) ;
2008-08-21 19:10:23 +04:00
privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
p_env = privptr - > p_env ;
rc = claw_send_control ( dev , SYSTEM_VALIDATE_RESPONSE ,
p_ctl - > linkid ,
p_ctl - > correlator ,
return_code ,
p_env - > host_name ,
p_env - > adapter_name ) ;
return rc ;
} /* end of claw_snd_sys_validate_rsp */
/*-------------------------------------------------------------------*
* claw_strt_conn_req *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int
claw_strt_conn_req ( struct net_device * dev )
{
int rc ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " conn_req " ) ;
2005-04-17 02:20:36 +04:00
rc = claw_snd_conn_req ( dev , 1 ) ;
return rc ;
} /* end of claw_strt_conn_req */
/*-------------------------------------------------------------------*
* claw_stats *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static struct
net_device_stats * claw_stats ( struct net_device * dev )
{
struct claw_privbk * privptr ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " stats " ) ;
2008-08-21 19:10:23 +04:00
privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
return & privptr - > stats ;
} /* end of claw_stats */
/*-------------------------------------------------------------------*
* unpack_read *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
unpack_read ( struct net_device * dev )
{
struct sk_buff * skb ;
struct claw_privbk * privptr ;
struct claw_env * p_env ;
struct ccwbk * p_this_ccw ;
struct ccwbk * p_first_ccw ;
struct ccwbk * p_last_ccw ;
struct clawph * p_packh ;
void * p_packd ;
struct clawctl * p_ctlrec = NULL ;
2008-07-18 17:24:56 +04:00
struct device * p_dev ;
2005-04-17 02:20:36 +04:00
__u32 len_of_data ;
__u32 pack_off ;
__u8 link_num ;
__u8 mtc_this_frm = 0 ;
__u32 bytes_to_mov ;
int i = 0 ;
int p = 0 ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " unpkread " ) ;
2005-04-17 02:20:36 +04:00
p_first_ccw = NULL ;
p_last_ccw = NULL ;
p_packh = NULL ;
p_packd = NULL ;
2008-08-21 19:10:23 +04:00
privptr = dev - > ml_priv ;
2008-07-18 17:24:56 +04:00
p_dev = & privptr - > channel [ READ ] . cdev - > dev ;
2005-04-17 02:20:36 +04:00
p_env = privptr - > p_env ;
p_this_ccw = privptr - > p_read_active_first ;
while ( p_this_ccw ! = NULL & & p_this_ccw - > header . flag ! = CLAW_PENDING ) {
pack_off = 0 ;
p = 0 ;
p_this_ccw - > header . flag = CLAW_PENDING ;
privptr - > p_read_active_first = p_this_ccw - > next ;
p_this_ccw - > next = NULL ;
p_packh = ( struct clawph * ) p_this_ccw - > p_buffer ;
if ( ( p_env - > packing = = PACK_SEND ) & &
( p_packh - > len = = 32 ) & &
( p_packh - > link_num = = 0 ) ) { /* is it a packed ctl rec? */
p_packh + + ; /* peek past pack header */
p_ctlrec = ( struct clawctl * ) p_packh ;
p_packh - - ; /* un peek */
if ( ( p_ctlrec - > command = = CONNECTION_RESPONSE ) | |
( p_ctlrec - > command = = CONNECTION_CONFIRM ) )
p_env - > packing = DO_PACKED ;
}
if ( p_env - > packing = = DO_PACKED )
link_num = p_packh - > link_num ;
else
link_num = p_this_ccw - > header . opcode / 8 ;
if ( ( p_this_ccw - > header . opcode & MORE_to_COME_FLAG ) ! = 0 ) {
mtc_this_frm = 1 ;
if ( p_this_ccw - > header . length ! =
privptr - > p_env - > read_size ) {
2009-01-20 09:14:33 +03:00
dev_warn ( p_dev ,
" The communication peer of %s "
" sent a faulty "
" frame of length %02x \n " ,
2005-04-17 02:20:36 +04:00
dev - > name , p_this_ccw - > header . length ) ;
}
}
if ( privptr - > mtc_skipping ) {
/*
* We ' re in the mode of skipping past a
* multi - frame message
* that we can ' t process for some reason or other .
* The first frame without the More - To - Come flag is
* the last frame of the skipped message .
*/
/* in case of More-To-Come not set in this frame */
if ( mtc_this_frm = = 0 ) {
privptr - > mtc_skipping = 0 ; /* Ok, the end */
privptr - > mtc_logical_link = - 1 ;
}
goto NextFrame ;
}
if ( link_num = = 0 ) {
claw_process_control ( dev , p_this_ccw ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " UnpkCntl " ) ;
2005-04-17 02:20:36 +04:00
goto NextFrame ;
}
unpack_next :
if ( p_env - > packing = = DO_PACKED ) {
if ( pack_off > p_env - > read_size )
goto NextFrame ;
p_packd = p_this_ccw - > p_buffer + pack_off ;
p_packh = ( struct clawph * ) p_packd ;
2009-01-20 09:14:33 +03:00
if ( ( p_packh - > len = = 0 ) | | /* done with this frame? */
2005-04-17 02:20:36 +04:00
( p_packh - > flag ! = 0 ) )
goto NextFrame ;
bytes_to_mov = p_packh - > len ;
pack_off + = bytes_to_mov + sizeof ( struct clawph ) ;
p + + ;
} else {
bytes_to_mov = p_this_ccw - > header . length ;
}
if ( privptr - > mtc_logical_link < 0 ) {
/*
* if More - To - Come is set in this frame then we don ' t know
* length of entire message , and hence have to allocate
* large buffer */
/* We are starting a new envelope */
privptr - > mtc_offset = 0 ;
privptr - > mtc_logical_link = link_num ;
}
if ( bytes_to_mov > ( MAX_ENVELOPE_SIZE - privptr - > mtc_offset ) ) {
/* error */
privptr - > stats . rx_frame_errors + + ;
goto NextFrame ;
}
if ( p_env - > packing = = DO_PACKED ) {
memcpy ( privptr - > p_mtc_envelope + privptr - > mtc_offset ,
p_packd + sizeof ( struct clawph ) , bytes_to_mov ) ;
} else {
memcpy ( privptr - > p_mtc_envelope + privptr - > mtc_offset ,
p_this_ccw - > p_buffer , bytes_to_mov ) ;
}
if ( mtc_this_frm = = 0 ) {
len_of_data = privptr - > mtc_offset + bytes_to_mov ;
skb = dev_alloc_skb ( len_of_data ) ;
if ( skb ) {
memcpy ( skb_put ( skb , len_of_data ) ,
privptr - > p_mtc_envelope ,
len_of_data ) ;
skb - > dev = dev ;
2007-03-20 01:33:04 +03:00
skb_reset_mac_header ( skb ) ;
2005-04-17 02:20:36 +04:00
skb - > protocol = htons ( ETH_P_IP ) ;
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
privptr - > stats . rx_packets + + ;
privptr - > stats . rx_bytes + = len_of_data ;
netif_rx ( skb ) ;
}
else {
2009-01-20 09:14:33 +03:00
dev_info ( p_dev , " Allocating a buffer for "
" incoming data failed \n " ) ;
2005-04-17 02:20:36 +04:00
privptr - > stats . rx_dropped + + ;
}
privptr - > mtc_offset = 0 ;
privptr - > mtc_logical_link = - 1 ;
}
else {
privptr - > mtc_offset + = bytes_to_mov ;
}
if ( p_env - > packing = = DO_PACKED )
goto unpack_next ;
NextFrame :
/*
* Remove ThisCCWblock from active read queue , and add it
* to queue of free blocks to be reused .
*/
i + + ;
p_this_ccw - > header . length = 0xffff ;
p_this_ccw - > header . opcode = 0xff ;
/*
* add this one to the free queue for later reuse
*/
if ( p_first_ccw = = NULL ) {
p_first_ccw = p_this_ccw ;
}
else {
p_last_ccw - > next = p_this_ccw ;
}
p_last_ccw = p_this_ccw ;
/*
* chain to next block on active read queue
*/
p_this_ccw = privptr - > p_read_active_first ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 4 , trace , " rxpkt %d " , p ) ;
2005-04-17 02:20:36 +04:00
} /* end of while */
/* check validity */
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 4 , trace , " rxfrm %d " , i ) ;
2005-04-17 02:20:36 +04:00
add_claw_reads ( dev , p_first_ccw , p_last_ccw ) ;
claw_strt_read ( dev , LOCK_YES ) ;
return ;
} /* end of unpack_read */
/*-------------------------------------------------------------------*
* claw_strt_read *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
claw_strt_read ( struct net_device * dev , int lock )
{
int rc = 0 ;
__u32 parm ;
unsigned long saveflags = 0 ;
2008-08-21 19:10:23 +04:00
struct claw_privbk * privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
struct ccwbk * p_ccwbk ;
struct chbk * p_ch ;
struct clawh * p_clawh ;
p_ch = & privptr - > channel [ READ ] ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " StRdNter " ) ;
2005-04-17 02:20:36 +04:00
p_clawh = ( struct clawh * ) privptr - > p_claw_signal_blk ;
p_clawh - > flag = CLAW_IDLE ; /* 0x00 */
if ( ( privptr - > p_write_active_first ! = NULL & &
privptr - > p_write_active_first - > header . flag ! = CLAW_PENDING ) | |
( privptr - > p_read_active_first ! = NULL & &
privptr - > p_read_active_first - > header . flag ! = CLAW_PENDING ) ) {
p_clawh - > flag = CLAW_BUSY ; /* 0xff */
}
if ( lock = = LOCK_YES ) {
spin_lock_irqsave ( get_ccwdev_lock ( p_ch - > cdev ) , saveflags ) ;
}
if ( test_and_set_bit ( 0 , ( void * ) & p_ch - > IO_active ) = = 0 ) {
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " HotRead " ) ;
2005-04-17 02:20:36 +04:00
p_ccwbk = privptr - > p_read_active_first ;
parm = ( unsigned long ) p_ch ;
rc = ccw_device_start ( p_ch - > cdev , & p_ccwbk - > read , parm ,
0xff , 0 ) ;
if ( rc ! = 0 ) {
ccw_check_return_code ( p_ch - > cdev , rc ) ;
}
}
else {
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " ReadAct " ) ;
2005-04-17 02:20:36 +04:00
}
if ( lock = = LOCK_YES ) {
spin_unlock_irqrestore ( get_ccwdev_lock ( p_ch - > cdev ) , saveflags ) ;
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " StRdExit " ) ;
2005-04-17 02:20:36 +04:00
return ;
} /* end of claw_strt_read */
/*-------------------------------------------------------------------*
* claw_strt_out_IO *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
claw_strt_out_IO ( struct net_device * dev )
{
int rc = 0 ;
unsigned long parm ;
struct claw_privbk * privptr ;
struct chbk * p_ch ;
struct ccwbk * p_first_ccw ;
if ( ! dev ) {
return ;
}
2008-08-21 19:10:23 +04:00
privptr = ( struct claw_privbk * ) dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
p_ch = & privptr - > channel [ WRITE ] ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " strt_io " ) ;
2005-04-17 02:20:36 +04:00
p_first_ccw = privptr - > p_write_active_first ;
if ( p_ch - > claw_state = = CLAW_STOP )
return ;
if ( p_first_ccw = = NULL ) {
return ;
}
if ( test_and_set_bit ( 0 , ( void * ) & p_ch - > IO_active ) = = 0 ) {
parm = ( unsigned long ) p_ch ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " StWrtIO " ) ;
2009-01-20 09:14:33 +03:00
rc = ccw_device_start ( p_ch - > cdev , & p_first_ccw - > write , parm ,
0xff , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( rc ! = 0 ) {
ccw_check_return_code ( p_ch - > cdev , rc ) ;
}
}
dev - > trans_start = jiffies ;
return ;
} /* end of claw_strt_out_IO */
/*-------------------------------------------------------------------*
* Free write buffers *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
claw_free_wrt_buf ( struct net_device * dev )
{
2008-08-21 19:10:23 +04:00
struct claw_privbk * privptr = ( struct claw_privbk * ) dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
struct ccwbk * p_first_ccw ;
struct ccwbk * p_last_ccw ;
struct ccwbk * p_this_ccw ;
struct ccwbk * p_next_ccw ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " freewrtb " ) ;
2005-04-17 02:20:36 +04:00
/* scan the write queue to free any completed write packets */
p_first_ccw = NULL ;
p_last_ccw = NULL ;
p_this_ccw = privptr - > p_write_active_first ;
while ( ( p_this_ccw ! = NULL ) & & ( p_this_ccw - > header . flag ! = CLAW_PENDING ) )
{
p_next_ccw = p_this_ccw - > next ;
if ( ( ( p_next_ccw ! = NULL ) & &
( p_next_ccw - > header . flag ! = CLAW_PENDING ) ) | |
( ( p_this_ccw = = privptr - > p_write_active_last ) & &
( p_this_ccw - > header . flag ! = CLAW_PENDING ) ) ) {
/* The next CCW is OK or this is */
/* the last CCW...free it @A1A */
privptr - > p_write_active_first = p_this_ccw - > next ;
p_this_ccw - > header . flag = CLAW_PENDING ;
p_this_ccw - > next = privptr - > p_write_free_chain ;
privptr - > p_write_free_chain = p_this_ccw ;
+ + privptr - > write_free_count ;
privptr - > stats . tx_bytes + = p_this_ccw - > write . count ;
p_this_ccw = privptr - > p_write_active_first ;
privptr - > stats . tx_packets + + ;
}
else {
break ;
}
}
if ( privptr - > write_free_count ! = 0 ) {
claw_clearbit_busy ( TB_NOBUFFER , dev ) ;
}
/* whole chain removed? */
if ( privptr - > p_write_active_first = = NULL ) {
privptr - > p_write_active_last = NULL ;
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 4 , trace , " FWC=%d " , privptr - > write_free_count ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/*-------------------------------------------------------------------*
* claw free netdevice *
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void
claw_free_netdevice ( struct net_device * dev , int free_dev )
{
struct claw_privbk * privptr ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " free_dev " ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev )
return ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , dev - > name ) ;
2008-08-21 19:10:23 +04:00
privptr = dev - > ml_priv ;
2005-04-17 02:20:36 +04:00
if ( dev - > flags & IFF_RUNNING )
claw_release ( dev ) ;
if ( privptr ) {
privptr - > channel [ READ ] . ndev = NULL ; /* say it's free */
}
2008-08-21 19:10:23 +04:00
dev - > ml_priv = NULL ;
2005-04-17 02:20:36 +04:00
# ifdef MODULE
if ( free_dev ) {
free_netdev ( dev ) ;
}
# endif
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " free_ok " ) ;
2005-04-17 02:20:36 +04:00
}
/**
* Claw init netdevice
* Initialize everything of the net device except the name and the
* channel structs .
*/
2009-01-09 06:43:59 +03:00
static const struct net_device_ops claw_netdev_ops = {
. ndo_open = claw_open ,
. ndo_stop = claw_release ,
. ndo_get_stats = claw_stats ,
. ndo_start_xmit = claw_tx ,
. ndo_change_mtu = claw_change_mtu ,
} ;
2005-04-17 02:20:36 +04:00
static void
claw_init_netdevice ( struct net_device * dev )
{
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " init_dev " ) ;
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , dev - > name ) ;
2005-04-17 02:20:36 +04:00
dev - > mtu = CLAW_DEFAULT_MTU_SIZE ;
dev - > hard_header_len = 0 ;
dev - > addr_len = 0 ;
dev - > type = ARPHRD_SLIP ;
dev - > tx_queue_len = 1300 ;
dev - > flags = IFF_POINTOPOINT | IFF_NOARP ;
2009-01-09 06:43:59 +03:00
dev - > netdev_ops = & claw_netdev_ops ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " initok " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/**
* Init a new channel in the privptr - > channel [ i ] .
*
* @ param cdev The ccw_device to be added .
*
* @ return 0 on success , ! 0 on error .
*/
static int
add_channel ( struct ccw_device * cdev , int i , struct claw_privbk * privptr )
{
struct chbk * p_ch ;
2007-06-20 15:00:20 +04:00
struct ccw_dev_id dev_id ;
2005-04-17 02:20:36 +04:00
2008-10-10 23:33:09 +04:00
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , dev_name ( & cdev - > dev ) ) ;
2005-04-17 02:20:36 +04:00
privptr - > channel [ i ] . flag = i + 1 ; /* Read is 1 Write is 2 */
p_ch = & privptr - > channel [ i ] ;
p_ch - > cdev = cdev ;
2008-10-10 23:33:09 +04:00
snprintf ( p_ch - > id , CLAW_ID_SIZE , " cl-%s " , dev_name ( & cdev - > dev ) ) ;
2007-06-20 15:00:20 +04:00
ccw_device_get_id ( cdev , & dev_id ) ;
p_ch - > devno = dev_id . devno ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
if ( ( p_ch - > irb = kzalloc ( sizeof ( struct irb ) , GFP_KERNEL ) ) = = NULL ) {
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
}
return 0 ;
}
/**
*
* Setup an interface .
*
* @ param cgdev Device to be setup .
*
* @ returns 0 on success , ! 0 on failure .
*/
static int
claw_new_device ( struct ccwgroup_device * cgdev )
{
struct claw_privbk * privptr ;
struct claw_env * p_env ;
struct net_device * dev ;
int ret ;
2007-06-20 15:00:20 +04:00
struct ccw_dev_id dev_id ;
2005-04-17 02:20:36 +04:00
2009-01-20 09:14:33 +03:00
dev_info ( & cgdev - > dev , " add for %s \n " ,
dev_name ( & cgdev - > cdev [ READ ] - > dev ) ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " new_dev " ) ;
2009-05-04 23:40:54 +04:00
privptr = dev_get_drvdata ( & cgdev - > dev ) ;
dev_set_drvdata ( & cgdev - > cdev [ READ ] - > dev , privptr ) ;
dev_set_drvdata ( & cgdev - > cdev [ WRITE ] - > dev , privptr ) ;
2005-04-17 02:20:36 +04:00
if ( ! privptr )
return - ENODEV ;
p_env = privptr - > p_env ;
2007-06-20 15:00:20 +04:00
ccw_device_get_id ( cgdev - > cdev [ READ ] , & dev_id ) ;
p_env - > devno [ READ ] = dev_id . devno ;
ccw_device_get_id ( cgdev - > cdev [ WRITE ] , & dev_id ) ;
p_env - > devno [ WRITE ] = dev_id . devno ;
2005-04-17 02:20:36 +04:00
ret = add_channel ( cgdev - > cdev [ 0 ] , 0 , privptr ) ;
if ( ret = = 0 )
ret = add_channel ( cgdev - > cdev [ 1 ] , 1 , privptr ) ;
if ( ret ! = 0 ) {
2009-01-20 09:14:33 +03:00
dev_warn ( & cgdev - > dev , " Creating a CLAW group device "
" failed with error code %d \n " , ret ) ;
2008-07-18 17:24:56 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
ret = ccw_device_set_online ( cgdev - > cdev [ READ ] ) ;
if ( ret ! = 0 ) {
2009-01-20 09:14:33 +03:00
dev_warn ( & cgdev - > dev ,
" Setting the read subchannel online "
" failed with error code %d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
ret = ccw_device_set_online ( cgdev - > cdev [ WRITE ] ) ;
if ( ret ! = 0 ) {
2009-01-20 09:14:33 +03:00
dev_warn ( & cgdev - > dev ,
" Setting the write subchannel online "
" failed with error code %d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
dev = alloc_netdev ( 0 , " claw%d " , claw_init_netdevice ) ;
if ( ! dev ) {
2009-01-20 09:14:33 +03:00
dev_warn ( & cgdev - > dev ,
" Activating the CLAW device failed \n " ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
2008-08-21 19:10:23 +04:00
dev - > ml_priv = privptr ;
2009-05-04 23:40:54 +04:00
dev_set_drvdata ( & cgdev - > dev , privptr ) ;
dev_set_drvdata ( & cgdev - > cdev [ READ ] - > dev , privptr ) ;
dev_set_drvdata ( & cgdev - > cdev [ WRITE ] - > dev , privptr ) ;
2005-04-17 02:20:36 +04:00
/* sysfs magic */
SET_NETDEV_DEV ( dev , & cgdev - > dev ) ;
if ( register_netdev ( dev ) ! = 0 ) {
claw_free_netdevice ( dev , 1 ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " regfail " ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
dev - > flags & = ~ IFF_RUNNING ;
if ( privptr - > buffs_alloc = = 0 ) {
ret = init_ccw_bk ( dev ) ;
if ( ret ! = 0 ) {
unregister_netdev ( dev ) ;
claw_free_netdevice ( dev , 1 ) ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , trace , " ccwmem " ) ;
2005-04-17 02:20:36 +04:00
goto out ;
}
}
privptr - > channel [ READ ] . ndev = dev ;
privptr - > channel [ WRITE ] . ndev = dev ;
privptr - > p_env - > ndev = dev ;
2009-01-20 09:14:33 +03:00
dev_info ( & cgdev - > dev , " %s:readsize=%d writesize=%d "
2005-04-17 02:20:36 +04:00
" readbuffer=%d writebuffer=%d read=0x%04x write=0x%04x \n " ,
dev - > name , p_env - > read_size ,
p_env - > write_size , p_env - > read_buffers ,
p_env - > write_buffers , p_env - > devno [ READ ] ,
p_env - > devno [ WRITE ] ) ;
2009-01-20 09:14:33 +03:00
dev_info ( & cgdev - > dev , " %s:host_name:%.8s, adapter_name "
2005-04-17 02:20:36 +04:00
" :%.8s api_type: %.8s \n " ,
dev - > name , p_env - > host_name ,
p_env - > adapter_name , p_env - > api_type ) ;
return 0 ;
out :
ccw_device_set_offline ( cgdev - > cdev [ 1 ] ) ;
ccw_device_set_offline ( cgdev - > cdev [ 0 ] ) ;
return - ENODEV ;
}
static void
claw_purge_skb_queue ( struct sk_buff_head * q )
{
struct sk_buff * skb ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 4 , trace , " purgque " ) ;
2005-04-17 02:20:36 +04:00
while ( ( skb = skb_dequeue ( q ) ) ) {
atomic_dec ( & skb - > users ) ;
2005-09-06 17:03:09 +04:00
dev_kfree_skb_any ( skb ) ;
2005-04-17 02:20:36 +04:00
}
}
/**
* Shutdown an interface .
*
* @ param cgdev Device to be shut down .
*
* @ returns 0 on success , ! 0 on failure .
*/
static int
claw_shutdown_device ( struct ccwgroup_device * cgdev )
{
struct claw_privbk * priv ;
struct net_device * ndev ;
int ret ;
2008-10-10 23:33:11 +04:00
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , dev_name ( & cgdev - > dev ) ) ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( & cgdev - > dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
ndev = priv - > channel [ READ ] . ndev ;
if ( ndev ) {
/* Close the device */
2009-01-20 09:14:33 +03:00
dev_info ( & cgdev - > dev , " %s: shutting down \n " ,
ndev - > name ) ;
2005-04-17 02:20:36 +04:00
if ( ndev - > flags & IFF_RUNNING )
ret = claw_release ( ndev ) ;
ndev - > flags & = ~ IFF_RUNNING ;
unregister_netdev ( ndev ) ;
2008-08-21 19:10:23 +04:00
ndev - > ml_priv = NULL ; /* cgdev data, not ndev's to free */
2005-04-17 02:20:36 +04:00
claw_free_netdevice ( ndev , 1 ) ;
priv - > channel [ READ ] . ndev = NULL ;
priv - > channel [ WRITE ] . ndev = NULL ;
priv - > p_env - > ndev = NULL ;
}
ccw_device_set_offline ( cgdev - > cdev [ 1 ] ) ;
ccw_device_set_offline ( cgdev - > cdev [ 0 ] ) ;
return 0 ;
}
static void
claw_remove_device ( struct ccwgroup_device * cgdev )
{
struct claw_privbk * priv ;
2008-07-18 17:24:56 +04:00
BUG_ON ( ! cgdev ) ;
2008-10-10 23:33:11 +04:00
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , dev_name ( & cgdev - > dev ) ) ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( & cgdev - > dev ) ;
2008-07-18 17:24:56 +04:00
BUG_ON ( ! priv ) ;
2009-01-20 09:14:33 +03:00
dev_info ( & cgdev - > dev , " will be removed. \n " ) ;
2005-04-17 02:20:36 +04:00
if ( cgdev - > state = = CCWGROUP_ONLINE )
claw_shutdown_device ( cgdev ) ;
claw_remove_files ( & cgdev - > dev ) ;
2005-11-07 12:01:30 +03:00
kfree ( priv - > p_mtc_envelope ) ;
priv - > p_mtc_envelope = NULL ;
kfree ( priv - > p_env ) ;
priv - > p_env = NULL ;
kfree ( priv - > channel [ 0 ] . irb ) ;
priv - > channel [ 0 ] . irb = NULL ;
kfree ( priv - > channel [ 1 ] . irb ) ;
priv - > channel [ 1 ] . irb = NULL ;
2005-04-17 02:20:36 +04:00
kfree ( priv ) ;
2009-05-04 23:40:54 +04:00
dev_set_drvdata ( & cgdev - > dev , NULL ) ;
dev_set_drvdata ( & cgdev - > cdev [ READ ] - > dev , NULL ) ;
dev_set_drvdata ( & cgdev - > cdev [ WRITE ] - > dev , NULL ) ;
2005-04-17 02:20:36 +04:00
put_device ( & cgdev - > dev ) ;
2008-07-18 17:24:56 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
/*
* sysfs attributes
*/
static ssize_t
2005-05-17 14:43:27 +04:00
claw_hname_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
return sprintf ( buf , " %s \n " , p_env - > host_name ) ;
}
static ssize_t
2009-01-20 09:14:33 +03:00
claw_hname_write ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
if ( count > MAX_NAME_LEN + 1 )
return - EINVAL ;
memset ( p_env - > host_name , 0x20 , MAX_NAME_LEN ) ;
strncpy ( p_env - > host_name , buf , count ) ;
p_env - > host_name [ count - 1 ] = 0x20 ; /* clear extra 0x0a */
p_env - > host_name [ MAX_NAME_LEN ] = 0x00 ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " HstnSet " ) ;
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , p_env - > host_name ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
static DEVICE_ATTR ( host_name , 0644 , claw_hname_show , claw_hname_write ) ;
static ssize_t
2005-05-17 14:43:27 +04:00
claw_adname_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
2008-07-18 17:24:56 +04:00
return sprintf ( buf , " %s \n " , p_env - > adapter_name ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2009-01-20 09:14:33 +03:00
claw_adname_write ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
if ( count > MAX_NAME_LEN + 1 )
return - EINVAL ;
memset ( p_env - > adapter_name , 0x20 , MAX_NAME_LEN ) ;
strncpy ( p_env - > adapter_name , buf , count ) ;
p_env - > adapter_name [ count - 1 ] = 0x20 ; /* clear extra 0x0a */
p_env - > adapter_name [ MAX_NAME_LEN ] = 0x00 ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " AdnSet " ) ;
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , p_env - > adapter_name ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
static DEVICE_ATTR ( adapter_name , 0644 , claw_adname_show , claw_adname_write ) ;
static ssize_t
2005-05-17 14:43:27 +04:00
claw_apname_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
return sprintf ( buf , " %s \n " ,
p_env - > api_type ) ;
}
static ssize_t
2009-01-20 09:14:33 +03:00
claw_apname_write ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
if ( count > MAX_NAME_LEN + 1 )
return - EINVAL ;
memset ( p_env - > api_type , 0x20 , MAX_NAME_LEN ) ;
strncpy ( p_env - > api_type , buf , count ) ;
p_env - > api_type [ count - 1 ] = 0x20 ; /* we get a loose 0x0a */
p_env - > api_type [ MAX_NAME_LEN ] = 0x00 ;
if ( strncmp ( p_env - > api_type , WS_APPL_NAME_PACKED , 6 ) = = 0 ) {
p_env - > read_size = DEF_PACK_BUFSIZE ;
p_env - > write_size = DEF_PACK_BUFSIZE ;
p_env - > packing = PACKING_ASK ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " PACKING " ) ;
2005-04-17 02:20:36 +04:00
}
else {
p_env - > packing = 0 ;
p_env - > read_size = CLAW_FRAME_SIZE ;
p_env - > write_size = CLAW_FRAME_SIZE ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " ApiSet " ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT_ ( 2 , setup , " %s " , p_env - > api_type ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
static DEVICE_ATTR ( api_type , 0644 , claw_apname_show , claw_apname_write ) ;
static ssize_t
2005-05-17 14:43:27 +04:00
claw_wbuff_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
return sprintf ( buf , " %d \n " , p_env - > write_buffers ) ;
}
static ssize_t
2009-01-20 09:14:33 +03:00
claw_wbuff_write ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
int nnn , max ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
sscanf ( buf , " %i " , & nnn ) ;
if ( p_env - > packing ) {
max = 64 ;
}
else {
max = 512 ;
}
if ( ( nnn > max ) | | ( nnn < 2 ) )
return - EINVAL ;
p_env - > write_buffers = nnn ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " Wbufset " ) ;
CLAW_DBF_TEXT_ ( 2 , setup , " WB=%d " , p_env - > write_buffers ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
static DEVICE_ATTR ( write_buffer , 0644 , claw_wbuff_show , claw_wbuff_write ) ;
static ssize_t
2005-05-17 14:43:27 +04:00
claw_rbuff_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
return sprintf ( buf , " %d \n " , p_env - > read_buffers ) ;
}
static ssize_t
2009-01-20 09:14:33 +03:00
claw_rbuff_write ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
struct claw_privbk * priv ;
struct claw_env * p_env ;
int nnn , max ;
2009-05-04 23:40:54 +04:00
priv = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! priv )
return - ENODEV ;
p_env = priv - > p_env ;
sscanf ( buf , " %i " , & nnn ) ;
if ( p_env - > packing ) {
max = 64 ;
}
else {
max = 512 ;
}
if ( ( nnn > max ) | | ( nnn < 2 ) )
return - EINVAL ;
p_env - > read_buffers = nnn ;
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " Rbufset " ) ;
CLAW_DBF_TEXT_ ( 2 , setup , " RB=%d " , p_env - > read_buffers ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
static DEVICE_ATTR ( read_buffer , 0644 , claw_rbuff_show , claw_rbuff_write ) ;
static struct attribute * claw_attr [ ] = {
& dev_attr_read_buffer . attr ,
& dev_attr_write_buffer . attr ,
& dev_attr_adapter_name . attr ,
& dev_attr_api_type . attr ,
& dev_attr_host_name . attr ,
NULL ,
} ;
static struct attribute_group claw_attr_group = {
. attrs = claw_attr ,
} ;
static int
claw_add_files ( struct device * dev )
{
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " add_file " ) ;
2005-04-17 02:20:36 +04:00
return sysfs_create_group ( & dev - > kobj , & claw_attr_group ) ;
}
static void
claw_remove_files ( struct device * dev )
{
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " rem_file " ) ;
2005-04-17 02:20:36 +04:00
sysfs_remove_group ( & dev - > kobj , & claw_attr_group ) ;
}
/*--------------------------------------------------------------------*
* claw_init and cleanup *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void __exit
claw_cleanup ( void )
{
unregister_cu3088_discipline ( & claw_group_driver ) ;
claw_unregister_debug_facility ( ) ;
2009-01-20 09:14:33 +03:00
pr_info ( " Driver unloaded \n " ) ;
2005-04-17 02:20:36 +04:00
}
/**
* Initialize module .
* This is called just after the module is loaded .
*
* @ return 0 on success , ! 0 on error .
*/
static int __init
claw_init ( void )
{
int ret = 0 ;
2009-01-20 09:14:33 +03:00
pr_info ( " Loading %s \n " , version ) ;
2005-04-17 02:20:36 +04:00
ret = claw_register_debug_facility ( ) ;
if ( ret ) {
2009-01-20 09:14:33 +03:00
pr_err ( " Registering with the S/390 debug feature "
" failed with error code %d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " init_mod " ) ;
2005-04-17 02:20:36 +04:00
ret = register_cu3088_discipline ( & claw_group_driver ) ;
if ( ret ) {
2008-07-18 17:24:56 +04:00
CLAW_DBF_TEXT ( 2 , setup , " init_bad " ) ;
2005-04-17 02:20:36 +04:00
claw_unregister_debug_facility ( ) ;
2009-01-20 09:14:33 +03:00
pr_err ( " Registering with the cu3088 device driver failed "
" with error code %d \n " , ret ) ;
2005-04-17 02:20:36 +04:00
}
return ret ;
}
module_init ( claw_init ) ;
module_exit ( claw_cleanup ) ;
2008-07-18 17:24:56 +04:00
MODULE_AUTHOR ( " Andy Richter <richtera@us.ibm.com> " ) ;
MODULE_DESCRIPTION ( " Linux for System z CLAW Driver \n " \
" Copyright 2000,2008 IBM Corporation \n " ) ;
MODULE_LICENSE ( " GPL " ) ;